fix stupid think-o that caused keytrans adduserid to misbehave if another key came...
[monkeysphere.git] / src / share / keytrans
index ad65ed32585829b40d4332154bc08167b97461d8..255a271c2cefd7f2dd446d5b69e9a275f8116ce5 100755 (executable)
@@ -429,7 +429,7 @@ sub fingerprint {
 
 
 # FIXME: handle DSA keys as well!
-sub pem2openpgp {
+sub makeselfsig {
   my $rsa = shift;
   my $uid = shift;
   my $args = shift;
@@ -442,10 +442,7 @@ sub pem2openpgp {
   if (! defined $args->{sig_timestamp}) {
     $args->{sig_timestamp} = time();
   }
-  if (! defined $args->{key_timestamp}) {
-    $args->{key_timestamp} = $args->{sig_timestamp} + 0;
-  }
-  my $key_timestamp = $args->{key_timestamp};
+  my $key_timestamp = $args->{key_timestamp} + 0;
 
   # generate and aggregate subpackets:
 
@@ -518,10 +515,7 @@ sub pem2openpgp {
                $feature_subpacket.
                  $keyserver_pref;
 
-  return
-    make_packet($packet_types->{seckey}, make_rsa_sec_key_body($rsa, $key_timestamp)).
-      make_packet($packet_types->{uid}, $uid).
-       gensig($rsa, $uid, $args);
+  return gensig($rsa, $uid, $args);
 }
 
 # FIXME: handle non-RSA keys
@@ -728,6 +722,7 @@ sub findkey {
   my $foundfprstr = Crypt::OpenSSL::Bignum->new_from_bin($foundfpr)->to_hex();
   # left-pad with 0's to bring up to full 40-char (160-bit) fingerprint:
   $foundfprstr = sprintf("%040s", $foundfprstr);
+  my $matched = 0;
 
   # is this a match?
   if ((!defined($data->{target}->{fpr})) ||
@@ -737,6 +732,7 @@ sub findkey {
     }
     $data->{key} = { 'rsa' => $pubkey,
                     'timestamp' => $key_timestamp };
+    $matched = 1;
   }
 
   if ($tag != $packet_types->{seckey} &&
@@ -746,7 +742,7 @@ sub findkey {
     }
     return;
   }
-  if (!defined($data->{key})) {
+  if (!$matched) {
     # we don't think the public part of this key matches
     if ($readbytes < $packetlen) {
       read($instr, $dummy, $packetlen - $readbytes) or die "Could not skip past this packet.\n";
@@ -803,7 +799,9 @@ sub openpgp2rsa {
     $fpr = uc($fpr);
   }
 
-  my $data = { 'fpr' => $fpr};
+  my $data = { target => { fpr => $fpr,
+                        },
+              };
   my $subs = { $packet_types->{pubkey} => \&findkey,
               $packet_types->{pub_subkey} => \&findkey,
               $packet_types->{seckey} => \&findkey,
@@ -814,6 +812,89 @@ sub openpgp2rsa {
   return $data->{key}->{rsa};
 }
 
+sub findkeyfprs {
+  my $data = shift;
+  my $instr = shift;
+  my $tag = shift;
+  my $packetlen = shift;
+
+  findkey($data, $instr, $tag, $packetlen);
+  if (defined($data->{key})) {
+    if (defined($data->{key}->{rsa}) && defined($data->{key}->{timestamp})) {
+      $data->{keys}->{fingerprint($data->{key}->{rsa}, $data->{key}->{timestamp})} = $data->{key};
+    } else {
+      die "should have found some key here";
+    }
+    undef($data->{key});
+  }
+};
+
+sub getallprimarykeys {
+  my $instr = shift;
+
+  my $subs = { $packet_types->{pubkey} => \&findkeyfprs,
+               $packet_types->{seckey} => \&findkeyfprs,
+            };
+  my $data = {target => { } };
+
+  packetwalk($instr, $subs, $data);
+
+  if (defined $data->{keys}) {
+    return $data->{keys};
+  } else {
+    return {};
+  }
+}
+
+sub adduserid {
+  my $instr = shift;
+  my $fpr = shift;
+  my $uid = shift;
+  my $args = shift;
+
+  if ((! defined $fpr) ||
+      (length($fpr) < 8)) {
+    die "We need at least 8 hex digits of fingerprint.\n";
+  }
+
+  $fpr = uc($fpr);
+
+  if (! defined $uid) {
+    die "No User ID defined.\n";
+  }
+
+  my $data = { target => { fpr => $fpr,
+                          uid => $uid,
+                        },
+            };
+  my $subs = { $packet_types->{seckey} => \&findkey,
+              $packet_types->{uid} => \&finduid,
+              $packet_types->{sig} => \&findsig,
+            };
+
+  packetwalk($instr, $subs, $data);
+
+  if ((! defined $data->{key}) ||
+      (! defined $data->{key}->{rsa}) ||
+      (! defined $data->{key}->{timestamp})) {
+    die "The key requested was not found.\n"
+  }
+
+  if (defined $data->{uid}->{$uid}) {
+    die "The requested User ID '$uid' is already associated with this key.\n";
+  }
+  $args->{key_timestamp} = $data->{key}->{timestamp};
+
+  return
+    make_packet($packet_types->{pubkey}, make_rsa_pub_key_body($data->{key}->{rsa}, $data->{key}->{timestamp})).
+      make_packet($packet_types->{uid}, $uid).
+       makeselfsig($data->{key}->{rsa},
+                   $uid,
+                   $args);
+
+}
+
+
 sub revokeuserid {
   my $instr = shift;
   my $fpr = shift;
@@ -996,10 +1077,18 @@ for (basename($0)) {
       $rsa = Crypt::OpenSSL::RSA->new_private_key($stdin);
     }
 
-    print pem2openpgp($rsa,
+    my $key_timestamp = $ENV{PEM2OPENPGP_KEY_TIMESTAMP};
+    my $sig_timestamp = $ENV{PEM2OPENPGP_TIMESTAMP};
+    $sig_timestamp = time() if (!defined $sig_timestamp);
+    $key_timestamp = $sig_timestamp if (!defined $key_timestamp);
+
+    print
+      make_packet($packet_types->{seckey}, make_rsa_sec_key_body($rsa, $key_timestamp)).
+       make_packet($packet_types->{uid}, $uid).
+         makeselfsig($rsa,
                      $uid,
-                     { sig_timestamp => $ENV{PEM2OPENPGP_TIMESTAMP},
-                       key_timestamp => $ENV{PEM2OPENPGP_KEY_TIMESTAMP},
+                     { sig_timestamp => $sig_timestamp,
+                       key_timestamp => $key_timestamp,
                        expiration => $ENV{PEM2OPENPGP_EXPIRATION},
                        usage_flags => $ENV{PEM2OPENPGP_USAGE_FLAGS},
                      }
@@ -1033,11 +1122,30 @@ for (basename($0)) {
        open($instream,'-');
        binmode($instream, ":bytes");
 
-       my $revcert = revokeuserid($instream, $fpr, $uid, $ENV{KEYTRANS_REVSIG_TIMESTAMP});
+       my $revcert = revokeuserid($instream, $fpr, $uid, $ENV{PEM2OPENPGP_TIMESTAMP});
 
        print $revcert;
+      } elsif (/^adduserid$/) {
+       my $fpr = shift;
+       my $uid = shift;
+       my $instream;
+       open($instream,'-');
+       binmode($instream, ":bytes");
+       my $newuid = adduserid($instream, $fpr, $uid, 
+                              { sig_timestamp => $ENV{PEM2OPENPGP_TIMESTAMP},
+                                expiration => $ENV{PEM2OPENPGP_EXPIRATION},
+                                usage_flags => $ENV{PEM2OPENPGP_USAGE_FLAGS},
+                              });
+
+       print $newuid;
+      } elsif (/^listfprs$/) {
+        my $instream;
+       open($instream,'-');
+       binmode($instream, ":bytes");
+        my $keys = getallprimarykeys($instream);
+        printf("%s\n", join("\n", map { uc(unpack('H*', $_)) } keys(%{$keys})));
       } else {
-       die "Unrecognized subcomand.  keytrans subcommands are not a stable interface!\n";
+       die "Unrecognized subcommand.  keytrans subcommands are not a stable interface!\n";
       }
     }
   }