I have to make an mTLS connection so that my application can connected to an organization server. For that I am provided a CA root certificate (that I am going to store in my java cacerts) and a public and private key files (.pem) and I am converting them into p12 keystore using openssl as follows:
openssl pkcs12 -export -inkey private-key.pem -in cert.pem -out test.p12 -name "aliaspk" -legacy
then I am converting the test.p12 keystore into my java 1.8 keystore using java keytool as follows:
keytool -importkeystore -srckeystore test.p12 -srcstoretype pkcs12 -destkeystore keystore.jks -srcalias aliaspk -destalias aliaspk
Now using privatekeyalias, clientkeyalias and passphrase and the keystore path I have to establish mTLS connection.
I am using the following method to establish an mTLS connection:
public class App {
public void makeMTLSConnection(String url) {
String passphrase = "password"; //that is used as destpass while make keystore.jks
String certAlias = "certalias";
String privateKeyAlias = "aliaspk" //used as src and dst alias in the above cmd
try(FileInputStream fis = "path/to/keystore/keystore.jks") {
//Load Keystore
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(fis, passphrase.toCharArray());
// Get certificate by alias
X509Certificate certificate = (X509Certificate) keyStore.getCertificate(privateKeyAlias);
PrivateKey privateKey = (PrivateKey) keyStore.getKey(privateKeyAlias, passphrase.toCharArray());
//Add private key and certificate chain into the keystore
keyStore.setKeyEntry(privateKeyAlias, privateKey, passphrase.toCharArray(), new Certificate[]{certificate});
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, passphrase.toCharArray());
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
// Load the default java cacerts
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (FileInputStream fis2 = new FileInputStream("/usr/java/bin/lib/cacerts")) {
trustStore.load(fis2, "changeit".toCharArray());
}
trustManagerFactory.init(trustStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, trustManagers, null);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
conn = (HttpsURLConnection) new URL(url).openConnection();
setTimeoutInConnection(60000);
conn.connect();
} catch (Exception e){
e.printStackTrace();
}
}
But when I run the application to establish the mTLS connection I am getting the following error:
Caused by: java.security.UnrecoverableKeyException: Cannot recover key at sun.security.provider.KeyProtector.recover(KeyProtector.java:315) at sun.security.provider.JavaKeyStore.engineGetKey(JavaKeyStore.java:143) at sun.security.provider.JavaKeyStore$JKS.engineGetKey(JavaKeyStore.java:57) at sun.security.provider.KeyStoreDelegator.engineGetKey(KeyStoreDelegator.java:96) at sun.security.provider.JavaKeyStore$DualFormatJKS.engineGetKey(JavaKeyStore.java:71) at java.security.KeyStore.getKey(KeyStore.java:1023) at sun.security.ssl.SunX509KeyManagerImpl.<init (SunX509KeyManagerImpl.java:145) at sun.security.ssl.KeyManagerFactoryImpl$SunX509.engineInit(KeyManagerFactoryImpl.java:70) at javax.net.ssl.KeyManagerFactory.init(KeyManagerFactory.java:256) at org.john.doe.Connector.makeMTLSConnection(Connector.java:224)... 49 common frames omitted