Becoming My Own Certificate Authority
I dabble with signing TLS certificates for home web services
I have deployed quite a few websites and I know the importance of TLS certificates. But I hardly ever have to do the work myself.
TLS certificates are handled by GitHub Pages, or Netlify where I usually host my static sites. And for the few web services I selfhost on a cloud server, I use nginx-proxy with its companion service for requesting and installing certificates from letsencrypt.org.
I had a vague idea of how to generate self-signed certificates using
openssl. But my understanding was so vague that I
had to refer to some guide online each time.
And the complexity of generating self-signed certificates is complemented by the fact that they are not trusted by most clients due to the abscence of signatures from a known and trusted Certificate Authority.
And so began my journey to become my own certificate authority.
What I Already Know
The hyper-text transfer protocol is at the application layer of communications that make up the world wide web – the web. It is built on top of TCP and IP
The secure version of HTTP uses transport layer security – TLS – to encrypt the data packets that are being trasmitted. This ensures that nobody other than the client and server will understand the messages being exchanged between themselves.
A layer between TCP and HTTP for encrypting HTTP packets. It is deployed by installing something to
your webserver. I almost always use nginx, so to me that meant saving a certificate file, and a key file
and configuring nginx webservers to use them. This meant specifying the
ssl_certificat_key directives in the nginx configurations.
Generating the TLS certificate
I have had to keep referring back to online guides to get this done.
openssl req -new -x509 \ -newkey rsa:4096 \ -nodes -sha256 \ -days 365 \ -keyout key.pem \ -out cert.pem
And this gave me two files – a certificate and a key – that I could install on my server.
Trusting on the client
Open client, normally my browser, settings and import
the previous step. On my android phone, I install the certificate
What I Want Now
I wanted to improve my setup in the following ways
use elliptic curve keys; that are supposedly faster and also more secure
be a certificate authority; to avoid trusting new certificates each time
Getting To What I need
The importance of the key
My understanding thus far of most cryptographic operations had been vague. But now, I finally realised the private key was the more basic element from which the certificate was derived.
I had come to the realise that the private key is also the encryption key. In retrospect, that is quite obvious! I just had not thought enough about what I was doing.
The private key is used to encrypt data. But first, I sign a certificate with it. Then I get it signed by an authority so my certificate is proven as trustworthy.
And there is usually a verification step to show that I do control the domain name in the certificate.
Elliptic Curve key
Trudging through the documentation, I did not really fully understand, but I found
an example in the manpage
openssl genpkey \ -out privkey.pem \ -algorithm EC \ -pkeyopt ec_paramgen_curve:P-384 \ -pkeyopt ec_param_enc:named_curve
Going a bit further, I added the
-aes256 flag to encrypt the key output.
The password was collected in the openssl prompts.
Becoming the certificate authority
Turns out becoming a certificate authority is pretty simple. I just had to create a self-signed certificate with they key I wanted to use. And then use the same certificate to sign other certificates.
openssl req -x509 \ -key privkey.pem \ -out CAcert.pem \ -sha512 -days 365
openssl-req is the subcommand to generate certificate requests (more on that later),
but combined with the
-x509 flag, it generates self-signed certificates. I do not
need to specify
-new as I did before because it is implied when used with x509.
So now that I had a satisfactory certificate linked to an elliptic key, I installed it on my devices.
Certificate signing request
Until now, I had only made certificates that were signed by the key. But now
that I wanted to have it signed by a certificate authority, I had to generate
CSRs. These are created
using the same command as self-signed certificates with the
-new instead of
First I generate a new private key - using an elliptic curve! Then a CSR using the key.
openssl req -new \ -key domainkey.pem \ -out domain.csr \ -sha512 -days 365
Authoritatively signed certificates
Now to use the original key
privkey.pem and its certificate
to sign the CSR and generate a new trusted certificate for the
openssl x509 -req \ -out domaincert.pem \ -in domain.csr \ -CA CAcert.pem -CAkey privkey.pem \ -sha512 -days 365
I now have a domaincert.pem and a domainkey.pem that I can use to set up https on my self-hosted webservers. And I also have a CAcert.pem that I can install on my devices to trust the current and future domain certificates.