问题
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:
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);
来源:https://stackoverflow.com/questions/42442721/java-keystore-programatically-select-the-certificate-to-use-from-keystore-file