You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2014/08/19 16:11:24 UTC

svn commit: r1618868 - in /httpcomponents/httpclient/trunk/httpclient/src: main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java

Author: olegk
Date: Tue Aug 19 14:11:23 2014
New Revision: 1618868

URL: http://svn.apache.org/r1618868
Log:
Ported existing test cases to new default HostnameVerifier impl

Modified:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java?rev=1618868&r1=1618867&r2=1618868&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java Tue Aug 19 14:11:23 2014
@@ -146,8 +146,8 @@ public final class DefaultHostnameVerifi
         final String normalisedHost = normaliseAddress(host);
         for (int i = 0; i < subjectAlts.size(); i++) {
             final String subjectAlt = subjectAlts.get(i);
-            final String normalizedsSubjectAlt = normaliseAddress(subjectAlt);
-            if (normalisedHost.equals(normalizedsSubjectAlt)) {
+            final String normalizedSubjectAlt = normaliseAddress(subjectAlt);
+            if (normalisedHost.equals(normalizedSubjectAlt)) {
                 return;
             }
         }
@@ -158,7 +158,7 @@ public final class DefaultHostnameVerifi
     static void matchDNSName(final String host, final List<String> subjectAlts) throws SSLException {
         for (int i = 0; i < subjectAlts.size(); i++) {
             final String subjectAlt = subjectAlts.get(i);
-            if (matchIdentity(host, subjectAlt)) {
+            if (matchIdentityStrict(host, subjectAlt)) {
                 return;
             }
         }
@@ -167,7 +167,7 @@ public final class DefaultHostnameVerifi
     }
 
     static void matchCN(final String host, final String cn) throws SSLException {
-        if (!matchIdentity(host, cn)) {
+        if (!matchIdentityStrict(host, cn)) {
             throw new SSLException("Certificate for <" + host + "> doesn't match " +
                     "common name of the certificate subject: " + cn);
         }
@@ -246,12 +246,12 @@ public final class DefaultHostnameVerifi
     }
 
     static List<String> extractSubjectAlts(final X509Certificate cert, final int subjectType) {
-        List<String> subjectAltList = null;
         Collection<List<?>> c = null;
         try {
             c = cert.getSubjectAlternativeNames();
         } catch(final CertificateParsingException ignore) {
         }
+        List<String> subjectAltList = null;
         if (c != null) {
             for (final List<?> aC : c) {
                 final List<?> list = aC;

Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java?rev=1618868&r1=1618867&r2=1618868&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java Tue Aug 19 14:11:23 2014
@@ -27,9 +27,16 @@
 
 package org.apache.http.conn.ssl;
 
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+
 import javax.net.ssl.SSLException;
 
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 
 /**
@@ -37,6 +44,210 @@ import org.junit.Test;
  */
 public class TestDefaultHostnameVerifier {
 
+    private DefaultHostnameVerifier impl;
+
+    @Before
+    public void setup() {
+        impl = DefaultHostnameVerifier.INSTANCE;
+    }
+
+    @Test
+    public void testVerify() throws Exception {
+        final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        InputStream in;
+        X509Certificate x509;
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+
+        impl.verify("foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+        exceptionPlease(impl, "bar.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        impl.verify("\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(impl, "a.\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO_BAR);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(impl, "foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+        impl.verify("bar.com", x509);
+        exceptionPlease(impl, "a.bar.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_FOO_BAR_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(impl, "foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+        impl.verify("bar.com", x509);
+        exceptionPlease(impl, "a.bar.com", x509);
+
+        /*
+           Java isn't extracting international subjectAlts properly.  (Or
+           OpenSSL isn't storing them properly).
+        */
+        // DEFAULT.verify("\u82b1\u5b50.co.jp", x509 );
+        // impl.verify("\u82b1\u5b50.co.jp", x509 );
+        exceptionPlease(impl, "a.\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_NO_CNS_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        impl.verify("foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_NO_CNS_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        impl.verify("foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_THREE_CNS_FOO_BAR_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(impl, "foo.com", x509);
+        exceptionPlease(impl, "a.foo.com", x509);
+        exceptionPlease(impl, "bar.com", x509);
+        exceptionPlease(impl, "a.bar.com", x509);
+        impl.verify("\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(impl, "a.\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(impl, "foo.com", x509);
+        impl.verify("www.foo.com", x509);
+        impl.verify("\u82b1\u5b50.foo.com", x509);
+        exceptionPlease(impl, "a.b.foo.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_CO_JP);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        // Silly test because no-one would ever be able to lookup an IP address
+        // using "*.co.jp".
+        impl.verify("*.co.jp", x509);
+        exceptionPlease(impl, "foo.co.jp", x509);
+        exceptionPlease(impl, "\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_WILD_FOO_BAR_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        // try the foo.com variations
+        exceptionPlease(impl, "foo.com", x509);
+        exceptionPlease(impl, "www.foo.com", x509);
+        exceptionPlease(impl, "\u82b1\u5b50.foo.com", x509);
+        exceptionPlease(impl, "a.b.foo.com", x509);
+        // try the bar.com variations
+        exceptionPlease(impl, "bar.com", x509);
+        impl.verify("www.bar.com", x509);
+        impl.verify("\u82b1\u5b50.bar.com", x509);
+        exceptionPlease(impl, "a.b.bar.com", x509);
+
+        in = new ByteArrayInputStream(CertificatesToPlayWith.X509_MULTIPLE_VALUE_AVA);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        impl.verify("repository.infonotary.com", x509);
+    }
+
+    @Test
+    public void testSubjectAlt() throws Exception {
+        final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        final InputStream in = new ByteArrayInputStream(CertificatesToPlayWith.X509_MULTIPLE_SUBJECT_ALT);
+        final X509Certificate x509 = (X509Certificate) cf.generateCertificate(in);
+
+        Assert.assertEquals("CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=CH",
+                x509.getSubjectDN().getName());
+
+        impl.verify("localhost.localdomain", x509);
+        impl.verify("127.0.0.1", x509);
+
+        try {
+            impl.verify("localhost", x509);
+            Assert.fail("SSLException should have been thrown");
+        } catch (final SSLException ex) {
+            // expected
+        }
+        try {
+            impl.verify("local.host", x509);
+            Assert.fail("SSLException should have been thrown");
+        } catch (final SSLException ex) {
+            // expected
+        }
+        try {
+            impl.verify("127.0.0.2", x509);
+            Assert.fail("SSLException should have been thrown");
+        } catch (final SSLException ex) {
+            // expected
+        }
+    }
+
+    public void exceptionPlease(final DefaultHostnameVerifier hv, final String host,
+                                final X509Certificate x509) {
+        try {
+            hv.verify(host, x509);
+            Assert.fail("HostnameVerifier shouldn't allow [" + host + "]");
+        }
+        catch(final SSLException e) {
+            // whew!  we're okay!
+        }
+    }
+
+    @Test
+    public void testIdentityMatching() {
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.b.c", "*.b.c"));
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "*.b.c"));
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.b.c", "*.b.c"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.b.c", "*.b.c")); // subdomain not OK
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.gov.uk", "*.gov.uk"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.gov.uk", "*.gov.uk"));  // Bad 2TLD
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.gov.uk", "*.gov.uk"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.uk", "*.gov.uk"));  // BBad 2TLD/no subdomain allowed
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.gov.com", "*.gov.com"));
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.gov.com", "*.gov.com"));
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("s.a.gov.com", "*.gov.com"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.com", "*.gov.com")); // no subdomain allowed
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.gov.uk", "a*.gov.uk"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.gov.uk", "a*.gov.uk")); // Bad 2TLD
+
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentity("s.a.gov.uk", "a*.gov.uk")); // Bad 2TLD
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("s.a.gov.uk", "a*.gov.uk")); // Bad 2TLD/no subdomain allowed
+    }
+
+    @Test
+    public void testHTTPCLIENT_1097() {
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.b.c", "a*.b.c"));
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "a*.b.c"));
+
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.a.b.c", "a*.b.c"));
+        Assert.assertFalse(DefaultHostnameVerifier.matchIdentityStrict("a.a.b.c", "a*.b.c"));
+    }
+
+    @Test
+    public void testHTTPCLIENT_1255() {
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("mail.a.b.c.com", "m*.a.b.c.com"));
+        Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("mail.a.b.c.com", "m*.a.b.c.com"));
+    }
+
+    @Test // Check compressed IPv6 hostname matching
+    public void testHTTPCLIENT_1316() throws Exception{
+        final String host1 = "2001:0db8:aaaa:bbbb:cccc:0:0:0001";
+        DefaultHostnameVerifier.matchIPv6Address(host1, Arrays.asList("2001:0db8:aaaa:bbbb:cccc:0:0:0001"));
+        DefaultHostnameVerifier.matchIPv6Address(host1, Arrays.asList("2001:0db8:aaaa:bbbb:cccc::1"));
+        try {
+            DefaultHostnameVerifier.matchIPv6Address(host1, Arrays.asList("2001:0db8:aaaa:bbbb:cccc::10"));
+            Assert.fail("SSLException expected");
+        } catch (SSLException expected) {
+        }
+        final String host2 = "2001:0db8:aaaa:bbbb:cccc::1";
+        DefaultHostnameVerifier.matchIPv6Address(host2, Arrays.asList("2001:0db8:aaaa:bbbb:cccc:0:0:0001"));
+        DefaultHostnameVerifier.matchIPv6Address(host2, Arrays.asList("2001:0db8:aaaa:bbbb:cccc::1"));
+        try {
+            DefaultHostnameVerifier.matchIPv6Address(host2, Arrays.asList("2001:0db8:aaaa:bbbb:cccc::10"));
+            Assert.fail("SSLException expected");
+        } catch (SSLException expected) {
+        }
+    }
+
     @Test
     public void testExtractCN() throws Exception {
         Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=blah, ou=blah, o=blah"));
@@ -47,16 +258,16 @@ public class TestDefaultHostnameVerifier
         Assert.assertEquals("blah, blah", DefaultHostnameVerifier.extractCN("cn=\"blah, blah\", ou=blah, o=blah"));
         Assert.assertEquals("blah, blah", DefaultHostnameVerifier.extractCN("cn=blah\\, blah, ou=blah, o=blah"));
         Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("c = cn=uuh, cn=blah, ou=blah, o=blah"));
-    }
-
-    @Test(expected = SSLException.class)
-    public void testExtractCNMissing() throws Exception {
-        DefaultHostnameVerifier.extractCN("blah,blah");
-    }
-
-    @Test(expected = SSLException.class)
-    public void testExtractCNNull() throws Exception {
-        DefaultHostnameVerifier.extractCN("cn,o=blah");
+        try {
+            DefaultHostnameVerifier.extractCN("blah,blah");
+            Assert.fail("SSLException expected");
+        } catch (SSLException expected) {
+        }
+        try {
+            DefaultHostnameVerifier.extractCN("cn,o=blah");
+            Assert.fail("SSLException expected");
+        } catch (SSLException expected) {
+        }
     }
 
 }