How to specify outbound certificate alias for HTTPS-calls?

aksamit picture aksamit · Mar 13, 2011 · Viewed 17.4k times · Source

I am calling a webservice that requires client certificate authentication.

If I specify a Java keystore containing a single certificate (the client certificate the service expects) then everything works fine. However if I use a keystore that contains multiple certificates then I can't seem to be able to specify which certificate should be picked up by the client, the client seems to pick up the first available certificate (in alphabetical order).

I have tried the following property but without expected result:

System.setProperty("com.sun.enterprise.security.httpsOutboundKeyAlias", "my-client-certificate alias");

How can I specify which client certificate alias that should be used?

Answer

zarniwoop picture zarniwoop · Dec 29, 2011

The links that Jakub provides in his response lead you to the answer, but I wanted to post a simpler response here, since we struggled with this problem for quite a while before finally getting something that worked.

We have the case where there are several certificates available to use, and we need to use the one that has a specific alias to perform our connection. We did this by creating our own KeyManager implementation which passes through most of its functionality to the default X509KeyManager but has functionality to select exactly the correct alias to use when the connection is performed.

First the key manager we created:

public class FilteredKeyManager implements X509KeyManager {

private final X509KeyManager originatingKeyManager;
private final X509Certificate[] x509Certificates;

public FilteredKeyManager(X509KeyManager originatingKeyManager, X509Certificate[] x509Certificates) {
    this.originatingKeyManager = originatingKeyManager;
    this.x509Certificates = x509Certificates;
}

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

public String[] getClientAliases(String keyType, Principal[] issuers) {
    return new String[] {"DesiredClientCertAlias"};
}

All other methods required for implementation are passthroughs to originatingKeyManager.

Then, when we actually set up the context:

SSLContext context = SSLContext.getInstance("TLSv1");
context.init(new KeyManager[] { new FilteredKeyManager((X509KeyManager)originalKeyManagers[0], desiredCertsForConnection) },
    trustManagerFactory.getTrustManagers(), new SecureRandom());

Hope that makes it clear, and works for anyone else trying to solve this problem.