Skip to content

Instantly share code, notes, and snippets.

@tkren
Last active March 12, 2021 19:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tkren/a89d682aa7ab1234941979f1a136e379 to your computer and use it in GitHub Desktop.
Save tkren/a89d682aa7ab1234941979f1a136e379 to your computer and use it in GitHub Desktop.
Setup a static OpenPGP Web Key Directory for your own domain using gnupg and sequoia-sq
#!/usr/bin/env bash
#
# gpg-export-wkd.sh: Uses gnupg and sequoia-sq to generate a Web Key Directory.
# See https://tools.ietf.org/html/draft-koch-openpgp-webkey-service-11 and
# https://wiki.gnupg.org/WKD for details.
#
# Prerequisite: gpg and sq must be located through the PATH.
# Install sq with `crate install sequoia-sq`
# See also https://crates.io/crates/sequoia-sq
#
# Copyright (c) 2021 Thomas Krennwallner <tk@postsubmeta.net>
# Licensed under MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Fail whenever some command exits with an error
set -Eeuo pipefail
trap "log-usage" EXIT
WELLKNOWN=".well-known/openpgpkey"
VERBOSE=0
COMPLETED=0
# Log usage whenever we did not complete successfully
function log-usage() {
if [[ $COMPLETED = 0 ]]; then
cat >&2 <<EOF
Usage:
gpg-export-wkd.sh [FLAGS] [OPTIONS]
FLAGS:
-d, --direct Build WKD for direct method (default: advanced method)
-v, --verbose Print verbose information
OPTIONS:
-e, --email EMAILADDRESS
Use gpg to export all enabled keys for email address EMAILADDRESS
(default: use EMAIL environment variable)
-o, --output PATH
Build WKD in PATH (default: current working directory)
EOF
fi
}
# Log error message on stderr and exit 1
function log-err-exit() {
echo "$@" >&2
exit 1
}
# Log information in verbose mode
function log-info() {
if [[ $VERBOSE = 1 ]]; then
echo "$@"
fi
}
# Export public keys through gpg
#
# We export only enabled keys, see field 12 (key capabilities) in
# http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;hb=HEAD
#
# Argument:
# 1: email address
# Output:
# ASCII-armored public keys for given email address
function gpg-export-keys() {
log-info "Export keys for $1 ..."
declare -a xargsparams
if [[ $VERBOSE = 1 ]]; then
xargsparams=( -t )
fi
gpg -k --with-colons $1 \
| awk -F: '$1 ~ /^pub/ && $12 !~ /D/ {print $5}' \
| xargs -r -L1 "${xargsparams[@]}" \
gpg --export --yes --export-options export-clean --armor
}
# parse command line options
opts=$(getopt -o 'vde:o:' --long 'verbose,direct,email:,output:' \
-n 'gpg-export-wkd.sh' -- "$@")
if [[ $? -ne 0 ]]; then
log-err-exit "getopt failed, terminating..."
fi
eval set -- "$opts"
unset opts
direct=0
email=""
path=""
while true; do
case "$1" in
-v|--verbose) VERBOSE=1; shift; continue ;;
-d|--direct) direct=1; shift; continue ;;
-e|--email) email="$2"; shift 2; continue ;;
-o|--output) path="$2"; shift 2; continue ;;
--) shift; break ;; # parsing complete
*) exit 1 ;; # unknown
esac
done
for arg; do
log-err-exit "Found unknown argument '$arg'"
done
# set default values
email="${email:-$EMAIL}"
path="${path:-$PWD}"
domain=$(cut -d@ -f2 <<<"${email}")
if [[ -z "${email}" ]]; then
log-err-exit "Error: Email address is empty"
fi
# use direct or advanced method for WKD
declare -a wkdparams
wkdparams=( "${path}" "${domain}" )
if [[ -d "${path}/${WELLKNOWN}" ]]; then
echo -n "Updating"
else
echo -n "Creating"
fi
if [[ $direct -eq 1 ]]; then
wkdparams=( -d "${wkdparams[@]}" )
echo -n " direct"
else
echo -n " avanced"
fi
echo " WKD for ${email} in ${path}/${WELLKNOWN}"
# export keys and generate WKD
gpg-export-keys "${email}" | sq wkd generate "${wkdparams[@]}"
COMPLETED=1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment