X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/0f00dc4c8eb47e67bc0f148c2dd109f73a451e0a..4dafd519dbbdc17887f2de4f6cabe33ac4667ab0:/progs/key.c diff --git a/progs/key.c b/progs/key.c index f263aaf1..05494691 100644 --- a/progs/key.c +++ b/progs/key.c @@ -38,7 +38,10 @@ #include #include +#include +#include #include +#include #include #include #include @@ -100,8 +103,10 @@ static const char *keyfile = "keyring"; static void doopen(key_file *f, unsigned how) { - if (key_open(f, keyfile, how, key_moan, 0)) - die(1, "couldn't open keyring `%s': %s", keyfile, strerror(errno)); + if (key_open(f, keyfile, how, key_moan, 0)){ + die(EXIT_FAILURE, "couldn't open keyring `%s': %s", + keyfile, strerror(errno)); + } } /* --- @doclose@ --- * @@ -290,7 +295,7 @@ static mp *getmp(key_data *k, const char *tag) if (!k) die(EXIT_FAILURE, "unexpected failure looking up subkey `%s'", tag); if ((k->e & KF_ENCMASK) != KENC_MP) - die(EXIT_FAILURE, "subkey `%s' has an incompatible type"); + die(EXIT_FAILURE, "subkey `%s' has an incompatible type", tag); return (k->u.m); } @@ -472,7 +477,7 @@ static void alg_dsaparam(keyopts *k) octet *p; size_t sz; dstr d = DSTR_INIT; - base64_ctx c; + codec *c; key_data *kd; dsa_seed ds; @@ -509,11 +514,9 @@ static void alg_dsaparam(keyopts *k) /* --- Store the seed for future verification --- */ - base64_init(&c); - c.maxline = 0; - c.indent = ""; - base64_encode(&c, ds.p, ds.sz, &d); - base64_encode(&c, 0, 0, &d); + c = base64_class.encoder(0, "", 0); + c->ops->code(c, ds.p, ds.sz, &d); c->ops->code(c, 0, 0, &d); + c->ops->destroy(c); DPUTZ(&d); key_putattr(k->kf, k->k, "seed", d.buf); DRESET(&d); @@ -1097,19 +1100,22 @@ static int cmd_add(int argc, char *argv[]) } break; case 's': { - base64_ctx b; + codec *c; + int rc; dstr d = DSTR_INIT; if (seed) die(EXIT_FAILURE, "seed already set"); - base64_init(&b); - base64_decode(&b, optarg, strlen(optarg), &d); - base64_decode(&b, 0, 0, &d); + c = base64_class.decoder(CDCF_IGNEQPAD); + if ((rc = c->ops->code(c, optarg, strlen(optarg), &d)) != 0 || + (rc = c->ops->code(c, 0, 0, &d)) != 0) + die(EXIT_FAILURE, "invalid seed base64: %s", codec_strerror(rc)); + c->ops->destroy(c); k.r = sa->gen(d.buf, d.len); seed = optarg; dstr_destroy(&d); } break; case 'n': { - base64_ctx b; + codec *c; dstr d = DSTR_INIT; char *p; unsigned n = strtoul(optarg, &p, 0); @@ -1119,9 +1125,9 @@ static int cmd_add(int argc, char *argv[]) n /= 8; p = xmalloc(n); rand_get(RAND_GLOBAL, p, n); - base64_init(&b); - base64_encode(&b, p, n, &d); - base64_encode(&b, 0, 0, &d); + c = base64_class.encoder(0, "", 0); + c->ops->code(c, p, n, &d); c->ops->code(c, 0, 0, &d); + c->ops->destroy(c); seed = d.buf; k.r = sa->gen(p, n); } break; @@ -1678,42 +1684,67 @@ static int cmd_getattr(int argc, char *argv[]) /* --- @cmd_finger@ --- */ -static void fingerprint(key *k, const gchash *ch, const key_filter *kf) +static const struct fpres { + const char *name; + const codec_class *cdc; + unsigned short ival; + const char *sep; +} fprestab[] = { + { "hex", &hex_class, 8, "-:" }, + { "base32", &base32_class, 6, ":" }, + { 0, 0 } +}; + +static void fingerprint(key *k, const struct fpres *fpres, + const gchash *ch, const key_filter *kf) { ghash *h; - dstr d = DSTR_INIT; + dstr d = DSTR_INIT, dd = DSTR_INIT; const octet *p; size_t i; + codec *c; h = GH_INIT(ch); if (key_fingerprint(k, h, kf)) { p = GH_DONE(h, 0); - key_fulltag(k, &d); - for (i = 0; i < ch->hashsz; i++) { - if (i && i % 4 == 0) - putchar('-'); - printf("%02x", p[i]); + c = fpres->cdc->encoder(CDCF_LOWERC | CDCF_NOEQPAD, "", 0); + c->ops->code(c, p, ch->hashsz, &dd); c->ops->code(c, 0, 0, &dd); + c->ops->destroy(c); + for (i = 0; i < dd.len; i++) { + if (i && i%fpres->ival == 0) dstr_putc(&d, fpres->sep[0]); + dstr_putc(&d, dd.buf[i]); } - printf(" %s\n", d.buf); + dstr_putc(&d, ' '); key_fulltag(k, &d); dstr_putc(&d, '\n'); + dstr_write(&d, stdout); } - dstr_destroy(&d); + dstr_destroy(&d); dstr_destroy(&dd); GH_DESTROY(h); } +static const struct fpres *lookup_fpres(const char *name) +{ + const struct fpres *fpres; + for (fpres = fprestab; fpres->name; fpres++) + if (strcmp(fpres->name, name) == 0) return (fpres); + die(EXIT_FAILURE, "unknown presentation syle `%s'", name); +} + static int cmd_finger(int argc, char *argv[]) { key_file f; int rc = 0; + const struct fpres *fpres = fprestab; const gchash *ch = &rmd160; key_filter kf = { KF_NONSECRET, KF_NONSECRET }; for (;;) { static struct option opt[] = { { "filter", OPTF_ARGREQ, 0, 'f' }, + { "presentation", OPTF_ARGREQ, 0, 'p' }, { "algorithm", OPTF_ARGREQ, 0, 'a' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "+f:a:", opt, 0, 0, 0); + int i = mdwopt(argc, argv, "+f:a:p:", opt, 0, 0, 0); if (i < 0) break; switch (i) { @@ -1723,6 +1754,9 @@ static int cmd_finger(int argc, char *argv[]) if (err || *p) die(EXIT_FAILURE, "bad filter string `%s'", optarg); } break; + case 'p': + fpres = lookup_fpres(optarg); + break; case 'a': if ((ch = ghash_byname(optarg)) == 0) die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg); @@ -1734,8 +1768,10 @@ static int cmd_finger(int argc, char *argv[]) } argv += optind; argc -= optind; - if (rc) - die(EXIT_FAILURE, "Usage: fingerprint [-f FILTER] [TAG...]"); + if (rc) { + die(EXIT_FAILURE, + "Usage: fingerprint [-a HASHALG] [-p STYLE] [-f FILTER] [TAG...]"); + } doopen(&f, KOPEN_READ); @@ -1744,7 +1780,7 @@ static int cmd_finger(int argc, char *argv[]) for (i = 0; i < argc; i++) { key *k = key_bytag(&f, argv[i]); if (k) - fingerprint(k, ch, &kf); + fingerprint(k, fpres, ch, &kf); else { rc = 1; moan("key `%s' not found", argv[i]); @@ -1754,50 +1790,13 @@ static int cmd_finger(int argc, char *argv[]) key_iter i; key *k; for (key_mkiter(&i, &f); (k = key_next(&i)) != 0; ) - fingerprint(k, ch, &kf); + fingerprint(k, fpres, ch, &kf); } 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; @@ -1805,17 +1804,21 @@ static int cmd_verify(int argc, char *argv[]) const gchash *ch = &rmd160; ghash *h; key *k; - octet *buf; const octet *fpr; + dstr d = DSTR_INIT, dd = DSTR_INIT; + codec *c; + const char *p; + const struct fpres *fpres = fprestab; key_filter kf = { KF_NONSECRET, KF_NONSECRET }; for (;;) { static struct option opt[] = { { "filter", OPTF_ARGREQ, 0, 'f' }, + { "presentation", OPTF_ARGREQ, 0, 'p' }, { "algorithm", OPTF_ARGREQ, 0, 'a' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "+f:a:", opt, 0, 0, 0); + int i = mdwopt(argc, argv, "+f:a:p:", opt, 0, 0, 0); if (i < 0) break; switch (i) { @@ -1825,6 +1828,9 @@ static int cmd_verify(int argc, char *argv[]) if (err || *p) die(EXIT_FAILURE, "bad filter string `%s'", optarg); } break; + case 'p': + fpres = lookup_fpres(optarg); + break; case 'a': if ((ch = ghash_byname(optarg)) == 0) die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg); @@ -1836,21 +1842,36 @@ static int cmd_verify(int argc, char *argv[]) } argv += optind; argc -= optind; - if (rc || argc != 2) - die(EXIT_FAILURE, "Usage: verify [-f FILTER] TAG FINGERPRINT"); + if (rc || argc != 2) { + die(EXIT_FAILURE, + "Usage: verify [-a HASHALG] [-p STYLE] [-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); + for (p = argv[1]; *p; p++) { + if (strchr(fpres->sep, *p)) continue; + dstr_putc(&dd, *p); + } + c = fpres->cdc->decoder(CDCF_IGNCASE | CDCF_IGNEQPAD | + CDCF_IGNSPC | CDCF_IGNNEWL); + if ((rc = c->ops->code(c, dd.buf, dd.len, &d)) != 0 || + (rc = c->ops->code(c, 0, 0, &d)) != 0) + die(EXIT_FAILURE, "invalid fingerprint: %s", codec_strerror(rc)); + c->ops->destroy(c); + if (d.len != ch->hashsz) { + die(EXIT_FAILURE, "incorrect fingerprint length (%lu != %lu)", + (unsigned long)d.len, (unsigned long)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) + if (memcmp(fpr, d.buf, ch->hashsz) != 0) die(EXIT_FAILURE, "key fingerprint mismatch"); + dstr_destroy(&d); dstr_destroy(&dd); doclose(&f); return (0); } @@ -2086,7 +2107,9 @@ static int cmd_merge(int argc, char *argv[]) LI("Key-generation algorithms", keygen, \ algtab[i].name, algtab[i].name) \ LI("Random seeding algorithms", seed, \ - seedtab[i].p, seedtab[i].p) + seedtab[i].p, seedtab[i].p) \ + LI("Fingerprint presentation styles", fpres, \ + fprestab[i].name, fprestab[i].name) MAKELISTTAB(listtab, LISTS) @@ -2109,17 +2132,21 @@ Options:\n\ -q, --quiet Show less information.\n\ -v, --verbose Show more information.\n\ " }, - { "fingerprint", cmd_finger, "fingerprint [-f FILTER] [TAG...]", "\ + { "fingerprint", cmd_finger, + "fingerprint [-a HASHALG] [-p STYLE] [-f FILTER] [TAG...]", "\ Options:\n\ \n\ -f, --filter=FILT Only hash key components matching FILT.\n\ +-p, --presentation=STYLE Use STYLE for presenting fingerprints.\n\ -a, --algorithm=HASH Use the named HASH algorithm.\n\ ($ show hash for list.)\n\ " }, - { "verify", cmd_verify, "verify [-f FILTER] TAG FINGERPRINT", "\ + { "verify", cmd_verify, + "verify [-a HASH] [-p STYLE] [-f FILTER] TAG FINGERPRINT", "\ Options:\n\ \n\ -f, --filter=FILT Only hash key components matching FILT.\n\ +-p, --presentation=STYLE Expect FINGERPRINT in the given STYLE.\n\ -a, --algorithm=HASH Use the named HASH algorithm.\n\ ($ show hash for list.)\n\ " },