X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/9b1663a5574182a66c6de8ad2fce7b3e4cbf277b..c81b29e0a7b1c0ee0b3299a39dafe480f16159ef:/progs/key.c diff --git a/progs/key.c b/progs/key.c index fe5f3137..9c9466b8 100644 --- a/progs/key.c +++ b/progs/key.c @@ -38,7 +38,11 @@ #include #include +#include +#include #include +#include +#include #include #include #include @@ -60,12 +64,17 @@ #include "gfreduce.h" #include "key.h" #include "mp.h" +#include "mpint.h" #include "mpmont.h" #include "mprand.h" #include "mptext.h" #include "pgen.h" #include "ptab.h" #include "rsa.h" +#include "x25519.h" +#include "x448.h" +#include "ed25519.h" +#include "ed448.h" #include "cc.h" #include "sha-mgf.h" @@ -100,8 +109,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@ --- * @@ -188,6 +199,7 @@ typedef struct keyopts { unsigned bits, qbits; /* Bit length for the new key */ const char *curve; /* Elliptic curve name/info */ grand *r; /* Random number source */ + mp *e; /* Public exponent */ key *p; /* Parameters key-data */ } keyopts; @@ -223,7 +235,7 @@ static void dolock(keyopts *k, key_data **kd, const char *t) /* --- @copyparam@ --- * * * Arguments: @keyopts *k@ = pointer to key options - * @const char **pp@ = checklist of parameters + * @const char **pp@ = checklist of parameters, or null * * Returns: Nonzero if parameters copied; zero if you have to generate * them. @@ -237,6 +249,7 @@ static int copyparam(keyopts *k, const char **pp) key_attriter i; key_data *kd; const char *n, *v; + dstr t = DSTR_INIT; kf.f = KCAT_SHARE; kf.m = KF_CATMASK; @@ -246,23 +259,35 @@ static int copyparam(keyopts *k, const char **pp) if (!k->p) return (0); - /* --- Run through the checklist --- */ + /* --- Copy the key data if there's anything we want --- */ - while (*pp) { - key_data *kd = key_structfind(k->p->k, *pp); - if (!kd) - die(EXIT_FAILURE, "bad parameter key: parameter `%s' not found", *pp); - if (!KEY_MATCH(kd, &kf)) - die(EXIT_FAILURE, "bad parameter key: subkey `%s' is not shared", *pp); - pp++; - } + if (pp) { - /* --- Copy over the parameters --- */ + /* --- Run through the checklist --- */ - kd = key_copydata(k->p->k, &kf); - assert(kd); - key_setkeydata(k->kf, k->k, kd); - key_drop(kd); + key_fulltag(k->p, &t); + if ((k->p->k->e & KF_ENCMASK) != KENC_STRUCT) + die(EXIT_FAILURE, "parameter key `%s' is not structured", t.buf); + while (*pp) { + key_data *kd = key_structfind(k->p->k, *pp); + if (!kd) { + die(EXIT_FAILURE, + "bad parameter key `%s': parameter `%s' not found", t.buf, *pp); + } + if (!KEY_MATCH(kd, &kf)) { + die(EXIT_FAILURE, + "bad parameter key `%s': subkey `%s' is not shared", t.buf, *pp); + } + pp++; + } + + /* --- Copy over the parameters --- */ + + kd = key_copydata(k->p->k, &kf); + assert(kd); + key_setkeydata(k->kf, k->k, kd); + key_drop(kd); + } /* --- Copy over attributes --- */ @@ -271,6 +296,7 @@ static int copyparam(keyopts *k, const char **pp) /* --- Done --- */ + dstr_destroy(&t); return (1); } @@ -349,6 +375,13 @@ static void keyrand(key_file *kf, const char *id) /* --- Key generation algorithms --- */ +static void alg_empty(keyopts *k) +{ + copyparam(k, 0); + key_setkeydata(k->kf, k->k, + key_newstring(KCAT_SHARE, k->curve ? k->curve : ".")); +} + static void alg_binary(keyopts *k) { unsigned sz; @@ -358,8 +391,7 @@ static void alg_binary(keyopts *k) if (!k->bits) k->bits = 128; - if (k->p) - die(EXIT_FAILURE, "no shared parameters for binary keys"); + copyparam(k, 0); sz = (k->bits + 7) >> 3; p = sub_alloc(sz); @@ -383,8 +415,7 @@ static void alg_des(keyopts *k) if (!k->bits) k->bits = 168; - if (k->p) - die(EXIT_FAILURE, "no shared parameters for DES keys"); + copyparam(k, 0); if (k->bits % 56 || k->bits > 168) die(EXIT_FAILURE, "DES keys must be 56, 112 or 168 bits long"); @@ -413,15 +444,18 @@ static void alg_rsa(keyopts *k) /* --- Sanity checking --- */ - if (k->p) - die(EXIT_FAILURE, "no shared parameters for RSA keys"); + copyparam(k, 0); if (!k->bits) k->bits = 1024; + if (k->bits < 64) + die(EXIT_FAILURE, "RSA key too tiny"); + if (!k->e) + k->e = mp_fromulong(MP_NEW, 65537); /* --- Generate the RSA parameters --- */ - if (rsa_gen(&rp, k->bits, k->r, 0, - (k->f & f_quiet) ? 0 : pgen_ev, 0)) + if (rsa_gen_e(&rp, k->bits, k->e, k->r, 0, + (k->f & f_quiet) ? 0 : pgen_ev, 0)) die(EXIT_FAILURE, "RSA key generation failed"); /* --- Run a test encryption --- */ @@ -472,7 +506,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 +543,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); @@ -571,7 +603,7 @@ static void alg_dhparam(keyopts *k) group *g; const char *e; - if (strcmp(k->curve, "list") == 0) { + if (STRCMP(k->curve, ==, "list")) { unsigned i, w; LIST("Built-in prime fields", stdout, ptab[i].name, ptab[i].name); exit(0); @@ -700,8 +732,7 @@ static void alg_bbs(keyopts *k) /* --- Sanity checking --- */ - if (k->p) - die(EXIT_FAILURE, "no shared parameters for Blum-Blum-Shub keys"); + copyparam(k, 0); if (!k->bits) k->bits = 1024; @@ -740,7 +771,7 @@ static void alg_binparam(keyopts *k) /* --- Decide on a field --- */ if (!k->bits) k->bits = 128; - if (k->curve && strcmp(k->curve, "list") == 0) { + if (k->curve && STRCMP(k->curve, ==, "list")) { unsigned i, w; LIST("Built-in binary fields", stdout, bintab[i].name, bintab[i].name); @@ -839,7 +870,7 @@ static void alg_ecparam(keyopts *k) /* --- Decide on a curve --- */ if (!k->bits) k->bits = 256; - if (k->curve && strcmp(k->curve, "list") == 0) { + if (k->curve && STRCMP(k->curve, ==, "list")) { unsigned i, w; LIST("Built-in elliptic curves", stdout, ectab[i].name, ectab[i].name); @@ -916,6 +947,64 @@ static void alg_ec(keyopts *k) mp_drop(x); } +#define XDHS(_) \ + _(x25519, X25519, "X25519") \ + _(x448, X448, "X448") + +#define XDHALG(xdh, XDH, name) \ + \ + static void alg_##xdh(keyopts *k) \ + { \ + key_data *kd, *kkd; \ + octet priv[XDH##_KEYSZ], pub[XDH##_PUBSZ]; \ + \ + copyparam(k, 0); \ + k->r->ops->fill(k->r, priv, sizeof(priv)); \ + xdh(pub, priv, xdh##_base); \ + kkd = key_newstruct(); \ + key_structsteal(kkd, "priv", \ + key_newbinary(KCAT_PRIV | KF_BURN, \ + priv, sizeof(priv))); \ + kd = key_newstruct(); \ + key_structsteal(kd, "private", kkd); \ + key_structsteal(kd, "pub", \ + key_newbinary(KCAT_PUB, pub, sizeof(pub))); \ + \ + key_setkeydata(k->kf, k->k, kd); \ + } + +XDHS(XDHALG) +#undef XDHALG + +#define EDDSAS(_) \ + _(ed25519, ED25519, "Ed25519") \ + _(ed448, ED448, "Ed448") + +#define EDDSAALG(ed, ED, name) \ + \ + static void alg_##ed(keyopts *k) \ + { \ + key_data *kd, *kkd; \ + octet priv[ED##_KEYSZ], pub[ED##_PUBSZ]; \ + \ + copyparam(k, 0); \ + k->r->ops->fill(k->r, priv, sizeof(priv)); \ + ed##_pubkey(pub, priv, sizeof(priv)); \ + kkd = key_newstruct(); \ + key_structsteal(kkd, "priv", \ + key_newbinary(KCAT_PRIV | KF_BURN, \ + priv, sizeof(priv))); \ + kd = key_newstruct(); \ + key_structsteal(kd, "private", kkd); \ + key_structsteal(kd, "pub", \ + key_newbinary(KCAT_PUB, pub, sizeof(pub))); \ + \ + key_setkeydata(k->kf, k->k, kd); \ + } + +EDDSAS(EDDSAALG) +#undef EDDSAALG + /* --- The algorithm tables --- */ typedef struct keyalg { @@ -937,6 +1026,15 @@ static keyalg algtab[] = { { "bindh-param", alg_binparam, "Binary-field DH parameters" }, { "ec-param", alg_ecparam, "Elliptic curve parameters" }, { "ec", alg_ec, "Elliptic curve crypto" }, +#define XDHTAB(xdh, XDH, name) \ + { #xdh, alg_##xdh, "" name " key exchange" }, + XDHS(XDHTAB) +#undef XDHTAB +#define EDDSATAB(ed, ED, name) \ + { #ed, alg_##ed, "" name " digital signatures" }, + EDDSAS(EDDSATAB) +#undef EDDSATAB + { "empty", alg_empty, "Empty parametrs-only key" }, { 0, 0 } }; @@ -952,7 +1050,7 @@ static int cmd_add(int argc, char *argv[]) keyalg *alg = algtab; const char *rtag = 0; const struct seedalg *sa = SEEDALG_DEFAULT; - keyopts k = { 0, 0, DSTR_INIT, 0, 0, 0, 0, 0 }; + keyopts k = { 0, 0, DSTR_INIT, 0, 0, 0, 0, 0, 0 }; const char *seed = 0; k.r = &rand_global; @@ -973,6 +1071,7 @@ static int cmd_add(int argc, char *argv[]) { "seedalg", OPTF_ARGREQ, 0, 'A' }, { "seed", OPTF_ARGREQ, 0, 's' }, { "newseed", OPTF_ARGREQ, 0, 'n' }, + { "public-exponent", OPTF_ARGREQ, 0, 'E' }, { "lock", 0, 0, 'l' }, { "quiet", 0, 0, 'q' }, { "lim-lee", 0, 0, 'L' }, @@ -980,7 +1079,7 @@ static int cmd_add(int argc, char *argv[]) { "kcdsa", 0, 0, 'K' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:R:I:C:A:s:n:lqrLKS", + int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:R:I:C:A:s:n:E:lqrLKS", opt, 0, 0, 0); if (i < 0) break; @@ -995,7 +1094,7 @@ static int cmd_add(int argc, char *argv[]) keyalg *a; size_t sz = strlen(optarg); - if (strcmp(optarg, "list") == 0) { + if (STRCMP(optarg, ==, "list")) { for (a = algtab; a->name; a++) printf("%-10s %s\n", a->name, a->help); return (0); @@ -1003,7 +1102,7 @@ static int cmd_add(int argc, char *argv[]) alg = 0; for (a = algtab; a->name; a++) { - if (strncmp(optarg, a->name, sz) == 0) { + if (STRNCMP(optarg, ==, a->name, sz)) { if (a->name[sz] == 0) { alg = a; break; @@ -1042,7 +1141,7 @@ static int cmd_add(int argc, char *argv[]) /* --- Expiry dates get passed to @get_date@ for parsing --- */ case 'e': - if (strcmp(optarg, "forever") == 0) + if (STRCMP(optarg, ==, "forever")) exp = KEXP_FOREVER; else { exp = get_date(optarg, 0); @@ -1080,7 +1179,7 @@ static int cmd_add(int argc, char *argv[]) case 'A': { const struct seedalg *ss; - if (strcmp(optarg, "list") == 0) { + if (STRCMP(optarg, ==, "list")) { printf("Seed algorithms:\n"); for (ss = seedtab; ss->p; ss++) printf(" %s\n", ss->p); @@ -1089,7 +1188,7 @@ static int cmd_add(int argc, char *argv[]) if (seed) die(EXIT_FAILURE, "seed already set -- put -A first"); sa = 0; for (ss = seedtab; ss->p; ss++) { - if (strcmp(optarg, ss->p) == 0) + if (STRCMP(optarg, ==, ss->p)) sa = ss; } if (!sa) @@ -1097,19 +1196,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 +1221,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; @@ -1139,6 +1241,15 @@ static int cmd_add(int argc, char *argv[]) kid = id; } break; + /* --- Public exponent --- */ + + case 'E': { + char *p; + k.e = mp_readstring(k.e, optarg, &p, 0); + if (!k.e || *p || MP_CMP(k.e, <, MP_THREE) || MP_EVENP(k.e)) + die(EXIT_FAILURE, "bad exponent `%s'", optarg); + } break; + /* --- Other flags --- */ case 'R': @@ -1210,7 +1321,7 @@ static int cmd_add(int argc, char *argv[]) if (k.f & f_retag) { if ((kk = key_bytag(&f, tag)) != 0 && kk->tag && - strcmp(kk->tag, tag) == 0) + STRCMP(kk->tag, ==, tag)) key_settag(&f, kk, 0); } if ((err = key_settag(&f, k.k, tag)) != 0) @@ -1233,12 +1344,8 @@ static int cmd_add(int argc, char *argv[]) /* --- Find the parameter key --- */ - if (ptag) { - if ((k.p = key_bytag(&f, ptag)) == 0) - die(EXIT_FAILURE, "parameter key `%s' not found", ptag); - if ((k.p->k->e & KF_ENCMASK) != KENC_STRUCT) - die(EXIT_FAILURE, "parameter key `%s' is not structured", ptag); - } + if (ptag && (k.p = key_bytag(&f, ptag)) == 0) + die(EXIT_FAILURE, "parameter key `%s' not found", ptag); /* --- Now generate the actual key data --- */ @@ -1678,42 +1785,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)) 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 +1855,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 +1869,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 HASH] [-p STYLE] [-f FILTER] [TAG...]"); + } doopen(&f, KOPEN_READ); @@ -1744,7 +1881,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 +1891,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 +1905,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 +1929,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 +1943,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 HASH] [-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)) die(EXIT_FAILURE, "key fingerprint mismatch"); + dstr_destroy(&d); dstr_destroy(&dd); doclose(&f); return (0); } @@ -1907,7 +2029,7 @@ static int cmd_tag(int argc, char *argv[]) die(EXIT_FAILURE, "Usage: tag [-r] TAG [NEW-TAG]"); doopen(&f, KOPEN_WRITE); if (flags & f_retag) { - if ((k = key_bytag(&f, argv[1])) != 0 && strcmp(k->tag, argv[1]) == 0) + if ((k = key_bytag(&f, argv[1])) != 0 && STRCMP(k->tag, ==, argv[1])) key_settag(&f, k, 0); } if ((k = key_bytag(&f, argv[0])) == 0) @@ -2001,7 +2123,7 @@ static int cmd_extract(int argc, char *argv[]) argv += optind; argc -= optind; if (rc || argc < 1) die(EXIT_FAILURE, "Usage: extract [-f FILTER] FILE [TAG...]"); - if (strcmp(*argv, "-") == 0) + if (STRCMP(*argv, ==, "-")) fp = stdout; else { outfile = *argv; @@ -2057,7 +2179,7 @@ static int cmd_merge(int argc, char *argv[]) if (argc != 2) die(EXIT_FAILURE, "Usage: merge FILE"); - if (strcmp(argv[1], "-") == 0) + if (STRCMP(argv[1], ==, "-")) fp = stdin; else if (!(fp = fopen(argv[1], "r"))) { die(EXIT_FAILURE, "couldn't open `%s' for reading: %s", @@ -2086,7 +2208,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 +2233,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 HASH] [-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\ " },