Create a Certificate Authority with bare OpenSSL

In this post we go through the steps to create your own personal Certificate Authority (CA) from scratch using only openssl.
This can be useful for your own homelab or your own server in a local LAN. Intentionally the design is simplified and we omit more advanced things like intermittent certificates.

We use rsa because my first experiments with ed25519 failed at the time of writing for reasons I didn’t wanted to investigate further.

Requirements: openssl. And that’s it!

Create CA key and certificate

NOTE: The CA key is your crown jewel and one must protect it as such. Never ever share this key or let it be compromised!

We create the CA key and encrypt it with a password for additional security (-aes256). I always use a key size of 4096 bit for additional security. Nowadays the default rsa key size is 2048 bit, which is also a bit faster when doing the TLS handshake.

# openssl genrsa -aes256 -out CA.key 4096
# openssl req -x509 -new -nodes -key CA.key -days 1825 -out CA.crt

The CA.key is your CA key. This key is the trust of the whole CA and it must be kept secret and protected with uttermost care. Never share this key or let it be compromised, otherwise the whole trust of your CA setup is jeopardized.

The CA.crt is the certificate, which can be made public and needs to be imported on the clients such that they can verify signed certificates. This certificate needs to be installed on clients and allows them to validate, if a signed server certificate is valid for this CA.

To show the fingerprint of the certificate run

# openssl x509 -in CA.crt -noout -fingerprint
# openssl x509 -in CA.crt -noout -fingerprint -sha256

Those fingerprints can be used to verify a distributed certificate before deployment. This step is however optional although I recommend doing so to ensure the certificate is the one you intent to install.

CA serial file

Each certificate requires a serial number. This is assigned by the CA at the time of signing. The data type is ASN1_INTEGER, which is a positive integer 160 bit long (See RFC3280). The CA keeps track of it’s own serial number via a CA.srl file.

We start the CA serial number with a HEX 01 value:

# echo 01 > CA.srl

This file will update itself every time a certificate is signed and allows OpenSSL to keep track of the CA serial number.

Sign a server certificate

First you need to create the server key file and a server certificate sign request (CSR) file. The server key file remains secret on the server and should never reach the CA - the CA only needs the certificate signing request. The CSR is a file that allows the CA to create a signed certificate for the server.

# openssl genrsa -out server.key 4096
# openssl req -new -key server.key -out server.csr

Now transfer the server.csr file to the CA, where we will generate a signed certificate file (.crt) from it.

For the certificates to work on modern web browsers we need to add the domain/hostname of the server via Subject Alternative Name (SAN) extensions. For instance, Firefox from 101.0 onwards no longer uses the certificate Common Name (CN) field for matching domain names to certificates but relies only on the SAN fields (See also RFC2818 page 5, beginning).

The following command creates a simple SAN with one DNS entry defined by HOSTNAME= at the beginning of the command.

# HOSTNAME=server.local openssl x509 -req -in server.csr -CA CA.crt -CAkey CA.key -CAserial CA.srl -out server.crt -days 1825 -sha256 -extensions SAN -extfile <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:$HOSTNAME"))

Note: There are better configurable ways of doing this via the openssl.cnf configuration file (see above). I decided to use this approach however because it allows me to script the whole CA certificate generation process within one line.

This generates the signed server certificate file server.crt. The CSR file server.csr can be deleted. Verify if the certificate is properly signed via

openssl verify -CAfile CA.crt server.crt

This certificate can now be used to serve content which is secured by the CA certificate.

And that’s it. Congratulations, you have now your own Certificate Authority.

Trust the CA on your system

In the section above we outlined all steps to create and run your own CA. But the clients still need to be configured to trust your CA, otherwise it doesn’t bring you much. In the following subsection I outline how to do this on Linux (at least on openSUSE).

Linux

On openSUSE Tumbleweed it’s enough to install the CA.crt file to /etc/pki/trust/anchors/ and then run update-ca-certificates:

# cp CA.crt /etc/pki/trust/anchors/homelab.crt
# update-ca-certificates

References

This post has been mostly based on https://openssl-ca.readthedocs.io/, which is an excellent source of information about running your own OpenSSL based Certificate Authority.