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

后端 未结 6 1421
伪装坚强ぢ
伪装坚强ぢ 2020-12-25 15:42

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 conne

6条回答
  •  天命终不由人
    2020-12-25 16:13

    I've run into the same issue with Commons HttpClient. Working solution for my case was to create delegation chain for PKIX TrustManagers in following way:

    public class TrustManagerDelegate implements X509TrustManager {
        private final X509TrustManager mainTrustManager;
        private final X509TrustManager trustManager;
        private final TrustStrategy trustStrategy;
    
        public TrustManagerDelegate(X509TrustManager mainTrustManager, X509TrustManager trustManager, TrustStrategy trustStrategy) {
            this.mainTrustManager = mainTrustManager;
            this.trustManager = trustManager;
            this.trustStrategy = trustStrategy;
        }
    
        @Override
        public void checkClientTrusted(
                final X509Certificate[] chain, final String authType) throws CertificateException {
            this.trustManager.checkClientTrusted(chain, authType);
        }
    
        @Override
        public void checkServerTrusted(
                final X509Certificate[] chain, final String authType) throws CertificateException {
            if (!this.trustStrategy.isTrusted(chain, authType)) {
                try {
                    mainTrustManager.checkServerTrusted(chain, authType);
                } catch (CertificateException ex) {
                    this.trustManager.checkServerTrusted(chain, authType);
                }
            }
        }
    
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return this.trustManager.getAcceptedIssuers();
        }
    
    }
    

    And initialize HttpClient in following way (yes it's ugly):

    final SSLContext sslContext;
    try {
        sslContext = SSLContext.getInstance("TLS");
        final TrustManagerFactory javaDefaultTrustManager = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        javaDefaultTrustManager.init((KeyStore)null);
        final TrustManagerFactory customCaTrustManager = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        customCaTrustManager.init(getKeyStore());
    
        sslContext.init(
            null,
            new TrustManager[]{
                new TrustManagerDelegate(
                        (X509TrustManager)customCaTrustManager.getTrustManagers()[0],
                        (X509TrustManager)javaDefaultTrustManager.getTrustManagers()[0],
                        new TrustSelfSignedStrategy()
                )
            },
            secureRandom
        );
    
    } catch (final NoSuchAlgorithmException ex) {
        throw new SSLInitializationException(ex.getMessage(), ex);
    } catch (final KeyManagementException ex) {
        throw new SSLInitializationException(ex.getMessage(), ex);
    }
    
    SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
    
    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(
            RegistryBuilder.create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslSocketFactory)
                    .build()
    );
    //maximum parallel requests is 500
    cm.setMaxTotal(500);
    cm.setDefaultMaxPerRoute(500);
    
    CredentialsProvider cp = new BasicCredentialsProvider();
    cp.setCredentials(
            new AuthScope(apiSettings.getIdcApiUrl(), 443),
            new UsernamePasswordCredentials(apiSettings.getAgencyId(), apiSettings.getAgencyPassword())
    );
    
    client = HttpClients.custom()
                        .setConnectionManager(cm)
                        .build();
    

    In your case with simple HttpsURLConnection you may get by with simplified version of delegating class:

    public class TrustManagerDelegate implements X509TrustManager {
        private final X509TrustManager mainTrustManager;
        private final X509TrustManager trustManager;
    
        public TrustManagerDelegate(X509TrustManager mainTrustManager, X509TrustManager trustManager) {
            this.mainTrustManager = mainTrustManager;
            this.trustManager = trustManager;
        }
    
        @Override
        public void checkClientTrusted(
                final X509Certificate[] chain, final String authType) throws CertificateException {
            this.trustManager.checkClientTrusted(chain, authType);
        }
    
        @Override
        public void checkServerTrusted(
                final X509Certificate[] chain, final String authType) throws CertificateException {
            try {
                mainTrustManager.checkServerTrusted(chain, authType);
            } catch (CertificateException ex) {
                this.trustManager.checkServerTrusted(chain, authType);
            }
        }
    
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return this.trustManager.getAcceptedIssuers();
        }
    
    }
    

提交回复
热议问题