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