2010-09-09 71 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