Essentially, get hold of the default trust manager, create a second trust manager that uses your own trust store. Wrap
them both in a custom trust manager implementation that delegates call to both (falling back on the other when one
fails).
TrustManagerFactorytmf= TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); // Using null here initialises the TMF with the default trust store. tmf.init((KeyStore) null);
// Get hold of the default trust manager X509TrustManagerdefaultTm=null; for (TrustManager tm : tmf.getTrustManagers()) { if (tm instanceof X509TrustManager) { defaultTm = (X509TrustManager) tm; break; } }
// Do the same with your trust store this time // Adapt how you load the keystore to your needs KeyStoremyTrustStore= KeyStore.getInstance(KeyStore.getDefaultType()); myTrustStore.load(myKeys, "password".toCharArray());
// Get hold of the default trust manager X509TrustManagermyTm=null; for (TrustManager tm : tmf.getTrustManagers()) { if (tm instanceof X509TrustManager) { myTm = (X509TrustManager) tm; break; } }
// Wrap it in your own class. finalX509TrustManagerfinalDefaultTm= defaultTm; finalX509TrustManagerfinalMyTm= myTm; X509TrustManagercustomTm=newX509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { // If you're planning to use client-cert auth, // merge results from "defaultTm" and "myTm". return finalDefaultTm.getAcceptedIssuers(); }
@Override publicvoidcheckServerTrusted(X509Certificate[] chain, String authType)throws CertificateException { try { finalMyTm.checkServerTrusted(chain, authType); } catch (CertificateException e) { // This will throw another CertificateException if this fails too. finalDefaultTm.checkServerTrusted(chain, authType); } }
@Override publicvoidcheckClientTrusted(X509Certificate[] chain, String authType)throws CertificateException { // If you're planning to use client-cert auth, // do the same as checking the server. finalDefaultTm.checkClientTrusted(chain, authType); } };
// You don't have to set this as the default context, // it depends on the library you're using. SSLContext.setDefault(sslContext);
You don’t have to set that context as the default context. How you use it depends on the client library you’re using (
and where it gets its socket factories from).
This being said, in principle, you’d always have to update the truststore as required anyway. The Java 7 JSSE Reference
Guide had an “important note” about this, now downgraded to just a “note” in version 8 of the same guide:
The JDK ships with a limited number of trusted root certificates in the
java-home/lib/security/cacerts file. As documented in keytool reference pages, it is your responsibility to maintain (
that is, add and remove) the certificates contained in this file if you use this file as a truststore.
Depending on the certificate configuration of the servers that you contact, you may need to add additional root
certificates. Obtain the needed specific root certificates from the appropriate vendor.