2 * Copyright (c) 2013 Pantheon Technologies s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.openflowjava.protocol.impl.core;
11 import static java.util.Objects.requireNonNull;
13 import java.io.IOException;
14 import java.net.Socket;
15 import java.security.KeyManagementException;
16 import java.security.KeyStore;
17 import java.security.KeyStoreException;
18 import java.security.NoSuchAlgorithmException;
19 import java.security.Security;
20 import java.security.UnrecoverableKeyException;
21 import java.security.cert.CertificateException;
22 import java.security.cert.X509Certificate;
23 import java.util.List;
24 import javax.net.ssl.KeyManagerFactory;
25 import javax.net.ssl.SSLContext;
26 import javax.net.ssl.SSLEngine;
27 import javax.net.ssl.TrustManager;
28 import javax.net.ssl.TrustManagerFactory;
29 import javax.net.ssl.X509ExtendedTrustManager;
30 import javax.net.ssl.X509TrustManager;
31 import org.eclipse.jdt.annotation.Nullable;
32 import org.opendaylight.openflowjava.protocol.api.connection.TlsConfiguration;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 * Class for setting up TLS connection.
39 * @author michal.polkorab
41 public class SslContextFactory {
42 private static final Logger LOG = LoggerFactory.getLogger(SslContextFactory.class);
44 // "TLS" - supports some version of TLS
45 // Use "TLSv1", "TLSv1.1", "TLSv1.2" for specific TLS version
46 private static final String PROTOCOL = "TLS";
48 private final TlsConfiguration tlsConfig;
50 private volatile List<X509Certificate> switchCertificateChain;
53 * Sets the TlsConfiguration.
56 * TLS configuration object, contains keystore locations +
59 public SslContextFactory(final TlsConfiguration tlsConfig) {
60 this.tlsConfig = requireNonNull(tlsConfig);
63 @Nullable List<X509Certificate> getSwitchCertificateChain() {
64 return switchCertificateChain;
67 void setSwitchCertificateChain(final X509Certificate[] chain) {
68 switchCertificateChain = List.of(chain);
71 public SSLContext getServerContext() {
72 String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
73 if (algorithm == null) {
74 algorithm = "SunX509";
76 SSLContext serverContext = null;
78 KeyStore ks = KeyStore.getInstance(tlsConfig.getTlsKeystoreType().name());
79 ks.load(SslKeyStore.asInputStream(tlsConfig.getTlsKeystore(), tlsConfig.getTlsKeystorePathType()),
80 tlsConfig.getKeystorePassword().toCharArray());
81 KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
82 kmf.init(ks, tlsConfig.getCertificatePassword().toCharArray());
84 KeyStore ts = KeyStore.getInstance(tlsConfig.getTlsTruststoreType().name());
85 ts.load(SslKeyStore.asInputStream(tlsConfig.getTlsTruststore(), tlsConfig.getTlsTruststorePathType()),
86 tlsConfig.getTruststorePassword().toCharArray());
87 TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
90 serverContext = SSLContext.getInstance(PROTOCOL);
92 // A bit ugly: intercept trust checks to establish switch certificate
93 final TrustManager[] delegates = tmf.getTrustManagers();
94 final TrustManager[] proxies;
95 if (delegates != null) {
96 proxies = new TrustManager[delegates.length];
97 for (int i = 0; i < delegates.length; i++) {
98 final TrustManager delegate = delegates[i];
99 if (delegate instanceof X509ExtendedTrustManager) {
100 proxies[i] = new ProxyExtendedTrustManager((X509ExtendedTrustManager) delegate);
101 } else if (delegate instanceof X509TrustManager) {
102 proxies[i] = new ProxyTrustManager((X509TrustManager) delegate);
104 LOG.debug("Cannot handle trust manager {}, passing through", delegate);
105 proxies[i] = delegate;
111 serverContext.init(kmf.getKeyManagers(), proxies, null);
112 } catch (IOException e) {
113 LOG.warn("IOException - Failed to load keystore / truststore."
114 + " Failed to initialize the server-side SSLContext", e);
115 } catch (NoSuchAlgorithmException e) {
116 LOG.warn("NoSuchAlgorithmException - Unsupported algorithm."
117 + " Failed to initialize the server-side SSLContext", e);
118 } catch (CertificateException e) {
119 LOG.warn("CertificateException - Unable to access certificate (check password)."
120 + " Failed to initialize the server-side SSLContext", e);
121 } catch (KeyManagementException | KeyStoreException | UnrecoverableKeyException e) {
122 LOG.warn("Exception - Failed to initialize the server-side SSLContext", e);
124 return serverContext;
127 private final class ProxyTrustManager implements X509TrustManager {
128 private final X509TrustManager delegate;
130 ProxyTrustManager(final X509TrustManager delegate) {
131 this.delegate = requireNonNull(delegate);
135 public void checkClientTrusted(final X509Certificate[] chain, final String authType)
136 throws CertificateException {
137 setSwitchCertificateChain(chain);
138 delegate.checkClientTrusted(chain, authType);
142 public void checkServerTrusted(final X509Certificate[] chain, final String authType)
143 throws CertificateException {
144 delegate.checkServerTrusted(chain, authType);
148 public X509Certificate[] getAcceptedIssuers() {
149 return delegate.getAcceptedIssuers();
153 private final class ProxyExtendedTrustManager extends X509ExtendedTrustManager {
154 private final X509ExtendedTrustManager delegate;
156 ProxyExtendedTrustManager(final X509ExtendedTrustManager trustManager) {
157 delegate = requireNonNull(trustManager);
161 public void checkClientTrusted(final X509Certificate[] chain, final String authType, final Socket socket)
162 throws CertificateException {
163 setSwitchCertificateChain(chain);
164 delegate.checkClientTrusted(chain, authType, socket);
168 public void checkClientTrusted(final X509Certificate[] chain, final String authType)
169 throws CertificateException {
170 setSwitchCertificateChain(chain);
171 delegate.checkClientTrusted(chain, authType);
175 public void checkClientTrusted(final X509Certificate[] chain, final String authType, final SSLEngine sslEngine)
176 throws CertificateException {
177 setSwitchCertificateChain(chain);
178 delegate.checkClientTrusted(chain, authType, sslEngine);
182 public void checkServerTrusted(final X509Certificate[] chain, final String authType, final SSLEngine sslEngine)
183 throws CertificateException {
184 delegate.checkServerTrusted(chain, authType, sslEngine);
188 public void checkServerTrusted(final X509Certificate[] chain, final String authType)
189 throws CertificateException {
190 delegate.checkServerTrusted(chain, authType);
194 public void checkServerTrusted(final X509Certificate[] chain, final String authType, final Socket socket)
195 throws CertificateException {
196 delegate.checkServerTrusted(chain, authType, socket);
200 public X509Certificate[] getAcceptedIssuers() {
201 return delegate.getAcceptedIssuers();