2012-09-17 82 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