Skip to content

Commit 032de2b

Browse files
ben1222vietj
authored andcommitted
Add peer host and port info for server SslHandler
1 parent 3600204 commit 032de2b

File tree

8 files changed

+289
-15
lines changed

8 files changed

+289
-15
lines changed

src/main/java/io/vertx/core/http/impl/HttpServerWorker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public void accept(Channel ch, SslChannelProvider sslChannelProvider) {
129129
private void configurePipeline(Channel ch, SslChannelProvider sslChannelProvider) {
130130
ChannelPipeline pipeline = ch.pipeline();
131131
if (options.isSsl()) {
132-
pipeline.addLast("ssl", sslChannelProvider.createServerHandler());
132+
pipeline.addLast("ssl", sslChannelProvider.createServerHandler(HttpUtils.socketAddressToHostAndPort(ch.remoteAddress())));
133133
ChannelPromise p = ch.newPromise();
134134
pipeline.addLast("handshaker", new SslHandshakeCompletionHandler(p));
135135
p.addListener(future -> {

src/main/java/io/vertx/core/http/impl/HttpUtils.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import java.io.FileNotFoundException;
4141
import java.io.IOException;
4242
import java.io.RandomAccessFile;
43+
import java.net.InetSocketAddress;
44+
import java.net.SocketAddress;
4345
import java.net.URI;
4446
import java.net.URISyntaxException;
4547
import java.nio.charset.Charset;
@@ -1078,4 +1080,20 @@ public static boolean canUpgradeToWebSocket(HttpServerRequest req) {
10781080
}
10791081
return false;
10801082
}
1083+
1084+
/**
1085+
* Convert a {@link SocketAddress} to a {@link HostAndPort}.
1086+
* If the socket address is an {@link InetSocketAddress}, the hostString and port are used.
1087+
* Otherwise {@code null} is returned.
1088+
*
1089+
* @param socketAddress The socket address to convert
1090+
* @return The converted instance or {@code null} if not applicable.
1091+
*/
1092+
public static HostAndPort socketAddressToHostAndPort(SocketAddress socketAddress) {
1093+
if (socketAddress instanceof InetSocketAddress) {
1094+
InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
1095+
return new HostAndPortImpl(inetSocketAddress.getHostString(), inetSocketAddress.getPort());
1096+
}
1097+
return null;
1098+
}
10811099
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import io.netty.channel.Channel;
1515
import io.netty.channel.ChannelPipeline;
1616
import io.netty.channel.ChannelPromise;
17-
import io.netty.channel.EventLoopGroup;
1817
import io.netty.handler.codec.haproxy.HAProxyMessageDecoder;
1918
import io.netty.handler.logging.LoggingHandler;
2019
import io.netty.handler.stream.ChunkedWriteHandler;
@@ -26,6 +25,7 @@
2625
import io.vertx.core.Future;
2726
import io.vertx.core.Handler;
2827
import io.vertx.core.Promise;
28+
import io.vertx.core.http.impl.HttpUtils;
2929
import io.vertx.core.impl.ContextInternal;
3030
import io.vertx.core.impl.VertxInternal;
3131
import io.vertx.core.impl.logging.Logger;
@@ -34,7 +34,6 @@
3434
import io.vertx.core.net.NetServerOptions;
3535
import io.vertx.core.net.NetSocket;
3636
import io.vertx.core.net.SocketAddress;
37-
import io.vertx.core.net.TrafficShapingOptions;
3837
import io.vertx.core.spi.metrics.MetricsProvider;
3938
import io.vertx.core.spi.metrics.TCPMetrics;
4039
import io.vertx.core.spi.metrics.VertxMetrics;
@@ -223,7 +222,7 @@ public void accept(Channel ch, SslChannelProvider sslChannelProvider) {
223222

224223
private void configurePipeline(Channel ch, SslChannelProvider sslChannelProvider) {
225224
if (options.isSsl()) {
226-
ch.pipeline().addLast("ssl", sslChannelProvider.createServerHandler());
225+
ch.pipeline().addLast("ssl", sslChannelProvider.createServerHandler(HttpUtils.socketAddressToHostAndPort(ch.remoteAddress())));
227226
ChannelPromise p = ch.newPromise();
228227
ch.pipeline().addLast("handshaker", new SslHandshakeCompletionHandler(p));
229228
p.addListener(future -> {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import io.vertx.core.buffer.Buffer;
2727
import io.vertx.core.eventbus.Message;
2828
import io.vertx.core.eventbus.MessageConsumer;
29+
import io.vertx.core.http.impl.HttpUtils;
2930
import io.vertx.core.impl.ContextInternal;
3031
import io.vertx.core.impl.future.PromiseInternal;
3132
import io.vertx.core.impl.logging.Logger;
@@ -337,7 +338,7 @@ public Future<Void> upgradeToSsl(String serverName) {
337338
if (remoteAddress != null) {
338339
sslHandler = sslChannelProvider.createClientSslHandler(remoteAddress, serverName, false);
339340
} else {
340-
sslHandler = sslChannelProvider.createServerHandler();
341+
sslHandler = sslChannelProvider.createServerHandler(HttpUtils.socketAddressToHostAndPort(chctx.channel().remoteAddress()));
341342
}
342343
chctx.pipeline().addFirst("ssl", sslHandler);
343344
} else {

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.netty.util.AsyncMapping;
1919
import io.netty.util.concurrent.ImmediateExecutor;
2020
import io.vertx.core.VertxException;
21+
import io.vertx.core.net.HostAndPort;
2122
import io.vertx.core.net.SocketAddress;
2223

2324
import javax.net.ssl.KeyManagerFactory;
@@ -143,25 +144,30 @@ public SslHandler createClientSslHandler(SocketAddress remoteAddress, String ser
143144
return sslHandler;
144145
}
145146

146-
public ChannelHandler createServerHandler() {
147+
public ChannelHandler createServerHandler(HostAndPort remoteAddress) {
147148
if (sni) {
148-
return createSniHandler();
149+
return createSniHandler(remoteAddress);
149150
} else {
150-
return createServerSslHandler(useAlpn);
151+
return createServerSslHandler(useAlpn, remoteAddress);
151152
}
152153
}
153154

154-
private SslHandler createServerSslHandler(boolean useAlpn) {
155+
private SslHandler createServerSslHandler(boolean useAlpn, HostAndPort remoteAddress) {
155156
SslContext sslContext = sslServerContext(useAlpn);
156157
Executor delegatedTaskExec = useWorkerPool ? workerPool : ImmediateExecutor.INSTANCE;
157-
SslHandler sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, delegatedTaskExec);
158+
SslHandler sslHandler;
159+
if (remoteAddress != null) {
160+
sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, remoteAddress.host(), remoteAddress.port(), delegatedTaskExec);
161+
} else {
162+
sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, delegatedTaskExec);
163+
}
158164
sslHandler.setHandshakeTimeout(sslHandshakeTimeout, sslHandshakeTimeoutUnit);
159165
return sslHandler;
160166
}
161167

162-
private SniHandler createSniHandler() {
168+
private SniHandler createSniHandler(HostAndPort remoteAddress) {
163169
Executor delegatedTaskExec = useWorkerPool ? workerPool : ImmediateExecutor.INSTANCE;
164-
return new VertxSniHandler(serverNameMapping(), sslHandshakeTimeoutUnit.toMillis(sslHandshakeTimeout), delegatedTaskExec);
170+
return new VertxSniHandler(serverNameMapping(), sslHandshakeTimeoutUnit.toMillis(sslHandshakeTimeout), delegatedTaskExec, remoteAddress);
165171
}
166172

167173
private static int idx(boolean useAlpn) {

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.netty.handler.ssl.SslContext;
1616
import io.netty.handler.ssl.SslHandler;
1717
import io.netty.util.AsyncMapping;
18+
import io.vertx.core.net.HostAndPort;
1819

1920
import java.util.concurrent.Executor;
2021
import java.util.concurrent.TimeUnit;
@@ -27,16 +28,24 @@
2728
class VertxSniHandler extends SniHandler {
2829

2930
private final Executor delegatedTaskExec;
31+
private final HostAndPort remoteAddress;
3032

31-
public VertxSniHandler(AsyncMapping<? super String, ? extends SslContext> mapping, long handshakeTimeoutMillis, Executor delegatedTaskExec) {
33+
public VertxSniHandler(AsyncMapping<? super String, ? extends SslContext> mapping, long handshakeTimeoutMillis, Executor delegatedTaskExec,
34+
HostAndPort remoteAddress) {
3235
super(mapping, handshakeTimeoutMillis);
3336

3437
this.delegatedTaskExec = delegatedTaskExec;
38+
this.remoteAddress = remoteAddress;
3539
}
3640

3741
@Override
3842
protected SslHandler newSslHandler(SslContext context, ByteBufAllocator allocator) {
39-
SslHandler sslHandler = context.newHandler(allocator, delegatedTaskExec);
43+
SslHandler sslHandler;
44+
if (remoteAddress != null) {
45+
sslHandler = context.newHandler(allocator, remoteAddress.host(), remoteAddress.port(), delegatedTaskExec);
46+
} else {
47+
sslHandler = context.newHandler(allocator, delegatedTaskExec);
48+
}
4049
sslHandler.setHandshakeTimeout(handshakeTimeoutMillis, TimeUnit.MILLISECONDS);
4150
return sslHandler;
4251
}

src/test/java/io/vertx/core/http/HttpTLSTest.java

Lines changed: 191 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,17 @@
2727
import java.security.interfaces.RSAPrivateKey;
2828
import java.util.*;
2929
import java.util.concurrent.CountDownLatch;
30+
import java.util.concurrent.atomic.AtomicBoolean;
3031
import java.util.concurrent.atomic.AtomicInteger;
3132
import java.util.concurrent.atomic.AtomicReference;
33+
import java.util.function.BiConsumer;
3234
import java.util.function.Function;
3335
import java.util.function.Supplier;
3436

3537
import javax.net.ssl.*;
3638

3739
import io.vertx.core.*;
3840
import io.vertx.core.impl.VertxThread;
39-
import io.vertx.core.net.SSLOptions;
4041
import io.vertx.core.net.impl.KeyStoreHelper;
4142
import org.junit.Assume;
4243
import org.junit.Rule;
@@ -2105,4 +2106,193 @@ public PrivateKey getPrivateKey(String alias) {
21052106
// It is fine using worker threads in this case
21062107
}
21072108
}
2109+
2110+
/**
2111+
* Test that for HttpServer, the peer host and port info is available in the SSLEngine
2112+
* when the X509ExtendedKeyManager.chooseEngineServerAlias is called.
2113+
*
2114+
* @throws Exception if an error occurs
2115+
*/
2116+
@Test
2117+
public void testTLSServerSSLEnginePeerHost() throws Exception {
2118+
AtomicBoolean called = new AtomicBoolean(false);
2119+
testTLS(Cert.NONE, Trust.SERVER_JKS, testPeerHostServerCert(Cert.SERVER_JKS, called), Trust.NONE).pass();
2120+
assertTrue("X509ExtendedKeyManager.chooseEngineServerAlias is not called", called.get());
2121+
}
2122+
2123+
/**
2124+
* Test that for HttpServer with SNI, the peer host and port info is available in the SSLEngine
2125+
* when the X509ExtendedKeyManager.chooseEngineServerAlias is called.
2126+
*
2127+
* @throws Exception if an error occurs
2128+
*/
2129+
@Test
2130+
public void testSNIServerSSLEnginePeerHost() throws Exception {
2131+
AtomicBoolean called = new AtomicBoolean(false);
2132+
TLSTest test = testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, testPeerHostServerCert(Cert.SNI_JKS, called), Trust.NONE)
2133+
.serverSni()
2134+
.requestOptions(new RequestOptions().setSsl(true).setPort(DEFAULT_HTTPS_PORT).setHost("host2.com"))
2135+
.pass();
2136+
assertEquals("host2.com", TestUtils.cnOf(test.clientPeerCert()));
2137+
assertEquals("host2.com", test.indicatedServerName);
2138+
assertTrue("X509ExtendedKeyManager.chooseEngineServerAlias is not called", called.get());
2139+
}
2140+
2141+
/**
2142+
* Create a {@link Cert} that will verify the peer host is not null and port is not -1 in the {@link SSLEngine}
2143+
* when the {@link X509ExtendedKeyManager#chooseEngineServerAlias(String, Principal[], SSLEngine)}
2144+
* is called.
2145+
*
2146+
* @param delegate The delegated Cert
2147+
* @param chooseEngineServerAliasCalled Will be set to true when the
2148+
* X509ExtendedKeyManager.chooseEngineServerAlias is called
2149+
* @return The {@link Cert}
2150+
*/
2151+
public static Cert<KeyCertOptions> testPeerHostServerCert(Cert<? extends KeyCertOptions> delegate, AtomicBoolean chooseEngineServerAliasCalled) {
2152+
return testPeerHostServerCert(delegate, (peerHost, peerPort) -> {
2153+
chooseEngineServerAliasCalled.set(true);
2154+
if (peerHost == null || peerPort == -1) {
2155+
throw new RuntimeException("Missing peer host/port");
2156+
}
2157+
});
2158+
}
2159+
2160+
/**
2161+
* Create a {@link Cert} that will verify the peer host and port in the {@link SSLEngine}
2162+
* when the {@link X509ExtendedKeyManager#chooseEngineServerAlias(String, Principal[], SSLEngine)}
2163+
* is called.
2164+
*
2165+
* @param delegate The delegated Cert
2166+
* @param peerHostVerifier The consumer to verify the peer host and port when the
2167+
* X509ExtendedKeyManager.chooseEngineServerAlias is called
2168+
* @return The {@link Cert}
2169+
*/
2170+
public static Cert<KeyCertOptions> testPeerHostServerCert(Cert<? extends KeyCertOptions> delegate, BiConsumer<String, Integer> peerHostVerifier) {
2171+
return () -> new VerifyServerPeerHostKeyCertOptions(delegate.get(), peerHostVerifier);
2172+
}
2173+
2174+
private static class VerifyServerPeerHostKeyCertOptions implements KeyCertOptions {
2175+
private final KeyCertOptions delegate;
2176+
private final BiConsumer<String, Integer> peerHostVerifier;
2177+
2178+
VerifyServerPeerHostKeyCertOptions(KeyCertOptions delegate, BiConsumer<String, Integer> peerHostVerifier) {
2179+
this.delegate = delegate;
2180+
this.peerHostVerifier = peerHostVerifier;
2181+
}
2182+
2183+
@Override
2184+
public KeyCertOptions copy() {
2185+
return new VerifyServerPeerHostKeyCertOptions(delegate.copy(), peerHostVerifier);
2186+
}
2187+
2188+
@Override
2189+
public KeyManagerFactory getKeyManagerFactory(Vertx vertx) throws Exception {
2190+
return new VerifyServerPeerHostKeyManagerFactory(delegate.getKeyManagerFactory(vertx), peerHostVerifier);
2191+
}
2192+
2193+
@Override
2194+
public Function<String, KeyManagerFactory> keyManagerFactoryMapper(Vertx vertx) throws Exception {
2195+
Function<String, KeyManagerFactory> mapper = delegate.keyManagerFactoryMapper(vertx);
2196+
return serverName -> new VerifyServerPeerHostKeyManagerFactory(mapper.apply(serverName), peerHostVerifier);
2197+
}
2198+
}
2199+
2200+
private static class VerifyServerPeerHostKeyManagerFactory extends KeyManagerFactory {
2201+
VerifyServerPeerHostKeyManagerFactory(KeyManagerFactory delegate, BiConsumer<String, Integer> peerHostVerifier) {
2202+
super(new KeyManagerFactorySpiWrapper(delegate, peerHostVerifier), delegate.getProvider(), delegate.getAlgorithm());
2203+
}
2204+
2205+
private static class KeyManagerFactorySpiWrapper extends KeyManagerFactorySpi {
2206+
private final KeyManagerFactory delegate;
2207+
private final BiConsumer<String, Integer> peerHostVerifier;
2208+
2209+
KeyManagerFactorySpiWrapper(KeyManagerFactory delegate, BiConsumer<String, Integer> peerHostVerifier) {
2210+
super();
2211+
this.delegate = delegate;
2212+
this.peerHostVerifier = peerHostVerifier;
2213+
}
2214+
2215+
@Override
2216+
protected void engineInit(KeyStore keyStore, char[] chars) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
2217+
delegate.init(keyStore, chars);
2218+
}
2219+
2220+
@Override
2221+
protected void engineInit(ManagerFactoryParameters managerFactoryParameters) throws InvalidAlgorithmParameterException {
2222+
delegate.init(managerFactoryParameters);
2223+
}
2224+
2225+
@Override
2226+
protected KeyManager[] engineGetKeyManagers() {
2227+
KeyManager[] keyManagers = delegate.getKeyManagers().clone();
2228+
for (int i = 0; i < keyManagers.length; ++i) {
2229+
KeyManager km = keyManagers[i];
2230+
if (km instanceof X509KeyManager) {
2231+
keyManagers[i] = new VerifyServerPeerHostKeyManager((X509KeyManager) km, peerHostVerifier);
2232+
}
2233+
}
2234+
2235+
return keyManagers;
2236+
}
2237+
}
2238+
}
2239+
2240+
private static class VerifyServerPeerHostKeyManager extends X509ExtendedKeyManager {
2241+
private final X509KeyManager delegate;
2242+
private final BiConsumer<String, Integer> peerHostVerifier;
2243+
2244+
VerifyServerPeerHostKeyManager(X509KeyManager delegate, BiConsumer<String, Integer> peerHostVerifier) {
2245+
this.delegate = delegate;
2246+
this.peerHostVerifier = peerHostVerifier;
2247+
}
2248+
2249+
@Override
2250+
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
2251+
if (delegate instanceof X509ExtendedKeyManager) {
2252+
return ((X509ExtendedKeyManager) delegate).chooseEngineClientAlias(keyType, issuers, engine);
2253+
} else {
2254+
return delegate.chooseClientAlias(keyType, issuers, null);
2255+
}
2256+
}
2257+
2258+
@Override
2259+
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine) {
2260+
peerHostVerifier.accept(engine.getPeerHost(), engine.getPeerPort());
2261+
if (delegate instanceof X509ExtendedKeyManager) {
2262+
return ((X509ExtendedKeyManager) delegate).chooseEngineServerAlias(keyType, issuers, engine);
2263+
} else {
2264+
return delegate.chooseServerAlias(keyType, issuers, null);
2265+
}
2266+
}
2267+
2268+
@Override
2269+
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
2270+
return delegate.chooseClientAlias(keyType, issuers, socket);
2271+
}
2272+
2273+
@Override
2274+
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
2275+
return delegate.chooseServerAlias(keyType, issuers, socket);
2276+
}
2277+
2278+
@Override
2279+
public String[] getClientAliases(String s, Principal[] principals) {
2280+
return delegate.getClientAliases(s, principals);
2281+
}
2282+
2283+
@Override
2284+
public String[] getServerAliases(String s, Principal[] principals) {
2285+
return delegate.getServerAliases(s, principals);
2286+
}
2287+
2288+
@Override
2289+
public X509Certificate[] getCertificateChain(String s) {
2290+
return delegate.getCertificateChain(s);
2291+
}
2292+
2293+
@Override
2294+
public PrivateKey getPrivateKey(String s) {
2295+
return delegate.getPrivateKey(s);
2296+
}
2297+
}
21082298
}

0 commit comments

Comments
 (0)