diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslContextFactoryReloadTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslContextFactoryReloadTest.java new file mode 100644 index 000000000000..c167f30ea96b --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SslContextFactoryReloadTest.java @@ -0,0 +1,265 @@ +// +// ======================================================================== +// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server.ssl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.http.HttpVersion; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.HttpConfiguration; +import org.eclipse.jetty.server.HttpConnectionFactory; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.SecureRequestCustomizer; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; +import org.eclipse.jetty.util.thread.Scheduler; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Assert; +import org.junit.Test; + +public class SslContextFactoryReloadTest +{ + public static final String KEYSTORE_1 = "src/test/resources/reload_keystore_1.jks"; + public static final String KEYSTORE_2 = "src/test/resources/reload_keystore_2.jks"; + + private Server server; + private SslContextFactory sslContextFactory; + private ServerConnector connector; + + private void start(Handler handler) throws Exception + { + server = new Server(); + + sslContextFactory = new SslContextFactory(); + sslContextFactory.setKeyStorePath(KEYSTORE_1); + sslContextFactory.setKeyStorePassword("storepwd"); + sslContextFactory.setKeyStoreType("JKS"); + sslContextFactory.setKeyStoreProvider(null); + + HttpConfiguration httpsConfig = new HttpConfiguration(); + httpsConfig.addCustomizer(new SecureRequestCustomizer()); + connector = new ServerConnector(server, + new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConfig)); + server.addConnector(connector); + + server.setHandler(handler); + + server.start(); + } + + @After + public void dispose() throws Exception + { + if (server != null) + server.stop(); + } + + @Test + public void testReload() throws Exception + { + start(new EchoHandler()); + + SSLContext ctx = SSLContext.getInstance("TLSv1.2"); + ctx.init(null, SslContextFactory.TRUST_ALL_CERTS, null); + SSLSocketFactory socketFactory = ctx.getSocketFactory(); + try (SSLSocket client1 = (SSLSocket)socketFactory.createSocket("localhost", connector.getLocalPort())) + { + String serverDN1 = client1.getSession().getPeerPrincipal().getName(); + Assert.assertThat(serverDN1, Matchers.startsWith("CN=localhost1")); + + String request = "" + + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "\r\n"; + + OutputStream output1 = client1.getOutputStream(); + output1.write(request.getBytes(StandardCharsets.UTF_8)); + output1.flush(); + + HttpTester.Response response1 = HttpTester.parseResponse(HttpTester.from(client1.getInputStream())); + Assert.assertNotNull(response1); + Assert.assertThat(response1.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + + // Reconfigure SslContextFactory. + sslContextFactory.reload(sslContextFactory -> + { + sslContextFactory.setKeyStorePath(KEYSTORE_2); + sslContextFactory.setKeyStorePassword("storepwd"); + }); + + // New connection should use the new keystore. + try (SSLSocket client2 = (SSLSocket)socketFactory.createSocket("localhost", connector.getLocalPort())) + { + String serverDN2 = client2.getSession().getPeerPrincipal().getName(); + Assert.assertThat(serverDN2, Matchers.startsWith("CN=localhost2")); + + OutputStream output2 = client1.getOutputStream(); + output2.write(request.getBytes(StandardCharsets.UTF_8)); + output2.flush(); + + HttpTester.Response response2 = HttpTester.parseResponse(HttpTester.from(client1.getInputStream())); + Assert.assertNotNull(response2); + Assert.assertThat(response2.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + } + + // Must still be possible to make requests with the first connection. + output1.write(request.getBytes(StandardCharsets.UTF_8)); + output1.flush(); + + response1 = HttpTester.parseResponse(HttpTester.from(client1.getInputStream())); + Assert.assertNotNull(response1); + Assert.assertThat(response1.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + } + } + + @Test + public void testReloadWhileServing() throws Exception + { + start(new EchoHandler()); + + Scheduler scheduler = new ScheduledExecutorScheduler(); + scheduler.start(); + try + { + SSLContext ctx = SSLContext.getInstance("TLSv1.2"); + ctx.init(null, SslContextFactory.TRUST_ALL_CERTS, null); + SSLSocketFactory socketFactory = ctx.getSocketFactory(); + + // Perform 4 reloads while connections are being served. + AtomicInteger reloads = new AtomicInteger(4); + long reloadPeriod = 500; + AtomicBoolean running = new AtomicBoolean(true); + scheduler.schedule(new Runnable() + { + @Override + public void run() + { + if (reloads.decrementAndGet() == 0) + { + running.set(false); + } + else + { + try + { + sslContextFactory.reload(sslContextFactory -> + { + if (sslContextFactory.getKeyStorePath().endsWith(KEYSTORE_1)) + sslContextFactory.setKeyStorePath(KEYSTORE_2); + else + sslContextFactory.setKeyStorePath(KEYSTORE_1); + }); + scheduler.schedule(this, reloadPeriod, TimeUnit.MILLISECONDS); + } + catch (Exception x) + { + running.set(false); + reloads.set(-1); + } + } + } + }, reloadPeriod, TimeUnit.MILLISECONDS); + + byte[] content = new byte[16 * 1024]; + while (running.get()) + { + try (SSLSocket client = (SSLSocket)socketFactory.createSocket("localhost", connector.getLocalPort())) + { + // We need to invalidate the session every time we open a new SSLSocket. + // This is because when the client uses session resumption, it caches + // the server certificates and then checks that it is the same during + // a new TLS handshake. If the SslContextFactory is reloaded during the + // TLS handshake, the client will see the new certificate and blow up. + // Note that browsers can handle this case better: they will just not + // use session resumption and fallback to the normal TLS handshake. + client.getSession().invalidate(); + + String request1 = "" + + "POST / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Content-Length: " + content.length + "\r\n" + + "\r\n"; + OutputStream outputStream = client.getOutputStream(); + outputStream.write(request1.getBytes(StandardCharsets.UTF_8)); + outputStream.write(content); + outputStream.flush(); + + InputStream inputStream = client.getInputStream(); + HttpTester.Response response1 = HttpTester.parseResponse(HttpTester.from(inputStream)); + Assert.assertNotNull(response1); + Assert.assertThat(response1.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + + String request2 = "" + + "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n" + + "\r\n"; + outputStream.write(request2.getBytes(StandardCharsets.UTF_8)); + outputStream.flush(); + + HttpTester.Response response2 = HttpTester.parseResponse(HttpTester.from(inputStream)); + Assert.assertNotNull(response2); + Assert.assertThat(response2.getStatus(), Matchers.equalTo(HttpStatus.OK_200)); + } + } + + Assert.assertEquals(0, reloads.get()); + } + finally + { + scheduler.stop(); + } + } + + private static class EchoHandler extends AbstractHandler + { + @Override + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + baseRequest.setHandled(true); + if (HttpMethod.POST.is(request.getMethod())) + IO.copy(request.getInputStream(), response.getOutputStream()); + else + response.setContentLength(0); + } + } +} diff --git a/jetty-server/src/test/resources/reload_keystore_1.jks b/jetty-server/src/test/resources/reload_keystore_1.jks new file mode 100644 index 000000000000..d615c22234db Binary files /dev/null and b/jetty-server/src/test/resources/reload_keystore_1.jks differ diff --git a/jetty-server/src/test/resources/reload_keystore_2.jks b/jetty-server/src/test/resources/reload_keystore_2.jks new file mode 100644 index 000000000000..3707c3a36139 Binary files /dev/null and b/jetty-server/src/test/resources/reload_keystore_2.jks differ diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java index a379ffa39d5f..d976dcd8f8c4 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java @@ -44,6 +44,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -209,6 +210,15 @@ private SslContextFactory(boolean trustAll, String keyStorePath) */ @Override protected void doStart() throws Exception + { + super.doStart(); + synchronized (this) + { + load(); + } + } + + private void load() throws Exception { SSLContext context = _setContext; KeyStore keyStore = _setKeyStore; @@ -244,7 +254,6 @@ protected void doStart() throws Exception Collection crls = loadCRL(getCrlPath()); // Look for X.509 certificates to create alias map - _certHosts.clear(); if (keyStore != null) { for (String alias : Collections.list(keyStore.aliases())) @@ -321,12 +330,22 @@ protected void doStart() throws Exception @Override protected void doStop() throws Exception + { + synchronized (this) + { + unload(); + } + super.doStop(); + } + + private void unload() { _factory = null; + _selectedProtocols = null; + _selectedCipherSuites = null; _aliasX509.clear(); _certHosts.clear(); _certWilds.clear(); - super.doStop(); } public String[] getSelectedProtocols() @@ -376,7 +395,6 @@ public String[] getExcludeProtocols() */ public void setExcludeProtocols(String... protocols) { - checkNotStarted(); _excludeProtocols.clear(); _excludeProtocols.addAll(Arrays.asList(protocols)); } @@ -386,7 +404,6 @@ public void setExcludeProtocols(String... protocols) */ public void addExcludeProtocols(String... protocol) { - checkNotStarted(); _excludeProtocols.addAll(Arrays.asList(protocol)); } @@ -405,7 +422,6 @@ public String[] getIncludeProtocols() */ public void setIncludeProtocols(String... protocols) { - checkNotStarted(); _includeProtocols.clear(); _includeProtocols.addAll(Arrays.asList(protocols)); } @@ -427,7 +443,6 @@ public String[] getExcludeCipherSuites() */ public void setExcludeCipherSuites(String... cipherSuites) { - checkNotStarted(); _excludeCipherSuites.clear(); _excludeCipherSuites.addAll(Arrays.asList(cipherSuites)); } @@ -437,7 +452,6 @@ public void setExcludeCipherSuites(String... cipherSuites) */ public void addExcludeCipherSuites(String... cipher) { - checkNotStarted(); _excludeCipherSuites.addAll(Arrays.asList(cipher)); } @@ -458,7 +472,6 @@ public String[] getIncludeCipherSuites() */ public void setIncludeCipherSuites(String... cipherSuites) { - checkNotStarted(); _includeCipherSuites.clear(); _includeCipherSuites.addAll(Arrays.asList(cipherSuites)); } @@ -486,7 +499,6 @@ public String getKeyStorePath() */ public void setKeyStorePath(String keyStorePath) { - checkNotStarted(); try { _keyStoreResource = Resource.newResource(keyStorePath); @@ -510,7 +522,6 @@ public String getKeyStoreProvider() */ public void setKeyStoreProvider(String keyStoreProvider) { - checkNotStarted(); _keyStoreProvider = keyStoreProvider; } @@ -527,7 +538,6 @@ public String getKeyStoreType() */ public void setKeyStoreType(String keyStoreType) { - checkNotStarted(); _keyStoreType = keyStoreType; } @@ -550,7 +560,6 @@ public String getCertAlias() */ public void setCertAlias(String certAlias) { - checkNotStarted(); _certAlias = certAlias; } @@ -559,7 +568,6 @@ public void setCertAlias(String certAlias) */ public void setTrustStorePath(String trustStorePath) { - checkNotStarted(); try { _trustStoreResource = Resource.newResource(trustStorePath); @@ -583,7 +591,6 @@ public String getTrustStoreProvider() */ public void setTrustStoreProvider(String trustStoreProvider) { - checkNotStarted(); _trustStoreProvider = trustStoreProvider; } @@ -600,7 +607,6 @@ public String getTrustStoreType() */ public void setTrustStoreType(String trustStoreType) { - checkNotStarted(); _trustStoreType = trustStoreType; } @@ -619,7 +625,6 @@ public boolean getNeedClientAuth() */ public void setNeedClientAuth(boolean needClientAuth) { - checkNotStarted(); _needClientAuth = needClientAuth; } @@ -638,7 +643,6 @@ public boolean getWantClientAuth() */ public void setWantClientAuth(boolean wantClientAuth) { - checkNotStarted(); _wantClientAuth = wantClientAuth; } @@ -655,7 +659,6 @@ public boolean isValidateCerts() */ public void setValidateCerts(boolean validateCerts) { - checkNotStarted(); _validateCerts = validateCerts; } @@ -672,7 +675,6 @@ public boolean isValidatePeerCerts() */ public void setValidatePeerCerts(boolean validatePeerCerts) { - checkNotStarted(); _validatePeerCerts = validatePeerCerts; } @@ -685,7 +687,6 @@ public void setValidatePeerCerts(boolean validatePeerCerts) */ public void setKeyStorePassword(String password) { - checkNotStarted(); if (password == null) { if (_keyStoreResource != null) @@ -694,7 +695,9 @@ public void setKeyStorePassword(String password) _keyStorePassword = null; } else + { _keyStorePassword = new Password(password); + } } /** @@ -705,7 +708,6 @@ public void setKeyStorePassword(String password) */ public void setKeyManagerPassword(String password) { - checkNotStarted(); if (password == null) { if (System.getProperty(KEYPASSWORD_PROPERTY) != null) @@ -714,7 +716,9 @@ public void setKeyManagerPassword(String password) _keyManagerPassword = null; } else + { _keyManagerPassword = new Password(password); + } } /** @@ -726,17 +730,17 @@ public void setKeyManagerPassword(String password) */ public void setTrustStorePassword(String password) { - checkNotStarted(); if (password == null) { - // Do we need a truststore password? if (_trustStoreResource != null && !_trustStoreResource.equals(_keyStoreResource)) _trustStorePassword = Password.getPassword(PASSWORD_PROPERTY, null, null); else _trustStorePassword = null; } else + { _trustStorePassword = new Password(password); + } } /** @@ -754,7 +758,6 @@ public String getProvider() */ public void setProvider(String provider) { - checkNotStarted(); _sslProvider = provider; } @@ -773,7 +776,6 @@ public String getProtocol() */ public void setProtocol(String protocol) { - checkNotStarted(); _sslProtocol = protocol; } @@ -794,14 +796,31 @@ public String getSecureRandomAlgorithm() */ public void setSecureRandomAlgorithm(String algorithm) { - checkNotStarted(); _secureRandomAlgorithm = algorithm; } /** - * @return The algorithm name (default "SunX509") used by the {@link KeyManagerFactory} + * @deprecated use {@link #getKeyManagerFactoryAlgorithm()} instead */ + @Deprecated public String getSslKeyManagerFactoryAlgorithm() + { + return getKeyManagerFactoryAlgorithm(); + } + + /** + * @deprecated use {@link #setKeyManagerFactoryAlgorithm(String)} instead + */ + @Deprecated + public void setSslKeyManagerFactoryAlgorithm(String algorithm) + { + setKeyManagerFactoryAlgorithm(algorithm); + } + + /** + * @return The algorithm name (default "SunX509") used by the {@link KeyManagerFactory} + */ + public String getKeyManagerFactoryAlgorithm() { return _keyManagerFactoryAlgorithm; } @@ -809,9 +828,8 @@ public String getSslKeyManagerFactoryAlgorithm() /** * @param algorithm The algorithm name (default "SunX509") used by the {@link KeyManagerFactory} */ - public void setSslKeyManagerFactoryAlgorithm(String algorithm) + public void setKeyManagerFactoryAlgorithm(String algorithm) { - checkNotStarted(); _keyManagerFactoryAlgorithm = algorithm; } @@ -847,7 +865,6 @@ public void setTrustAll(boolean trustAll) */ public void setTrustManagerFactoryAlgorithm(String algorithm) { - checkNotStarted(); _trustManagerFactoryAlgorithm = algorithm; } @@ -880,7 +897,6 @@ public String getCrlPath() */ public void setCrlPath(String crlPath) { - checkNotStarted(); _crlPath = crlPath; } @@ -899,7 +915,6 @@ public int getMaxCertPathLength() */ public void setMaxCertPathLength(int maxCertPathLength) { - checkNotStarted(); _maxCertPathLength = maxCertPathLength; } @@ -908,7 +923,13 @@ public void setMaxCertPathLength(int maxCertPathLength) */ public SSLContext getSslContext() { - return isStarted() ? _factory._context : _setContext; + if (!isStarted()) + return _setContext; + + synchronized (this) + { + return _factory._context; + } } /** @@ -916,10 +937,17 @@ public SSLContext getSslContext() */ public void setSslContext(SSLContext sslContext) { - checkNotStarted(); _setContext = sslContext; } + /** + * @return the endpoint identification algorithm + */ + public String getEndpointIdentificationAlgorithm() + { + return _endpointIdentificationAlgorithm; + } + /** * When set to "HTTPS" hostname verification will be enabled * @@ -927,7 +955,7 @@ public void setSslContext(SSLContext sslContext) */ public void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm) { - this._endpointIdentificationAlgorithm = endpointIdentificationAlgorithm; + _endpointIdentificationAlgorithm = endpointIdentificationAlgorithm; } /** @@ -939,7 +967,8 @@ public void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgo */ protected KeyStore loadKeyStore(Resource resource) throws Exception { - return CertificateUtils.getKeyStore(resource, getKeyStoreType(), getKeyStoreProvider(), _keyStorePassword == null ? null : _keyStorePassword.toString()); + String storePassword = _keyStorePassword == null ? null : _keyStorePassword.toString(); + return CertificateUtils.getKeyStore(resource, getKeyStoreType(), getKeyStoreProvider(), storePassword); } /** @@ -964,7 +993,6 @@ protected KeyStore loadTrustStore(Resource resource) throws Exception if (passwd == null) passwd = _keyStorePassword == null ? null : _keyStorePassword.toString(); } - return CertificateUtils.getKeyStore(resource, type, provider, passwd); } @@ -989,7 +1017,7 @@ protected KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception if (keyStore != null) { - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(getSslKeyManagerFactoryAlgorithm()); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(getKeyManagerFactoryAlgorithm()); keyManagerFactory.init(keyStore, _keyManagerPassword == null ? (_keyStorePassword == null ? null : _keyStorePassword.toString().toCharArray()) : _keyManagerPassword.toString().toCharArray()); managers = keyManagerFactory.getKeyManagers(); @@ -1187,30 +1215,12 @@ protected void removeExcludedCipherSuites(List selected_ciphers) /** * Check if the lifecycle has been started and throw runtime exception */ - protected void checkNotStarted() - { - if (isStarted()) - throw new IllegalStateException("Cannot modify configuration when " + getState()); - } - - /** - * Check if the lifecycle has been started and throw runtime exception - */ - protected void checkIsStarted() + private void checkIsStarted() { if (!isStarted()) throw new IllegalStateException("!STARTED: " + this); } - /** - * Check if the lifecycle has been started and throw runtime exception - */ - protected void checkIsRunning() - { - if (!isRunning()) - throw new IllegalStateException("!RUNNING: " + this); - } - /** * @return true if CRL Distribution Points support is enabled */ @@ -1226,7 +1236,6 @@ public boolean isEnableCRLDP() */ public void setEnableCRLDP(boolean enableCRLDP) { - checkNotStarted(); _enableCRLDP = enableCRLDP; } @@ -1245,7 +1254,6 @@ public boolean isEnableOCSP() */ public void setEnableOCSP(boolean enableOCSP) { - checkNotStarted(); _enableOCSP = enableOCSP; } @@ -1264,7 +1272,6 @@ public String getOcspResponderURL() */ public void setOcspResponderURL(String ocspResponderURL) { - checkNotStarted(); _ocspResponderURL = ocspResponderURL; } @@ -1275,13 +1282,18 @@ public void setOcspResponderURL(String ocspResponderURL) */ public void setKeyStore(KeyStore keyStore) { - checkNotStarted(); _setKeyStore = keyStore; } public KeyStore getKeyStore() { - return isStarted() ? _factory._keyStore : _setKeyStore; + if (!isStarted()) + return _setKeyStore; + + synchronized (this) + { + return _factory._keyStore; + } } /** @@ -1291,13 +1303,18 @@ public KeyStore getKeyStore() */ public void setTrustStore(KeyStore trustStore) { - checkNotStarted(); _setTrustStore = trustStore; } public KeyStore getTrustStore() { - return isStarted() ? _factory._trustStore : _setTrustStore; + if (!isStarted()) + return _setTrustStore; + + synchronized (this) + { + return _factory._trustStore; + } } /** @@ -1307,7 +1324,6 @@ public KeyStore getTrustStore() */ public void setKeyStoreResource(Resource resource) { - checkNotStarted(); _keyStoreResource = resource; } @@ -1323,7 +1339,6 @@ public Resource getKeyStoreResource() */ public void setTrustStoreResource(Resource resource) { - checkNotStarted(); _trustStoreResource = resource; } @@ -1406,12 +1421,14 @@ public SSLServerSocket newSslServerSocket(String host, int port, int backlog) th { checkIsStarted(); - SSLServerSocketFactory factory = _factory._context.getServerSocketFactory(); + SSLContext context = getSslContext(); + SSLServerSocketFactory factory = context.getServerSocketFactory(); SSLServerSocket socket = (SSLServerSocket)(host == null ? factory.createServerSocket(port, backlog) : factory.createServerSocket(port, backlog, InetAddress.getByName(host))); socket.setSSLParameters(customize(socket.getSSLParameters())); + return socket; } @@ -1419,9 +1436,11 @@ public SSLSocket newSslSocket() throws IOException { checkIsStarted(); - SSLSocketFactory factory = _factory._context.getSocketFactory(); + SSLContext context = getSslContext(); + SSLSocketFactory factory = context.getSocketFactory(); SSLSocket socket = (SSLSocket)factory.createSocket(); socket.setSSLParameters(customize(socket.getSSLParameters())); + return socket; } @@ -1436,9 +1455,12 @@ public SSLSocket newSslSocket() throws IOException */ public SSLEngine newSSLEngine() { - checkIsRunning(); - SSLEngine sslEngine = _factory._context.createSSLEngine(); + checkIsStarted(); + + SSLContext context = getSslContext(); + SSLEngine sslEngine = context.createSSLEngine(); customize(sslEngine); + return sslEngine; } @@ -1453,10 +1475,13 @@ public SSLEngine newSSLEngine() public SSLEngine newSSLEngine(String host, int port) { checkIsStarted(); - SSLEngine sslEngine = isSessionCachingEnabled() - ? _factory._context.createSSLEngine(host, port) - : _factory._context.createSSLEngine(); + + SSLContext context = getSslContext(); + SSLEngine sslEngine = isSessionCachingEnabled() ? + context.createSSLEngine(host, port) : + context.createSSLEngine(); customize(sslEngine); + return sslEngine; } @@ -1510,7 +1535,7 @@ public void customize(SSLEngine sslEngine) */ public SSLParameters customize(SSLParameters sslParams) { - sslParams.setEndpointIdentificationAlgorithm(_endpointIdentificationAlgorithm); + sslParams.setEndpointIdentificationAlgorithm(getEndpointIdentificationAlgorithm()); sslParams.setUseCipherSuitesOrder(isUseCipherSuitesOrder()); if (!_certHosts.isEmpty() || !_certWilds.isEmpty()) sslParams.setSNIMatchers(Collections.singletonList(new AliasSNIMatcher())); @@ -1525,6 +1550,16 @@ public SSLParameters customize(SSLParameters sslParams) return sslParams; } + public void reload(Consumer consumer) throws Exception + { + synchronized (this) + { + consumer.accept(this); + unload(); + load(); + } + } + public static X509Certificate[] getCertChain(SSLSession sslSession) { try