2017-07-31 83 views
1

我們爲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]增加了發行人接受款

+0

此問題不是名稱檢查,因爲只有在路徑驗證成功後纔會發生此問題,並且僅適用於某些應用程序,例如, HTTPS。但是,如果/完成後,您的文本顯示「他們」(用戶?)使用127.0.0.1,但您的跟蹤顯示證書具有CN = localhost;這些名稱不是相同的名稱,嘗試時不會匹配,即使通常都是同一主機和僞接口的名稱。至於你的實際問題,我可以確認selfsigned cert和hostname = localhost工作正常,就像你顯然做的那樣。 ... –

+0

...我想不出除(secprop)jdk.certpath.disabledAlgorithms之外的任何JVM設置,對於給定的JRE中的所有應用程序應該是相同的,並且不應該影響這種情況。最好我可以建議是嘗試與sysprop java.security.debug = certpath運行,看看它說什麼有所幫助。 : - ? –

+0

我意識到127.0.0.1和localhost是不同的。但是,在我的測試代碼中,使用該證書成功建立連接,無論我是否使用127.0.0.1或localhost,無論是否使用我們的提供程序。 此外,我設法把錯誤的證書放在帖子中。這是來自以前的連接,我們充當服務器(沒有問題)。 我會嘗試certpath並查看給了我什麼。謝謝。 –

回答

0

事實證明,這是與緩存信任管理的問題。

無論是默認提供程序還是我們的自定義提供程序,信任管理器最初都是通過cacerts信任庫實例化的。

對於默認提供程序,新的信任管理器稍後將使用javax.net.ssl實例化。trustStore指定的信任庫。我們的自定義提供者只是重新使用之前實例化的cacerts信任管理器。

解決方案:實例化一個新的信任管理器,它將遵循javax.net.ssl.trustStore。