8

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

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

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

谢谢你,迪帕克

4

2 回答 2

5

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

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)SSLContextFactoryandX509TrustManagerWrapper来自 jSSLutils,但其余的在 J2SE/J2EE 中可用。)

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

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

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

于 2010-09-09T09:46:57.727 回答
2

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.

于 2013-01-26T13:22:49.680 回答