Skip to content

Commit 1b8a5bd

Browse files
committed
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.
1 parent 5e1cae2 commit 1b8a5bd

File tree

5 files changed

+41
-36
lines changed

5 files changed

+41
-36
lines changed

src/main/java/io/vertx/core/net/impl/SSLHelper.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@ public SSLHelper(SSLEngineOptions sslEngineOptions, int cacheMaxSize) {
100100
this.useWorkerPool = sslEngineOptions.getUseWorkerThread();
101101
}
102102

103+
public synchronized int sniEntrySize() {
104+
int size = 0;
105+
for (Future<SslChannelProvider> fut : sslChannelProviderMap.values()) {
106+
SslChannelProvider result = fut.result();
107+
if (result != null) {
108+
size += result.sniEntrySize();
109+
}
110+
}
111+
return size;
112+
}
113+
103114
public SSLHelper(SSLEngineOptions sslEngineOptions) {
104115
this(sslEngineOptions, 256);
105116
}

src/main/java/io/vertx/core/net/impl/SslChannelProvider.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ public SslChannelProvider(SslContextProvider sslContextProvider,
5353
this.sslContextProvider = sslContextProvider;
5454
}
5555

56+
public int sniEntrySize() {
57+
return sslContextMaps[0].size() + sslContextMaps[1].size();
58+
}
59+
5660
public SslContextProvider sslContextProvider() {
5761
return sslContextProvider;
5862
}
@@ -67,17 +71,18 @@ public SslContext sslClientContext(String serverName, boolean useAlpn, boolean t
6771

6872
public SslContext sslContext(String serverName, boolean useAlpn, boolean server, boolean trustAll) throws Exception {
6973
int idx = idx(useAlpn);
70-
if (serverName == null) {
71-
if (sslContexts[idx] == null) {
72-
SslContext context = sslContextProvider.createContext(server, null, null, null, useAlpn, trustAll);
73-
sslContexts[idx] = context;
74-
}
75-
return sslContexts[idx];
76-
} else {
74+
if (serverName != null) {
7775
KeyManagerFactory kmf = sslContextProvider.resolveKeyManagerFactory(serverName);
7876
TrustManager[] trustManagers = trustAll ? null : sslContextProvider.resolveTrustManagers(serverName);
79-
return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createContext(server, kmf, trustManagers, s, useAlpn, trustAll));
77+
if (kmf != null || trustManagers != null || !server) {
78+
return sslContextMaps[idx].computeIfAbsent(serverName, s -> sslContextProvider.createContext(server, kmf, trustManagers, s, useAlpn, trustAll));
79+
}
80+
}
81+
if (sslContexts[idx] == null) {
82+
SslContext context = sslContextProvider.createContext(server, null, null, serverName, useAlpn, trustAll);
83+
sslContexts[idx] = context;
8084
}
85+
return sslContexts[idx];
8186
}
8287

8388
public SslContext sslServerContext(boolean useAlpn) {

src/main/java/io/vertx/core/net/impl/SslContextProvider.java

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -154,13 +154,6 @@ protected void initEngine(SSLEngine engine) {
154154
}
155155
}
156156

157-
public KeyManagerFactory loadKeyManagerFactory(String serverName) throws Exception {
158-
if (keyManagerFactoryMapper != null) {
159-
return keyManagerFactoryMapper.apply(serverName);
160-
}
161-
return null;
162-
}
163-
164157
public TrustManager[] defaultTrustManagers() {
165158
return trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null;
166159
}
@@ -174,8 +167,7 @@ public KeyManagerFactory defaultKeyManagerFactory() {
174167
}
175168

176169
/**
177-
* Resolve the {@link KeyManagerFactory} for the {@code serverName}, when a factory cannot be resolved, the default
178-
* factory is returned.
170+
* Resolve the {@link KeyManagerFactory} for the {@code serverName}, when a factory cannot be resolved, {@code null} is returned.
179171
* <br/>
180172
* This can block and should be executed on the appropriate thread.
181173
*
@@ -184,23 +176,14 @@ public KeyManagerFactory defaultKeyManagerFactory() {
184176
* @throws Exception anything that would prevent loading the factory
185177
*/
186178
public KeyManagerFactory resolveKeyManagerFactory(String serverName) throws Exception {
187-
KeyManagerFactory kmf = loadKeyManagerFactory(serverName);
188-
if (kmf == null) {
189-
kmf = keyManagerFactory;
190-
}
191-
return kmf;
192-
}
193-
194-
public TrustManager[] loadTrustManagers(String serverName) throws Exception {
195-
if (trustManagerMapper != null) {
196-
return trustManagerMapper.apply(serverName);
179+
if (keyManagerFactoryMapper != null) {
180+
return keyManagerFactoryMapper.apply(serverName);
197181
}
198182
return null;
199183
}
200184

201185
/**
202-
* Resolve the {@link TrustManager}[] for the {@code serverName}, when managers cannot be resolved, the default
203-
* managers are returned.
186+
* Resolve the {@link TrustManager}[] for the {@code serverName}, when managers cannot be resolved, {@code null} is returned.
204187
* <br/>
205188
* This can block and should be executed on the appropriate thread.
206189
*
@@ -209,11 +192,10 @@ public TrustManager[] loadTrustManagers(String serverName) throws Exception {
209192
* @throws Exception anything that would prevent loading the managers
210193
*/
211194
public TrustManager[] resolveTrustManagers(String serverName) throws Exception {
212-
TrustManager[] trustManagers = loadTrustManagers(serverName);
213-
if (trustManagers == null && trustManagerFactory != null) {
214-
trustManagers = trustManagerFactory.getTrustManagers();
195+
if (trustManagerMapper != null) {
196+
return trustManagerMapper.apply(serverName);
215197
}
216-
return trustManagers;
198+
return null;
217199
}
218200

219201
private VertxTrustManagerFactory buildVertxTrustManagerFactory(TrustManager[] mgrs) {

src/main/java/io/vertx/core/net/impl/TCPServerBase.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ private GlobalTrafficShapingHandler createTrafficShapingHandler(EventLoopGroup e
122122
protected void configure(SSLOptions options) {
123123
}
124124

125+
public int sniEntrySize() {
126+
return sslHelper.sniEntrySize();
127+
}
128+
125129
public Future<Boolean> updateSSLOptions(ServerSSLOptions options, boolean force) {
126130
TCPServerBase server = actualServer;
127131
if (server != null && server != this) {

src/test/java/io/vertx/core/net/NetTest.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,14 +1481,17 @@ public void testClientSniMultipleServerName() throws Exception {
14811481
receivedServerNames.add(so.indicatedServerName());
14821482
});
14831483
startServer();
1484-
List<String> serverNames = Arrays.asList("host1", "host2.com");
1484+
List<String> serverNames = Arrays.asList("host1", "host2.com", "fake");
1485+
List<String> cns = new ArrayList<>();
14851486
client = vertx.createNetClient(new NetClientOptions().setSsl(true).setTrustAll(true));
14861487
for (String serverName : serverNames) {
14871488
NetSocket so = awaitFuture(client.connect(testAddress, serverName));
14881489
String host = cnOf(so.peerCertificates().get(0));
1489-
assertEquals(serverName, host);
1490+
cns.add(host);
14901491
}
1491-
assertWaitUntil(() -> receivedServerNames.size() == 2);
1492+
assertEquals(Arrays.asList("host1", "host2.com", "localhost"), cns);
1493+
assertEquals(2, ((TCPServerBase)server).sniEntrySize());
1494+
assertWaitUntil(() -> receivedServerNames.size() == 3);
14921495
assertEquals(receivedServerNames, serverNames);
14931496
}
14941497

0 commit comments

Comments
 (0)