Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java X509 Certificate parsing and validating

I'm trying to process X509 certificates in several steps and running into a couple of problems. I'm new to JCE so I not completely up to date on everything yet.

We want to be able to parse several different X509 certificates based on different encodings (PEM, DER and PCKS7). I've exported the same certificate from https://belgium.be in PEM and PCKS7 format using FireFox (certificate including chain). I've left couple lines out that are not needed for the questions

public List<X509Certificate> parse(FileInputStream fis) {  
    /*
     * Generate a X509 Certificate initialized with the data read from the inputstream. 
     * NOTE: Generation fails when using BufferedInputStream on PKCS7 certificates.
     */
    List<X509Certificate> certificates = null;
      log.debug("Parsing new certificate.");
      certificates = (List<X509Certificate>) cf.generateCertificates(fis);
    return certificates;
  }

This code is working fine aslong as I work with a FileInputStream instead of a BufferedInputStream for PCKS7, which is quite strange already I think? But I can live with it.

The next step is to validate these certificate chains. 1) Check if all certificates have a valid date (easy) 2) Validate certificate chain using OCSP (and fallback to CRL if no OCSP URL is found in the certificate). This is where I'm not completely sure how to handle this.

I'm using the Sun JCE, but it seems there is not that much documentation available (in examples) for this?

I first made a simple implementation that only checks the chain without going through the OCSP/CRL checks.

private Boolean validateChain(List<X509Certificate> certificates) {
    PKIXParameters params;
    CertPath certPath;
    CertPathValidator certPathValidator;
    Boolean valid = Boolean.FALSE;

    params = new PKIXParameters(keyStore);
    params.setRevocationEnabled(false);

    certPath = cf.generateCertPath(certificates);
    certPathValidator = CertPathValidator.getInstance("PKIX");

    PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)  
    certPathValidator.validate(certPath, params);

      if(null != result) {
        valid = Boolean.TRUE;
      }
    return valid;
 }

This is working fine for my PEM certificate, but not for the PCKS7 certificate (same certifcate, only exported in other format). java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors.

The only difference I'm able to see is that the order in which the CertPath is formed is not the same? I was not able to figure out what was going wrong so I left this for now and kept on going with the PEM certificate, but lets call this QUESTION 1 ;)

What I wanted to implement afterwards was the OCSP checking. Apparently if I enable OCSP using: Security.setProperty("ocsp.enable", "true"); and set params.setRevocationEnabled(true); it should be able to find the OCSP URL on its own, but that does not seem to be the case. What is the standard implementation supposed to do (QUESTION 2)? java.security.cert.CertPathValidatorException: Must specify the location of an OCSP Responder

Going past this, I found a way to retrieve the OCSP url from the certificate using AuthorityInfoAccessExtension and such.

But after setting the OCSP url manually in the ocsp.url property, I'm getting an java.security.cert.CertPathValidatorException: OCSP response error: UNAUTHORIZED

It seems like I'm missing a lot of necessary steps while alot of online references say setting the ocsp.enable property should be all you need to do?

Perhaps any of you whizkids cant guide me through the process a little bit? Show me where I'm completely wrong :)

The next step would be implementing CRL checks if no OCSP was found, if anyone could point out any example or show me some documentation on this it would also be much appreciated!

Thanks!

EDIT: Since it's not picking up the properties on its own, I've been trying to set all the properties myself using the following:

    // Activate OCSP
        Security.setProperty("ocsp.enable", "true");
        // Activate CRLDP -- no idea what this is
        Security.setProperty("com.sun.security.enableCRLDP", "true");

        X509Certificate target = (X509Certificate) certPath.getCertificates().get(0);
        Security.setProperty("ocsp.responderURL","http://ocsp.pki.belgium.be/");
        Security.setProperty("ocsp.responderCertIssuerName", target.getIssuerX500Principal().getName());
        Security.setProperty("ocsp.responderCertSubjectName", target.getSubjectX500Principal().getName());
        Security.setProperty("ocsp.responderCertSerialNumber", target.getSerialNumber().toString(16));

Which gives an exception: java.security.cert.CertPathValidatorException: Cannot find the responder's certificate (set using the OCSP security properties).

like image 739
Driss Amri Avatar asked Apr 06 '12 12:04

Driss Amri


1 Answers

For future reference I'll post the answer to my own question (partly atleast)

OCSP and CRL checks are implemented in the standard Java implementation already and there is no need for custom code or other providers (BC, ..). They are disabled by default.

To enable this, you have to atleast set two parameters:

(PKIXParameters or PKIXParameterBuilder) params.setRevocationEnabled(true);
Security.setProperty("ocsp.enable", "true");

This will activate OCSP checking when you are trying to validate the certificate path (PKIXCertPathValidatorResult.validate()).

When you want to add the fallback check for CRL if no OCSP is available, add an aditional property:

System.setProperty("com.sun.security.enableCRLDP", "true");

A lot of my problems are happening due to the fact that I have to support different certificate formats (PKCS7, PEM). My implementation works fine for PEM, but since PKCS7 does NOT save ordering of the certificates in the chain it is a bit harder (http://bugs.sun.com/view_bug.do?bug_id=6238093)

X509CertSelector targetConstraints = new X509CertSelector();

targetConstraints.setCertificate(certificates.get(0));
// Here's the issue for PKCS7 certificates since they are not ordered,
// but I havent figured out how I can see what the target certificate
// (lowest level) is in the incoming certificates..

PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, targetConstraints);   

Hope this will be useful remarks for other people as well, perhaps someone can shed a light on how to find the target certificate in an unordered PKCS7 list?

like image 61
Driss Amri Avatar answered Sep 20 '22 02:09

Driss Amri