Secure digital QSL cards, part 2: shell script

Following on from Creating secure digital QSL cards with your LoTW certificate, here’s a Bash script to generate encrypted signed PDF QSLs. You will need to edit the certificate file name, the QSL blank file name, your call sign, your LoTW password and the PDF encryption password. After doing so, please keep the script safe, as whoever has your LoTW password can pretend to be you.

The only checks that this script doesn’t do (and probably should) are if you have pdftk and PortableSigner executables in your path. PortableSigner is rather weird the way it runs; you need to specify full paths for all files, or it dies.

The script is called like this:

mkdqsl.sh callsign date utc mhz mode report

for example:

mkdqsl.sh VE3KPK 2011-10-02 2341 7.03581 CW 499

Code below the fold.

#!/bin/bash
# mkdqsl.sh - make a secure digital QSL PDF
# scruss / VA3PID - 2011-10-14
# $Id: mkdqsl.sh,v 1.2 2011/10/15 15:37:13 scruss Exp $

##################
# Things to edit #
##################

# Your Logbook of the World certificate file name
#   (or any valid X.509 P12 or PFX file)
# Needs to be in the current directory
LOTW_CERTIFICATE="VA3PID.p12"

# Your blank QSL PDF form with the following form fields defined:
#   callsign  date  utc  mhz  mode  report
# Needs to be in the current directory
QSL_BLANK="VA3PID-QSL-blank3.pdf"

# Your call sign - used only for output file naming
MY_CALL="VA3PID"

# Super-secret passwords
# Keep them safe; whoever has access can pretend to be you
LOTW_PASSWORD="NotYourPassword"
OWNER_PASSWORD="AlsoNotYourPassword"

#############################
# Nothing to edit past here #
#############################

# Check args, give usage otherwise
# takes six arguments: callsign, date, utc, mhz, mode, and report
if [ $# -lt 6 ]
then
    echo "Usage: " $0 " callsign date utc mhz mode report"
    exit
fi

CALLSIGN=$1 
DATE=$2 
UTC=$3 
MHZ=$4 
MODE=$5 
REPORT=$6

# temp files based on run variables
TEMP_FDF="temp_${CALLSIGN}_$$.fdf"
TEMP_FILLED_PDF="temp_${CALLSIGN}_$$.pdf"
TEMP_ENCRYPTED_PDF="tempE_${CALLSIGN}_$$.pdf"
OUTFILE="${MY_CALL}-qsl-${CALLSIGN}-${DATE}-${UTC}.pdf"

# check existence of required input files
if [ ! -f $LOTW_CERTIFICATE ]
then
    echo "Signing certificate " $LOTW_CERTIFICATE " not found."
    exit
fi

if [ ! -f $QSL_BLANK ]
then
    echo "QSL blank " $QSL_BLANK " not found."
    exit
fi

# make FDF file from form data
cat > ${TEMP_FDF} <<ZORKLE
%FDF-1.2

1 0 obj
<<
/FDF << /Fields 2 0 R>>
>>
endobj
2 0 obj
[<< /T (callsign) /V (${CALLSIGN}) >>
<< /T (date) /V (${DATE}) >>
<< /T (utc) /V (${UTC}) >>
<< /T (mhz) /V (${MHZ}) >>
<< /T (mode) /V (${MODE}) >>
<< /T (report) /V (${REPORT}) >>
]
endobj
trailer
<<
/Root 1 0 R

>>
%%EOF
ZORKLE

# create first stage filled-in form
pdftk $QSL_BLANK fill_form $TEMP_FDF output $TEMP_FILLED_PDF flatten

# create encrypted document using $OWNER_PASSWORD
pdftk $TEMP_FILLED_PDF output $TEMP_ENCRYPTED_PDF owner_pw $OWNER_PASSWORD  allow AllFeatures

# sign encrypted PDF
# note that PortableSigner is picky about file locations
PortableSigner -n -o "${PWD}/$OUTFILE"  -ownerpwd "$OWNER_PASSWORD" -p "$LOTW_PASSWORD"  -s "${PWD}/$LOTW_CERTIFICATE"  -t "${PWD}/$TEMP_ENCRYPTED_PDF"

echo Wrote to $OUTFILE

# the end; clean up
rm -f $TEMP_FDF $TEMP_FILLED_PDF $TEMP_ENCRYPTED_PDF

3 thoughts on “Secure digital QSL cards, part 2: shell script”

  1. I really should update this to include the ability to send cards to /P contacts; Unix gets confused by that character. Also, it would be nice to have the file date the same time as the QSL using ‘touch’.

  2. Very cool this procedure you have come up with. Have you used it with many people? The only thing I would change in that script is I would prompt the user for their private key password instead of storing it in the script.

  3. Hi John – yes, I’ve sent out 558 of these to 529 different hams, starting with my first QSO in mid-May 2011. I do a batch monthly.

    I agree about the private key, but that would a pain for me in batch processing.

Leave a Reply

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