Shell script to create and sign certificates
============================================

Modern web browsers lament the absence of encryption when they access
local web services on the home network. Adding certificates
to these services gain sigificance.

Mkcert
------
Mkcert creates signed locally trusted certificates. It makes managing
and operating a local CA much easier.

Mkcert is written in Go and available for Linux, Mac OS and Windows.

My home network's systems are running FreeBSD. I had some dependency
issues when compiling Mkcert, so I installed Mkcert it in a Linux
virtual machine. It is excessive to start a virtual machine (VM)
merely to generate few certificates.

Shell script
------------
After some trial and error, I created a shell script to generate
signed certificates. The script signs using the rootCA key generated
by Mkcert, which is already trusted on my systems.

Mkcert creates certificates with the parameter:

   subjectAltName=DNS:<FQDN of the subdomain>,IP:<ip-address of the server>

I also set out to accomplish this with the script.

Structure
---------
* The script asumes that the rootCA.key and the rootCA.crt are
 in the directory ~/certs/rootcert.
* For every subdomain a subdirectory is created under
 ~/certs/keys/

This is how it looks:

   certs
   |-- keys
   |   |-- first.example.com
   |   |   |-- first.example.com.crt
   |   |   `-- first.example.com.key
   |   `-- second.example.com
   |       |-- second.example.com.crt
   |       `-- second.example.com.key
   `-- rootcert
       |-- rootCA-key
       `-- rootCA.crt

The idea is that you can either put ~/certs or the subdirectory
~/certs/keys into a versioning system like Git.

Choose any versioning system, the key and certificate are text files.

Not a security solution
-----------------------
Always evaluate your thread model before selecting a security
solution.

The purpose of the certificates is to prevent browsers from
complaining about the lack of encryption. Perhaps in the future,
browsers will not allow users to log in to sites that do not use
encryption. It's best to have things ready before that happens.

The traffic is now encrypted, providing some protection against
eavesdropping; nonetheless, do not use this method when security is
critical.

Where to install the certificates
---------------------------------

Your FreeBSD workstation trust the certificates when you place the
rootCA certificate in:

   /usr/local/share/certs

Next, run

  certctl rehash

Configuriation of your subdomains in NGINX:

   server {
       listen *:443 ssl;
       server_name subdomain.example.com;
       ssl_certificate /path/to/subdomain.crt;
       ssl_certificate_key /path/to/subdomain.key;
       location / {
         ...
       }
   }

The script
----------

Here's the script:

   #!/bin/sh

   if [ $# -ne 2 ]; then
     echo "Usage: $0 <subdomain> <ip-address>"
     exit
   fi

   subdomain=$1
   IP=$2

   echo "Creating certifcate for FQDN: <$subdomain> on IP: <$IP> ..."
   echo ""

   myrootcertpath=${HOME}/certs/rootcert/
   mypath=${HOME}/certs/keys/$subdomain
   mkdir -p $mypath
   cd $mypath

   # Create conf file:
   echo "[req]" > $subdomain.conf
   echo "distinguished_name=req" >> $subdomain.conf
   echo "[SAN]" >> $mypath/$subdomain.conf
   echo "subjectAltName=DNS:$subdomain,IP:$IP" >> $subdomain.conf

   echo "subjectAltName=DNS:$subdomain,IP:$IP" > $subdomain.ext

   # Check if key exists, if not, create
   if [ -e $subdomain.key ]; then
     echo "Key $mypath/$subdomain.key available, not generated"
   else
     openssl genrsa -out $subdomain.key 2048
     echo "Created key $mypath/$subdomain.key"
   fi

   # Create a new csr from the key
   openssl req -new -sha256 -key $subdomain.key -subj /CN=$subdomain -out $subdomain.csr

   # Sign the key
   openssl x509 -req -extfile $subdomain.ext -in $subdomain.csr \
           -CA $myrootcertpath/rootCA.crt -CAkey $myrootcertpath/rootCA.key \
           -CAcreateserial -out $subdomain.crt -days 500 -sha256

   # Clean up
   rm $subdomain.conf
   rm $subdomain.ext
   rm $subdomain.csr

   echo "Certificate $mypath/$subdomain.crt created"
   echo "view with: openssl x509 -noout -text -in $mypath/$subdomain.crt"

Have fun!


Last edited: $Date: 2024/03/31 19:34:07 $