I have two certificate/key pairs in a java keystore. Aliases of those key-entries are "foo" and "bar".
My TLS client (java program) uses the keystore. TLS client authentication is done during connection opening.
The client program should use "foo" key-entry when TLS server request certificate from the client.
Now the client send wrong certificate ("bar") to the server during connection handshake.
How I can tell alias of the wanted key-entry to SSLSocket before connecting?
Currently the code is following:
final SSLSocket ss = (SSLSocket)SSLSocketFactory.getDefault().createSocket();
ss.setEnabledProtocols( new String[] {"TLSv1"});
ss.connect( targetAddress );
The default KeyManager
will send the first certificate it finds that matches the conditions requested by the server, that is, it will send the first one it find for which it can build a certification chain up one of the CA names sent by the server during the request.
If you always want a specific alias to be chosen, you'll need to implement your own X509KeyManager
, possibly wrapping the default manager. Something along these lines should work (not tested this actual code, there may be a few typos):
KeyStore keystore = ... // create and load your keystore.
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keystore, password.toCharArray());
final X509KeyManager origKm = (X509KeyManager)kmf.getKeyManagers()[0];
X509KeyManager km = new X509KeyManager() {
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
return "foo";
}
public X509Certificate[] getCertificateChain(String alias) {
return origKm.getCertificateChain(alias);
}
// Delegate the rest of the methods from origKm too...
}
Then use it for your SSLContext
:
SSLContext sslContext = sslContext.getInstance("TLS");
sslContext.init(new KeyManager[] { km }, null, null);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();