Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Keystore - programatically select the certificate to use from keystore file

Tags:

java

ssl

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);
like image 864
StevieP Avatar asked Mar 24 '26 20:03

StevieP


1 Answers

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);
like image 71
pedrofb Avatar answered Mar 26 '26 10:03

pedrofb



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!