Being your own Certificate Authority
There are many blogs and tutorials with nice shortcuts providing the necessary
openssl
commands to create and sign x509 certficates.
However, there is precious few instructions for how to easily create your own certificate authority.
You probably never want to do this in a production environment, but in a development environment it will make your life signficantly easier.
Create the certificate authority
Prepare your CA directories
Pick a directory to store your keys and certificates in.
Then make a subdirectory for the certficiate authority and some required directories:
mkdir ca
mkdir ca/private
touch index.txt
Create the key and certificate
Then, make your certificate authority key and certificate:
openssl genrsa -out ca/private/cakey.pem 2048
openssl req -x509 -new -nodes -key ca/private/cakey.pem -sha256 -days 1024 -out ca/cacert.pem
Some tips:
- You will be prompted to enter some information about your certificate
authoirty. Provide the minimum information - i.e., only overwrite the
defaults. So, provide a value for
Country
,State or Province
, andOrganization Name
and leave the rest blank. - You probably want to leave the password blank if this is a development/testing environment.
Want to review what you created?
openssl x509 -text -noout -in ca/cacert.pem
Prepare your openssl.cnf file
With Debian Trixie, the default openssl configuration file seems to be
/usr/lib/ssl/openssl.cnf
. Prior versions used /etc/ssl/openssl.cnf
.
In this document we will explicitly use /etc/ssl/openssl.cnf
to get the Debiand defaults.
But, there are two bits missing from the Debian configuration that have to be added.
- At the very top add:
subjectAltName = ''
. - In the
[user_cert]
section, add:subjectAltName=$ENV::subjectAltName
Create a your first key and ceritificate signing request
First, pick your domain names (aka “common” names). For example, example.org
and www.example.org
.
Set those values in an environment variable. If you just have one:
export subjectAltName=DNS:example.org
If you have more then one:
export subjectAltName=DNS:example.org,DNS:www.example.org
If you have a wild card domain:
export subjectAltName='DNS:*.example.org'
Next, create a key and a certificate signing request:
openssl req -config /etc/ssl/openssl.cnf -new -nodes -addext "$subjectAltName" -out new.csr -keyout new.key
Again, you will be prompted for some values (country, state, etc) - be sure to choose the same values you used with your certficiate authority! I honestly don’t understand why this is necessary (when I set different values I get an error on the signing request step below). Maybe someone can add a comment to this post explaining why these values have to match?
Also, you must provide a common name for your certificate - you can choose the same name as the altSubjectNames value you set above (but just one domain).
Want to review what you created?
openssl req -config /etc/ssl/openssl.cnf -in new.csr -text -noout
Sign it!
At last the momenet we have been waiting for:
openssl ca -config /etc/ssl/openssl.cnf -keyfile ca/private/cakey.pem -cert ca/cacert.pem -out new.crt -outdir . -rand_serial -infiles new.csr
Now you have a new.crt and new.csr that you can install via your web browser, mail server, etc specification.
Smoke Test
This command will confirm that the certificate is trusted by your certificate authority.
openssl verify -config /etc/ssl/openssl.cnf -no-CApath -CAfile ca/cacert.pem new.crt
But wait, there’s still a question of trust
You probably want to tell your computer or browser that you want to trust your certificate signing authority.
Command line tools
Most tools in linux by default will trust all the certificates in
/etc/ssl/certs/ca-certificates.crt
. (If that file doesn’t exist, try
installing the ca-certificates
package). If you want to add your certificate
to that file:
cp cacert.pem /usr/local/share/ca-certificates/cacert.crt
sudo dpkg-reconfigure ca-certificates
Want to know what’s funny? Ok, not really funny. If the certificate name ends
with .pem
the command above won’t work. Seriously.
Once your certificate is installed with your web server you can now test to make sure it’s all working with:
gnutls-cli --print-cert $domainName
Want a second opinion?
curl https://$domainName
wget https://$domainName -O-
Both will report errors if the certificate can’t be verified by a system certificate.
If you really want to narrow down the cause of error (maybe reconfiguring ca-certificates didn’t work)?
curl --cacert /path/to/your/cacert.pem --capath /tmp
Those arguments tell curl to use your certificate authority file and not to load any other certificate authority files (well, unless you have some installed in the temp directory).
Web browsers
Firefox and Chrome have their own store of trusted certificates - you’ll have to import your cacert.pem file into each browser that you want to trust your key.
Renewing
In the first step, you created a certificate signing authority key with an expiration of 1,024 days.
With luck, you’ll still be using it after 3 years which means you’ll need to renew it.
Start by changing into the ca
directory.
Then, create a new certificate signing request:
openssl x509 -x509toreq -in ca/cacert.pem -signkey ca/private/cakey.pem -out new-server.csr
That command creates the file new-server.csr
- a certificate signing request.
Now, simply sign it:
openssl x509 -req -days 1024 -in new-server.csr -signkey private/cakey.pem -out new-cacert.pem
This command generates your brand new cacert.pem
file, but with the new name new-cacert.pem
.
Now, you simply use the new file to replace your old cacert.pem
file.