#!/bin/bash
# -*- bash -*-
# Copyright (C) 2021 Jacob Bachmeyer
#
# This file is part of a testsuite for the GNU FTP upload system.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
: ${GNUPGHOME:=~/.gnupg}
# parse command line
while :; do
case "$1" in
--version)
echo 'gpgv (Testing mock)'
exit 0
;;
--keyring)
case "$2" in
*/*)
Keyrings="$Keyrings \"$2\""
;;
*)
Keyrings="$Keyrings \"${GNUPGHOME}/$2\""
;;
esac
shift 2
;;
--homedir)
GNUPGHOME=$2
shift 2
;;
--status-fd)
StatusFd=$2
shift 2
;;
--logger-fd)
LogFd=$2
shift 2
;;
--*)
echo bogus option $1
shift
;;
*)
break
;;
esac
done
### Output helpers
function status {
if [ x$StatusFd != x ]; then
echo '[GNUPG:]' "$@" >&${StatusFd}
fi
}
function log {
echo gpgv: "$@" >&${LogFd-2}
}
### Keyring handling
# Mock keyrings consist of line-oriented records, in the format:
# ::::
# The field is 16 hex digits.
# The is 'V' for a valid key or 'R' for a revoked key.
# The field may be omitted if same as key ID.
# The field is free-form text.
# The is empty for no expiration.
# search keyrings for the given long key ID
# return success and load global KeyRec if found
function search_keyrings {
KeyRec=$(eval grep -he \"^$1:\" $Keyrings | head -1; \
return ${PIPESTATUS[0]})
return $?
}
# access fields from global KeyRec
function keyrec_id() (IFS=: ; set -- $KeyRec ; echo $1)
function keyrec_status()(IFS=: ; set -- $KeyRec ; echo $2)
function keyrec_pri() (IFS=: ; set -- $KeyRec ; echo ${3:-$1})
function keyrec_user() (IFS=: ; set -- $KeyRec ; echo $4)
function keyrec_exp() (IFS=: ; set -- $KeyRec ; echo $5)
function keyrec_expired() {
[ -n "$(keyrec_exp)" \
-a $(date -d "$(keyrec_exp)" +%s) -lt $(date -d now +%s) ]
}
function keyrec_revoked() { [ "$(keyrec_status)" = R ]; }
### Signature handling
ExitCode=0
# handle SIGNED record in mock data
function handle_SIGNED {
# SIGNED "" \
# ""
local status="$1" sigID="$2" keyID="$3" tstamp="$4"
if [ "x$5" = x ]; then local exptstamp=0
else local exptstamp=$(date -d "$5" +%s) exptstamp_raw="$5"
fi
log Signature made $(date -d "$tstamp" +'%a %b %e %T %Y %Z') \
using RSA key ID ${keyID:8}
if search_keyrings $keyID; then
# key was found in the keyrings
# handle caveats (expired signature, expired key, revoked key)
local chktype=GOOD desctype=Good
keyrec_revoked && chktype=REVKEY
keyrec_expired && chktype=EXPKEY
# Note that signatures from expired and revoked keys are still
# considered "Good" apparently ...
[ $exptstamp -gt 0 \
-a $exptstamp -lt $(date -d now +%s) ] \
&& chktype=EXP desctype=Expired
# ... but a signature that has *itself* expired is reported.
case "$status" in
V) # valid signature
if keyrec_expired; then
status KEYEXPIRED $(date -d "$(keyrec_exp)" +%s)
fi
status SIG_ID testmock/sig/"$sigID"/id \
$(date -d "$tstamp" +'%Y-%m-%d %s')
status ${chktype}SIG $keyID $(keyrec_user)
log ${desctype} signature from \"$(keyrec_user)\"
status VALIDSIG 000000000000000000000000$keyID \
$(date -d "$tstamp" +'%Y-%m-%d %s') \
$exptstamp 3 0 1 2 01 \
000000000000000000000000$(keyrec_pri)
if [ $chktype = EXP ]; then
log Signature expired \
$(date -d "$exptstamp_raw" +'%a %b %e %T %Y %Z')
elif [ $exptstamp -gt 0 ]; then
log Signature expires \
$(date -d "$exptstamp_raw" +'%a %b %e %T %Y %Z')
fi
;;
B) # bogus signature
status BADSIG $keyID $(keyrec_user)
log BAD signature from \"$(keyrec_user)\"
ExitCode=1
;;
esac
else
# key not found
status ERRSIG $keyID 1 2 01 $(date -d "$tstamp" +%s) 9
status NO_PUBKEY $keyID
log "Can't check signature:" public key not found
ExitCode=2
fi
}
# process a "signature" file for a testing run
function process_sig_file {
while read line; do
case "$line" in
-----BEGIN?PGP?SIGNATURE-----)
break
;;
DETACHED?SIGNATURE)
DataFile="$1"
shift
break
esac
done
while read token rest; do
case "$token" in
-----END)
break
;;
Version:)
# this looks like a GPG signature instead of mock data...
# complain... loudly
echo mockgpgv: looks like someone fed a real signature \
to the mock tool
log mock: real GPG signature detected instead of mock test data
status NODATA 3
exit 120
;;
SIGNED_FILE)
if [ x"$DataFile" = x ]; then
log no signed data
log "can't hash datafile:" file open error
ExitCode=2
break
elif [ ! -f "$DataFile" ]; then
log "can't open signed data" $DataFile
log "can't hash datafile:" file open error
ExitCode=2
break
fi
;;
SIGNED)
eval handle_SIGNED $rest
;;
*)
echo $token $rest
;;
esac
done
} <"$SigFile"
# check that we were actually given a file to process
if [ x"$*" = x ]; then
status NODATA 2
log verify signatures failed: eof
exit 2
fi
# check that the file is readable and process it
SigFile="$1"
shift
if [ -r "$SigFile" ] ; then
process_sig_file "$@"
else
log "can't" open '`'"$SigFile'"
log verify signatures failed: file open error
exit 2
fi
exit $ExitCode
#EOF