我的应用程序有一个个人 keystore ,其中包含供本地网络使用的受信任的自签名证书,例如mykeystore.jks。我希望能够使用本地提供的自签名证书连接到公共(public)站点(例如google.com)以及我本地网络中的公共(public)站点。

这里的问题是,当我连接到https://google.com时,路径构建失败,因为设置自己的 keystore 会覆盖包含与JRE bundle 在一起的根CA的默认 keystore ,从而报告异常

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

但是,如果我将CA证书导入我自己的 keystore (mykeystore.jks),则可以正常工作。有两种方法都可以支持吗?

为此,我有自己的TrustManger,
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 */
            }
        }
    }

然后,我初始化SSLContext,
TrustManager[] trustManagers =
            new TrustManager[] { new CustomX509TrustManager(keystore) };
SSLContext customSSLContext =
        SSLContext.getInstance("TLS");
customSSLContext.init(null, trustManagers, null);

并设置 socket 工厂,
HttpsURLConnection.setDefaultSSLSocketFactory(customSSLContext.getSocketFactory());

主程序
URL targetServer = new URL(url);
HttpsURLConnection conn = (HttpsURLConnection) targetServer.openConnection();

如果我没有设置我自己的信任管理器,那么它就可以连接到https://google.com了。如何获得指向默认 keystore 的“默认信任管理器”?

最佳答案

trustMgrFactory.init(keystore);中,您要使用自己的个人 keystore (而不是系统默认 keystore )配置defaultTrustManager。

基于阅读sun.security.ssl.TrustManagerFactoryImpl的源代码,看起来trustMgrFactory.init((KeyStore) null);可以完全满足您的需要(加载系统默认 keystore ),并且基于快速测试,它似乎对我有用。

关于java - 如何使用多个信任源初始化TrustManagerFactory?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23144353/

10-13 04:20