Using client side certificates for secure authentication

Client-side SSL certificates are a great tool to add an extra layer of security by validating client connections. They use similar infrastructure to server-side certificates, like the one protecting website traffic and encrypting it between your web browser and this very website. The difference is that server-side certificates are used to verify the authenticity of a website and also used to encrypt traffic in transit, client-side certificated on the other hand are used for authenticating client connections only.

They can be combined with password authentication and the client certificate itself can be encrypted using a password to protect it from theft when it’s not used.

We are going to look at how to create these certificates and how to use them using Apache to authenticate web server connections.

Pubic key cryptography

Both the client and server-side certificate system is based on public key (asymmetric) cryptography. In simple terms, it means that it’s using a pair of keys – a public and a private key. The public key is meant to be shared while the private key should be kept secret.

Introducing EasyRSA

EasyRSA is a software package to manage a complete PKI infrastructure, root certificates, intermedia certificates, client revocation lists, request and signing certificates. It’s part of the OpenVPN software package but can also be downloaded separately from here: https://github.com/OpenVPN/easy-rsa/releases

It is using OpenSSL for cryptography – the Windows version includes OpenSSL binaries, for Linux or MacOS it requires OpenSSL to be installed.

Become a Certificate Authority

The first step is to create a Certificate Authority (CA for short). The CA is the entity that is going to issue certificates. Technically, a CA has a private and a public key, the private key can be used to issue certificates with it, the public key can validate keys if they were really issued by the CA. You need to publish your CA’s public key and services can use it to validate client certificates.

The great thing about this system is that creating new client certificates doesn’t need any change at all. It can magically validate all client keys (because they are issued by the CA) without having seen them because they are issued by the CA.

First we need to initialize the whole public key infrastructure environment (PKI) then create our CA certificate.

$ easyrsa init-pki
init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/techtipbits/ea/pki

$ easyrsa build-ca
Enter New CA Key Passphrase: 
Re-Enter New CA Key Passphrase: 
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:techtipbits
CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/home/techtipbits/ea/pki/ca.crt

Creating a certificate is done with the “easyrsa build-ca” command, it then asks for a keyphrase and a name for the CA. That’s it, it is done. Files are stored in the “pki” folder, that folder can be backed up or copied elsewhere, it contains all the information about the CA and its issued certificates.

Create certificate(s)

Once the CA is created, we can start issuing certificates. Every time the command is run, it asks for a password to protect the newly issued certificate then the CA’s password (the one that was set above, it’s protecting the CA’s private key). In this example, I named the client cert “tt1”:

$ easyrsa build-client-full tt1
Using SSL: openssl OpenSSL 1.1.1d  10 Sep 2019
Generating a RSA private key
....+++++
.........................................+++++
writing new private key to '/home/techtipbits/ea/pki/easy-rsa-55572.smj5u0/tmp.rtXpMf'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
Using configuration from /home/techtipbits/ea/pki/easy-rsa-55572.smj5u0/tmp.syO36L
Enter pass phrase for /home/techtipbits/ea/pki/private/ca.key:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'tt1'
Certificate is to be certified until Aug 11 15:26:08 2023 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

Aaand we’re done. The folder “pk1/private” contains all the private keys (for now there are two of them the CA’s and the first cert’s (tt1). The folder “pk1/issued” contains the certificates themselves.

$ ls -la pki/{issued,private}/*
-rw------- 1 techtipbits techtipbits 4485 May  8 17:26 pki/issued/tt1.crt
-rw------- 1 techtipbits techtipbits 1766 May  8 17:21 pki/private/ca.key
-rw------- 1 techtipbits techtipbits 1854 May  8 17:26 pki/private/tt1.key

You can keep going and add as many client side certificates, as needed.

Revoking certificates

Now and then a certificate may need to be revoked because it got lost or the person who has it simply shouldn’t have access to the protected resource anymore. This is where revocation lists come into the picture – they contain a list of certificates issued by the CA that were revoked and shouldn’t be accepted. Each certificate has an expiry date (the one above is valid for 825 days) so they naturally expire (and should be renewed, see “easyrsa renew”, but until then, they can only be revoked by the “easyrsa revoke” command.

Once a certificate is revoked, the revocation list should be updated by “easyrsa gen-crl” and the revocation list should be re-published to the services using the CA.

Example (creating a new cert tt2, revoking it, updating the CRL (certificate revocation list):

$ easyrsa build-client-full tt2
$ easyrsa revoke tt2
$ easyrsa gen-crl
...
CRL file: /home/techtipbits/ea/pki/crl.pem

Using client-side certificates with Apache

To enforce client side validation, a few configuration directives should be copied into the Apache virtual host configuration to be protected. It’s also possible to protect a directory by using the same configuration in a .htaccess file.

SSLVerifyClient require
SSLCACertificateFile "/etc/ssl/private/ca.crt"

The filename after “SSLCACertificateFile” should point to the absolute path of the ca’s public key. To enable revocation list checking, the following should be added:

SSLCARevocationFile "/etc/ssl/private/ca.crl"
SSLCARevocationCheck chain

The difference between adding these commands to server configuration or .htaccess is that when added at the virtual host level, the server won’t even accept a connection without the proper client certificate. When it’s in “htaccess”, the server will allow the request to find which folder it should check for .htaccess settings then re-negotiate the connection, if needed.

It’s also possible to set a list of allowed client certificates instead of all of them to further limit access by doing this:

  <Location />
        SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)-/ and %{SSL_CLIENT_S_DN_CN} in {"tt1","tt3"} )
  </Location>

This line limits access to client certificates called “tt1” and “tt3”. In .htaccess, the <location> and </location> lines should be removed.

Browser usage

Once client side certificate validation is enabled, connecting to the service with a browser will result in an instant error because the browser doesn’t know that a client certificate should be used to authenticate the connection.

To enable connection, the client side certificate should be imported into the operating system’s certificate store. For example, in Google Chrome, there is a Manage Certificates” tool in Settings / Privacy and Security / Security / Manage certificates that will open the certificate import wizard.

Most operating systems can handle certificates in the “p12” format, to export a certificate in this format, you can run the following command:

$ easyrsa export-p12 tt1
Using SSL: openssl OpenSSL 1.1.1d  10 Sep 2019
Enter pass phrase for /home/techtipbits/ea/pki/private/tt1.key:
Enter Export Password:
Verifying - Enter Export Password:

Successful export of p12 file. Your exported file is at the following
location: /home/techtipbits/ea/pki/private/tt1.p12

It will ask for the client certificate’s password then an export password to protect the exported cert. The resulting tt1.p12 file (that contains the whole certificate, including the privat key) can then be imported into the operating system’s certificate store and it will automatically use it, when a connection is made in the browser to a resource that’s protected by client side certificate authentication.

This way, only clients that have a client certificate that was signed by the appropriate CA will be able to connect to protected resources.

Related Posts