java - 在 java 中使用自定义信任库以及默认信任库

标签 java ssl keystore truststore

我正在用 Java 编写一个应用程序,它通过 HTTPS 连接到两个 Web 服务器。一个通过默认信任链获得受信任的证书,另一个使用自签名证书。当然,连接到第一台服务器是开箱即用的,而使用自签名证书连接到服务器是行不通的,直到我使用来自该服务器的证书创建了一个 trustStore。但是,默认情况下与受信任服务器的连接不再起作用,因为显然,一旦我创建了自己的信任库,默认信任库就会被忽略。

我找到的一个解决方案是将默认 trustStore 中的证书添加到我自己的。但是,我不喜欢这个解决方案,因为它需要我继续管理那个 trustStore。 (我不能假设这些证书在可预见的 future 保持不变,对吧?)

除此之外,我发现两个 5 年前的线程有类似的问题:

Registering multiple keystores in JVM

How can I have multiple SSL certificates for a Java server

他们都深入研究了 Java SSL 基础架构。我希望现在有一个更方便的解决方案,我可以在对我的代码进行安全审查时轻松解释它。

最佳答案

您可以使用与我在 previous answer 中提到的类似的模式(针对不同的问题)。

基本上,获取默认信任管理器,创建使用您自己的信任存储的第二个信任管理器。将它们都包装在一个自定义信任管理器实现中,该实现将调用委托(delegate)给两者(当一个失败时回退到另一个)。

TrustManagerFactory tmf = 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
X509TrustManager defaultTm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
    if (tm instanceof X509TrustManager) {
        defaultTm = (X509TrustManager) tm;
        break;
    }
}

FileInputStream myKeys = new FileInputStream("truststore.jks");

// Do the same with your trust store this time
// Adapt how you load the keystore to your needs
KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
myTrustStore.load(myKeys, "password".toCharArray());

myKeys.close();

tmf = TrustManagerFactory
    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(myTrustStore);

// Get hold of the default trust manager
X509TrustManager myTm = null;
for (TrustManager tm : tmf.getTrustManagers()) {
    if (tm instanceof X509TrustManager) {
        myTm = (X509TrustManager) tm;
        break;
    }
}

// Wrap it in your own class.
final X509TrustManager finalDefaultTm = defaultTm;
final X509TrustManager finalMyTm = myTm;
X509TrustManager customTm = new X509TrustManager() {
    @Override
    public X509Certificate[] getAcceptedIssuers() {
        // If you're planning to use client-cert auth,
        // merge results from "defaultTm" and "myTm".
        return finalDefaultTm.getAcceptedIssuers();
    }

    @Override
    public void checkServerTrusted(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
    public void checkClientTrusted(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);
    }
};


SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { customTm }, null);

// You don't have to set this as the default context,
// it depends on the library you're using.
SSLContext.setDefault(sslContext);

您不必将该上下文设置为默认上下文。你如何使用它取决于你使用的客户端库(以及它从哪里获取它的套接字工厂)。


话虽如此,原则上,无论如何您总是必须根据需要更新信任库。 Java 7 JSSE 引用指南对此有一个“重要说明”,现在降级为 "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.

关于java - 在 java 中使用自定义信任库以及默认信任库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24555890/

相关文章:

java - JUnit:是否有执行并行测试的聪明方法?

.htaccess - 如何将所有传入请求重定向到 https?

ubuntu - 如何在 Ubuntu 的本地主机上安装 SSL?

java - HTTPS 上的 Weblogic 服务器 SSL 问题

Java网络驱动程序: How to save the page same as "save page as" in firefox?

java - 如何在我的 ModelInput 类中使用 Joshua Bloch 版本所描述的构建器模式?

php - 如何将现有套接字转换为使用 TLS/SSL?

android - 如何将 Android 调试 keystore 放入颠覆存储库,然后让 Eclipse 使用它?

java - 在spring xml文件中隐藏数据源密码

java - 是否有递归检查矩阵对角线上是否有字母序列