Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to specify outbound certificate alias for HTTPS-calls?

Tags:

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?

like image 475
aksamit Avatar asked Mar 13 '11 20:03

aksamit


2 Answers

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.

like image 167
zarniwoop Avatar answered Oct 02 '22 22:10

zarniwoop


Short answer: it cannot be done with default Java ssl implementation.

Long answer: I looked on how the SSL handshake is implemented in the sun.security.ssl.ClientHandshaker. In its method serverHelloDone is called X509ExtendedKeyManager.chooseClientAlias. Its implementations are really done in such a way that they return first alias, whose entry matches the given key algorithm and few other things. No way how to tweak the alias selection.

For those who can change the code, this looks like a promising workaround: http://www.44342.com/java-f392-t785-p1.htm

like image 21
Jakub Avatar answered Oct 02 '22 20:10

Jakub