Using multiple SSL client certificates with the same host in Java
In my java application, I need to use SSL to connect to the same host, but I use a different certificate every time The reason why I need different certificates is that the remote site uses the user ID attribute embedded in the certificate to identify the client
This is a server application running on three different operating systems. I need to be able to switch certificates without restarting the process
Another user suggests importing multiple certificates into the same keystore However, I'm not sure this will help me unless there is a way to tell Java which certificate in the keystore to use
Solution
SSL can provide the client with hints about the certificate to be rendered This may allow you to use a keystore with multiple identities, but unfortunately, most servers do not use this prompt function Therefore, if you specify the client certificate to use for each connection, it will be more robust
The following is the sample code for setting an sslcontext using the specified identity and trust store You can repeat these steps to create multiple contexts, each corresponding to each client certificate you want to use Each sslcontext may use the same truststore, but use a different identity store (containing a single client key entry to use in that context)
Initialize the context you need once and reuse the correct context for each connection If you want to establish multiple connections, this will allow you to take advantage of SSL sessions
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(identityStore,password); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(trustStore); SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(kmf.getKeyManagers(),tmf.getTrustManagers(),null);
Later, you can create the socket directly:
SSLSocketFactory factory = ctx.getSocketFactory(); Socket socket = factory.createSocket(host,port);
Alternatively, if you are using the URL class, you can specify the sslsocketfactory to use when issuing HTTPS requests:
HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); con.setSSLSocketFactory(ctx.getSocketFactory());
Java 6 has some additional APIs that make it easier to configure sockets based on your preference for cipher suites, etc