Add support for openpgp4fpr pkc type
authorJameson Rollins <jrollins@finestructure.net>
Sat, 25 Dec 2010 00:10:25 +0000 (19:10 -0500)
committerJameson Rollins <jrollins@finestructure.net>
Sat, 25 Dec 2010 00:10:25 +0000 (19:10 -0500)
Instead of passing a full key, we here allow instead passing a full
OpenPGP fingerprint.  The key is 'recv'd from the keyserver if not
available, and validation is done on the exact matching key.

Crypt/Monkeysphere/MSVA.pm

index 3b582311a3895adfdbd7d47b24266628e88eeed3..ff1631675a5bb8b3d9e57a2e69f876bbf3d29adf 100755 (executable)
     return $default_keyserver;
   }
 
+  sub fetch_fpr_from_keyserver {
+    my $fpr = shift;
+
+    my $cmd = IO::Handle::->new();
+    my $nul = IO::File::->new("< /dev/null");
+
+    my $ks = get_keyserver();
+    msvalog('debug', "start ks query to %s for fingerprint: %s\n", $ks, $fpr);
+    my $pid = $gnupg->wrap_call
+      ( handles => GnuPG::Handles::->new( command => $cmd, stdout => $nul, stderr => $nul ),
+       command_args => [ '0x'.$fpr ],
+       commands => [ '--keyserver',
+                     $ks,
+                     qw( --no-tty --recv-keys ) ]
+                                       );
+    # FIXME: can we do something to avoid hanging forever?
+    waitpid($pid, 0);
+    msvalog('debug', "ks query returns %d\n", POSIX::WEXITSTATUS($?));
+  }
+
   sub fetch_uid_from_keyserver {
     my $uid = shift;
 
     my $uid = $prefix.$data->{peer}->{name};
     msvalog('verbose', "user ID: %s\n", $uid);
 
-    # extract key from PKC
+    # extract key or openpgp fingerprint from PKC
+    my $fpr;
     my $key;
-    $key = pkcextractkey($data);
-    if (exists $key->{error}) {
-      $ret->{message} = $key->{error};
-      return $status,$ret;
+    my $gpgquery;
+    if (lc($data->{pkc}->{type}) eq 'openpgp4fpr') {
+      if ($data->{pkc}->{data} =~ /^([[:xdigit:]]+)$/) {
+       $data->{pkc}->{data} = $1;
+       $fpr = $data->{pkc}->{data};
+       msvalog('verbose', "OpenPGP v4 fingerprint: %s\n",$fpr);
+      } else {
+       msvalog('error', "invalid OpenPGP v4 fingerprint: %s\n",$data->{pkc}->{data});
+       $ret->{message} = sprintf("Invalid OpengPGP v4 fingerprint.");
+       return $status,$ret;
+      }
+      $gpgquery = '0x'.$fpr;
+    } else {
+      # extract key from PKC
+      $key = pkcextractkey($data);
+      if (exists $key->{error}) {
+       $ret->{message} = $key->{error};
+       return $status,$ret;
+      }
+      $gpgquery = '='.$uid;
     }
 
     # setup variables
     # needed because $gnupg spawns child processes
     $ENV{PATH} = '/usr/local/bin:/usr/bin:/bin';
     if ($kspolicy eq 'always') {
-      fetch_uid_from_keyserver($uid);
+      if (defined $fpr) {
+       fetch_fpr_from_keyserver($fpr);
+      } else {
+       fetch_uid_from_keyserver($uid);
+      }
       $lastloop = 1;
     } elsif ($kspolicy eq 'never') {
       $lastloop = 1;
     my @subvalid_key_fprs;
 
     while (1) {
-      foreach my $gpgkey ($gnupg->get_public_keys('='.$uid)) {
+      foreach my $gpgkey ($gnupg->get_public_keys($gpgquery)) {
        my $validity = '-';
        foreach my $tryuid ($gpgkey->user_ids) {
          if ($tryuid->as_string eq $uid) {
        }
        # treat primary keys just like subkeys:
        foreach my $subkey ($gpgkey, @{$gpgkey->subkeys}) {
-         my $primarymatch = keycomp($key, $subkey);
+         my $primarymatch;
+         if (defined $key) {
+           $primarymatch = keycomp($key, $subkey);
+         } else {
+           $primarymatch = 1;
+         }
          if ($primarymatch) {
            if ($subkey->usage_flags =~ /a/) {
              msvalog('verbose', "key matches, and 0x%s is authentication-capable\n", $subkey->hex_id);
              if ($validity =~ /^[fu]$/) {
                $foundvalid = 1;
-               msvalog('verbose', "...and it matches!\n");
+               msvalog('verbose', "...and it's fully valid!\n");
                $ret->{valid} = JSON::true;
                $ret->{message} = sprintf('Successfully validated "%s" through the OpenPGP Web of Trust.', $uid);
              } else {
       if ($lastloop) {
        last;
       } else {
-       fetch_uid_from_keyserver($uid) if (!$foundvalid);
+       if (!$foundvalid) {
+         if (defined $fpr) {
+           fetch_fpr_from_keyserver($fpr);
+         } else {
+           fetch_uid_from_keyserver($uid);
+         }
+       }
        $lastloop = 1;
       }
     }