Automating the CRL generation and distribution of an OpenSSL Certificate Authority

In my previous Article i described, how i created the PKI for my Home Network. This time i will show you how i implemented a few small scripts to automate the necessary maintenance for my PKI.

I created my CA with a standard revoke list expiration date of 48 hours. This means I have to create and publish the revoke lists fairly often. Obviously I have no intention of doing this by hand, so I wrote a small script to do the work for me. The Script first creates the new Certificate Revoke List by calling on OpenSSL and afterwards moves it to my web server with the use of scp.

#!/bin/bash
#this script generates the CRL and moves it to the web server
CANAME=$1
CRLPATH=/etc/ssl/$CANAME/$2
CRLPUBNAME=$3
cert_archiver_log="/etc/ssl/scriptlog.log"
echo $(date +"%d.%m.%Y %T") Starting Publishing new CRL for $CANAME >> $cert_archiver_log
openssl ca -name $CANAME -gencrl -out $CRLPATH && echo $(date +"%d.%m.%Y %T") New CRL for $CANAME created >> $cert_archiver_log || echo $(date +"%d.%m.%Y %T") ERROR_CRL error creating CRL for $CANAME >> $cert_archiver_log
scp $CRLPATH username@webservername:/var/www/CA_Dist/$CRLPUBNAME && echo $(date +"%d.%m.%Y %T") Published CRL for $CANAME >> $cert_archiver_log || echo $(date +"%d.%m.%Y %T") ERROR_CRL error publishing CRL for $CANAME >> $cert_archiver_log

Before I could use the script, had to prepare scp for Operation without password. First I had to create a key pair for use with scp.

ssh-keygen -t rsa

Since the entire point of this was not having to enter a password when using scp, I pressed enter when prompted for a password. This way a key without a password was created. The command will create two files and tell you where you can find them. Usually the files can be found in “/home/username/.ssh”. Next I needed to transfer the file id_rsa.pub to my web server. After the file was transferred, I logged onto the web server as the user whom I wanted to connect with in the script(the username specified in the scp line of the script). I went to the /.ssh folder in the users home directory and moved my id_rsa.pub there and named it “authorized_keys”. If the file “authorized_keys” should exist already, append your id_rsa to the file to it. As last step I made sure, that the remote user had write access to the target folder of the script.

After these preparations the script ran without problems. Even though the script does what it should, I still had some work to do. I have multiple Certificate Authorities and I need to publish the CRLs for each of them. Because of this I wrote another script, that calls the CRL publishing script with the appropriate parameters for each CRL and while I was at it I also made sure it called the certificate archiving script from the previous article.

#!/bin/bash
#this script calls the maintanance scripts for different CAs
cert_archiver_log="/etc/ssl/scriptlog.log"
ssl_script_dir=/etc/ssl/scripts/
#values that need to be provided to the called script and position
#CANAME=$1
#CRLNAME=$2
#CRLPUBNAME=$3
CAINFOS[0]="CA_skelleton.net arl.pem skelleton.net-root.crl"
CAINFOS[1]="CA_servers_skelleton.net crl_servers.pem skelleton.net-server.crl"
echo $(date +"%d.%m.%Y %T") START Starting to run CA maintenance scripts >> $cert_archiver_log
for parameters in "${CAINFOS[@]}"
do
${ssl_script_dir}openssl_archiver.bsh $parameters
${ssl_script_dir}openssl_crlcreate.bsh $parameters
done
echo $(date +"%d.%m.%Y %T") FINISH finished running CA maintenance scripts >> $cert_archiver_log

The parameters for each CA are in an array in the script code and can be extended easily if the need should arise.
In order to save on the needed parameters I had to modify my archive script somewhat though:

#!/bin/bash
#this script archives issued certificates by moving them from the newcerts to certs and and link the hash value as index
#script must be called scriptname "/path/to/newcerts" "/path/to/certs"
cert_archiver_log="/etc/ssl/scriptlog.log"
CA_newcerts_dir=/etc/ssl/$1/newcerts
CA_certs_dir=/etc/ssl/$1/certs
echo $(date +"%d.%m.%Y %T") Starting Archiving of certificates in the directory $CA_newcerts_dir >> $cert_archiver_log
if [ ! "$(ls -A ${CA_newcerts_dir}/*.pem)" ]; then
                                #check if there are actually any certs in the newcerts folder
                                echo no new certificates
                                echo $(date +"%d.%m.%Y %T") Ending Archiving there are no new certificates in the directory $CA_newcerts_dir >> $cert_archiver_log
else
        for CertSN in ${CA_newcerts_dir}/*.pem; do
                echo certsn: $CertSN
                echo moving $certSN to ${CA_certs_dir}/${CertSN##*/}
                mv $CertSN ${CA_certs_dir}/${CertSN##*/} || echo $(date +"%d.%m.%Y %T") ERROR_ARC while moving certificate $CERTSN into $CA_newcerts_dir >> $cert_archiver_log
                #The Number at the end should increase, if the cert exists already -> cert has been reissued
                indexfile=$(openssl x509 -hash -noout -in ${CA_certs_dir}/${CertSN##*/})
                if [ ! -e ${CA_certs_dir}/${indexfile}.0 ]; then
                        echo the certificate has not been issued before creating link ${indexfile}.0
                        ln -s ${CA_certs_dir}/${CertSN##*/} ${CA_certs_dir}/${indexfile}.0 && echo $(date +"%d.%m.%Y %T") Archived Certificate ${CertSN##*/} >> $cert_archiver_log || echo $(date +"%d.%m.%Y %T") ERROR_ARC error while creating symlink for certificate ${CertSN##*/} >> $cert_archiver_log
                else
                        echo certificate has been issued before incrementing index
                        echo $(date +"%d.%m.%Y %T") Certificate ${CertSN##*/} has been reissued, incrementing index >> $cert_archiver_log
                        i=0
                        success=0
                        while [ ! $success == 1 ]
                        do
                                i=$((i + 1))
                                echo check if ${indexfile}.$i exists
                                if [ ! -e ${CA_certs_dir}/${indexfile}.$i ]; then
                                        ln -s ${CA_certs_dir}/${CertSN##*/} ${CA_certs_dir}/${indexfile}.$i && echo $(date +"%d.%m.%Y %T") Archived Certificate ${CertSN##*/} >> $cert_archiver_log || echo $(date +"%d.%m.%Y %T") ERROR_ARC error while creating symlink for certificate ${CertSN##*/} >> $cert_archiver_log
                                        success=1
                                fi
                        done
                fi
        done;
fi
echo $(date +"%d.%m.%Y %T") Ending Archiving >> $cert_archiver_log

I made a test run and after fixing a few spelling mistakes everything went fine. All that was left to do was scheduling the scripts to run every day.

 crontab -e

After issuing this command, your default editor will open your users crontab file. I added the following line:

#m h dom mon dow command
42 0 * * * /bin/bash /path/to/the/script/openssl_wrapper.bsh &>/dev/null

This line means the script with run on minute 42 of hour 0 every day of every month on every day of the week. Cron executes /bin/bash with my script as parameter and all the command line output will be dropped instead of being mailed to the user.

 

Leave a Reply

Your email address will not be published. Required fields are marked *