CRL is a shortcut for (C)ertificate (R)evokation (L)ist. This is a publicly distributed list of certificates, which have been revoked (deemed invalid). The CRL does not contain either public or private keys of the revoked certificates. Checking if a certificate is on the list is done through comparing the serial ID, which all certificates are normally issued with.


In this example, the certificate to be investigates resides in a PKCS#12 formatted file. This should be a resonable realistic scenario, which may be encountered often.

The examples does the following: All in all - this should be a resonable realistic and pratical situation.

Example files

Example files have been taken from where all links in this section may be found.

First argument to the test program is the CRL file name. The actual file may be found at stest1.crl.

Second argument to the test program is the PKCS#12 file name. The actual file may be found at OleLukoeje.p12. Yes.. this is also an example of a PKCS#12 file using the special Danish country-specific characters.

Third argument to the test program is the PKCS#12 password. It is "Test1234" (the quotes are naturally not part of the password). It may also be found at the bottom of the page

Fourth (final) argument to the test program is the root certificate for the CA authrority sys-tst-ca-i.cer, supposedly having issued the certificate in the PKCS#12 file.

The example goes...

Java source code for testing CRL and PKCS#12 keystore

package dk.cryptography;

import java.math.BigInteger;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

 * About: general managemnt of PKCS#12 certificate format.<br><br>
 * @author dk.cryptography (
 * Copyright dk.cryptography /2004
 * Revision 1.0,
 * Web reference:
 * Open source software under the terms of the
 * GNU Lesser General Public License as published by the 
 * Free Software Foundation. Please observe: 
 * Permission to use, copy, modify, and distribute this software
 * for any purpose and without fee is hereby granted, provided
 * that the above copyright notices appear in all copies and that
 * both the copyright notice and this permission notice appear in
 * supporting documentation.
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * GNU Lesser General Public License for more details.
public class TestCRLandPKCS12
  public static void main(String [] argv)
      try {
           * First part - analyzing the CRL
           * Looping through the entries and retrieving information about the contents
        if(argv.length<4) {
            System.out.println("Parameter usage: <crl filename> <pkcs12 filename> <password> <CA certificate filename>");

        String crlFileName =  argv[0];
        String pkcs12FileName = argv[1]; 
        String pkcs12Password = argv[2];
        String certCAFileName = argv[3];

        // Analyzing the CRL - using appropriate certificate factory...
        CertificateFactory certificatefactory = CertificateFactory.getInstance("X.509");
        // File specified on the command line must contain a single DER-encoded X.509 CRL.        
        FileInputStream fileinputstream = new FileInputStream(crlFileName); // Open file
          // Generate a certificate from the data in the file.
        X509CRL x509crl = (X509CRL)certificatefactory.generateCRL(fileinputstream);
        System.out.println(">>CRL info<<"); // Request information about the crl.
        System.out.println("type = " +              x509crl.getType());
        System.out.println("version = " +           x509crl.getVersion());
        System.out.println("issuer = " +            x509crl.getIssuerDN().getName());
        System.out.println("signing algorithm = " + x509crl.getSigAlgName());
        System.out.println("signing OID = " +       x509crl.getSigAlgOID());
        System.out.println("this update = " +       x509crl.getThisUpdate());
        System.out.println("next update = " +       x509crl.getNextUpdate());
        Set serialSet = new HashSet(); //keep track of the serials encountered in the CRL
        Set setEntries = x509crl.getRevokedCertificates();
        Date startDate=null, endDate=null;
        int hasExtentions =0; 
        if (setEntries != null && setEntries.isEmpty() == false)
          for (Iterator iterator = setEntries.iterator();
               iterator.hasNext(); )  {
            X509CRLEntry x509crlentry = (X509CRLEntry);
            BigInteger bi = x509crlentry.getSerialNumber();
            serialSet.add(bi); //serial number
            Date revokeDate = x509crlentry.getRevocationDate();
            if(startDate==null || revokeDate.before(startDate))
               startDate = revokeDate;
            if(endDate==null || revokeDate.after(endDate))
               endDate = revokeDate;
        System.out.println("Number in total="+setEntries.size());        
        System.out.println("Number having extensions="+setEntries.size());        
        System.out.println("Revokation dates in range="+startDate+" to "+endDate);        

         * Second part - applying the CRL information
        System.out.println(">>PKCS#12 info<<"); // Request information about the crl.
        char[] passwordCharArray = pkcs12Password.toCharArray(); 
        Pkcs12CertificateManager pkcs12 = new Pkcs12CertificateManager(new,passwordCharArray);
        System.out.println("Checking PKCS#12 for revoked, the X509CRL class says: " 
                            + x509crl.isRevoked(pkcs12.getOwnerCertificate(passwordCharArray))
                            +"\n and the ID list number compare says: " 
                            +serialSet.contains(pkcs12.getSerialNumber(passwordCharArray))  );

         * Third part - retrieve general information from the PKCS#12 file
        System.out.println("PKCS#12 certificate valid from="+pkcs12.getNotBefore(passwordCharArray)+" to "+pkcs12.getNotAfter(passwordCharArray));
        Principal p = pkcs12.getSubjectDN(passwordCharArray);
        String subjectDN = p!=null ? p.toString() : null;
        System.out.println("Certificate holder in keystore "
                            +(subjectDN!=null ? "is really known as="+ subjectDN : 
                                  "has no associated X.509 certificate subject DN"));
        String verifier = pkcs12.getCertificateVerifier(passwordCharArray);
        System.out.println("Certificate issuer/verification part "
                            +(verifier!=null ? "is "+ verifier : 
                                  "isn't recognized as a X.509 certificate holder")); 
        Certificate ownerCert = pkcs12.getOwnerCertificate(passwordCharArray);
        PrivateKey privKey = pkcs12.getPrivateKey(passwordCharArray);
        PublicKey pubKey = pkcs12.getPublicKey(passwordCharArray);
        System.out.println("Holders private key uses algorithm: "+ privKey.getAlgorithm());
        System.out.println("Holders public  key uses algorithm: "+ pubKey.getAlgorithm());
        System.out.println("Usage types="+pkcs12.getKeyUsage(passwordCharArray)); System.out.flush();
        System.out.println("Holders certificate may be exported as=\n"+pkcs12.exportCert(ownerCert)+"\n");

         * Fourth part - verifying PKCS#12 contents using CA certificate
         System.out.println(">>CA verification info<<"); // Request information about the crl.
         FileInputStream isCA = new FileInputStream(certCAFileName);  //get the CA certificate..
         CertificateFactory cf = CertificateFactory.getInstance("X.509"); certCA = cf.generateCertificate(isCA);
         PublicKey pubKeyCA = certCA.getPublicKey(); //get the public key used to verify the PKCS#12
         try {
             pkcs12.validateCA(passwordCharArray, pubKeyCA);
             System.out.println("CA validation successfull");         
         catch(Exception ex) {
             System.out.println("CA validation failed");         
    catch (Exception exception)

Running the example

You also need the "" class found elsewhere on . Compile both with JDK 1.4+ . Run. The output should be...

Intended output

>>CRL info<<
type = X.509
version = 2
issuer = OU=TDC Internet Systemtest CA I, O=TDC Internet, C=DK
signing algorithm = SHA1withRSA
signing OID = 1.2.840.113549.1.1.5
this update = Fri Feb 27 11:05:31 CET 2004
next update = Fri Mar 12 12:05:31 CET 2004
Number in total=74
Number having extensions=74
Revokation dates in range=Tue Mar 19 07:05:27 CET 2002 to Fri Jan 30 10:41:16 CET 2004

>>PKCS#12 info<<
unknown attr1.
Checking PKCS#12 for revoked, the X509CRL class says: true
 and the ID list number compare says: true

PKCS#12 certificate valid from=Thu Mar 13 08:32:50 CET 2003 to Sat Mar 13 09:02:50 CET 2004
Certificate holder in keystore is really known as=CN=Ole Lukųje + SERIALNUMBER=PID:9802-2002-2-507029458883, O=Ingen Organisatorisk Tilknytning, C=DK
Certificate issuer/verification part is OU=TDC Internet Systemtest CA I, O=TDC Internet, C=DK
Holders private key uses algorithm: RSA
Holders public  key uses algorithm: RSA
Usage types=digitalSignature, nonRepudiation
Holders certificate may be exported as=

>>CA verification info<<
CA validation successfull

What this means

From the output, it appears the CRL list was successfully read. It is supposedly issued by TDC (but in fact we can't be entirely sure about that). All contained revoked entries has dates between the update timestamps for the CRL file.

The PKCS#12 section says "unknown attr1." - but that's not something the testprogram - or the PKCS12 manager actually writes. It's an error message which slips out of the Keystore.load method when reading the PKCS#12 file (in JDK 1.4.0). Obviously this is a compatibility issue between the JDK version and the PKCS#12 contents. The call is actually more precisely:

KeyStore.getInstance("PKCS12").load(new FileInputStream(filename),password);

Where filename=OleLukoeje.p12 and password=char[] {'T','e','s','t','1','2','4','3','4' }.

Checking the PKCS#12 contents with the CRL reveals that the certificate is indeed revoked. Both when asking the X509CRL API or brute-force checking into the list of ID's in the CRL.

The subject distinguished name (DN) turns out to be "CN=Ole Luk..." which corresponds well with the file name - and information found on the origin website. The issuer is supposedly "OU=TDC Internet Systemtest..." which also is in line with expectations.

Finally, verifying the certificate issuer with the root certificate - the verification processes without InvalidKeyException, NoSuchProviderException According to the Certificate.verify API this may be interpreted as successfull verification.


Running a simple example with a CRL, PKCS#12 file and a root certificate demonstrated: The CRL check and root certificate validation are important processes when handling digital signatures. These issues should have been demonstrated here. / (2004-7-30)