1. Introduction

The Secure Sockets Layer (SSL) is the basis for Transport Layer Security (TLS). Both can use certificates to identify servers to clients and vice versa. To ensure a certificate is valid and issued by the respective entity, a certificate authority (CA) validates all involved identities beforehand. Moreover, one CA can be and usually is behind many certificates. Conversely, to verify the CA entity itself, we also keep their own certificate.

In this tutorial, we discuss ways to list all SSL certificates in the default path of a Linux system. First, we discuss the certificate store and its paths. After that, we look at two ways to enumerate certificates in the store.

We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4 and OpenSSL 1.1.1n. It should work in most POSIX-compliant environments unless otherwise specified.

2. Certificate Store

Since SSL and TLS are so vital to the seamless security of communications, there is usually a directory that holds all related certificates, similar to the $HOME/.ssh path for the Secure Shell (SSH) protocol.

Thus, to get its respective path, we can use openssl from the OpenSSL toolkit:

$ openssl version -d
OPENSSLDIR: "/usr/lib/ssl"

Here, we employ the version subcommand with its -d flag to get the OPENSSLDIR option value.

In this case, the SSL directory is at /usr/lib/ssl, so we can expect to find the certs certificate store there as well:

$ ls -l /usr/lib/ssl/
total 4
lrwxrwxrwx 1 root root    5 Jun  6  2022 certs -> /etc/ssl/certs
drwxr-xr-x 2 root root 4096 Feb 20 07:07 misc
lrwxrwxrwx 1 root root   11 Feb  2 16:56 openssl.cnf -> /etc/ssl/openssl.cnf
lrwxrwxrwx 1 root root   15 Jun 26  2022 private -> /etc/ssl/private

Indeed, ls and its [-l]ong list format shows us the /usr/lib/ssl/certs subdirectory. However, /usr/lib/ssl/certs is a link to /etc/ssl/certs.

So, let’s list the files under /etc/ssl/certs to see the actual store contents:

$ ls /etc/ssl/certs

This /etc/ssl/certs listing shows all available SSL certificates in the default store of the system. In fact, most of them are links to files in directories like /usr/share/ca-certificates, as well as .0 aliases for the same files:

$ ls -la /etc/ssl/certs | grep Amazon_Root_CA
lrwxrwxrwx 1 root root     20 Oct 10  2022 6661d539.0 -> Amazon_Root_CA_2.pem
lrwxrwxrwx 1 root root     20 Oct 10  2022 8cb6660f.0 -> Amazon_Root_CA_3.pem
lrwxrwxrwx 1 root root     55 Oct 10  2022 Amazon_Root_CA_1.pem -> /usr/share/ca-certificates/mozilla/Amazon_Root_CA_1.crt
lrwxrwxrwx 1 root root     55 Oct 10  2022 Amazon_Root_CA_2.pem -> /usr/share/ca-certificates/mozilla/Amazon_Root_CA_2.crt
lrwxrwxrwx 1 root root     55 Oct 10  2022 Amazon_Root_CA_3.pem -> /usr/share/ca-certificates/mozilla/Amazon_Root_CA_3.crt
lrwxrwxrwx 1 root root     55 Oct 10  2022 Amazon_Root_CA_4.pem -> /usr/share/ca-certificates/mozilla/Amazon_Root_CA_4.crt
lrwxrwxrwx 1 root root     20 Oct 10  2022 ce0666ef.0 -> Amazon_Root_CA_1.pem
lrwxrwxrwx 1 root root     20 Oct 10  2022 de1d6673.0 -> Amazon_Root_CA_4.pem

Also, we see the ca-certificates.crt file, where all the certificate authority certificates are stored.

3. List CA Certificates

Since certificates are just keys, raw certificate contents don’t usually tell us much about the issuer in a human-readable way:

$ cat /etc/ssl/certs/ca-certificates.crt

So, to list a certificate along with its related metadata, we can use openssl with the awk command.

3.1. Using /etc/ssl/certs/ca-certificates.crt

First, let’s employ openssl and awk with the /etc/ssl/certs/ca-certificates.crt file:

$ awk -v decoder='openssl x509 -noout -subject -enddate 2>/dev/null' '
  /BEGIN/{close(decoder)};{print | decoder}
' < /etc/ssl/certs/ca-certificates.crt
subject=C = US, O = Amazon, CN = Amazon Root CA 1
subject=C = US, O = Amazon, CN = Amazon Root CA 2
subject=C = US, O = Amazon, CN = Amazon Root CA 3
subject=C = US, O = Amazon, CN = Amazon Root CA 4

This command enumerates the CA certificates in /etc/ssl/certs/ca-certificates.crt with awk, running openssl for each via the preset decoder [-v]ariable with {print | decoder}. The command within the variable gets the -subject and expiry -enddate of the x509 certificates with [-noout]put of their raw data. Naturally, we can run similar commands for other certificate types.

Critically, to know where the data for a certificate starts, we close() the command after encountering a line with a BEGIN string.

3.2. Using .0 Files

Since .0 files lead to the actual certificates, we can leverage find to use them instead of ca-certificates.crt:

$ awk -v decoder='openssl x509 -noout -subject -enddate 2>/dev/null'
  '/BEGIN/{close(decoder)};{print | decoder}' <(find /etc/ssl/certs -type l -name '*.0' -exec cat "{}" \;)

In this case, we use process substitution to find all [l]ink -type files with a -name ending with .0.

Then, we output each with cat, so awk and openssl can handle them similarly to the previous example.

3.3. Check Used Certificate

Finally, we can check the certificate a given connection uses via the s_client subcommand:

$ openssl s_client -showcerts -connect gerganov.com:443

In this case, -connect to a given host and port and use the -showcerts flag to get all certificates the server sends. Thus, we can both get the information about the involved certificates, as well as check them against our store.

4. Summary

In this article, we discussed ways to list all SSL certificates in the default store of a Linux machine.

In conclusion, regardless of the option we choose, basic parsing is required to process and read the full certificate data in each file.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.