我正在處理嵌入式碼頭服務器和客戶端之間的客戶端證書驗證。他們都使用密鑰庫。客戶端證書由由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中的簽名證書可能很有用。
你爲什麼不通過JSSE讓信任管理者爲你做這一切? – Bruno
因爲我的服務器也在接受非cert-auth連接。我必須先讓它接受所有連接,然後在某些情況下驗證客戶端證書(如果有)。 – Ghetolay
不,您只需要使用wantClientAuth選項(而不是需要)使客戶端證書可選。 – Bruno