javasocketsssltcpcertificate-revocation

TCP Socket - Java SSL Certificate Revocation Checking


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.

edit: Removed outdated Dropbox link


Solution

  • 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.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.