f9efe2
#!/bin/bash
f9efe2
f9efe2
# Copyright 2018 B. Persson, Bjorn@Rombobeorn.se
f9efe2
#
f9efe2
# This material is provided as is, with absolutely no warranty expressed
f9efe2
# or implied. Any use is at your own risk.
f9efe2
#
f9efe2
# Permission is hereby granted to use or copy this shellscript
f9efe2
# for any purpose, provided the above notices are retained on all copies.
f9efe2
# Permission to modify the code and to distribute modified code is granted,
f9efe2
# provided the above notices are retained, and a notice that the code was
f9efe2
# modified is included with the above copyright notice.
f9efe2
f9efe2
f9efe2
function print_help {
f9efe2
    cat <<'EOF'
f9efe2
Usage: gpgverify --keyring=<pathname> --signature=<pathname> --data=<pathname>
f9efe2
f9efe2
gpgverify is a wrapper around gpgv designed for easy and safe scripting. It
f9efe2
verifies a file against a detached OpenPGP signature and a keyring. The keyring
f9efe2
shall contain all the keys that are trusted to certify the authenticity of the
f9efe2
file, and must not contain any untrusted keys.
f9efe2
f9efe2
The differences, compared to invoking gpgv directly, are that gpgverify accepts
f9efe2
the keyring in either ASCII-armored or unarmored form, and that it will not
f9efe2
accidentally use a default keyring in addition to the specified one.
f9efe2
f9efe2
Parameters:
f9efe2
  --keyring=<pathname>    keyring with all the trusted keys and no others
f9efe2
  --signature=<pathname>  detached signature to verify
f9efe2
  --data=<pathname>       file to verify against the signature
f9efe2
EOF
f9efe2
}
f9efe2
f9efe2
f9efe2
fatal_error() {
f9efe2
    message="$1"  # an error message
f9efe2
    status=$2     # a number to use as the exit code
f9efe2
    echo "gpgverify: $message" >&2
f9efe2
    exit $status
f9efe2
}
f9efe2
f9efe2
f9efe2
require_parameter() {
f9efe2
    term="$1"   # a term for a required parameter
f9efe2
    value="$2"  # Complain and terminate if this value is empty.
f9efe2
    if test -z "${value}" ; then
f9efe2
        fatal_error "No ${term} was provided." 2
f9efe2
    fi
f9efe2
}
f9efe2
f9efe2
f9efe2
check_status() {
f9efe2
    action="$1"  # a string that describes the action that was attempted
f9efe2
    status=$2    # the exit code of the command
f9efe2
    if test $status -ne 0 ; then
f9efe2
        fatal_error "$action failed." $status
f9efe2
    fi
f9efe2
}
f9efe2
f9efe2
f9efe2
# Parse the command line.
f9efe2
keyring=
f9efe2
signature=
f9efe2
data=
f9efe2
for parameter in "$@" ; do
f9efe2
    case "${parameter}" in
f9efe2
        (--help)
f9efe2
            print_help
f9efe2
            exit
f9efe2
            ;;
f9efe2
        (--keyring=*)
f9efe2
            keyring="${parameter#*=}"
f9efe2
            ;;
f9efe2
        (--signature=*)
f9efe2
            signature="${parameter#*=}"
f9efe2
            ;;
f9efe2
        (--data=*)
f9efe2
            data="${parameter#*=}"
f9efe2
            ;;
f9efe2
        (*)
f9efe2
            fatal_error "Unknown parameter: \"${parameter}\"" 2
f9efe2
            ;;
f9efe2
    esac
f9efe2
done
f9efe2
require_parameter 'keyring' "${keyring}"
f9efe2
require_parameter 'signature' "${signature}"
f9efe2
require_parameter 'data file' "${data}"
f9efe2
f9efe2
# Make a temporary working directory.
f9efe2
workdir="$(mktemp --directory)"
f9efe2
check_status 'Making a temporary directory' $?
f9efe2
workring="${workdir}/keyring.gpg"
f9efe2
f9efe2
# Decode any ASCII armor on the keyring. This is harmless if the keyring isn't
f9efe2
# ASCII-armored.
f9efe2
gpg2 --homedir="${workdir}" --yes --output="${workring}" --dearmor "${keyring}"
f9efe2
check_status 'Decoding the keyring' $?
f9efe2
f9efe2
# Verify the signature using the decoded keyring.
f9efe2
gpgv2 --homedir="${workdir}" --keyring="${workring}" "${signature}" "${data}"
f9efe2
check_status 'Signature verification' $?
f9efe2
f9efe2
# (--homedir isn't actually necessary. --dearmor processes only the input file,
f9efe2
# and if --keyring is used and contains a slash, then gpgv2 uses only that
f9efe2
# keyring. Thus neither command will look for a default keyring, but --homedir
f9efe2
# makes extra double sure that no default keyring will be touched in case
f9efe2
# another version of GPG works differently.)
f9efe2
f9efe2
# Clean up. (This is not done in case of an error that may need inspection.)
f9efe2
rm --recursive --force ${workdir}