box.matto.nl
Enjoying Open Source Software

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!

Tags:

⇽ Twentysix year old RedHat 5.2 on QEMU i386