2
votes

I am having a chain of X509Certificates starting with user certificate and ending with trusted CA certificate. For the test, I am experimenting with Google certificates.

I want to check the revocation status of every certificate in Certificate chain.

I am using following code:

public static boolean isCertChainValid(ArrayList<X509Certificate> certificateList) {

    try {

        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

        CertPath certPath = certificateFactory.generateCertPath(certificateList);

        CertPathValidator validator = CertPathValidator.getInstance("PKIX");

        KeyStore keystore = KeyStore.getInstance("JKS");
        InputStream is = new FileInputStream(System.getProperty("java.home") + "/lib/security/" + "cacerts");
        keystore.load(is, "changeit".toCharArray());

        PKIXParameters params = new PKIXParameters(keystore);

        params.setRevocationEnabled(true);

        Security.setProperty("ocsp.enable", "true");
        System.setProperty("com.sun.net.ssl.checkRevocation", "true");
        System.setProperty("com.sun.security.enableCRLDP", "true");

        PKIXCertPathValidatorResult r = (PKIXCertPathValidatorResult) validator.validate(certPath, params);
        return true;
    } catch (CertificateException e) {
        throw new RuntimeException(e);

    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);

    } catch (KeyStoreException e) {
        throw new RuntimeException(e);

    } catch (IOException e) {
        throw new RuntimeException(e);

    } catch (InvalidAlgorithmParameterException e) {
        throw new RuntimeException(e);

    } catch (CertPathValidatorException e) {
        throw new RuntimeException(e);
    }
}

This is how I get list of certificates:

public static void main(String args[]) throws Exception {

    CertVal certVal = new CertVal(new File("/home/varun/Documents/SampleCerts/google.pem"), "X.509");
    X509Certificate cert = (X509Certificate) certVal.getCert();

    certVal = new CertVal(new File("/home/varun/Documents/SampleCerts/google.int.pem"), "X.509");
    X509Certificate int_cert = (X509Certificate) certVal.getCert();

    certVal = new CertVal(new File("/home/varun/Documents/SampleCerts/google.root.pem"), "X.509");
    X509Certificate root_cert = (X509Certificate) certVal.getCert();

    System.out.println(cert.toString());

    ArrayList<X509Certificate> cList = new ArrayList<>();
    cList.add(cert);
    cList.add(int_cert);
    cList.add(root_cert);

    System.out.println(isCertChainValid(cList));
}

google.pem, google.int.pem, google.root.pem are the end, intermediate and root certificates respectively obtained using the export option in browser.

CertVal is a class made by me that will import certificate from file and its method will return certificate object. It is working fine and end certificate is nicely printed as shown below:

[ [ Version: V3 Subject: CN=*.google.com, O=Google Inc, L=Mountain View, ST=California, C=US Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

Key: Sun EC public key, 256 bits public x coord: 46177506158937302063723158048612066903199153823785912505310712817097913459047 public y coord: 113809014154880901150321029617294838083005712679903474974082163637608868220331 parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7) Validity: [From: Thu Jun 16 14:07:32 IST 2016, To: Thu Sep 08 13:59:00 IST 2016] Issuer: CN=Google Internet Authority G2, O=Google Inc, C=US SerialNumber: [
51e47ed1 28a4436e]

Certificate Extensions: 9 [1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false AuthorityInfoAccess [ [ accessMethod: caIssuers accessLocation: URIName: http://pki.google.com/GIAG2.crt ,
accessMethod: ocsp accessLocation: URIName: http://clients1.google.com/ocsp ] ]

[2]: ObjectId: 2.5.29.35 Criticality=false AuthorityKeyIdentifier [ KeyIdentifier [ 0000: 4A DD 06 16 1B BC F6 68 B5 76 F5 81 B6 BB 62 1A J......h.v....b. 0010: BA 5A 81 2F
.Z./ ] ]

[3]: ObjectId: 2.5.29.19 Criticality=true BasicConstraints:[
CA:false PathLen: undefined ]

[4]: ObjectId: 2.5.29.31 Criticality=false CRLDistributionPoints [
[DistributionPoint: [URIName: http://pki.google.com/GIAG2.crl] ]]

[5]: ObjectId: 2.5.29.32 Criticality=false CertificatePolicies [
[CertificatePolicyId: [1.3.6.1.4.1.11129.2.5.1] [] ]
[CertificatePolicyId: [2.23.140.1.2.2] [] ] ]

[6]: ObjectId: 2.5.29.37 Criticality=false ExtendedKeyUsages [
serverAuth clientAuth ]

[7]: ObjectId: 2.5.29.15 Criticality=false KeyUsage [
DigitalSignature ]

[8]: ObjectId: 2.5.29.17 Criticality=false SubjectAlternativeName [
DNSName: *.google.com DNSName: *.android.com DNSName: *.appengine.google.com DNSName: *.cloud.google.com DNSName: *.google-analytics.com DNSName: *.google.ca DNSName: *.google.cl DNSName: *.google.co.in DNSName: *.google.co.jp DNSName: *.google.co.uk DNSName: *.google.com.ar DNSName: *.google.com.au DNSName: *.google.com.br DNSName: *.google.com.co DNSName: *.google.com.mx DNSName: *.google.com.tr DNSName: *.google.com.vn DNSName: *.google.de DNSName: *.google.es DNSName: *.google.fr
DNSName: *.google.hu DNSName: *.google.it DNSName: *.google.nl
DNSName: *.google.pl DNSName: *.google.pt DNSName: *.googleadapis.com DNSName: *.googleapis.cn DNSName: *.googlecommerce.com DNSName: *.googlevideo.com DNSName: *.gstatic.cn DNSName: *.gstatic.com DNSName: *.gvt1.com DNSName: *.gvt2.com DNSName: *.metric.gstatic.com DNSName: *.urchin.com DNSName: *.url.google.com DNSName: *.youtube-nocookie.com DNSName: *.youtube.com DNSName: *.youtubeeducation.com DNSName: *.ytimg.com DNSName: android.clients.google.com DNSName: android.com DNSName: g.co DNSName: goo.gl DNSName: google-analytics.com DNSName: google.com DNSName: googlecommerce.com DNSName: urchin.com
DNSName: www.goo.gl DNSName: youtu.be DNSName: youtube.com
DNSName: youtubeeducation.com ]

[9]: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: EE 4B 83 40 44 28 0A 6A 01 4D 55 D0 A4 A7 5F 1E .K.@D(.j.MU..._. 0010: DF 60 F2 1E
.`.. ] ]

] Algorithm: [SHA256withRSA] Signature: 0000: 38 89 81 D8 57 DA 3C C7 60 EA BA 6B 08 D4 92 47 8...W.<...k...G 0010: 60 AA B1 4B 39 34 1C E4 7B CC 71 1F 28 8F 07 82..K94....q.(... 0020: D7 04 3F CC 12 B7 9E DF 9F 13 D4 5A 5A 30 31 1F ..?........ZZ01. 0030: A5 41 BE 9A 60 27 EE AF 28 A8 BC 21 2F 65 31 BF .A..'..(..!/e1. 0040: A5 7D D6 D4 86 89 27 7F F6 3B 28 D6 16 AA 60 31 ......'..;(...1 0050: 3D CD 67 97 84 22 43 2F B0 53 84 87 8C 47 44 5C =.g.."C/.S...GD\ 0060: EF 16 7A 73 2F 37 CB 39 48 3C F2 87 C5 77 82 A0 ..zs/7.9H<...w.. 0070: 08 84 2C 18 C6 A8 9C 57 5F 2B CC 9B 4F 7A 72 87 ..,....W_+..Ozr. 0080: C1 19 BC 0B 98 8B 09 1E 1D B1 5A BB 34 B6 95 1E ..........Z.4... 0090: B9 37 27 5C C4 73 DB AE 68 B7 B1 F9 E7 4D BB 75 .7'.s..h....M.u 00A0: 0B CE 16 75 B0 48 F2 39 AC DB 7C 68 C2 13 16 82 ...u.H.9...h.... 00B0: D2 E8 A8 F2 C1 D4 45 69 2C 8E D0 D4 FB 3D 74 7D ......Ei,....=t. 00C0: 02 CF 7C D6 17 64 63 9A E6 3B 8D F4 93 62 58 56 .....dc..;...bXV 00D0: 49 F8 0D 28 15 BC C5 B1 0F 66 1C 19 DF 83 A5 94 I..(.....f...... 00E0: 1C 2F 6A E1 A2 31 A1 23 C8 07 F8 09 BF A1 9A E4 ./j..1.#........ 00F0: EB E8 1A 7C 9D 89 CF 22 8A 4F 64 CC 8F D7 20 BD .......".Od... .

]

As it is seen in Certificate Exceptions 9:[1] and [2], OSCP URL and CRL URL both are available with certificate. Both these things are there in intermediate certificate too but they are not there in root certificate which is justifiable since they are not needed with them.

My problem is when I run above program, it gives me following error.

Exception in thread "main" java.lang.RuntimeException: java.security.cert.CertPathValidatorException: Certificate does not specify OCSP responder at test_data.ImportAndTestCert.isCertChainValid(ImportAndTestCert.java:157) at test_data.ImportAndTestCert.main(ImportAndTestCert.java:72) Caused by: java.security.cert.CertPathValidatorException: Certificate does not specify OCSP responder at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:135) at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:219) at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140) at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79) at java.security.cert.CertPathValidator.validate(CertPathValidator.java:292) at test_data.ImportAndTestCert.isCertChainValid(ImportAndTestCert.java:126) ... 1 more

If I comment Security.setProperty("ocsp.enable", "true");, it is giving me following error:

Exception in thread "main" java.lang.RuntimeException: java.security.cert.CertPathValidatorException: Could not determine revocation status at test_data.ImportAndTestCert.isCertChainValid(ImportAndTestCert.java:157) at test_data.ImportAndTestCert.main(ImportAndTestCert.java:72) Caused by: java.security.cert.CertPathValidatorException: Could not determine revocation status at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:135) at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:219) at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:140) at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79) at java.security.cert.CertPathValidator.validate(CertPathValidator.java:292) at test_data.ImportAndTestCert.isCertChainValid(ImportAndTestCert.java:126) ... 1 more

Am I missing something here?

Thanks for helping.

1

1 Answers

7
votes

I found the problem.

It was the presence of root certificate in certpath that was creating all the trouble.

Root certificates don't contain CRL and OSCP links. It is the job of Trusted Certificate Repository or TrustStore to keep updating the repository.

Since root certificate don't contain CRL and OSCP links, it was giving errors like

Exception in thread "main" java.lang.RuntimeException: java.security.cert.CertPathValidatorException: Could not determine revocation status at

and

Exception in thread "main" java.lang.RuntimeException: java.security.cert.CertPathValidatorException: Certificate does not specify OCSP responder at

In short, to check for revocation status of certificates in a certificate chain, root certificate needs to be excluded. Validator algorithm can determine whether last intermediate certificate is signed by root CA or not.