From: Jacob Bachmeyer Date: Fri, 8 Sep 2023 23:38:00 +0000 (-0500) Subject: Move replay check to operations list handlers X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=6d31f2368b084051b643320ce420b6f00f728144;p=gatekeeper.git Move replay check to operations list handlers This also splits the test into separate check and update steps, such that the timestamp ratchet file is no longer updated when a packet is rejected. --- diff --git a/gatekeeper.pl b/gatekeeper.pl index edd205a..4ee13da 100755 --- a/gatekeeper.pl +++ b/gatekeeper.pl @@ -1722,11 +1722,11 @@ Install a file into the managed tree as DESTINATION_FILENAME. my $info = shift; my $packet = $info->{packet}; + my $install_as = $step->[1]; + # If the upload installs a file, check if the final file exists; if so, # require the 'replace' option to be set. - my $install_as = $step->[1]; - my $pubfinal = File::Spec::Unix->catfile (pub => @{$packet->target_directory}, $install_as); my $final_upload = File::Spec->catfile @@ -1740,6 +1740,13 @@ Install a file into the managed tree as DESTINATION_FILENAME. summary => $pubfinal." exists and 'replace' was not selected"; } } + + # If a file is to be installed, ensure that this directive is newer than + # any previous directive installing a file under the same full name. + + ::check_timestamp_ratchet + (File::Spec::Unix->catfile($packet->target_directory, $install_as), + $packet->auth_signature_timestamp); } sub execute { @@ -1765,6 +1772,10 @@ Install a file into the managed tree as DESTINATION_FILENAME. mkdir_p CONF_DIR_Public, @$directory; + ::advance_timestamp_ratchet + (File::Spec::Unix->catfile($packet->target_directory, $install_as), + $packet->auth_signature_timestamp); + # We now allow overwriting of files - without warning!! if (-e $final_signature || -e $final_upload) { # previous validation has ensured that the 'replace' option is set @@ -1970,6 +1981,7 @@ BEGIN { sub auth_keyrings; sub auth_signature_fingerprints; + sub auth_signature_timestamp; sub parse; sub auth_check; @@ -2070,8 +2082,6 @@ BEGIN { summary => "gpg verification problem: could not extract timestamp" unless defined $dsig_info->{sig_creation}; check_signature_timestamp(directive => $dsig_info->{sig_creation}); - - ::check_replay($self->{oplist}, $dsig_info->{sig_creation}); } sub auth_signature_fingerprints { @@ -2083,6 +2093,15 @@ BEGIN { return $self->{auth_directive_signature_info}{key_fingerprint}; } + sub auth_signature_timestamp { + my $self = shift; + + return () + unless $self->{auth_directive_signature_info} + && $self->{auth_directive_signature_info}{sig_creation}; + return $self->{auth_directive_signature_info}{sig_creation}; + } + sub upload_check { } sub install { @@ -3145,6 +3164,56 @@ sub advance_timestamp_ratchet { return $old_epoch; } +=item $epoch = check_timestamp_ratchet ( $full_filename, $epoch ) + +Locate the stored timestamp for FULL_FILENAME, which is relative to the +root of the managed tree, and verify that the given EPOCH is newer. Return +the stored timestamp. + +An exception is thrown if the given EPOCH timestamp is not newer than the +stored value. An undefined value is returned if FULL_FILENAME did not have +a stored timestamp. + +=cut + +sub check_timestamp_ratchet { + my $full_filename = shift; + my $new_epoch = shift; + + my $serials_path = File::Spec->catfile(CONF_DIR_State, 'serials'); + my $serials_flag_name = File::Spec->catfile(CONF_DIR_State, 'serials.flag'); + + open my $serials_flag, '>', $serials_flag_name + or die "open serials flag: $!"; + flock $serials_flag, LOCK_EX + or die "lock serials flag: $!"; + + return undef unless -e $serials_path; + + my $old_epoch = undef; + + open my $serials, '<', $serials_path or die "open $serials_path: $!"; + flock $serials, LOCK_EX; + local *_; + while (<$serials>) { + s/\s+//g; + m/^(.*?):(.*?)$/ + or abort "bad line in serials file: [$_]"; + $old_epoch = $2 if $1 eq $full_filename; + } + flock $serials, LOCK_UN or die "unlock serials: $!"; + close $serials or die "close serials: $!"; + flock $serials_flag, LOCK_UN or die "unlock serials flag: $!"; + close $serials_flag or die "close serials flag: $!"; + + if (defined $old_epoch and $old_epoch >= $new_epoch) { + throw signature_replay => + previous_timestamp => $old_epoch, new_timestamp => $new_epoch + } + + return $old_epoch; +} + =item check_signature_timestamp ( $what , $timestamp ) Report the WHAT signature TIMESTAMP to the log and raise an exception if @@ -3167,35 +3236,6 @@ sub check_signature_timestamp { } } -=item check_replay ( $oplist, $timestamp ) - -Check that OPLIST has not been seen before. This is accomplished by -storing directive signature timestamps, indexed by the name of the -published file they installed. The TIMESTAMP is the signature creation -timestamp obtained from C for this directive. - -An exception is thrown if this directive is not the newest we have seen for -the file it seeks to install. - -=cut - -sub check_replay { - my $ops = shift; - my $timestamp = shift; - - my $op_header = $ops->[0][1]; - - # If a file is to be installed, ensure that this directive is newer than - # any previous directive installing a file under the same full name. - if (grep $_->[0] eq 'install', @$ops) { - foreach my $installed (map $_->[1], grep $_->[0] eq 'install', @$ops) { - my $full_filename = File::Spec::Unix->catfile($op_header->{directory}, - $installed); - advance_timestamp_ratchet($full_filename, $timestamp); - } - } -} - =back diff --git a/testsuite/gatekeeper.all/03_triplet.exp b/testsuite/gatekeeper.all/03_triplet.exp index f8bec87..f9df22b 100644 --- a/testsuite/gatekeeper.all/03_triplet.exp +++ b/testsuite/gatekeeper.all/03_triplet.exp @@ -1407,7 +1407,6 @@ foreach FVER $DIRECTIVE_FORMAT_VERSIONS { file { test } fsig { good 0B 1000 } } }] check { - serials updated file-tree { { inbox stage archive } empty {} { scratch } files { @@ -1451,7 +1450,6 @@ foreach FVER $DIRECTIVE_FORMAT_VERSIONS { file { test } fsig { good 0B 1000 } } }] check { - serials updated file-tree { { inbox stage archive } empty {} { scratch } files { diff --git a/testsuite/lib/tool/gatekeeper.exp b/testsuite/lib/tool/gatekeeper.exp index 3d8c208..1a57962 100644 --- a/testsuite/lib/tool/gatekeeper.exp +++ b/testsuite/lib/tool/gatekeeper.exp @@ -631,7 +631,7 @@ proc analyze_log { base_dir name assess } { set A(validate,future-signature-timestamp) 1 exp_continue } - -re {^gatekeeper\[[0-9]+\]: \(Test\) \[AA\]\ + -re {^gatekeeper\[[0-9]+\]: \(Test\) \[EX\]\ directive signature timestamp older than expected} { # from read_directive_file, if signature timestamp bad set A(validate,older-signature-timestamp) 1