Add mock gpgv signature verification tool and mock tool testsuite
authorJacob Bachmeyer <jcb@gnu.org>
Wed, 10 Mar 2021 05:48:12 +0000 (23:48 -0600)
committerJacob Bachmeyer <jcb@gnu.org>
Wed, 10 Mar 2021 05:48:12 +0000 (23:48 -0600)
testsuite/lib/exec/mockgpgv [new file with mode: 0755]
testsuite/lib/mock.exp [new file with mode: 0644]
testsuite/lib/mockgpg.exp [new file with mode: 0644]
testsuite/mock.gpgv/sign.exp [new file with mode: 0644]

diff --git a/testsuite/lib/exec/mockgpgv b/testsuite/lib/exec/mockgpgv
new file mode 100755 (executable)
index 0000000..c4ccfd2
--- /dev/null
@@ -0,0 +1,239 @@
+#!/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 <http://www.gnu.org/licenses/>.
+
+: ${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:
+#  <long key ID>:<status>:<primary long key ID>:<user ID>:<expiration timestamp>
+#   The <long key ID> field is 16 hex digits.
+#   The <status> is 'V' for a valid key or 'R' for a revoked key.
+#   The <primary long key ID> field may be omitted if same as key ID.
+#   The <user ID> field is free-form text.
+#   The <expiration timestamp> 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 <status> <sigID> <keyID> "<timestamp>" \
+    #  "<expiration timestamp>"
+    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
diff --git a/testsuite/lib/mock.exp b/testsuite/lib/mock.exp
new file mode 100644 (file)
index 0000000..da21208
--- /dev/null
@@ -0,0 +1,40 @@
+# DejaGnu tool init file for testing gpgv mock tests
+
+# 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 <http://www.gnu.org/licenses/>.
+
+set MINLOGD  [testsuite file -source -top lib exec minlogd.pl]
+set MINSMTPD [testsuite file -source -top lib exec minsmtpd.tcl]
+
+set MOCKGPGV [testsuite file -source -top lib exec mockgpgv]
+set ::env(GNUPGHOME) [file join \
+                         [file dirname [testsuite file -object -top]] \
+                         test.tmp gpgv]
+
+load_lib mockgpg.exp
+
+proc put_file { file string } {
+    set chan [open $file w]
+    puts -nonewline $chan $string
+    close $chan
+}
+
+proc mock_exit {} {}
+proc mock_version {} {}
+# The mock tools do not have independent versions.
+
+#EOF
diff --git a/testsuite/lib/mockgpg.exp b/testsuite/lib/mockgpg.exp
new file mode 100644 (file)
index 0000000..a2f702e
--- /dev/null
@@ -0,0 +1,111 @@
+# DejaGnu library file for mockGPG support procedures
+
+# 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 <http://www.gnu.org/licenses/>.
+
+# Wrap value in double quotes if it contains spaces.
+proc _mockGPG_quote_value { val } {
+    if { [regexp {[[:space:]]} $val] } {
+       return "\"$val\""
+    } else {
+       return $val
+    }
+}
+
+# Prepare a keyring file suitable for the GPG mock tools.
+# Call as:
+# write_test_keyring /some/file/some/where {
+#    { id <subkey-long-ID> name <user> [is <state>]
+#      [subkey-of <primary-key-long-ID>]
+#      [expires <expiration>] }...
+# }
+proc write_test_keyring { file keylist } {
+    set keys [list]
+    foreach keyrec $keylist {
+       set keyfields [list {} V {} {} {}]
+       foreach { fld val } $keyrec {
+           switch -- $fld {
+               id {
+                   lset keyfields 0 [format "%016s" $val]
+               }
+               name {
+                   lset keyfields 3 $val
+               }
+               is {
+                   switch -- $val {
+                       valid   { lset keyfields 1 V }
+                       revoked { lset keyfields 1 R }
+                   }
+               }
+               subkey-of {
+                   lset keyfields 2 [format "%016s" $val]
+               }
+               expired -
+               expires {
+                   lset keyfields 4 $val
+               }
+               default { error "invalid key record: $keyrec" }
+           }
+       }
+       lappend keys [join $keyfields ":"]
+    }
+    set chan [open $file w]
+    foreach key $keys { puts $chan $key }
+    close $chan
+}
+
+# Return a signature suitable for the GPG mock tools.
+# Call as:
+# make_test_signature <good|bad> <sigID> <keyID> [<timestamp>] \
+#     [expires <expiration>]
+proc make_test_signature { validity sigID keyID
+                          {timestamp {5 minutes ago}} args } {
+    set sig "SIGNED"
+
+    if { $validity eq "good" } {
+       lappend sig V
+    } elseif { $validity eq "bad" } {
+       lappend sig B
+    } else { error "bad call to make_test_signature" }
+
+    lappend sig [_mockGPG_quote_value $sigID]
+    lappend sig [_mockGPG_quote_value [format "%016s" $keyID]]
+    lappend sig [_mockGPG_quote_value $timestamp]
+
+    if { [llength $args] > 1 && [regexp {expire[ds]} [lindex $args 0]] } {
+       lappend sig [_mockGPG_quote_value [lindex $args 1]]
+    }
+
+    return [join $sig " "]
+}
+
+# Combine a message and a signature (from [make_test_signature ...])
+proc sign_test_message { message signature } {
+    set msg "-----BEGIN PGP SIGNED MESSAGE-----\nHash: SHA1\n\n"
+    append msg $message
+    append msg "\n-----BEGIN PGP SIGNATURE-----\n"
+    append msg $signature
+    append msg "\n-----END PGP SIGNATURE-----\n"
+    return $msg
+}
+
+# Return a detached signature
+proc sign_test_file { filename signature } {
+    return "DETACHED SIGNATURE\nSIGNED_FILE ${filename}\n$signature\n"
+}
+
+#EOF
diff --git a/testsuite/mock.gpgv/sign.exp b/testsuite/mock.gpgv/sign.exp
new file mode 100644 (file)
index 0000000..5f8208f
--- /dev/null
@@ -0,0 +1,741 @@
+# Signature "verification" tests for GPG mock
+
+# 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 <http://www.gnu.org/licenses/>.
+
+file mkdir $::env(GNUPGHOME)
+
+write_test_keyring [file join $::env(GNUPGHOME) dg1.gpg] {
+    { id 1001 name {test 1-1} }
+    { id 1002 name {test 1-2} }
+    { id 1003 name {test 1-3} expires {+5 minutes} }
+    { id 1004 name {test 1-4 (expired)} expired {5 minutes ago} }
+    { id 1005 name {test 1-5 (revoked)} is revoked }
+    { id 1006 name {test 1-6 (revoked expired)}
+       is revoked expired {5 minutes ago} }
+}
+
+write_test_keyring [file join $::env(GNUPGHOME) dg2.gpg] {
+    { id 1011 name {test 2-1 (primary)} }
+    { id 1012 name {test 2-2 (subkey)} subkey-of 1011 }
+    { id 1013 name {test 2-3 (subkey)} subkey-of 1011 expires {+5 minutes} }
+    { id 1014 name {test 2-4 (expired subkey)}
+       subkey-of 1011 expired {5 minutes ago} }
+    { id 1015 name {test 2-5 (revoked subkey)}
+       subkey-of 1011 is revoked }
+    { id 1016 name {test 2-6 (revoked expired subkey)}
+       subkey-of 1011 is revoked expired {5 minutes ago} }
+}
+
+#
+
+proc prepare_test_group { stem message signature } {
+    put_file $stem $message
+    put_file "${stem}.asc" [sign_test_message $message $signature]
+    put_file "${stem}.sig" [sign_test_file $stem $signature]
+}
+
+proc spawn_gpgv { keyrings args } {
+    global MOCKGPGV
+    upvar 1 spawn_id spawn_id
+    set cmd [list spawn $MOCKGPGV --logger-fd 2 --status-fd 2]
+    foreach ring $keyrings { lappend cmd --keyring $ring }
+    verbose -log "$cmd $args"
+    eval $cmd $args
+}
+
+# InitialCapital variable names may be used in the $expect block.
+# The "test_dir" variable is also set for the $init block.
+proc run_gpgv_test { Name stem keyrings exitCode init phases assess expect } {
+    set test_dir [file join \
+                     [file dirname [testsuite file -object -top]] test.tmp]
+    file mkdir $test_dir
+
+    eval $init
+
+    array set A {}
+    append expect {
+       -re {^[\r\n]+} { exp_continue }
+       -re .+ {
+           warning "$Name (${Phase}): unexpected output from mockgpgv"
+           exp_continue
+       }
+       eof { set waited [wait] }
+    }
+
+    foreach Phase $phases {
+       foreach {key desc} $assess { set A($Phase,$key) 0 }
+       switch -- $Phase {
+           inline {
+               spawn_gpgv $keyrings \
+                   [file join $test_dir "${stem}.asc"]
+           }
+           detached {
+               spawn_gpgv $keyrings \
+                   [file join $test_dir "${stem}.sig"] \
+                   [file join $test_dir "${stem}"]
+           }
+           file_missing {
+               spawn_gpgv $keyrings \
+                   [file join $test_dir "${stem}.sig"]
+           }
+       }
+       expect $expect
+       if { [lindex $waited 2] != 0 } {
+           perror "OS error in child process: $waited"
+       } else {
+           if { [lindex $waited 3] == $exitCode } {
+               pass "$Name (${Phase}): expected exit code"
+           } else {
+               fail "$Name (${Phase}): expected exit code"
+               verbose -log [format "%s (%s): expected exit code %d got %d" \
+                                 $Name $Phase $exitCode [lindex $waited 3]]
+           }
+       }
+       foreach {key desc} $assess {
+           if { $A($Phase,$key) } {
+               pass "$Name (${Phase}): $desc"
+           } else {
+               fail "$Name (${Phase}): $desc"
+           }
+       }
+    }
+}
+proc do_gpgv_test { Name stem keyrings exitCode signature assess expect } {
+    run_gpgv_test $Name $stem $keyrings $exitCode \
+       "prepare_test_group \[file join \$test_dir {$stem}\] {$Name} {$signature}"\
+       {inline detached} $assess $expect
+}
+
+#
+
+do_gpgv_test "unknown key used for signature" t0a {dg1.gpg dg2.gpg} 2 \
+    [make_test_signature good 00 8765 "5 minutes ago"] {
+       sighdr "signature header" ERRSIG "ERRSIG status"
+       NO_PUBKEY "NO_PUBKEY status" keynotfound "key not found message"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00008765[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Can't check signature: public key not found[\r\n]+} {
+           set A($Phase,keynotfound) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] ERRSIG 0{12}8765 1 2 01 [0-9]+ 9[\r\n]+} {
+           set A($Phase,ERRSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] NO_PUBKEY 0{12}8765[\r\n]+} {
+           set A($Phase,NO_PUBKEY) 1
+           exp_continue
+       }
+    }
+run_gpgv_test "detached signature without signed file" t0b {dg1.gpg dg2.gpg} 2 \
+    { put_file [file join $test_dir t0b.sig] \
+         [sign_test_file t0b \
+              [make_test_signature good 00 1001 "5 minutes ago"]]
+    } {file_missing} {
+       nodata "missing data message" canthash "file open error message"
+    } {
+       -re {^gpgv: no signed data[\r\n]+} {
+           set A($Phase,nodata) 1
+           exp_continue
+       }
+       -re {^gpgv: can't hash datafile: file open error[\r\n]+} {
+           set A($Phase,canthash) 1
+           exp_continue
+       }
+    }
+run_gpgv_test "detached signature with missing signed file" t0c {dg1.gpg} 2 \
+    { put_file [file join $test_dir t0c.sig] \
+         [sign_test_file t0c \
+              [make_test_signature good 00 1001 "5 minutes ago"]]
+    } {detached} {
+       cantopen "missing file message" canthash "file open error message"
+    } {
+       -re {^gpgv: can't open signed data [^\r\n]+[\r\n]+} {
+           set A($Phase,cantopen) 1
+           exp_continue
+       }
+       -re {^gpgv: can't hash datafile: file open error[\r\n]+} {
+           set A($Phase,canthash) 1
+           exp_continue
+       }
+    }
+run_gpgv_test "all signed files missing" t0d {dg1.gpg} 2 \
+    { put_file [file join $test_dir t0d] $Name } {inline detached} {
+       cantopen "missing file message" failuremsg "verify failure message"
+    } {
+       -re {^gpgv: can't open [^\r\n]+[\r\n]+} {
+           set A($Phase,cantopen) 1
+           exp_continue
+       }
+       -re {^gpgv: verify signatures failed: file open error[\r\n]+} {
+           set A($Phase,failuremsg) 1
+           exp_continue
+       }
+    }
+
+do_gpgv_test "valid signature" t1a {dg1.gpg} 0 \
+    [make_test_signature good 00 1001 "5 minutes ago"] {
+       sighdr "signature header" goodsigmsg "good signature message"
+       SIG_ID "SIG_ID status"
+       GOODSIG "GOODSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001001[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Good signature from "test 1-1"[\r\n]+} {
+           set A($Phase,goodsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/00/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] GOODSIG 0{12}1001 test 1-1[\r\n]+} {
+           set A($Phase,GOODSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1001 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1001[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+do_gpgv_test "valid signature from subkey" t1b {dg2.gpg} 0 \
+    [make_test_signature good 80 1012 "5 minutes ago"] {
+       sighdr "signature header" goodsigmsg "good signature message"
+       SIG_ID "SIG_ID status"
+       GOODSIG "GOODSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001012[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Good signature from "test 2-2 \(subkey\)"[\r\n]+} {
+           set A($Phase,goodsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/80/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] GOODSIG 0{12}1012 test 2-2 \(subkey\)[\r\n]+} {
+           set A($Phase,GOODSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1012 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1011[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+
+do_gpgv_test "bad signature" t2a {dg1.gpg} 1 \
+    [make_test_signature bad 01 1002 "5 minutes ago"] {
+       sighdr "signature header" badsigmsg "bad signature message"
+       BADSIG "BADSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001002[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: BAD signature from "test 1-2"[\r\n]+} {
+           set A($Phase,badsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] BADSIG 0{12}1002 test 1-2[\r\n]+} {
+           set A($Phase,BADSIG) 1
+           exp_continue
+       }
+    }
+do_gpgv_test "bad signature from subkey" t2b {dg2.gpg} 1 \
+    [make_test_signature bad 01 1012 "5 minutes ago"] {
+       sighdr "signature header" badsigmsg "bad signature message"
+       BADSIG "BADSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001012[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: BAD signature from "test 2-2 \(subkey\)"[\r\n]+} {
+           set A($Phase,badsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] BADSIG 0{12}1012 test 2-2 \(subkey\)[\r\n]+} {
+           set A($Phase,BADSIG) 1
+           exp_continue
+       }
+    }
+
+do_gpgv_test "expired signature" t3a {dg1.gpg} 0 \
+    [make_test_signature good 02 1001 "10 minutes ago" expired "5 minutes ago"] {
+       sighdr "signature header" expsigmsg "expired signature message"
+       sigexpmsg "signature expiration message"
+       SIG_ID "SIG_ID status"
+       EXPSIG "EXPSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001001[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Expired signature from "test 1-1"[\r\n]+} {
+           set A($Phase,expsigmsg) 1
+           exp_continue
+       }
+       -re {^gpgv: Signature expired [^:]+:..:[^\r\n]+[\r\n]+} {
+           set A($Phase,sigexpmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/02/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPSIG 0{12}1001 test 1-1[\r\n]+} {
+           set A($Phase,EXPSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1001 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1001[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+do_gpgv_test "expired signature from subkey" t3b {dg2.gpg} 0 \
+    [make_test_signature good 82 1012 "10 minutes ago" expired "5 minutes ago"] {
+       sighdr "signature header" expsigmsg "expired signature message"
+       sigexpmsg "signature expiration message"
+       SIG_ID "SIG_ID status"
+       EXPSIG "EXPSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001012[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Expired signature from "test 2-2 \(subkey\)"[\r\n]+} {
+           set A($Phase,expsigmsg) 1
+           exp_continue
+       }
+       -re {^gpgv: Signature expired [^:]+:..:[^\r\n]+[\r\n]+} {
+           set A($Phase,sigexpmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/82/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPSIG 0{12}1012 test 2-2 \(subkey\)[\r\n]+} {
+           set A($Phase,EXPSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1012 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1011[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+
+do_gpgv_test "good signature from expired key" t4a {dg1.gpg} 0 \
+    [make_test_signature good 03 1004 "6 minutes ago"] {
+       sighdr "signature header" goodsigmsg "good signature message"
+       KEYEXPIRED "KEYEXPIRED status" SIG_ID "SIG_ID status"
+       EXPKEYSIG "EXPKEYSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001004[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Good signature from "test 1-4 \(expired\)"[\r\n]+} {
+           set A($Phase,goodsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] KEYEXPIRED [0-9]+[\r\n]+} {
+           set A($Phase,KEYEXPIRED) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/03/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPKEYSIG 0{12}1004 test 1-4 \(expired\)[\r\n]+} {
+           set A($Phase,EXPKEYSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1004 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1004[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+do_gpgv_test "good signature from expired subkey" t4b {dg2.gpg} 0 \
+    [make_test_signature good 83 1014 "6 minutes ago"] {
+       sighdr "signature header" goodsigmsg "good signature message"
+       KEYEXPIRED "KEYEXPIRED status" SIG_ID "SIG_ID status"
+       EXPKEYSIG "EXPKEYSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001014[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Good signature from "test 2-4 \(expired subkey\)"[\r\n]+} {
+           set A($Phase,goodsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] KEYEXPIRED [0-9]+[\r\n]+} {
+           set A($Phase,KEYEXPIRED) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/83/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPKEYSIG 0{12}1014 test 2-4 \(expired subkey\)[\r\n]+} {
+           set A($Phase,EXPKEYSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1014 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1011[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+
+do_gpgv_test "expired signature from expired key" t5a {dg1.gpg} 0 \
+    [make_test_signature good 04 1004 "10 minutes ago" expired "5 minutes ago"] {
+       sighdr "signature header" expsigmsg "expired signature message"
+       sigexpmsg "signature expiration message"
+       KEYEXPIRED "KEYEXPIRED status" SIG_ID "SIG_ID status"
+       EXPSIG "EXPSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001004[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Expired signature from "test 1-4 \(expired\)"[\r\n]+} {
+           set A($Phase,expsigmsg) 1
+           exp_continue
+       }
+       -re {^gpgv: Signature expired [^:]+:..:[^\r\n]+[\r\n]+} {
+           set A($Phase,sigexpmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] KEYEXPIRED [0-9]+[\r\n]+} {
+           set A($Phase,KEYEXPIRED) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/04/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPSIG 0{12}1004 test 1-4 \(expired\)[\r\n]+} {
+           set A($Phase,EXPSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1004 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1004[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+do_gpgv_test "expired signature from expired subkey" t5b {dg2.gpg} 0 \
+    [make_test_signature good 84 1014 "10 minutes ago" expired "5 minutes ago"] {
+       sighdr "signature header" expsigmsg "expired signature message"
+       sigexpmsg "signature expiration message"
+       KEYEXPIRED "KEYEXPIRED status" SIG_ID "SIG_ID status"
+       EXPSIG "EXPSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001014[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Expired signature from "test 2-4 \(expired subkey\)"[\r\n]+} {
+           set A($Phase,expsigmsg) 1
+           exp_continue
+       }
+       -re {^gpgv: Signature expired [^:]+:..:[^\r\n]+[\r\n]+} {
+           set A($Phase,sigexpmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] KEYEXPIRED [0-9]+[\r\n]+} {
+           set A($Phase,KEYEXPIRED) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/84/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPSIG 0{12}1014 test 2-4 \(expired subkey\)[\r\n]+} {
+           set A($Phase,EXPSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1014 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1011[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+
+do_gpgv_test "signature from revoked key" t6a {dg1.gpg} 0 \
+    [make_test_signature good 05 1005 "5 minutes ago"] {
+       sighdr "signature header" goodsigmsg "good signature message"
+       SIG_ID "SIG_ID status"
+       REVKEYSIG "REVKEYSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001005[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Good signature from "test 1-5 \(revoked\)"[\r\n]+} {
+           set A($Phase,goodsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/05/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] REVKEYSIG 0{12}1005 test 1-5 \(revoked\)[\r\n]+} {
+           set A($Phase,REVKEYSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1005 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1005[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+do_gpgv_test "signature from revoked subkey" t6b {dg2.gpg} 0 \
+    [make_test_signature good 85 1015 "5 minutes ago"] {
+       sighdr "signature header" goodsigmsg "good signature message"
+       SIG_ID "SIG_ID status"
+       REVKEYSIG "REVKEYSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001015[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Good signature from "test 2-5 \(revoked subkey\)"[\r\n]+} {
+           set A($Phase,goodsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/85/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] REVKEYSIG 0{12}1015 test 2-5 \(revoked subkey\)[\r\n]+} {
+           set A($Phase,REVKEYSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1015 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1011[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+
+do_gpgv_test "expired signature from revoked key" t7a {dg1.gpg} 0 \
+    [make_test_signature good 06 1005 "10 minutes ago" expired "5 minutes ago"] {
+       sighdr "signature header" expsigmsg "expired signature message"
+       sigexpmsg "signature expiration message"
+       SIG_ID "SIG_ID status"
+       EXPSIG "EXPSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001005[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Expired signature from "test 1-5 \(revoked\)"[\r\n]+} {
+           set A($Phase,expsigmsg) 1
+           exp_continue
+       }
+       -re {^gpgv: Signature expired [^:]+:..:[^\r\n]+[\r\n]+} {
+           set A($Phase,sigexpmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/06/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPSIG 0{12}1005 test 1-5 \(revoked\)[\r\n]+} {
+           set A($Phase,EXPSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1005 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1005[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+do_gpgv_test "expired signature from revoked subkey" t7b {dg2.gpg} 0 \
+    [make_test_signature good 86 1015 "10 minutes ago" expired "5 minutes ago"] {
+       sighdr "signature header" expsigmsg "expired signature message"
+       sigexpmsg "signature expiration message"
+       SIG_ID "SIG_ID status"
+       EXPSIG "EXPSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001015[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Expired signature from "test 2-5 \(revoked subkey\)"[\r\n]+} {
+           set A($Phase,expsigmsg) 1
+           exp_continue
+       }
+       -re {^gpgv: Signature expired [^:]+:..:[^\r\n]+[\r\n]+} {
+           set A($Phase,sigexpmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/86/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPSIG 0{12}1015 test 2-5 \(revoked subkey\)[\r\n]+} {
+           set A($Phase,EXPSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1015 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1011[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+
+do_gpgv_test "signature from revoked expired key" t8a {dg1.gpg} 0 \
+    [make_test_signature good 07 1006 "6 minutes ago"] {
+       sighdr "signature header" goodsigmsg "good signature message"
+       KEYEXPIRED "KEYEXPIRED status" SIG_ID "SIG_ID status"
+       EXPKEYSIG "EXPKEYSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001006[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Good signature from "test 1-6 \(revoked expired\)"[\r\n]+} {
+           set A($Phase,goodsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] KEYEXPIRED [0-9]+[\r\n]+} {
+           set A($Phase,KEYEXPIRED) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/07/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPKEYSIG 0{12}1006 test 1-6 \(revoked expired\)[\r\n]+} {
+           set A($Phase,EXPKEYSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1006 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1006[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+do_gpgv_test "signature from revoked expired subkey" t8b {dg2.gpg} 0 \
+    [make_test_signature good 87 1016 "6 minutes ago"] {
+       sighdr "signature header" goodsigmsg "good signature message"
+       KEYEXPIRED "KEYEXPIRED status" SIG_ID "SIG_ID status"
+       EXPKEYSIG "EXPKEYSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001016[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Good signature from "test 2-6 \(revoked expired subkey\)"[\r\n]+} {
+           set A($Phase,goodsigmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] KEYEXPIRED [0-9]+[\r\n]+} {
+           set A($Phase,KEYEXPIRED) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/87/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPKEYSIG 0{12}1016 test 2-6 \(revoked expired subkey\)[\r\n]+} {
+           set A($Phase,EXPKEYSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1016 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1011[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+
+do_gpgv_test "expired signature from revoked key" t9a {dg1.gpg} 0 \
+    [make_test_signature good 08 1006 "10 minutes ago" expired "5 minutes ago"] {
+       sighdr "signature header" expsigmsg "expired signature message"
+       sigexpmsg "signature expiration message"
+       KEYEXPIRED "KEYEXPIRED status" SIG_ID "SIG_ID status"
+       EXPSIG "EXPSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001006[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Expired signature from "test 1-6 \(revoked expired\)"[\r\n]+} {
+           set A($Phase,expsigmsg) 1
+           exp_continue
+       }
+       -re {^gpgv: Signature expired [^:]+:..:[^\r\n]+[\r\n]+} {
+           set A($Phase,sigexpmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] KEYEXPIRED [0-9]+[\r\n]+} {
+           set A($Phase,KEYEXPIRED) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/08/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPSIG 0{12}1006 test 1-6 \(revoked expired\)[\r\n]+} {
+           set A($Phase,EXPSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1006 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1006[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }
+do_gpgv_test "expired signature from expired subkey" t9b {dg2.gpg} 0 \
+    [make_test_signature good 88 1016 "10 minutes ago" expired "5 minutes ago"] {
+       sighdr "signature header" expsigmsg "expired signature message"
+       sigexpmsg "signature expiration message"
+       KEYEXPIRED "KEYEXPIRED status" SIG_ID "SIG_ID status"
+       EXPSIG "EXPSIG status" VALIDSIG "VALIDSIG status"
+    } {
+       -re {^gpgv: Signature made [^:]+:..:[^k]+key ID 00001016[\r\n]+} {
+           set A($Phase,sighdr) 1
+           exp_continue
+       }
+       -re {^gpgv: Expired signature from "test 2-6 \(revoked expired subkey\)"[\r\n]+} {
+           set A($Phase,expsigmsg) 1
+           exp_continue
+       }
+       -re {^gpgv: Signature expired [^:]+:..:[^\r\n]+[\r\n]+} {
+           set A($Phase,sigexpmsg) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] KEYEXPIRED [0-9]+[\r\n]+} {
+           set A($Phase,KEYEXPIRED) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] SIG_ID testmock/sig/88/id ....-..-.. [0-9]+[\r\n]+} {
+           set A($Phase,SIG_ID) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] EXPSIG 0{12}1016 test 2-6 \(revoked expired subkey\)[\r\n]+} {
+           set A($Phase,EXPSIG) 1
+           exp_continue
+       }
+       -re {^\[GNUPG:\] VALIDSIG 0{36}1016 [-0-9]+ [0-9]+ [0-9]+ 3 0 1 2 01 0{36}1011[\r\n]+} {
+           set A($Phase,VALIDSIG) 1
+           exp_continue
+       }
+    }