Replace clearsigned message verification
authorJacob Bachmeyer <jcb@gnu.org>
Wed, 26 Oct 2022 03:24:59 +0000 (22:24 -0500)
committerJacob Bachmeyer <jcb@gnu.org>
Wed, 26 Oct 2022 03:24:59 +0000 (22:24 -0500)
This removes the use of the shell to run gpgv when verifying directives.
This also improves the handling the of gpgv generally, since the use of
the --status-fd option is the recommended mechanism for automatic usage.

gatekeeper.pl

index 1616677acc8416b7bda7f4894dfdfa7ad2d1c2bb..31622b5eb580dc9e8a113c060ca673946144336c 100755 (executable)
@@ -1596,59 +1596,6 @@ sub verify_clearsigned_message {
   return \%ret;
 }
 
-#
-# Verify that the signature used for the directive file is valid for
-# this package's keyring. We go through all keyring files, starting at the
-# sub-most directory, until we find one that matches (or not!)
-#
-sub verify_keyring {
-  my $directive_file = shift;
-  my $directive_file_contents = shift;
-  my @keyrings = @_;
-
-  my $directive_file_size = -s $directive_file;
-  ftp_syslog('debug', "DEBUG: "
-            ."$directive_file size is $directive_file_size") if DEBUG;
-
-  foreach (@keyrings) {
-    # We need what gpgv writes to STDERR to determine the timestamp
-    # Hence the silly trick with storing the return code of gpgv in
-    # the command output
-    my @verify_args = (GPGV_BIN, "--keyring", $_,
-                      $directive_file,"2>&1",";echo \$?");
-
-    my $verify_str = join(' ',@verify_args);
-
-    ($verify_str) = $verify_str =~ /^(.*)$/;
-
-    ftp_syslog('debug',"DEBUG: gpgv command line: $verify_str\n")
-      if (DEBUG > 0);
-    my $retval = '';
-    open (GPGV, "$verify_str|")
-      or fatal("failed to run command: $verify_str",1);
-    while (defined (my $line = <GPGV>)) {
-      $retval .= $line;
-    }
-    close (GPGV) or ftp_warn("gpgv exited $?");
-
-    if (!defined($retval)) {
-      # This is bad - we couldn't even execute the gpgv command properly
-      guess_uploader_email($directive_file_contents);
-      fatal("gpg verify of directive file failed (error executing gpgv): $!",
-           0,'',2);
-    } elsif ($retval =~ /\n0\n$/s) {
-      # We store the return value of gpgv on the last line of the output
-      ftp_syslog('info', "verified against $_\n");
-      return $retval; # We got return value 0 from gpgv -> key verified!
-    } else {
-      # gpgv returned an error - most likely just key not found. Ignore,
-      # since we are testing all keyrings.
-    }
-  }
-  guess_uploader_email($directive_file_contents);
-  fatal("gpg verify of directive file failed",1,'',2);
-}
-
 \f
 #
 # - [PV] Parsing and Validation
@@ -1868,19 +1815,27 @@ sub read_directive_file {
   # 'directory:' line is messed up or not there, we'd still like to let the
   # uploader know something went wrong.  So let's see if we can match the
   # directive file signature against one of our public keyrings.
-  my @tmp_keyrings;
-  open(TMP,"/usr/bin/find $package_config_base -name pubring.gpg|");
-  while(<TMP>) {
-    chomp;
-    m,^(/?${RE_filename_relative})$, or next;
-    push @tmp_keyrings, $1;
-  }
-  close(TMP);
+  {
+    my @tmp_keyrings;
+    open(TMP,"/usr/bin/find $package_config_base -name pubring.gpg|");
+    while(<TMP>) {
+      chomp;
+      m,^(/?${RE_filename_relative})$, or next;
+      push @tmp_keyrings, $1;
+    }
+    close(TMP);
 
-  my $tmp_retval = verify_keyring($directive_file,$directive_file_contents,
-                                 @tmp_keyrings);
-  push(@{$info{email}},$1)
-    if ($tmp_retval =~ /Good signature from .*?<(.*?)>/);
+    my $tmp_result = verify_clearsigned_message
+      ($directive_file_contents, @tmp_keyrings);
+
+    if ($tmp_result->{exitcode} != 0 || defined $tmp_result->{TILT}) {
+      guess_uploader_email($directive_file_contents);
+      fatal("gpg verify of directive file failed",1,'',2);
+    }
+
+    push(@{$info{email}},$1)
+      if ($tmp_result->{raw_log} =~ /Good signature from .*?<(.*?)>/);
+  }
 
   my $ops = interpret_directive($directive, $directive_file_contents);
   my $op_header = $ops->[0][1];
@@ -1951,14 +1906,19 @@ sub read_directive_file {
       unless $stem eq $op_header->{filename};
   }
 
-  my $retval = verify_keyring($directive_file,$directive_file_contents,
-                             @keyrings);
+  my $result = verify_clearsigned_message($directive_file_contents, @keyrings);
+
+  if ($result->{exitcode} != 0 || defined $result->{TILT}) {
+    guess_uploader_email($directive_file_contents);
+    fatal("gpg verify of directive file failed",1,'',2);
+  }
 
   # Now check that the timestamp of signing for the directive is not older
   # than the one for the last file that was uploaded
   # This is only relevant when a 'filename' directive is present, hence the
   # test of the $filename_required variable.
-  if (($retval =~ /Signature made (.*)/) && (exists($info{filename}))) {
+  if (($result->{raw_log} =~ /Signature made (.*)/)
+      && (exists($info{filename}))) {
     my $timestr = $1;
 
     ftp_syslog('debug', "DEBUG: Signature made $1") if DEBUG;