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 BDFF211F6A for ; Fri, 5 Sep 2014 13:17:53 +0000 (UTC) Received: (qmail 25989 invoked by uid 500); 5 Sep 2014 13:17:53 -0000 Delivered-To: apmail-hc-commits-archive@hc.apache.org Received: (qmail 25953 invoked by uid 500); 5 Sep 2014 13:17:53 -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 25944 invoked by uid 99); 5 Sep 2014 13:17:53 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 05 Sep 2014 13:17:53 +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; Fri, 05 Sep 2014 13:17:51 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 32C1E23888E2 for ; Fri, 5 Sep 2014 13:17:31 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1622696 - in /httpcomponents/httpclient/trunk/httpclient/src: main/java/org/apache/http/conn/ssl/ test/java/org/apache/http/conn/ssl/ Date: Fri, 05 Sep 2014 13:17:30 -0000 To: commits@hc.apache.org From: olegk@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140905131731.32C1E23888E2@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: olegk Date: Fri Sep 5 13:17:30 2014 New Revision: 1622696 URL: http://svn.apache.org/r1622696 Log: Reverted to simple wildcard matching Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLConnectionSocketFactory.java httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestHostnameVerifier.java Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java?rev=1622696&r1=1622695&r2=1622696&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java (original) +++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java Fri Sep 5 13:17:30 2014 @@ -177,20 +177,46 @@ public abstract class AbstractVerifier i } } - private static boolean matchIdentity(final String host, final String identity, final boolean strictWithSubDomains) { - return strictWithSubDomains ? - DefaultHostnameVerifier.matchIdentityStrict(host, identity) : - DefaultHostnameVerifier.matchIdentity(host, identity); + private static boolean matchIdentity(final String host, final String identity, final boolean strict) { + if (host == null) { + return false; + } + final String normalizedHost = host.toLowerCase(Locale.ROOT); + final String normalizedIdentity = identity.toLowerCase(Locale.ROOT); + // The CN better have at least two dots if it wants wildcard + // action. It also can't be [*.co.uk] or [*.co.jp] or + // [*.org.uk], etc... + final String parts[] = normalizedIdentity.split("\\."); + final boolean doWildcard = parts.length >= 3 && parts[0].endsWith("*") && + (!strict || validCountryWildcard(parts)); + if (doWildcard) { + boolean match; + final String firstpart = parts[0]; + if (firstpart.length() > 1) { // e.g. server* + final String prefix = firstpart.substring(0, firstpart.length() - 1); // e.g. server + final String suffix = normalizedIdentity.substring(firstpart.length()); // skip wildcard part from cn + final String hostSuffix = normalizedHost.substring(prefix.length()); // skip wildcard part from normalizedHost + match = normalizedHost.startsWith(prefix) && hostSuffix.endsWith(suffix); + } else { + match = normalizedHost.endsWith(normalizedIdentity.substring(1)); + } + return match && (!strict || countDots(normalizedHost) == countDots(normalizedIdentity)); + } else { + return normalizedHost.equals(normalizedIdentity); + } } - public static boolean acceptableCountryWildcard(final String cn) { - final String parts[] = cn.split("\\."); + private static boolean validCountryWildcard(final String parts[]) { if (parts.length != 3 || parts[2].length() != 2) { return true; // it's not an attempt to wildcard a 2TLD within a country code } return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0; } + public static boolean acceptableCountryWildcard(final String cn) { + return validCountryWildcard(cn.split("\\.")); + } + public static String[] getCNs(final X509Certificate cert) { final String subjectPrincipal = cert.getSubjectX500Principal().toString(); try { 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=1622696&r1=1622695&r2=1622696&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 Fri Sep 5 13:17:30 2014 @@ -35,9 +35,9 @@ import java.security.cert.X509Certificat import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Locale; import java.util.NoSuchElementException; import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; import javax.naming.InvalidNameException; import javax.naming.NamingException; @@ -63,11 +63,6 @@ import org.apache.http.conn.util.InetAdd @Immutable public final class DefaultHostnameVerifier implements HostnameVerifier { - public static final DefaultHostnameVerifier INSTANCE = new DefaultHostnameVerifier(); - - private final static Pattern WILDCARD_PATTERN = Pattern.compile( - "^[a-z0-9\\-\\*]+(\\.[a-z0-9\\-]+){2,}$", - Pattern.CASE_INSENSITIVE); /** * This contains a list of 2nd-level domains that aren't allowed to * have wildcards when combined with country-codes. @@ -155,9 +150,11 @@ public final class DefaultHostnameVerifi } static void matchDNSName(final String host, final List subjectAlts) throws SSLException { + final String normalizedHost = host.toLowerCase(Locale.ROOT); for (int i = 0; i < subjectAlts.size(); i++) { final String subjectAlt = subjectAlts.get(i); - if (matchIdentityStrict(host, subjectAlt)) { + final String normalizedSubjectAlt = subjectAlt.toLowerCase(Locale.ROOT); + if (matchIdentityStrict(normalizedHost, normalizedSubjectAlt)) { return; } } @@ -176,34 +173,31 @@ public final class DefaultHostnameVerifi if (host == null) { return false; } - // The CN better have at least two dots if it wants wildcard - // action. It also can't be [*.co.uk] or [*.co.jp] or - // [*.org.uk], etc... - if (identity.contains("*") && WILDCARD_PATTERN.matcher(identity).matches()) { + // RFC 2818, 3.1. Server Identity + // "...Names may contain the wildcard + // character * which is considered to match any single domain name + // component or component fragment..." + // Based on this statement presuming only singular wildcard is legal + final int asteriskIdx = identity.indexOf('*'); + if (asteriskIdx != -1) { if (!strict || !BAD_COUNTRY_WILDCARD_PATTERN.matcher(identity).matches()) { - final StringBuilder buf = new StringBuilder(); - buf.append("^"); - for (int i = 0; i < identity.length(); i++) { - final char ch = identity.charAt(i); - if (ch == '.') { - buf.append("\\."); - } else if (ch == '*') { - if (strict) { - buf.append("[a-z0-9\\-]*"); - } else { - buf.append(".*"); - } - } else { - buf.append(ch); - } + final String prefix = identity.substring(0, asteriskIdx); + final String suffix = identity.substring(asteriskIdx + 1); + if (!prefix.isEmpty() && !host.startsWith(prefix)) { + return false; + } + if (!suffix.isEmpty() && !host.endsWith(suffix)) { + return false; } - buf.append("$"); - try { - final Pattern identityPattern = Pattern.compile(buf.toString(), Pattern.CASE_INSENSITIVE); - return identityPattern.matcher(host).matches(); - } catch (PatternSyntaxException ignore) { - // do simple match + // Additional sanity checks on content selected by wildcard can be done here + if (strict) { + final String remainder = host.substring( + prefix.length(), host.length() - suffix.length()); + if (remainder.contains(".")) { + return false; + } } + return true; } } return host.equalsIgnoreCase(identity); Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLConnectionSocketFactory.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLConnectionSocketFactory.java?rev=1622696&r1=1622695&r2=1622696&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLConnectionSocketFactory.java (original) +++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/SSLConnectionSocketFactory.java Fri Sep 5 13:17:30 2014 @@ -148,7 +148,7 @@ public class SSLConnectionSocketFactory * @since 4.4 */ public static HostnameVerifier getDefaultHostnameVerifier() { - return DefaultHostnameVerifier.INSTANCE; + return new DefaultHostnameVerifier(); } /** 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=1622696&r1=1622695&r2=1622696&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 Fri Sep 5 13:17:30 2014 @@ -48,7 +48,7 @@ public class TestDefaultHostnameVerifier @Before public void setup() { - impl = DefaultHostnameVerifier.INSTANCE; + impl = new DefaultHostnameVerifier(); } @Test @@ -113,7 +113,7 @@ public class TestDefaultHostnameVerifier x509 = (X509Certificate) cf.generateCertificate(in); exceptionPlease(impl, "foo.com", x509); impl.verify("www.foo.com", x509); - exceptionPlease(impl, "\u82b1\u5b50.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); @@ -134,7 +134,7 @@ public class TestDefaultHostnameVerifier // try the bar.com variations exceptionPlease(impl, "bar.com", x509); impl.verify("www.bar.com", x509); - exceptionPlease(impl, "\u82b1\u5b50.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); @@ -191,13 +191,6 @@ public class TestDefaultHostnameVerifier Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.b.c", "*.b.c")); Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.b.c", "*.b.c")); - Assert.assertTrue(DefaultHostnameVerifier.matchIdentity("a.B.c", "*.b.c")); - Assert.assertTrue(DefaultHostnameVerifier.matchIdentityStrict("a.B.c", "*.b.c")); - - 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 Modified: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestHostnameVerifier.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestHostnameVerifier.java?rev=1622696&r1=1622695&r2=1622696&view=diff ============================================================================== --- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestHostnameVerifier.java (original) +++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestHostnameVerifier.java Fri Sep 5 13:17:30 2014 @@ -139,7 +139,7 @@ public class TestHostnameVerifier { DEFAULT.verify("www.foo.com", x509); STRICT.verify("www.foo.com", x509); DEFAULT.verify("\u82b1\u5b50.foo.com", x509); - exceptionPlease(STRICT, "\u82b1\u5b50.foo.com", x509); + STRICT.verify("\u82b1\u5b50.foo.com", x509); DEFAULT.verify("a.b.foo.com", x509); exceptionPlease(STRICT, "a.b.foo.com", x509); @@ -171,7 +171,7 @@ public class TestHostnameVerifier { DEFAULT.verify("www.bar.com", x509); STRICT.verify("www.bar.com", x509); DEFAULT.verify("\u82b1\u5b50.bar.com", x509); - exceptionPlease(STRICT, "\u82b1\u5b50.bar.com", x509); + STRICT.verify("\u82b1\u5b50.bar.com", x509); DEFAULT.verify("a.b.bar.com", x509); exceptionPlease(STRICT, "a.b.bar.com", x509);