Java/Keystore Verify Signed certificate

末鹿安然 提交于 2020-02-02 03:14:06

问题


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 :

Client Keystore :

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 
...

Server truststore :

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

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.

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

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.

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.

Also It could be useful to know how to validate a signed certificate in Java.


回答1:


Please check your certificate CRL or OCSP is accessible, you can find such information in certificate, such as

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



回答2:


Actually I don't need to do the validation myself.

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.

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.

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 !



来源:https://stackoverflow.com/questions/12456079/java-keystore-verify-signed-certificate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!