Lab - X509 Certificates

Public Key certificates comply with the X.509v3 standard and are managed in the context of a PKI (Public Key Infrastructure), that define the policies under which the certificates may be used. Most of the standards that regulate the use of X.509 certificates in the Internet are produced by the IETF PKIX Working Group1.

In this guide you will focus in the certificate validation processes. For creating Certification Authorities and certificates look the syntax of openssl x509 or XCA2. A certificate is considered valid for a specific purpose if the following conditions are verified: (i) if the certificate is used during its validity interval, (ii) if the certificate was issued (signed) by an entity (CA) in which the user trusts and (iii) if the policies in the certificate allow its use for the intended specific purpose. Here we are going to handle the first two conditions. For additional information on the subject of this guide, you may consult the Python Cryptography X509 PKI Tutorial3.

To complete this guide you will need to obtain a X509 Public Key Certificate. They are present in the Portuguese Citizen Card.

In alternative you can also use software such as XCA to create a new Certification Authority and certificates, or simply obtain the certificate from any website using the command:

openssl s_client -connect host:port -showcerts -servername SERVERNAME

In this command, if you are accessing a Web server, please replace SERVERNAME with the server name (subdomain.domain.tld). This is needed in order to properly select the correct server using a mecahanism named Server Name Indication.

Certificate Validity Interval

X.509 public key certificates contain a validity interval, that defines the temporal date interval where the certificate may be used.

Task: Implement a small program that reads a certificate and a function that verifies its vality by analysing the attributes not_valid_after and not_valid_before.

The certificate loaded should be stored in a dictionary where the key is the certificate subject. This will speed up the implementation of the remaining guide.

HINT: Use the cryptography.x509 class4 to load the certificate and then check its attributes.

Trust Anchor certificates

Trust anchor certificates are the user trustable certificates, that typically are root certificates (i.e., self-signed certificates). Trust anchor certificates are important to validate certification paths (certificate chains). Every valid certification path must terminate (have a root) in a trust anchor certificate.

Reading trust anchor certificates

Usually trust anchor certificates are provided by the operating system or the program in use (e.g., Firefox, Chrome, etc.), but may also be provided by the user. The anchor certificates in which we trust must be protected in a keystore, or a restricted location (/etc/ssl/certs), to prevent new additions our removals, intentionally or not intentionally. Python uses the certificates present in the system, as individual files containing certificates in the PEM format.

Task: Implement a small program that reads all system trusted certificates into a dictionary of certificates, with the subject as the key.

Do not load certificates with that have expired (use the previous function)

HINT: Use the os.scandir object to scan for all certificates in /etc/ssl/certs.

Build a certification path

A certificate chain, or certification path, is the set of certificates that composes a chain of trust, from a trust anchor certificate till an end user certificate. Frequently, to validate an end-user certificate it is necessary to build the certification path from a set of several candidate intermediary certificates. Other times, the entity to be validated (e.g, web server) provides the certification path together with his certificate.

Task: For this exercise, take each user certificate (from CC, downloaded, etc...), and create list with the full chain. To create the chain, load the user certificate, a dictionary of user specified intermediate roots, and the roots.

Task: Then build a list starting on the user certificate and adding each issuer certificate.

You should stop when you get a root certificate (self signed).

HINT: Remember that the user and root certificates are loaded into a dictionary with the subject as key. Therefore it is simple to obtain the issuer of a certificate.

Validate a certification path

Given a certification path we can validate it, by validating each certificate, and the relations between certificates.

Task: As the first step, create a function that validates the revokation status of each certificate in the chain. The validation should be made using CRL, Delta-CRL or OCSP as available. Each certificate specifies the validation methods and endpoints to use. A certificate can support all, or only some methods.

HINT: A CRL is a file that can be downloaded and loaded using the x509.load_pen_x509_crl method. It is comprised by a list of Revoked Certificates, and you can search it for the certificate under validation.

Task: The next step will be to validate the signatures in the chain. Each certificate should have a signature (x509.signature field) created with the private key of the issuer. Use the issuer x509.public_key to validate the signature. The signed data is present in the attribute x509.tbs_certificate_bytes.

Validating the certificates also includes checking its purpose, common name and validity. Build a function that checks these attributes, and then call the previous functions to further validate the certificate chain.

NOTE: You can use Wireshark to verify the messages exchanged with the OCSP servers to get the revocation status of certificates.

To explore

There are several other tasks you can do to explore how the X509 certificates are used in common systems. Some are:

  1. Alter your program to only use the CRL mechanism for revocation check when validating the certification path.

  2. Alter your program to use OCSP first and to use CRL if OCSP mechanism fails.

  3. Add caching mechanisms that store OCSP and CRL responses while they are valid.


Authored by João Paulo Barraca, André Zúquete, and Hélder Gomes