Skip to content

Commit

Permalink
Add peer host and port info for server SslHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
ben1222 committed Oct 24, 2024
1 parent 78e2176 commit 8678c41
Show file tree
Hide file tree
Showing 7 changed files with 291 additions and 11 deletions.
18 changes: 18 additions & 0 deletions vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -819,4 +821,20 @@ public static boolean canUpgradeToWebSocket(HttpServerRequest req) {
}
return false;
}

/**
* Convert a {@link SocketAddress} to a {@link HostAndPort}.
* If the socket address is an {@link InetSocketAddress}, the hostString and port are used.
* Otherwise {@code null} is returned.
*
* @param socketAddress The socket address to convert
* @return The converted instance or {@code null} if not applicable.
*/
public static HostAndPort socketAddressToHostAndPort(SocketAddress socketAddress) {
if (socketAddress instanceof InetSocketAddress) {
InetSocketAddress inetSocketAddress = (InetSocketAddress) socketAddress;
return new HostAndPortImpl(inetSocketAddress.getHostString(), inetSocketAddress.getPort());
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
import io.netty.util.concurrent.ImmediateExecutor;
import io.vertx.core.internal.VertxInternal;
import io.vertx.core.internal.tls.SslContextProvider;
import io.vertx.core.net.HostAndPort;
import io.vertx.core.net.SocketAddress;

import java.net.InetSocketAddress;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -59,25 +61,30 @@ public SslHandler createClientSslHandler(SocketAddress peerAddress, String serve
return sslHandler;
}

public ChannelHandler createServerHandler(boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit) {
public ChannelHandler createServerHandler(boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit, HostAndPort remoteAddress) {
if (sni) {
return createSniHandler(useAlpn, sslHandshakeTimeout, sslHandshakeTimeoutUnit);
return createSniHandler(useAlpn, sslHandshakeTimeout, sslHandshakeTimeoutUnit, remoteAddress);
} else {
return createServerSslHandler(useAlpn, sslHandshakeTimeout, sslHandshakeTimeoutUnit);
return createServerSslHandler(useAlpn, sslHandshakeTimeout, sslHandshakeTimeoutUnit, remoteAddress);
}
}

private SslHandler createServerSslHandler(boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit) {
private SslHandler createServerSslHandler(boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit, HostAndPort remoteAddress) {
SslContext sslContext = sslContextProvider.sslServerContext(useAlpn);
Executor delegatedTaskExec = sslContextProvider.useWorkerPool() ? workerPool : ImmediateExecutor.INSTANCE;
SslHandler sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, delegatedTaskExec);
SslHandler sslHandler;
if (remoteAddress != null) {
sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, remoteAddress.host(), remoteAddress.port(), delegatedTaskExec);
} else {
sslHandler = sslContext.newHandler(ByteBufAllocator.DEFAULT, delegatedTaskExec);
}
sslHandler.setHandshakeTimeout(sslHandshakeTimeout, sslHandshakeTimeoutUnit);
return sslHandler;
}

private SniHandler createSniHandler(boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit) {
private SniHandler createSniHandler(boolean useAlpn, long sslHandshakeTimeout, TimeUnit sslHandshakeTimeoutUnit, HostAndPort remoteAddress) {
Executor delegatedTaskExec = sslContextProvider.useWorkerPool() ? workerPool : ImmediateExecutor.INSTANCE;
return new VertxSniHandler(sslContextProvider.serverNameMapping(delegatedTaskExec, useAlpn), sslHandshakeTimeoutUnit.toMillis(sslHandshakeTimeout), delegatedTaskExec);
return new VertxSniHandler(sslContextProvider.serverNameMapping(delegatedTaskExec, useAlpn), sslHandshakeTimeoutUnit.toMillis(sslHandshakeTimeout), delegatedTaskExec, remoteAddress);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.AsyncMapping;
import io.vertx.core.net.HostAndPort;

import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
Expand All @@ -27,16 +28,24 @@
class VertxSniHandler extends SniHandler {

private final Executor delegatedTaskExec;
private final HostAndPort remoteAddress;

public VertxSniHandler(AsyncMapping<? super String, ? extends SslContext> mapping, long handshakeTimeoutMillis, Executor delegatedTaskExec) {
public VertxSniHandler(AsyncMapping<? super String, ? extends SslContext> mapping, long handshakeTimeoutMillis, Executor delegatedTaskExec,
HostAndPort remoteAddress) {
super(mapping, handshakeTimeoutMillis);

this.delegatedTaskExec = delegatedTaskExec;
this.remoteAddress = remoteAddress;
}

@Override
protected SslHandler newSslHandler(SslContext context, ByteBufAllocator allocator) {
SslHandler sslHandler = context.newHandler(allocator, delegatedTaskExec);
SslHandler sslHandler;
if (remoteAddress != null) {
sslHandler = context.newHandler(allocator, remoteAddress.host(), remoteAddress.port(), delegatedTaskExec);
} else {
sslHandler = context.newHandler(allocator, delegatedTaskExec);
}
sslHandler.setHandshakeTimeout(handshakeTimeoutMillis, TimeUnit.MILLISECONDS);
return sslHandler;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import io.vertx.core.buffer.impl.PartialPooledByteBufAllocator;
import io.vertx.core.http.ClientAuth;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.http.impl.HttpUtils;
import io.vertx.core.internal.CloseSequence;
import io.vertx.core.impl.HostnameResolver;
import io.vertx.core.internal.ContextInternal;
Expand Down Expand Up @@ -221,7 +222,8 @@ public void accept(Channel ch, SslContextProvider sslChannelProvider, SslContext
private void configurePipeline(Channel ch, SslContextProvider sslContextProvider, SslContextManager sslContextManager, ServerSSLOptions sslOptions) {
if (options.isSsl()) {
SslChannelProvider sslChannelProvider = new SslChannelProvider(vertx, sslContextProvider, sslOptions.isSni());
ch.pipeline().addLast("ssl", sslChannelProvider.createServerHandler(options.isUseAlpn(), options.getSslHandshakeTimeout(), options.getSslHandshakeTimeoutUnit()));
ch.pipeline().addLast("ssl", sslChannelProvider.createServerHandler(options.isUseAlpn(), options.getSslHandshakeTimeout(),
options.getSslHandshakeTimeoutUnit(), HttpUtils.socketAddressToHostAndPort(ch.remoteAddress())));
ChannelPromise p = ch.newPromise();
ch.pipeline().addLast("handshaker", new SslHandshakeCompletionHandler(p));
p.addListener(future -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.vertx.core.eventbus.Message;
import io.vertx.core.eventbus.MessageConsumer;
import io.vertx.core.http.ClientAuth;
import io.vertx.core.http.impl.HttpUtils;
import io.vertx.core.internal.ContextInternal;
import io.vertx.core.internal.PromiseInternal;
import io.vertx.core.internal.concurrent.InboundMessageQueue;
Expand Down Expand Up @@ -323,7 +324,8 @@ private Future<Void> sslUpgrade(String serverName, SSLOptions sslOptions, ByteBu
ClientSSLOptions clientSSLOptions = (ClientSSLOptions) sslOptions;
sslHandler = provider.createClientSslHandler(remoteAddress, serverName, sslOptions.isUseAlpn(), clientSSLOptions.getSslHandshakeTimeout(), clientSSLOptions.getSslHandshakeTimeoutUnit());
} else {
sslHandler = provider.createServerHandler(sslOptions.isUseAlpn(), sslOptions.getSslHandshakeTimeout(), sslOptions.getSslHandshakeTimeoutUnit());
sslHandler = provider.createServerHandler(sslOptions.isUseAlpn(), sslOptions.getSslHandshakeTimeout(),
sslOptions.getSslHandshakeTimeoutUnit(), HttpUtils.socketAddressToHostAndPort(chctx.channel().remoteAddress()));
}
chctx.pipeline().addFirst("ssl", sslHandler);
channelPromise.addListener(p);
Expand Down
51 changes: 51 additions & 0 deletions vertx-core/src/test/java/io/vertx/tests/net/NetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
import static io.vertx.test.http.HttpTestBase.DEFAULT_HTTPS_HOST;
import static io.vertx.test.http.HttpTestBase.DEFAULT_HTTPS_PORT;
import static io.vertx.test.core.TestUtils.*;
import static io.vertx.tests.tls.HttpTLSTest.testPeerHostServerCert;
import static org.hamcrest.CoreMatchers.*;

/**
Expand Down Expand Up @@ -4602,4 +4603,54 @@ public void testConnectToServerShutdown() throws Exception {
assertWaitUntil(closed::get);
fut.await();
}

/**
* Test that for NetServer, the peer host and port info is available in the SSLEngine
* when the X509ExtendedKeyManager.chooseEngineServerAlias is called.
*
* @throws Exception if an error occurs
*/
@Test
public void testTLSServerSSLEnginePeerHost() throws Exception {
testTLSServerSSLEnginePeerHostImpl(false);
}

/**
* Test that for NetServer with start TLS, the peer host and port info is available
* in the SSLEngine when the X509ExtendedKeyManager.chooseEngineServerAlias is called.
*
* @throws Exception if an error occurs
*/
@Test
public void testStartTLSServerSSLEnginePeerHost() throws Exception {
testTLSServerSSLEnginePeerHostImpl(true);
}

private void testTLSServerSSLEnginePeerHostImpl(boolean startTLS) throws Exception {
AtomicBoolean called = new AtomicBoolean(false);
testTLS(Cert.NONE, Trust.SERVER_JKS, testPeerHostServerCert(Cert.SERVER_JKS, called), Trust.NONE,
false, false, true, startTLS);
assertTrue("X509ExtendedKeyManager.chooseEngineServerAlias is not called", called.get());
}

/**
* Test that for NetServer with SNI, the peer host and port info is available
* in the SSLEngine when the X509ExtendedKeyManager.chooseEngineServerAlias is called.
*
* @throws Exception if an error occurs
*/
@Test
public void testSNIServerSSLEnginePeerHost() throws Exception {
AtomicBoolean called = new AtomicBoolean(false);
TLSTest test = new TLSTest()
.clientTrust(Trust.SNI_JKS_HOST2)
.address(SocketAddress.inetSocketAddress(DEFAULT_HTTPS_PORT, "host2.com"))
.serverCert(testPeerHostServerCert(Cert.SNI_JKS, called))
.sni(true);
test.run(true);
await();
assertEquals("host2.com", cnOf(test.clientPeerCert()));
assertEquals("host2.com", test.indicatedServerName);
assertTrue("X509ExtendedKeyManager.chooseEngineServerAlias is not called", called.get());
}
}
Loading

0 comments on commit 8678c41

Please sign in to comment.