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

我正在编写一个Java应用程序,通过HTTPS连接到两个Web服务器。 一个通过默认信任链得到一个可信的证书,另一个使用自签名证书。 当然,连接到第一台服务器的工作,而使用自签名证书连接到服务器不工作,直到我用该服务器的证书创build一个信任存储。 但是,默认情况下,受信任服务器的连接不再起作用,因为显然默认的trustStore在创build自己的服务器时会被忽略。

我find的一个解决scheme是从默认的trustStore添加证书到我自己的。 但是,我不喜欢这个解决scheme,因为它需要我继续pipe理那个trustStore。 (我不能认为这些证书在可预见的将来会保持不变,对吗?)

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

在JVM中注册多个密钥库

我怎样才能有一个Java服务器的多个SSL证书

他们都深入到Java的SSL基础设施。 我希望现在有一个更方便的解决scheme,我可以很容易地解释我的代码的安全审查。

你可以使用一个类似的模式,我在之前的回答中提到(针对不同的问题)。

从本质上讲,掌握默认的信任pipe理器,创build第二个使用自己的信任存储的信任pipe理器。 将它们都包装在委托调用两者的自定义信任pipe理器实现中(当一个失败的时候再次落在另一个实例上)。

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参考指南”对此有一个“重要提示”,现在在同一指南的第8版中降级为“注释” :

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

根据您联系的服务器的证书configuration,您可能需要添加其他根证书。 从相应的供应商获取所需的特定根证书。