I'm working on a server in a distributed application that has browser clients and also participates in server-to-server communication with a 3rd party. My server has a CA-signed certificate to let my clients connect using TLS (SSL) communication using HTTP/S and XMPP(secure). That's all working fine.
Now I need to securely connect to a 3rd party server. In this communication, my server acts as client and I've a client certificate signed by the 3rd party.
The issue is when I tried adding the client certificates that I got from the 3rd party server and using the standard system configuration (-Djavax.net.ssl.keyStore=xyz). I get a "No X.509 certificate for client authentication" error in the debug log for SSL.
javax.net.ssl|FINE|01|main|2021-09-15 02:07:40.538 IST|CertificateMessage.java:297|No X.509 certificate for client authentication, use empty Certificate message instead
javax.net.ssl|FINE|01|main|2021-09-15 02:07:40.538 IST|CertificateMessage.java:328|Produced client Certificate handshake message (
"Certificates": <empty list>
)
But when I use a custom SSL context with the same keystore, it works fine. Following is the code for the same.
String keystorePath = "keystorePath";
String keystorePassword = "changeit";
// Make a KeyStore from the JKS file
KeyStore ks = null;
try {
ks = KeyStore.getInstance("JKS");
} catch (KeyStoreException e) {
e.printStackTrace();
}
try (
FileInputStream fis = new FileInputStream(keystorePath)) {
ks.load(fis, keystorePassword.toCharArray());
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
// Make a KeyManagerFactory from the KeyStore
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keystorePassword.toCharArray());
// Get hold of the default trust manager
X509TrustManager x509Tm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
if (tm instanceof X509TrustManager) {
x509Tm = (X509TrustManager) tm;
break;
}
}
// Now make an SSL Context with our Key Manager and the default Trust Manager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, null);
return okHttpClient.newBuilder()
.sslSocketFactory(sslContext.getSocketFactory(), x509Tm)
.connectTimeout(10000, TimeUnit.MILLISECONDS)
.readTimeout(10000, TimeUnit.MILLISECONDS)
.build();
I want to use only the standard system configuration for keystore and not the custom SSL context.