Add SwitchCertificate attributes in TLS failure notification 13/91313/10
authorHarshini M <hm@luminanetworks.com>
Mon, 13 Jul 2020 15:39:01 +0000 (21:09 +0530)
committerHarshini M <hm@luminanetworks.com>
Wed, 22 Jul 2020 15:11:33 +0000 (20:41 +0530)
JIRA : OPNFLWPLUG-1094

Change-Id: I00aa25b3dfc33d10333a43b8bc67a2515f8fc874
Signed-off-by: Harshini M <hm@luminanetworks.com>
13 files changed:
model/model-flow-service/src/main/yang/node-ssl-connection-errors.yang
openflowjava/openflow-protocol-api/src/main/java/org/opendaylight/openflowjava/protocol/api/connection/ConnectionAdapter.java
openflowjava/openflow-protocol-api/src/main/yang/system-notifications.yang
openflowjava/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/SslContextFactory.java
openflowjava/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/TcpChannelInitializer.java
openflowjava/openflow-protocol-impl/src/main/java/org/opendaylight/openflowjava/protocol/impl/core/connection/ConnectionAdapterImpl.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/configuration/ConfigurationProperty.java
openflowplugin-api/src/main/yang/openflow-provider-config.yang
openflowplugin-blueprint-config/src/main/resources/initial/openflowplugin.cfg
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/configuration/OpenFlowProviderConfigImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/ConnectionManagerImpl.java
openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/listener/SystemNotificationsListenerImpl.java
openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/connection/ConnectionManagerImplTest.java

index 72e6a66cea26d2bbae535f7c9a818f6e2489a6b9..954dd11c6101deb90daaee42f6266b1a08c12b58 100644 (file)
@@ -4,6 +4,8 @@ module node-ssl-connection-error {
 
     import ietf-inet-types {prefix inet; revision-date "2013-07-15";}
 
+    import system-notifications { prefix system-notifications; revision-date "2013-09-27"; }
+
     description "Openflow node ssl connection error.";
 
     revision "2019-07-23" {
@@ -42,6 +44,9 @@ module node-ssl-connection-error {
     notification ssl-error {
         description "Model for Node SSL Error Messages.";
         uses error-message;
+        container switch-certificate {
+            uses system-notifications:switch-certificate;
+        }
     }
 
 }
index af560b75568072c84fe84f3e68e87fa295312443..4de37851dbebb014f70e2fc3751eefe99f2c2e29 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.openflowjava.protocol.api.connection;
 import com.google.common.annotations.Beta;
 import java.math.BigInteger;
 import java.net.InetSocketAddress;
+import java.security.cert.X509Certificate;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import org.opendaylight.openflowjava.protocol.api.extensibility.AlienMessageListener;
@@ -77,6 +78,12 @@ public interface ConnectionAdapter extends OpenflowProtocolService {
      */
     void fireConnectionReadyNotification();
 
+    /**
+     * Notify listener about switch certificate information.
+     * @param switchcertificate X509Certificate of switch
+     */
+    void onSwitchCertificateIdentified(X509Certificate switchcertificate);
+
     /**
      * Set listener for connection became ready-to-use event.
      *
index 0cb639b9db70fd78e49e4ce20e5f788176706878..83421ca08e49e6acc0f9a9b330cf24f05bca4a3b 100644 (file)
     namespace "urn:opendaylight:openflow:system";
     prefix "ofs";
 
+    import ietf-yang-types {prefix yang; revision-date "2013-07-15";}
+
     revision "2013-09-27" {
         description "#NOT_PUBLISHED# Model of system messages used in OpenFlow Protocol Library";
     }
 
+    grouping x500-principal {
+        leaf country {
+           type string;
+        }
+        leaf state {
+           type string;
+        }
+        leaf locality {
+           type string;
+        }
+        leaf organization {
+           type string;
+        }
+        leaf organization-unit {
+           type string;
+        }
+        leaf common-name {
+           type string;
+        }
+    }
+    grouping switch-certificate {
+        container subject {
+            uses x500-principal;
+        }
+        container issuer {
+            uses x500-principal;
+        }
+        leaf valid-from {
+            type yang:date-and-time;
+        }
+        leaf valid-to {
+            type yang:date-and-time;
+        }
+        leaf serial-number {
+            type uint64;
+        }
+        leaf-list subject-alternate-names {
+            type string;
+        }
+    }
+
     notification disconnect-event {
         description "Disconnect notification";
         leaf info {
         leaf info {
             type string;
         }
+        container switch-certificate{
+            uses switch-certificate;
+        }
     }
 
 
-}
\ No newline at end of file
+}
index 993fbedea745dbff6dd3685b08bd71e94a793bbf..4ed7618cfaa951d551b84c15f376f6cd233529d0 100644 (file)
@@ -9,6 +9,7 @@
 package org.opendaylight.openflowjava.protocol.impl.core;
 
 import java.io.IOException;
+import java.net.Socket;
 import java.security.KeyManagementException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
@@ -16,9 +17,12 @@ import java.security.NoSuchAlgorithmException;
 import java.security.Security;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
 import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedTrustManager;
 import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -34,6 +38,8 @@ public class SslContextFactory {
     // Use "TLSv1", "TLSv1.1", "TLSv1.2" for specific TLS version
     private static final String PROTOCOL = "TLS";
     private final TlsConfiguration tlsConfig;
+    private static X509Certificate switchCertificate = null;
+    private static boolean isCustomTrustManagerEnabled;
 
     private static final Logger LOG = LoggerFactory
             .getLogger(SslContextFactory.class);
@@ -49,6 +55,22 @@ public class SslContextFactory {
         this.tlsConfig = tlsConfig;
     }
 
+    public X509Certificate getSwitchCertificate() {
+        return switchCertificate;
+    }
+
+    public boolean isCustomTrustManagerEnabled() {
+        return isCustomTrustManagerEnabled;
+    }
+
+    public static void setSwitchCertificate(X509Certificate certificate) {
+        switchCertificate = certificate;
+    }
+
+    public static void setIsCustomTrustManagerEnabled(boolean customTrustManagerEnabled) {
+        isCustomTrustManagerEnabled = customTrustManagerEnabled;
+    }
+
     public SSLContext getServerContext() {
         String algorithm = Security
                 .getProperty("ssl.KeyManagerFactory.algorithm");
@@ -70,7 +92,16 @@ public class SslContextFactory {
             tmf.init(ts);
 
             serverContext = SSLContext.getInstance(PROTOCOL);
-            serverContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            if (isCustomTrustManagerEnabled) {
+                CustomTrustManager[] customTrustManager = new CustomTrustManager[tmf.getTrustManagers().length];
+                for (int i = 0; i < tmf.getTrustManagers().length; i++) {
+                    customTrustManager[i] = new CustomTrustManager((X509ExtendedTrustManager)
+                            tmf.getTrustManagers()[i]);
+                }
+                serverContext.init(kmf.getKeyManagers(), customTrustManager, null);
+            } else {
+                serverContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            }
         } catch (IOException e) {
             LOG.warn("IOException - Failed to load keystore / truststore."
                     + " Failed to initialize the server-side SSLContext", e);
@@ -85,4 +116,59 @@ public class SslContextFactory {
         }
         return serverContext;
     }
+
+
+    private static class CustomTrustManager extends X509ExtendedTrustManager {
+        private final X509ExtendedTrustManager trustManager;
+
+        CustomTrustManager(final X509ExtendedTrustManager trustManager) {
+            this.trustManager = trustManager;
+        }
+
+        @Override
+        public void checkClientTrusted(final X509Certificate[] x509Certificates, final String authType,
+                final Socket socket) throws CertificateException {
+            SslContextFactory.setSwitchCertificate(x509Certificates[0]);
+            trustManager.checkClientTrusted(x509Certificates, authType, socket);
+        }
+
+        @Override
+        public void checkClientTrusted(final X509Certificate[] x509Certificates, final String authType)
+                throws CertificateException {
+            SslContextFactory.setSwitchCertificate(x509Certificates[0]);
+            trustManager.checkClientTrusted(x509Certificates, authType);
+        }
+
+        @Override
+        public void checkClientTrusted(final X509Certificate[] x509Certificates, final String authType,
+                final SSLEngine sslEngine) throws CertificateException {
+            SslContextFactory.setSwitchCertificate(x509Certificates[0]);
+            trustManager.checkClientTrusted(x509Certificates, authType, sslEngine);
+        }
+
+        @Override
+        public void checkServerTrusted(final X509Certificate[] x509Certificates, final String authType,
+                final SSLEngine sslEngine) throws CertificateException {
+            trustManager.checkServerTrusted(x509Certificates, authType, sslEngine);
+        }
+
+        @Override
+        public void checkServerTrusted(final X509Certificate[] x509Certificates, final String authType)
+                throws CertificateException {
+            trustManager.checkServerTrusted(x509Certificates, authType);
+        }
+
+        @Override
+        public void checkServerTrusted(final X509Certificate[] x509Certificates, final String authType,
+                final Socket socket) throws CertificateException {
+            trustManager.checkServerTrusted(x509Certificates, authType, socket);
+        }
+
+        @Override
+        public X509Certificate[] getAcceptedIssuers() {
+            return trustManager.getAcceptedIssuers();
+        }
+
+    }
+
 }
index 40ade03cbc8954a32ff0e751bd24c16db1a071a4..4eb27184c8ba3773414a99d2c6b92c8394da206f 100644 (file)
@@ -96,6 +96,10 @@ public class TcpChannelInitializer extends ProtocolChannelInitializer<SocketChan
                 final SslHandler ssl = new SslHandler(engine);
                 final Future<Channel> handshakeFuture = ssl.handshakeFuture();
                 final ConnectionFacade finalConnectionFacade = connectionFacade;
+                if (sslFactory.isCustomTrustManagerEnabled()) {
+                    handshakeFuture.addListener(future -> finalConnectionFacade
+                            .onSwitchCertificateIdentified(sslFactory.getSwitchCertificate()));
+                }
                 handshakeFuture.addListener(future -> finalConnectionFacade.fireConnectionReadyNotification());
                 ch.pipeline().addLast(PipelineHandlers.SSL_HANDLER.name(), ssl);
             }
index cb6ca66b4421463c90a08c14bb519844149bea84..85cf37610df7cbd3e78b6bf7e70e9f86537c95a5 100644 (file)
@@ -13,13 +13,25 @@ import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
 import java.math.BigInteger;
 import java.net.InetSocketAddress;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionReadyListener;
 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandler;
 import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandlerRegistration;
 import org.opendaylight.openflowjava.protocol.api.extensibility.AlienMessageListener;
 import org.opendaylight.openflowjava.protocol.impl.core.OFVersionDetector;
 import org.opendaylight.openflowjava.protocol.impl.core.PipelineHandlers;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoRequestMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessage;
@@ -33,8 +45,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.DisconnectEvent;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SslConnectionError;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SslConnectionErrorBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SwitchIdleEvent;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SystemNotificationsListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927._switch.certificate.IssuerBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927._switch.certificate.SubjectBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.ssl.connection.error.SwitchCertificate;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.ssl.connection.error.SwitchCertificateBuilder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.slf4j.Logger;
@@ -58,6 +75,7 @@ public class ConnectionAdapterImpl extends AbstractConnectionAdapterStatistics i
     private BigInteger datapathId;
     private ExecutorService executorService;
     private final boolean useBarrier;
+    private X509Certificate switchCertificate;
     /**
      * Default constructor.
      * @param channel the channel to be set - used for communication
@@ -111,7 +129,9 @@ public class ConnectionAdapterImpl extends AbstractConnectionAdapterStatistics i
             } else if (message instanceof SwitchIdleEvent) {
                 systemListener.onSwitchIdleEvent((SwitchIdleEvent) message);
             } else if (message instanceof SslConnectionError) {
-                systemListener.onSslConnectionError((SslConnectionError) message);
+                systemListener.onSslConnectionError((SslConnectionError) new SslConnectionErrorBuilder()
+                        .setInfo(((SslConnectionError) message).getInfo())
+                        .setSwitchCertificate(buildSwitchCertificate()).build());
             // OpenFlow messages
             } else if (message instanceof EchoRequestMessage) {
                 if (outputManager != null) {
@@ -194,6 +214,11 @@ public class ConnectionAdapterImpl extends AbstractConnectionAdapterStatistics i
         executorService.execute(() -> connectionReadyListener.onConnectionReady());
     }
 
+    @Override
+    public void onSwitchCertificateIdentified(X509Certificate switchcertificate) {
+        this.switchCertificate = switchcertificate;
+    }
+
     @Override
     public <T extends OutboundQueueHandler> OutboundQueueHandlerRegistration<T> registerOutboundQueueHandler(
             final T handler, final int maxQueueDepth, final long maxBarrierNanos) {
@@ -236,6 +261,63 @@ public class ConnectionAdapterImpl extends AbstractConnectionAdapterStatistics i
         LOG.debug("PacketIn filtering {}abled", enabled ? "en" : "dis");
     }
 
+    private SwitchCertificate buildSwitchCertificate() {
+        if (switchCertificate != null) {
+            SwitchCertificateBuilder switchCertificateBuilder = new SwitchCertificateBuilder();
+            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'-00:00'");
+            formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
+            try {
+                Map<String, String> subjectMap = new ConcurrentHashMap<>();
+                Map<String, String> issuerMap = new ConcurrentHashMap<>();
+                subjectMap.putAll(new LdapName(switchCertificate.getSubjectX500Principal().getName())
+                        .getRdns().stream()
+                        .collect(Collectors.toMap(rdn -> rdn.getType(), rdn -> rdn.getValue().toString())));
+                issuerMap.putAll(new LdapName(switchCertificate.getIssuerX500Principal().getName())
+                        .getRdns().stream()
+                        .collect(Collectors.toMap(rdn -> rdn.getType(), rdn -> rdn.getValue().toString())));
+                SubjectBuilder subjectBuilder = new SubjectBuilder();
+                subjectBuilder.setCommonName(subjectMap.get("CN"));
+                subjectBuilder.setCountry(subjectMap.get("C"));
+                subjectBuilder.setLocality(subjectMap.get("L"));
+                subjectBuilder.setOrganization(subjectMap.get("O"));
+                subjectBuilder.setOrganizationUnit(subjectMap.get("OU"));
+                subjectBuilder.setState(subjectMap.get("ST"));
+                IssuerBuilder issuerBuilder = new IssuerBuilder();
+                issuerBuilder.setCommonName(issuerMap.get("CN"));
+                issuerBuilder.setCountry(issuerMap.get("C"));
+                issuerBuilder.setLocality(issuerMap.get("L"));
+                issuerBuilder.setOrganization(issuerMap.get("O"));
+                issuerBuilder.setOrganizationUnit(issuerMap.get("OU"));
+                issuerBuilder.setState(issuerMap.get("ST"));
+                switchCertificateBuilder.setSubject(subjectBuilder.build());
+                switchCertificateBuilder.setIssuer(issuerBuilder.build());
+            } catch (InvalidNameException e) {
+                LOG.error("Exception ", e);
+            }
+            switchCertificateBuilder.setSerialNumber(switchCertificate.getSerialNumber());
+            try {
+                if (switchCertificate.getSubjectAlternativeNames() != null) {
+                    List<String> subjectAlternateNames = new ArrayList<>();
+                    switchCertificate.getSubjectAlternativeNames().forEach(generalName -> {
+                        final Object value = generalName.get(1);
+                        if (value instanceof String) {
+                            subjectAlternateNames.add(((String) value));
+                        }
+                    });
+                    switchCertificateBuilder.setSubjectAlternateNames(subjectAlternateNames);
+                } else {
+                    switchCertificateBuilder.setSubjectAlternateNames(null);
+                }
+            } catch (CertificateParsingException e) {
+                LOG.error("Error encountered while parsing certificate ", e);
+            }
+            switchCertificateBuilder.setValidFrom(new DateAndTime(formatter.format(switchCertificate.getNotBefore())));
+            switchCertificateBuilder.setValidTo(new DateAndTime(formatter.format(switchCertificate.getNotAfter())));
+            return switchCertificateBuilder.build();
+        }
+        return null;
+    }
+
     @Override
     public void setDatapathId(final BigInteger datapathId) {
         this.datapathId = datapathId;
index 4a5a58a563fd8e18f05403d30bd908611e7b7ecd..2b39f24ab72aa1b78af3669889f30e34d030756b 100644 (file)
@@ -123,7 +123,12 @@ public enum ConfigurationProperty {
     /**
      * Delay for Device removal from Operational DataStore.
      */
-    DEVICE_DATASTORE_REMOVAL_DELAY;
+    DEVICE_DATASTORE_REMOVAL_DELAY,
+    /**
+     * Enable or disable customtrustmanager which adds switch certificate attributes to TLS
+     * failure notification property type.
+     */
+    ENABLE_CUSTOM_TRUST_MANAGER;
 
     private static final Map<String, ConfigurationProperty> KEY_VALUE_MAP;
 
index 66645a52f72a2c7f0017598a43a2c7b143df026e..775dece99c717eaeda041924a20e1f5d06d07d4a 100644 (file)
@@ -221,5 +221,12 @@ module openflow-provider-config {
             type non-zero-uint32-type;
             default 500;
         }
+
+        leaf enable-custom-trust-manager {
+            description "When true would use customtrustmanager to get switch certificate for TLS
+            authentication failure notification. ";
+            type boolean;
+            default "false";
+       }
     }
 }
index 9306919e728a211a201515effba390874603aba2..ef35148f3f2e16c061a99eefe7fa22b566066832 100644 (file)
 #
 # device-datastore-removal-delay=500
 
+#
+# When true, uses customtrustmanager to add switch certificate attributes to TLS authentification failure
+# notification
+#
+# enable-custom-trust-manager=false
+
 #############################################################################
 #                                                                           #
 #            Forwarding Rule Manager Application Configuration              #
index a959f6972c97bc1cfffdc1647c8e7e18351f29f0..17e77afea9b5e4a23d54840ea4990bdaa1cb1df9 100644 (file)
@@ -194,4 +194,10 @@ public class OpenFlowProviderConfigImpl implements OpenflowProviderConfig {
 
         return new NonZeroUint32Type(property);
     }
+
+    @Override
+    public Boolean isEnableCustomTrustManager() {
+        return service.getProperty(ConfigurationProperty.ENABLE_CUSTOM_TRUST_MANAGER.toString(),
+                Boolean::valueOf);
+    }
 }
index e2f9e2b881134743d4bf63b2a4f9800300600199..90b4841674347d79e2879de408f45ab186170ba2 100644 (file)
@@ -29,6 +29,7 @@ import org.opendaylight.mdsal.binding.api.NotificationPublishService;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionReadyListener;
+import org.opendaylight.openflowjava.protocol.impl.core.SslContextFactory;
 import org.opendaylight.openflowplugin.api.OFConstants;
 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
 import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionManager;
@@ -117,6 +118,7 @@ public class ConnectionManagerImpl implements ConnectionManager {
         final SystemNotificationsListener systemListener = new SystemNotificationsListenerImpl(connectionContext,
                 config.getEchoReplyTimeout().getValue().toJava(), executorService, notificationPublishService);
         connectionAdapter.setSystemListener(systemListener);
+        SslContextFactory.setIsCustomTrustManagerEnabled(config.isEnableCustomTrustManager());
 
         LOG.trace("connection ballet finished");
     }
index 1efac4a99ef581f1da4d5ce0836bd218132322fd..8f5f48ebbcfb3cba6c7d86c93cc8440882bf8d0a 100644 (file)
@@ -23,6 +23,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.ssl.connection.error.service.rev190723.SslErrorBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.ssl.connection.error.service.rev190723.SslErrorType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.node.ssl.connection.error.service.rev190723.ssl.error.SwitchCertificateBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
@@ -146,12 +147,18 @@ public class SystemNotificationsListenerImpl implements SystemNotificationsListe
             ip = IpAddressBuilder.getDefaultInstance(
                     connectionContext.getConnectionAdapter().getRemoteAddress().getAddress().getHostAddress());
         }
+        SwitchCertificateBuilder switchCertificateBuilder = new SwitchCertificateBuilder();
+        if (notification.getSwitchCertificate() != null) {
+            switchCertificateBuilder = new SwitchCertificateBuilder(notification.getSwitchCertificate());
+        }
         notificationPublishService
                 .offerNotification(
                         new SslErrorBuilder().setType(SslErrorType.SslConFailed)
                                 .setCode(SslErrorType.SslConFailed.getIntValue())
                                 .setNodeIpAddress(ip)
                                 .setData(notification.getInfo())
+                                .setSwitchCertificate(notification.getSwitchCertificate() != null
+                                        ? switchCertificateBuilder.build() : null)
                                 .build());
     }
 }
index 09703be1bb471bfddd77d1687e51f3a56d7cddc4..25321260a480419d9a82fe9b13fd6d7188539a83 100644 (file)
@@ -72,6 +72,7 @@ public class ConnectionManagerImplTest {
     private static final long ECHO_REPLY_TIMEOUT = 500;
     private static final int DEVICE_CONNECTION_RATE_LIMIT_PER_MIN = 0;
     private static final int DEVICE_CONNECTION_HOLD_TIME_IN_SECONDS = 60;
+    private static final boolean ENABLE_CUSTOM_TRUST_MANAGER = false;
 
     @Before
     public void setUp() {
@@ -83,6 +84,7 @@ public class ConnectionManagerImplTest {
                 .setEchoReplyTimeout(new NonZeroUint32Type(ECHO_REPLY_TIMEOUT))
                 .setDeviceConnectionRateLimitPerMin(DEVICE_CONNECTION_RATE_LIMIT_PER_MIN)
                 .setDeviceConnectionHoldTimeInSeconds(DEVICE_CONNECTION_HOLD_TIME_IN_SECONDS)
+                .setEnableCustomTrustManager(ENABLE_CUSTOM_TRUST_MANAGER)
                 .build(), threadPool, dataBroker, notificationPublishService);
 
         connectionManagerImpl.setDeviceConnectedHandler(deviceConnectedHandler);