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
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 {
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
sub auth_keyrings;
sub auth_signature_fingerprints;
+ sub auth_signature_timestamp;
sub parse;
sub auth_check;
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 {
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 {
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
}
}
-=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<verify_clearsigned_message> 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);
- }
- }
-}
-
\f
=back