Creating certificates for SSL/TLS protected services
Creating a certificate without a root CA
If you dont need to have your self signed cert signed by a Root CA in order to have that root CA added to your certificate store and trusted by your client, you can generate a key and cert in a fairly simple fashion.
First, set some environment variables with your chosen hostname and IP address, these will be added to the CN and SAN fields in the cert
export DEVICENAME='hostname'
export IP='192.168.0.1'
If you want the key and cert in seperate files device.key
for the private key, device.pem
for the certificate, run the following:
openssl req -x509 -newkey rsa:4096 -keyout device1.key -out device1.pem -sha256 -days 1826 -nodes -subj "/C=AU/ST=A.C.T./L=Canberra/O=Secops/OU=Org/CN=$DEVICENAME" -extensions SAN -config <(cat /etc/ssl/openssl.cnf && printf "\n[SAN]\nsubjectAltName=DNS:$DEVICENAME,DNS:$IP")
I have filled in details above for the location, organisation, organisational unit, and have included subject alternative name values for both the IP address and hostname in the above. Feel free to change these as required, remove the SAN for the IP address, etc.
Alternatively to the above, you can also combine the key and cert into the same file server1.pem
, by setting the keyout
and newkey
to the same pem file by either running openssl as shown below, or by concatenating the files together, with the key file first:
openssl req -x509 -newkey rsa:4096 -keyout server1.pem -out server1.pem -sha256 -days 1826 -nodes -subj "/C=AU/ST=A.C.T./L=Canberra/O=Secops/OU=Org/CN=$DEVICENAME" -extensions SAN -config <(cat /etc/ssl/openssl.cnf && printf "\n[SAN]\nsubjectAltName=DNS:$DEVICENAME,DNS:$IP")
Creating a certificate signed with a root CA you create
If you want your certificate signed using a root CA you create, so that you can add that root CA to a trust store so that client software trusts it, you need to create the CA and then sign a certificate request.
Create the Root CA key and Cert:
Run the following one-liner, to create a root CA certificate rootca.pem
and a root CA private key rootca.key
:
openssl req -x509 -newkey rsa:4096 -sha256 -keyout rootca.key -out rootca.pem -days 1826 -nodes -subj "/C=AU/ST=A.C.T./L=Canberra/O=Secops/OU=Org/CN=RootCA"
The subject details of the root CA have been filled in with example values in the above, feel free to change them as required.
Create the device key, csr, and then sign it with the RootCA cert:
This will create a certificate with common name and alternative names set to the correct values.
Set some environment variables with your chosen hostname and IP address, these will be added to the CN and SAN fields in the cert
export DEVICENAME='hostname'
export IP='192.168.0.1'
Now run the following commands to generate a device key, and create the certificate signing request:
openssl genrsa -out device.key 4096
openssl req -new -sha256 -key device.key -out device.csr -subj "/C=AU/ST=A.C.T./L=Canberra/O=Secops/OU=Org/CN=$DEVICENAME" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf && printf "\n[SAN]\nsubjectAltName=DNS:$DEVICENAME,DNS:$IP")
I have filled in details above for the location, organisation, organisational unit, and have included subject alternative name values for both the IP address and hostname in the above. Feel free to change these as required, remove the SAN for the IP address, etc.
The above will create a key for the servers certificate device.key
, and a certificate signing request device.csr
with all of the specified details like common name, SANs etc, that will end up in the final certificate.
The last step is to create a certificate device.pem
signed by the root CA based on details in the signing request:
openssl x509 -req -in device.csr -CA rootca.pem -CAkey rootca.key -CAcreateserial -out device.pem -days 1826 -sha256 -extensions SAN -extfile <(cat /etc/ssl/openssl.cnf && printf "\n[SAN]\nsubjectAltName=DNS:$DEVICENAME,DNS:$IP")
Again, I have included details on the alternative names for the final certificate in the command above, change them as required for your purposes.
As a final step, you may want to have the server key and certificate chain included in one file, server.pem
, for easy use in certain servers, which you can do by concatenating the required files together, with the key first followed by certificates in order up the chain ending with the root CA certificate:
cat device.key device.pem rootca.pem > server.pem
Trust a root CA signed certificate
On Ubuntu to add the signing Root CA to the local stores so it is trusted (The filename must end in .crt to be recognised, but the rest of the name doesn’t matter too much):
sudo cp rootca.pem /usr/share/ca-certificates/rootca.crt
sudo cp rootca.pem /usr/local/share/ca-certificates/rootca.crt
Then run the following commands to import the certificates into the various places that various components of Ubuntu look.
sudo dpkg-reconfigure ca-certificates
sudo update-ca-certificates
If a Python application needs to trust the certificate, it may use the system store, or if the certifi module is installed it will use its own certificates file. You can find where it is using:
>>> import certifi
>>> certifi.where()
For Python requests, you can specify an alternate CA Bundle via an environment variable:
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
You can also append to the end of the certifi store using something like the following:
(cat /usr/local/lib/python3.5/dist-packages/certifi/cacert.pem && printf "\n" && cat rootca.pem )| sudo tee /usr/local/lib/python3.5/dist-packages/certifi/cacert.pem > /dev/null
Checking the certificate or certificate signing request you created
If you want to see the details of the certificate file you created, say server.pem
, run openssl like below
openssl x509 -in server.pem -text -noout
To look at whats in a certificate signing request device.csr
, run openssl like below:
openssl req -text -noout -verify -in device.csr