/* * Copyright (c) 2011-2013 The original author or authors * ------------------------------------------------------ * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. */ package io.vertx.test.core; import io.vertx.core.Vertx; import io.vertx.core.VertxException; import io.vertx.core.VertxOptions; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.*; import io.vertx.core.net.*; import io.vertx.core.net.impl.TrustAllTrustManager; import io.vertx.test.core.tls.Cert; import io.vertx.test.core.tls.Trust; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManagerFactorySpi; import javax.security.cert.X509Certificate; import java.io.IOException; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.security.InvalidAlgorithmParameterException; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.KeyStoreException; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.function.Function; /** * @author <a href="mailto:julien@julienviet.com">Julien Viet</a> */ public abstract class HttpTLSTest extends HttpTestBase { @Rule public TemporaryFolder testFolder = new TemporaryFolder(); @Override protected VertxOptions getOptions() { VertxOptions options = super.getOptions(); options.getAddressResolverOptions().setHostsValue(Buffer.buffer("" + "127.0.0.1 localhost\n" + "127.0.0.1 host1\n" + "127.0.0.1 host2.com\n" + "127.0.0.1 sub.host3.com\n" + "127.0.0.1 host4.com\n" + "127.0.0.1 www.host4.com\n" + "127.0.0.1 host5.com\n" + "127.0.0.1 www.host5.com\n" + "127.0.0.1 unknown.com")); return options; } @Override protected void tearDown() throws Exception { if (proxy != null) { proxy.stop(); } super.tearDown(); } @Test // Client trusts all server certs public void testTLSClientTrustAll() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE).clientTrustAll().pass(); } @Test // Server specifies cert that the client trusts (not trust all) public void testTLSClientTrustServerCert() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts (not trust all) public void testTLSClientTrustServerCertPKCS12() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_PKCS12, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts (not trust all) public void testTLSClientTrustServerCertPEM() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_PEM, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a root CA (not trust all) public void testTLSClientTrustServerCertJKSRootCAWithJKSRootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS_ROOT_CA, Cert.SERVER_JKS_ROOT_CA, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a root CA (not trust all) public void testTLSClientTrustServerCertJKSRootCAWithPKCS12RootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PKCS12_ROOT_CA, Cert.SERVER_JKS_ROOT_CA, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a root CA (not trust all) public void testTLSClientTrustServerCertJKSRootRootCAWithPEMRootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM_ROOT_CA, Cert.SERVER_JKS_ROOT_CA, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a root CA (not trust all) public void testTLSClientTrustServerCertPKCS12RootCAWithJKSRootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS_ROOT_CA, Cert.SERVER_PKCS12_ROOT_CA, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a root CA (not trust all) public void testTLSClientTrustServerCertPKCS12RootCAWithPKCS12RootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PKCS12_ROOT_CA, Cert.SERVER_PKCS12_ROOT_CA, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a root CA (not trust all) public void testTLSClientTrustServerCertPKCS12RootCAWithPEMRootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM_ROOT_CA, Cert.SERVER_PKCS12_ROOT_CA, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a root CA (not trust all) public void testTLSClientTrustServerCertPEMRootCAWithJKSRootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS_ROOT_CA, Cert.SERVER_PEM_ROOT_CA, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a root CA (not trust all) public void testTLSClientTrustServerCertPEMRootCAWithPKCS12RootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PKCS12_ROOT_CA, Cert.SERVER_PEM_ROOT_CA, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a root CA (not trust all) public void testTLSClientTrustServerCertPEMRootCAWithPEMRootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM_ROOT_CA, Cert.SERVER_PEM_ROOT_CA, Trust.NONE).pass(); } // These two tests should be grouped in same method - todo later @Test // Server specifies cert that the client trusts via a root CA that is in a multi pem store (not trust all) public void testTLSClientTrustServerCertMultiPemWithPEMRootCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM_ROOT_CA_AND_OTHER_CA, Cert.SERVER_PEM_ROOT_CA, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts via a other CA that is in a multi pem store (not trust all) public void testTLSClientTrustServerCertMultiPemWithPEMOtherCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM_ROOT_CA_AND_OTHER_CA, Cert.SERVER_PEM_OTHER_CA, Trust.NONE).pass(); } @Test // Server specifies cert chain that the client trusts via a CA (not trust all) public void testTLSClientTrustServerCertPEMRootCAWithPEMCAChain() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM_ROOT_CA, Cert.SERVER_PEM_CA_CHAIN, Trust.NONE).pass(); } @Test // Server specifies intermediate cert that the client doesn't trust because it is missing the intermediate CA signed by the root CA public void testTLSClientUntrustedServerCertPEMRootCAWithPEMCA() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM_ROOT_CA, Cert.SERVER_PEM_INT_CA, Trust.NONE).fail(); } @Test // Server specifies cert that the client trusts (not trust all) public void testTLSClientTrustPKCS12ServerCert() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PKCS12, Cert.SERVER_JKS, Trust.NONE).pass(); } @Test // Server specifies cert that the client trusts (not trust all) public void testTLSClientTrustPEMServerCert() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM, Cert.SERVER_JKS, Trust.NONE).pass(); } @Test // Server specifies cert that the client doesn't trust public void testTLSClientUntrustedServer() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE).fail(); } @Test // Server specifies cert that the client doesn't trust public void testTLSClientUntrustedServerPEM() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_PEM, Trust.NONE).fail(); } @Test // Client specifies cert even though it's not required public void testTLSClientCertNotRequired() throws Exception { testTLS(Cert.CLIENT_JKS, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS).pass(); } @Test // Client specifies cert even though it's not required public void testTLSClientCertNotRequiredPEM() throws Exception { testTLS(Cert.CLIENT_JKS, Trust.SERVER_JKS, Cert.SERVER_PEM, Trust.CLIENT_JKS).pass(); } @Test // Client specifies cert and it is required public void testTLSClientCertRequired() throws Exception { testTLS(Cert.CLIENT_JKS, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS).requiresClientAuth().pass(); } @Test // Client specifies cert and it is required public void testTLSClientCertRequiredPKCS12() throws Exception { testTLS(Cert.CLIENT_JKS, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_PKCS12).requiresClientAuth().pass(); } @Test // Client specifies cert and it is required public void testTLSClientCertRequiredPEM() throws Exception { testTLS(Cert.CLIENT_JKS, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_PEM).requiresClientAuth().pass(); } @Test // Client specifies cert and it is required public void testTLSClientCertPKCS12Required() throws Exception { testTLS(Cert.CLIENT_PKCS12, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS).requiresClientAuth().pass(); } @Test // Client specifies cert and it is required public void testTLSClientCertPEMRequired() throws Exception { testTLS(Cert.CLIENT_PEM, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS).requiresClientAuth().pass(); } @Test // Client specifies cert by CA and it is required public void testTLSClientCertPEM_CARequired() throws Exception { testTLS(Cert.CLIENT_PEM_ROOT_CA, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_PEM_ROOT_CA).requiresClientAuth().pass(); } @Test // Client doesn't specify cert but it's required public void testTLSClientCertRequiredNoClientCert() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS).requiresClientAuth().fail(); } @Test // Client specifies cert but it's not trusted public void testTLSClientCertClientNotTrusted() throws Exception { testTLS(Cert.CLIENT_JKS, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).requiresClientAuth().fail(); } @Test // Server specifies cert that the client does not trust via a revoked certificate of the CA public void testTLSClientRevokedServerCert() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM_ROOT_CA, Cert.SERVER_PEM_ROOT_CA, Trust.NONE).clientUsesCrl().fail(); } @Test // Client specifies cert that the server does not trust via a revoked certificate of the CA public void testTLSRevokedClientCertServer() throws Exception { testTLS(Cert.CLIENT_PEM_ROOT_CA, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_PEM_ROOT_CA).requiresClientAuth().serverUsesCrl().fail(); } @Test // Specify some matching cipher suites public void testTLSMatchingCipherSuites() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE).clientTrustAll().serverEnabledCipherSuites(ENABLED_CIPHER_SUITES).pass(); } @Test // Specify some non matching cipher suites public void testTLSNonMatchingCipherSuites() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE).clientTrustAll().serverEnabledCipherSuites(new String[]{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"}).clientEnabledCipherSuites(new String[]{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"}).fail(); } @Test // Specify some matching TLS protocols public void testTLSMatchingProtocolVersions() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE).clientTrustAll().serverEnabledSecureTransportProtocol(new String[]{"SSLv2Hello", "TLSv1", "TLSv1.1", "TLSv1.2"}).pass(); } @Test // Specify some matching TLS protocols public void testTLSInvalidProtocolVersion() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE).clientTrustAll().serverEnabledSecureTransportProtocol(new String[]{"HelloWorld"}).fail(); } @Test // Specify some non matching TLS protocols public void testTLSNonMatchingProtocolVersions() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE).clientTrustAll().serverEnabledSecureTransportProtocol(new String[]{"TLSv1.2"}).clientEnabledSecureTransportProtocol(new String[]{"SSLv2Hello"}).fail(); } @Test // Test host verification with a CN matching localhost public void testTLSVerifyMatchingHost() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_JKS, Trust.NONE).clientTrustAll().clientVerifyHost().pass(); } @Test // Test host verification with a CN NOT matching localhost public void testTLSVerifyNonMatchingHost() throws Exception { testTLS(Cert.NONE, Trust.NONE, Cert.SERVER_MIM, Trust.NONE).clientTrustAll().clientVerifyHost().fail(); } // OpenSSL tests @Test // Server uses OpenSSL with JKS public void testTLSClientTrustServerCertJKSOpenSSL() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).serverOpenSSL().pass(); } @Test // Server uses OpenSSL with PKCS12 public void testTLSClientTrustServerCertPKCS12OpenSSL() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_PKCS12, Trust.NONE).serverOpenSSL().pass(); } @Test // Server uses OpenSSL with PEM public void testTLSClientTrustServerCertPEMOpenSSL() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_PEM, Trust.NONE).serverOpenSSL().pass(); } @Test // Client trusts OpenSSL with PEM public void testTLSClientTrustServerCertWithJKSOpenSSL() throws Exception { testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).clientOpenSSL().pass(); } @Test // Server specifies cert that the client trusts (not trust all) public void testTLSClientTrustServerCertWithPKCS12OpenSSL() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PKCS12, Cert.SERVER_JKS, Trust.NONE).clientOpenSSL().pass(); } @Test // Server specifies cert that the client trusts (not trust all) public void testTLSClientTrustServerCertWithPEMOpenSSL() throws Exception { testTLS(Cert.NONE, Trust.SERVER_PEM, Cert.SERVER_JKS, Trust.NONE).clientOpenSSL().pass(); } @Test // Client specifies cert and it is required public void testTLSClientCertRequiredOpenSSL() throws Exception { testTLS(Cert.CLIENT_JKS, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS).clientOpenSSL().requiresClientAuth().pass(); } @Test // Client specifies cert and it is required public void testTLSClientCertPKCS12RequiredOpenSSL() throws Exception { testTLS(Cert.CLIENT_PKCS12, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS).clientOpenSSL().requiresClientAuth().pass(); } @Test // Client specifies cert and it is required public void testTLSClientCertPEMRequiredOpenSSL() throws Exception { testTLS(Cert.CLIENT_PEM, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.CLIENT_JKS).clientOpenSSL().requiresClientAuth().pass(); } // SNI tests @Test // Client provides SNI and server responds with a matching certificate for the indicated server name public void testSNITrust() 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); } @Test // Client provides SNI and server responds with a matching certificate for the indicated server name public void testSNITrustPKCS12() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, Cert.SNI_PKCS12, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host2.com")) .pass() .clientPeerCert(); assertEquals("host2.com", TestUtils.cnOf(cert)); } @Test // Client provides SNI and server responds with a matching certificate for the indicated server name public void testSNITrustPEM() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, Cert.SNI_PEM, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host2.com")) .pass() .clientPeerCert(); assertEquals("host2.com", TestUtils.cnOf(cert)); } @Test // Client provides SNI but server ignores it and provides a different cerficate public void testSNIServerIgnoresExtension1() throws Exception { testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, Cert.SNI_JKS, Trust.NONE) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host2.com")) .fail(); } @Test // Client provides SNI but server ignores it and provides a different cerficate - check we get a certificate public void testSNIServerIgnoresExtension2() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SNI_JKS, Trust.NONE) .clientVerifyHost(false) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host2.com")) .pass() .clientPeerCert(); assertEquals("localhost", TestUtils.cnOf(cert)); } @Test // Client provides SNI unknown to the server and server responds with the default certificate (first) public void testSNIUnknownServerName1() throws Exception { testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, Cert.SNI_JKS, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("unknown.com")).fail(); } @Test // Client provides SNI unknown to the server and server responds with the default certificate (first) public void testSNIUnknownServerName2() throws Exception { TLSTest test = testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SNI_JKS, Trust.NONE) .serverSni() .clientVerifyHost(false) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("unknown.com")) .pass(); assertEquals("localhost", TestUtils.cnOf(test.clientPeerCert())); assertEquals("unknown.com", test.indicatedServerName); } @Test // Client provides SNI matched on the server by a wildcard certificate public void testSNIWildcardMatch() throws Exception { TLSTest test = testTLS(Cert.NONE, Trust.SNI_JKS_HOST3, Cert.SNI_JKS, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("sub.host3.com")) .pass(); assertEquals("*.host3.com", TestUtils.cnOf(test.clientPeerCert())); assertEquals("sub.host3.com", test.indicatedServerName); } @Test // Client provides SNI matched on the server by a wildcard certificate public void testSNIWildcardMatchPKCS12() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST3, Cert.SNI_PKCS12, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("sub.host3.com")) .pass() .clientPeerCert(); assertEquals("*.host3.com", TestUtils.cnOf(cert)); } @Test // Client provides SNI matched on the server by a wildcard certificate public void testSNIWildcardMatchPEM() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST3, Cert.SNI_PEM, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("sub.host3.com")) .pass() .clientPeerCert(); assertEquals("*.host3.com", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAlternativeNameMatch1() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST4, Cert.SNI_JKS, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host4.com")) .pass() .clientPeerCert(); assertEquals("host4.com certificate", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAlternativeNameMatch1PKCS12() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST4, Cert.SNI_PKCS12, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host4.com")) .pass() .clientPeerCert(); assertEquals("host4.com certificate", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAlternativeNameMatch1PEM() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST4, Cert.SNI_PEM, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host4.com")) .pass() .clientPeerCert(); assertEquals("host4.com certificate", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAlternativeNameMatch2() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST4, Cert.SNI_JKS, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("www.host4.com")) .pass() .clientPeerCert(); assertEquals("host4.com certificate", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAlternativeNameMatch2PKCS12() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST4, Cert.SNI_PKCS12, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("www.host4.com")) .pass() .clientPeerCert(); assertEquals("host4.com certificate", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAlternativeNameMatch2PEM() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST4, Cert.SNI_PEM, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("www.host4.com")) .pass() .clientPeerCert(); assertEquals("host4.com certificate", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAlternativeNameWildcardMatch() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST5, Cert.SNI_JKS, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("www.host5.com")) .pass() .clientPeerCert(); assertEquals("host5.com", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAlternativeNameWildcardMatchPKCS12() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST5, Cert.SNI_PKCS12, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("www.host5.com")) .pass() .clientPeerCert(); assertEquals("host5.com", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAlternativeNameWildcardMatchPEM() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST5, Cert.SNI_PEM, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("www.host5.com")) .pass() .clientPeerCert(); assertEquals("host5.com", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAltenativeNameCNMatch1() throws Exception { testTLS(Cert.NONE, Trust.SNI_JKS_HOST5, Cert.SNI_JKS, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host5.com")) .fail() .clientPeerCert(); } @Test public void testSNISubjectAltenativeNameCNMatch1PKCS12() throws Exception { testTLS(Cert.NONE, Trust.SNI_JKS_HOST5, Cert.SNI_PKCS12, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host5.com")) .fail() .clientPeerCert(); } @Test public void testSNISubjectAltenativeNameCNMatch1PEM() throws Exception { testTLS(Cert.NONE, Trust.SNI_JKS_HOST5, Cert.SNI_PEM, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host5.com")) .fail() .clientPeerCert(); } @Test public void testSNISubjectAltenativeNameCNMatch2() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST5, Cert.SNI_JKS, Trust.NONE) .serverSni() .clientVerifyHost(false) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host5.com")) .pass() .clientPeerCert(); assertEquals("host5.com", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAltenativeNameCNMatch2PKCS12() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST5, Cert.SNI_PKCS12, Trust.NONE) .serverSni() .clientVerifyHost(false) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host5.com")) .pass() .clientPeerCert(); assertEquals("host5.com", TestUtils.cnOf(cert)); } @Test public void testSNISubjectAltenativeNameCNMatch2PEM() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST5, Cert.SNI_PEM, Trust.NONE) .serverSni() .clientVerifyHost(false) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host5.com")) .pass() .clientPeerCert(); assertEquals("host5.com", TestUtils.cnOf(cert)); } @Test public void testSNIWithALPN() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, Cert.SNI_JKS, Trust.NONE) .serverSni() .clientUsesAlpn() .serverUsesAlpn() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host2.com")) .pass() .clientPeerCert(); assertEquals("host2.com", TestUtils.cnOf(cert)); } @Test // Client provides SNI and server responds with a matching certificate for the indicated server name public void testSNIWithHostHeader() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, Cert.SNI_JKS, Trust.NONE) .serverSni() .requestProvider(client -> client.post(4043, "localhost", "/somepath").setHost("host2.com:4043")) .pass() .clientPeerCert(); assertEquals("host2.com", TestUtils.cnOf(cert)); } @Test public void testSNIWithOpenSSL() throws Exception { X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, Cert.SNI_JKS, Trust.NONE) .clientOpenSSL() .serverOpenSSL() .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host2.com")) .pass() .clientPeerCert(); assertEquals("host2.com", TestUtils.cnOf(cert)); } @Test public void testSNIDontSendServerNameForShortnames1() throws Exception { testTLS(Cert.NONE, Trust.SNI_JKS_HOST1, Cert.SNI_JKS, Trust.NONE) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host1")) .fail(); } @Test public void testSNIDontSendServerNameForShortnames2() throws Exception { TLSTest test = testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SNI_JKS, Trust.NONE) .clientVerifyHost(false) .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host1")) .pass(); assertEquals(null, test.indicatedServerName); } @Test public void testSNIForceSend() throws Exception { TLSTest test = testTLS(Cert.NONE, Trust.SNI_JKS_HOST1, Cert.SNI_JKS, Trust.NONE) .clientForceSni() .serverSni() .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host1")) .pass(); assertEquals("host1", test.indicatedServerName); } // Other tests @Test // Test custom trust manager factory public void testCustomTrustManagerFactory() throws Exception { testTLS(Cert.NONE, () -> new TrustOptions() { @Override public TrustManagerFactory getTrustManagerFactory(Vertx v) throws Exception { return new TrustManagerFactory(new TrustManagerFactorySpi() { @Override protected void engineInit(KeyStore keyStore) throws KeyStoreException { } @Override protected void engineInit(ManagerFactoryParameters managerFactoryParameters) throws InvalidAlgorithmParameterException { } @Override protected TrustManager[] engineGetTrustManagers() { return new TrustManager[]{TrustAllTrustManager.INSTANCE}; } }, KeyPairGenerator.getInstance("RSA").getProvider(), KeyPairGenerator.getInstance("RSA").getAlgorithm()) { }; } @Override public TrustOptions clone() { return this; } }, Cert.SERVER_JKS, Trust.NONE).pass(); } class TLSTest { HttpVersion version; KeyCertOptions clientCert; TrustOptions clientTrust; boolean clientTrustAll; boolean clientUsesCrl; boolean clientUsesAlpn; boolean clientOpenSSL; boolean clientVerifyHost = true; boolean clientSSL = true; boolean requiresClientAuth; KeyCertOptions serverCert; TrustOptions serverTrust; boolean serverUsesCrl; boolean serverOpenSSL; boolean serverUsesAlpn; boolean serverSSL = true; ProxyType proxyType; boolean useProxyAuth; String[] clientEnabledCipherSuites = new String[0]; String[] serverEnabledCipherSuites = new String[0]; String[] clientEnabledSecureTransportProtocol = new String[0]; String[] serverEnabledSecureTransportProtocol = new String[0]; private String connectHostname; private boolean followRedirects; private boolean serverSNI; private boolean clientForceSNI; private Function<HttpClient, HttpClientRequest> requestProvider = client -> { String httpHost; if (connectHostname != null) { httpHost = connectHostname; } else { httpHost = DEFAULT_HTTP_HOST; } return client.request(HttpMethod.POST, 4043, httpHost, DEFAULT_TEST_URI); }; X509Certificate clientPeerCert; String indicatedServerName; public TLSTest(Cert<?> clientCert, Trust<?> clientTrust, Cert<?> serverCert, Trust<?> serverTrust) { this.version = HttpVersion.HTTP_1_1; this.clientCert = clientCert.get(); this.clientTrust = clientTrust.get(); this.serverCert = serverCert.get(); this.serverTrust = serverTrust.get(); } TLSTest version(HttpVersion version) { this.version = version; return this; } TLSTest requiresClientAuth() { requiresClientAuth = true; return this; } TLSTest serverUsesCrl() { serverUsesCrl = true; return this; } TLSTest serverOpenSSL() { serverOpenSSL = true; return this; } TLSTest clientOpenSSL() { clientOpenSSL = true; return this; } TLSTest clientUsesCrl() { clientUsesCrl = true; return this; } TLSTest clientTrustAll() { clientTrustAll = true; return this; } TLSTest clientVerifyHost() { clientVerifyHost = true; return this; } TLSTest clientVerifyHost(boolean verify) { clientVerifyHost = verify; return this; } TLSTest clientEnabledCipherSuites(String[] value) { clientEnabledCipherSuites = value; return this; } TLSTest serverEnabledCipherSuites(String[] value) { serverEnabledCipherSuites = value; return this; } TLSTest clientEnabledSecureTransportProtocol(String[] value) { clientEnabledSecureTransportProtocol = value; return this; } TLSTest serverEnabledSecureTransportProtocol(String[] value) { serverEnabledSecureTransportProtocol = value; return this; } TLSTest serverSni() { serverSNI = true; return this; } TLSTest clientForceSni() { clientForceSNI = true; return this; } TLSTest clientUsesAlpn() { clientUsesAlpn = true; return this; } TLSTest serverUsesAlpn() { serverUsesAlpn = true; return this; } TLSTest useProxy(ProxyType type) { proxyType = type; return this; } TLSTest useProxyAuth() { useProxyAuth = true; return this; } TLSTest connectHostname(String connectHostname) { this.connectHostname = connectHostname; return this; } TLSTest requestOptions(RequestOptions requestOptions) { this.requestProvider = client -> client.request(HttpMethod.POST, requestOptions); return this; } TLSTest requestProvider(Function<HttpClient, HttpClientRequest> requestProvider) { this.requestProvider = requestProvider; return this; } TLSTest clientSSL(boolean ssl) { clientSSL = ssl; return this; } TLSTest serverSSL(boolean ssl) { serverSSL = ssl; return this; } TLSTest followRedirects(boolean follow) { followRedirects = follow; return this; } public X509Certificate clientPeerCert() { return clientPeerCert; } TLSTest pass() { return run(true); } TLSTest fail() { return run(false); } TLSTest run(boolean shouldPass) { server.close(); HttpClientOptions options = new HttpClientOptions(); options.setProtocolVersion(version); options.setSsl(clientSSL); options.setForceSni(clientForceSNI); if (clientTrustAll) { options.setTrustAll(true); } if (clientUsesCrl) { options.addCrlPath("tls/root-ca/crl.pem"); } if (clientOpenSSL) { options.setOpenSslEngineOptions(new OpenSSLEngineOptions()); } if (clientUsesAlpn) { options.setUseAlpn(true); } options.setVerifyHost(clientVerifyHost); options.setTrustOptions(clientTrust); options.setKeyCertOptions(clientCert); for (String suite: clientEnabledCipherSuites) { options.addEnabledCipherSuite(suite); } for (String protocols: clientEnabledSecureTransportProtocol) { options.addEnabledSecureTransportProtocol(protocols); } if (proxyType != null) { ProxyOptions proxyOptions; if (proxyType == ProxyType.SOCKS5) { proxyOptions = new ProxyOptions().setHost("localhost").setPort(11080).setType(ProxyType.SOCKS5); } else { proxyOptions = new ProxyOptions().setHost("localhost").setPort(13128).setType(ProxyType.HTTP); } if (useProxyAuth) { proxyOptions.setUsername("username").setPassword("username"); } options.setProxyOptions(proxyOptions); } client = createHttpClient(options); HttpServerOptions serverOptions = new HttpServerOptions(); serverOptions.setTrustOptions(serverTrust); serverOptions.setKeyCertOptions(serverCert); if (requiresClientAuth) { serverOptions.setClientAuth(ClientAuth.REQUIRED); } if (serverUsesCrl) { serverOptions.addCrlPath("tls/root-ca/crl.pem"); } if (serverOpenSSL) { serverOptions.setOpenSslEngineOptions(new OpenSSLEngineOptions()); } serverOptions.setUseAlpn(serverUsesAlpn); serverOptions.setSsl(serverSSL); serverOptions.setSni(serverSNI); for (String suite: serverEnabledCipherSuites) { serverOptions.addEnabledCipherSuite(suite); } for (String protocols: serverEnabledSecureTransportProtocol) { serverOptions.addEnabledSecureTransportProtocol(protocols); } server = createHttpServer(serverOptions.setPort(4043)); server.requestHandler(req -> { indicatedServerName = req.connection().indicatedServerName(); assertEquals(version, req.version()); req.bodyHandler(buffer -> { assertEquals(serverSSL, req.isSSL()); assertEquals("foo", buffer.toString()); req.response().end("bar"); }); }); server.listen(ar -> { assertTrue(ar.succeeded()); String httpHost; if (connectHostname != null) { httpHost = connectHostname; } else { httpHost = DEFAULT_HTTP_HOST; } HttpClientRequest req = requestProvider.apply(client); req.setFollowRedirects(followRedirects); req.handler(response -> { HttpConnection conn = response.request().connection(); if (conn.isSsl()) { try { clientPeerCert = conn.peerCertificateChain()[0]; } catch (SSLPeerUnverifiedException ignore) { } } if (shouldPass) { response.version(); response.bodyHandler(data -> assertEquals("bar", data.toString())); testComplete(); } else { HttpTLSTest.this.fail("Should not get a response"); } }); req.exceptionHandler(t -> { if (shouldPass) { t.printStackTrace(); HttpTLSTest.this.fail("Should not throw exception"); } else { testComplete(); } }); req.end("foo"); }); await(); return this; } } abstract HttpServer createHttpServer(HttpServerOptions options); abstract HttpClient createHttpClient(HttpClientOptions options); protected TLSTest testTLS(Cert<?> clientCert, Trust<?> clientTrust, Cert<?> serverCert, Trust<?> serverTrust) throws Exception { return new TLSTest(clientCert, clientTrust, serverCert, serverTrust); } @Test public void testJKSInvalidPath() { testInvalidKeyStore(Cert.SERVER_JKS.get().setPath("/invalid.jks"), "java.nio.file.NoSuchFileException: ", "invalid.jks"); } @Test public void testJKSMissingPassword() { testInvalidKeyStore(Cert.SERVER_JKS.get().setPassword(null), "Password must not be null", null); } @Test public void testJKSInvalidPassword() { testInvalidKeyStore(Cert.SERVER_JKS.get().setPassword("wrongpassword"), "Keystore was tampered with, or password was incorrect", null); } @Test public void testPKCS12InvalidPath() { testInvalidKeyStore(Cert.SERVER_PKCS12.get().setPath("/invalid.p12"), "java.nio.file.NoSuchFileException: ", "invalid.p12"); } @Test public void testPKCS12MissingPassword() { testInvalidKeyStore(Cert.SERVER_PKCS12.get().setPassword(null), "Get Key failed: null", null); } @Test public void testPKCS12InvalidPassword() { testInvalidKeyStore(Cert.SERVER_PKCS12.get().setPassword("wrongpassword"), Arrays.asList( "failed to decrypt safe contents entry: javax.crypto.BadPaddingException: Given final block not properly padded", "keystore password was incorrect"), null); } @Test public void testKeyCertMissingKeyPath() { testInvalidKeyStore(Cert.SERVER_PEM.get().setKeyPath(null), "Missing private key", null); } @Test public void testKeyCertInvalidKeyPath() { testInvalidKeyStore(Cert.SERVER_PEM.get().setKeyPath("/invalid.pem"), "java.nio.file.NoSuchFileException: ", "invalid.pem"); } @Test public void testKeyCertMissingCertPath() { testInvalidKeyStore(Cert.SERVER_PEM.get().setCertPath(null), "Missing X.509 certificate", null); } @Test public void testKeyCertInvalidCertPath() { testInvalidKeyStore(Cert.SERVER_PEM.get().setCertPath("/invalid.pem"), "java.nio.file.NoSuchFileException: ", "invalid.pem"); } @Test public void testKeyCertInvalidPem() throws IOException { String[] contents = { "", "-----BEGIN PRIVATE KEY-----", "-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----", "-----BEGIN PRIVATE KEY-----\n*\n-----END PRIVATE KEY-----" }; String[] messages = { "Missing -----BEGIN PRIVATE KEY----- delimiter", "Missing -----END PRIVATE KEY----- delimiter", "Empty pem file", "Input byte[] should at least have 2 bytes for base64 bytes" }; for (int i = 0;i < contents.length;i++) { Path file = testFolder.newFile("vertx" + UUID.randomUUID().toString() + ".pem").toPath(); Files.write(file, Collections.singleton(contents[i])); String expectedMessage = messages[i]; testInvalidKeyStore(Cert.SERVER_PEM.get().setKeyPath(file.toString()), expectedMessage, null); } } @Test public void testNoKeyCert() { testInvalidKeyStore(null, "Key/certificate is mandatory for SSL", null); } @Test public void testCaInvalidPath() { testInvalidTrustStore(new PemTrustOptions().addCertPath("/invalid.pem"), "java.nio.file.NoSuchFileException: ", "invalid.pem"); } @Test public void testCaInvalidPem() throws IOException { String[] contents = { "", "-----BEGIN CERTIFICATE-----", "-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----", "-----BEGIN CERTIFICATE-----\n*\n-----END CERTIFICATE-----" }; String[] messages = { "Missing -----BEGIN CERTIFICATE----- delimiter", "Missing -----END CERTIFICATE----- delimiter", "Empty pem file", "Input byte[] should at least have 2 bytes for base64 bytes" }; for (int i = 0;i < contents.length;i++) { Path file = testFolder.newFile("vertx" + UUID.randomUUID().toString() + ".pem").toPath(); Files.write(file, Collections.singleton(contents[i])); String expectedMessage = messages[i]; testInvalidTrustStore(new PemTrustOptions().addCertPath(file.toString()), expectedMessage, null); } } private void testInvalidKeyStore(KeyCertOptions options, String expectedPrefix, String expectedSuffix) { HttpServerOptions serverOptions = new HttpServerOptions(); setOptions(serverOptions, options); testStore(serverOptions, Collections.singletonList(expectedPrefix), expectedSuffix); } private void testInvalidKeyStore(KeyCertOptions options, List<String> expectedPossiblePrefixes, String expectedSuffix) { HttpServerOptions serverOptions = new HttpServerOptions(); setOptions(serverOptions, options); testStore(serverOptions, expectedPossiblePrefixes, expectedSuffix); } private void testInvalidTrustStore(TrustOptions options, String expectedPrefix, String expectedSuffix) { HttpServerOptions serverOptions = new HttpServerOptions(); serverOptions.setTrustOptions(options); testStore(serverOptions, Collections.singletonList(expectedPrefix), expectedSuffix); } private void testStore(HttpServerOptions serverOptions, List<String> expectedPossiblePrefixes, String expectedSuffix) { serverOptions.setSsl(true); serverOptions.setPort(4043); HttpServer server = vertx.createHttpServer(serverOptions); server.requestHandler(req -> { }); try { server.listen(); fail("Was expecting a failure"); } catch (VertxException e) { Throwable cause = e.getCause(); if(expectedSuffix == null) { boolean ok = expectedPossiblePrefixes.isEmpty(); for (String expectedPossiblePrefix : expectedPossiblePrefixes) { ok |= expectedPossiblePrefix.equals(cause.getMessage()); } if (!ok) { fail("Was expecting <" + cause.getMessage() + "> to be equals to one of " + expectedPossiblePrefixes); } } else { boolean ok = expectedPossiblePrefixes.isEmpty(); for (String expectedPossiblePrefix : expectedPossiblePrefixes) { ok |= cause.getMessage().startsWith(expectedPossiblePrefix); } if (!ok) { fail("Was expecting e.getCause().getMessage() to be prefixed by one of " + expectedPossiblePrefixes); } assertTrue(cause.getMessage().endsWith(expectedSuffix)); } } } @Test public void testCrlInvalidPath() throws Exception { HttpClientOptions clientOptions = new HttpClientOptions(); clientOptions.setTrustOptions(Trust.SERVER_PEM_ROOT_CA.get()); clientOptions.setSsl(true); clientOptions.addCrlPath("/invalid.pem"); HttpClient client = vertx.createHttpClient(clientOptions); HttpClientRequest req = client.request(HttpMethod.CONNECT, DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST, "/", (handler) -> {}); try { req.end(); fail("Was expecting a failure"); } catch (VertxException e) { assertNotNull(e.getCause()); assertEquals(NoSuchFileException.class, e.getCause().getCause().getClass()); } } // Proxy tests @Test // Access https server via connect proxy public void testHttpsProxy() throws Exception { testProxy(ProxyType.HTTP); assertEquals("Host header doesn't contain target host", "localhost:4043", proxy.getLastRequestHeaders().get("Host")); assertEquals("Host header doesn't contain target host", HttpMethod.CONNECT, proxy.getLastMethod()); } private void testProxy(ProxyType proxyType) throws Exception { startProxy(null, proxyType); testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).useProxy(proxyType).pass(); assertNotNull("connection didn't access the proxy", proxy.getLastUri()); assertEquals("hostname resolved but it shouldn't be", "localhost:4043", proxy.getLastUri()); } @Test // Access https server via connect proxy public void testHttpsProxyWithSNI() throws Exception { testProxyWithSNI(ProxyType.HTTP); assertEquals("Host header doesn't contain target host", "host2.com:4043", proxy.getLastRequestHeaders().get("Host")); assertEquals("Host header doesn't contain target host", HttpMethod.CONNECT, proxy.getLastMethod()); } private void testProxyWithSNI(ProxyType proxyType) throws Exception { startProxy(null, proxyType); X509Certificate cert = testTLS(Cert.NONE, Trust.SNI_JKS_HOST2, Cert.SNI_JKS, Trust.NONE) .serverSni() .useProxy(proxyType) .requestOptions(new RequestOptions().setSsl(true).setPort(4043).setHost("host2.com")) .pass() .clientPeerCert(); assertNotNull("connection didn't access the proxy", proxy.getLastUri()); assertEquals("hostname resolved but it shouldn't be", "host2.com:4043", proxy.getLastUri()); assertEquals("host2.com", TestUtils.cnOf(cert)); } @Test // Check that proxy auth fails if it is missing public void testHttpsProxyAuthFail() throws Exception { startProxy("username", ProxyType.HTTP); testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).useProxy(ProxyType.HTTP).fail(); } @Test // Access https server via connect proxy with proxy auth required public void testHttpsProxyAuth() throws Exception { startProxy("username", ProxyType.HTTP); testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).useProxy(ProxyType.HTTP).useProxyAuth().pass(); assertNotNull("connection didn't access the proxy", proxy.getLastUri()); assertEquals("hostname resolved but it shouldn't be", "localhost:4043", proxy.getLastUri()); assertEquals("Host header doesn't contain target host", "localhost:4043", proxy.getLastRequestHeaders().get("Host")); assertEquals("Host header doesn't contain target host", HttpMethod.CONNECT, proxy.getLastMethod()); } @Test // Access https server via connect proxy with a hostname that doesn't resolve // the hostname may resolve at the proxy if that is accessing another DNS // we simulate this by mapping the hostname to localhost:xxx in the test proxy code public void testHttpsProxyUnknownHost() throws Exception { startProxy(null, ProxyType.HTTP); proxy.setForceUri("localhost:4043"); testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).useProxy(ProxyType.HTTP) .connectHostname("doesnt-resolve.host-name").clientTrustAll().clientVerifyHost(false).pass(); assertNotNull("connection didn't access the proxy", proxy.getLastUri()); assertEquals("hostname resolved but it shouldn't be", "doesnt-resolve.host-name:4043", proxy.getLastUri()); assertEquals("Host header doesn't contain target host", "doesnt-resolve.host-name:4043", proxy.getLastRequestHeaders().get("Host")); assertEquals("Host header doesn't contain target host", HttpMethod.CONNECT, proxy.getLastMethod()); } @Test // Access https server via socks5 proxy public void testHttpsSocks() throws Exception { testProxy(ProxyType.SOCKS5); } @Test // Access https server via socks5 proxy public void testHttpsSocksWithSNI() throws Exception { testProxyWithSNI(ProxyType.SOCKS5); } @Test // Access https server via socks5 proxy with authentication public void testHttpsSocksAuth() throws Exception { startProxy("username", ProxyType.SOCKS5); testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).useProxy(ProxyType.SOCKS5).useProxyAuth().pass(); assertNotNull("connection didn't access the proxy", proxy.getLastUri()); assertEquals("hostname resolved but it shouldn't be", "localhost:4043", proxy.getLastUri()); } @Test // Access https server via socks proxy with a hostname that doesn't resolve // the hostname may resolve at the proxy if that is accessing another DNS // we simulate this by mapping the hostname to localhost:xxx in the test proxy code public void testSocksProxyUnknownHost() throws Exception { startProxy(null, ProxyType.SOCKS5); proxy.setForceUri("localhost:4043"); testTLS(Cert.NONE, Trust.SERVER_JKS, Cert.SERVER_JKS, Trust.NONE).useProxy(ProxyType.SOCKS5) .connectHostname("doesnt-resolve.host-name").clientTrustAll().clientVerifyHost(false).pass(); assertNotNull("connection didn't access the proxy", proxy.getLastUri()); assertEquals("hostname resolved but it shouldn't be", "doesnt-resolve.host-name:4043", proxy.getLastUri()); } }