Holy 🔑: Mutt and S/MIME emails through the ages

As might be apparent from my blogging oeuvre, I like to cryptographically sign and encrypt emails to my friends and family. And while it's true that I've set up a personal PKI so I can cheaply and easily manage my correspondents' credentials for them, I also buy my own certificate every 3 years so that I can keep signing turned on, even for recipients who don't have my root certificate installed.

With my strong and perhaps eccentric appreciation of email, I occasionally like to be able to go back and re-read messages from a while ago. This is quite straightforward to do in most of my applications, but my favourite client Mutt demands that you either:

  1. Set a single value for smime_default_key, or;
  2. Keep unset smime_decrypt_use_default_key in your ~/.muttrc, and choose the right key each time you need to decrypt.

Neither of these is really satisfactory

smime_keys is the programme that mutt uses to manage keys, and when a new key is added, it is placed in the directory specified under smime_certificates in your ~/.muttrc.

Provided that you keep the same certificate subject and certificate password, the naming convention used for each certificate can be exploited; each subsequent certificate is called something like a1b2c3.0, a1b2c3.1, a1b2c3.2 and so on.

I have written a bash script that assumes Mutt is configured to use your latest certificate by default, and if the associated key fails to decrypt your message, goes back through time and checks for matches with previous keys:

#!/bin/bash

password=$(cat - )

keybase=${2%.*}
extension=${2##*.}
certbase=${3%.*}

while : ; do
    if [[ -f ${1} && -f ${keybase}.${extension} && -f ${certbase}.${extension} ]]; then
        openssl smime -decrypt -passin pass:${password} -inform DER -in ${1} -inkey ${keybase}.${extension} -recip ${certbase}.${extension} 2>/dev/null
        openssl_exit=$?
        extension=$(expr ${extension} - 1)
    else
        openssl_exit=1
    fi
    [[ $openssl_exit -ne 0 && $extension -ge 0 ]] || break
done

if [[ $openssl_exit -ne 0 ]]; then
    openssl smime -decrypt -passin pass:${password} -inform DER -in ${1} -inkey ${2} -recip ${3} 2>/dev/null
fi

If this file is called ~/bin/smime_decrypt.sh, it can be referred to in your ~/.muttrc with:

set smime_decrypt_command="~/bin/smime_decrypt.sh %f %k %c"

And that's it! Simple, single-password entry for all of your keys through the ages.