2012-09-17 157 views
5

我正在處理嵌入式碼頭服務器和客戶端之間的客戶端證書驗證。他們都使用密鑰庫。客戶端證書由由CA簽名的服務器證書籤署。 Jetty使用2方法來驗證客戶端證書javax.net.ssl.SSLEngine,它似乎可以正常工作,他們也使用上面的代碼。Java/Keystore驗證簽名證書

List<X509Certificate> certList = Certificate chain sent by the client 
KeyStore truststore = server's truststore 

//No use of CRL/OSCP/CRLDP 
_crls = null; 
_enableOCSP = false; 
_enableCRLDP = false; 

try{ 
X509CertSelector certSelect = new X509CertSelector(); 
certSelect.setCertificate((X509Certificate) certList.get(0)); 

// Configure certification path builder parameters 
PKIXBuilderParameters pbParams = new PKIXBuilderParameters(truststore, certSelect); 
pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList))); 

// Set maximum certification path length 
pbParams.setMaxPathLength(-1); 

// Enable revocation checking 
pbParams.setRevocationEnabled(true); 

// Set static Certificate Revocation List 
if (_crls != null && !_crls.isEmpty()) 
    pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(_crls))); 

    // Enable On-Line Certificate Status Protocol (OCSP) support 
    if (_enableOCSP) 
     Security.setProperty("ocsp.enable","true"); 

    // Enable Certificate Revocation List Distribution Points (CRLDP) support 
    if (_enableCRLDP) 
     System.setProperty("com.sun.security.enableCRLDP","true"); 

// Build certification path 
CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);    

// Validate certification path 
CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams); 
}catch(GeneralSecurityException gse){ 
... 
} 

當然,我必須使用此第二種方式...... 因此,讓我們專注於這個代碼,這是檢驗簽名證書的好辦法? 這裏是我的密鑰庫的轉儲:

客戶端密鑰庫:

Entry type: PrivateKeyEntry 
Certificate chain length: 2 
Certificate[1]: 
Owner: [email protected], CN=Servlet, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR 
Issuer: [email protected], CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR 
... 

Certificate[2]: 
Owner: [email protected], CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR 
Issuer: [email protected], CN=Greenpacs Certificate Authority, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR 
... 

Server信任:

Entry type: trustedCertEntry 

Owner: [email protected], CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR 
Issuer: [email protected], CN=Greenpacs Certificate Authority, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR 

我不知道這些密鑰庫,但我有不同的一個嘗試(添加CA證書添加到客戶端的證書鏈中,將證書添加到信任庫),驗證仍然失敗。通過這些密鑰庫,第一種驗證方式(SSLEngine)似乎可行。

調試輸出是太大了,把它放在這裏,但這裏是堆棧跟蹤:

java.security.cert.CertPathValidatorException: Could not determine revocation status 
    at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:153) 
    at sun.security.provider.certpath.PKIXCertPathValidator.doValidate(PKIXCertPathValidator.java:325) 
    at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:187) 
    at java.security.cert.CertPathValidator.validate(CertPathValidator.java:267) 
    at MainClass.main(MainClass.java:75) 
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197) 
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255) 
    at sun.security.provider.certpath.CrlRevocationChecker.buildToNewKey(CrlRevocationChecker.java:583) 
    at sun.security.provider.certpath.CrlRevocationChecker.verifyWithSeparateSigningKey(CrlRevocationChecker.java:459) 
    at sun.security.provider.certpath.CrlRevocationChecker.verifyRevocationStatus(CrlRevocationChecker.java:339) 
    at sun.security.provider.certpath.CrlRevocationChecker.verifyRevocationStatus(CrlRevocationChecker.java:248) 
    at sun.security.provider.certpath.CrlRevocationChecker.check(CrlRevocationChecker.java:189) 
    at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:131) 
    ... 4 more 

如果我禁用撤銷或者如果我設置的最後一個證書(而不是第一)作爲X509CertSelector代碼工作但我不確定我在做什麼。

我開始懷疑碼頭碼,但我不是證書和SSL握手方面的專家,所以它也可能來自錯誤的密鑰庫/信任庫。這就是爲什麼我沒有在碼頭板上創建問題並在此之前提出問題,以確保代碼需要更改。

另外,瞭解如何驗證Java中的簽名證書可能很有用。

+0

你爲什麼不通過JSSE讓信任管理者爲你做這一切? – Bruno

+0

因爲我的服務器也在接受非cert-auth連接。我必須先讓它接受所有連接,然後在某些情況下驗證客戶端證書(如果有)。 – Ghetolay

+4

不,您只需要使用wantClientAuth選項(而不是需要)使客戶端證書可選。 – Bruno

回答

0

請檢查您的證書CRL或OCSP進行訪問,你可以找到在證書等信息,如

[1]CRL Distribution Point 
    Distribution Point Name: 
      Full Name: 
       URL=http://crl.verisign.com/pca2-g2.crl 
+0

我不使用任何CRL,OSCP或CRLDP。我的證書上沒有這樣的行。此外,所顯示的代碼並不完整,但對於CRL/OSCP/CRLDP有一些「如果」,但這些「如果」從未達到,因爲我沒有設置這些選項。我是不是該 ?這是絕對必要的嗎? – Ghetolay

0

其實我並不需要做驗證自己。

的SSLEngine的是已經在做了,如果一個有效的證書是由客戶端發送,您可以在使用getPeerCertificateChain()得到,如果沒有證書或證書無效,由客戶getPeerCertificateChain()返回NULL拋出一個發送例外。

使用jetty(或任何Java ServletContainer我猜)你只需要檢查HttpServletRequest的屬性[「javax.servlet.request.X509Certificate」]來知道客戶端是否發送了有效的證書。

我仍然不知道如何在Java中驗證證書,但這種解決方案對我來說已經足夠了:)我不需要再自己去做了。感謝布魯諾!

+0

getPeerCertificateChain()不返回null,它會引發異常。 – EJP