Java/密钥库验证签名证书 [英] Java/Keystore Verify Signed certificate
问题描述
我正在研究嵌入式码头服务器和客户端之间的客户端证书身份验证.他们都使用密钥库.客户端证书由CA签署的服务器证书签署. Jetty使用2种方法来验证客户端证书javax.net.ssl.SSLEngine似乎有效,并且它们也使用上面的代码.
I'm working on a client-cert authentication between a embedded jetty server and a client. They both use keystore. The client certificate is signed by the server's certificate which is signed by a CA. Jetty use 2 method to authenticate a client certificate, javax.net.ssl.SSLEngine which seems to work and they also use the code above.
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){
...
}
我当然必须使用第二种方式... 因此,让我们专注于此代码,这是验证签名证书的好方法吗? 这是我的密钥库的转储:
Of course I must use this second way... So let's concentrate on this code, is this a good way to verify a signed certificate ? Here is a dump of my keystores :
客户端密钥库:
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
Owner: EMAILADDRESS=truc@ok.com, CN=Servlet, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR
Issuer: EMAILADDRESS=contact@greenpacs.com, CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR
...
Certificate[2]:
Owner: EMAILADDRESS=contact@greenpacs.com, CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR
Issuer: EMAILADDRESS=ghetolay@imbasoft.com, CN=Greenpacs Certificate Authority, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR
...
服务器信任库:
Entry type: trustedCertEntry
Owner: EMAILADDRESS=contact@greenpacs.com, CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR
Issuer: EMAILADDRESS=ghetolay@imbasoft.com, CN=Greenpacs Certificate Authority, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR
我不确定这些密钥库,但尝试使用其他密钥库(将CA证书添加到客户端的证书链,将证书添加到信任库),但验证仍然失败.有了这些密钥库,第一种验证方法(SSLEngine)似乎可以正常工作.
I'm not sure about these keystores but I tried with different one (adding the CA certificate to the client's certificate chain, adding certificate to the truststore) and the validation still fail. And with these keystores the first way of validation (SSLEngine) seems to work.
调试输出太大,无法将其放在此处,但这是stacktrace:
The debug output is too big to put it here but here is the stacktrace :
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,则代码可以正常工作,但是我不确定自己在做什么.
If I disable the revocation or if I set the last certificate (instead of the first) as X509CertSelector the code work but I'm not sure of what I'm doing.
我开始怀疑码头代码,但我不是证书和SSL握手方面的专家,因此它也可能来自错误的密钥库/信任库.这就是为什么我没有在码头的董事会上创建问题,而是在这里问过这个问题,以确保需要更改代码的原因.
I'm starting to doubt about the jetty code but I'm not an expert in certificate and SSL handshaking so it could also come from bad keystore/truststore. That's why I did not create a issue on jetty's board and asked here before, to be sure the code needs to be changed.
另外,了解如何在Java中验证签名证书可能很有用.
Also It could be useful to know how to validate a signed certificate in Java.
推荐答案
实际上,我不需要自己进行验证.
Actually I don't need to do the validation myself.
SSLEngine已经在执行此操作,如果客户端发送了有效的证书,则可以使用getPeerCertificateChain()获取它,如果客户端没有发送证书或无效的证书,则getPeerCertificateChain()返回null 引发异常.
The SSLEngine is already doing it and if a valid certificate is sent by the client you can get it using getPeerCertificateChain(), if no certificate or an invalid certificate is sent by the client getPeerCertificateChain() return null throws a exception.
使用码头(或我猜想的任何Java ServletContainer),您只需要检查HttpServletRequest的attribute ["javax.servlet.request.X509Certificate"]即可知道客户端是否发送了有效证书.
Using jetty (or any Java ServletContainer I guess) you just need to check the HttpServletRequest's attribute["javax.servlet.request.X509Certificate"] to know if a valid certificate was sent by the client.
我仍然不知道如何在Java中验证证书,但是这种解决方案对我来说已经足够了:)我不再需要自己做.多亏布鲁诺!
I still don't know how to validate a certificate in Java but this solution is enough for me :) I don't need to do it myself anymore. Thanks to Bruno !
这篇关于Java/密钥库验证签名证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!