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/18 20:39:34 UTC

svn commit: r1618698 - in /httpcomponents/httpclient/trunk/httpclient/src: main/java/org/apache/http/conn/ssl/ test/java/org/apache/http/conn/ssl/

Author: olegk
Date: Mon Aug 18 18:39:33 2014
New Revision: 1618698

URL: http://svn.apache.org/r1618698
Log:
Re-designed hostname verification API and rewritten implementation code

Added:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java   (with props)
    httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java   (with props)
Removed:
    httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/AbstractCommonHostnameVerifier.java
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/BrowserCompatHostnameVerifier.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=1618698&r1=1618697&r2=1618698&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 Mon Aug 18 18:39:33 2014
@@ -31,11 +31,18 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
 
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
+import javax.security.auth.x500.X500Principal;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.conn.util.InetAddressUtils;
 import org.apache.http.util.Args;
 
 /**
@@ -44,11 +51,13 @@ import org.apache.http.util.Args;
  *
  * @since 4.0
  *
- * @deprecated (4.4) use {@link javax.net.ssl.HostnameVerifier} or
- *  {@link org.apache.http.conn.ssl.AbstractCommonHostnameVerifier}.
+ * @deprecated (4.4) use an implementation of {@link javax.net.ssl.HostnameVerifier} or
+ *  {@link DefaultHostnameVerifier}.
  */
 @Deprecated
-public abstract class AbstractVerifier extends AbstractCommonHostnameVerifier implements X509HostnameVerifier {
+public abstract class AbstractVerifier implements X509HostnameVerifier {
+
+    private final Log log = LogFactory.getLog(getClass());
 
     @Override
     public final void verify(final String host, final SSLSocket ssl)
@@ -96,10 +105,97 @@ public abstract class AbstractVerifier e
         verify(host, x509);
     }
 
+    @Override
+    public final boolean verify(final String host, final SSLSession session) {
+        try {
+            final Certificate[] certs = session.getPeerCertificates();
+            final X509Certificate x509 = (X509Certificate) certs[0];
+            verify(host, x509);
+            return true;
+        } catch(final SSLException ex) {
+            if (log.isDebugEnabled()) {
+                log.debug(ex.getMessage(), ex);
+            }
+            return false;
+        }
+    }
+
+    public final void verify(
+            final String host, final X509Certificate cert) throws SSLException {
+        final boolean ipv4 = InetAddressUtils.isIPv4Address(host);
+        final boolean ipv6 = InetAddressUtils.isIPv6Address(host);
+        final int subjectType = ipv4 || ipv6 ? DefaultHostnameVerifier.IP_ADDRESS_TYPE : DefaultHostnameVerifier.DNS_NAME_TYPE;
+        final List<String> subjectAlts = DefaultHostnameVerifier.extractSubjectAlts(cert, subjectType);
+        final X500Principal subjectPrincipal = cert.getSubjectX500Principal();
+        final String cn = DefaultHostnameVerifier.extractCN(subjectPrincipal.getName(X500Principal.RFC2253));
+        verify(host,
+                cn != null ? new String[] {cn} : null,
+                subjectAlts != null && !subjectAlts.isEmpty() ? subjectAlts.toArray(new String[subjectAlts.size()]) : null);
+    }
+
+    public final void verify(final String host, final String[] cns,
+                             final String[] subjectAlts,
+                             final boolean strictWithSubDomains)
+            throws SSLException {
+
+        final String cn = cns != null && cns.length > 0 ? cns[0] : null;
+        final List<String> subjectAltList = subjectAlts != null && subjectAlts.length > 0 ? Arrays.asList(subjectAlts) : null;
+        if (cn == null && subjectAltList == null) {
+            final String msg = "Certificate subject for <" + host + "> doesn't contain a common name " +
+                    "and does not have alternative names";
+            throw new SSLException(msg);
+        }
+        final String normalizedHost = InetAddressUtils.isIPv6Address(host) ?
+                DefaultHostnameVerifier.normaliseAddress(host.toLowerCase(Locale.ROOT)) : host;
+        if (cn != null) {
+            final String normalizedCN = InetAddressUtils.isIPv6Address(cn) ?
+                    DefaultHostnameVerifier.normaliseAddress(cn) : cn;
+            if (matchIdentity(normalizedHost, normalizedCN, strictWithSubDomains)) {
+                return;
+            }
+        }
+        if (subjectAltList != null) {
+            for (String subjectAlt: subjectAltList) {
+                final String normalizedAltSubject = InetAddressUtils.isIPv6Address(subjectAlt) ?
+                        DefaultHostnameVerifier.normaliseAddress(subjectAlt) : subjectAlt;
+                if (matchIdentity(normalizedHost, normalizedAltSubject, strictWithSubDomains)) {
+                    return;
+                }
+            }
+        }
+        final StringBuilder buf = new StringBuilder();
+        buf.append("Certificate for <").append(host).append("> doesn't match ");
+        if (cn != null) {
+            buf.append("common name of the certificate subject [").append(cn).append("]");
+        }
+        if (subjectAltList != null) {
+            if (cn != null) {
+                buf.append(" or ");
+            }
+            buf.append(" any of the subject alternative names").append(subjectAltList);
+        }
+        throw new SSLException(buf.toString());
+    }
+
+    private static boolean matchIdentity(final String host, final String identity, final boolean strictWithSubDomains) {
+        return strictWithSubDomains ?
+                DefaultHostnameVerifier.matchIdentityStrict(host, identity) :
+                DefaultHostnameVerifier.matchIdentity(host, identity);
+    }
+
+    public static boolean acceptableCountryWildcard(final String cn) {
+        final String parts[] = cn.split("\\.");
+        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(DefaultHostnameVerifier.BAD_COUNTRY_2LDS, parts[1]) < 0;
+    }
+
     public static String[] getCNs(final X509Certificate cert) {
         final String subjectPrincipal = cert.getSubjectX500Principal().toString();
         try {
-            return extractCNs(subjectPrincipal);
+            final String cn = DefaultHostnameVerifier.extractCN(subjectPrincipal);
+            return cn != null ? new String[] { cn } : null;
         } catch (SSLException ex) {
             return null;
         }
@@ -120,7 +216,19 @@ public abstract class AbstractVerifier e
      * @return Array of SubjectALT DNS names stored in the certificate.
      */
     public static String[] getDNSSubjectAlts(final X509Certificate cert) {
-        return extractSubjectAlts(cert, null);
+        final List<String> subjectAlts = DefaultHostnameVerifier.extractSubjectAlts(
+                cert, DefaultHostnameVerifier.DNS_NAME_TYPE);
+        return subjectAlts != null && !subjectAlts.isEmpty() ?
+                subjectAlts.toArray(new String[subjectAlts.size()]) : null;
+    }
+
+    /**
+     * Counts the number of dots "." in a string.
+     * @param s  string to count dots from
+     * @return  number of dots
+     */
+    public static int countDots(final String s) {
+        return DefaultHostnameVerifier.countDots(s);
     }
 
 }

Modified: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java?rev=1618698&r1=1618697&r2=1618698&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java (original)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java Mon Aug 18 18:39:33 2014
@@ -58,11 +58,6 @@ public class BrowserCompatHostnameVerifi
     }
 
     @Override
-    boolean validCountryWildcard(final String cn) {
-        return true;
-    }
-
-    @Override
     public final String toString() {
         return "BROWSER_COMPATIBLE";
     }

Added: 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=1618698&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java Mon Aug 18 18:39:33 2014
@@ -0,0 +1,296 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+
+import javax.naming.InvalidNameException;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.ldap.LdapName;
+import javax.naming.ldap.Rdn;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.annotation.Immutable;
+import org.apache.http.conn.util.InetAddressUtils;
+
+/**
+ * Default {@link javax.net.ssl.HostnameVerifier} implementation.
+ *
+ * @since 4.4
+ */
+@Immutable
+public final class DefaultHostnameVerifier implements HostnameVerifier {
+
+    public static final DefaultHostnameVerifier INSTANCE = new DefaultHostnameVerifier();
+
+    /**
+     * This contains a list of 2nd-level domains that aren't allowed to
+     * have wildcards when combined with country-codes.
+     * For example: [*.co.uk].
+     * <p/>
+     * The [*.co.uk] problem is an interesting one.  Should we just hope
+     * that CA's would never foolishly allow such a certificate to happen?
+     * Looks like we're the only implementation guarding against this.
+     * Firefox, Curl, Sun Java 1.4, 5, 6 don't bother with this check.
+     */
+    final static String[] BAD_COUNTRY_2LDS =
+          { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
+            "lg", "ne", "net", "or", "org" };
+
+    static {
+        // Just in case developer forgot to manually sort the array.  :-)
+        Arrays.sort(BAD_COUNTRY_2LDS);
+    }
+
+    final static int DNS_NAME_TYPE        = 2;
+    final static int IP_ADDRESS_TYPE      = 7;
+
+    private final Log log = LogFactory.getLog(getClass());
+
+    @Override
+    public final boolean verify(final String host, final SSLSession session) {
+        try {
+            final Certificate[] certs = session.getPeerCertificates();
+            final X509Certificate x509 = (X509Certificate) certs[0];
+            verify(host, x509);
+            return true;
+        } catch(final SSLException ex) {
+            if (log.isDebugEnabled()) {
+                log.debug(ex.getMessage(), ex);
+            }
+            return false;
+        }
+    }
+
+    public final void verify(
+            final String host, final X509Certificate cert) throws SSLException {
+        final boolean ipv4 = InetAddressUtils.isIPv4Address(host);
+        final boolean ipv6 = InetAddressUtils.isIPv6Address(host);
+        final int subjectType = ipv4 || ipv6 ? IP_ADDRESS_TYPE : DNS_NAME_TYPE;
+        final List<String> subjectAlts = extractSubjectAlts(cert, subjectType);
+        if (subjectAlts != null && !subjectAlts.isEmpty()) {
+            if (ipv4) {
+                matchIPAddress(host, subjectAlts);
+            } else if (ipv6) {
+                matchIPv6Address(host, subjectAlts);
+            } else {
+                matchDNSName(host, subjectAlts);
+            }
+        } else {
+            // CN matching has been deprecated by rfc2818 and can be used
+            // as fallback only when no subjectAlts are available
+            final X500Principal subjectPrincipal = cert.getSubjectX500Principal();
+            final String cn = extractCN(subjectPrincipal.getName(X500Principal.RFC2253));
+            matchCN(host, cn);
+        }
+    }
+
+    static void matchIPAddress(final String host, final List<String> subjectAlts) throws SSLException {
+        for (int i = 0; i < subjectAlts.size(); i++) {
+            final String subjectAlt = subjectAlts.get(i);
+            if (host.equals(subjectAlt)) {
+                return;
+            }
+        }
+        throw new SSLException("Certificate for <" + host + "> doesn't match any " +
+                "of the subject alternative names " + subjectAlts);
+    }
+
+    static void matchIPv6Address(final String host, final List<String> subjectAlts) throws SSLException {
+        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)) {
+                return;
+            }
+        }
+        throw new SSLException("Certificate for <" + host + "> doesn't match any " +
+                "of the subject alternative names " + subjectAlts);
+    }
+
+    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)) {
+                return;
+            }
+        }
+        throw new SSLException("Certificate for <" + host + "> doesn't match any " +
+                "of the subject alternative names " + subjectAlts);
+    }
+
+    static void matchCN(final String host, final String cn) throws SSLException {
+        if (!matchIdentity(host, cn)) {
+            throw new SSLException("Certificate for <" + host + "> doesn't match " +
+                    "common name of the certificate subject [" + cn + "]");
+        }
+    }
+
+    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);
+        }
+    }
+
+    static boolean matchIdentity(final String host, final String identity) {
+        return matchIdentity(host, identity, false);
+    }
+
+    static boolean matchIdentityStrict(final String host, final String identity) {
+        return matchIdentity(host, identity, true);
+    }
+
+    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;
+    }
+
+    static String extractCN(final String subjectPrincipal) throws SSLException {
+        if (subjectPrincipal == null) {
+            return null;
+        }
+        try {
+            final LdapName subjectDN = new LdapName(subjectPrincipal);
+            final List<Rdn> rdns = subjectDN.getRdns();
+            for (int i = rdns.size() - 1; i >= 0; i--) {
+                final Rdn rds = rdns.get(i);
+                final Attributes attributes = rds.toAttributes();
+                final Attribute cn = attributes.get("cn");
+                if (cn != null) {
+                    try {
+                        final Object value = cn.get();
+                        if (value != null) {
+                            return value.toString();
+                        }
+                    } catch (NoSuchElementException ignore) {
+                    } catch (NamingException ignore) {
+                    }
+                }
+            }
+            return null;
+        } catch (InvalidNameException e) {
+            throw new SSLException(subjectPrincipal + " is not a valid X500 distinguished name");
+        }
+    }
+
+    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) {
+        }
+        if (c != null) {
+            for (final List<?> aC : c) {
+                final List<?> list = aC;
+                final int type = ((Integer) list.get(0)).intValue();
+                if (type == subjectType) {
+                    final String s = (String) list.get(1);
+                    if (subjectAltList == null) {
+                        subjectAltList = new ArrayList<String>();
+                    }
+                    subjectAltList.add(s);
+                }
+            }
+        }
+        return subjectAltList;
+    }
+
+    /**
+     * Counts the number of dots "." in a string.
+     * @param s  string to count dots from
+     * @return  number of dots
+     */
+    static int countDots(final String s) {
+        int count = 0;
+        for(int i = 0; i < s.length(); i++) {
+            if(s.charAt(i) == '.') {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    /*
+     * Normalize IPv6 or DNS name.
+     */
+    static String normaliseAddress(final String hostname) {
+        if (hostname == null) {
+            return hostname;
+        }
+        try {
+            final InetAddress inetAddress = InetAddress.getByName(hostname);
+            return inetAddress.getHostAddress();
+        } catch (final UnknownHostException unexpected) { // Should not happen, because we check for IPv6 address above
+            return hostname;
+        }
+    }
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/main/java/org/apache/http/conn/ssl/DefaultHostnameVerifier.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 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=1618698&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java (added)
+++ httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java Mon Aug 18 18:39:33 2014
@@ -0,0 +1,62 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.SSLException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link org.apache.http.conn.ssl.DefaultHostnameVerifier}.
+ */
+public class TestDefaultHostnameVerifier {
+
+    @Test
+    public void testExtractCN() throws Exception {
+        Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=blah, ou=blah, o=blah"));
+        Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=blah, cn=yada, cn=booh"));
+        Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("c = pampa ,  cn  =    blah    , ou = blah , o = blah"));
+        Assert.assertEquals("blah", DefaultHostnameVerifier.extractCN("cn=\"blah\", ou=blah, o=blah"));
+        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, 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");
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: httpcomponents/httpclient/trunk/httpclient/src/test/java/org/apache/http/conn/ssl/TestDefaultHostnameVerifier.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

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=1618698&r1=1618697&r2=1618698&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 Mon Aug 18 18:39:33 2014
@@ -39,8 +39,9 @@ import org.junit.Assert;
 import org.junit.Test;
 
 /**
- * Unit tests for {@link X509HostnameVerifier}.
+ * Unit tests for deprecated {@link X509HostnameVerifier} implementations.
  */
+@Deprecated
 public class TestHostnameVerifier {
 
     @Test
@@ -288,7 +289,6 @@ public class TestHostnameVerifier {
 
         checkMatching(bhv, "s.a.gov.uk", cns, alt, false); // OK
         checkMatching(shv, "s.a.gov.uk", cns, alt, true); // Bad 2TLD/no subdomain allowed
-
         alt = new String []{"*.gov.com"};
         checkMatching(bhv, "a.gov.com", cns, alt, false); // OK, gov not 2TLD here
         checkMatching(shv, "a.gov.com", cns, alt, false); // OK, gov not 2TLD here
@@ -321,6 +321,7 @@ public class TestHostnameVerifier {
         // TODO need some more samples
     }
 
+
     @Test
     public void testHTTPCLIENT_1097() {
         String cns[];
@@ -347,26 +348,4 @@ public class TestHostnameVerifier {
         checkMatching(shv, "mail.a.b.c.com", cns, alt, false); // OK
     }
 
-    @Test
-    public void testExtractCN() throws Exception {
-        Assert.assertArrayEquals(new String[] {"blah"}, AbstractCommonHostnameVerifier.extractCNs("cn=blah, ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah", "yada", "booh"}, AbstractCommonHostnameVerifier.extractCNs("cn=blah, cn=yada, cn=booh"));
-        Assert.assertArrayEquals(new String[] {"blah"}, AbstractCommonHostnameVerifier.extractCNs("c = pampa ,  cn  =    blah    , ou = blah , o = blah"));
-        Assert.assertArrayEquals(new String[] {"blah"}, AbstractCommonHostnameVerifier.extractCNs("cn=\"blah\", ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah  blah"}, AbstractCommonHostnameVerifier.extractCNs("cn=\"blah  blah\", ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah, blah"}, AbstractCommonHostnameVerifier.extractCNs("cn=\"blah, blah\", ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah, blah"}, AbstractCommonHostnameVerifier.extractCNs("cn=blah\\, blah, ou=blah, o=blah"));
-        Assert.assertArrayEquals(new String[] {"blah"}, AbstractCommonHostnameVerifier.extractCNs("c = cn=uuh, cn=blah, ou=blah, o=blah"));
-    }
-
-    @Test(expected = SSLException.class)
-    public void testExtractCNMissing() throws Exception {
-        AbstractCommonHostnameVerifier.extractCNs("blah,blah");
-    }
-
-    @Test(expected = SSLException.class)
-    public void testExtractCNNull() throws Exception {
-        AbstractCommonHostnameVerifier.extractCNs("cn,o=blah");
-    }
-
 }