我們的系統中有一些用於自動生成自簽名證書的密碼,然後由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。
是的,我們發現了IP地址的問題,結果編寫了我們自己的HostnameVerifier來檢查是否匹配並返回true。最初我們有一個HostnameVerifier,它總是返回true,這只是因爲顯而易見的原因而被拋出。許多現有用戶將IP地址配置爲他們的「主機名」,我們不想積極攻擊那些。 – Trejkaz