I'm currently writing a network TCP server using SSL. In production, we'll finally require clients to authenticate with a certificate.
In order to revoke certificates in case of a emergency, we would also like to establish a CRL.
My question is: Does Java check CRLs (if provided with the certificate) out of the box or do I need to manually implement such checks?
For testing, I prepared a certificate with a CRL set but Java does not seem to try to validate it (I dropped it into a local web server and there's no access).
I only found the com.sun.net.ssl.checkRevocation=true VM option, but apparently it doesn't query the CRL. VM debugging set to java.security.debug=certpath does not generate any output, either...
Java seems to have related classes in its subsystems (e.g. java.security.cert.X509CRLSelector), but it does not come into play, obviously.
I wrote a small maven-style project using Apache Mina as client server that initializes a SSLContext based on key/truststores and self-signed certificates for client/server which can be downloaded here as ZIP archive: https://www.dropbox.com/s/3fqmd1v9mn2a5ve/ssltest.zip?dl=0
I figured how to enable CRL checking within a SSLContext without implementing a custom validator, as suggested in the comments.
It is mainly about properly initializing the SSLContext's TrustManagers with a revocation checker, only a few lines, no custom check logic and the CRL is now checked automatically as well as the verification path.
Here's a snippet...
KeyStore ts = KeyStore.getInstance("JKS"); FileInputStream tfis = new FileInputStream(trustStorePath); ts.load(tfis, trustStorePass.toCharArray()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); // initialize certification path checking for the offered certificates and revocation checks against CLRs CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX"); PKIXRevocationChecker rc = (PKIXRevocationChecker)cpb.getRevocationChecker(); rc.setOptions(EnumSet.of( PKIXRevocationChecker.Option.PREFER_CRLS, // prefer CLR over OCSP PKIXRevocationChecker.Option.ONLY_END_ENTITY, PKIXRevocationChecker.Option.SOFT_FAIL, // handshake should not fail when CRL is not available PKIXRevocationChecker.Option.NO_FALLBACK)); // don't fall back to OCSP checking PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(ts, new X509CertSelector()); pkixParams.addCertPathChecker(rc); tmf.init( new CertPathTrustManagerParameters(pkixParams) ); // init KeyManagerFactory kmf.init(...) SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(kmf.getKeyManagers), tmf.getTrustManagers(), null);
That essentially did what I needed in my application, checking whether a certificate issued to a client is revoked in our CRL. Only checking the end entity and allowing the CRL check to fail is accepted because its all our infrastructure.