From: LiGuosheng Date: Fri, 23 Feb 2018 06:34:39 +0000 (+0800) Subject: Add interface SslHandlerFactory X-Git-Tag: release/fluorine~134 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F23%2F68523%2F12;p=netconf.git Add interface SslHandlerFactory This factory is used by the TLS clients to create SslHandler that will be added to the channel pipeline when the channel is active. TLS versions are configurable. Change-Id: I95c2a0ff105020ac84b02d82207f830d70ef7197 Signed-off-by: Li guosheng --- diff --git a/netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/SslHandlerFactory.java b/netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/SslHandlerFactory.java new file mode 100644 index 0000000000..7fadf38e47 --- /dev/null +++ b/netconf/netconf-client/src/main/java/org/opendaylight/netconf/client/SslHandlerFactory.java @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2018 ZTE Corporation. 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.netconf.client; + +import io.netty.handler.ssl.SslHandler; + +public interface SslHandlerFactory { + /** + * This factory is used by the TLS client to create SslHandler that will be added + * into the channel pipeline when the channel is active. + */ + SslHandler createSslHandler(); +} diff --git a/netconf/netconf-console/src/test/resources/schemas/netconf-node-topology.yang b/netconf/netconf-console/src/test/resources/schemas/netconf-node-topology.yang index 3da84be98b..1e1f85545e 100644 --- a/netconf/netconf-console/src/test/resources/schemas/netconf-node-topology.yang +++ b/netconf/netconf-console/src/test/resources/schemas/netconf-node-topology.yang @@ -79,6 +79,30 @@ module netconf-node-topology { type boolean; } + container protocol { + config true; + leaf name { + type enumeration { + enum SSH; + enum TLS; + } + default SSH; + } + + choice specification { + case tls-case { + container tls { + leaf-list excluded-versions { + type string; + description "A list of TLS version names provided in JDK that are not supported by the + target netconf device, eg, the netopeer2 simulator does not support the + SSLv2Hello. Most of the time, this list need not be set"; + } + } + } + } + } + leaf schemaless { type boolean; default false; diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java index df3eff0976..b82af0d5cb 100644 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java +++ b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java @@ -12,19 +12,29 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import io.netty.handler.ssl.SslHandler; import io.netty.util.concurrent.EventExecutor; import java.io.File; +import java.io.IOException; import java.math.BigDecimal; import java.net.InetSocketAddress; import java.net.URL; +import java.security.GeneralSecurityException; +import java.security.KeyStore; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManagerFactory; import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; @@ -33,6 +43,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.netconf.api.NetconfMessage; import org.opendaylight.netconf.client.NetconfClientDispatcher; import org.opendaylight.netconf.client.NetconfClientSessionListener; +import org.opendaylight.netconf.client.SslHandlerFactory; import org.opendaylight.netconf.client.conf.NetconfClientConfiguration; import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration; import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder; @@ -62,6 +73,8 @@ import org.opendaylight.protocol.framework.TimedReconnectStrategy; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.protocol.Specification; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.parameters.protocol.specification.TlsCase; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability.CapabilityOrigin; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.Credentials; import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.KeyAuth; @@ -588,4 +601,50 @@ public abstract class AbstractNetconfTopology implements NetconfTopology { facade.close(); } } + + private static final class SslHandlerFactoryImpl implements SslHandlerFactory { + private final NetconfKeystoreAdapter keystoreAdapter; + private final Optional specOptional; + + SslHandlerFactoryImpl(final NetconfKeystoreAdapter keystoreAdapter, final Specification specification) { + this.keystoreAdapter = keystoreAdapter; + this.specOptional = Optional.fromNullable(specification); + } + + @Override + public SslHandler createSslHandler() { + try { + final KeyStore keyStore = keystoreAdapter.getJavaKeyStore(); + + final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(keyStore, "".toCharArray()); + + final TrustManagerFactory tmf = + TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(keyStore); + + final SSLContext sslCtx = SSLContext.getInstance("TLS"); + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + final SSLEngine engine = sslCtx.createSSLEngine(); + engine.setUseClientMode(true); + + final Set protocols = Sets.newHashSet(engine.getSupportedProtocols()); + if (specOptional.isPresent()) { + final Specification specification = specOptional.get(); + if (!(specification instanceof TlsCase)) { + throw new IllegalArgumentException("Cannot get TLS specification from: " + specification); + } + protocols.removeAll(((TlsCase)specification).getTls().getExcludedVersions()); + } + + engine.setEnabledProtocols(protocols.toArray(new String[0])); + engine.setEnabledCipherSuites(engine.getSupportedCipherSuites()); + engine.setEnableSessionCreation(true); + + return new SslHandler(engine); + } catch (GeneralSecurityException | IOException exc) { + throw new IllegalStateException(exc); + } + } + } } diff --git a/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang b/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang index 3da84be98b..1e1f85545e 100644 --- a/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang +++ b/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang @@ -79,6 +79,30 @@ module netconf-node-topology { type boolean; } + container protocol { + config true; + leaf name { + type enumeration { + enum SSH; + enum TLS; + } + default SSH; + } + + choice specification { + case tls-case { + container tls { + leaf-list excluded-versions { + type string; + description "A list of TLS version names provided in JDK that are not supported by the + target netconf device, eg, the netopeer2 simulator does not support the + SSLv2Hello. Most of the time, this list need not be set"; + } + } + } + } + } + leaf schemaless { type boolean; default false; diff --git a/netconf/sal-netconf-connector/src/test/resources/schemas/netconf-node-topology.yang b/netconf/sal-netconf-connector/src/test/resources/schemas/netconf-node-topology.yang index 7b872968ce..8488211364 100644 --- a/netconf/sal-netconf-connector/src/test/resources/schemas/netconf-node-topology.yang +++ b/netconf/sal-netconf-connector/src/test/resources/schemas/netconf-node-topology.yang @@ -46,6 +46,30 @@ module netconf-node-topology { type boolean; } + container protocol { + config true; + leaf name { + type enumeration { + enum SSH; + enum TLS; + } + default SSH; + } + + choice specification { + case tls-case { + container tls { + leaf-list excluded-versions { + type string; + description "A list of TLS version names provided in JDK that are not supported by the + target netconf device, eg, the netopeer2 simulator does not support the + SSLv2Hello. Most of the time, this list need not be set"; + } + } + } + } + } + leaf schemaless { type boolean; default false;