Overview
JSSE allows users to provide default trust stores and key stores by specifying javax.net.ssl.* parameters. I would like to provide a non-default TrustManager for my application, while allowing the user to specify the KeyManager as usual, but there doesn't seem to be any way to achieve this.
Details
Suppose on unix machines I want to allow the user to use a pkcs12 key store for authentication, while on OS X I want allow the user to use the system keychain. On OS X the application might be started as follows:
java -Djavax.net.ssl.keyStore=NONE -Djavax.net.ssl.keyStoreType=KeychainStore \
-Djavax.net.ssl.keyStorePassword=- -jar MyApplication.jar
This will work fine: when the application accesses an https server that requires mutual authentication (client certificate authentication) then the user will be prompted to allow access to their keychain.
The Problem
Now suppose I want to bundle a self-signed certificate authority with my application. I can override the default trust manager by constructing a TrustManagerFactory and passing in a KeyStore containing my certificate (javadoc). However, to use this non-default trust manager I need to create and initialise an SSLContext. Here-in lies the problem.
SSLContexts are initialised by calling init(..) and passing both a KeyManager and a TrustManager. However, logic for creating a KeyManager using the javax.net.ssl.* parameters is embedded in the implementation of the default SSLContexts -- I can't find a way to obtain a KeyManager or a KeyManagerFactory using the default behaviour while also specifying a non-default TrustManager or TrustManagerFactory. Thus, it seems that it is not possible to use, for example, the appropriate operating-system specific keychain implementation while also providing a root certificate for authenticating remote servers.