Proper handling of host names ending with a dot in client connections - closes #3080

This commit is contained in:
Julien Viet
2019-08-21 10:54:32 +02:00
parent 692ffc02a8
commit 27c3a13596
6 changed files with 93 additions and 8 deletions

View File

@@ -434,7 +434,11 @@ public class HttpClientRequestImpl extends HttpClientRequestBase implements Http
peerAddress = SocketAddress.inetSocketAddress(80, hostHeader);
}
} else {
peerAddress = SocketAddress.inetSocketAddress(port, host);
String peerHost = host;
if (peerHost.endsWith(".")) {
peerHost = peerHost.substring(0, peerHost.length() - 1);
}
peerAddress = SocketAddress.inetSocketAddress(port, peerHost);
}
// Capture some stuff

View File

@@ -141,6 +141,9 @@ public class DnsResolverProvider implements ResolverProvider {
builder.hostsFileEntriesResolver(new HostsFileEntriesResolver() {
@Override
public InetAddress address(String inetHost, ResolvedAddressTypes resolvedAddressTypes) {
if (inetHost.endsWith(".")) {
inetHost = inetHost.substring(0, inetHost.length() - 1);
}
InetAddress address = lookup(inetHost, resolvedAddressTypes);
if (address == null) {
address = lookup(inetHost.toLowerCase(Locale.ENGLISH), resolvedAddressTypes);

View File

@@ -230,7 +230,12 @@ public class NetClientImpl implements MetricsProvider, NetClient {
}
};
channelProvider.connect(remoteAddress, remoteAddress, serverName, sslHelper.isSSL(), channelHandler);
SocketAddress peerAddress = remoteAddress;
String peerHost = peerAddress.host();
if (peerHost != null && peerHost.endsWith(".")) {
peerAddress = SocketAddress.inetSocketAddress(peerAddress.port(), peerHost.substring(0, peerHost.length() - 1));
}
channelProvider.connect(remoteAddress, peerAddress, serverName, sslHelper.isSSL(), channelHandler);
}
private void connected(ContextInternal context, Channel ch, Handler<AsyncResult<NetSocket>> connectHandler, SocketAddress remoteAddress) {

View File

@@ -390,6 +390,17 @@ public class HostnameResolutionTest extends VertxTestBase {
await();
}
@Test
public void testTrailingDotResolveFromHosts() {
VertxInternal vertx = (VertxInternal) vertx(new VertxOptions().setAddressResolverOptions(new AddressResolverOptions().setHostsPath("hosts_config.txt")));
vertx.resolveAddress("server.net.", onSuccess(addr -> {
assertEquals("192.168.0.15", addr.getHostAddress());
assertEquals("server.net", addr.getHostName());
testComplete();
}));
await();
}
@Test
public void testResolveMissingLocalhost() throws Exception {

View File

@@ -286,6 +286,17 @@ public abstract class HttpTLSTest extends HttpTestBase {
testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE).clientTrustAll().serverEnabledSecureTransportProtocol(new String[]{"SSLv2Hello", "TLSv1", "TLSv1.1", "TLSv1.2"}).pass();
}
@Test
// Provide an host name with a trailing dot
public void testTLSTrailingDotHost() throws Exception {
// We just need a vanilla cert for this test
SelfSignedCertificate cert = SelfSignedCertificate.create("host2.com");
TLSTest test = testTLS(Cert.NONE, cert::trustOptions, cert::keyCertOptions, Trust.NONE)
.requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host2.com."))
.pass();
assertEquals("host2.com", TestUtils.cnOf(test.clientPeerCert()));
}
/*
checks that we can enable algorithms
@@ -847,6 +858,16 @@ public abstract class HttpTLSTest extends HttpTestBase {
.pass();
}
@Test
// Provide an host name with a trailing dot validated on the server with SNI
public void testSniWithTrailingDotHost() throws Exception {
TLSTest test = testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, Cert.SNI_JKS, Trust.NONE)
.serverSni()
.requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host2.com."))
.pass();
assertEquals("host2.com", TestUtils.cnOf(test.clientPeerCert()));
assertEquals("host2.com", test.indicatedServerName);
}
// Other tests
@@ -1198,6 +1219,7 @@ public abstract class HttpTLSTest extends HttpTestBase {
} else {
Throwable t = ar.cause();
if (shouldPass) {
t.printStackTrace();
HttpTLSTest.this.fail("Should not throw exception");
} else {
complete();

View File

@@ -1228,6 +1228,21 @@ public class NetTest extends VertxTestBase {
new String[]{"TLSv1.2"});
}
@Test
public void testTLSTrailingDotHost() throws Exception {
// We just need a vanilla cert for this test
SelfSignedCertificate cert = SelfSignedCertificate.create("host2.com");
TLSTest test = new TLSTest()
.clientTrust(cert::trustOptions)
.connectAddress(SocketAddress.inetSocketAddress(4043, "host2.com."))
.bindAddress(SocketAddress.inetSocketAddress(4043, "host2.com"))
.serverCert(cert::keyCertOptions);
test.run(true);
await();
assertEquals("host2.com", cnOf(test.clientPeerCert()));
assertNull(test.indicatedServerName);
}
@Test
// SNI without server name should use the first keystore entry
public void testSniWithoutServerNameUsesTheFirstKeyStoreEntry1() throws Exception {
@@ -1391,6 +1406,19 @@ public class NetTest extends VertxTestBase {
await();
}
@Test
public void testSniWithTrailingDotHost() throws Exception {
TLSTest test = new TLSTest()
.clientTrust(Trust.SNI_JKS_HOST2)
.connectAddress(SocketAddress.inetSocketAddress(4043, "host2.com."))
.bindAddress(SocketAddress.inetSocketAddress(4043, "host2.com"))
.serverCert(Cert.SNI_JKS).sni(true);
test.run(true);
await();
assertEquals("host2.com", cnOf(test.clientPeerCert()));
assertEquals("host2.com", test.indicatedServerName);
}
void testTLS(Cert<?> clientCert, Trust<?> clientTrust,
Cert<?> serverCert, Trust<?> serverTrust,
boolean requireClientAuth, boolean clientTrustAll,
@@ -1440,7 +1468,8 @@ public class NetTest extends VertxTestBase {
String[] enabledCipherSuites = new String[0];
String[] enabledSecureTransportProtocols = new String[0];
boolean sni;
SocketAddress address = SocketAddress.inetSocketAddress(4043, "localhost");
SocketAddress bindAddress = SocketAddress.inetSocketAddress(4043, "localhost");
SocketAddress connectAddress = bindAddress;
String serverName;
X509Certificate clientPeerCert;
String indicatedServerName;
@@ -1491,7 +1520,18 @@ public class NetTest extends VertxTestBase {
}
public TLSTest address(SocketAddress address) {
this.address = address;
this.bindAddress = address;
this.connectAddress = address;
return this;
}
public TLSTest bindAddress(SocketAddress address) {
this.bindAddress = address;
return this;
}
public TLSTest connectAddress(SocketAddress address) {
this.connectAddress = address;
return this;
}
@@ -1588,8 +1628,7 @@ public class NetTest extends VertxTestBase {
}
});
};
server.connectHandler(serverHandler).listen(address, ar -> {
assertTrue(ar.succeeded());
server.connectHandler(serverHandler).listen(bindAddress, onSuccess(ar -> {
client.close();
NetClientOptions clientOptions = new NetClientOptions();
if (!startTLS) {
@@ -1610,7 +1649,7 @@ public class NetTest extends VertxTestBase {
clientOptions.addEnabledSecureTransportProtocol(protocol);
}
client = vertx.createNetClient(clientOptions);
client.connect(address, serverName, ar2 -> {
client.connect(connectAddress, serverName, ar2 -> {
if (ar2.succeeded()) {
if (!startTLS && !shouldPass) {
fail("Should not connect");
@@ -1678,13 +1717,14 @@ public class NetTest extends VertxTestBase {
}
} else {
if (shouldPass) {
ar2.cause().printStackTrace();
fail("Should not fail to connect");
} else {
complete();
}
}
});
});
}));
}
}