Skip to content

Commit

Permalink
Allow to get the SNI server name on the connection
Browse files Browse the repository at this point in the history
  • Loading branch information
vietj committed Apr 26, 2017
1 parent 12208e7 commit 82e4ccf
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 13 deletions.
7 changes: 7 additions & 0 deletions src/main/java/io/vertx/core/http/HttpConnection.java
Expand Up @@ -264,4 +264,11 @@ default HttpConnection goAway(long errorCode, int lastStreamId) {
*/ */
@GenIgnore @GenIgnore
X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedException; X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedException;

/**
* Returns the SNI server name presented during the SSL handshake by the client.
*
* @return the indicated server name
*/
String indicatedServerName();
} }
Expand Up @@ -287,4 +287,9 @@ public boolean isSsl() {
public X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedException { public X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedException {
return conn.peerCertificateChain(); return conn.peerCertificateChain();
} }

@Override
public String indicatedServerName() {
return conn.indicatedServerName();
}
} }
7 changes: 7 additions & 0 deletions src/main/java/io/vertx/core/net/NetSocket.java
Expand Up @@ -241,5 +241,12 @@ default NetSocket sendFile(String filename, long offset, Handler<AsyncResult<Voi
*/ */
@GenIgnore @GenIgnore
X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedException; X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedException;

/**
* Returns the SNI server name presented during the SSL handshake by the client.
*
* @return the indicated server name
*/
String indicatedServerName();
} }


8 changes: 8 additions & 0 deletions src/main/java/io/vertx/core/net/impl/ConnectionBase.java
Expand Up @@ -272,6 +272,14 @@ public X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedExceptio
} }
} }


public String indicatedServerName() {
if (channel.hasAttr(VertxSniHandler.SERVER_NAME_ATTR)) {
return channel.attr(VertxSniHandler.SERVER_NAME_ATTR).get();
} else {
return null;
}
}

public String remoteName() { public String remoteName() {
InetSocketAddress addr = (InetSocketAddress) channel.remoteAddress(); InetSocketAddress addr = (InetSocketAddress) channel.remoteAddress();
if (addr == null) return null; if (addr == null) return null;
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/io/vertx/core/net/impl/VertxSniHandler.java
Expand Up @@ -20,6 +20,8 @@
import io.netty.handler.ssl.SniHandler; import io.netty.handler.ssl.SniHandler;
import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler; import io.netty.handler.ssl.SslHandler;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
import io.netty.util.concurrent.DefaultPromise; import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.EventExecutor;
Expand All @@ -34,8 +36,9 @@
*/ */
public class VertxSniHandler extends SniHandler { public class VertxSniHandler extends SniHandler {


public static AttributeKey<String> SERVER_NAME_ATTR = AttributeKey.valueOf("sniServerName");

private final SSLHelper helper; private final SSLHelper helper;
private final VertxInternal vertx;
private ChannelHandlerContext context; private ChannelHandlerContext context;
private final Promise<Channel> handshakeFuture; private final Promise<Channel> handshakeFuture;


Expand All @@ -44,7 +47,6 @@ public VertxSniHandler(SSLHelper helper, VertxInternal vertx) {
return helper.getContext(vertx, input); return helper.getContext(vertx, input);
}); });
this.helper = helper; this.helper = helper;
this.vertx = vertx;
this.handshakeFuture = new DefaultPromise<Channel>() { this.handshakeFuture = new DefaultPromise<Channel>() {
@Override @Override
protected EventExecutor executor() { protected EventExecutor executor() {
Expand Down Expand Up @@ -76,6 +78,8 @@ protected void replaceHandler(ChannelHandlerContext ctx, String hostname, SslCon
Future<Channel> fut = sslHandler.handshakeFuture(); Future<Channel> fut = sslHandler.handshakeFuture();
fut.addListener(future -> { fut.addListener(future -> {
if (future.isSuccess()) { if (future.isSuccess()) {
Attribute<String> val = ctx.channel().attr(SERVER_NAME_ATTR);
val.set(hostname);
handshakeFuture.setSuccess(ctx.channel()); handshakeFuture.setSuccess(ctx.channel());
} else { } else {
handshakeFuture.setFailure(future.cause()); handshakeFuture.setFailure(future.cause());
Expand Down
24 changes: 13 additions & 11 deletions src/test/java/io/vertx/test/core/HttpTLSTest.java
Expand Up @@ -382,13 +382,13 @@ public void testTLSClientCertPEMRequiredOpenSSL() throws Exception {
@Test @Test
// Client provides SNI and server responds with a matching certificate for the indicated server name // Client provides SNI and server responds with a matching certificate for the indicated server name
public void testSNITrust() throws Exception { public void testSNITrust() throws Exception {
X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST1, Cert.SNI_JKS, Trust.NONE) TLSTest test = testTLS(Cert.NONE, Trust.SNI_JKS_HOST1, Cert.SNI_JKS, Trust.NONE)
.serverSni() .serverSni()
.clientSni() .clientSni()
.requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host1")) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host1"))
.pass() .pass();
.clientPeerCert(); assertEquals("host1", TestUtils.cnOf(test.clientPeerCert()));
assertEquals("host1", TestUtils.cnOf(cert)); assertEquals("host1", test.indicatedServerName);
} }


@Test @Test
Expand Down Expand Up @@ -461,13 +461,13 @@ public void testSNIUnknownServerName2() throws Exception {
@Test @Test
// Client provides SNI matched on the server by a wildcard certificate // Client provides SNI matched on the server by a wildcard certificate
public void testSNIWildcardMatch() throws Exception { public void testSNIWildcardMatch() throws Exception {
X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST3, Cert.SNI_JKS, Trust.NONE) TLSTest test = testTLS(Cert.NONE, Trust.SNI_JKS_HOST3, Cert.SNI_JKS, Trust.NONE)
.serverSni() .serverSni()
.clientSni() .clientSni()
.requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("sub.host3")) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("sub.host3"))
.pass() .pass();
.clientPeerCert(); assertEquals("*.host3", TestUtils.cnOf(test.clientPeerCert()));
assertEquals("*.host3", TestUtils.cnOf(cert)); assertEquals("sub.host3", test.indicatedServerName);
} }


@Test @Test
Expand Down Expand Up @@ -699,11 +699,11 @@ public void testSNIWithOpenSSL() throws Exception {


@Test @Test
public void testSNIClientDisabled() throws Exception { public void testSNIClientDisabled() throws Exception {
testTLS(Cert.NONE, Trust.SNI_JKS_HOST1, Cert.SNI_JKS, Trust.NONE) TLSTest test = testTLS(Cert.NONE, Trust.SNI_JKS_HOST1, Cert.SNI_JKS, Trust.NONE)
.serverSni() .serverSni()
.requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host1")) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host1"))
.fail() .fail();
.clientPeerCert(); assertNull(test.indicatedServerName);
} }




Expand Down Expand Up @@ -774,6 +774,7 @@ class TLSTest {
return client.request(HttpMethod.POST, 4043, httpHost, DEFAULT_TEST_URI); return client.request(HttpMethod.POST, 4043, httpHost, DEFAULT_TEST_URI);
}; };
X509Certificate clientPeerCert; X509Certificate clientPeerCert;
String indicatedServerName;


public TLSTest(Cert<?> clientCert, Trust<?> clientTrust, Cert<?> serverCert, Trust<?> serverTrust) { public TLSTest(Cert<?> clientCert, Trust<?> clientTrust, Cert<?> serverCert, Trust<?> serverTrust) {
this.version = HttpVersion.HTTP_1_1; this.version = HttpVersion.HTTP_1_1;
Expand Down Expand Up @@ -983,6 +984,7 @@ TLSTest run(boolean shouldPass) {
} }
server = createHttpServer(serverOptions.setPort(4043)); server = createHttpServer(serverOptions.setPort(4043));
server.requestHandler(req -> { server.requestHandler(req -> {
indicatedServerName = req.connection().indicatedServerName();
assertEquals(version, req.version()); assertEquals(version, req.version());
req.bodyHandler(buffer -> { req.bodyHandler(buffer -> {
assertEquals(serverSSL, req.isSSL()); assertEquals(serverSSL, req.isSSL());
Expand Down
4 changes: 4 additions & 0 deletions src/test/java/io/vertx/test/core/NetTest.java
Expand Up @@ -1252,6 +1252,7 @@ public void testSniWithServerName1() throws Exception {
test.run(true); test.run(true);
await(); await();
assertEquals("host1", cnOf(test.clientPeerCert())); assertEquals("host1", cnOf(test.clientPeerCert()));
assertEquals("host1", test.indicatedServerName);
} }


@Test @Test
Expand Down Expand Up @@ -1349,6 +1350,7 @@ class TLSTest {
boolean sni; boolean sni;
String serverName; String serverName;
X509Certificate clientPeerCert; X509Certificate clientPeerCert;
String indicatedServerName;


public TLSTest clientCert(Cert<?> clientCert) { public TLSTest clientCert(Cert<?> clientCert) {
this.clientCert = clientCert; this.clientCert = clientCert;
Expand Down Expand Up @@ -1445,6 +1447,7 @@ void run(boolean shouldPass) {
options.setPort(4043); options.setPort(4043);
server = vertx.createNetServer(options); server = vertx.createNetServer(options);
Handler<NetSocket> serverHandler = socket -> { Handler<NetSocket> serverHandler = socket -> {
indicatedServerName = socket.indicatedServerName();
if (socket.isSsl()) { if (socket.isSsl()) {
certificateChainChecker.accept(socket); certificateChainChecker.accept(socket);
} }
Expand All @@ -1454,6 +1457,7 @@ void run(boolean shouldPass) {
socket.write(buff); // echo the data socket.write(buff); // echo the data
if (startTLS) { if (startTLS) {
if (upgradedServer.compareAndSet(false, true)) { if (upgradedServer.compareAndSet(false, true)) {
indicatedServerName = socket.indicatedServerName();
assertFalse(socket.isSsl()); assertFalse(socket.isSsl());
socket.upgradeToSsl(v -> { socket.upgradeToSsl(v -> {
certificateChainChecker.accept(socket); certificateChainChecker.accept(socket);
Expand Down

0 comments on commit 82e4ccf

Please sign in to comment.