2010-09-09 70 views
7

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

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

请建议如何可以做到这一点。 此外,有没有什么办法可以使用特定的信托商店只在Java特定线程,让其他(现有的和新的)线程应该仍使用默认的Java trueststore区(cacerts),和一个特定的线程将使用特殊信任为服务器。

谢谢 迪帕克

回答

5

如果要动态导入证书,您可能需要使用自定义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)SSLContextFactory而来X509TrustManagerWrapper从jSSLutils,但其余的是可用的J2SE/J2EE)

有几个CertificateExceptions你可能想要赶上(见子类)。 如果您对用户进行回拨,由于SSL/TLS握手超时(如果回调需要太长时间才能回复),SSL/TLS连接可能会首次失败。

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

通过检查X509TrustManager中的当前线程,您也可以针对每个线程而不是每个将要连接的对象(库依赖):这可能会使事情在同步和线程管理/信任管理者的“意识”。

+0

它对我有效..感谢 – Nayeem 2015-10-13 17:06:44

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并参数设置为“打包” cacerts文件 - 密钥存储参数设置为我的“额外证书”文件 - 设置ke yStorePassword参数到我的密钥库密码(默认为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,但它在你使用的时候有效。

+1

问题是关于为特定的线程/连接执行此操作,而设置'javax.net.ssl.trustStore'会影响所有连接(除了那些具有其特定的'SSLContext'的连接) 。另外,在这种情况下,根本不需要设置'javax.net.ssl.keyStore *'(并且'jssecacerts'不应该包含任何私钥,因此无论如何都不会用作“密钥库”)。 – Bruno 2013-01-26 14:26:13