--- /dev/null
+# DejaGnu library file for timestamp ratchet handling
+
+# Copyright (C) 2023 Jacob Bachmeyer
+#
+# This file is part of a testsuite for the GNU Secure Software Gatekeeper.
+#
+# 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/>.
+
+# The timestamp ratchet, also known as the "serials" file, enables the
+# gatekeeper to detect and reject replay attacks. The actual file is a
+# flat text file, but a format change to an indexed text-based database is
+# planned.
+
+# allow a few seconds difference from expected values to accommodate delays
+# while running the testsuite
+set SERIALS_TOLERANCE 5
+
+# entry:
+# { <filename> <timestamp> ... }
+# FILENAME is the full filename relative to the zone root
+# TIMESTAMP is a timestamp acceptable for [clock scan ...]
+# Addtional fields to be added to support later formats.
+
+proc write_serials_v0 { filename contents } {
+ set chan [open $filename w]
+
+ foreach cell $contents {
+ puts $chan [format "%s:%d" \
+ [lindex $cell 0] \
+ [clock scan [lindex $cell 1]]]
+ }
+
+ close $chan
+}
+
+proc check_serials_v0 { testname filename contents } {
+ global SERIALS_TOLERANCE
+
+ array set want {}
+ foreach cell $contents {
+ set want([lindex $cell 0]) [clock scan [lindex $cell 1]]
+ }
+
+ set result pass
+ verbose -log "Reading legacy format serials file $filename..."
+ spawn -open [open $filename r]
+ expect {
+ -re {^([^:]+):([^\r\n]+)[\r\n]+} {
+ regsub -all {[[:space:]]+} $expect_out(1,string) "" fname
+ regsub -all {[[:space:]]+} $expect_out(2,string) "" tstamp
+ if { [info exists want($fname)] } {
+ if { [expr { abs($want($fname) - $tstamp) }]
+ < $SERIALS_TOLERANCE } {
+ unset want($fname)
+ } else {
+ verbose -log "unexpected timestamp for $fname:"
+ verbose -log " want: $want($fname)"
+ verbose -log " have: $tstamp"
+ set result fail
+ }
+ }
+ exp_continue
+ }
+ eof { catch close }
+ }
+
+ if { [llength [array get want]] > 0 } {
+ verbose -log "expected record(s) not found:"
+ verbose -log " want: [array names want]"
+ set result fail
+ }
+
+ $result "$testname: directive timestamp ratchet"
+}
+
+#EOF