How do I initialize a TrustManagerFactory with multiple sources of trust?
java, jsse, ssl, x509
Solution
In `trustMgrFactory.init(keystore);` you're configuring defaultTrustManager with your own personal keystore, not the system default keystore.
Based on reading the source code for sun.security.ssl.TrustManagerFactoryImpl, it looks like `trustMgrFactory.init((KeyStore) null);` would do exactly what you need (load the system default keystore), and based on quick testing, it seems to work for me.
Problem
My application has a personal keystore containing trusted self-signed certificates for use in the local network - say `mykeystore.jks`. I wish to be able to connect to public sites(say google.com) as well as ones in my local network using self-signed certificates which have been provisioned locally. The problem here is that, when I connect to https://google.com, path building fails, because setting my own keystore overrides the default keystore containing root CAs bundled with the JRE, reporting the exception ``` sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target ``` However, if I import a CA certificate into my own keystore(`mykeystore.jks`) it works fine. Is there a way to support both? I have my own TrustManger for this purpose, ``` public class CustomX509TrustManager implements X509TrustManager { X509TrustManager defaultTrustManager; public MyX509TrustManager(KeyStore keystore) { TrustManagerFactory trustMgrFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustMgrFactory.init(keystore); TrustManager trustManagers[] = trustMgrFactory.getTrustManagers(); for (int i = 0; i < trustManagers.length; i++) { if (trustManagers[i] instanceof X509TrustManager) { defaultTrustManager = (X509TrustManager) trustManagers[i]; return; } } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { try { defaultTrustManager.checkServerTrusted(chain, authType); } catch (CertificateException ce) { /* Handle untrusted certificates */ } } } ``` I then initialize the SSLContext, ``` TrustManager[] trustManagers = new TrustManager[] { new CustomX509TrustManager(keystore) }; SSLContext customSSLContext = SSLContext.getInstance("TLS"); customSSLContext.init(null, trustManagers, null); ``` and set the socket factory, ``` HttpsURLConnection.setDefaultSSLSocketFactory(customSSLContext.getSocketFactory()); ``` The main program, ``` URL targetServer = new URL(url); HttpsURLConnection conn = (HttpsURLConnection) targetServer.openConnection(); ``` If I don't set my own trust managers, it connects to https://google.com just fine. How do I get a "default trust manager" which points to the default key store?