X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/ef13e9a46baaa347014ac236f36a2536f055b108..8cd9f01dac408893755906282d79284c1ee7ddd6:/keyutil.c diff --git a/keyutil.c b/keyutil.c index 1d4bbca..74f6409 100644 --- a/keyutil.c +++ b/keyutil.c @@ -7,7 +7,7 @@ * (c) 1999 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of Catacomb. * @@ -15,12 +15,12 @@ * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * Catacomb is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. - * + * * You should have received a copy of the GNU Library General Public * License along with Catacomb; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, @@ -160,17 +160,17 @@ static void setattr(key_file *f, key *k, char *v[]) const struct seedalg { const char *p; grand *(*gen)(const void *, size_t); } seedtab[] = { - { "dsarand", dsarand_create }, - { "rmd128-mgf", rmd128_mgfrand }, - { "rmd160-mgf", rmd160_mgfrand }, - { "rmd256-mgf", rmd256_mgfrand }, - { "rmd320-mgf", rmd320_mgfrand }, - { "sha-mgf", sha_mgfrand }, - { "sha224-mgf", sha224_mgfrand }, - { "sha256-mgf", sha256_mgfrand }, - { "sha384-mgf", sha384_mgfrand }, - { "sha512-mgf", sha512_mgfrand }, - { "tiger-mgf", tiger_mgfrand }, + { "dsarand", dsarand_create }, + { "rmd128-mgf", rmd128_mgfrand }, + { "rmd160-mgf", rmd160_mgfrand }, + { "rmd256-mgf", rmd256_mgfrand }, + { "rmd320-mgf", rmd320_mgfrand }, + { "sha-mgf", sha_mgfrand }, + { "sha224-mgf", sha224_mgfrand }, + { "sha256-mgf", sha256_mgfrand }, + { "sha384-mgf", sha384_mgfrand }, + { "sha512-mgf", sha512_mgfrand }, + { "tiger-mgf", tiger_mgfrand }, { 0, 0 } }; @@ -197,6 +197,7 @@ typedef struct keyopts { #define f_limlee 8u /* Generate Lim-Lee primes */ #define f_subgroup 16u /* Generate a subgroup */ #define f_retag 32u /* Remove any existing tag */ +#define f_kcdsa 64u /* Generate KCDSA primes */ /* --- @dolock@ --- * * @@ -234,8 +235,12 @@ static int copyparam(keyopts *k, const char **pp) { key_filter kf; key_attriter i; + key_data *kd; const char *n, *v; + kf.f = KCAT_SHARE; + kf.m = KF_CATMASK; + /* --- Quick check if no parameters supplied --- */ if (!k->p) @@ -247,16 +252,17 @@ static int copyparam(keyopts *k, const char **pp) key_data *kd = key_structfind(k->p->k, *pp); if (!kd) die(EXIT_FAILURE, "bad parameter key: parameter `%s' not found", *pp); - if ((kd->e & KF_CATMASK) != KCAT_SHARE) + if (!KEY_MATCH(kd, &kf)) die(EXIT_FAILURE, "bad parameter key: subkey `%s' is not shared", *pp); pp++; } /* --- Copy over the parameters --- */ - kf.f = KCAT_SHARE; - kf.m = KF_CATMASK; - key_setkeydata(k->kf, k->k, k->p->k); + kd = key_copydata(k->p->k, &kf); + assert(kd); + key_setkeydata(k->kf, k->k, kd); + key_drop(kd); /* --- Copy over attributes --- */ @@ -564,7 +570,7 @@ static void alg_dhparam(keyopts *k) qd_parse qd; group *g; const char *e; - + if (strcmp(k->curve, "list") == 0) { unsigned i, w; LIST("Built-in prime fields", stdout, ptab[i].name, ptab[i].name); @@ -578,11 +584,11 @@ static void alg_dhparam(keyopts *k) if ((g = group_prime(&dp)) == 0) die(EXIT_FAILURE, "invalid prime field"); if (!(k->f & f_quiet) && (e = G_CHECK(g, &rand_global)) != 0) - moan("WARNING! group check failed: %s", e); + moan("WARNING! group check failed: %s", e); G_DESTROYGROUP(g); goto done; } - + if (!k->bits) k->bits = 1024; @@ -609,6 +615,24 @@ static void alg_dhparam(keyopts *k) key_putattr(k->kf, k->k, "factors", d.buf); dstr_destroy(&d); } + } else if (k->f & f_kcdsa) { + if (!k->qbits) + k->qbits = 256; + rc = dh_kcdsagen(&dp, k->qbits, k->bits, 0, + 0, k->r, (k->f & f_quiet) ? 0 : pgen_ev, 0); + if (!rc) { + dstr d = DSTR_INIT; + mp *v = MP_NEW; + + mp_writedstr(dp.q, &d, 10); + mp_div(&v, 0, dp.p, dp.q); + v = mp_lsr(v, v, 1); + dstr_puts(&d, ", "); + mp_writedstr(v, &d, 10); + mp_drop(v); + key_putattr(k->kf, k->k, "factors", d.buf); + dstr_destroy(&d); + } } else rc = dh_gen(&dp, k->qbits, k->bits, 0, k->r, (k->f & f_quiet) ? 0 : pgen_ev, 0); @@ -922,6 +946,7 @@ static int cmd_add(int argc, char *argv[]) { key_file f; time_t exp = KEXP_EXPIRE; + uint32 kid = rand_global.ops->word(&rand_global); const char *tag = 0, *ptag = 0; const char *c = 0; keyalg *alg = algtab; @@ -943,6 +968,7 @@ static int cmd_add(int argc, char *argv[]) { "comment", OPTF_ARGREQ, 0, 'c' }, { "tag", OPTF_ARGREQ, 0, 't' }, { "rand-id", OPTF_ARGREQ, 0, 'R' }, + { "key-id", OPTF_ARGREQ, 0, 'I' }, { "curve", OPTF_ARGREQ, 0, 'C' }, { "seedalg", OPTF_ARGREQ, 0, 'A' }, { "seed", OPTF_ARGREQ, 0, 's' }, @@ -951,9 +977,10 @@ static int cmd_add(int argc, char *argv[]) { "quiet", 0, 0, 'q' }, { "lim-lee", 0, 0, 'L' }, { "subgroup", 0, 0, 'S' }, + { "kcdsa", 0, 0, 'K' }, { 0, 0, 0, 0 } }; - int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:R:C:A:s:n:lqrLS", + int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:R:I:C:A:s:n:lqrLKS", opt, 0, 0, 0); if (i < 0) break; @@ -1015,7 +1042,7 @@ static int cmd_add(int argc, char *argv[]) /* --- Expiry dates get passed to @get_date@ for parsing --- */ case 'e': - if (strncmp(optarg, "forever", strlen(optarg)) == 0) + if (strcmp(optarg, "forever") == 0) exp = KEXP_FOREVER; else { exp = get_date(optarg, 0); @@ -1072,7 +1099,7 @@ static int cmd_add(int argc, char *argv[]) case 's': { base64_ctx b; dstr d = DSTR_INIT; - if (seed) die(EXIT_FAILURE, "seed already set"); + if (seed) die(EXIT_FAILURE, "seed already set"); base64_init(&b); base64_decode(&b, optarg, strlen(optarg), &d); base64_decode(&b, 0, 0, &d); @@ -1080,7 +1107,7 @@ static int cmd_add(int argc, char *argv[]) seed = optarg; dstr_destroy(&d); } break; - + case 'n': { base64_ctx b; dstr d = DSTR_INIT; @@ -1088,7 +1115,7 @@ static int cmd_add(int argc, char *argv[]) unsigned n = strtoul(optarg, &p, 0); if (n == 0 || *p != 0 || n % 8 != 0) die(EXIT_FAILURE, "bad seed length `%s'", optarg); - if (seed) die(EXIT_FAILURE, "seed already set"); + if (seed) die(EXIT_FAILURE, "seed already set"); n /= 8; p = xmalloc(n); rand_get(RAND_GLOBAL, p, n); @@ -1098,7 +1125,20 @@ static int cmd_add(int argc, char *argv[]) seed = d.buf; k.r = sa->gen(p, n); } break; - + + /* --- Key id --- */ + + case 'I': { + char *p; + unsigned long id; + + errno = 0; + id = strtoul(optarg, &p, 16); + if (errno || *p || id > MASK32) + die(EXIT_FAILURE, "bad key-id `%s'", optarg); + kid = id; + } break; + /* --- Other flags --- */ case 'R': @@ -1113,6 +1153,9 @@ static int cmd_add(int argc, char *argv[]) case 'L': k.f |= f_limlee; break; + case 'K': + k.f |= f_kcdsa; + break; case 'S': k.f |= f_subgroup; break; @@ -1152,9 +1195,8 @@ static int cmd_add(int argc, char *argv[]) keyrand(&f, rtag); for (;;) { - uint32 id = rand_global.ops->word(&rand_global); int err; - if ((err = key_new(&f, id, argv[optind], exp, &k.k)) == 0) + if ((err = key_new(&f, kid, argv[optind], exp, &k.k)) == 0) break; else if (err != KERR_DUPID) die(EXIT_FAILURE, "error adding new key: %s", key_strerror(err)); @@ -1166,7 +1208,9 @@ static int cmd_add(int argc, char *argv[]) int err; key *kk; if (k.f & f_retag) { - if ((kk = key_bytag(&f, tag)) != 0 && strcmp(kk->tag, tag) == 0) + if ((kk = key_bytag(&f, tag)) != 0 && + kk->tag && + strcmp(kk->tag, tag) == 0) key_settag(&f, kk, 0); } if ((err = key_settag(&f, k.k, tag)) != 0) @@ -1324,7 +1368,7 @@ static void showkeydata(key_data *k, int ind, listopts *o, dstr *d) fputs(", 0x", stdout); mp_writefile(k->u.e.y, stdout, 16); putchar('\n'); } - break; + break; /* --- Structured keys --- * * @@ -1348,7 +1392,7 @@ static void showkeydata(key_data *k, int ind, listopts *o, dstr *d) } INDENT(ind); fputs("}\n", stdout); - } break; + } break; } #undef INDENT @@ -1398,10 +1442,10 @@ static void showkey(key *k, listopts *o) if (!o->v) { if (!(o->f & f_newline)) { - printf("%8s %-20s %-20s %-10s %-10s\n", + printf("%8s %-20s %-20s %-10s %s\n", "Id", "Tag", "Type", "Expire", "Delete"); } - printf("%08lx %-20s %-20s %-10s %-10s\n", + printf("%08lx %-20s %-20s %-10s %s\n", (unsigned long)k->id, k->tag ? k->tag : "", k->type, ebuf, dbuf); o->f |= f_newline; @@ -1446,7 +1490,7 @@ static void showkey(key *k, listopts *o) showkeydata(k->k, 0, o, &d); dstr_destroy(&d); } - + o->f |= f_newline; } @@ -1488,7 +1532,7 @@ static int cmd_list(int argc, char *argv[]) int e = key_readflags(optarg, &p, &o.kf.f, &o.kf.m); if (e || *p) die(EXIT_FAILURE, "bad filter string `%s'", optarg); - } break; + } break; default: o.f |= f_bogus; break; @@ -1609,6 +1653,29 @@ static int cmd_setattr(int argc, char *argv[]) return (0); } +/* --- @cmd_getattr@ --- */ + +static int cmd_getattr(int argc, char *argv[]) +{ + key_file f; + key *k; + dstr d = DSTR_INIT; + const char *p; + + if (argc != 3) + die(EXIT_FAILURE, "Usage: getattr TAG ATTR"); + doopen(&f, KOPEN_READ); + if ((k = key_bytag(&f, argv[1])) == 0) + die(EXIT_FAILURE, "key `%s' not found", argv[1]); + key_fulltag(k, &d); + if ((p = key_getattr(&f, k, argv[2])) == 0) + die(EXIT_FAILURE, "no attribute `%s' for key `%s'", argv[2], d.buf); + puts(p); + dstr_destroy(&d); + doclose(&f); + return (0); +} + /* --- @cmd_finger@ --- */ static void fingerprint(key *k, const gchash *ch, const key_filter *kf) @@ -1784,9 +1851,10 @@ static int cmd_verify(int argc, char *argv[]) fpr = GH_DONE(h, 0); if (memcmp(fpr, buf, ch->hashsz) != 0) die(EXIT_FAILURE, "key fingerprint mismatch"); + doclose(&f); return (0); } - + /* --- @cmd_comment@ --- */ static int cmd_comment(int argc, char *argv[]) @@ -1905,6 +1973,8 @@ static int cmd_extract(int argc, char *argv[]) int i; int rc = 0; key_filter kf = { 0, 0 }; + dstr d = DSTR_INIT; + const char *outfile = 0; FILE *fp; for (;;) { @@ -1933,9 +2003,13 @@ static int cmd_extract(int argc, char *argv[]) die(EXIT_FAILURE, "Usage: extract [-f FILTER] FILE [TAG...]"); if (strcmp(*argv, "-") == 0) fp = stdout; - else if (!(fp = fopen(*argv, "w"))) { - die(EXIT_FAILURE, "couldn't open `%s' for writing: %s", - *argv, strerror(errno)); + else { + outfile = *argv; + dstr_putf(&d, "%s.new", outfile); + if (!(fp = fopen(d.buf, "w"))) { + die(EXIT_FAILURE, "couldn't open `%s' for writing: %s", + d.buf, strerror(errno)); + } } doopen(&f, KOPEN_READ); @@ -1944,7 +2018,7 @@ static int cmd_extract(int argc, char *argv[]) key *k; for (key_mkiter(&i, &f); (k = key_next(&i)) != 0; ) key_extract(&f, k, fp, &kf); - } else { + } else { for (i = 1; i < argc; i++) { if ((k = key_bytag(&f, argv[i])) != 0) key_extract(&f, k, fp, &kf); @@ -1954,8 +2028,9 @@ static int cmd_extract(int argc, char *argv[]) } } } - if (fclose(fp)) + if (fclose(fp) || (outfile && rename(d.buf, outfile))) die(EXIT_FAILURE, "error writing file: %s", strerror(errno)); + dstr_destroy(&d); doclose(&f); return (rc); } @@ -2057,6 +2132,7 @@ Options:\n\ { "expire", cmd_expire, "expire TAG..." }, { "delete", cmd_delete, "delete TAG..." }, { "setattr", cmd_setattr, "setattr TAG ATTR..." }, + { "getattr", cmd_getattr, "getattr TAG ATTR" }, { "comment", cmd_comment, "comment TAG [COMMENT]" }, { "lock", cmd_lock, "lock QTAG" }, { "unlock", cmd_unlock, "unlock QTAG" }, @@ -2068,9 +2144,9 @@ Options:\n\ { "tidy", cmd_tidy, "tidy" }, { "add", cmd_add, "add [-OPTIONS] TYPE [ATTR...]\n\ - Options: [-lqrLS] [-a ALG] [-bB BITS] [-p PARAM] [-R TAG]\n\ - [-A SEEDALG] [-s SEED] [-n BITS]\n\ - [-e EXPIRE] [-t TAG] [-c COMMENT]", "\ + Options: [-lqrLKS] [-a ALG] [-bB BITS] [-p PARAM] [-R TAG]\n\ + [-A SEEDALG] [-s SEED] [-n BITS] [-I KEYID]\n\ + [-e EXPIRE] [-t TAG] [-c COMMENT]", "\ Options:\n\ \n\ -a, --algorithm=ALG Generate keys suitable for ALG.\n\ @@ -2089,9 +2165,11 @@ Options:\n\ -t, --tag=TAG Tag the key with the name TAG.\n\ -r, --retag Untag any key currently with that tag.\n\ -R, --rand-id=TAG Use key named TAG for the random number generator.\n\ +-I, --key-id=ID Force the key-id for the new key.\n\ -l, --lock Lock the generated key with a passphrase.\n\ -q, --quiet Don't give progress indicators while working.\n\ -L, --lim-lee Generate Lim-Lee primes for Diffie-Hellman groups.\n\ +-K, --kcdsa Generate KCDSA-style Lim-Lee primes for DH groups.\n\ -S, --subgroup Use a prime-order subgroup for Diffie-Hellman.\n\ " }, { 0, 0, 0 }