Skip to content

Instantly share code, notes, and snippets.

@LucaFilipozzi
Last active August 10, 2023 12:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LucaFilipozzi/ce2ce9d8f650b48e9f98fa7c4daaa5b5 to your computer and use it in GitHub Desktop.
Save LucaFilipozzi/ce2ce9d8f650b48e9f98fa7c4daaa5b5 to your computer and use it in GitHub Desktop.
gpg-sign-key -- offline key signing utility

this utility will generate an mbox containing the emails, one email per uid, to be sent once online again

to configure, modify the src and from variables

to generate the mbox, use gpg-sign-key «key» > mbox

to send the emails, use: cat mbox | formail -s /usr/sbin/sendmail -t

yes, the mime stuff is tedious but i wanted to avoid using perl, python, ruby, etc.

#!/bin/bash
# Copyright (C) 2018 Luca Filipozzi
set -e
src="B5754A69B6BE608C"
from='Luca Filipozzi <lfilipoz@emyr.net>'
key="$1"
dir=$(mktemp -d /tmp/gpg-sign-key.XXXXXX)
trap 'rm -rf ${dir}' EXIT
gpg="gpg --batch --quiet --yes --homedir ${dir} --no-default-keyring --keyring tmpring.kbx"
ln -s ${HOME}/.gnupg/private-keys-v1.d ${dir}
ln -s ${HOME}/.gnupg/dirmngr.conf ${dir}
ln -s ${HOME}/.gnupg/gpg.conf ${dir}
# receive key
${gpg} --receive-keys ${key}
# for each of the key's uids
i=1; ${gpg} --with-colons --list-keys ${key} | grep -E '^uid:' | while IFS=':' read -a arr ; do
uid=${arr[9]}
# delete any previous signatures
${gpg} --edit-key ${key} minimize clean save 2>/dev/null
# attempt to create a signature
${gpg} --keyring ~/.gnupg/pubring.kbx --default-cert-level 3 --edit-key ${key} uid ${i} sign save 2>/dev/null
# if a signature exists (gpg will not sign revoked uids, for example)
if ${gpg} --with-colons --list-sigs ${key} | grep -v -F ${key} | grep -q -E '^sig:' ; then
# construct an encrypted multipart/mixed payload containing the signed key
makemime -j \
\( \
-m 'multipart/mixed' \
-a 'MIME-Version: 1.0' \
\( \
-c 'text/plain; charset="utf-8"' \
-a 'Content-Disposition: inline' \
-a "Content-Description: PGP key import instructions" \
-e '8bit' \
<(echo "Please find attached your signed PGP key. Use 'gpg --import' to import it.") \
\) \
\) \
\( \
-c "application/pgp-keys; name=\"${key}-${i}-by-${src}.asc\"" \
-a "Content-Disposition: attachment; filename=\"${key}-${i}-by-${src}.asc\"" \
-a "Content-Description: PGP key ${key} (${uid}) signed by ${src}" \
<(${gpg} --export --armor ${key}) \
\) | ${gpg} --keyring ~/.gnupg/pubring.kbx --trust-model always --encrypt --armor --default-key ${src} --recipient ${src} --recipient ${key} > ${dir}/${key}-${i}.asc
# contruct a multipart/encrypted message containing the payload
makemime -j \
\( \
-m 'multipart/encrypted' \
-a 'MIME-Version: 1.0' \
\( \
-c 'application/pgp-encrypted; name="signedkey.msg"' \
-a 'Content-Disposition: attachment; filename="signedkey.msg"' \
<(echo 'Version: 1') \
\) \
\) \
\( \
-c 'application/octet-stream; name="msg.asc"' \
-a 'Content-Disposition: inline; filename="msg.asc"' \
${dir}/${key}-${i}.asc \
\) > ${dir}/${key}-${i}.msg
# add headers and save to mbox
hdr=$(cat ${dir}/${key}-${i}.msg | formail -x 'Content-Type') # hack
cat ${dir}/${key}-${i}.msg | formail \
-I "Date: $(date -R)" \
-I "From: ${from}" \
-I "To: ${uid}" \
-I "Cc: ${from}" \
-I "Subject: Your signed PGP key ${key}" \
-I "Content-Type:${hdr}; protocol=\"application/pgp-encrypted\""
(>&2 echo "key: ${key}, uid: ${uid}")
fi
i=$(expr ${i} + 1)
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment