【问题标题】:How support multiple TrustStores in java SSL client application如何在 Java SSL 客户端应用程序中支持多个 TrustStore
【发布时间】:2011-04-10 03:28:58
【问题描述】:

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

我们正在考虑我们应该使用两个信任存储,一个 cacerts(默认一个随 jre 提供)和另一个包含我们在列表中动态添加/删除的服务器的证书。这将确保我们不会修改 java 的默认 TrustStore(cacerts)。

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

谢谢你, 迪帕克

【问题讨论】:

    标签: java ssl certificate truststore


    【解决方案1】:

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

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

    这将遵循以下原则:

    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 中可用。)

    有几个CertificateExceptions 您可能想要捕获(请参阅子类)。 如果您向用户进行回调,则 SSL/TLS 连接可能会因为 SSL/TLS 握手超时而第一次失败(如果回调时间过长无法回复。)

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

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

    【讨论】:

      【解决方案2】:

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

      如果您想解决 OP(原始海报)的问题而不诉诸代码更改,您可以配置您的 JVM(我仅使用 Tomcat 测试)以支持 OP 所需的配置:

      1. 不理会“打包”的 JDK cacerts 文件
      2. 将您的证书导入到单独的文件中,让您的 JAVA 应用“信任”它们

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

      所以我从这篇文章和这些页面(有一些小的改动)中找到了一个使用英特尔的绝妙解决方案:

      我曾经做过的事情:

      • 将 JVM trustStore 参数设置为我的单独密钥库文件(我将在其中导入其他证书),如下所示

      我现在做什么:

      • 将 trustStore 参数设置为“打包”的 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,但是当您这样做时它可以工作。

      【讨论】:

      • 问题是针对特定线程/连接执行此操作,而设置 javax.net.ssl.trustStore 将影响所有连接(具有特定 SSLContext 的连接除外)。此外,在这种情况下,设置javax.net.ssl.keyStore* 根本没有意义(jssecacerts 不应该包含任何私钥,因此无论如何作为“密钥库”将毫无用处)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-28
      • 1970-01-01
      • 1970-01-01
      • 2019-05-11
      • 2020-03-19
      • 2012-07-23
      • 1970-01-01
      相关资源
      最近更新 更多