如何在java SSL客户端应用程序中支持多个TrustStore

时间:2010-09-09 08:13:58

标签: java ssl certificate truststore

在我们的java应用程序中,我们需要使用https协议与SSL上的服务器列表进行通信。要通信的服务器列表将在运行时更改。最初我们没有任何服务器的证书。在运行时,我们将获得新服务器的证书并将公钥证书添加到信任库中;与服务器的任何新的https连接都应该使用更新的信任库。

我们认为我们应该使用两个信任库,一个cacerts(默认一个jre附带)和其他包含我们在列表中动态添加/删除的服务器的证书。这将确保我们不修改java的默认TrustStore(cacerts)。

请建议如何实现这一目标。 此外,有没有办法只为java中的特定线程使用特定的信任存储,以便其他(现有的和新的)线程仍应使用默认的java trueststore(cacerts),并且一个特定的线程将使用特定的信任库服务器。

谢谢你, 迪帕克

2 个答案:

答案 0 :(得分:5)

如果要动态导入证书,可能需要使用自定义x509TrustManager。这在配置SSLContext时完成,jSSLutils本身用于创建SSLSocketFactorySSLEngine

CertificateExceptions是一个库,可让您包装现有的信任管理器并自定义某些设置。你不需要它,但它可能有所帮助。

这将遵循以下几点:

PKIXSSLContextFactory sslContextFactory = new PKIXSSLContextFactory();
sslContextFactory.setTrustManagerWrapper(new X509TrustManagerWrapper() {
    @Override
    public X509TrustManager wrapTrustManager(final X509TrustManager origManager) {
        return new X509TrustManager() { 
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return origManager.getAcceptedIssuers();
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain,
                                                   String authType)
                    throws CertificateException {
                try {
                    // This will call the default trust manager
                    // which will throw an exception if it doesn't know the certificate
                    origManager.checkServerTrusted(chain, authType);
                } catch (CertificateException e) {
                    // If it throws an exception, check what this exception is
                    // the server certificate is in chain[0], you could
                    // implement a callback to the user to accept/refuse
                }
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain,
                                                   String authType)
                    throws CertificateException {
                origManager.checkClientTrusted(chain, authType);
            }
        };
    }
});
SSLContext sslContext = sslContextFactory.buildSSLContext();

(PKIX)SSLContextFactoryX509TrustManagerWrapper来自jSSLutils,但其余部分可用于J2SE / J2EE。)

您可能想要捕获一些{{3}}(请参阅子类)。 如果您对用户进行回调,则SSL / TLS连接可能会因SSL / TLS握手超时而失败(如果回调需要很长时间才能回复。)

然后,您可以使用此SSLContext作为默认值SSLContext.setSSLContext(...)(来自Java 6),但这不一定是个好主意。如果可以,请将SSLContext传递给建立SSL / TLS连接的库。如何做到这一点各不相同,但Apache HTTP Client 4.x有多个选项来配置其SSL设置,其中一个是传递KeyStore,另一个是传递SSLContext

通过检查X509TrustManager中的当前线程,您还可以使用每个线程而不是每个要连接的对象(依赖于库):这可能会使同步方面的事情变得更复杂一些线程管理/信任经理的“意识”。

答案 1 :(得分:2)

这个问题太老了,我怀疑我会帮助任何人,但这里有...

如果您想在不诉诸代码更改的情况下解决OP(原始海报)问题,您可以配置您的JVM(我只测试过Tomcat)以支持OP所需的配置: 1.单独留下'打包'的JDK cacerts文件 2.将您的证书导入一个单独的文件,让您的JAVA应用程序“信任”他们

我过去只是将我的附加证书导入一个单独的文件,然后在我的JVM启动中使用参数'-Djavax.net.ssl.trustStore = $ JAVA_HOME / jre / lib / security / jssecacerts'引用它,取得了巨大的成功但我想最近(有些)JAVA安全问题改变了随SDK一起分发的cacerts文件的自动包含。

所以我发现了一篇很棒的解决方案,使用了这篇文章中的英特尔和这些页面(稍作修改):   - http://www.coderanch.com/t/529157/Tomcat/Configure-Tomcat-trust-store-cacerts   - http://andyarismendi.blogspot.com/2012/01/changing-tomcats-ca-trust-keystore-file.html

我以前做的事情:   - 将JVM trustStore参数设置为我的单独密钥库文件(我将其他证书导入),如下所示

我现在做什么:   - 将trustStore参数设置为'packed'cacerts文件   - 将keyStore参数设置为我的“其他证书”文件   - 将keyStorePassword参数设置为我的keyStore密码(默认为changeit)

它看起来像什么:

-Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/cacerts \
-Djavax.net.ssl.keyStore=$JAVA_HOME/jre/lib/security/jssecacerts \
-Djavax.net.ssl.keyStorePassword="changeit" \

希望这对某人有帮助。我不是100%你需要指定keyStore密码,因为你没有使用trustStore,但是当你这样做时它会起作用。