Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I initialize a TrustManagerFactory with multiple sources of trust?

Tags:

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?

like image 457
varrunr Avatar asked Apr 17 '14 22:04

varrunr


People also ask

What is a trust manager factory?

public class TrustManagerFactory extends Object. This class acts as a factory for trust managers based on a source of trust material. Each trust manager manages a specific type of trust material for use by secure sockets. The trust material is based on a KeyStore and/or provider specific sources.

What is trust manager in Java?

TrustManager s are responsible for managing the trust material that is used when making trust decisions, and for deciding whether credentials presented by a peer should be accepted. TrustManager s are created by either using a TrustManagerFactory , or by implementing one of the TrustManager subclasses.


1 Answers

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.

like image 83
Pasi Avatar answered Sep 19 '22 19:09

Pasi