Bug 2231 - Secure transport for PCEP 30/15730/8
authorMilos Fabian <milfabia@cisco.com>
Mon, 27 Apr 2015 19:51:01 +0000 (21:51 +0200)
committerMilos Fabian <milfabia@cisco.com>
Fri, 1 May 2015 06:08:25 +0000 (06:08 +0000)
http://tools.ietf.org/html/draft-ietf-pce-pceps-03

-configurable TLS parameters (location of keystore, truststore, etc.)
-example initial configuration
-if TLS is configured, PCEPS is enabled, session negotiation starts with StartTLS msg
-StartTLSWait timer set to 60 seconds
-extended PCEP FRM to handle StartTLS

Change-Id: I4ad4ebc52187eaa58654db3ccabe484758132761
Signed-off-by: Ladislav Borak <lborak@cisco.com>
Signed-off-by: Milos Fabian <milfabia@cisco.com>
16 files changed:
pcep/controller-config/src/main/resources/initial/32-pcep.xml
pcep/impl/pom.xml
pcep/impl/src/main/java/org/opendaylight/controller/config/yang/pcep/impl/PCEPDispatcherImplModule.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/AbstractPCEPSessionNegotiator.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/DefaultPCEPSessionNegotiator.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/DefaultPCEPSessionNegotiatorFactory.java
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/tls/SslContextFactory.java [new file with mode: 0644]
pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/tls/SslKeyStore.java [new file with mode: 0644]
pcep/impl/src/main/yang/odl-pcep-impl-cfg.yang
pcep/impl/src/test/java/org/opendaylight/controller/config/yang/pcep/impl/PCEPDispatcherImplModuleTest.java
pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/AbstractPCEPSessionTest.java
pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/FiniteStateMachineTest.java
pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/SslContextFactoryTest.java [new file with mode: 0644]
pcep/impl/src/test/resources/exemplary-ctlKeystore [new file with mode: 0644]
pcep/impl/src/test/resources/exemplary-ctlTrustStore [new file with mode: 0644]
pcep/spi/src/main/java/org/opendaylight/protocol/pcep/spi/PCEPErrors.java

index 4ceee88cc940d8f108aad20265d6a391e78c9275..fd77fb11e706b0ae9f2199762b5af9e0d961c062 100644 (file)
                         <name>md5-server-channel-factory</name>
                     </md5-server-channel-factory>
                     -->
+
+                    <!--
+                        Uncomment this block to enable PCEPS TLS communication. Change example values as needed.
+                    <tls>
+                       <keystore>configuration/ctl.jks</keystore>
+                       <keystore-type>JKS</keystore-type>
+                       <keystore-path-type>PATH</keystore-path-type>
+                       <keystore-password>opendaylight</keystore-password>
+                       <truststore>configuration/truststore.jks</truststore>
+                       <truststore-type>JKS</truststore-type>
+                       <truststore-path-type>PATH</truststore-path-type>
+                       <truststore-password>opendaylight</truststore-password>
+                       <certificate-password>opendaylight</certificate-password>
+                     </tls>
+                     -->
                 </module>
             </modules>
 
index 19134830571b7fc1a9713582f2cc03e57fdb3238..6768baf338d1e7b02a66fbafa792370571163df1 100644 (file)
             <groupId>io.netty</groupId>
             <artifactId>netty-common</artifactId>
         </dependency>
+        <dependency>
+        <groupId>io.netty</groupId>
+        <artifactId>netty-handler</artifactId>
+      </dependency>
         <dependency>
             <groupId>io.netty</groupId>
             <artifactId>netty-transport</artifactId>
index cd63d91b7378dc584147b926575f22b889e744a8..09749f4af7119730b8461a7825c67c447701289b 100644 (file)
@@ -26,6 +26,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.typ
  */
 public final class PCEPDispatcherImplModule extends org.opendaylight.controller.config.yang.pcep.impl.AbstractPCEPDispatcherImplModule {
 
+    private static final String VALUE_IS_NOT_SET = "value is not set.";
+    private static final String KEYSTORE = "keystore";
+    private static final String TRUSTSTORE = "truststore";
+    private static final String PASSWORD = " password ";
+    private static final String LOCATION = " location ";
+    private static final String TYPE = " type ";
+    private static final String PATH_TYPE = " path" + TYPE;
+
     public PCEPDispatcherImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier name,
             final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(name, dependencyResolver);
@@ -40,15 +48,26 @@ public final class PCEPDispatcherImplModule extends org.opendaylight.controller.
     @Override
     public void validate() {
         super.validate();
-        JmxAttributeValidationException.checkNotNull(getMaxUnknownMessages(), "value is not set.", maxUnknownMessagesJmxAttribute);
+        JmxAttributeValidationException.checkNotNull(getMaxUnknownMessages(), VALUE_IS_NOT_SET, maxUnknownMessagesJmxAttribute);
         JmxAttributeValidationException.checkCondition(getMaxUnknownMessages() > 0, "Parameter 'maxUnknownMessages' "
                 + "must be greater than 0", maxUnknownMessagesJmxAttribute);
+        if (getTls() != null) {
+            JmxAttributeValidationException.checkNotNull(getTls().getCertificatePassword(), "certificate" + PASSWORD + VALUE_IS_NOT_SET, tlsJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(getTls().getKeystore(), KEYSTORE + LOCATION + VALUE_IS_NOT_SET, tlsJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(getTls().getKeystorePassword(), KEYSTORE + PASSWORD + VALUE_IS_NOT_SET, tlsJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(getTls().getKeystorePathType(), KEYSTORE + PATH_TYPE + VALUE_IS_NOT_SET, tlsJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(getTls().getKeystoreType(), KEYSTORE + TYPE + VALUE_IS_NOT_SET, tlsJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(getTls().getTruststore(), TRUSTSTORE + LOCATION + VALUE_IS_NOT_SET, tlsJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(getTls().getTruststorePassword(), TRUSTSTORE + PASSWORD + VALUE_IS_NOT_SET, tlsJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(getTls().getTruststorePathType(), TRUSTSTORE + PATH_TYPE + VALUE_IS_NOT_SET, tlsJmxAttribute);
+            JmxAttributeValidationException.checkNotNull(getTls().getTruststoreType(), TRUSTSTORE + TYPE + VALUE_IS_NOT_SET, tlsJmxAttribute);
+        }
     }
 
     @Override
     public java.lang.AutoCloseable createInstance() {
         Open localPrefs = getPcepSessionProposalFactoryDependency().getSessionProposal(null, 0);
-        DefaultPCEPSessionNegotiatorFactory negFactory = new DefaultPCEPSessionNegotiatorFactory(localPrefs, getMaxUnknownMessages());
+        DefaultPCEPSessionNegotiatorFactory negFactory = new DefaultPCEPSessionNegotiatorFactory(localPrefs, getMaxUnknownMessages(), getTls());
 
         return new PCEPDispatcherImpl(getPcepExtensionsDependency().getMessageHandlerRegistry(), negFactory, getBossGroupDependency(), getWorkerGroupDependency(), getMd5ChannelFactoryDependency(), getMd5ServerChannelFactoryDependency());
     }
index 36f6289d63722cb6a5102996025cf36f2ac7ff56..bf859614097fc2971ec6bcdf06a9a5a7c41178f7 100644 (file)
@@ -10,16 +10,23 @@ package org.opendaylight.protocol.pcep.impl;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
+import io.netty.handler.ssl.SslHandler;
 import io.netty.util.concurrent.Promise;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import org.opendaylight.controller.config.yang.pcep.impl.Tls;
 import org.opendaylight.protocol.framework.AbstractSessionNegotiator;
+import org.opendaylight.protocol.pcep.impl.tls.SslContextFactory;
 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Keepalive;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.KeepaliveBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.OpenBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Pcerr;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Starttls;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.StarttlsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.Message;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.OpenMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.keepalive.message.KeepaliveMessageBuilder;
@@ -27,6 +34,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.typ
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Open;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcep.error.object.ErrorObject;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcerr.message.pcerr.message.error.type.SessionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.start.tls.message.StartTlsMessageBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,6 +61,10 @@ public abstract class AbstractPCEPSessionNegotiator extends AbstractSessionNegot
          * point we move into OpenWait state.
          */
         IDLE,
+        /**
+         * Waiting for the peer's StartTLS message
+         */
+        START_TLS_WAIT,
         /**
          * Waiting for the peer's OPEN message.
          */
@@ -75,6 +87,7 @@ public abstract class AbstractPCEPSessionNegotiator extends AbstractSessionNegot
     private Future<?> failTimer;
     private Open localPrefs;
     private Open remotePrefs;
+    private Tls tlsConfiguration;
 
     protected AbstractPCEPSessionNegotiator(final Promise<PCEPSessionImpl> promise, final Channel channel) {
         super(promise, channel);
@@ -140,6 +153,10 @@ public abstract class AbstractPCEPSessionNegotiator extends AbstractSessionNegot
                 case FINISHED:
                 case IDLE:
                     break;
+                case START_TLS_WAIT:
+                    sendErrorMessage(PCEPErrors.STARTTLS_TIMER_EXP);
+                    negotiationFailed(new TimeoutException("StartTLSWait timer expired"));
+                    AbstractPCEPSessionNegotiator.this.state = State.FINISHED;
                 case KEEP_WAIT:
                     sendErrorMessage(PCEPErrors.NO_MSG_BEFORE_EXP_KEEPWAIT);
                     negotiationFailed(new TimeoutException("KeepWait timer expired"));
@@ -160,6 +177,17 @@ public abstract class AbstractPCEPSessionNegotiator extends AbstractSessionNegot
     @Override
     protected final void startNegotiation() {
         Preconditions.checkState(this.state == State.IDLE);
+        if (this.tlsConfiguration != null) {
+            this.sendMessage(new StarttlsBuilder().setStartTlsMessage(new StartTlsMessageBuilder().build()).build());
+            this.state = State.START_TLS_WAIT;
+            scheduleFailTimer();
+            LOG.info("Started TLS connection negotiation with peer {}", this.channel);
+        } else {
+            startNegotiationWithOpen();
+        }
+    }
+
+    private void startNegotiationWithOpen() {
         this.localPrefs = getInitialProposal();
         final OpenMessage m = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.OpenBuilder().setOpenMessage(
                 new OpenMessageBuilder().setOpen(this.localPrefs).build()).build();
@@ -250,6 +278,32 @@ public abstract class AbstractPCEPSessionNegotiator extends AbstractSessionNegot
         return true;
     }
 
+    private boolean handleMessageStartTlsWait(final Message msg) {
+        if (msg instanceof Starttls) {
+            final SslContextFactory sslFactory = new SslContextFactory(this.tlsConfiguration);
+            final SSLContext sslContext = sslFactory.getServerContext();
+            if (sslContext == null) {
+                this.sendErrorMessage(PCEPErrors.NOT_POSSIBLE_WITHOUT_TLS);
+                negotiationFailed(new IllegalStateException("Failed to establish a TLS connection."));
+                this.state = State.FINISHED;
+                return true;
+            }
+            final SSLEngine engine = sslContext.createSSLEngine();
+            engine.setNeedClientAuth(true);
+            engine.setUseClientMode(false);
+            this.channel.pipeline().addFirst(new SslHandler(engine));
+            LOG.info("PCEPS TLS connection with peer: {} established succesfully.", this.channel);
+            startNegotiationWithOpen();
+            return true;
+        } else if (! (msg instanceof Pcerr)) {
+            this.sendErrorMessage(PCEPErrors.NON_STARTTLS_MSG_RCVD);
+            negotiationFailed(new IllegalStateException("Unexpected message recieved."));
+            this.state = State.FINISHED;
+            return true;
+        }
+        return false;
+    }
+
     @Override
     protected final void handleMessage(final Message msg) {
         this.failTimer.cancel(false);
@@ -260,6 +314,11 @@ public abstract class AbstractPCEPSessionNegotiator extends AbstractSessionNegot
         case FINISHED:
         case IDLE:
             throw new IllegalStateException("Unexpected handleMessage in state " + this.state);
+        case START_TLS_WAIT:
+            if (handleMessageStartTlsWait(msg)) {
+                return;
+            }
+            break;
         case KEEP_WAIT:
             if (handleMessageKeepWait(msg)) {
                 return;
@@ -283,4 +342,8 @@ public abstract class AbstractPCEPSessionNegotiator extends AbstractSessionNegot
     State getState() {
         return this.state;
     }
+
+    public void setTlsConfiguration(final Tls tlsConfiguration) {
+        this.tlsConfiguration = tlsConfiguration;
+    }
 }
index 62a22025bc1de088553f381c95fecbd5c8c8eba3..f74807438642fe708a80319af63e132e337581de 100644 (file)
@@ -9,10 +9,9 @@ package org.opendaylight.protocol.pcep.impl;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
-
 import io.netty.channel.Channel;
 import io.netty.util.concurrent.Promise;
-
+import org.opendaylight.controller.config.yang.pcep.impl.Tls;
 import org.opendaylight.protocol.pcep.PCEPSessionListener;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Open;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.OpenBuilder;
@@ -22,14 +21,20 @@ public final class DefaultPCEPSessionNegotiator extends AbstractPCEPSessionNegot
     private final int maxUnknownMessages;
 
     public DefaultPCEPSessionNegotiator(final Promise<PCEPSessionImpl> promise, final Channel channel,
-            final PCEPSessionListener listener, final short sessionId, final int maxUnknownMessages, final Open localPrefs) {
+            final PCEPSessionListener listener, final short sessionId, final int maxUnknownMessages, final Open localPrefs, final Tls tlsConfiguration) {
         super(promise, channel);
+        super.setTlsConfiguration(tlsConfiguration);
         this.maxUnknownMessages = maxUnknownMessages;
         this.myLocalPrefs = new OpenBuilder().setKeepalive(localPrefs.getKeepalive()).setDeadTimer(localPrefs.getDeadTimer()).setSessionId(
                 sessionId).setTlvs(localPrefs.getTlvs()).build();
         this.listener = Preconditions.checkNotNull(listener);
     }
 
+    public DefaultPCEPSessionNegotiator(final Promise<PCEPSessionImpl> promise, final Channel channel,
+            final PCEPSessionListener listener, final short sessionId, final int maxUnknownMessages, final Open localPrefs) {
+        this(promise, channel, listener, sessionId, maxUnknownMessages, localPrefs, null);
+    }
+
     private final Open myLocalPrefs;
 
     @Override
index 004c8c1dc694a5c52f5d1cacdd2bc414e7626197..d32372c9eaae9e02f2620b145be89386f188f287 100644 (file)
@@ -8,25 +8,30 @@
 package org.opendaylight.protocol.pcep.impl;
 
 import com.google.common.base.Preconditions;
-
 import io.netty.channel.Channel;
 import io.netty.util.concurrent.Promise;
-
+import org.opendaylight.controller.config.yang.pcep.impl.Tls;
 import org.opendaylight.protocol.pcep.PCEPSessionListener;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Open;
 
 public final class DefaultPCEPSessionNegotiatorFactory extends AbstractPCEPSessionNegotiatorFactory {
     private final Open localPrefs;
     private final int maxUnknownMessages;
+    private final Tls tlsConfiguration;
 
     public DefaultPCEPSessionNegotiatorFactory(final Open localPrefs, final int maxUnknownMessages) {
+        this(localPrefs, maxUnknownMessages, null);
+    }
+
+    public DefaultPCEPSessionNegotiatorFactory(final Open localPrefs, final int maxUnknownMessages, final Tls tlsConfiguration) {
         this.localPrefs = Preconditions.checkNotNull(localPrefs);
         this.maxUnknownMessages = maxUnknownMessages;
+        this.tlsConfiguration = tlsConfiguration;
     }
 
     @Override
     protected AbstractPCEPSessionNegotiator createNegotiator(final Promise<PCEPSessionImpl> promise, final PCEPSessionListener listener,
             final Channel channel, final short sessionId) {
-        return new DefaultPCEPSessionNegotiator(promise, channel, listener, sessionId, this.maxUnknownMessages, this.localPrefs);
+        return new DefaultPCEPSessionNegotiator(promise, channel, listener, sessionId, this.maxUnknownMessages, this.localPrefs, this.tlsConfiguration);
     }
 }
diff --git a/pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/tls/SslContextFactory.java b/pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/tls/SslContextFactory.java
new file mode 100644 (file)
index 0000000..102cddd
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.pcep.impl.tls;
+
+import com.google.common.base.Preconditions;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+import org.opendaylight.controller.config.yang.pcep.impl.Tls;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class for setting up TLS connection.
+ */
+public class SslContextFactory {
+
+    private static final String PROTOCOL = "TLS";
+    private final Tls tlsConfig;
+
+    private static final Logger LOG = LoggerFactory
+            .getLogger(SslContextFactory.class);
+
+    /**
+     * @param tlsConfig
+     *            TLS configuration object, contains keystore locations and
+     *            keystore types
+     */
+    public SslContextFactory(final Tls tlsConfig) {
+        this.tlsConfig = Preconditions.checkNotNull(tlsConfig);
+    }
+
+    public SSLContext getServerContext() {
+        try {
+            final KeyStore ks = KeyStore.getInstance(this.tlsConfig.getKeystoreType().name());
+            ks.load(SslKeyStore.asInputStream(this.tlsConfig.getKeystore(), this.tlsConfig.getKeystorePathType()),
+                    this.tlsConfig.getKeystorePassword().toCharArray());
+            final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+            kmf.init(ks, this.tlsConfig.getCertificatePassword().toCharArray());
+
+            final KeyStore ts = KeyStore.getInstance(this.tlsConfig.getTruststoreType().name());
+            ts.load(SslKeyStore.asInputStream(this.tlsConfig.getTruststore(), this.tlsConfig.getTruststorePathType()),
+                    this.tlsConfig.getTruststorePassword().toCharArray());
+            final TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+            tmf.init(ts);
+
+            final SSLContext serverContext = SSLContext.getInstance(PROTOCOL);
+            serverContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            return serverContext;
+        } catch (final IOException e) {
+            LOG.warn("IOException - Failed to load keystore / truststore."
+                    + " Failed to initialize the server-side SSLContext", e);
+        } catch (final NoSuchAlgorithmException e) {
+            LOG.warn("NoSuchAlgorithmException - Unsupported algorithm."
+                    + " Failed to initialize the server-side SSLContext", e);
+        } catch (final CertificateException e) {
+            LOG.warn("CertificateException - Unable to access certificate (check password)."
+                    + " Failed to initialize the server-side SSLContext", e);
+        } catch (final Exception e) {
+            LOG.warn("Exception - Failed to initialize the server-side SSLContext", e);
+        }
+        //TODO try to use default SSLContext instance?
+        return null;
+    }
+}
+
diff --git a/pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/tls/SslKeyStore.java b/pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/tls/SslKeyStore.java
new file mode 100644 (file)
index 0000000..85c6b5a
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.pcep.impl.tls;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.impl.rev130627.PathType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class SslKeyStore {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SslKeyStore.class);
+
+    private SslKeyStore() {
+        throw new UnsupportedOperationException("Utility class shouldn't be instantiated");
+    }
+
+    /**
+     * InputStream instance of key - key location is on classpath or specific path
+     *
+     * @param filename
+     *          keystore location
+     * @param pathType
+     *          keystore location type - "classpath" or "path"
+     *
+     * @return key as InputStream
+     */
+    public static InputStream asInputStream(final String filename, final PathType pathType) {
+        InputStream in;
+        switch (pathType) {
+        case CLASSPATH:
+            in = SslKeyStore.class.getResourceAsStream(filename);
+            if (in == null) {
+                throw new IllegalStateException("KeyStore file not found: "
+                        + filename);
+            }
+            break;
+        case PATH:
+            LOG.debug("Current dir using System: {}", System.getProperty("user.dir"));
+            final File keystorefile = new File(filename);
+            try {
+                in = new FileInputStream(keystorefile);
+            } catch (FileNotFoundException e) {
+                throw new IllegalStateException("KeyStore file not found: "
+                        + filename,e);
+            }
+            break;
+        default:
+            throw new IllegalArgumentException("Unknown path type: " + pathType);
+        }
+        return in;
+    }
+}
+
index 6f166c0e03287bfae95524b3bdaa8543fe5f5496..6d531b45fde6e98f1a79b176827da2b58d2ff3c3 100644 (file)
@@ -35,6 +35,20 @@ module odl-pcep-impl-cfg {
             "Initial revision";
     }
 
+    typedef path-type {
+        type enumeration {
+            enum "PATH";
+            enum "CLASSPATH";
+        }
+    }
+
+    typedef store-type {
+        type enumeration {
+            enum "JKS";
+            enum "PKCS12";
+        }
+    }
+
     identity pcep-parser-base {
         base config:module-type;
         config:provided-service spi:extension;
@@ -115,6 +129,54 @@ module odl-pcep-impl-cfg {
                     }
                 }
             }
+
+            container tls {
+                leaf keystore {
+                    description "keystore location";
+                    type string;
+                    mandatory true;
+                }
+                leaf keystore-type {
+                    description "keystore type (JKS or PKCS12)";
+                    type store-type;
+                    mandatory true;
+                }
+                leaf keystore-path-type {
+                    description "keystore path type (CLASSPATH or PATH)";
+                    type path-type;
+                    mandatory true;
+                }
+                leaf keystore-password {
+                    description "password protecting keystore";
+                    type string;
+                    mandatory true;
+                }
+                leaf certificate-password {
+                    description "password protecting certificate";
+                    type string;
+                    mandatory true;
+                }
+                leaf truststore {
+                    description "truststore location";
+                    type string;
+                    mandatory true;
+                }
+                leaf truststore-type {
+                    description "truststore type (JKS or PKCS12)";
+                    type store-type;
+                    mandatory true;
+                }
+                leaf truststore-path-type {
+                    description "truststore path type (CLASSPATH or PATH)";
+                    type path-type;
+                    mandatory true;
+                }
+                leaf truststore-password {
+                    description "password protecting truststore";
+                    type string;
+                    mandatory true;
+                }
+            }
         }
     }
 
index fcc86a8d87504e2be88b329eb9dececeb32abe1b..ffc4af21e8b6071a976bc46aac34d8f400c255b2 100644 (file)
@@ -23,6 +23,8 @@ import org.opendaylight.controller.config.yang.netty.threadgroup.NettyThreadgrou
 import org.opendaylight.controller.config.yang.netty.threadgroup.NettyThreadgroupModuleMXBean;
 import org.opendaylight.controller.config.yang.pcep.spi.SimplePCEPExtensionProviderContextModuleFactory;
 import org.opendaylight.controller.config.yang.pcep.spi.SimplePCEPExtensionProviderContextModuleMXBean;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.impl.rev130627.PathType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.impl.rev130627.StoreType;
 
 public class PCEPDispatcherImplModuleTest extends AbstractConfigTest {
 
@@ -36,6 +38,10 @@ public class PCEPDispatcherImplModuleTest extends AbstractConfigTest {
     private static final String EXTENSION_INSTANCE_NAME = "pcep-extension-privider";
     private static final String EXTENSION_FACTORYNAME = SimplePCEPExtensionProviderContextModuleFactory.NAME;
 
+    private static final String STORE_PASSWORD = "opendaylight";
+    private static final String KEYSTORE = "ctl.jks";
+    private static final String TRUSTSTORE = "truststore.jks";
+
     @Before
     public void setUp() throws Exception {
         super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(this.mockedContext, new PCEPDispatcherImplModuleFactory(), new PCEPSessionProposalFactoryImplModuleFactory(), new NettyThreadgroupModuleFactory(), new SimplePCEPExtensionProviderContextModuleFactory()));
@@ -61,6 +67,105 @@ public class PCEPDispatcherImplModuleTest extends AbstractConfigTest {
         }
     }
 
+    @Test
+    public void testValidationExceptionCertificatePassword() throws Exception {
+        try {
+            createDispatcherInstance(1, createTls(null, KEYSTORE, STORE_PASSWORD, PathType.PATH, StoreType.JKS, TRUSTSTORE, STORE_PASSWORD,
+                    PathType.PATH, StoreType.JKS));
+            fail();
+        } catch (final ValidationException e) {
+            assertTrue(e.getMessage().contains("certificate password"));
+        }
+    }
+
+    @Test
+    public void testValidationExceptionKeystoreLocation() throws Exception {
+        try {
+            createDispatcherInstance(1, createTls(STORE_PASSWORD, null, STORE_PASSWORD, PathType.PATH, StoreType.JKS, TRUSTSTORE, STORE_PASSWORD,
+                    PathType.PATH, StoreType.JKS));
+            fail();
+        } catch (final ValidationException e) {
+            assertTrue(e.getMessage().contains("keystore location"));
+        }
+    }
+
+    @Test
+    public void testValidationExceptionKeystorePassword() throws Exception {
+        try {
+            createDispatcherInstance(1, createTls(STORE_PASSWORD, KEYSTORE, null, PathType.PATH, StoreType.JKS, TRUSTSTORE, STORE_PASSWORD,
+                    PathType.PATH, StoreType.JKS));
+            fail();
+        } catch (final ValidationException e) {
+            assertTrue(e.getMessage().contains("keystore password"));
+        }
+    }
+
+    @Test
+    public void testValidationExceptionKeystorePathType() throws Exception {
+        try {
+            createDispatcherInstance(1, createTls(STORE_PASSWORD, KEYSTORE, STORE_PASSWORD, null, StoreType.JKS, TRUSTSTORE, STORE_PASSWORD,
+                    PathType.PATH, StoreType.JKS));
+            fail();
+        } catch (final ValidationException e) {
+            assertTrue(e.getMessage().contains("keystore path type"));
+        }
+    }
+
+    @Test
+    public void testValidationExceptionKeystoreType() throws Exception {
+        try {
+            createDispatcherInstance(1, createTls(STORE_PASSWORD, KEYSTORE, STORE_PASSWORD, PathType.PATH, null, TRUSTSTORE, STORE_PASSWORD,
+                    PathType.PATH, StoreType.JKS));
+            fail();
+        } catch (final ValidationException e) {
+            assertTrue(e.getMessage().contains("keystore type"));
+        }
+    }
+
+    @Test
+    public void testValidationExceptionTruststoreLocation() throws Exception {
+        try {
+            createDispatcherInstance(1, createTls(STORE_PASSWORD, KEYSTORE, STORE_PASSWORD, PathType.PATH, StoreType.JKS, null, STORE_PASSWORD,
+                    PathType.PATH, StoreType.JKS));
+            fail();
+        } catch (final ValidationException e) {
+            assertTrue(e.getMessage().contains("truststore location"));
+        }
+    }
+
+    @Test
+    public void testValidationExceptionTruststorePassword() throws Exception {
+        try {
+            createDispatcherInstance(1, createTls(STORE_PASSWORD, KEYSTORE, STORE_PASSWORD, PathType.PATH, StoreType.JKS, TRUSTSTORE, null,
+                    PathType.PATH, StoreType.JKS));
+            fail();
+        } catch (final ValidationException e) {
+            assertTrue(e.getMessage().contains("truststore password"));
+        }
+    }
+
+    @Test
+    public void testValidationExceptionTruststorePathType() throws Exception {
+        try {
+            createDispatcherInstance(1, createTls(STORE_PASSWORD, KEYSTORE, STORE_PASSWORD, PathType.PATH, StoreType.JKS, TRUSTSTORE, STORE_PASSWORD,
+                    null, StoreType.JKS));
+            fail();
+        } catch (final ValidationException e) {
+            assertTrue(e.getMessage().contains("truststore path type"));
+        }
+    }
+
+    @Test
+    public void testValidationExceptionTruststoreType() throws Exception {
+        try {
+            createDispatcherInstance(1, createTls(STORE_PASSWORD, KEYSTORE, STORE_PASSWORD, PathType.PATH, StoreType.JKS, TRUSTSTORE, STORE_PASSWORD,
+                    PathType.PATH, null));
+            fail();
+        } catch (final ValidationException e) {
+            assertTrue(e.getMessage().contains("truststore type"));
+        }
+    }
+
     @Test
     public void testCreateBean() throws Exception {
         final CommitStatus status = createDispatcherInstance(5);
@@ -91,12 +196,26 @@ public class PCEPDispatcherImplModuleTest extends AbstractConfigTest {
         assertStatus(status, 0, 1, 4);
     }
 
+    @Test
+    public void testCreateBeanWithTls() throws Exception {
+        final CommitStatus status = createDispatcherInstance(5, createTls(STORE_PASSWORD, KEYSTORE, STORE_PASSWORD, PathType.PATH, StoreType.JKS,
+                TRUSTSTORE, STORE_PASSWORD, PathType.PATH, StoreType.JKS));
+        assertBeanCount(1, FACTORY_NAME);
+        assertStatus(status, 5, 0, 0);
+    }
+
     private CommitStatus createDispatcherInstance(final Integer maxUnknownMessages) throws Exception {
         final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
         createDispatcherInstance(transaction, maxUnknownMessages);
         return transaction.commit();
     }
 
+    private CommitStatus createDispatcherInstance(final Integer maxUnknownMessages, final Tls tls) throws Exception {
+        final ConfigTransactionJMXClient transaction = this.configRegistryClient.createTransaction();
+        createDispatcherInstance(transaction, maxUnknownMessages, tls);
+        return transaction.commit();
+    }
+
     public static ObjectName createDispatcherInstance(final ConfigTransactionJMXClient transaction, final Integer maxUnknownMessages)
             throws Exception {
         final ObjectName nameCreated = transaction.createModule(FACTORY_NAME, INSTANCE_NAME);
@@ -109,6 +228,14 @@ public class PCEPDispatcherImplModuleTest extends AbstractConfigTest {
         return nameCreated;
     }
 
+    private static ObjectName createDispatcherInstance(final ConfigTransactionJMXClient transaction, final Integer maxUnknownMessages,
+            final Tls tls) throws Exception {
+        final ObjectName objName = createDispatcherInstance(transaction, maxUnknownMessages);
+        final PCEPDispatcherImplModuleMXBean mxBean = transaction.newMXBeanProxy(objName, PCEPDispatcherImplModuleMXBean.class);
+        mxBean.setTls(tls);
+        return objName;
+    }
+
     private static ObjectName createExtensionsInstance(final ConfigTransactionJMXClient transaction) throws InstanceAlreadyExistsException {
         final ObjectName nameCreated = transaction.createModule(EXTENSION_FACTORYNAME, EXTENSION_INSTANCE_NAME);
         transaction.newMXBeanProxy(nameCreated, SimplePCEPExtensionProviderContextModuleMXBean.class);
@@ -124,4 +251,20 @@ public class PCEPDispatcherImplModuleTest extends AbstractConfigTest {
         return nameCreated;
     }
 
+    private static Tls createTls(final String certificatePassword, final String keystore, final String keystorePassword,
+            final PathType keystorePathType, final StoreType keystoreType, final String truststore,
+            final String truststorePassword, final PathType truststorePathType, final StoreType truststoreType) {
+        final Tls tls = new Tls();
+        tls.setCertificatePassword(certificatePassword);
+        tls.setKeystore(keystore);
+        tls.setKeystorePassword(keystorePassword);
+        tls.setKeystorePathType(keystorePathType);
+        tls.setKeystoreType(keystoreType);
+        tls.setTruststore(truststore);
+        tls.setTruststorePassword(truststorePassword);
+        tls.setTruststorePathType(truststorePathType);
+        tls.setTruststoreType(truststoreType);
+        return tls;
+    }
+
 }
index bb491f59006eb8a132ea186a1123157f3a88e451..8eac65ae0b35c85632ad3dc2432f1b0d38bf5c86 100644 (file)
@@ -34,8 +34,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.mes
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.KeepaliveBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Open;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.OpenBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Starttls;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.StarttlsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.keepalive.message.KeepaliveMessageBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.message.OpenMessageBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.start.tls.message.StartTlsMessageBuilder;
 import org.opendaylight.yangtools.yang.binding.Notification;
 
 public class AbstractPCEPSessionTest {
@@ -63,6 +66,8 @@ public class AbstractPCEPSessionTest {
 
     protected Open openMsg;
 
+    protected Starttls startTlsMsg;
+
     protected Keepalive kaMsg;
 
     protected SimpleSessionListener listener;
@@ -87,6 +92,7 @@ public class AbstractPCEPSessionTest {
         doReturn(true).when(this.future).cancel(false);
         doReturn(this.future).when(this.eventLoop).schedule(any(Runnable.class), any(long.class), any(TimeUnit.class));
         doReturn(this.pipeline).when(this.pipeline).replace(any(ChannelHandler.class), any(String.class), any(ChannelHandler.class));
+        doReturn(this.pipeline).when(this.pipeline).addFirst(any(ChannelHandler.class));
         doReturn(true).when(this.channel).isActive();
         doReturn(mock(ChannelFuture.class)).when(this.channel).close();
         doReturn(new InetSocketAddress(IP_ADDRESS, 4189)).when(this.channel).remoteAddress();
@@ -96,6 +102,8 @@ public class AbstractPCEPSessionTest {
                         new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.OpenBuilder().setDeadTimer(
                                 DEADTIMER).setKeepalive(KEEP_ALIVE).setSessionId((short) 0).build()).build()).build();
         this.kaMsg = new KeepaliveBuilder().setKeepaliveMessage(new KeepaliveMessageBuilder().build()).build();
+        this.startTlsMsg = new StarttlsBuilder().setStartTlsMessage(new StartTlsMessageBuilder().build()).build();
+
 
         this.listener = new SimpleSessionListener();
     }
index 55a37946632721c4f872020ea4cb0de283440ad5..4cb597b1aaf515e16d4182e396ccb6038b3e8714 100644 (file)
@@ -16,23 +16,30 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
+import org.opendaylight.controller.config.yang.pcep.impl.Tls;
 import org.opendaylight.protocol.pcep.spi.PCEPErrors;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Keepalive;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Open;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Pcerr;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.message.rev131007.Starttls;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.OpenMessage;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.OpenBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.pcerr.message.pcerr.message.Errors;
 import org.opendaylight.yangtools.yang.binding.Notification;
 
 public class FiniteStateMachineTest extends AbstractPCEPSessionTest {
 
     private DefaultPCEPSessionNegotiator serverSession;
+    private DefaultPCEPSessionNegotiator tlsSessionNegotiator;
 
     @Before
     public void setup() {
-        final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Open localPrefs = new org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.OpenBuilder().setKeepalive(
+        final org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.pcep.types.rev131005.open.object.Open localPrefs = new OpenBuilder().setKeepalive(
                 (short) 1).build();
-        this.serverSession = new DefaultPCEPSessionNegotiator(new DefaultPromise<PCEPSessionImpl>(GlobalEventExecutor.INSTANCE), this.channel, this.listener, (short) 1, 20, localPrefs);
+        this.serverSession = new DefaultPCEPSessionNegotiator(new DefaultPromise<PCEPSessionImpl>(GlobalEventExecutor.INSTANCE),
+                this.channel, this.listener, (short) 1, 20, localPrefs);
+        this.tlsSessionNegotiator = new DefaultPCEPSessionNegotiator(new DefaultPromise<PCEPSessionImpl>(GlobalEventExecutor.INSTANCE),
+                this.channel, this.listener, (short) 1, 20, localPrefs, new Tls());
     }
 
     /**
@@ -53,6 +60,66 @@ public class FiniteStateMachineTest extends AbstractPCEPSessionTest {
         assertEquals(this.serverSession.getState(), DefaultPCEPSessionNegotiator.State.FINISHED);
     }
 
+    /**
+     * Establish PCEPS TLS connection with peer
+     */
+    @Test
+    public void testEstablishTLS() {
+        final DefaultPCEPSessionNegotiator negotiator = new DefaultPCEPSessionNegotiator(new DefaultPromise<PCEPSessionImpl>(GlobalEventExecutor.INSTANCE),
+                this.channel, this.listener, (short) 1, 20, new OpenBuilder().setKeepalive((short) 1).build(),
+                SslContextFactoryTest.createTlsConfig());
+        negotiator.channelActive(null);
+        assertEquals(1, this.msgsSend.size());
+        assertTrue(this.msgsSend.get(0) instanceof Starttls);
+        assertEquals(DefaultPCEPSessionNegotiator.State.START_TLS_WAIT, negotiator.getState());
+        negotiator.handleMessage(this.startTlsMsg);
+        assertEquals(DefaultPCEPSessionNegotiator.State.OPEN_WAIT, negotiator.getState());
+        assertEquals(2, this.msgsSend.size());
+        assertTrue(this.msgsSend.get(1) instanceof Open);
+        negotiator.handleMessage(this.openMsg);
+        assertEquals(DefaultPCEPSessionNegotiator.State.KEEP_WAIT, negotiator.getState());
+    }
+
+    /**
+     * As Tls is not configured properly, PCE will send error PCEPErrors.NOT_POSSIBLE_WITHOUT_TLS
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testFailedToEstablishTLS() throws Exception {
+        this.tlsSessionNegotiator.channelActive(null);
+        assertEquals(1, this.msgsSend.size());
+        assertTrue(this.msgsSend.get(0) instanceof Starttls);
+        assertEquals(DefaultPCEPSessionNegotiator.State.START_TLS_WAIT, this.tlsSessionNegotiator.getState());
+        this.tlsSessionNegotiator.handleMessage(this.startTlsMsg);
+        assertEquals(2, this.msgsSend.size());
+        assertTrue(this.msgsSend.get(1) instanceof Pcerr);
+        final Errors obj = ((Pcerr) this.msgsSend.get(1)).getPcerrMessage().getErrors().get(0);
+        assertEquals(PCEPErrors.NOT_POSSIBLE_WITHOUT_TLS.getErrorType(), obj.getErrorObject().getType().shortValue());
+        assertEquals(PCEPErrors.NOT_POSSIBLE_WITHOUT_TLS.getErrorValue(), obj.getErrorObject().getValue().shortValue());
+        assertEquals(DefaultPCEPSessionNegotiator.State.FINISHED, this.tlsSessionNegotiator.getState());
+    }
+
+    /**
+     * As PCE does not receive expected message (StartTLS), error PCEPErrors.NON_STARTTLS_MSG_RCVD is send
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testTLSUnexpectedMessage() {
+        this.tlsSessionNegotiator.channelActive(null);
+        assertEquals(1, this.msgsSend.size());
+        assertTrue(this.msgsSend.get(0) instanceof Starttls);
+        assertEquals(DefaultPCEPSessionNegotiator.State.START_TLS_WAIT, this.tlsSessionNegotiator.getState());
+        this.tlsSessionNegotiator.handleMessage(this.openMsg);
+        assertEquals(2, this.msgsSend.size());
+        assertTrue(this.msgsSend.get(1) instanceof Pcerr);
+        final Errors obj = ((Pcerr) this.msgsSend.get(1)).getPcerrMessage().getErrors().get(0);
+        assertEquals(PCEPErrors.NON_STARTTLS_MSG_RCVD.getErrorType(), obj.getErrorObject().getType().shortValue());
+        assertEquals(PCEPErrors.NON_STARTTLS_MSG_RCVD.getErrorValue(), obj.getErrorObject().getValue().shortValue());
+        assertEquals(this.tlsSessionNegotiator.getState(), DefaultPCEPSessionNegotiator.State.FINISHED);
+    }
+
     /**
      * Mock PCE does not accept session characteristics the first time.
      *
diff --git a/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/SslContextFactoryTest.java b/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/SslContextFactoryTest.java
new file mode 100644 (file)
index 0000000..6eada3f
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.protocol.pcep.impl;
+
+import static org.junit.Assert.assertNotNull;
+
+import javax.net.ssl.SSLContext;
+import org.junit.Test;
+import org.opendaylight.controller.config.yang.pcep.impl.Tls;
+import org.opendaylight.protocol.pcep.impl.tls.SslContextFactory;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.impl.rev130627.PathType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.pcep.impl.rev130627.StoreType;
+
+public class SslContextFactoryTest {
+
+    @Test
+    public void testSslContextFactory() {
+        final SslContextFactory sslContextFactory = new SslContextFactory(createTlsConfig());
+        final SSLContext sslContext = sslContextFactory.getServerContext();
+        assertNotNull(sslContext);
+    }
+
+    public static Tls createTlsConfig() {
+        final Tls tlsConfig = new Tls();
+        tlsConfig.setCertificatePassword("opendaylight");
+        tlsConfig.setKeystore("/exemplary-ctlKeystore");
+        tlsConfig.setKeystorePassword("opendaylight");
+        tlsConfig.setKeystorePathType(PathType.CLASSPATH);
+        tlsConfig.setKeystoreType(StoreType.JKS);
+        tlsConfig.setTruststore("/exemplary-ctlTrustStore");
+        tlsConfig.setTruststorePassword("opendaylight");
+        tlsConfig.setTruststorePathType(PathType.CLASSPATH);
+        tlsConfig.setTruststoreType(StoreType.JKS);
+        return tlsConfig;
+    }
+
+}
diff --git a/pcep/impl/src/test/resources/exemplary-ctlKeystore b/pcep/impl/src/test/resources/exemplary-ctlKeystore
new file mode 100644 (file)
index 0000000..c731097
Binary files /dev/null and b/pcep/impl/src/test/resources/exemplary-ctlKeystore differ
diff --git a/pcep/impl/src/test/resources/exemplary-ctlTrustStore b/pcep/impl/src/test/resources/exemplary-ctlTrustStore
new file mode 100644 (file)
index 0000000..e14e21a
Binary files /dev/null and b/pcep/impl/src/test/resources/exemplary-ctlTrustStore differ
index d6045916531fd0300754cb04a4216b2a6fefadd5..3598605fdaa2d9d0c03684ddf3bfcddd5e4f7661 100644 (file)
@@ -299,7 +299,32 @@ public enum PCEPErrors {
     /**
      * MONITORING object missing
      */
-    MONITORING_OBJECT_MISSING(6, 4);
+    MONITORING_OBJECT_MISSING(6, 4),
+    /**
+     * Reception of StartTLS after any PCEP exchange
+     * TODO: error code to be assigned by IANA
+     */
+    STARTTLS_RCVD_INCORRECTLY(30, 1),
+    /**
+     * Reception of non-StartTLS or non-PCErr message
+     * TODO: error code to be assigned by IANA
+     */
+    NON_STARTTLS_MSG_RCVD(30, 2),
+    /**
+     * Failure, connection without TLS not possible
+     * TODO: error code to be assigned by IANA
+     */
+    NOT_POSSIBLE_WITHOUT_TLS(30, 3),
+    /**
+     * Failure, connection without TLS possible
+     * TODO: error code to be assigned by IANA
+     */
+    POSSIBLE_WITHOUT_TLS(30, 4),
+    /**
+     * No StartTLS message before StartTLSWait timer expired
+     * TODO: error code to be assigned by IANA
+     */
+    STARTTLS_TIMER_EXP(30, 5);
 
     private PCEPErrorIdentifier errorId;
     private static final Map<PCEPErrorIdentifier, PCEPErrors> VALUE_MAP;