3

Is there some quick "declarative" way in Java 11, instead of a tedious manual implementation, to enable checking if a certificate is revoked?

I tried to use properties from this answer: Check X509 certificate revocation status in Spring-Security before authenticating with this dummy revoked certificate: https://revoked.badssl.com but the code always accepts the certificate. Am I doing something wrong or these properties are no more actual for Java 11? If so, do we have any alternatives?

Below is my code:

public static void validateOnCertificateRevocation(boolean check) {
    if (check) {
        System.setProperty("com.sun.net.ssl.checkRevocation", "true");
        System.setProperty("com.sun.security.enableCRLDP", "true");

        Security.setProperty("ocsp.enable", "true");
    }

    try {
        new URL("https://revoked.badssl.com").openConnection().connect();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
Roman Khomyshynets
  • 724
  • 1
  • 9
  • 12

1 Answers1

3

It seems like those options have to be set before the first request has been performed.

Therefore the following code as standalone Java program throws an CertPathValidatorException: Certificate has been revoked (tested using OpenJDK 11.0.2 x64 on Windows):

public static void main(String[] args) {
    validateOnCertificateRevocation(true); // throws CertPathValidatorException
}

However the following code does not cause any errors/Exceptions:

public static void main(String[] args) {
    validateOnCertificateRevocation(false);
    validateOnCertificateRevocation(true); // nothing happens
}

You can see the changing the options after the first request has been processed isn't effective. I assume that those options are processed in a static { ... } block of some certificate validation related class.

If you still want to enable/disable certificate revocation checking on a per-request base you can do so by implementing your own X509TrustManager that uses CertPathValidator (for which you can enable/disable certificate revocation checking via PKIXParameters.setRevocationEnabled(boolean).

Alternatively there is the solution to globally enable certificate revocation checking and explicitly handle the CertificateRevokedException:

private boolean checkOnCertificateRevocation;

@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
    try {
        getDefaultTrustManager().checkServerTrusted(certs, authType);
    } catch (CertificateException e) {
        if (checkOnCertificateRevocation) {
            if (getRootCause(e) instanceof CertificateRevokedException) {
                throw e;
            }
        }
    }
}
Robert
  • 39,162
  • 17
  • 99
  • 152
  • Thank you! The "com.sun.net.ssl.checkRevocation" property is actually, as you supposed, being processed only once in initializing of the static field "checkTLSRevocation" in "sun.security.validator.PKIXValidator" class. So, as a workaround, we could always keep this property enabled and catch/rethrow exception basing on the boolean flag in client code. But maybe there exist some more elegant solution for enabling/disabling the revocation checking in every request? – Roman Khomyshynets Mar 26 '19 at 13:14
  • You could implement an own `X509TrustManager` that uses `CertPathValidator` to validate the certificate. The used `PKIXParameters` class has a method named `setRevocationEnabled(boolen)` which can enable/disable cert revocation checking. This should work on a per-request level. – Robert Mar 26 '19 at 15:08
  • Appreciate your help! However, after several tries to implement overcomplicated `CertPathValidator` it has been decided to stick with "always throw, catch when needed" principle. The final code of custom `X509TrustManager` now looks like `@Override public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException { try { getDefaultTrustManager().checkServerTrusted(certs, authType); } catch (CertificateException e) { if (checkOnCertificateRevocation) { if (getRootCause(e) instanceof CertificateRevokedException) { throw e; } } } }` – Roman Khomyshynets Mar 28 '19 at 16:08
  • 1
    @Roman I updated my answer and included our discussion from the comments. – Robert Mar 28 '19 at 18:34