Attached is a diff of SSLServerSocketFactory which demonstrates my proposed fix 
for bug #1400 (Tomcat SSL does not handle keystores with multiple entries). 
While this entry was classified as an "enhancement" during last week's roundup, 
I would argue that it is an actual bug (albeit a non-critical one).

The problem is this: Given a keystore with multiple entries, Sun's SSL 
implementation classes do not provide a way to affect which certificate is 
selected for use on the socket. In other words, it just grabs the first cert it 
finds inside the keystore. The attached fix extracts the "tomcat" entry 
from the keystore file, sticks it in a second keystore by itself, then uses 
this second, "tomcat-only" keystore to init the secure socket. (Yes, I know, 
it's kind of a roundabout hack, but it's a relatively clean one :-)

Note that while this is a diff, it is NOT meant to be a patch. This code will 
not yet compile, because it requires my exception cleanup patches from last 
month (which have not yet been applied). All I'm looking for at this point is 
any objections to my basic approach. If I get no objections over the next few 
days, while I test this code locally, I will commit it once it is tested and 
working, then close out the associated bugzilla entry.

- Christopher

/**
 * Pleurez, pleurez, mes yeux, et fondez vous en eau!
 * La moitié de ma vie a mis l'autre au tombeau.
 *    ---Corneille
 */
--- SSLServerSocketFactory.java Sun Sep  9 12:29:36 2001
+++ SSLServerSocketFactory-new.java     Sun Sep  9 12:59:52 2001
@@ -185,6 +185,12 @@
 
 
     /**
+     * An internal keystore which contains only the Tomcat certificate.
+     * This one is used to initialize the socket.
+     */
+    private KeyStore implKeystore = null;
+
+    /**
      * Pathname to the key store file to be used.
      */
     private String keystoreFile =
@@ -387,13 +393,31 @@
             Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
             */
 
+            char[] ksPass = keystorePass.toCharArray();
+
+            // Check for "tomcat" entry in our keystore
+            if ( keyStore.containsAlias("tomcat") == false )
+                throw new IOException("The specified keystore does not " +
+                    "appear to have a Tomcat certificate.");
+
+            // Setup our Tomcat-only keystore (does not get written to disk)
+            implKeystore = KeyStore.getInstance(keystoreType);
+            implKeystore.load(null, null);
+
+            implKeystore.setKeyEntry(
+                "tomcat",
+                keyStore.getKey("tomcat", ksPass),
+                ksPass,
+                keyStore.getCertificateChain("tomcat")
+            );
+
             // Create an SSL context used to create an SSL socket factory
             SSLContext context = SSLContext.getInstance(protocol);
 
             // Create the key manager factory used to extract the server key
             KeyManagerFactory keyManagerFactory =
                 KeyManagerFactory.getInstance(algorithm);
-            keyManagerFactory.init(keyStore, keystorePass.toCharArray());
+            keyManagerFactory.init(implKeystore, keystorePass.toCharArray());
 
             // Create the trust manager factory used for checking certificates
             /*

Reply via email to