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

发布于 2024-09-18 12:43:46 字数 419 浏览 6 评论 0原文

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

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

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

谢谢你, 迪帕克

In our java application we need to communicate with a list of servers on SSL using https protocol. The list of servers to communicate will change at runtime. Initially we do not have any of the server's certificate. At runtime, we will obtain a new server's certificate and add the public key certificate into a truststore; and any new https connection with the server should use the updated trust store.

We are thinking that we should use two trust stores, one cacerts(default one shipped with jre) and other containing certificates of the servers that we add/remove dynamically in a list. This will make sure that we do not modify the default TrustStore(cacerts) of java.

Please suggest how this can be achieved.
Also, is there any way to use a specific trust store only for a particular thread in java, so that other(existing and new) threads should still use the default java trueststore(cacerts), and one specific thread will use the particular truststore for the server.

Thank you,
Deepak

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不气馁 2024-09-25 12:43:46

如果您想动态导入证书,您可能需要使用自定义的x509TrustManager。这是在配置 SSLContext< 时完成的/code>,它本身用于创建 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。)

有一些 < a href="http://download.oracle.com/javase/6/docs/api/java/security/cert/CertificateException.html" rel="noreferrer">CertificateExceptions 您可能想要捕获的(请参阅子类)。
如果您向用户进行回调,则 SSL/TLS 连接可能会因为 SSL/TLS 握手超时而第一次失败(如果回调需要很长时间才能回复)。

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

您还可以通过检查 X509TrustManager 中的当前线程来对每个线程而不是每个要连接的对象进行某些操作(依赖于库):这可能会使事情在同步和信任管理器的线程管理/“意识”。

If you want to import certificate dynamically, you may need to use a custom x509TrustManager. This is done when configuring the SSLContext, which is itself used to create the SSLSocketFactory or SSLEngine.

jSSLutils is a library that lets you wrap existing trust managers and customize certain settings. You don't need it, but it may help.

This would go along these lines:

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

(The (PKIX)SSLContextFactory and X509TrustManagerWrapper come from jSSLutils, but the rest is available with the J2SE/J2EE.)

There are a few CertificateExceptions that you may want to catch (see subclasses).
If you make a callback to the user, it's possible that the SSL/TLS connection will fail the first time because of a time-out on the SSL/TLS handshake (if the callback takes too long to be replied to.)

You could then use this SSLContext as your default using SSLContext.setSSLContext(...) (from Java 6), but that's not necessarily a good idea. If you can, pass the SSLContext to the library that makes the SSL/TLS connection. How this is done varies, but Apache HTTP Client 4.x, for example, has multiple options to configure its SSL settings, one of them being by passing KeyStores, another one being by passing an SSLContext.

You could also to something per thread instead of per object that's going to connect (library dependent), by checking the current thread within the X509TrustManager: this would probably make things a bit more complex in terms of synchronization and thread management/"awareness" by the trust manager.

回首观望 2024-09-25 12:43:46

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

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

  1. 单独保留“打包”的JDK cacerts文件
  2. 将您的证书导入到一个单独的文件中,并让您的JAVA应用程序“信任”它们

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

因此,我使用这篇文章和这些页面中的英特尔找到了一个漂亮的解决方案(进行了一些细微的更改):

我过去所做的:

  • 将 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,但当您这样做时它就可以工作。

This question is so old that I have my doubts my bit will help anyone but here goes...

If you want to solve the OP's (original poster) problem without resorting to code changes you can configure your JVM (I only tested with Tomcat) to support the OP's desired config:

  1. leave the 'packaged' JDK cacerts file alone
  2. import your certs into a separate file and have your JAVA apps 'trust' them

I used to just import my additional cert into a separate file and then reference it in my JVM startup with the parameter -Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/jssecacerts with great success but I guess the recent (somewhat) JAVA security problems changed an automated inclusion of the cacerts file distributed with the SDK.

So I found a nifty solution using intel from this post and the these pages (with some minor changes):

What I used to do:

  • set the JVM trustStore parameter to my separate keystore file (that I'd import additional certs into) as follows

What I do Now:

  • Set the trustStore parameter to the 'packaged' cacerts file
  • Set the keyStore parameter to my 'additional certs' file
  • Set the keyStorePassword parameter to my keyStore's password (default is changeit)

What it looks like:

-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" \

Hope this is helpful to someone. I'm not 100% that you need to specify the keyStore password since you don't with the trustStore, but it works when you do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文