import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXParameters;
import java.security.cert.PKIXRevocationChecker;
import java.util.Arrays;
import java.util.EnumSet;

public class CrlDistPointIssue {

  public static void main(String[] args) throws CertificateException, IOException, NoSuchAlgorithmException, KeyStoreException, InvalidAlgorithmParameterException, InterruptedException {
    CertificateFactory fact = CertificateFactory.getInstance("X.509");

    Path validate = Paths.get("entity.crt");
    Path trust = Paths.get("trust.crt");
    Certificate trustCertificate = fact.generateCertificate(Files.newInputStream(trust));
    Certificate entityCertificate = fact.generateCertificate(Files.newInputStream(validate));

    KeyStore trustStore = KeyStore.getInstance("JKS");
    trustStore.load(null);
    trustStore.setCertificateEntry("trust", trustCertificate);

    PKIXParameters pkixp = new PKIXParameters(trustStore);

    CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
    PKIXRevocationChecker rc = (PKIXRevocationChecker) cpv.getRevocationChecker();
    rc.setOptions(EnumSet.of(
        PKIXRevocationChecker.Option.NO_FALLBACK,
        PKIXRevocationChecker.Option.PREFER_CRLS
    ));
    pkixp.addCertPathChecker(rc);
    pkixp.setRevocationEnabled(true);

    CertPath certPath = fact.generateCertPath(Arrays.asList(entityCertificate));

    try {
      System.out.println("########################## Checking");
      cpv.validate(certPath, pkixp);
      System.out.println("########################## Should not be visible since validation fails on the first endpoint.");
    }
    catch (CertPathValidatorException ex) {
      System.out.println("########################## Validation failed");
    }
    try {
      System.out.println("########################## Checking again");
      cpv.validate(certPath, pkixp);
      System.out.println("########################## Validation Successful since it fetched the CRL from the file");
    }
    catch (CertPathValidatorException ex) {
      System.out.println("########################## Validation failed");
    }
    
    Thread.sleep(30500); //CRL lookup cache time is 30s. All checks within this time will succeed since they skip the first endpoint.
    
    try {
      System.out.println("########################## Checking again");
      cpv.validate(certPath, pkixp);
      System.out.println("########################## Should not be visible since validation will fail again.");
    }
    catch (CertPathValidatorException ex) {
      System.out.println("########################## Validation failed");
    }
    try {
      System.out.println("########################## Checking again");
      cpv.validate(certPath, pkixp);
      System.out.println("########################## Validation Successful since it fetched the CRL from the file");
    }
    catch (CertPathValidatorException ex) {
      System.out.println("########################## Validation failed");
    }
  }
}
