hc-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ol...@apache.org
Subject svn commit: r487346 - in /jakarta/httpcomponents/httpclient/trunk/src: java/org/apache/http/conn/ssl/ test/org/apache/http/conn/ssl/ test/org/apache/httpclient/
Date Thu, 14 Dec 2006 20:49:35 GMT
Author: olegk
Date: Thu Dec 14 12:49:34 2006
New Revision: 487346

URL: http://svn.apache.org/viewvc?view=rev&rev=487346
Log:
HTTPCLIENT-614: allow different strategies when checking CN of x509 cert

* Test coverage

Contributed by Julius Davies <juliusdavies at gmail.com>
Reviewed by Oleg Kalnichevski

Added:
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/HostnameVerifier.java   (with props)
    jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/
    jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/CertificatesToPlayWith.java   (with props)
    jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestAllSSL.java   (with props)
    jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestHostnameVerifier.java   (with props)
    jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestSSLSocketFactory.java   (with props)
Modified:
    jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/SSLSocketFactory.java
    jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/httpclient/TestAll.java

Added: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/HostnameVerifier.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/HostnameVerifier.java?view=auto&rev=487346
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/HostnameVerifier.java (added)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/HostnameVerifier.java Thu Dec 14 12:49:34 2006
@@ -0,0 +1,434 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Copyright 2002-2004 The Apache Software Foundation
+ *
+ *  Licensed 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 javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * Interface for checking if a hostname matches the names stored inside the
+ * server's X.509 certificate.  Implements javax.net.ssl.HostnameVerifier, but
+ * we don't actually use that interface.  Instead we added some methods that
+ * take String parameters (instead of javax.net.ssl.HostnameVerifier's
+ * SSLSession).  JUnit is a lot easier this way!  :-)
+ * <p/>
+ * We provide the HostnameVerifier.DEFAULT, HostnameVerifier.STRICT, and
+ * HostnameVerifier.ALLOW_ALL implementations.  But feel free to define
+ * your own implementation!
+ * <p/>
+ * Inspired by Sebastian Hauer's original StrictSSLProtocolSocketFactory in the
+ * HttpClient "contrib" repository.
+ *
+ * @author Julius Davies
+ * @author <a href="mailto:hauer@psicode.com">Sebastian Hauer</a>
+ * @since 8-Dec-2006
+ */
+public interface HostnameVerifier extends javax.net.ssl.HostnameVerifier {
+
+    boolean verify(String host, SSLSession session);
+
+    void verify(String host, SSLSocket ssl) throws IOException;
+
+    void verify(String host, X509Certificate cert) throws SSLException;
+
+    /**
+     * Checks to see if the supplied hostname matches any of the supplied CNs
+     * or "DNS" Subject-Alts.  Most implementations only look at the first CN,
+     * and ignore any additional CNs.  Most implementations do look at all of
+     * the "DNS" Subject-Alts. The CNs or Subject-Alts may contain wildcards
+     * according to RFC 2818.
+     *
+     * @param cns         CN fields, in order, as extracted from the X.509
+     *                    certificate.
+     * @param subjectAlts Subject-Alt fields of type 2 ("DNS"), as extracted
+     *                    from the X.509 certificate.
+     * @param host        The hostname to verify.
+     * @throws SSLException If verification failed.
+     */
+    void verify(String host, String[] cns, String[] subjectAlts)
+          throws SSLException;
+
+
+    /**
+     * The DEFAULT HostnameVerifier works the same way as Curl and Firefox.
+     * <p/>
+     * The hostname must match either the first CN, or any of the subject-alts.
+     * A wildcard can occur in the CN, and in any of the subject-alts.
+     * <p/>
+     * The only difference between DEFAULT and STRICT is that a wildcard (such
+     * as "*.foo.com") with DEFAULT matches all subdomains, including
+     * "a.b.foo.com".
+     */
+    public final static HostnameVerifier DEFAULT =
+          new AbstractVerifier() {
+              public final void verify(final String host, final String[] cns,
+                                       final String[] subjectAlts)
+                    throws SSLException {
+                  verify(host, cns, subjectAlts, false);
+              }
+
+              public final String toString() { return "DEFAULT"; }
+          };
+
+    /**
+     * The Strict HostnameVerifier works the same way as Sun Java 1.4, Sun
+     * Java 5, Sun Java 6-rc.  It's also pretty close to IE6.  This
+     * implementation appears to be compliant with RFC 2818 for dealing with
+     * wildcards.
+     * <p/>
+     * The hostname must match either the first CN, or any of the subject-alts.
+     * A wildcard can occur in the CN, and in any of the subject-alts.  The
+     * one divergence from IE6 is how we only check the first CN.  IE6 allows
+     * a match against any of the CNs present.  We decided to follow in
+     * Sun Java 1.4's footsteps and only check the first CN.  (If you need
+     * to check all the CN's, feel free to write your own implementation!).
+     * <p/>
+     * A wildcard such as "*.foo.com" matches only subdomains in the same
+     * level, for example "a.foo.com".  It does not match deeper subdomains
+     * such as "a.b.foo.com".
+     */
+    public final static HostnameVerifier STRICT =
+          new AbstractVerifier() {
+              public final void verify(final String host, final String[] cns,
+                                       final String[] subjectAlts)
+                    throws SSLException {
+                  verify(host, cns, subjectAlts, true);
+              }
+
+              public final String toString() { return "STRICT"; }
+          };
+
+    /**
+     * The ALLOW_ALL HostnameVerifier essentially turns hostname verification
+     * off.  This implementation is a no-op, and never throws the SSLException.
+     */
+    public final static HostnameVerifier ALLOW_ALL =
+          new AbstractVerifier() {
+              public final void verify(final String host, final String[] cns,
+                                       final String[] subjectAlts) {
+                  // Allow everything - so never blowup.
+              }
+
+              public final String toString() { return "ALLOW_ALL"; }
+          };
+
+    abstract class AbstractVerifier implements HostnameVerifier {
+
+        /**
+         * 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.
+         */
+        private 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);
+        }
+
+        AbstractVerifier() {}
+
+        public final void verify(String host, SSLSocket ssl)
+              throws IOException {
+            if(host == null) {
+                throw new NullPointerException("host to verify is null");
+            }
+
+            SSLSession session = ssl.getSession();
+            if(session == null) {
+                // In our experience this only happens under IBM 1.4.x when
+                // spurious (unrelated) certificates show up in the server'
+                // chain.  Hopefully this will unearth the real problem:
+                InputStream in = ssl.getInputStream();
+                in.available();
+                /*
+                  If you're looking at the 2 lines of code above because
+                  you're running into a problem, you probably have two
+                  options:
+
+                    #1.  Clean up the certificate chain that your server
+                         is presenting (e.g. edit "/etc/apache2/server.crt"
+                         or wherever it is your server's certificate chain
+                         is defined).
+
+                                               OR
+
+                    #2.   Upgrade to an IBM 1.5.x or greater JVM, or switch
+                          to a non-IBM JVM.
+                */
+
+                // If ssl.getInputStream().available() didn't cause an
+                // exception, maybe at least now the session is available?
+                session = ssl.getSession();
+                if(session == null) {
+                    // If it's still null, probably a startHandshake() will
+                    // unearth the real problem.
+                    ssl.startHandshake();
+
+                    // Okay, if we still haven't managed to cause an exception,
+                    // might as well go for the NPE.  Or maybe we're okay now?
+                    session = ssl.getSession();
+                }
+            }
+
+            Certificate[] certs = session.getPeerCertificates();
+            X509Certificate x509 = (X509Certificate) certs[0];
+            verify(host, x509);
+        }
+
+        public final boolean verify(String host, SSLSession session) {
+            try {
+                Certificate[] certs = session.getPeerCertificates();
+                X509Certificate x509 = (X509Certificate) certs[0];
+                verify(host, x509);
+                return true;
+            }
+            catch(SSLException e) {
+                return false;
+            }
+        }
+
+        public final void verify(String host, X509Certificate cert)
+              throws SSLException {
+            String[] cns = getCNs(cert);
+            String[] subjectAlts = getDNSSubjectAlts(cert);
+            verify(host, cns, subjectAlts);
+        }
+
+        public final void verify(final String host, final String[] cns,
+                                 final String[] subjectAlts,
+                                 final boolean strictWithSubDomains)
+              throws SSLException {
+
+            // Build the list of names we're going to check.  Our DEFAULT and
+            // STRICT implementations of the HostnameVerifier only use the
+            // first CN provided.  All other CNs are ignored.
+            // (Firefox, wget, curl, Sun Java 1.4, 5, 6 all work this way).
+            LinkedList names = new LinkedList();
+            if(cns != null && cns.length > 0 && cns[0] != null) {
+                names.add(cns[0]);
+            }
+            if(subjectAlts != null) {
+                for(int i = 0; i < subjectAlts.length; i++) {
+                    if(subjectAlts[i] != null) {
+                        names.add(subjectAlts[i]);
+                    }
+                }
+            }
+
+            if(names.isEmpty()) {
+                String msg = "Certificate for <" + host + "> doesn't contain CN or DNS subjectAlt";
+                throw new SSLException(msg);
+            }
+
+            // StringBuffer for building the error message.
+            StringBuffer buf = new StringBuffer();
+
+            // We're can be case-insensitive when comparing the host we used to
+            // establish the socket to the hostname in the certificate.
+            String hostName = host.trim().toLowerCase();
+            boolean match = false;
+            for(Iterator it = names.iterator(); it.hasNext();) {
+                // Don't trim the CN, though!
+                String cn = (String) it.next();
+                cn = cn.toLowerCase();
+                // Store CN in StringBuffer in case we need to report an error.
+                buf.append(" <");
+                buf.append(cn);
+                buf.append('>');
+                if(it.hasNext()) {
+                    buf.append(" OR");
+                }
+
+                // 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...
+                boolean doWildcard = cn.startsWith("*.") &&
+                                     cn.lastIndexOf('.') >= 0 &&
+                                     acceptableCountryWildcard(cn);
+
+                if(doWildcard) {
+                    match = hostName.endsWith(cn.substring(1));
+                    if(match && strictWithSubDomains) {
+                        // If we're in strict mode, then [*.foo.com] is not
+                        // allowed to match [a.b.foo.com]
+                        match = countDots(hostName) == countDots(cn);
+                    }
+                } else {
+                    match = hostName.equals(cn);
+                }
+                if(match) {
+                    break;
+                }
+            }
+            if(!match) {
+                throw new SSLException("hostname in certificate didn't match: <" + host + "> !=" + buf);
+            }
+        }
+
+        public static boolean acceptableCountryWildcard(String cn) {
+            int cnLen = cn.length();
+            if(cnLen >= 7 && cnLen <= 9) {
+                // Look for the '.' in the 3rd-last position:
+                if(cn.charAt(cnLen - 3) == '.') {
+                    // Trim off the [*.] and the [.XX].
+                    String s = cn.substring(2, cnLen - 3);
+                    // And test against the sorted array of bad 2lds:
+                    int x = Arrays.binarySearch(BAD_COUNTRY_2LDS, s);
+                    return x < 0;
+                }
+            }
+            return true;
+        }
+
+        public static String[] getCNs(X509Certificate cert) {
+            LinkedList cnList = new LinkedList();
+            /*
+              Sebastian Hauer's original StrictSSLProtocolSocketFactory used
+              getName() and had the following comment:
+
+                    Parses a X.500 distinguished name for the value of the
+                    "Common Name" field.  This is done a bit sloppy right
+                     now and should probably be done a bit more according to
+                    <code>RFC 2253</code>.
+
+               I've noticed that toString() seems to do a better job than
+               getName() on these X500Principal objects, so I'm hoping that
+               addresses Sebastian's concern.
+
+               For example, getName() gives me this:
+               1.2.840.113549.1.9.1=#16166a756c6975736461766965734063756362632e636f6d
+
+               whereas toString() gives me this:
+               EMAILADDRESS=juliusdavies@cucbc.com
+
+               Looks like toString() even works with non-ascii domain names!
+               I tested it with "&#x82b1;&#x5b50;.co.jp" and it worked fine.
+            */
+            String subjectPrincipal = cert.getSubjectX500Principal().toString();
+            StringTokenizer st = new StringTokenizer(subjectPrincipal, ",");
+            while(st.hasMoreTokens()) {
+                String tok = st.nextToken();
+                int x = tok.indexOf("CN=");
+                if(x >= 0) {
+                    cnList.add(tok.substring(x + 3));
+                }
+            }
+            if(!cnList.isEmpty()) {
+                String[] cns = new String[cnList.size()];
+                cnList.toArray(cns);
+                return cns;
+            } else {
+                return null;
+            }
+        }
+
+
+        /**
+         * Extracts the array of SubjectAlt DNS names from an X509Certificate.
+         * Returns null if there aren't any.
+         * <p/>
+         * Note:  Java doesn't appear able to extract international characters
+         * from the SubjectAlts.  It can only extract international characters
+         * from the CN field.
+         * <p/>
+         * (Or maybe the version of OpenSSL I'm using to test isn't storing the
+         * international characters correctly in the SubjectAlts?).
+         *
+         * @param cert X509Certificate
+         * @return Array of SubjectALT DNS names stored in the certificate.
+         */
+        public static String[] getDNSSubjectAlts(X509Certificate cert) {
+            LinkedList subjectAltList = new LinkedList();
+            Collection c = null;
+            try {
+                c = cert.getSubjectAlternativeNames();
+            }
+            catch(CertificateParsingException cpe) {
+                // Should probably log.debug() this?
+                cpe.printStackTrace();
+            }
+            if(c != null) {
+                Iterator it = c.iterator();
+                while(it.hasNext()) {
+                    List list = (List) it.next();
+                    int type = ((Integer) list.get(0)).intValue();
+                    // If type is 2, then we've got a dNSName
+                    if(type == 2) {
+                        String s = (String) list.get(1);
+                        subjectAltList.add(s);
+                    }
+                }
+            }
+            if(!subjectAltList.isEmpty()) {
+                String[] subjectAlts = new String[subjectAltList.size()];
+                subjectAltList.toArray(subjectAlts);
+                return subjectAlts;
+            } else {
+                return 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) {
+            int count = 0;
+            for(int i = 0; i < s.length(); i++) {
+                if(s.charAt(i) == '.') {
+                    count++;
+                }
+            }
+            return count;
+        }
+    }
+
+}

Propchange: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/HostnameVerifier.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

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

Modified: jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/SSLSocketFactory.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/SSLSocketFactory.java?view=diff&rev=487346&r1=487345&r2=487346
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/SSLSocketFactory.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/java/org/apache/http/conn/ssl/SSLSocketFactory.java Thu Dec 14 12:49:34 2006
@@ -34,16 +34,14 @@
 import org.apache.http.params.HttpConnectionParams;
 import org.apache.http.params.HttpParams;
 
+import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
@@ -54,8 +52,6 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
 
 /**
  * <p>
@@ -156,6 +152,7 @@
     
     private final SSLContext sslcontext;
     private final javax.net.ssl.SSLSocketFactory socketfactory;
+    private HostnameVerifier hostnameVerifier = HostnameVerifier.DEFAULT;
 
     public SSLSocketFactory(
         String algorithm, 
@@ -206,8 +203,7 @@
     public SSLSocketFactory() {
         super();
         this.sslcontext = null;
-        this.socketfactory = (javax.net.ssl.SSLSocketFactory) 
-            javax.net.ssl.SSLSocketFactory.getDefault(); 
+        this.socketfactory = HttpsURLConnection.getDefaultSSLSocketFactory();
     }
 
     private static KeyManager[] createKeyManagers(final KeyStore keystore, final String password)
@@ -261,155 +257,47 @@
         if (params == null) {
             throw new IllegalArgumentException("Parameters may not be null");
         }
-        SSLSocket socket = (SSLSocket) this.socketfactory.createSocket();
+        SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket();
         if (localAddress != null) {
-            socket.bind(new InetSocketAddress(localAddress, localPort));
+            sslSocket.bind(new InetSocketAddress(localAddress, localPort));
         }
         int timeout = HttpConnectionParams.getConnectionTimeout(params);
-        socket.connect(new InetSocketAddress(host, port), timeout);
-
-        verifyHostName( host, (SSLSocket) socket );
-
+        sslSocket.connect(new InetSocketAddress(host, port), timeout);
+        hostnameVerifier.verify(host, sslSocket);
         // verifyHostName() didn't blowup - good!
-
-        return socket;
+        return sslSocket;
     }
 
     /**
      * @see SecureSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
      */
     public Socket createSocket(
-        Socket socket,
-        String host,
-        int port,
-        boolean autoClose)
-        throws IOException, UnknownHostException {        
-        SSLSocket s = (SSLSocket) this.socketfactory.createSocket(
-            socket,
-            host,
-            port,
-            autoClose
+        final Socket socket,
+        final String host,
+        final int port,
+        final boolean autoClose
+    ) throws IOException, UnknownHostException {
+        SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
+              socket,
+              host,
+              port,
+              autoClose
         );
-
-        verifyHostName( host, (SSLSocket) socket );
-
+        hostnameVerifier.verify(host, sslSocket);
         // verifyHostName() didn't blowup - good!
-        return s;
+        return sslSocket;
     }
 
-    private static void verifyHostName( String host, SSLSocket ssl )
-          throws IOException {
-        if ( host == null ) {
-            throw new NullPointerException( "host to verify was null" );
-        }
-
-        SSLSession session = ssl.getSession();
-        if ( session == null ) {
-            // In our experience this only happens under IBM 1.4.x when
-            // spurious (unrelated) certificates show up in the server's chain.
-            // Hopefully this will unearth the real problem:
-            InputStream in = ssl.getInputStream();
-            in.available();
-            /*
-               If you're looking at the 2 lines of code above because you're
-               running into a problem, you probably have two options:
-
-                  #1.  Clean up the certificate chain that your server
-                       is presenting (e.g. edit "/etc/apache2/server.crt" or
-                       wherever it is your server's certificate chain is
-                       defined).
-
-                                           OR
-
-                  #2.   Upgrade to an IBM 1.5.x or greater JVM, or switch to a
-                        non-IBM JVM.
-            */
-
-            // If ssl.getInputStream().available() didn't cause an exception,
-            // maybe at least now the session is available?
-            session = ssl.getSession();            
-            if ( session == null ) {
-                // If it's still null, probably a startHandshake() will
-                // unearth the real problem.
-                ssl.startHandshake();
-
-                // Okay, if we still haven't managed to cause an exception,
-                // might as well go for the NPE.  Or maybe we're okay now?
-                session = ssl.getSession();
-            }
-        }
-
-        Certificate[] certs = session.getPeerCertificates();
-        X509Certificate x509 = (X509Certificate) certs[ 0 ]; 
-        String cn = getCN( x509 );
-        if ( cn == null ) {
-            String subject = x509.getSubjectX500Principal().toString();
-            String msg = "certificate doesn't contain CN: " + subject;
-            throw new SSLException( msg );
-        }
-        // I'm okay with being case-insensitive when comparing the host we used
-        // to establish the socket to the hostname in the certificate.
-        // Don't trim the CN, though.
-        cn = cn.toLowerCase();
-        host = host.trim().toLowerCase();
-        boolean doWildcard = false;
-        if ( cn.startsWith( "*." ) ) {
-            // The CN better have at least two dots if it wants wildcard action,
-            // but can't be [*.co.uk] or [*.co.jp] or [*.org.uk], etc...
-            String withoutCountryCode = "";
-            if ( cn.length() >= 7 && cn.length() <= 9 ) {
-                withoutCountryCode = cn.substring( 2, cn.length() - 2 );
-            }
-            doWildcard = cn.lastIndexOf( '.' ) >= 0 &&
-                         !"ac.".equals( withoutCountryCode ) &&
-                         !"co.".equals( withoutCountryCode ) &&
-                         !"com.".equals( withoutCountryCode ) &&
-                         !"ed.".equals( withoutCountryCode ) &&
-                         !"edu.".equals( withoutCountryCode ) &&
-                         !"go.".equals( withoutCountryCode ) &&
-                         !"gouv.".equals( withoutCountryCode ) &&
-                         !"gov.".equals( withoutCountryCode ) &&
-                         !"info.".equals( withoutCountryCode ) &&                         
-                         !"lg.".equals( withoutCountryCode ) &&
-                         !"ne.".equals( withoutCountryCode ) &&
-                         !"net.".equals( withoutCountryCode ) &&
-                         !"or.".equals( withoutCountryCode ) &&
-                         !"org.".equals( withoutCountryCode );
-
-            // The [*.co.uk] problem is an interesting one.  Should we just
-            // hope that CA's would never foolishly allow such a
-            // certificate to happen?
-        }
-
-        boolean match;
-        if ( doWildcard ) {
-            match = host.endsWith( cn.substring( 1 ) );
+    public void setHostnameVerifier(HostnameVerifier hostnameVerifier) {
+        if ( hostnameVerifier == null ) {
+            this.hostnameVerifier = HostnameVerifier.DEFAULT;
         } else {
-            match = host.equals( cn );
-        }
-        if ( !match ) {
-            throw new SSLException( "hostname in certificate didn't match: <" + host + "> != <" + cn + ">" );
+            this.hostnameVerifier = hostnameVerifier;
         }
     }
 
-    private static String getCN( X509Certificate cert ) {
-        // Note:  toString() seems to do a better job than getName()
-        //
-        // For example, getName() gives me this:
-        // 1.2.840.113549.1.9.1=#16166a756c6975736461766965734063756362632e636f6d
-        //
-        // whereas toString() gives me this:
-        // EMAILADDRESS=juliusdavies@cucbc.com        
-        String subjectPrincipal = cert.getSubjectX500Principal().toString();
-        int x = subjectPrincipal.indexOf( "CN=" );
-        if ( x >= 0 ) {
-            int y = subjectPrincipal.indexOf( ',', x );
-            // If there are no more commas, then CN= is the last entry.
-            y = ( y >= 0 ) ? y : subjectPrincipal.length();
-            return subjectPrincipal.substring( x + 3, y );
-        } else {
-            return null;
-        }
+    public HostnameVerifier getHostnameVerifier() {
+        return hostnameVerifier;
     }
-    
+
 }

Added: jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/CertificatesToPlayWith.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/CertificatesToPlayWith.java?view=auto&rev=487346
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/CertificatesToPlayWith.java (added)
+++ jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/CertificatesToPlayWith.java Thu Dec 14 12:49:34 2006
@@ -0,0 +1,451 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Copyright 1999-2006 The Apache Software Foundation
+ *
+ *  Licensed 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;
+
+/**
+ * Some X509 certificates to test against.
+ * <p/>
+ * Note:  some of these certificates have Japanese Kanji in the "subjectAlt"
+ * field (UTF8).  Not sure how realistic that is since international characters
+ * in DNS names usually get translated into ASCII using "xn--" style DNS
+ * entries.  "xn--i8s592g.co.jp" is what FireFox actually uses when trying to
+ * find &#x82b1;&#x5b50;.co.jp.  So would the CN in the certificate contain
+ * "xn--i8s592g.co.jp" in ASCII, or "&#x82b1;&#x5b50;.co.jp" in UTF8?  (Both?)
+ *
+ * @author Julius Davies
+ * @since 11-Dec-2006
+ */
+public interface CertificatesToPlayWith {
+
+    /**
+     * CN=foo.com
+     */
+    public final static byte[] X509_FOO = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aQMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n" +
+          "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n" +
+          "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzE0MVoXDTI4MTEwNTE1MzE0MVowgaQx\n" +
+          "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n" +
+          "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n" +
+          "cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs\n" +
+          "aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
+          "ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B\n" +
+          "lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy\n" +
+          "zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY\n" +
+          "07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8\n" +
+          "BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV\n" +
+          "JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB\n" +
+          "hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE\n" +
+          "FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS\n" +
+          "yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQC3jRmEya6sQCkmieULcvx8zz1euCk9\n" +
+          "fSez7BEtki8+dmfMXe3K7sH0lI8f4jJR0rbSCjpmCQLYmzC3NxBKeJOW0RcjNBpO\n" +
+          "c2JlGO9auXv2GDP4IYiXElLJ6VSqc8WvDikv0JmCCWm0Zga+bZbR/EWN5DeEtFdF\n" +
+          "815CLpJZNcYwiYwGy/CVQ7w2TnXlG+mraZOz+owr+cL6J/ZesbdEWfjoS1+cUEhE\n" +
+          "HwlNrAu8jlZ2UqSgskSWlhYdMTAP9CPHiUv9N7FcT58Itv/I4fKREINQYjDpvQcx\n" +
+          "SaTYb9dr5sB4WLNglk7zxDtM80H518VvihTcP7FHL+Gn6g4j5fkI98+S\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * CN=&#x82b1;&#x5b50;.co.jp
+     */
+    public final static byte[] X509_HANAKO = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIESzCCAzOgAwIBAgIJAIz+EYMBU6aTMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n" +
+          "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n" +
+          "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1NDIxNVoXDTI4MTEwNTE1NDIxNVowgakx\n" +
+          "CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0\n" +
+          "IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl\n" +
+          "cnRpZmljYXRlczEVMBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkB\n" +
+          "FhZqdWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
+          "MIIBCgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjU\n" +
+          "g4pNjYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQc\n" +
+          "wHf0ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t\n" +
+          "7iu1JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAn\n" +
+          "AxK6q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArD\n" +
+          "qUYxqJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwG\n" +
+          "CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV\n" +
+          "HQ4EFgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLS\n" +
+          "rNuzA1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBALJ27i3okV/KvlDp6KMID3gd\n" +
+          "ITl68PyItzzx+SquF8gahMh016NX73z/oVZoVUNdftla8wPUB1GwIkAnGkhQ9LHK\n" +
+          "spBdbRiCj0gMmLCsX8SrjFvr7cYb2cK6J/fJe92l1tg/7Y4o7V/s4JBe/cy9U9w8\n" +
+          "a0ctuDmEBCgC784JMDtT67klRfr/2LlqWhlOEq7pUFxRLbhpquaAHSOjmIcWnVpw\n" +
+          "9BsO7qe46hidgn39hKh1WjKK2VcL/3YRsC4wUi0PBtFW6ScMCuMhgIRXSPU55Rae\n" +
+          "UIlOdPjjr1SUNWGId1rD7W16Scpwnknn310FNxFMHVI0GTGFkNdkilNCFJcIoRA=\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * CN=foo.com, subjectAlt=bar.com
+     */
+    public final static byte[] X509_FOO_BAR = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIEXDCCA0SgAwIBAgIJAIz+EYMBU6aRMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n" +
+          "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n" +
+          "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzYyOVoXDTI4MTEwNTE1MzYyOVowgaQx\n" +
+          "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n" +
+          "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n" +
+          "cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs\n" +
+          "aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
+          "ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B\n" +
+          "lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy\n" +
+          "zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY\n" +
+          "07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8\n" +
+          "BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV\n" +
+          "JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCG\n" +
+          "SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E\n" +
+          "FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz\n" +
+          "A1LKh6YNPg0wEgYDVR0RBAswCYIHYmFyLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEA\n" +
+          "dQyprNZBmVnvuVWjV42sey/PTfkYShJwy1j0/jcFZR/ypZUovpiHGDO1DgL3Y3IP\n" +
+          "zVQ26uhUsSw6G0gGRiaBDe/0LUclXZoJzXX1qpS55OadxW73brziS0sxRgGrZE/d\n" +
+          "3g5kkio6IED47OP6wYnlmZ7EKP9cqjWwlnvHnnUcZ2SscoLNYs9rN9ccp8tuq2by\n" +
+          "88OyhKwGjJfhOudqfTNZcDzRHx4Fzm7UsVaycVw4uDmhEHJrAsmMPpj/+XRK9/42\n" +
+          "2xq+8bc6HojdtbCyug/fvBZvZqQXSmU8m8IVcMmWMz0ZQO8ee3QkBHMZfCy7P/kr\n" +
+          "VbWx/uETImUu+NZg22ewEw==\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * CN=foo.com, subjectAlt=bar.com, subjectAlt=&#x82b1;&#x5b50;.co.jp
+     * (hanako.co.jp in kanji)
+     */
+    public final static byte[] X509_FOO_BAR_HANAKO = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIEajCCA1KgAwIBAgIJAIz+EYMBU6aSMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n" +
+          "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n" +
+          "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzgxM1oXDTI4MTEwNTE1MzgxM1owgaQx\n" +
+          "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n" +
+          "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n" +
+          "cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs\n" +
+          "aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
+          "ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B\n" +
+          "lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy\n" +
+          "zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY\n" +
+          "07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8\n" +
+          "BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV\n" +
+          "JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBnjCBmzAJBgNVHRMEAjAAMCwGCWCG\n" +
+          "SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E\n" +
+          "FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz\n" +
+          "A1LKh6YNPg0wIAYDVR0RBBkwF4IHYmFyLmNvbYIM6Iqx5a2QLmNvLmpwMA0GCSqG\n" +
+          "SIb3DQEBBQUAA4IBAQBeZs7ZIYyKtdnVxVvdLgwySEPOE4pBSXii7XYv0Q9QUvG/\n" +
+          "++gFGQh89HhABzA1mVUjH5dJTQqSLFvRfqTHqLpxSxSWqMHnvRM4cPBkIRp/XlMK\n" +
+          "PlXadYtJLPTgpbgvulA1ickC9EwlNYWnowZ4uxnfsMghW4HskBqaV+PnQ8Zvy3L0\n" +
+          "12c7Cg4mKKS5pb1HdRuiD2opZ+Hc77gRQLvtWNS8jQvd/iTbh6fuvTKfAOFoXw22\n" +
+          "sWIKHYrmhCIRshUNohGXv50m2o+1w9oWmQ6Dkq7lCjfXfUB4wIbggJjpyEtbNqBt\n" +
+          "j4MC2x5rfsLKKqToKmNE7pFEgqwe8//Aar1b+Qj+\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * CN=*.foo.com
+     */
+    public final static byte[] X509_WILD_FOO = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIESDCCAzCgAwIBAgIJAIz+EYMBU6aUMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n" +
+          "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n" +
+          "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTU1NVoXDTI4MTEwNTE2MTU1NVowgaYx\n" +
+          "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n" +
+          "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n" +
+          "cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq\n" +
+          "dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +
+          "CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN\n" +
+          "jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0\n" +
+          "ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1\n" +
+          "JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6\n" +
+          "q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx\n" +
+          "qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG\n" +
+          "SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E\n" +
+          "FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz\n" +
+          "A1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBAH0ipG6J561UKUfgkeW7GvYwW98B\n" +
+          "N1ZooWX+JEEZK7+Pf/96d3Ij0rw9ACfN4bpfnCq0VUNZVSYB+GthQ2zYuz7tf/UY\n" +
+          "A6nxVgR/IjG69BmsBl92uFO7JTNtHztuiPqBn59pt+vNx4yPvno7zmxsfI7jv0ww\n" +
+          "yfs+0FNm7FwdsC1k47GBSOaGw38kuIVWqXSAbL4EX9GkryGGOKGNh0qvAENCdRSB\n" +
+          "G9Z6tyMbmfRY+dLSh3a9JwoEcBUso6EWYBakLbq4nG/nvYdYvG9ehrnLVwZFL82e\n" +
+          "l3Q/RK95bnA6cuRClGusLad0e6bjkBzx/VQ3VarDEpAkTLUGVAa0CLXtnyc=\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * CN=*.co.jp
+     */
+    public final static byte[] X509_WILD_CO_JP = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aVMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n" +
+          "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n" +
+          "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTYzMFoXDTI4MTEwNTE2MTYzMFowgaQx\n" +
+          "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n" +
+          "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n" +
+          "cnRpZmljYXRlczEQMA4GA1UEAxQHKi5jby5qcDElMCMGCSqGSIb3DQEJARYWanVs\n" +
+          "aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" +
+          "ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B\n" +
+          "lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy\n" +
+          "zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY\n" +
+          "07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8\n" +
+          "BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV\n" +
+          "JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB\n" +
+          "hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE\n" +
+          "FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS\n" +
+          "yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQA0sWglVlMx2zNGvUqFC73XtREwii53\n" +
+          "CfMM6mtf2+f3k/d8KXhLNySrg8RRlN11zgmpPaLtbdTLrmG4UdAHHYr8O4y2BBmE\n" +
+          "1cxNfGxxechgF8HX10QV4dkyzp6Z1cfwvCeMrT5G/V1pejago0ayXx+GPLbWlNeZ\n" +
+          "S+Kl0m3p+QplXujtwG5fYcIpaGpiYraBLx3Tadih39QN65CnAh/zRDhLCUzKyt9l\n" +
+          "UGPLEUDzRHMPHLnSqT1n5UU5UDRytbjJPXzF+l/+WZIsanefWLsxnkgAuZe/oMMF\n" +
+          "EJMryEzOjg4Tfuc5qM0EXoPcQ/JlheaxZ40p2IyHqbsWV4MRYuFH4bkM\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * CN=*.foo.com, subjectAlt=*.bar.com, subjectAlt=*.&#x82b1;&#x5b50;.co.jp
+     * (*.hanako.co.jp in kanji)
+     */
+    public final static byte[] X509_WILD_FOO_BAR_HANAKO = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIEcDCCA1igAwIBAgIJAIz+EYMBU6aWMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n" +
+          "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n" +
+          "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTczMVoXDTI4MTEwNTE2MTczMVowgaYx\n" +
+          "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0\n" +
+          "IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl\n" +
+          "cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq\n" +
+          "dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +
+          "CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN\n" +
+          "jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0\n" +
+          "ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1\n" +
+          "JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6\n" +
+          "q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx\n" +
+          "qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo4GiMIGfMAkGA1UdEwQCMAAwLAYJ\n" +
+          "YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1Ud\n" +
+          "DgQWBBSfFHe/Pzq2yjiCQkgWLNrQy16H2DAfBgNVHSMEGDAWgBR7mtqPkJlOUtKs\n" +
+          "27MDUsqHpg0+DTAkBgNVHREEHTAbggkqLmJhci5jb22CDiou6Iqx5a2QLmNvLmpw\n" +
+          "MA0GCSqGSIb3DQEBBQUAA4IBAQBobWC+D5/lx6YhX64CwZ26XLjxaE0S415ajbBq\n" +
+          "DK7lz+Rg7zOE3GsTAMi+ldUYnhyz0wDiXB8UwKXl0SDToB2Z4GOgqQjAqoMmrP0u\n" +
+          "WB6Y6dpkfd1qDRUzI120zPYgSdsXjHW9q2H77iV238hqIU7qCvEz+lfqqWEY504z\n" +
+          "hYNlknbUnR525ItosEVwXFBJTkZ3Yw8gg02c19yi8TAh5Li3Ad8XQmmSJMWBV4XK\n" +
+          "qFr0AIZKBlg6NZZFf/0dP9zcKhzSriW27bY0XfzA6GSiRDXrDjgXq6baRT6YwgIg\n" +
+          "pgJsDbJtZfHnV1nd3M6zOtQPm1TIQpNmMMMd/DPrGcUQerD3\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * CN=foo.com, CN=bar.com, CN=&#x82b1;&#x5b50;.co.jp
+     */
+    public final static byte[] X509_THREE_CNS_FOO_BAR_HANAKO = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIEbzCCA1egAwIBAgIJAIz+EYMBU6aXMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n" +
+          "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n" +
+          "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTk0NVoXDTI4MTEwNTE2MTk0NVowgc0x\n" +
+          "CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0\n" +
+          "IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl\n" +
+          "cnRpZmljYXRlczEQMA4GA1UEAwwHZm9vLmNvbTEQMA4GA1UEAwwHYmFyLmNvbTEV\n" +
+          "MBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyGOv\n" +
+          "loI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pNjYGViGjg7zhf\n" +
+          "bjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0ZHLN6sD9m2uV\n" +
+          "Sp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1JVjTuE0pcBva\n" +
+          "h2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6q/wGqcZ3zvFB\n" +
+          "TcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYxqJUlPGlMqrKb\n" +
+          "3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf\n" +
+          "Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86\n" +
+          "tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0w\n" +
+          "DQYJKoZIhvcNAQEFBQADggEBAGuZb8ai1NO2j4v3y9TLZvd5s0vh5/TE7n7RX+8U\n" +
+          "y37OL5k7x9nt0mM1TyAKxlCcY+9h6frue8MemZIILSIvMrtzccqNz0V1WKgA+Orf\n" +
+          "uUrabmn+CxHF5gpy6g1Qs2IjVYWA5f7FROn/J+Ad8gJYc1azOWCLQqSyfpNRLSvY\n" +
+          "EriQFEV63XvkJ8JrG62b+2OT2lqT4OO07gSPetppdlSa8NBSKP6Aro9RIX1ZjUZQ\n" +
+          "SpQFCfo02NO0uNRDPUdJx2huycdNb+AXHaO7eXevDLJ+QnqImIzxWiY6zLOdzjjI\n" +
+          "VBMkLHmnP7SjGSQ3XA4ByrQOxfOUTyLyE7NuemhHppuQPxE=\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * subjectAlt=foo.com
+     */
+    public final static byte[] X509_NO_CNS_FOO = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIESjCCAzKgAwIBAgIJAIz+EYMBU6aYMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE\n" +
+          "ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU\n" +
+          "FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp\n" +
+          "ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MjYxMFoXDTI4MTEwNTE2MjYxMFowgZIx\n" +
+          "CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0\n" +
+          "IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl\n" +
+          "cnRpZmljYXRlczElMCMGCSqGSIb3DQEJARYWanVsaXVzZGF2aWVzQGdtYWlsLmNv\n" +
+          "bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhjr5aCPoyp0R1iroWA\n" +
+          "fnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2BlYho4O84X244QrZTRl8kQbYt\n" +
+          "xnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRyzerA/ZtrlUqf+lKo0uWcocxe\n" +
+          "Rc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY07hNKXAb2odnVqgzcYiDkLV8\n" +
+          "ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8BqnGd87xQU3FVZI4tbtkB+Kz\n" +
+          "jD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiVJTxpTKqym93whYk93l3ocEe5\n" +
+          "5c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM\n" +
+          "IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86tso4gkJIFiza\n" +
+          "0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0wEgYDVR0RBAsw\n" +
+          "CYIHZm9vLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAjl78oMjzFdsMy6F1sGg/IkO8\n" +
+          "tF5yUgPgFYrs41yzAca7IQu6G9qtFDJz/7ehh/9HoG+oqCCIHPuIOmS7Sd0wnkyJ\n" +
+          "Y7Y04jVXIb3a6f6AgBkEFP1nOT0z6kjT7vkA5LJ2y3MiDcXuRNMSta5PYVnrX8aZ\n" +
+          "yiqVUNi40peuZ2R8mAUSBvWgD7z2qWhF8YgDb7wWaFjg53I36vWKn90ZEti3wNCw\n" +
+          "qAVqixM+J0qJmQStgAc53i2aTMvAQu3A3snvH/PHTBo+5UL72n9S1kZyNCsVf1Qo\n" +
+          "n8jKTiRriEM+fMFlcgQP284EBFzYHyCXFb9O/hMjK2+6mY9euMB1U1aFFzM/Bg==\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * Intermediate CA for all of these.
+     */
+    public final static byte[] X509_INTERMEDIATE_CA = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIEnDCCA4SgAwIBAgIJAJTNwZ6yNa5cMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxFjAUBgNVBAoTDXd3dy5jdWNiYy5jb20xFDAS\n" +
+          "BgNVBAsUC2NvbW1vbnNfc3NsMRUwEwYDVQQDFAxkZW1vX3Jvb3RfY2ExJTAjBgkq\n" +
+          "hkiG9w0BCQEWFmp1bGl1c2Rhdmllc0BnbWFpbC5jb20wHhcNMDYxMTA1MjE0OTMx\n" +
+          "WhcNMDcxMTA1MjE0OTMxWjCBojELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAkJDMRIw\n" +
+          "EAYDVQQHEwlWYW5jb3V2ZXIxFjAUBgNVBAoTDXd3dy5jdWNiYy5jb20xFDASBgNV\n" +
+          "BAsUC2NvbW1vbnNfc3NsMR0wGwYDVQQDFBRkZW1vX2ludGVybWVkaWF0ZV9jYTEl\n" +
+          "MCMGCSqGSIb3DQEJARYWanVsaXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZI\n" +
+          "hvcNAQEBBQADggEPADCCAQoCggEBAL0S4y3vUO0EM6lwqOEfK8fvrUprIbsikXaG\n" +
+          "XzejcZ+T3l2Dc7t8WtBfRf78i4JypMqJQSijrUicj3H6mOMIReKaXm6ls4hA5d8w\n" +
+          "Lhmgiqsz/kW+gA8SeWGWRN683BD/RbQmzOls6ynBvap9jZlthXWBrSIlPCQoBLXY\n" +
+          "KVaxGzbL4ezaq+XFMKMQSm2uKwVmHHQNbfmZlPsuendBVomb/ked53Ab9IH6dwwN\n" +
+          "qJH9WIrvIzIVEXWlpvQ5MCqozM7u1akU+G8cazr8theGPCaYkzoXnigWua4OjdpV\n" +
+          "9z5ZDknhfBzG1AjapdG07FIirwWWgIyZXqZSD96ikmLtwT29qnsCAwEAAaOB7jCB\n" +
+          "6zAdBgNVHQ4EFgQUe5raj5CZTlLSrNuzA1LKh6YNPg0wgbsGA1UdIwSBszCBsIAU\n" +
+          "rN8eFIvMiRFXXgDqKumS0/W2AhOhgYykgYkwgYYxCzAJBgNVBAYTAkNBMQswCQYD\n" +
+          "VQQIEwJCQzEWMBQGA1UEChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9u\n" +
+          "c19zc2wxFTATBgNVBAMUDGRlbW9fcm9vdF9jYTElMCMGCSqGSIb3DQEJARYWanVs\n" +
+          "aXVzZGF2aWVzQGdtYWlsLmNvbYIJAJTNwZ6yNa5bMAwGA1UdEwQFMAMBAf8wDQYJ\n" +
+          "KoZIhvcNAQEFBQADggEBAIB4KMZvHD20pdKajFtMBpL7X4W4soq6EeTtjml3NYa9\n" +
+          "Qc52bsQEGNccKY9afYSBIndaQvFdtmz6HdoN+B8TjYShw2KhyjtKimGLpWYoi1YF\n" +
+          "e4aHdmA/Gp5xk8pZzR18FmooxC9RqBux+NAM2iTFSLgDtGIIj4sg2rbn6Bb6ZlQT\n" +
+          "1rg6VucXCA1629lNfMeNcu7CBNmUKIdaxHR/YJQallE0KfGRiOIWPrPj/VNk0YA6\n" +
+          "XFg0ocjqXJ2/N0N9rWVshMUaXgOh7m4D/5zga5/nuxDU+PoToA6mQ4bV6eCYqZbh\n" +
+          "aa1kQYtR9B4ZiG6pB82qVc2dCqStOH2FAEWos2gAVkQ=\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * Root CA for all of these.
+     */
+    public final static byte[] X509_ROOT_CA = (
+          "-----BEGIN CERTIFICATE-----\n" +
+          "MIIEgDCCA2igAwIBAgIJAJTNwZ6yNa5bMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD\n" +
+          "VQQGEwJDQTELMAkGA1UECBMCQkMxFjAUBgNVBAoTDXd3dy5jdWNiYy5jb20xFDAS\n" +
+          "BgNVBAsUC2NvbW1vbnNfc3NsMRUwEwYDVQQDFAxkZW1vX3Jvb3RfY2ExJTAjBgkq\n" +
+          "hkiG9w0BCQEWFmp1bGl1c2Rhdmllc0BnbWFpbC5jb20wHhcNMDYxMTA1MjEzNjQz\n" +
+          "WhcNMjYxMTA1MjEzNjQzWjCBhjELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAkJDMRYw\n" +
+          "FAYDVQQKEw13d3cuY3VjYmMuY29tMRQwEgYDVQQLFAtjb21tb25zX3NzbDEVMBMG\n" +
+          "A1UEAxQMZGVtb19yb290X2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZpZXNA\n" +
+          "Z21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+OnocmJ\n" +
+          "79UeO2hlCwK+Cle5uZWnU6uwJl+08z5cvebb5tT64WL9+psDbfgUH/Gm9JsuxKTg\n" +
+          "w1tZO/4duIgnaLNSx4HoqaTjwigd/hR3TsoGEPXTCkz1ikgTCOEDvl+iMid6aOrd\n" +
+          "mViE8HhscxKZ+h5FE7oHZyuT6gFoiaIXhFq+xK2w4ZwDz9L+paiwqywyUJJMnh9U\n" +
+          "jKorY+nua81N0oxpIhHPspCanDU4neMzCzYOZyLR/LqV5xORvHcFY84GWMz5hI25\n" +
+          "JbgaWJsYKuCAvNsnQwVoqKPGa7x1fn7x6oGsXJaCVt8weUwIj2xwg1lxMhrNaisH\n" +
+          "EvKpEAEnGGwWKQIDAQABo4HuMIHrMB0GA1UdDgQWBBSs3x4Ui8yJEVdeAOoq6ZLT\n" +
+          "9bYCEzCBuwYDVR0jBIGzMIGwgBSs3x4Ui8yJEVdeAOoq6ZLT9bYCE6GBjKSBiTCB\n" +
+          "hjELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAkJDMRYwFAYDVQQKEw13d3cuY3VjYmMu\n" +
+          "Y29tMRQwEgYDVQQLFAtjb21tb25zX3NzbDEVMBMGA1UEAxQMZGVtb19yb290X2Nh\n" +
+          "MSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZpZXNAZ21haWwuY29tggkAlM3BnrI1\n" +
+          "rlswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAlPl3/8h1LttR1svC\n" +
+          "S8RXbHpAWIT2BEDhGHUNjSmgDQNkE/itf/FCEXh0tlU4bYdtBSOHzflbnzOyIPId\n" +
+          "VZeSWs33V38xDFy6KoVg1gT8JxkLmE5S1vWkpsHIlpw/U6r7KD0Kx9FYx5AiXjw0\n" +
+          "lzz/zlVNuO2U09KIDwDPVG1mBzQiMiSWj1U1pM4KxINkWQwDy/fvu/I983s8lW5z\n" +
+          "hf2WuFNzQN3fcMK5dpBE9NVIu27oYuGYh2sak34v+7T700W2ooBB71qFXtm9P5rl\n" +
+          "Yp9RCEsg3KEEPNTtCBs8fROeXvLDrP0cmBIqwGYDuRNCxFDTOdjv6YGdA8nLOjaH\n" +
+          "2dDk0g==\n" +
+          "-----END CERTIFICATE-----\n").getBytes();
+
+    /**
+     * Below is the private key for all the server certificates above (but
+     * not the intermediate CA or the root CA).  All of those server certs
+     * came from the same private key.
+     */
+    public final static String RSA_PUBLIC_MODULUS =
+          "00c863af96823e8ca9d11d62ae85807e713204c1985a80a2747f7ac863c5" +
+          "8d82e8c1ecf9698298d4838a4d8d81958868e0ef385f6e3842b653465f24" +
+          "41b62dc671a1e204820fe67c82367f80cbcb52586a39bf965cf0141cc077" +
+          "f46472cdeac0fd9b6b954a9ffa52a8d2e59ca1cc5e45cefbd4a37c70f1f7" +
+          "9c7674ad5d07c78640672e94e31c4e6dee2bb52558d3b84d29701bda8767" +
+          "56a83371888390b57c8a5bc49a8356316ae9f1406a913729121621098a77" +
+          "713920270312baabfc06a9c677cef1414dc5559238b5bb6407e2b38c3f73" +
+          "cfc4020c901f0e3647474dca350e66c4e817c31c0ac3a94631a895253c69" +
+          "4caab29bddf085893dde5de87047b9e5cd";
+
+    public final static String RSA_PUBLIC_EXPONENT = "65537";
+
+    public final static String RSA_PRIVATE_EXPONENT =
+          "577abd3295553d0efd4d38c13b62a6d03fa7b7e40cce4f1d5071877d96c6" +
+          "7a39a63f0f7ab21a89db8acae45587b3ef251309a70f74dc1ac02bde68f3" +
+          "8ed658e54e685ed370a18c054449512ea66a2252ed36e82b565b5159ec83" +
+          "f23df40ae189550a183865b25fd77789e960f0d8cedcd72f32d7a66edb4b" +
+          "a0a2baf3fbeb6c7d75f56ef0af9a7cff1c8c7f297d72eae7982164e50a89" +
+          "d450698cf598d39343201094241d2d180a95882a7111e58f4a5bdbc5c125" +
+          "a967dd6ed9ec614c5853e88e4c71e8b682a7cf89cb1d82b6fe78cc865084" +
+          "c8c5dfbb50c939df2b839c977b0245bfa3615e0592b527b1013d5b675ecb" +
+          "44e6b355c1df581f50997175166eef39";
+
+    public final static String RSA_PRIME1 =
+          "00fe759c4f0ce8b763880215e82767e7a937297668f4e4b1e119c6b22a3c" +
+          "a2c7b06c547d88d0aa45f645d7d3aeadaf7f8bc594deae0978529592977c" +
+          "b1ff890f05033a9e9e15551cad9fbf9c41d12139ccd99c1c3ac7b2197eff" +
+          "350d236bb900c1440953b64956e0a058ef824a2e16894af175177c77dbe1" +
+          "fef7d8b532608d2513";
+
+    public final static String RSA_PRIME2 =
+          "00c99a45878737a4cf73f9896680b75487f1b669b7686a6ba07103856f31" +
+          "db668c2c440c44cdd116f708f631c37a9adf119f5b5cb58ffe3dc62e20af" +
+          "af72693d936dc6bb3c5194996468389c1f094079b81522e94572b4ad7d39" +
+          "529178e9b8ebaeb1f0fdd83b8731c5223f1dea125341d1d64917f6b1a6ae" +
+          "c18d320510d79f859f";
+
+    public final static String RSA_EXPONENT1 =
+          "029febf0d4cd41b7011c2465b4a259bd6118486464c247236f44a169d61e" +
+          "47b9062508f674508d5031003ceabc57e714e600d71b2c75d5443db2da52" +
+          "6bb45a374f0537c5a1aab3150764ce93cf386c84346a6bd01f6732e42075" +
+          "c7a0e9e78a9e73b934e7d871d0f75673820089e129a1604438edcbbeb4e2" +
+          "106467da112ce389";
+    
+    public final static String RSA_EXPONENT2 =
+          "00827e76650c946afcd170038d32e1f8386ab00d6be78d830efe382e45d4" +
+          "7ad4bd04e6231ee22e66740efbf52838134932c9f8c460cdccdec58a1424" +
+          "4427859192fd6ab6c58b74e97941b0eaf577f2a11713af5e5952af3ae124" +
+          "9a9a892e98410dfa2628d9af668a43b5302fb7d496c9b2fec69f595292b6" +
+          "e997f079b0f6314eb7";
+
+    public final static String RSA_COEFFICIENT =
+          "00e6b62add350f1a2a8968903ff76c31cf703b0d7326c4a620aef01225b7" +
+          "1640b3f2ec375208c5f7299863f6005b7799b6e529bb1133c8435bf5fdb5" +
+          "a786f6cd8a19ee7094a384e6557c600a38845a0960ddbfd1df18d0af5740" +
+          "001853788f1b5ccbf9affb4c52c9d2efdb8aab0183d86735b32737fb4e79" +
+          "2b8a9c7d91c7d175ae";
+
+}

Propchange: jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/CertificatesToPlayWith.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

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

Added: jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestAllSSL.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestAllSSL.java?view=auto&rev=487346
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestAllSSL.java (added)
+++ jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestAllSSL.java Thu Dec 14 12:49:34 2006
@@ -0,0 +1,51 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ * ====================================================================
+ *
+ *  Copyright 1999-2006 The Apache Software Foundation
+ *
+ *  Licensed 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 junit.framework.*;
+
+public class TestAllSSL extends TestCase {
+
+    public TestAllSSL(String testName) {
+        super(testName);
+    }
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTest(TestHostnameVerifier.suite());
+        suite.addTest(TestSSLSocketFactory.suite());
+        return suite;
+    }
+
+    public static void main(String args[]) {
+        String[] testCaseName = { TestAllSSL.class.getName() };
+        junit.textui.TestRunner.main(testCaseName);
+    }
+
+}

Propchange: jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestAllSSL.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

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

Added: jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestHostnameVerifier.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestHostnameVerifier.java?view=auto&rev=487346
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestHostnameVerifier.java (added)
+++ jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestHostnameVerifier.java Thu Dec 14 12:49:34 2006
@@ -0,0 +1,221 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Copyright 1999-2006 The Apache Software Foundation
+ *
+ *  Licensed 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 junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import javax.net.ssl.SSLException;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+/**
+ * Unit tests for {@link HostnameVerifier}.
+ *
+ * @author Julius Davies
+ * @since 11-Dec-2006
+ */
+public class TestHostnameVerifier extends TestCase
+      implements CertificatesToPlayWith {
+
+    public TestHostnameVerifier(String testName) {
+        super(testName);
+    }
+
+    public static void main(String args[]) throws Exception {
+        String[] testCaseName = { TestHostnameVerifier.class.getName() };
+        junit.textui.TestRunner.main(testCaseName);
+    }
+
+    public static Test suite() {
+        TestSuite ts = new TestSuite();
+        ts.addTestSuite(TestHostnameVerifier.class);
+        return ts;
+    }
+
+    public void testVerify() throws Exception {
+        HostnameVerifier DEFAULT = HostnameVerifier.DEFAULT;
+        HostnameVerifier STRICT = HostnameVerifier.STRICT;
+        HostnameVerifier ALLOW_ALL = HostnameVerifier.ALLOW_ALL;
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        InputStream in;
+        X509Certificate x509;
+        in = new ByteArrayInputStream(X509_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+
+        DEFAULT.verify("foo.com", x509);
+        STRICT.verify("foo.com", x509);
+        exceptionPlease(DEFAULT, "a.foo.com", x509);
+        exceptionPlease(STRICT, "a.foo.com", x509);
+        exceptionPlease(DEFAULT, "bar.com", x509);
+        exceptionPlease(STRICT, "bar.com", x509);
+        ALLOW_ALL.verify("foo.com", x509);
+        ALLOW_ALL.verify("a.foo.com", x509);
+        ALLOW_ALL.verify("bar.com", x509);
+
+        in = new ByteArrayInputStream(X509_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        DEFAULT.verify("\u82b1\u5b50.co.jp", x509);
+        STRICT.verify("\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(DEFAULT, "a.\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(STRICT, "a.\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(X509_FOO_BAR);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        DEFAULT.verify("foo.com", x509);
+        STRICT.verify("foo.com", x509);
+        exceptionPlease(DEFAULT, "a.foo.com", x509);
+        exceptionPlease(STRICT, "a.foo.com", x509);
+        DEFAULT.verify("bar.com", x509);
+        STRICT.verify("bar.com", x509);
+        exceptionPlease(DEFAULT, "a.bar.com", x509);
+        exceptionPlease(STRICT, "a.bar.com", x509);
+
+        in = new ByteArrayInputStream(X509_FOO_BAR_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        DEFAULT.verify("foo.com", x509);
+        STRICT.verify("foo.com", x509);
+        exceptionPlease(DEFAULT, "a.foo.com", x509);
+        exceptionPlease(STRICT, "a.foo.com", x509);
+        DEFAULT.verify("bar.com", x509);
+        STRICT.verify("bar.com", x509);
+        exceptionPlease(DEFAULT, "a.bar.com", x509);
+        exceptionPlease(STRICT, "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 );
+        // STRICT.verify("\u82b1\u5b50.co.jp", x509 );
+        exceptionPlease(DEFAULT, "a.\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(STRICT, "a.\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(X509_NO_CNS_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        DEFAULT.verify("foo.com", x509);
+        STRICT.verify("foo.com", x509);
+        exceptionPlease(DEFAULT, "a.foo.com", x509);
+        exceptionPlease(STRICT, "a.foo.com", x509);
+
+        in = new ByteArrayInputStream(X509_NO_CNS_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        DEFAULT.verify("foo.com", x509);
+        STRICT.verify("foo.com", x509);
+        exceptionPlease(DEFAULT, "a.foo.com", x509);
+        exceptionPlease(STRICT, "a.foo.com", x509);
+
+        in = new ByteArrayInputStream(X509_THREE_CNS_FOO_BAR_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(DEFAULT, "foo.com", x509);
+        exceptionPlease(STRICT, "foo.com", x509);
+        exceptionPlease(DEFAULT, "a.foo.com", x509);
+        exceptionPlease(STRICT, "a.foo.com", x509);
+        exceptionPlease(DEFAULT, "bar.com", x509);
+        exceptionPlease(STRICT, "bar.com", x509);
+        exceptionPlease(DEFAULT, "a.bar.com", x509);
+        exceptionPlease(STRICT, "a.bar.com", x509);
+        DEFAULT.verify("\u82b1\u5b50.co.jp", x509);
+        STRICT.verify("\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(DEFAULT, "a.\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(STRICT, "a.\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(X509_WILD_FOO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        exceptionPlease(DEFAULT, "foo.com", x509);
+        exceptionPlease(STRICT, "foo.com", x509);
+        DEFAULT.verify("www.foo.com", x509);
+        STRICT.verify("www.foo.com", x509);
+        DEFAULT.verify("\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);
+
+        in = new ByteArrayInputStream(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".
+        DEFAULT.verify("*.co.jp", x509);
+        STRICT.verify("*.co.jp", x509);
+        exceptionPlease(DEFAULT, "foo.co.jp", x509);
+        exceptionPlease(STRICT, "foo.co.jp", x509);
+        exceptionPlease(DEFAULT, "\u82b1\u5b50.co.jp", x509);
+        exceptionPlease(STRICT, "\u82b1\u5b50.co.jp", x509);
+
+        in = new ByteArrayInputStream(X509_WILD_FOO_BAR_HANAKO);
+        x509 = (X509Certificate) cf.generateCertificate(in);
+        // try the foo.com variations
+        exceptionPlease(DEFAULT, "foo.com", x509);
+        exceptionPlease(STRICT, "foo.com", x509);
+        DEFAULT.verify("www.foo.com", x509);
+        STRICT.verify("www.foo.com", x509);
+        DEFAULT.verify("\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);
+        // try the bar.com variations
+        exceptionPlease(DEFAULT, "bar.com", x509);
+        exceptionPlease(STRICT, "bar.com", x509);
+        DEFAULT.verify("www.bar.com", x509);
+        STRICT.verify("www.bar.com", x509);
+        DEFAULT.verify("\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);
+        // try the \u82b1\u5b50.co.jp variations
+        /*
+           Java isn't extracting international subjectAlts properly.  (Or
+           OpenSSL isn't storing them properly).
+        */
+        //exceptionPlease( DEFAULT, "\u82b1\u5b50.co.jp", x509 );
+        //exceptionPlease( STRICT, "\u82b1\u5b50.co.jp", x509 );
+        //DEFAULT.verify("www.\u82b1\u5b50.co.jp", x509 );
+        //STRICT.verify("www.\u82b1\u5b50.co.jp", x509 );
+        //DEFAULT.verify("\u82b1\u5b50.\u82b1\u5b50.co.jp", x509 );
+        //STRICT.verify("\u82b1\u5b50.\u82b1\u5b50.co.jp", x509 );
+        //DEFAULT.verify("a.b.\u82b1\u5b50.co.jp", x509 );
+        //exceptionPlease(STRICT,"a.b.\u82b1\u5b50.co.jp", x509 );
+    }
+
+    private void exceptionPlease(HostnameVerifier hv, String host,
+                                 X509Certificate x509) {
+        try {
+            hv.verify(host, x509);
+            fail("HostnameVerifier shouldn't allow [" + host + "]");
+        }
+        catch(SSLException e) {
+            // whew!  we're okay!
+        }
+    }
+
+}

Propchange: jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestHostnameVerifier.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

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

Added: jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestSSLSocketFactory.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestSSLSocketFactory.java?view=auto&rev=487346
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestSSLSocketFactory.java (added)
+++ jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestSSLSocketFactory.java Thu Dec 14 12:49:34 2006
@@ -0,0 +1,215 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Copyright 1999-2006 The Apache Software Foundation
+ *
+ *  Licensed 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 junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.apache.http.impl.DefaultHttpParams;
+import org.apache.http.params.HttpParams;
+
+import javax.net.ServerSocketFactory;
+import javax.net.ssl.SSLServerSocketFactory;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+
+/**
+ * Unit tests for {@link SSLSocketFactory}.
+ *
+ * @author Julius Davies
+ * @since 8-Dec-2006
+ */
+public class TestSSLSocketFactory extends TestCase
+      implements CertificatesToPlayWith {
+
+    public TestSSLSocketFactory(String testName) {
+        super(testName);
+    }
+
+    public static void main(String args[]) throws Exception {
+        String[] testCaseName = { TestSSLSocketFactory.class.getName() };
+        junit.textui.TestRunner.main(testCaseName);
+    }
+
+    public static Test suite() {
+        TestSuite ts = new TestSuite();
+        ts.addTestSuite(TestSSLSocketFactory.class);
+        return ts;
+    }
+
+    public void testConstructor() {}
+
+    public void testCreateKeyManagers() {}
+
+    public void testCreateTrustManagers() {}
+
+    public void testHashCode() {}
+
+    public void testEquals() {}
+
+    public void testToString() {}
+
+    public void testCreateSocket() throws Exception {
+        HttpParams params = new DefaultHttpParams();
+        String password = "changeit";
+        char[] pwd = password.toCharArray();
+
+        RSAPrivateCrtKeySpec k;
+        k = new RSAPrivateCrtKeySpec(new BigInteger(RSA_PUBLIC_MODULUS, 16),
+                                     new BigInteger(RSA_PUBLIC_EXPONENT, 10),
+                                     new BigInteger(RSA_PRIVATE_EXPONENT, 16),
+                                     new BigInteger(RSA_PRIME1, 16),
+                                     new BigInteger(RSA_PRIME2, 16),
+                                     new BigInteger(RSA_EXPONENT1, 16),
+                                     new BigInteger(RSA_EXPONENT2, 16),
+                                     new BigInteger(RSA_COEFFICIENT, 16));
+
+        PrivateKey pk = KeyFactory.getInstance("RSA").generatePrivate(k);
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        InputStream in1, in2, in3;
+        in1 = new ByteArrayInputStream(X509_FOO);
+        in2 = new ByteArrayInputStream(X509_INTERMEDIATE_CA);
+        in3 = new ByteArrayInputStream(X509_ROOT_CA);
+        X509Certificate[] chain = new X509Certificate[3];
+        chain[0] = (X509Certificate) cf.generateCertificate(in1);
+        chain[1] = (X509Certificate) cf.generateCertificate(in2);
+        chain[2] = (X509Certificate) cf.generateCertificate(in3);
+
+        ks.setKeyEntry("RSA_KEY", pk, pwd, chain);
+        ks.setCertificateEntry("CERT", chain[2]); // Let's trust ourselves. :-)
+
+        File tempFile = File.createTempFile("junit", "jks");
+        try {
+            String path = tempFile.getCanonicalPath();
+            tempFile.deleteOnExit();
+            FileOutputStream fOut = new FileOutputStream(tempFile);
+            ks.store(fOut, pwd);
+            fOut.close();
+
+            System.setProperty("javax.net.ssl.keyStore", path);
+            System.setProperty("javax.net.ssl.keyStorePassword", password);
+            System.setProperty("javax.net.ssl.trustStore", path);
+            System.setProperty("javax.net.ssl.trustStorePassword", password);
+
+            ServerSocketFactory server = SSLServerSocketFactory.getDefault();
+            // Let the operating system just choose an available port:
+            ServerSocket serverSocket = server.createServerSocket(0);
+            serverSocket.setSoTimeout(30000);
+            int port = serverSocket.getLocalPort();
+            // System.out.println("\nlistening on port: " + port);
+
+            SSLSocketFactory ssf = new SSLSocketFactory();
+            ssf.setHostnameVerifier(HostnameVerifier.ALLOW_ALL);
+
+            // Test 1 - createSocket()
+            IOException[] e = new IOException[1];
+            boolean[] success = new boolean[1];
+            listen(serverSocket, e, success);
+            Socket s = ssf.createSocket("localhost", port, null, 0, params);
+            exerciseSocket(s, e, success);
+
+            // Test 2 - createSocket( Socket ), where we upgrade a plain socket
+            //          to SSL.
+            success[0] = false;
+            listen(serverSocket, e, success);
+            s = new Socket("localhost", port);
+            s = ssf.createSocket(s, "localhost", port, true);
+            exerciseSocket(s, e, success);
+        }
+        finally {
+            tempFile.delete();
+        }
+    }
+
+    private static void listen(final ServerSocket ss,
+                               final IOException[] e,
+                               final boolean[] success) {
+        Runnable r = new Runnable() {
+            public void run() {
+                try {
+                    Socket s = ss.accept();
+                    InputStream in = s.getInputStream();
+                    OutputStream out = s.getOutputStream();
+                    out.write("server says hello\n".getBytes());
+                    byte[] buf = new byte[4096];
+                    in.read(buf);
+                    out.close();
+                    in.close();
+                    s.close();
+                } catch(IOException ioe) {
+                    e[0] = ioe;
+                } finally {
+                    success[0] = true;
+                }
+            }
+        };
+        new Thread(r).start();
+        Thread.yield();
+    }
+
+    private static void exerciseSocket(Socket s, IOException[] e,
+                                       boolean[] success)
+          throws IOException {
+        InputStream in = s.getInputStream();
+        OutputStream out = s.getOutputStream();
+        out.write(42);
+        byte[] buf = new byte[4096];
+        in.read(buf);
+        out.close();
+        in.close();
+        s.close();
+        // String response = new String( buf, 0, c );
+        while(!success[0]) {
+            Thread.yield();
+        }
+        if(e[0] != null) {
+            throw e[0];
+        }
+    }
+
+
+}

Propchange: jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/http/conn/ssl/TestSSLSocketFactory.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

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

Modified: jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/httpclient/TestAll.java
URL: http://svn.apache.org/viewvc/jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/httpclient/TestAll.java?view=diff&rev=487346&r1=487345&r2=487346
==============================================================================
--- jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/httpclient/TestAll.java (original)
+++ jakarta/httpcomponents/httpclient/trunk/src/test/org/apache/httpclient/TestAll.java Thu Dec 14 12:49:34 2006
@@ -30,6 +30,7 @@
 
 import org.apache.http.cookie.TestAllCookie;
 import org.apache.http.cookie.impl.TestAllCookieImpl;
+import org.apache.http.conn.ssl.TestAllSSL;
 import org.apache.httpclient.impl.TestAllHttpClientImpl;
 
 import junit.framework.*;
@@ -45,6 +46,7 @@
         suite.addTest(TestAllCookie.suite());
         suite.addTest(TestAllCookieImpl.suite());
         suite.addTest(TestAllHttpClientImpl.suite());
+        suite.addTest(TestAllSSL.suite());        
         return suite;
     }
 



Mime
View raw message