CRL

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.

PKCS#12

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 https://www.certifikat.dk/developer/eksempler.html 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 https://www.certifikat.dk/developer/eksempler.html.

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
TestCRLandPKCS12.java



package dk.cryptography;

import java.io.FileInputStream;
import java.math.BigInteger;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
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 (http://www.cryptography.dk)
 *
 * Copyright dk.cryptography /2004
 * Revision 1.0, stigv@hotmail.com
 * 
 * Web reference: http://www.cryptography.dk
 *                http://www.topsecurity.dk
 *                http://www.compression.dk
 *
 * Open source software under the terms of the
 * GNU Lesser General Public License as published by the 
 * Free Software Foundation. Please observe: 
 * http://www.gnu.org/licenses/lgpl.txt.
 *
 * 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
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * 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>");
            System.exit(1);            
        }

        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)iterator.next();
            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;
            if(x509crlentry.hasExtensions())
               hasExtentions++;
          }
        }        
        fileinputstream.close();
        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);        
        System.out.println();


        /*
         * 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 java.io.File(pkcs12FileName),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))  );
        System.out.println();


        /*
         * 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");
        System.out.println();

        /*
         * 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");
         java.security.cert.Certificate certCA = cf.generateCertificate(isCA);
         isCA.close();
         
         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");         
             ex.printStackTrace();
         }
    }
    catch (Exception exception)
    {
      exception.printStackTrace();
    }
  }
}


Running the example

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

Intended output
Listing




>>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.3.6.1.4.1.311.17.1
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=
-----BEGIN CERTIFICATE-----
MIIEXTCCA0WgAwIBAgIEPesnhDANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJESzEVMBMGA1UE
ChMMVERDIEludGVybmV0MSUwIwYDVQQLExxUREMgSW50ZXJuZXQgU3lzdGVtdGVzdCBDQSBJMB4X
DTAzMDMxMzA3MzI1MFoXDTA0MDMxMzA4MDI1MFowcjELMAkGA1UEBhMCREsxKTAnBgNVBAoTIElu
Z2VuIE9yZ2FuaXNhdG9yaXNrIFRpbGtueXRuaW5nMTgwEQYDVQQDFApPbGUgTHVr+GplMCMGA1UE
BRMcUElEOjk4MDItMjAwMi0yLTUwNzAyOTQ1ODg4MzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
gYEAu/6e9SDu3O+ZyGwZtOrztvv3NcECoRxROXXEBCfB0geqq6UCKFQr3ifV/ItCpsxHD4mSYlIB
1BX6P4Pb2woU4jZyVMuU0pXeShDQRAfGn2qShOMVO8duHdvHojxX1ZwFb8fvCHuD8255yTTMK63U
rEvbGz51sXvhPZxKCXwl/1MCAwEAAaOCAaQwggGgMAsGA1UdDwQEAwIGwDArBgNVHRAEJDAigA8y
MDAzMDMxMzA3MzI1MFqBDzIwMDQwMzEzMDgwMjUwWjAjBgNVHREEHDAagRhkZXZzdXBwb3J0QGNl
cnRpZmlrYXQuZGswgdgGA1UdHwSB0DCBzTBioGCgXqRcMFoxCzAJBgNVBAYTAkRLMRUwEwYDVQQK
EwxUREMgSW50ZXJuZXQxJTAjBgNVBAsTHFREQyBJbnRlcm5ldCBTeXN0ZW10ZXN0IENBIEkxDTAL
BgNVBAMTBENSTDMwN6A1oDOGMWh0dHA6Ly9yaW1mYWtzZS5jZXJ0aWZpa2F0LmRrL29jZXMvMTAz
ODgyMTI1Mi5jcmwwLqAsoCqGKGh0dHA6Ly9yaW1mYWtzZS5jZXJ0aWZpa2F0LmRrL3N0ZXN0MS5j
cmwwHwYDVR0jBBgwFoAUSWYFHUgAHH5hVZHqd+HQCtsPx/swHQYDVR0OBBYEFD0niepWUYEJV3YJ
AR4bsRLjQUrEMAkGA1UdEwQCMAAwGQYJKoZIhvZ9B0EABAwwChsEVjYuMAMCA6gwDQYJKoZIhvcN
AQEFBQADggEBAH9jrUDcLzOsSlfmII0KcpogowyzBwpOAEQJmaXT5oDgNsoN3Sj+jCKc1TF3W7OJ
xT2/dFyqkLO6lGmS5lnukD6wTMAlVqLxdgEIxMQo/sj4d6oiLvJp5/JC0LH/CnnoTxRT562inMrM
KPLlylmyAPde1Vd8WKLqn4crKseko44/YLFcD/1Fz2Z51TqqOj+Vxa8pHNuPeHM+ESD3ujALzc3X
zKgZCtwTWuImFJdGgppWJKehkAcIGfi0OPQ2/ESZW62aft4hSugQ5XFx01GHTImp9FM72Kyrqp1i
qlJrl4rMIIAv+7itPDEpOmqZltK63lx2Z2C7o6rtdQ3id+ofZxQ=
-----END CERTIFICATE-----


>>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.3.6.1.4.1.311.17.1" - 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.

Conclusion

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. /www.cryptography.dk (2004-7-30)

Ref:
http://java.sun.com/developer/onlineTraining/Security/Fundamentals/contents.html