Return-Path: X-Original-To: apmail-hc-commits-archive@www.apache.org Delivered-To: apmail-hc-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 6C9A511356 for ; Tue, 19 Aug 2014 14:11:47 +0000 (UTC) Received: (qmail 15603 invoked by uid 500); 19 Aug 2014 14:11:47 -0000 Delivered-To: apmail-hc-commits-archive@hc.apache.org Received: (qmail 15563 invoked by uid 500); 19 Aug 2014 14:11:47 -0000 Mailing-List: contact commits-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list commits@hc.apache.org Received: (qmail 15554 invoked by uid 99); 19 Aug 2014 14:11:47 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 19 Aug 2014 14:11:47 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 19 Aug 2014 14:11:44 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 64D7823889E1 for ; Tue, 19 Aug 2014 14:11:24 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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 Date: Tue, 19 Aug 2014 14:11:24 -0000 To: commits@hc.apache.org From: olegk@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140819141124.64D7823889E1@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 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 extractSubjectAlts(final X509Certificate cert, final int subjectType) { - List subjectAltList = null; Collection> c = null; try { c = cert.getSubjectAlternativeNames(); } catch(final CertificateParsingException ignore) { } + List 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) { + } } }