Q:

How to check revocation status of X509Certificate chain using JAVA?

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.

A:

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. 

