在java中使用自定义信任库以及默认信任库 [英] Using a custom truststore in java as well as the default one

查看:143
本文介绍了在java中使用自定义信任库以及默认信任库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm writing an application in Java which connects to two web servers via HTTPS. One got a certificate trusted via the default chain of trust, the other uses a self signed certificate. Of course, connecting to the first server worked out of the box, whereas connecting to the server with the self signed certificate did not work until I created a trustStore with the certificate from that server. However, the connection to the by default trusted server does not work any more, because apparently the default trustStore gets to be ignored once I created my own.

我发现一个解决方案是将证书从默认的trustStore添加到我自己的。但是,我不喜欢这个解决方案,因为它需要我继续管理那个trustStore。 (我不能假设这些证书在可预见的将来仍然是静态的,对吗?)

One solution I found was to add the certificates from the default trustStore to my own. However, I don't like this solution, because it requires me to keep managing that trustStore. (I cannot assume these certificates remain static in the foreseeable future, right?)

除此之外我发现了两个有着类似问题的5岁线程:

Apart from that I found two 5 year old threads with a similar problem:

在JVM中注册多个密钥库

如何为Java服务器提供多个SSL证书

它们都深入到Java SSL基础架构中。我希望到现在有一​​个更方便的解决方案,我可以在我的代码的安全审查中轻松解释。

They both go deep into the Java SSL infrastructure. I was hoping that by now there is a more convenient solution which I can explain easily in a security review of my code.

推荐答案

您可以使用与我在上一个答案中提到的类似模式(针对其他问题)。

You could use a similar pattern to what I've mentioned in a previous answer (for a different problem).

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

Essentially, get hold of the default trust manager, create a second trust manager that uses your own trust store. Wrap them both in a custom trust manager implementation that delegates call to both (falling back on the other when one fails).

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);

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

You don't have to set that context as the default context. How you use it depends on the client library you're using (and where it gets its socket factories from).

原则上说,无论如何,您总是必须根据需要更新信任库。 Java 7 JSSE参考指南有一个关于此的重要说明,现在降级为note在同一指南的第8版中

This being said, in principle, you'd always have to update the truststore as required anyway. The Java 7 JSSE Reference Guide had an "important note" about this, now downgraded to just a "note" in version 8 of the same guide:


JDK在
java-home / lib / security / cacerts文件中附带有限数量的受信任根证书。如keytool
参考页中所述,如果您将此
文件用作信任库,则您有责任维护(即添加
并删除)此文件中包含的证书。

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中使用自定义信任库以及默认信任库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆