Check Certificate Revocation Status via CRL

6 min readJan 10, 2021


Photo by Gary Chan on Unsplash

Originally published at

In this post, we are going to learn on how to check certificate revocation status by using Certificate Revocation List (CRL). CRL though is not the only way for us to check for certificate revocation status. There is another protocol called Online Certificate Status Protocol (OCSP), that is more preferred in terms of doing certificate revocation checking. We will discuss on the OCSP in the next blog post.


People and the internet are becoming more conscious on securing their information online. One of the security mechanism that is very common and used everywhere on the internet is the use of TLS to secure the HTTP transport (HTTPS). Another common use case that is becoming more prevalent is to digitally sign a document using digital certificate. Signing a document using digital certificate instead of printing it and using hand-signature not only help in reducing the paper wastage but also in digitalising the workflow. Everyone, wherever and whenever they are, can now sign documents easily without the need to send papers everywhere. You may visit SigningCloud, one of the good digital signing solutions available on the internet.

The use of digital certificate though imposes another risk. Someone can use an abused digital certificate to be used on the internet. A TLS certificate might be mis-issued or the keys might be leaked, leading to the needs to revoke the certificate and stop it from being used further. It is the responsibility of the clients to check for the certificate revocation status before trusting the certificate for further usage. To do this, we can utilise Certificate Revocation List (CRL) that is maintained and regularly issued by the Certificate Authority (CA).


A CRL is a list of revoked certificates. This file contains the list of serial number and the revocation date of the revoked certificates. Based on the RFC5280, there are several reasons that a CA can choose when revoking a certificate:

  • unspecified (0)
  • keyCompromise (1)
  • cACompromise (2)
  • affiliationChanged (3)
  • superseded (4)
  • cessationOfOperation (5)
  • certificateHold (6)
  • removeFromCRL (8)
  • privilegeWithdrawn (9)
  • aACompromise (10)

Sometimes, a CA might just want to temporarily halt the use of the certificate. In this case, the certificate itself is not totally revoked, but instead its on-hold (revoke reason certificateHold).

Despite the usage, there is still a disadvantage in choosing CRL to do certificate revocation checking. As you might have noticed, CRL is file based, hence the size can be quite big depending on how many certificates have been revoked by the CA. The bigger the size of the CRLs, the longer it takes to loop through its content and check for the certificate revocation status.

Another disadvantage of using CRL is there is a gap between the time a certificate is revoked and the time a new CRL is generated. If a certificate is revoked before CA is scheduled to issue a new CRL, then during this gap period, the revoked certificate will still be trusted. Some clients as well cached the CRL to avoid re-downloading the CRL. In this case, when the downloaded CRL has not yet expired, the clients will not know that a certificate has been revoked due to the cached CRL is still being used for validation.


In this post, we are going to just see the CRL handling which is located at HTTP server. CRL can be located anywhere, such as in LDAP, but we will skip that and focus on HTTP only in this blog post.

Get Through the Code

For this demo, I’ll be using the Go programming language. We will run through step by step from reading a certificate file and retrieving the CRL endpoints from the certificate data itself.

Before we begin, I have downloaded an SSL certificate from a website (accessed: Jan 10, 2021). Below is the content of the SSL certificate.


I have the above certificate file saved as

Create Certificate Object

Once we have the certificate data, we can easily parse the certificate data and store it as a Certificate object through few simple steps.

First of all, we’ll read the whole content of the file and store it into a variable called fc.

// Read the certificate file content
fc, err := ioutil.ReadFile("")
if err != nil {
log.Printf("Failed to read certificate file: %s\n", err)

Once we have read the file content, we will need to decode the content. We can simply use the function Decode provided in the pem package.

// Decode the PEM file
block, _ := pem.Decode(fc)
if block == nil {
log.Println("Failed to decode certificate data")

And lastly, we will use the function ParseCertificate inside the package x509 and send the bytes of the certificate data to be parsed. This function returns the certificate object that we can use for further operations.

// Parse the certificate data
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
log.Printf("Failed to parse certificate data: %s\n", err)

Get the CRL Endpoints

Now that we have the certificate object, we will need to retrieve the list of CRL endpoints. Lucky for us, Go has provided a convenient way to retrieve list of CRL Distribution Points.

The field CRLDistributionPoints contains the CRL information that we can use later on for certificate revocation status checking.

// Retrieve the CRL URLs
crlUrls := cert.CRLDistributionPoints

if crlUrls == nil || len(crlUrls) == 0 {
log.Println("Unable to check certificate revocation status. No CRL URL defined.")

Certificate Revocation Checking

First of all, we will need to download the CRL from the HTTP server and read the CRL data. We are storing the downloaded CRL binary data into a variable data.

// Let's download the crl
resp, err := http.Get(url)
if err != nil {
log.Printf("Failed to download CRL from %s. Skipping this URL.\n", err)

// Download successful, read the body
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("Failed to read response body %s. Skipping this URL.\n", err)

// Close the connection
_ = resp.Body.Close()

Once we have the CRL data, we can use a function ParseCRL provided in package x509 to easily parse the CRL data and get an instance of the CertificateList.

// Parse the CRL data
crl, err := x509.ParseCRL(data)
if err != nil {
log.Printf("Failed to parse CRL data: %s. Skipping this URL.\n", err)

We will then loop through each of the RevokedCertificate and do comparison based on the certificate serial number.

certSn := cert.SerialNumber // The certificate serial number to check
revokedCerts := crl.TBSCertList.RevokedCertificates
wg := sync.WaitGroup{}

for _, revokedCert := range revokedCerts {
revokedSn := revokedCert.SerialNumber

// Spawn a new go-routine to speed-up the checking. Helpful for CRL that contains
// a lot of items. You might want to limit the number of go-routines based on your
// circumstances.
go func() {
if certSn.Cmp(revokedSn) == 0 {
// The certificate is revoked since the serial number is inside the CRL
revoked = true

From the above code, I am spawning a lot of go-routines for the sake of speeding-up the checking. Instead of sequentially do a serial number comparison, we’ll do it concurrently through multiple go-routines. This is useful if your CRL contains a huge number of revoked certificates. Of course, care must be taken especially if you want to limit the number of go-routines created, but that will be out of the scope of this post.

If the serial number can be found inside the CRL file, that means the certificate you are checking has been either revoked or put on-hold. You can then decide the next course of action based on the revocation status result.

That’s all. It looks very easy and straight-forward. In the next follow-up article, we’ll see how can we do certificate revocation status checking by using OCSP instead of CRL.

I hope this is helpful and the source code (including the docker related files) for this is available at Github here.





I am a software engineer focusing on Java programming language and Public Key Infrastructure (PKI). Loves Linux and open-source technology.