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 /*