public static void main(String[] args) throws Exception { String[] illegalNames = { "example\u3002\u3002com", "example..com", "com\u3002", "com.", "." }; for (String name : illegalNames) { try { SNIHostName hostname = new SNIHostName(name); throw new Exception( "Expected to get IllegalArgumentException for " + name); } catch (IllegalArgumentException iae) { // That's the right behavior. } } }
/** * Returns client ssl engine. * * @param context - SSLContext to get SSLEngine from. * @param useSNI - flag used to enable or disable using SNI extension. * Needed for Kerberos. */ public static SSLEngine getClientSSLEngine( SSLContext context, boolean useSNI) { SSLEngine clientEngine = context.createSSLEngine(HOST, 80); clientEngine.setUseClientMode(true); if (useSNI) { SNIHostName serverName = new SNIHostName(SERVER_NAME); List<SNIServerName> serverNames = new ArrayList<>(); serverNames.add(serverName); SSLParameters params = clientEngine.getSSLParameters(); params.setServerNames(serverNames); clientEngine.setSSLParameters(params); } return clientEngine; }
/** * Returns server ssl engine. * * @param context - SSLContext to get SSLEngine from. * @param useSNI - flag used to enable or disable using SNI extension. * Needed for Kerberos. */ public static SSLEngine getServerSSLEngine( SSLContext context, boolean useSNI) { SSLEngine serverEngine = context.createSSLEngine(); serverEngine.setUseClientMode(false); if (useSNI) { SNIMatcher matcher = SNIHostName.createSNIMatcher(SNI_PATTERN); List<SNIMatcher> matchers = new ArrayList<>(); matchers.add(matcher); SSLParameters params = serverEngine.getSSLParameters(); params.setSNIMatchers(matchers); serverEngine.setSSLParameters(params); } return serverEngine; }
@Test public void test_setSSLParameters_Socket() throws Exception { assumeJava8(); Socket socket = new OpenSSLSocketFactoryImpl().createSocket(); SSLParametersImpl impl = SSLParametersImpl.getDefault(); SSLParameters params = new SSLParameters(); List<SNIServerName> names = new ArrayList<SNIServerName>(); names.add(new SNIHostName("some.host")); params.setServerNames(names); params.setUseCipherSuitesOrder(false); params.setEndpointIdentificationAlgorithm("ABC"); String[] applicationProtocols = new String[] {"foo", "bar"}; if (isJavaVersion(9)) { setApplicationProtocols(params, applicationProtocols); } Platform.setSSLParameters(params, impl, (AbstractConscryptSocket) socket); assertEquals("some.host", ((AbstractConscryptSocket) socket).getHostname()); assertFalse(impl.getUseCipherSuitesOrder()); assertEquals("ABC", impl.getEndpointIdentificationAlgorithm()); if (isJavaVersion(9)) { assertArrayEquals(applicationProtocols, impl.getApplicationProtocols()); } }
@Test public void test_getSSLParameters_Socket() throws Exception { assumeJava8(); Socket socket = new OpenSSLSocketFactoryImpl().createSocket(); SSLParametersImpl impl = SSLParametersImpl.getDefault(); SSLParameters params = new SSLParameters(); impl.setUseCipherSuitesOrder(false); impl.setEndpointIdentificationAlgorithm("ABC"); String[] applicationProtocols = new String[] {"foo", "bar"}; if (isJavaVersion(9)) { impl.setApplicationProtocols(applicationProtocols); } ((AbstractConscryptSocket) socket).setHostname("some.host"); Platform.getSSLParameters(params, impl, (AbstractConscryptSocket) socket); assertEquals("some.host", ((SNIHostName) params.getServerNames().get(0)).getAsciiName()); assertFalse(params.getUseCipherSuitesOrder()); assertEquals("ABC", params.getEndpointIdentificationAlgorithm()); if (isJavaVersion(9)) { assertArrayEquals(applicationProtocols, getApplicationProtocols(params)); } }
@Test public void test_setSSLParameters_Engine() throws Exception { assumeJava8(); SSLParametersImpl impl = SSLParametersImpl.getDefault(); SSLParameters params = new SSLParameters(); ConscryptEngine engine = new ConscryptEngine(impl); List<SNIServerName> names = new ArrayList<SNIServerName>(); names.add(new SNIHostName("some.host")); params.setServerNames(names); params.setUseCipherSuitesOrder(false); params.setEndpointIdentificationAlgorithm("ABC"); String[] applicationProtocols = new String[] {"foo", "bar"}; if (isJavaVersion(9)) { setApplicationProtocols(params, applicationProtocols); } Platform.setSSLParameters(params, impl, engine); assertEquals("some.host", engine.getHostname()); assertFalse(impl.getUseCipherSuitesOrder()); assertEquals("ABC", impl.getEndpointIdentificationAlgorithm()); if (isJavaVersion(9)) { assertArrayEquals(applicationProtocols, impl.getApplicationProtocols()); } }
@Test public void test_getSSLParameters_Engine() throws Exception { assumeJava8(); SSLParametersImpl impl = SSLParametersImpl.getDefault(); SSLParameters params = new SSLParameters(); ConscryptEngine engine = new ConscryptEngine(impl); impl.setUseCipherSuitesOrder(false); impl.setEndpointIdentificationAlgorithm("ABC"); engine.setHostname("some.host"); String[] applicationProtocols = new String[] {"foo", "bar"}; if (isJavaVersion(9)) { impl.setApplicationProtocols(applicationProtocols); } Platform.getSSLParameters(params, impl, engine); assertEquals("some.host", ((SNIHostName) params.getServerNames().get(0)).getAsciiName()); assertFalse(params.getUseCipherSuitesOrder()); assertEquals("ABC", params.getEndpointIdentificationAlgorithm()); if (isJavaVersion(9)) { assertArrayEquals(applicationProtocols, getApplicationProtocols(params)); } }
@TargetApi(24) private static String getSniHostnameFromParams(SSLParameters params) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Method m_getServerNames = params.getClass().getMethod("getServerNames"); @SuppressWarnings("unchecked") List<SNIServerName> serverNames = (List<SNIServerName>) m_getServerNames.invoke(params); if (serverNames != null) { for (SNIServerName serverName : serverNames) { if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { return ((SNIHostName) serverName).getAsciiName(); } } } return null; }
@Test public void test_byteArray_Constructor() throws Exception { TestUtils.assumeSNIHostnameAvailable(); // From draft-josefsson-idn-test-vectors-00 section 5.2 byte[] idnEncoded = new byte[] { (byte) 0xE4, (byte) 0xBB, (byte) 0x96, (byte) 0xE4, (byte) 0xBB, (byte) 0xAC, (byte) 0xE4, (byte) 0xB8, (byte) 0xBA, (byte) 0xE4, (byte) 0xBB, (byte) 0x80, (byte) 0xE4, (byte) 0xB9, (byte) 0x88, (byte) 0xE4, (byte) 0xB8, (byte) 0x8D, (byte) 0xE8, (byte) 0xAF, (byte) 0xB4, (byte) 0xE4, (byte) 0xB8, (byte) 0xAD, (byte) 0xE6, (byte) 0x96, (byte) 0x87, }; SNIHostName hostName = new SNIHostName(idnEncoded); assertEquals("xn--ihqwcrb4cv8a8dqg056pqjye", hostName.getAsciiName()); assertEquals(StandardConstants.SNI_HOST_NAME, hostName.getType()); assertEquals(Arrays.toString(idnEncoded), Arrays.toString(hostName.getEncoded())); }
/** * Returns true if name matches against template.<p> * * The matching is performed as per RFC 2818 rules for TLS and * RFC 2830 rules for LDAP.<p> * * The <code>name</code> parameter should represent a DNS name. * The <code>template</code> parameter * may contain the wildcard character * */ private boolean isMatched(String name, String template) { // check the validity of the domain name template. try { // Replacing wildcard character '*' with 'x' so as to check // the domain name template validity. // // Using the checking implemented in SNIHostName SNIHostName sni = new SNIHostName(template.replace('*', 'x')); } catch (IllegalArgumentException iae) { // It would be nice to add debug log if not matching. return false; } if (checkType == TYPE_TLS) { return matchAllWildcards(name, template); } else if (checkType == TYPE_LDAP) { return matchLeftmostWildcard(name, template); } else { return false; } }
public String getServerName() { String ret = serverName; if (sslEngine != null && sslEngine.getSession() != null) { SSLSession session = sslEngine.getSession(); if (session instanceof ExtendedSSLSession) { ExtendedSSLSession es = (ExtendedSSLSession) session; for (SNIServerName sni : es.getRequestedServerNames()) { SNIHostName hn = new SNIHostName(sni.getEncoded()); ret = hn.getAsciiName(); break; } } } LOG.log("HS DONE, servername is " + ret); return ret; }
/** * Method retrieves requested server name from ExtendedSSLSession and * uses it to return proper alias for server certificate * * @param session * @return */ private String chooseServerAlias(ExtendedSSLSession session) { // Pick first SNIHostName in the list of SNI names. String hostname = null; for (SNIServerName name : session.getRequestedServerNames()) { if (name.getType() == StandardConstants.SNI_HOST_NAME) { hostname = ((SNIHostName) name).getAsciiName(); break; } } // If we got given a hostname over SNI, check if we have a cert and // key for that hostname. If so, we use it. // Otherwise, we fall back to the default certificate. if (hostname != null && (getCertificateChain(hostname) != null && getPrivateKey(hostname) != null)) { return hostname; } else { return def_cert_alias; } }
static SSLClient init(String host, int port, String cipherSuiteFilter, String sniHostName) throws NoSuchAlgorithmException, IOException { SSLContext sslContext = SSLContext.getDefault(); SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory(); SSLSocket socket = (SSLSocket) ssf.createSocket(host, port); SSLParameters params = new SSLParameters(); if (cipherSuiteFilter != null) { String[] cipherSuites = UnboundSSLUtils.filterStringArray( ssf.getSupportedCipherSuites(), cipherSuiteFilter); System.out.println("Client: enabled cipher suites: " + Arrays.toString(cipherSuites)); params.setCipherSuites(cipherSuites); } if (sniHostName != null) { System.out.println("Client: set SNI hostname: " + sniHostName); SNIHostName serverName = new SNIHostName(sniHostName); List<SNIServerName> serverNames = new ArrayList<>(); serverNames.add(serverName); params.setServerNames(serverNames); } socket.setSSLParameters(params); return new SSLClient(socket); }
static SSLEchoServer init(String cipherSuiteFilter, String sniPattern) throws NoSuchAlgorithmException, IOException { SSLContext context = SSLContext.getDefault(); SSLServerSocketFactory ssf = (SSLServerSocketFactory) context.getServerSocketFactory(); SSLServerSocket ssocket = (SSLServerSocket) ssf.createServerSocket(0); // specify enabled cipher suites if (cipherSuiteFilter != null) { String[] ciphersuites = UnboundSSLUtils.filterStringArray( ssf.getSupportedCipherSuites(), cipherSuiteFilter); System.out.println("Server: enabled cipher suites: " + Arrays.toString(ciphersuites)); ssocket.setEnabledCipherSuites(ciphersuites); } // specify SNI matcher pattern if (sniPattern != null) { System.out.println("Server: set SNI matcher: " + sniPattern); SNIMatcher matcher = SNIHostName.createSNIMatcher(sniPattern); List<SNIMatcher> matchers = new ArrayList<>(); matchers.add(matcher); SSLParameters params = ssocket.getSSLParameters(); params.setSNIMatchers(matchers); ssocket.setSSLParameters(params); } return new SSLEchoServer(ssocket); }
/** * Check if the certificate allows use of the given DNS name. * * From RFC2818: * If a subjectAltName extension of type dNSName is present, that MUST * be used as the identity. Otherwise, the (most specific) Common Name * field in the Subject field of the certificate MUST be used. Although * the use of the Common Name is existing practice, it is deprecated and * Certification Authorities are encouraged to use the dNSName instead. * * Matching is performed using the matching rules specified by * [RFC5280]. If more than one identity of a given type is present in * the certificate (e.g., more than one dNSName name, a match in any one * of the set is considered acceptable.) */ private void matchDNS(String expectedName, X509Certificate cert, boolean chainsToPublicCA) throws CertificateException { // Check that the expected name is a valid domain name. try { // Using the checking implemented in SNIHostName SNIHostName sni = new SNIHostName(expectedName); } catch (IllegalArgumentException iae) { throw new CertificateException( "Illegal given domain name: " + expectedName, iae); } Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames(); if (subjAltNames != null) { boolean foundDNS = false; for (List<?> next : subjAltNames) { if (((Integer)next.get(0)).intValue() == ALTNAME_DNS) { foundDNS = true; String dnsName = (String)next.get(1); if (isMatched(expectedName, dnsName, chainsToPublicCA)) { return; } } } if (foundDNS) { // if certificate contains any subject alt names of type DNS // but none match, reject throw new CertificateException("No subject alternative DNS " + "name matching " + expectedName + " found."); } } X500Name subjectName = getSubjectX500Name(cert); DerValue derValue = subjectName.findMostSpecificAttribute (X500Name.commonName_oid); if (derValue != null) { try { if (isMatched(expectedName, derValue.getAsString(), chainsToPublicCA)) { return; } } catch (IOException e) { // ignore } } String msg = "No name matching " + expectedName + " found"; throw new CertificateException(msg); }
/** * Returns true if name matches against template.<p> * * The matching is performed as per RFC 2818 rules for TLS and * RFC 2830 rules for LDAP.<p> * * The <code>name</code> parameter should represent a DNS name. * The <code>template</code> parameter * may contain the wildcard character * */ private boolean isMatched(String name, String template, boolean chainsToPublicCA) { if (hasIllegalWildcard(name, template, chainsToPublicCA)) { return false; } // check the validity of the domain name template. try { // Replacing wildcard character '*' with 'x' so as to check // the domain name template validity. // // Using the checking implemented in SNIHostName SNIHostName sni = new SNIHostName(template.replace('*', 'x')); } catch (IllegalArgumentException iae) { // It would be nice to add debug log if not matching. return false; } if (checkType == TYPE_TLS) { return matchAllWildcards(name, template); } else if (checkType == TYPE_LDAP) { return matchLeftmostWildcard(name, template); } else { return false; } }
/** * Returns client ssl engine. * * @param context - SSLContext to get SSLEngine from. * @param useSNI - flag used to enable or disable using SNI extension. * Needed for Kerberos. */ public static SSLEngine getClientSSLEngine(SSLContext context, boolean useSNI) { SSLEngine clientEngine = context.createSSLEngine(HOST, 80); clientEngine.setUseClientMode(true); if (useSNI) { SNIHostName serverName = new SNIHostName(SERVER_NAME); List<SNIServerName> serverNames = new ArrayList<>(); serverNames.add(serverName); SSLParameters params = clientEngine.getSSLParameters(); params.setServerNames(serverNames); clientEngine.setSSLParameters(params); } return clientEngine; }
/** * Returns server ssl engine. * * @param context - SSLContext to get SSLEngine from. * @param useSNI - flag used to enable or disable using SNI extension. * Needed for Kerberos. */ public static SSLEngine getServerSSLEngine(SSLContext context, boolean useSNI) { SSLEngine serverEngine = context.createSSLEngine(); serverEngine.setUseClientMode(false); if (useSNI) { SNIMatcher matcher = SNIHostName.createSNIMatcher(SNI_PATTERN); List<SNIMatcher> matchers = new ArrayList<>(); matchers.add(matcher); SSLParameters params = serverEngine.getSSLParameters(); params.setSNIMatchers(matchers); serverEngine.setSSLParameters(params); } return serverEngine; }
static void setSSLParameters( SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); List<SNIServerName> serverNames = params.getServerNames(); if (serverNames != null) { for (SNIServerName serverName : serverNames) { if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { socket.setHostname(((SNIHostName) serverName).getAsciiName()); break; } } } }
static void getSSLParameters( SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); if (impl.getUseSni() && AddressUtils.isValidSniHostname(socket.getHostname())) { params.setServerNames(Collections.<SNIServerName>singletonList( new SNIHostName(socket.getHostname()))); } }
static void setSSLParameters( SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { impl.setEndpointIdentificationAlgorithm(params.getEndpointIdentificationAlgorithm()); impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); List<SNIServerName> serverNames = params.getServerNames(); if (serverNames != null) { for (SNIServerName serverName : serverNames) { if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { engine.setHostname(((SNIHostName) serverName).getAsciiName()); break; } } } }
static void getSSLParameters( SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { params.setEndpointIdentificationAlgorithm(impl.getEndpointIdentificationAlgorithm()); params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) { params.setServerNames(Collections.<SNIServerName>singletonList( new SNIHostName(engine.getHostname()))); } }
static void setSSLParameters( SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { Java7PlatformUtil.setSSLParameters(params, impl); impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); List<SNIServerName> serverNames = params.getServerNames(); if (serverNames != null) { for (SNIServerName serverName : serverNames) { if (serverName.getType() == SNI_HOST_NAME) { socket.setHostname(((SNIHostName) serverName).getAsciiName()); break; } } } }
static void getSSLParameters( SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) { Java7PlatformUtil.getSSLParameters(params, impl); params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); if (impl.getUseSni() && AddressUtils.isValidSniHostname(socket.getHostname())) { params.setServerNames(Collections.singletonList( (SNIServerName) new SNIHostName(socket.getHostname()))); } }
static void setSSLParameters( SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { Java7PlatformUtil.setSSLParameters(params, impl); impl.setUseCipherSuitesOrder(params.getUseCipherSuitesOrder()); List<SNIServerName> serverNames = params.getServerNames(); if (serverNames != null) { for (SNIServerName serverName : serverNames) { if (serverName.getType() == SNI_HOST_NAME) { engine.setHostname(((SNIHostName) serverName).getAsciiName()); break; } } } }
static void getSSLParameters( SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) { Java7PlatformUtil.getSSLParameters(params, impl); params.setUseCipherSuitesOrder(impl.getUseCipherSuitesOrder()); if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) { params.setServerNames(Collections.singletonList( (SNIServerName) new SNIHostName((engine.getHostname())))); } }
@TargetApi(24) private static void setParametersSniHostname( SSLParameters params, SSLParametersImpl impl, AbstractConscryptSocket socket) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (impl.getUseSni() && AddressUtils.isValidSniHostname(socket.getHostname())) { Method m_setServerNames = params.getClass().getMethod("setServerNames", List.class); m_setServerNames.invoke(params, Collections.<SNIServerName>singletonList( new SNIHostName(socket.getHostname()))); } }
@TargetApi(24) private static void setParametersSniHostname( SSLParameters params, SSLParametersImpl impl, ConscryptEngine engine) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (impl.getUseSni() && AddressUtils.isValidSniHostname(engine.getHostname())) { Method m_setServerNames = params.getClass().getMethod("setServerNames", List.class); m_setServerNames.invoke(params, Collections.<SNIServerName>singletonList( new SNIHostName(engine.getHostname()))); } }
@Override public final List<SNIServerName> getRequestedServerNames() { String requestedServerName = getDelegate().getRequestedServerName(); if (requestedServerName == null) { return null; } return Collections.singletonList((SNIServerName) new SNIHostName(requestedServerName)); }