#!/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