From 10cf577f2ca9d39546a91712dc20d509b2fc30a6 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Mon, 5 Feb 2024 10:50:26 +0100 Subject: [PATCH 1/3] The TCP client will not send the correct server name to the client due to SSL client resumption performed by the SSL implementation although we are using a new engine implementation. The SSL channel provider when a server name is specified for a client should use the SSL context map to avoid this. --- .../core/net/impl/SslChannelProvider.java | 31 ++++++++++++++++--- .../core/net/impl/SslContextProvider.java | 26 +++++++++++----- src/test/java/io/vertx/core/net/NetTest.java | 29 +++++++++++++---- .../java/io/vertx/core/net/SSLHelperTest.java | 6 ++-- src/test/java/io/vertx/it/SSLEngineTest.java | 2 +- 5 files changed, 72 insertions(+), 22 deletions(-) diff --git a/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java b/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java index 3c84d978bac..3207fd6b988 100644 --- a/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java +++ b/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java @@ -17,6 +17,7 @@ import io.netty.handler.ssl.SslHandler; import io.netty.util.AsyncMapping; import io.netty.util.concurrent.ImmediateExecutor; +import io.vertx.core.VertxException; import io.vertx.core.net.SocketAddress; import javax.net.ssl.KeyManagerFactory; @@ -26,6 +27,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import static io.vertx.core.net.impl.SslContextProvider.createTrustAllTrustManager; + /** * Provider for {@link SslHandler} and {@link SniHandler}. *
@@ -74,11 +77,31 @@ public SslContext sslClientContext(String serverName, boolean useAlpn) { public SslContext sslClientContext(String serverName, boolean useAlpn, boolean trustAll) { int idx = idx(useAlpn); - if (sslContexts[idx] == null) { - SslContext context = sslContextProvider.createClientContext(serverName, useAlpn, trustAll); - sslContexts[idx] = context; + if (serverName == null) { + if (sslContexts[idx] == null) { + SslContext context = sslContextProvider.createClientContext(useAlpn, trustAll); + sslContexts[idx] = context; + } + return sslContexts[idx]; + } else { + KeyManagerFactory kmf; + try { + kmf = sslContextProvider.resolveKeyManagerFactory(serverName); + } catch (Exception e) { + throw new VertxException(e); + } + TrustManager[] trustManagers; + if (trustAll) { + trustManagers = new TrustManager[] { createTrustAllTrustManager() }; + } else { + try { + trustManagers = sslContextProvider.resolveTrustManagers(serverName); + } catch (Exception e) { + throw new VertxException(e); + } + } + return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createClientContext(kmf, trustManagers, s, useAlpn)); } - return sslContexts[idx]; } public SslContext sslServerContext(boolean useAlpn) { diff --git a/src/main/java/io/vertx/core/net/impl/SslContextProvider.java b/src/main/java/io/vertx/core/net/impl/SslContextProvider.java index f60c0ce369b..588cee1c322 100644 --- a/src/main/java/io/vertx/core/net/impl/SslContextProvider.java +++ b/src/main/java/io/vertx/core/net/impl/SslContextProvider.java @@ -66,7 +66,23 @@ public SslContextProvider(ClientAuth clientAuth, this.crls = crls; } - public VertxSslContext createClientContext(String serverName, boolean useAlpn, boolean trustAll) { + public VertxSslContext createClientContext( + boolean useAlpn, + boolean trustAll) { + TrustManager[] trustManagers = null; + if (trustAll) { + trustManagers = new TrustManager[] { createTrustAllTrustManager() }; + } else if (trustManagerFactory != null) { + trustManagers = trustManagerFactory.getTrustManagers(); + } + return createClientContext(keyManagerFactory, trustManagers, null, useAlpn); + } + + public VertxSslContext createClientContext( + KeyManagerFactory keyManagerFactory, + TrustManager[] trustManagers, + String serverName, + boolean useAlpn) { try { SslContextFactory factory = provider.get() .useAlpn(useAlpn) @@ -76,12 +92,6 @@ public VertxSslContext createClientContext(String serverName, boolean useAlpn, b if (keyManagerFactory != null) { factory.keyMananagerFactory(keyManagerFactory); } - TrustManager[] trustManagers = null; - if (trustAll) { - trustManagers = new TrustManager[] { createTrustAllTrustManager() }; - } else if (trustManagerFactory != null) { - trustManagers = trustManagerFactory.getTrustManagers(); - } if (trustManagers != null) { TrustManagerFactory tmf = buildVertxTrustManagerFactory(trustManagers); factory.trustManagerFactory(tmf); @@ -233,7 +243,7 @@ public X509Certificate[] getAcceptedIssuers() { } // Create a TrustManager which trusts everything - private static TrustManager createTrustAllTrustManager() { + static TrustManager createTrustAllTrustManager() { return new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { diff --git a/src/test/java/io/vertx/core/net/NetTest.java b/src/test/java/io/vertx/core/net/NetTest.java index 902d49b0329..aa61cb5e88c 100755 --- a/src/test/java/io/vertx/core/net/NetTest.java +++ b/src/test/java/io/vertx/core/net/NetTest.java @@ -95,12 +95,7 @@ import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.security.cert.Certificate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; @@ -1530,6 +1525,28 @@ public void testSniOverrideServerName() throws Exception { assertEquals("host2.com", cnOf(test.clientPeerCert())); } + @Test + public void testClientSniMultipleServerName() throws Exception { + List receivedServerNames = Collections.synchronizedList(new ArrayList<>()); + server = vertx.createNetServer(new NetServerOptions() + .setSni(true) + .setSsl(true) + .setKeyCertOptions(Cert.SNI_JKS.get()) + ).connectHandler(so -> { + receivedServerNames.add(so.indicatedServerName()); + }); + startServer(); + List serverNames = Arrays.asList("host1", "host2.com"); + client = vertx.createNetClient(new NetClientOptions().setSsl(true).setTrustAll(true)); + for (String serverName : serverNames) { + NetSocket so = client.connect(testAddress, serverName).toCompletionStage().toCompletableFuture().get(); + String host = cnOf(so.peerCertificates().get(0)); + assertEquals(serverName, host); + } + assertWaitUntil(() -> receivedServerNames.size() == 2); + assertEquals(receivedServerNames, serverNames); + } + @Test // SNI present an unknown server public void testSniWithUnknownServer1() throws Exception { diff --git a/src/test/java/io/vertx/core/net/SSLHelperTest.java b/src/test/java/io/vertx/core/net/SSLHelperTest.java index add737058f6..3e4dfef55e3 100755 --- a/src/test/java/io/vertx/core/net/SSLHelperTest.java +++ b/src/test/java/io/vertx/core/net/SSLHelperTest.java @@ -46,7 +46,7 @@ public void testUseJdkCiphersWhenNotSpecified() throws Exception { helper .buildContextProvider(new SSLOptions().setKeyCertOptions(Cert.CLIENT_JKS.get()).setTrustOptions(Trust.SERVER_JKS.get()), (ContextInternal) vertx.getOrCreateContext()) .onComplete(onSuccess(provider -> { - SslContext ctx = provider.createClientContext(null, false, false); + SslContext ctx = provider.createClientContext(false, false); assertEquals(new HashSet<>(Arrays.asList(expected)), new HashSet<>(ctx.cipherSuites())); testComplete(); })); @@ -60,7 +60,7 @@ public void testUseOpenSSLCiphersWhenNotSpecified() throws Exception { new HttpClientOptions().setOpenSslEngineOptions(new OpenSSLEngineOptions()).setPemKeyCertOptions(Cert.CLIENT_PEM.get()).setTrustOptions(Trust.SERVER_PEM.get()), null); helper.buildContextProvider(new SSLOptions().setKeyCertOptions(Cert.CLIENT_PEM.get()).setTrustOptions(Trust.SERVER_PEM.get()), (ContextInternal) vertx.getOrCreateContext()).onComplete(onSuccess(provider -> { - SslContext ctx = provider.createClientContext(null, false, false); + SslContext ctx = provider.createClientContext(false, false); assertEquals(expected, new HashSet<>(ctx.cipherSuites())); testComplete(); })); @@ -185,6 +185,6 @@ private void testTLSVersions(HttpServerOptions options, Consumer chec } public SSLEngine createEngine(SslContextProvider provider) { - return provider.createClientContext(null, false, false).newEngine(ByteBufAllocator.DEFAULT); + return provider.createClientContext(false, false).newEngine(ByteBufAllocator.DEFAULT); } } diff --git a/src/test/java/io/vertx/it/SSLEngineTest.java b/src/test/java/io/vertx/it/SSLEngineTest.java index cc03334a6ed..1667dcece0e 100644 --- a/src/test/java/io/vertx/it/SSLEngineTest.java +++ b/src/test/java/io/vertx/it/SSLEngineTest.java @@ -105,7 +105,7 @@ private void doTest(SSLEngineOptions engine, } } SslContextProvider provider = ((HttpServerImpl)server).sslContextProvider(); - SslContext ctx = provider.createClientContext(null, false, false); + SslContext ctx = provider.createClientContext(false, false); switch (expectedSslContext != null ? expectedSslContext : "jdk") { case "jdk": assertTrue(ctx.sessionContext().getClass().getName().equals("sun.security.ssl.SSLSessionContextImpl")); From 565894189474ee1d843293b101d86dfb20852b70 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Mon, 5 Feb 2024 11:00:16 +0100 Subject: [PATCH 2/3] Refactor and unify client/server code in SslChannelProvider/SslContextProvider --- .../core/net/impl/SslChannelProvider.java | 67 ++++++----------- .../core/net/impl/SslContextProvider.java | 75 ++++++++++++------- .../java/io/vertx/core/net/SSLHelperTest.java | 8 +- src/test/java/io/vertx/it/SSLEngineTest.java | 2 +- 4 files changed, 77 insertions(+), 75 deletions(-) diff --git a/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java b/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java index 3207fd6b988..0460b334140 100644 --- a/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java +++ b/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java @@ -27,8 +27,6 @@ import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -import static io.vertx.core.net.impl.SslContextProvider.createTrustAllTrustManager; - /** * Provider for {@link SslHandler} and {@link SniHandler}. *
@@ -76,40 +74,34 @@ public SslContext sslClientContext(String serverName, boolean useAlpn) { } public SslContext sslClientContext(String serverName, boolean useAlpn, boolean trustAll) { + try { + return sslContext(serverName, useAlpn, false, trustAll); + } catch (Exception e) { + throw new VertxException(e); + } + } + + public SslContext sslContext(String serverName, boolean useAlpn, boolean server, boolean trustAll) throws Exception { int idx = idx(useAlpn); if (serverName == null) { if (sslContexts[idx] == null) { - SslContext context = sslContextProvider.createClientContext(useAlpn, trustAll); + SslContext context = sslContextProvider.createContext(server, null, null, null, useAlpn, trustAll); sslContexts[idx] = context; } return sslContexts[idx]; } else { - KeyManagerFactory kmf; - try { - kmf = sslContextProvider.resolveKeyManagerFactory(serverName); - } catch (Exception e) { - throw new VertxException(e); - } - TrustManager[] trustManagers; - if (trustAll) { - trustManagers = new TrustManager[] { createTrustAllTrustManager() }; - } else { - try { - trustManagers = sslContextProvider.resolveTrustManagers(serverName); - } catch (Exception e) { - throw new VertxException(e); - } - } - return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createClientContext(kmf, trustManagers, s, useAlpn)); + KeyManagerFactory kmf = sslContextProvider.resolveKeyManagerFactory(serverName); + TrustManager[] trustManagers = trustAll ? null : sslContextProvider.resolveTrustManagers(serverName); + return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createContext(server, kmf, trustManagers, s, useAlpn, trustAll)); } } public SslContext sslServerContext(boolean useAlpn) { - int idx = idx(useAlpn); - if (sslContexts[idx] == null) { - sslContexts[idx] = sslContextProvider.createServerContext(useAlpn); + try { + return sslContext(null, useAlpn, true, false); + } catch (Exception e) { + throw new VertxException(e); } - return sslContexts[idx]; } /** @@ -120,27 +112,14 @@ public SslContext sslServerContext(boolean useAlpn) { public AsyncMapping serverNameMapping() { return (AsyncMapping) (serverName, promise) -> { workerPool.execute(() -> { - if (serverName == null) { - promise.setSuccess(sslServerContext(useAlpn)); - } else { - KeyManagerFactory kmf; - try { - kmf = sslContextProvider.resolveKeyManagerFactory(serverName); - } catch (Exception e) { - promise.setFailure(e); - return; - } - TrustManager[] trustManagers; - try { - trustManagers = sslContextProvider.resolveTrustManagers(serverName); - } catch (Exception e) { - promise.setFailure(e); - return; - } - int idx = idx(useAlpn); - SslContext sslContext = sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createServerContext(kmf, trustManagers, s, useAlpn)); - promise.setSuccess(sslContext); + SslContext sslContext; + try { + sslContext = sslContext(serverName, useAlpn, true, false); + } catch (Exception e) { + promise.setFailure(e); + return; } + promise.setSuccess(sslContext); }); return promise; }; diff --git a/src/main/java/io/vertx/core/net/impl/SslContextProvider.java b/src/main/java/io/vertx/core/net/impl/SslContextProvider.java index 588cee1c322..fcbefb91ee4 100644 --- a/src/main/java/io/vertx/core/net/impl/SslContextProvider.java +++ b/src/main/java/io/vertx/core/net/impl/SslContextProvider.java @@ -66,16 +66,29 @@ public SslContextProvider(ClientAuth clientAuth, this.crls = crls; } - public VertxSslContext createClientContext( - boolean useAlpn, - boolean trustAll) { - TrustManager[] trustManagers = null; + public VertxSslContext createContext(boolean server, + KeyManagerFactory keyManagerFactory, + TrustManager[] trustManagers, + String serverName, + boolean useAlpn, + boolean trustAll) { + if (keyManagerFactory == null) { + keyManagerFactory = defaultKeyManagerFactory(); + } if (trustAll) { - trustManagers = new TrustManager[] { createTrustAllTrustManager() }; - } else if (trustManagerFactory != null) { - trustManagers = trustManagerFactory.getTrustManagers(); + trustManagers = SslContextProvider.createTrustAllManager(); + } else if (trustManagers == null) { + trustManagers = defaultTrustManagers(); } - return createClientContext(keyManagerFactory, trustManagers, null, useAlpn); + if (server) { + return createServerContext(keyManagerFactory, trustManagers, serverName, useAlpn); + } else { + return createClientContext(keyManagerFactory, trustManagers, serverName, useAlpn); + } + } + + public VertxSslContext createContext(boolean server, boolean useAlpn) { + return createContext(server, defaultKeyManagerFactory(), defaultTrustManagers(), null, useAlpn, false); } public VertxSslContext createClientContext( @@ -108,10 +121,6 @@ protected void initEngine(SSLEngine engine) { } } - public VertxSslContext createServerContext(boolean useAlpn) { - return createServerContext(keyManagerFactory, trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null, null, useAlpn); - } - public VertxSslContext createServerContext(KeyManagerFactory keyManagerFactory, TrustManager[] trustManagers, String serverName, @@ -152,6 +161,18 @@ public KeyManagerFactory loadKeyManagerFactory(String serverName) throws Excepti return null; } + public TrustManager[] defaultTrustManagers() { + return trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null; + } + + public TrustManagerFactory defaultTrustManagerFactory() { + return trustManagerFactory; + } + + public KeyManagerFactory defaultKeyManagerFactory() { + return keyManagerFactory; + } + /** * Resolve the {@link KeyManagerFactory} for the {@code serverName}, when a factory cannot be resolved, the default * factory is returned. @@ -242,22 +263,24 @@ public X509Certificate[] getAcceptedIssuers() { return trustMgrs; } - // Create a TrustManager which trusts everything - static TrustManager createTrustAllTrustManager() { - return new X509TrustManager() { - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - } + private static final TrustManager TRUST_ALL_MANAGER = new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + } - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - } + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + } - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - }; + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + }; + + // Create a TrustManager which trusts everything + private static TrustManager[] createTrustAllManager() { + return new TrustManager[] { TRUST_ALL_MANAGER }; } public void configureEngine(SSLEngine engine, Set enabledProtocols, String serverName, boolean client) { diff --git a/src/test/java/io/vertx/core/net/SSLHelperTest.java b/src/test/java/io/vertx/core/net/SSLHelperTest.java index 3e4dfef55e3..af422290e2b 100755 --- a/src/test/java/io/vertx/core/net/SSLHelperTest.java +++ b/src/test/java/io/vertx/core/net/SSLHelperTest.java @@ -46,7 +46,7 @@ public void testUseJdkCiphersWhenNotSpecified() throws Exception { helper .buildContextProvider(new SSLOptions().setKeyCertOptions(Cert.CLIENT_JKS.get()).setTrustOptions(Trust.SERVER_JKS.get()), (ContextInternal) vertx.getOrCreateContext()) .onComplete(onSuccess(provider -> { - SslContext ctx = provider.createClientContext(false, false); + SslContext ctx = provider.createContext(false, false); assertEquals(new HashSet<>(Arrays.asList(expected)), new HashSet<>(ctx.cipherSuites())); testComplete(); })); @@ -60,7 +60,7 @@ public void testUseOpenSSLCiphersWhenNotSpecified() throws Exception { new HttpClientOptions().setOpenSslEngineOptions(new OpenSSLEngineOptions()).setPemKeyCertOptions(Cert.CLIENT_PEM.get()).setTrustOptions(Trust.SERVER_PEM.get()), null); helper.buildContextProvider(new SSLOptions().setKeyCertOptions(Cert.CLIENT_PEM.get()).setTrustOptions(Trust.SERVER_PEM.get()), (ContextInternal) vertx.getOrCreateContext()).onComplete(onSuccess(provider -> { - SslContext ctx = provider.createClientContext(false, false); + SslContext ctx = provider.createContext(false, false); assertEquals(expected, new HashSet<>(ctx.cipherSuites())); testComplete(); })); @@ -90,7 +90,7 @@ private void testOpenSslServerSessionContext(boolean testDefault){ defaultHelper .buildContextProvider(httpServerOptions.getSslOptions(), (ContextInternal) vertx.getOrCreateContext()) .onComplete(onSuccess(provider -> { - SslContext ctx = provider.createServerContext(false); + SslContext ctx = provider.createContext(true, false); SSLSessionContext sslSessionContext = ctx.sessionContext(); assertTrue(sslSessionContext instanceof OpenSslServerSessionContext); @@ -185,6 +185,6 @@ private void testTLSVersions(HttpServerOptions options, Consumer chec } public SSLEngine createEngine(SslContextProvider provider) { - return provider.createClientContext(false, false).newEngine(ByteBufAllocator.DEFAULT); + return provider.createContext(false, false).newEngine(ByteBufAllocator.DEFAULT); } } diff --git a/src/test/java/io/vertx/it/SSLEngineTest.java b/src/test/java/io/vertx/it/SSLEngineTest.java index 1667dcece0e..31874fbad58 100644 --- a/src/test/java/io/vertx/it/SSLEngineTest.java +++ b/src/test/java/io/vertx/it/SSLEngineTest.java @@ -105,7 +105,7 @@ private void doTest(SSLEngineOptions engine, } } SslContextProvider provider = ((HttpServerImpl)server).sslContextProvider(); - SslContext ctx = provider.createClientContext(false, false); + SslContext ctx = provider.createContext(false, false); switch (expectedSslContext != null ? expectedSslContext : "jdk") { case "jdk": assertTrue(ctx.sessionContext().getClass().getName().equals("sun.security.ssl.SSLSessionContextImpl")); From 60b526860a5af96468d34dfe00ec6b45f04c1585 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Mon, 5 Feb 2024 12:02:17 +0100 Subject: [PATCH 3/3] The SslChannelProvider class maintains a map of server name to Netty SslContext that is filled when a client provides a server name. When a server name does not resolve to a KeyManagerFactory or TrustManagerFactory, the default factories are used and the entry is stored in the map. Instead no specific factory is resolved the default Netty SslContext is used, since this can lead to a a memory leak when a client specifies spurious SNI server names. This affects only a TCP server when SNI is set in the HttpServerOptions. --- .../io/vertx/core/net/impl/SSLHelper.java | 8 +++++ .../core/net/impl/SslChannelProvider.java | 21 +++++++----- .../core/net/impl/SslContextProvider.java | 32 ++++--------------- .../io/vertx/core/net/impl/TCPServerBase.java | 4 +++ src/test/java/io/vertx/core/net/NetTest.java | 14 ++++---- 5 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/main/java/io/vertx/core/net/impl/SSLHelper.java b/src/main/java/io/vertx/core/net/impl/SSLHelper.java index 1fb4fc0abed..017b0ea747e 100755 --- a/src/main/java/io/vertx/core/net/impl/SSLHelper.java +++ b/src/main/java/io/vertx/core/net/impl/SSLHelper.java @@ -124,6 +124,14 @@ public SSLHelper(TCPSSLOptions options, List applicationProtocols) { this.applicationProtocols = applicationProtocols; } + public synchronized int sniEntrySize() { + CachedProvider res = cachedProvider.result(); + if (res != null) { + return res.sslChannelProvider.sniEntrySize(); + } + return 0; + } + private static class CachedProvider { final SSLOptions options; final SslChannelProvider sslChannelProvider; diff --git a/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java b/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java index 0460b334140..290bf8c23f7 100644 --- a/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java +++ b/src/main/java/io/vertx/core/net/impl/SslChannelProvider.java @@ -65,6 +65,10 @@ public SslChannelProvider(SslContextProvider sslContextProvider, this.sslContextProvider = sslContextProvider; } + public int sniEntrySize() { + return sslContextMaps[0].size() + sslContextMaps[1].size(); + } + public SslContextProvider sslContextProvider() { return sslContextProvider; } @@ -83,17 +87,18 @@ public SslContext sslClientContext(String serverName, boolean useAlpn, boolean t public SslContext sslContext(String serverName, boolean useAlpn, boolean server, boolean trustAll) throws Exception { int idx = idx(useAlpn); - if (serverName == null) { - if (sslContexts[idx] == null) { - SslContext context = sslContextProvider.createContext(server, null, null, null, useAlpn, trustAll); - sslContexts[idx] = context; - } - return sslContexts[idx]; - } else { + if (serverName != null) { KeyManagerFactory kmf = sslContextProvider.resolveKeyManagerFactory(serverName); TrustManager[] trustManagers = trustAll ? null : sslContextProvider.resolveTrustManagers(serverName); - return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createContext(server, kmf, trustManagers, s, useAlpn, trustAll)); + if (kmf != null || trustManagers != null || !server) { + return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createContext(server, kmf, trustManagers, s, useAlpn, trustAll)); + } + } + if (sslContexts[idx] == null) { + SslContext context = sslContextProvider.createContext(server, null, null, serverName, useAlpn, trustAll); + sslContexts[idx] = context; } + return sslContexts[idx]; } public SslContext sslServerContext(boolean useAlpn) { diff --git a/src/main/java/io/vertx/core/net/impl/SslContextProvider.java b/src/main/java/io/vertx/core/net/impl/SslContextProvider.java index fcbefb91ee4..e44cefda4b6 100644 --- a/src/main/java/io/vertx/core/net/impl/SslContextProvider.java +++ b/src/main/java/io/vertx/core/net/impl/SslContextProvider.java @@ -154,13 +154,6 @@ protected void initEngine(SSLEngine engine) { } } - public KeyManagerFactory loadKeyManagerFactory(String serverName) throws Exception { - if (keyManagerFactoryMapper != null) { - return keyManagerFactoryMapper.apply(serverName); - } - return null; - } - public TrustManager[] defaultTrustManagers() { return trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null; } @@ -174,8 +167,7 @@ public KeyManagerFactory defaultKeyManagerFactory() { } /** - * Resolve the {@link KeyManagerFactory} for the {@code serverName}, when a factory cannot be resolved, the default - * factory is returned. + * Resolve the {@link KeyManagerFactory} for the {@code serverName}, when a factory cannot be resolved, {@code null} is returned. *
* This can block and should be executed on the appropriate thread. * @@ -184,23 +176,14 @@ public KeyManagerFactory defaultKeyManagerFactory() { * @throws Exception anything that would prevent loading the factory */ public KeyManagerFactory resolveKeyManagerFactory(String serverName) throws Exception { - KeyManagerFactory kmf = loadKeyManagerFactory(serverName); - if (kmf == null) { - kmf = keyManagerFactory; - } - return kmf; - } - - public TrustManager[] loadTrustManagers(String serverName) throws Exception { - if (trustManagerMapper != null) { - return trustManagerMapper.apply(serverName); + if (keyManagerFactoryMapper != null) { + return keyManagerFactoryMapper.apply(serverName); } return null; } /** - * Resolve the {@link TrustManager}[] for the {@code serverName}, when managers cannot be resolved, the default - * managers are returned. + * Resolve the {@link TrustManager}[] for the {@code serverName}, when managers cannot be resolved, {@code null} is returned. *
* This can block and should be executed on the appropriate thread. * @@ -209,11 +192,10 @@ public TrustManager[] loadTrustManagers(String serverName) throws Exception { * @throws Exception anything that would prevent loading the managers */ public TrustManager[] resolveTrustManagers(String serverName) throws Exception { - TrustManager[] trustManagers = loadTrustManagers(serverName); - if (trustManagers == null && trustManagerFactory != null) { - trustManagers = trustManagerFactory.getTrustManagers(); + if (trustManagerMapper != null) { + return trustManagerMapper.apply(serverName); } - return trustManagers; + return null; } private VertxTrustManagerFactory buildVertxTrustManagerFactory(TrustManager[] mgrs) { diff --git a/src/main/java/io/vertx/core/net/impl/TCPServerBase.java b/src/main/java/io/vertx/core/net/impl/TCPServerBase.java index 5de3a611f3e..bf86f6f8381 100644 --- a/src/main/java/io/vertx/core/net/impl/TCPServerBase.java +++ b/src/main/java/io/vertx/core/net/impl/TCPServerBase.java @@ -127,6 +127,10 @@ private GlobalTrafficShapingHandler createTrafficShapingHandler(EventLoopGroup e return trafficShapingHandler; } + public int sniEntrySize() { + return sslHelper.sniEntrySize(); + } + public Future updateSSLOptions(SSLOptions options) { TCPServerBase server = actualServer; if (server != null && server != this) { diff --git a/src/test/java/io/vertx/core/net/NetTest.java b/src/test/java/io/vertx/core/net/NetTest.java index aa61cb5e88c..c92b9359016 100755 --- a/src/test/java/io/vertx/core/net/NetTest.java +++ b/src/test/java/io/vertx/core/net/NetTest.java @@ -58,10 +58,7 @@ import io.vertx.core.impl.logging.LoggerFactory; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; -import io.vertx.core.net.impl.HAProxyMessageCompletionHandler; -import io.vertx.core.net.impl.NetServerImpl; -import io.vertx.core.net.impl.NetSocketInternal; -import io.vertx.core.net.impl.VertxHandler; +import io.vertx.core.net.impl.*; import io.vertx.core.spi.tls.SslContextFactory; import io.vertx.core.streams.ReadStream; import io.vertx.test.core.CheckingSender; @@ -1536,14 +1533,17 @@ public void testClientSniMultipleServerName() throws Exception { receivedServerNames.add(so.indicatedServerName()); }); startServer(); - List serverNames = Arrays.asList("host1", "host2.com"); + List serverNames = Arrays.asList("host1", "host2.com", "fake"); + List cns = new ArrayList<>(); client = vertx.createNetClient(new NetClientOptions().setSsl(true).setTrustAll(true)); for (String serverName : serverNames) { NetSocket so = client.connect(testAddress, serverName).toCompletionStage().toCompletableFuture().get(); String host = cnOf(so.peerCertificates().get(0)); - assertEquals(serverName, host); + cns.add(host); } - assertWaitUntil(() -> receivedServerNames.size() == 2); + assertEquals(Arrays.asList("host1", "host2.com", "localhost"), cns); + assertEquals(2, ((TCPServerBase)server).sniEntrySize()); + assertWaitUntil(() -> receivedServerNames.size() == 3); assertEquals(receivedServerNames, serverNames); }