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 $