Verify key fingerprints.
[u/mdw/catacomb] / keyutil.c
index 5e1fa66..1ead08d 100644 (file)
--- a/keyutil.c
+++ b/keyutil.c
@@ -31,6 +31,7 @@
 
 #include "config.h"
 
+#include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -1695,6 +1696,101 @@ static int cmd_finger(int argc, char *argv[])
   return (rc);
 }
 
+/* --- @cmd_verify@ --- */
+
+static unsigned xdigit(char c)
+{
+  if ('A' <= c && c <= 'Z') return (c + 10 - 'A');
+  if ('a' <= c && c <= 'z') return (c + 10 - 'a');
+  if ('0' <= c && c <= '9') return (c - '0');
+  return (~0u);
+}
+
+static void unhexify(octet *q, char *p, size_t n)
+{
+  unsigned a = 0;
+  int i = 0;
+
+  for (;;) {
+    if (*p == '-' || *p == ':' || isspace((unsigned char)*p)) {
+      p++;
+      continue;
+    }
+    if (!n && !*p)
+      break;
+    if (!*p)
+      die(EXIT_FAILURE, "hex string too short");
+    if (!isxdigit((unsigned char)*p))
+      die(EXIT_FAILURE, "bad hex string");
+    if (!n)
+      die(EXIT_FAILURE, "hex string too long");
+    a = (a << 4) | xdigit(*p++);
+    i++;
+    if (i == 2) {
+      *q++ = U8(a);
+      a = 0;
+      i = 0;
+      n--;
+    }
+  }
+}
+
+static int cmd_verify(int argc, char *argv[])
+{
+  key_file f;
+  int rc = 0;
+  const gchash *ch = &rmd160;
+  ghash *h;
+  key *k;
+  octet *buf;
+  const octet *fpr;
+  key_filter kf = { KF_NONSECRET, KF_NONSECRET };
+
+  for (;;) {
+    static struct option opt[] = {
+      { "filter",      OPTF_ARGREQ,    0,      'f' },
+      { "algorithm",   OPTF_ARGREQ,    0,      'a' },
+      { 0,             0,              0,      0 }
+    };
+    int i = mdwopt(argc, argv, "+f:a:", opt, 0, 0, 0);
+    if (i < 0)
+      break;
+    switch (i) {
+      case 'f': {
+       char *p;
+       int err = key_readflags(optarg, &p, &kf.f, &kf.m);
+       if (err || *p)
+         die(EXIT_FAILURE, "bad filter string `%s'", optarg);
+      } break;
+      case 'a':
+       if ((ch = ghash_byname(optarg)) == 0)
+         die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg);
+       break;
+      default:
+       rc = 1;
+       break;
+    }
+  }
+
+  argv += optind; argc -= optind;
+  if (rc || argc != 2)
+    die(EXIT_FAILURE, "Usage: verify [-f FILTER] TAG FINGERPRINT");
+
+  doopen(&f, KOPEN_READ);
+
+  if ((k = key_bytag(&f, argv[0])) == 0)
+    die(EXIT_FAILURE, "key `%s' not found", argv[0]);
+  buf = xmalloc(ch->hashsz);
+  unhexify(buf, argv[1], ch->hashsz);
+  h = GH_INIT(ch);
+  if (!key_fingerprint(k, h, &kf))
+    die(EXIT_FAILURE, "key has no fingerprintable components (as filtered)");
+  fpr = GH_DONE(h, 0);
+  if (memcmp(fpr, buf, ch->hashsz) != 0)
+    die(EXIT_FAILURE, "key fingerprint mismatch");
+  return (0);
+}
+  
 /* --- @cmd_comment@ --- */
 
 static int cmd_comment(int argc, char *argv[])
@@ -1949,6 +2045,13 @@ Options:\n\
 -a, --algorithm=HASH   Use the named HASH algorithm.\n\
                          ($ show hash for list.)\n\
 " },
+  { "verify", cmd_verify, "verify [-f FILTER] TAG FINGERPRINT", "\
+Options:\n\
+\n\
+-f, --filter=FILT      Only hash key components matching FILT.\n\
+-a, --algorithm=HASH   Use the named HASH algorithm.\n\
+                         ($ show hash for list.)\n\
+" },
   { "extract", cmd_extract, "extract [-f FILTER] FILE [TAG...]", "\
 Options:\n\
 \n\