WebSphere Application Server (Version 9.0.5.3 here) allows you to add TLS certificates to a custom truststore NodeDefaultTrustStore in the WebUI that is then used by the applications running on the server. That is: Both the IBM JDKs truststore as well as the custom truststore are somehow merged and used when making SSL connections in a Java app running on WAS.
That was working fine for all our backends (DB, LDAP, Webservices etc), except for one and that one was using okhttp to make the connection. It first failed with no matching cipher (which was easily fixed by adding com.ibm.jsse2.overrideDefaultTLS=true) and then failed with a PKIX error when trying to find a valid certification path. Turns out okhttp does not use both truststores, but only the JDK one without my custom CA.
What I found out:
1. If you get the TrustManager the following way, you will always end up with the JDK certs only. The certs in the custom truststore would not be there.
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
2. Getting a SSLSocketFactory using SSLContext.getInstance("SSL").getSocketFactory() will also give you the JDK certs only.
3. I tried hard to find a way to get the TrustManager out of socket factories (with reflection) but only succeeded when running on the IBM JDK on the command line. When running on a WebSphere server, the SSLSocketFactory you get looks complete different again and does not seem to contain a TrustManager object... see #2427 (comment) for the cmdline approach.
4. I found a way to get a SSLSocketFactory though that does work! HttpsURLConnection.getDefaultSSLSocketFactory() gives you one that queries both TrustStores!
I now have it working using something like this:
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
defaultJDKTrustmanger = trustManagerFactory.getTrustManagers()
...
builder.sslSocketFactory(HttpsURLConnection.getDefaultSSLSocketFactory(), defaultJDKTrustmanger)
The obvious problem here: HttpsURLConnection gives you the correct trusts, where defaultJDKTrustmanger contains only the JDKs trusted certs.
This has implications for certificate pinning and other things you want to check yourself.
Is there a way to get the NodeDefaultTrustStore using some official/inofficial Java API from my code? Or is this a bug in WAS or the IBM JDK?
#Support#SupportMigration#WebSphereApplicationServer(WAS)