2012-05-03 19 views
16

我們的系統中有一些用於自動生成自簽名證書的密碼,然後由Jetty使用。如果給定主機的關鍵已經存在,那麼什麼都不會發生,但如果它不存在,我們生成一個新的密鑰,這樣的:如果Jetty的密鑰存儲區中存在多個證書,它將如何選擇?

public void generateKey(String commonName) { 
    X500Name x500Name = new X500Name("CN=" + commonName); 
    CertAndKeyGen keyPair = new CertAndKeyGen("DSA", "SHA1withDSA"); 
    keyPair.generate(1024); 
    PrivateKey privateKey = keyPair.getPrivateKey(); 
    X509Certificate certificate = keyPair.getSelfCertificate(x500Name, 20*365*24*60*60); 
    Certificate[] chain = { certificate }; 
    keyStore.setEntry(commonName, privateKey, "secret".toCharArray(), chain); 
} 

這一切,只要能正常工作,因爲只有一個密鑰和證書在關鍵商店。一旦你有多個按鍵,奇怪的事情發生了,當你試圖連接:

java.io.IOException: HTTPS hostname wrong: should be <127.0.0.1> 

這是一個相當神祕的錯誤,但我終於寫它連接到服務器,並斷言,一個單元測試,以追查的證書上的CN與主機名相匹配。我發現的非常有趣 - 碼頭似乎隨意選擇向客戶提供哪種證書,但採用一致的方式。

例如:

  • 如果 「CN =本地主機」 和 「CN = cheese.mydomain」 是在密鑰存儲,它總是選擇 「CN = cheese.mydomain」。
  • 如果「CN = 127.0.0.1」和「CN = cheese.mydomain」在密鑰存儲區中,則始終選擇「CN = cheese.mydomain」。
  • 如果密鑰存儲區中存在「CN = 192.168.222.100」(cheese.mydomain)和「CN = cheese.mydomain」,則始終選擇「CN = 192.168.222.100」。

我寫了一些代碼,循環通過商店中的證書打印出來,發現它不一致地選擇第一個證書或任何這樣的瑣事。

它究竟使用什麼標準?起初我以爲localhost很特別,但後來的第三個例子完全讓我感到困惑。

我認爲這是在某種程度上由KeyManagerFactory決定的,在我的情況下是SunX509。

回答

13

這確實最終由KeyManager(通常從KeyManagerFactory獲得)決定。

密鑰庫可以有多個證書存儲在不同的別名下。如果沒有通過certAlias in the Jetty configuration明確配置別名,那麼SunX509實現將選擇第一個別名,它找到了一個私鑰和一個適用於所選密碼套件的正確類型的密鑰(通常是RSA,但這裏可能是DSA) 。選擇邏輯還有一點,如果你看看Sun provider implementation,但你不應該真的依賴一般的訂單,只需要別名。

你當然可以給你自己的碼頭SSLContext與你自己的X509KeyManager選擇別名。你將不得不實施:

chooseServerAlias(String keyType, Principal[] issuers, Socket socket) 

不幸的是,除了keyTypeissuers,所有你必須做出決定是socket本身。充其量,您獲得的有用信息是本地IP地址和遠程IP地址。

除非您的服務器正在偵聽同一端口上的多個IP地址,否則您將始終獲得相同的本地IP地址。(很明顯,你至少有兩個:127.0.0.1192.168.222.100,但我懷疑你對本地主機不感興趣,除了你自己的測試。)你需要服務器端的服務器名稱指示(SNI)支持才能夠根據請求的主機名(由支持它的客戶端)做出決定。不幸的是,SNI was only introduced in Java 7, but only on the client side

您將面臨的另一個問題是Java clients will complain about IP addresses in the Subject DN's CN。有些瀏覽器會容忍這種情況,但這不符合HTTPS規範(RFC 2818)。 IP地址必須是IP地址類型的主題備用名稱條目。

+0

是的,我們發現了IP地址的問題,結果編寫了我們自己的HostnameVerifier來檢查是否匹配並返回true。最初我們有一個HostnameVerifier,它總是返回true,這只是因爲顯而易見的原因而被拋出。許多現有用戶將IP地址配置爲他們的「主機名」,我們不想積極攻擊那些。 – Trejkaz

相關問題