3

I have a java keystore file which contains multiple client certificates. I wish to select just one of these certificates in my Java application to connect to a service. Is there a simple way to do this? The only way I've found a solution to this so far is to create a new KeyStore in the program using the client cert details (found by its alias) from the original keystore file. I though there might be a simple way to just say "use the cert from the keystore.jks file with this alias", rather than have to create a new keystore just for the cert you want to use. Code is as follows:

        // Set up Client Cert settings
        KeyStore clientCertStore = KeyStore.getInstance("JKS");
        clientCertStore.load(new FileInputStream(clientKeystoreLocation), clientKeystorePassword);            

        // Create temporary one keystore, then extract the client cert using it's alias from keystore.jks, then create
        // a new keystore with this cert, that the process will use to connect with.
        KeyStore tempKstore = KeyStore.getInstance("JKS");
        tempKstore.load(null);
        tempKstore.setKeyEntry(certificateAlias, clientCertStore.getKey(certificateAlias, bwConfig.clientKeystorePassword),
                clientKeystorePassword, clientCertStore.getCertificateChain(certificateAlias));
        clientCertStore = tempKstore;

        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(clientCertStore, clientKeystorePassword);            

        // Set up Truststore settings
        File truststoreFile = new File(TrustStoreLocation);
        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream(truststoreFile), TrustStorePassword);
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(trustStore);

        // Set to TLS 1.2 encryption
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);

        SSLSocketFactory ssf = sslContext.getSocketFactory();
        ssf.createSocket(serviceURL.getHost(), servicePort);

        bp.getRequestContext().put("com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory", ssf);

1 Answer 1

4

Your question is similar to How I can tell alias of the wanted key-entry to SSLSocket before connecting?

The default KeyManager will select the first certificate in handshake (according to CA list sent by server), You can build your own X509KeyManager to specify the alias to be used wrapping the default.

final X509KeyManager origKm = (X509KeyManager)keyManagerFactory.getKeyManagers()[0];
X509KeyManager km = new X509KeyManager() {
   public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
       return "alias";
   }

   public X509Certificate[] getCertificateChain(String alias) {
       return origKm.getCertificateChain(alias);
   }

// override the rest of the methods delegating to origKm ...
}

Set the new keyManager in SSLContext

 sslContext.init(new KeyManager[] { km }, trustManagerFactory.getTrustManagers(), null);
Sign up to request clarification or add additional context in comments.

2 Comments

In both cases I am a little confused by "// override the rest of the methods delegating to origKm ..." Does this just mean take the default suggestion? Like should serverAlias be null?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.