我們爲SSL/TLS開發自定義JCE安全提供程序。JCE:驗證X509自簽名證書時發生異常
我們的一位用戶正在客戶端獲取服務器證書驗證失敗。這是通常的「無法找到有效的證書路徑到要求的目標」的錯誤。 (是的,證書在信任庫中。)
注意:儘管我們正在實現自定義提供程序,但我們依賴於標準JCE提供程序用於信任管理器,使用javax.net.ssl.X509TrustManager.checkServerTrusted(X509Certificate [ ]鏈,字符串)在TLS握手期間。
sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:105)
[snip]
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:146)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
...
與我們所有的用戶一樣,他們安裝了無限的安全策略jar。
服務器證書是自簽名的(不是CA)。他們使用127.0.0.1作爲主機名,因爲他們只是連接到後端進程。
JRE/JDK的缺省安裝工作(使用Sun/Oracle安全提供程序)。使用javax.net.debug輸出,我確認這些成功的連接使用相同的自簽名證書。但是,當我將一些代碼黑入到一起以簡單建立連接時,它在同一臺計算機上使用相同的信任庫,密鑰庫,證書和JDK時可以毫無問題地工作。這使用相同的驗證函數,它使用相同的證書和相同的authType字符串對X509TrustManager.checkServerTrusted()進行相同的調用。我無法解釋爲什麼checkServerTrusted()在這種情況下驗證證書,但在用戶的情況下失敗。
有沒有可能通過某種方式來調整JCE,使X509TrustManager無法驗證此證書?也許是因爲它是自簽名的,或者是因爲通用名稱是服務的名稱而不是域名?我沒有看到他們的JVM參數或安全屬性中的任何內容來表明這一點。但是也許他們正在做一些JCE調用,我不知道哪些修改了X509TrustManager的行爲?
cert的javax.net.debug輸出如下。通用名稱就是我們採用者服務的名稱。這對我來說似乎很腥。但是,它可以與默認安全提供程序一起使用。
***
Found trusted certificate:
[
[
Version: V3
Subject: CN=[snip], OU=[snip], O=[snip], L=Bangalore, ST=[snip], C=IN
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 2048 bits
modulus: [snip]
public exponent: 65537
Validity: [From: Wed Feb 17 14:45:40 IST 2016,
To: Thu Nov 20 14:45:40 IST 2070]
Issuer: CN=[snip], OU=[snip], O=[snip], L=Bangalore, ST=[snip], C=IN
SerialNumber: [ 5cf68160]
Certificate Extensions: 1
[1]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
[snip]
]
]
]
Algorithm: [SHA256withRSA]
Signature:
[snip]
]
添加一些額外的日誌後,很明顯的是,接受發行人正在填充不同無論出於何種原因。在失敗的案例中,從[trust-manager] .getAcceptedIssuers [];中返回大量已接受的發佈者。他們不包括有問題的證書。在通過的情況下,只有有問題的證書才包含在接受的發行人中。
[編輯1]更正了證書。
修正了大膽問題中的通用名稱。
[編輯3]增加了發行人接受款
此問題不是名稱檢查,因爲只有在路徑驗證成功後纔會發生此問題,並且僅適用於某些應用程序,例如, HTTPS。但是,如果/完成後,您的文本顯示「他們」(用戶?)使用127.0.0.1,但您的跟蹤顯示證書具有CN = localhost;這些名稱不是相同的名稱,嘗試時不會匹配,即使通常都是同一主機和僞接口的名稱。至於你的實際問題,我可以確認selfsigned cert和hostname = localhost工作正常,就像你顯然做的那樣。 ... –
...我想不出除(secprop)jdk.certpath.disabledAlgorithms之外的任何JVM設置,對於給定的JRE中的所有應用程序應該是相同的,並且不應該影響這種情況。最好我可以建議是嘗試與sysprop java.security.debug = certpath運行,看看它說什麼有所幫助。 : - ? –
我意識到127.0.0.1和localhost是不同的。但是,在我的測試代碼中,使用該證書成功建立連接,無論我是否使用127.0.0.1或localhost,無論是否使用我們的提供程序。 此外,我設法把錯誤的證書放在帖子中。這是來自以前的連接,我們充當服務器(沒有問題)。 我會嘗試certpath並查看給了我什麼。謝謝。 –