Re: New code: Easy PKCS#12 client certificate support for pgjdbc - Mailing list pgsql-jdbc
From | Craig Ringer |
---|---|
Subject | Re: New code: Easy PKCS#12 client certificate support for pgjdbc |
Date | |
Msg-id | 4BFDEA8F.6040707@postnewspapers.com.au Whole thread Raw |
In response to | New code: Easy PKCS#12 client certificate support for pgjdbc (Craig Ringer <craig@postnewspapers.com.au>) |
List | pgsql-jdbc |
Just a follow-up on this: The code I posted works, but is the wrong approach to take. I've removed it and replaced it with some suitable documentation. Given how much trouble I had figuring out the right way to do this, I bet I'm not alone, so I thought I'd write it up. In summary: Applications should use the core SunPKIX trust and certificate managers and the default SSLSocketFactory if at all possible, because they're flexible enough to handle pluggable authentication methods like hardware tokens with no app code changes. If you override the SSLSocketFactory and provide your own trust and key managers you lose a lot of the power of the system. If, like mine, your app needs to offer a user a way to configure additional keys and trusted certs, just create your own JKS or JECKS KeyStores for the trust- and key- stores during startup (if they don't already exist), and set the javax.net.ssl. properties to point to them. The default Sun providers will then load those app-specific stores instead of the global cert- and key- stores. If the user attempts a connection to a service that requires a client certificate, or a service whose certificate isn't trusted, you can catch the resulting exception, examine it to determine the root cause, and prompt the user to supply a client certificate or to install a trusted root cert as appropriate. Apache Commons Lang is useful here for inspection of deep exception chains. If you'd prefer to load a user PKCS#12 file directly for the keystore, just specify it in your app's javax.net.ssl. system properties via System.setProperty(...) before any SSL code is invoked, and the default X509KeyStore will be happy to use it. Make sure to set javax.net.ssl.keyStoreType to "pkcs12". If you really do need to replace the X509TrustManager for some reason, use the certificate verification built-in to the JVM rather than re-implementing it. Create a Set<TrustAnchor> from your list of trusted X509Certificate instances from your trust store, and use it with CertPathValidator to validate a CertPath created from the X509Certificate[] provided to the TrustManager. This does proper PKIX validation a few lines of code. Even better is to load the default "SunPKIX" X509TrustManager and X509KeyManager and put them before your own in the appropriate array when creating the SSL context in your SSLSocketFactory. The SSL context will try them in order. That way the user can still use all the pluggable features, but you can (eg) fall back to your X509TrustManager if the cert isn't trusted so you can display a "add to trust store?" prompt. About the only downside with this that I've found is that there doesn't appear to be any way to force the SunPKIX code to re-load a KeyStore (the trust store or the key store) after SSL has been inited, so if the user adds a trusted cert or key they seem to need to re-start the app. You can get around it by using non-public com.sun api, but that's never a good idea. If you're having problems in this area, you should read the JSSE reference guide, as it'll help you understand how it all works: http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html -- Craig Ringer
pgsql-jdbc by date: