math/strongprime.c: Improve the commentary.
[catacomb] / progs / key.c
CommitLineData
d03ab969 1/* -*-c-*-
2 *
d03ab969 3 * Simple key manager program
4 *
252c122d 5 * (c) 1999 Straylight/Edgeware
d03ab969 6 */
7
45c0fd36 8/*----- Licensing notice --------------------------------------------------*
d03ab969 9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
45c0fd36 16 *
d03ab969 17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
45c0fd36 21 *
d03ab969 22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
d03ab969 28/*----- Header files ------------------------------------------------------*/
29
cd6eca43
MW
30#define _FILE_OFFSET_BITS 64
31
d03ab969 32#include "config.h"
33
58507325 34#include <ctype.h>
d03ab969 35#include <errno.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <time.h>
40
2b4be81b 41#include <mLib/codec.h>
16810bbd 42#include <mLib/base32.h>
252c122d 43#include <mLib/base64.h>
16810bbd 44#include <mLib/hex.h>
d03ab969 45#include <mLib/mdwopt.h>
46#include <mLib/quis.h>
47#include <mLib/report.h>
48#include <mLib/sub.h>
49
50#include <noise.h>
51#include <rand.h>
52
3688eb75 53#include "bintab.h"
252c122d 54#include "bbs.h"
052b36d0 55#include "dh.h"
252c122d 56#include "dsa.h"
34e4f738 57#include "dsarand.h"
1ba83484 58#include "ec.h"
59#include "ec-keys.h"
60#include "ectab.h"
252c122d 61#include "fibrand.h"
d03ab969 62#include "getdate.h"
3688eb75 63#include "gfreduce.h"
d03ab969 64#include "key.h"
252c122d 65#include "mp.h"
66#include "mpmont.h"
67#include "mprand.h"
68#include "mptext.h"
69#include "pgen.h"
3563e365 70#include "ptab.h"
252c122d 71#include "rsa.h"
fc2d44af 72#include "x25519.h"
643eb1bb 73#include "x448.h"
d56fd9d1 74#include "ed25519.h"
d03ab969 75
c65df279 76#include "cc.h"
34e4f738 77#include "sha-mgf.h"
78#include "sha256-mgf.h"
79#include "sha224-mgf.h"
80#include "sha384-mgf.h"
81#include "sha512-mgf.h"
82#include "tiger-mgf.h"
83#include "rmd128-mgf.h"
84#include "rmd160-mgf.h"
85#include "rmd256-mgf.h"
86#include "rmd320-mgf.h"
87#include "md5-mgf.h"
88#include "dsarand.h"
89
d03ab969 90/*----- Handy global state ------------------------------------------------*/
91
92static const char *keyfile = "keyring";
93
94/*----- Useful shared functions -------------------------------------------*/
95
96/* --- @doopen@ --- *
97 *
98 * Arguments: @key_file *f@ = pointer to key file block
99 * @unsigned how@ = method to open file with
100 *
101 * Returns: ---
102 *
103 * Use: Opens a key file and handles errors by panicking
104 * appropriately.
105 */
106
107static void doopen(key_file *f, unsigned how)
108{
204607bd
MW
109 if (key_open(f, keyfile, how, key_moan, 0)){
110 die(EXIT_FAILURE, "couldn't open keyring `%s': %s",
111 keyfile, strerror(errno));
112 }
d03ab969 113}
114
115/* --- @doclose@ --- *
116 *
117 * Arguments: @key_file *f@ = pointer to key file block
118 *
119 * Returns: ---
120 *
121 * Use: Closes a key file and handles errors by panicking
122 * appropriately.
123 */
124
125static void doclose(key_file *f)
126{
127 switch (key_close(f)) {
128 case KWRITE_FAIL:
129 die(EXIT_FAILURE, "couldn't write file `%s': %s",
130 keyfile, strerror(errno));
131 case KWRITE_BROKEN:
132 die(EXIT_FAILURE, "keyring file `%s' broken: %s (repair manually)",
133 keyfile, strerror(errno));
134 }
135}
136
137/* --- @setattr@ --- *
138 *
139 * Arguments: @key_file *f@ = pointer to key file block
140 * @key *k@ = pointer to key block
141 * @char *v[]@ = array of assignments (overwritten!)
142 *
143 * Returns: ---
144 *
145 * Use: Applies the attribute assignments to the key.
146 */
147
148static void setattr(key_file *f, key *k, char *v[])
149{
150 while (*v) {
252c122d 151 int err;
d03ab969 152 char *p = *v;
153 size_t eq = strcspn(p, "=");
72f13799 154 if (!p[eq]) {
155 moan("invalid assignment: `%s' (ignored)", p);
156 v++;
157 continue;
158 }
d03ab969 159 p[eq] = 0;
160 p += eq + 1;
252c122d 161 if ((err = key_putattr(f, k, *v, *p ? p : 0)) != 0)
162 die(EXIT_FAILURE, "couldn't set attributes: %s", key_strerror(err));
d03ab969 163 v++;
164 }
165}
166
34e4f738 167/*----- Seeding -----------------------------------------------------------*/
168
169const struct seedalg { const char *p; grand *(*gen)(const void *, size_t); }
170seedtab[] = {
45c0fd36
MW
171 { "dsarand", dsarand_create },
172 { "rmd128-mgf", rmd128_mgfrand },
173 { "rmd160-mgf", rmd160_mgfrand },
174 { "rmd256-mgf", rmd256_mgfrand },
175 { "rmd320-mgf", rmd320_mgfrand },
176 { "sha-mgf", sha_mgfrand },
177 { "sha224-mgf", sha224_mgfrand },
178 { "sha256-mgf", sha256_mgfrand },
179 { "sha384-mgf", sha384_mgfrand },
180 { "sha512-mgf", sha512_mgfrand },
181 { "tiger-mgf", tiger_mgfrand },
34e4f738 182 { 0, 0 }
183};
184
185#define SEEDALG_DEFAULT (seedtab + 2)
186
252c122d 187/*----- Key generation ----------------------------------------------------*/
188
189/* --- Key generation parameters --- */
190
191typedef struct keyopts {
192 key_file *kf; /* Pointer to key file */
193 key *k; /* Pointer to the actual key */
194 dstr tag; /* Full tag name for the key */
195 unsigned f; /* Flags for the new key */
196 unsigned bits, qbits; /* Bit length for the new key */
1ba83484 197 const char *curve; /* Elliptic curve name/info */
34e4f738 198 grand *r; /* Random number source */
252c122d 199 key *p; /* Parameters key-data */
200} keyopts;
201
16efd15b 202#define f_bogus 1u /* Error in parsing */
203#define f_lock 2u /* Passphrase-lock private key */
204#define f_quiet 4u /* Don't show a progress indicator */
205#define f_limlee 8u /* Generate Lim-Lee primes */
206#define f_subgroup 16u /* Generate a subgroup */
ce70ec47 207#define f_retag 32u /* Remove any existing tag */
4e67e30b 208#define f_kcdsa 64u /* Generate KCDSA primes */
252c122d 209
210/* --- @dolock@ --- *
211 *
212 * Arguments: @keyopts *k@ = key generation options
ef13e9a4 213 * @key_data **kd@ = pointer to key data to lock
252c122d 214 * @const char *t@ = tag suffix or null
215 *
216 * Returns: ---
217 *
218 * Use: Does passphrase locking on new keys.
219 */
220
ef13e9a4 221static void dolock(keyopts *k, key_data **kd, const char *t)
252c122d 222{
223 if (!(k->f & f_lock))
224 return;
225 if (t)
226 dstr_putf(&k->tag, ".%s", t);
ef13e9a4 227 if (key_plock(kd, 0, k->tag.buf))
252c122d 228 die(EXIT_FAILURE, "couldn't lock key");
229}
230
252c122d 231/* --- @copyparam@ --- *
232 *
233 * Arguments: @keyopts *k@ = pointer to key options
7532e25e 234 * @const char **pp@ = checklist of parameters, or null
252c122d 235 *
236 * Returns: Nonzero if parameters copied; zero if you have to generate
237 * them.
238 *
239 * Use: Copies parameters from a source key to the current one.
240 */
241
242static int copyparam(keyopts *k, const char **pp)
243{
244 key_filter kf;
4739c68a 245 key_attriter i;
9eef0c14 246 key_data *kd;
4739c68a 247 const char *n, *v;
f49fc4a0 248 dstr t = DSTR_INIT;
252c122d 249
9eef0c14
MW
250 kf.f = KCAT_SHARE;
251 kf.m = KF_CATMASK;
252
252c122d 253 /* --- Quick check if no parameters supplied --- */
254
255 if (!k->p)
256 return (0);
257
7532e25e 258 /* --- Copy the key data if there's anything we want --- */
252c122d 259
7532e25e
MW
260 if (pp) {
261
262 /* --- Run through the checklist --- */
263
264 key_fulltag(k->p, &t);
265 if ((k->p->k->e & KF_ENCMASK) != KENC_STRUCT)
266 die(EXIT_FAILURE, "parameter key `%s' is not structured", t.buf);
267 while (*pp) {
268 key_data *kd = key_structfind(k->p->k, *pp);
269 if (!kd) {
270 die(EXIT_FAILURE,
271 "bad parameter key `%s': parameter `%s' not found", t.buf, *pp);
272 }
273 if (!KEY_MATCH(kd, &kf)) {
274 die(EXIT_FAILURE,
275 "bad parameter key `%s': subkey `%s' is not shared", t.buf, *pp);
276 }
277 pp++;
f49fc4a0 278 }
252c122d 279
7532e25e 280 /* --- Copy over the parameters --- */
252c122d 281
7532e25e
MW
282 kd = key_copydata(k->p->k, &kf);
283 assert(kd);
284 key_setkeydata(k->kf, k->k, kd);
285 key_drop(kd);
286 }
4739c68a 287
288 /* --- Copy over attributes --- */
289
290 for (key_mkattriter(&i, k->p); key_nextattr(&i, &n, &v); )
291 key_putattr(k->kf, k->k, n, v);
292
293 /* --- Done --- */
294
f49fc4a0 295 dstr_destroy(&t);
252c122d 296 return (1);
297}
298
299/* --- @getmp@ --- *
300 *
301 * Arguments: @key_data *k@ = pointer to key data block
302 * @const char *tag@ = tag string to use
303 *
304 * Returns: Pointer to multiprecision integer key item.
305 *
306 * Use: Fetches an MP key component.
307 */
308
309static mp *getmp(key_data *k, const char *tag)
310{
311 k = key_structfind(k, tag);
312 if (!k)
313 die(EXIT_FAILURE, "unexpected failure looking up subkey `%s'", tag);
314 if ((k->e & KF_ENCMASK) != KENC_MP)
9b1663a5 315 die(EXIT_FAILURE, "subkey `%s' has an incompatible type", tag);
252c122d 316 return (k->u.m);
317}
318
052b36d0 319/* --- @keyrand@ --- *
320 *
321 * Arguments: @key_file *kf@ = pointer to key file
322 * @const char *id@ = pointer to key id (or null)
323 *
324 * Returns: ---
325 *
326 * Use: Keys the random number generator.
327 */
328
329static void keyrand(key_file *kf, const char *id)
330{
331 key *k;
332
333 /* --- Find the key --- */
334
335 if (id) {
336 if ((k = key_bytag(kf, id)) == 0)
337 die(EXIT_FAILURE, "key `%s' not found", id);
338 } else
339 k = key_bytype(kf, "catacomb-rand");
340
341 if (k) {
ef13e9a4 342 key_data *kd = k->k, *kkd;
343 key_incref(kd);
052b36d0 344
345 again:
346 switch (kd->e & KF_ENCMASK) {
347 case KENC_BINARY:
348 break;
349 case KENC_ENCRYPT: {
350 dstr d = DSTR_INIT;
351 key_fulltag(k, &d);
ef13e9a4 352 if (key_punlock(&kkd, kd, d.buf))
052b36d0 353 die(EXIT_FAILURE, "error unlocking key `%s'", d.buf);
354 dstr_destroy(&d);
ef13e9a4 355 key_drop(kd);
356 kd = kkd;
052b36d0 357 } goto again;
358 default: {
359 dstr d = DSTR_INIT;
360 key_fulltag(k, &d);
361 die(EXIT_FAILURE, "bad encoding type for key `%s'", d.buf);
362 } break;
363 }
364
365 /* --- Key the generator --- */
366
367 rand_key(RAND_GLOBAL, kd->u.k.k, kd->u.k.sz);
ef13e9a4 368 key_drop(kd);
052b36d0 369 }
370}
371
252c122d 372/* --- Key generation algorithms --- */
373
7532e25e
MW
374static void alg_empty(keyopts *k)
375{
376 copyparam(k, 0);
377 key_setkeydata(k->kf, k->k,
378 key_newstring(KCAT_SHARE, k->curve ? k->curve : "."));
379}
380
252c122d 381static void alg_binary(keyopts *k)
382{
383 unsigned sz;
384 unsigned m;
ef13e9a4 385 key_data *kd;
252c122d 386 octet *p;
387
388 if (!k->bits)
389 k->bits = 128;
7532e25e 390 copyparam(k, 0);
252c122d 391
392 sz = (k->bits + 7) >> 3;
393 p = sub_alloc(sz);
394 m = (1 << (((k->bits - 1) & 7) + 1)) - 1;
34e4f738 395 k->r->ops->fill(k->r, p, sz);
252c122d 396 *p &= m;
ef13e9a4 397 kd = key_newbinary(KCAT_SYMM | KF_BURN, p, sz);
252c122d 398 memset(p, 0, sz);
ef13e9a4 399 dolock(k, &kd, 0);
400 key_setkeydata(k->kf, k->k, kd);
401 key_drop(kd);
252c122d 402 sub_free(p, sz);
252c122d 403}
404
405static void alg_des(keyopts *k)
406{
407 unsigned sz;
408 octet *p;
ef13e9a4 409 key_data *kd;
252c122d 410 int i;
411
412 if (!k->bits)
1ba83484 413 k->bits = 168;
7532e25e 414 copyparam(k, 0);
252c122d 415 if (k->bits % 56 || k->bits > 168)
416 die(EXIT_FAILURE, "DES keys must be 56, 112 or 168 bits long");
417
418 sz = k->bits / 7;
419 p = sub_alloc(sz);
34e4f738 420 k->r->ops->fill(k->r, p, sz);
252c122d 421 for (i = 0; i < sz; i++) {
052b36d0 422 octet x = p[i] | 0x01;
252c122d 423 x = x ^ (x >> 4);
424 x = x ^ (x >> 2);
052b36d0 425 x = x ^ (x >> 1);
252c122d 426 p[i] = (p[i] & 0xfe) | (x & 0x01);
427 }
ef13e9a4 428 kd = key_newbinary(KCAT_SYMM | KF_BURN, p, sz);
252c122d 429 memset(p, 0, sz);
ef13e9a4 430 dolock(k, &kd, 0);
431 key_setkeydata(k->kf, k->k, kd);
432 key_drop(kd);
252c122d 433 sub_free(p, sz);
252c122d 434}
435
436static void alg_rsa(keyopts *k)
437{
ab0ca95f 438 rsa_priv rp;
ef13e9a4 439 key_data *kd, *kkd;
252c122d 440
441 /* --- Sanity checking --- */
442
7532e25e 443 copyparam(k, 0);
252c122d 444 if (!k->bits)
445 k->bits = 1024;
446
447 /* --- Generate the RSA parameters --- */
448
34e4f738 449 if (rsa_gen(&rp, k->bits, k->r, 0,
252c122d 450 (k->f & f_quiet) ? 0 : pgen_ev, 0))
451 die(EXIT_FAILURE, "RSA key generation failed");
452
453 /* --- Run a test encryption --- */
454
455 {
34e4f738 456 grand *g = fibrand_create(k->r->ops->word(k->r));
ab0ca95f 457 rsa_pub rpp;
252c122d 458 mp *m = mprand_range(MP_NEW, rp.n, g, 0);
459 mp *c;
460
ab0ca95f 461 rpp.n = rp.n;
462 rpp.e = rp.e;
463 c = rsa_qpubop(&rpp, MP_NEW, m);
464 c = rsa_qprivop(&rp, c, c, g);
252c122d 465
4b536f42 466 if (!MP_EQ(c, m))
252c122d 467 die(EXIT_FAILURE, "test encryption failed");
468 mp_drop(c);
469 mp_drop(m);
470 g->ops->destroy(g);
471 }
472
473 /* --- Allrighty then --- */
474
ef13e9a4 475 kd = key_newstruct();
476 key_structsteal(kd, "n", key_newmp(KCAT_PUB, rp.n));
477 key_structsteal(kd, "e", key_newmp(KCAT_PUB, rp.e));
478
479 kkd = key_newstruct();
480 key_structsteal(kkd, "d", key_newmp(KCAT_PRIV | KF_BURN, rp.d));
481 key_structsteal(kkd, "p", key_newmp(KCAT_PRIV | KF_BURN, rp.p));
482 key_structsteal(kkd, "q", key_newmp(KCAT_PRIV | KF_BURN, rp.q));
483 key_structsteal(kkd, "q-inv", key_newmp(KCAT_PRIV | KF_BURN, rp.q_inv));
484 key_structsteal(kkd, "d-mod-p", key_newmp(KCAT_PRIV | KF_BURN, rp.dp));
485 key_structsteal(kkd, "d-mod-q", key_newmp(KCAT_PRIV | KF_BURN, rp.dq));
486 dolock(k, &kkd, "private");
487 key_structsteal(kd, "private", kkd);
488 key_setkeydata(k->kf, k->k, kd);
489 key_drop(kd);
ab0ca95f 490 rsa_privfree(&rp);
252c122d 491}
492
493static void alg_dsaparam(keyopts *k)
494{
495 static const char *pl[] = { "q", "p", "g", 0 };
496 if (!copyparam(k, pl)) {
497 dsa_param dp;
498 octet *p;
499 size_t sz;
500 dstr d = DSTR_INIT;
2b4be81b 501 codec *c;
ef13e9a4 502 key_data *kd;
f4f8e305 503 dsa_seed ds;
252c122d 504
505 /* --- Choose appropriate bit lengths if necessary --- */
506
507 if (!k->qbits)
508 k->qbits = 160;
509 if (!k->bits)
ef13e9a4 510 k->bits = 1024;
252c122d 511
512 /* --- Allocate a seed block --- */
513
514 sz = (k->qbits + 7) >> 3;
515 p = sub_alloc(sz);
34e4f738 516 k->r->ops->fill(k->r, p, sz);
252c122d 517
518 /* --- Allocate the parameters --- */
519
f4f8e305 520 if (dsa_gen(&dp, k->qbits, k->bits, 0, p, sz, &ds,
40d5a112 521 (k->f & f_quiet) ? 0 : pgen_ev, 0))
252c122d 522 die(EXIT_FAILURE, "DSA parameter generation failed");
523
524 /* --- Store the parameters --- */
525
ef13e9a4 526 kd = key_newstruct();
527 key_structsteal(kd, "q", key_newmp(KCAT_SHARE, dp.q));
528 key_structsteal(kd, "p", key_newmp(KCAT_SHARE, dp.p));
529 key_structsteal(kd, "g", key_newmp(KCAT_SHARE, dp.g));
252c122d 530 mp_drop(dp.q);
531 mp_drop(dp.p);
532 mp_drop(dp.g);
ef13e9a4 533 key_setkeydata(k->kf, k->k, kd);
534 key_drop(kd);
252c122d 535
536 /* --- Store the seed for future verification --- */
537
2b4be81b
MW
538 c = base64_class.encoder(0, "", 0);
539 c->ops->code(c, ds.p, ds.sz, &d); c->ops->code(c, 0, 0, &d);
540 c->ops->destroy(c);
ef13e9a4 541 DPUTZ(&d);
252c122d 542 key_putattr(k->kf, k->k, "seed", d.buf);
f4f8e305 543 DRESET(&d);
544 dstr_putf(&d, "%u", ds.count);
545 key_putattr(k->kf, k->k, "count", d.buf);
546 xfree(ds.p);
252c122d 547 sub_free(p, sz);
548 dstr_destroy(&d);
549 }
550}
551
552static void alg_dsa(keyopts *k)
553{
554 mp *q, *p, *g;
555 mp *x, *y;
556 mpmont mm;
ef13e9a4 557 key_data *kd, *kkd;
252c122d 558
559 /* --- Get the shared parameters --- */
560
561 alg_dsaparam(k);
ef13e9a4 562 key_split(&k->k->k); kd = k->k->k;
252c122d 563 q = getmp(kd, "q");
564 p = getmp(kd, "p");
565 g = getmp(kd, "g");
566
567 /* --- Choose a private key --- */
568
34e4f738 569 x = mprand_range(MP_NEWSEC, q, k->r, 0);
252c122d 570 mpmont_create(&mm, p);
571 y = mpmont_exp(&mm, MP_NEW, g, x);
572
573 /* --- Store everything away --- */
574
ef13e9a4 575 key_structsteal(kd, "y", key_newmp(KCAT_PUB, y));
252c122d 576
ef13e9a4 577 kkd = key_newstruct();
578 key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
579 dolock(k, &kkd, "private");
580 key_structsteal(kd, "private", kkd);
052b36d0 581
582 mp_drop(x); mp_drop(y);
252c122d 583}
584
585static void alg_dhparam(keyopts *k)
586{
052b36d0 587 static const char *pl[] = { "p", "q", "g", 0 };
ef13e9a4 588 key_data *kd;
252c122d 589 if (!copyparam(k, pl)) {
052b36d0 590 dh_param dp;
40d5a112 591 int rc;
252c122d 592
3563e365 593 if (k->curve) {
594 qd_parse qd;
3688eb75 595 group *g;
596 const char *e;
45c0fd36 597
3563e365 598 if (strcmp(k->curve, "list") == 0) {
c65df279 599 unsigned i, w;
3688eb75 600 LIST("Built-in prime fields", stdout, ptab[i].name, ptab[i].name);
3563e365 601 exit(0);
602 }
603 qd.p = k->curve;
604 if (dh_parse(&qd, &dp))
3688eb75 605 die(EXIT_FAILURE, "error in field spec: %s", qd.e);
606 if (!qd_eofp(&qd))
607 die(EXIT_FAILURE, "junk at end of field spec");
608 if ((g = group_prime(&dp)) == 0)
609 die(EXIT_FAILURE, "invalid prime field");
610 if (!(k->f & f_quiet) && (e = G_CHECK(g, &rand_global)) != 0)
45c0fd36 611 moan("WARNING! group check failed: %s", e);
3688eb75 612 G_DESTROYGROUP(g);
3563e365 613 goto done;
614 }
45c0fd36 615
252c122d 616 if (!k->bits)
617 k->bits = 1024;
618
619 /* --- Choose a large safe prime number --- */
620
40d5a112 621 if (k->f & f_limlee) {
622 mp **f;
623 size_t nf;
624 if (!k->qbits)
625 k->qbits = 256;
626 rc = dh_limlee(&dp, k->qbits, k->bits,
627 (k->f & f_subgroup) ? DH_SUBGROUP : 0,
34e4f738 628 0, k->r, (k->f & f_quiet) ? 0 : pgen_ev, 0,
40d5a112 629 (k->f & f_quiet) ? 0 : pgen_evspin, 0, &nf, &f);
630 if (!rc) {
631 dstr d = DSTR_INIT;
632 size_t i;
633 for (i = 0; i < nf; i++) {
634 if (i)
635 dstr_puts(&d, ", ");
636 mp_writedstr(f[i], &d, 10);
637 mp_drop(f[i]);
638 }
639 key_putattr(k->kf, k->k, "factors", d.buf);
640 dstr_destroy(&d);
641 }
4e67e30b
MW
642 } else if (k->f & f_kcdsa) {
643 if (!k->qbits)
644 k->qbits = 256;
645 rc = dh_kcdsagen(&dp, k->qbits, k->bits, 0,
646 0, k->r, (k->f & f_quiet) ? 0 : pgen_ev, 0);
647 if (!rc) {
648 dstr d = DSTR_INIT;
649 mp *v = MP_NEW;
650
651 mp_writedstr(dp.q, &d, 10);
652 mp_div(&v, 0, dp.p, dp.q);
653 v = mp_lsr(v, v, 1);
654 dstr_puts(&d, ", ");
655 mp_writedstr(v, &d, 10);
656 mp_drop(v);
657 key_putattr(k->kf, k->k, "factors", d.buf);
658 dstr_destroy(&d);
659 }
40d5a112 660 } else
34e4f738 661 rc = dh_gen(&dp, k->qbits, k->bits, 0, k->r,
40d5a112 662 (k->f & f_quiet) ? 0 : pgen_ev, 0);
663
664 if (rc)
252c122d 665 die(EXIT_FAILURE, "Diffie-Hellman parameter generation failed");
666
3563e365 667 done:
ef13e9a4 668 kd = key_newstruct();
669 key_structsteal(kd, "p", key_newmp(KCAT_SHARE, dp.p));
670 key_structsteal(kd, "q", key_newmp(KCAT_SHARE, dp.q));
671 key_structsteal(kd, "g", key_newmp(KCAT_SHARE, dp.g));
052b36d0 672 mp_drop(dp.q);
673 mp_drop(dp.p);
674 mp_drop(dp.g);
ef13e9a4 675 key_setkeydata(k->kf, k->k, kd);
676 key_drop(kd);
34e4f738 677 }
252c122d 678}
679
680static void alg_dh(keyopts *k)
681{
682 mp *x, *y;
052b36d0 683 mp *p, *q, *g;
252c122d 684 mpmont mm;
ef13e9a4 685 key_data *kd, *kkd;
252c122d 686
687 /* --- Get the shared parameters --- */
688
689 alg_dhparam(k);
ef13e9a4 690 key_split(&k->k->k); kd = k->k->k;
252c122d 691 p = getmp(kd, "p");
052b36d0 692 q = getmp(kd, "q");
252c122d 693 g = getmp(kd, "g");
694
695 /* --- Choose a suitable private key --- *
696 *
697 * Since %$g$% has order %$q$%, choose %$x < q$%.
698 */
699
34e4f738 700 x = mprand_range(MP_NEWSEC, q, k->r, 0);
252c122d 701
702 /* --- Compute the public key %$y = g^x \bmod p$% --- */
703
704 mpmont_create(&mm, p);
052b36d0 705 y = mpmont_exp(&mm, MP_NEW, g, x);
252c122d 706 mpmont_destroy(&mm);
707
708 /* --- Store everything away --- */
709
ef13e9a4 710 key_structsteal(kd, "y", key_newmp(KCAT_PUB, y));
252c122d 711
ef13e9a4 712 kkd = key_newstruct();
713 key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
714 dolock(k, &kkd, "private");
715 key_structsteal(kd, "private", kkd);
052b36d0 716
717 mp_drop(x); mp_drop(y);
252c122d 718}
719
720static void alg_bbs(keyopts *k)
721{
ab0ca95f 722 bbs_priv bp;
ef13e9a4 723 key_data *kd, *kkd;
252c122d 724
725 /* --- Sanity checking --- */
726
7532e25e 727 copyparam(k, 0);
252c122d 728 if (!k->bits)
729 k->bits = 1024;
730
731 /* --- Generate the BBS parameters --- */
732
34e4f738 733 if (bbs_gen(&bp, k->bits, k->r, 0,
052b36d0 734 (k->f & f_quiet) ? 0 : pgen_ev, 0))
252c122d 735 die(EXIT_FAILURE, "Blum-Blum-Shub key generation failed");
252c122d 736
737 /* --- Allrighty then --- */
738
ef13e9a4 739 kd = key_newstruct();
740 key_structsteal(kd, "n", key_newmp(KCAT_PUB, bp.n));
252c122d 741
ef13e9a4 742 kkd = key_newstruct();
743 key_structsteal(kkd, "p", key_newmp(KCAT_PRIV | KF_BURN, bp.p));
744 key_structsteal(kkd, "q", key_newmp(KCAT_PRIV | KF_BURN, bp.q));
745 dolock(k, &kkd, "private");
746 key_structsteal(kd, "private", kkd);
747 key_setkeydata(k->kf, k->k, kd);
748 key_drop(kd);
252c122d 749
ab0ca95f 750 bbs_privfree(&bp);
252c122d 751}
752
3688eb75 753static void alg_binparam(keyopts *k)
754{
755 static const char *pl[] = { "p", "q", "g", 0 };
756 if (!copyparam(k, pl)) {
757 gbin_param gb;
758 qd_parse qd;
759 group *g;
760 const char *e;
ef13e9a4 761 key_data *kd;
3688eb75 762
763 /* --- Decide on a field --- */
764
765 if (!k->bits) k->bits = 128;
766 if (k->curve && strcmp(k->curve, "list") == 0) {
767 unsigned i, w;
768 LIST("Built-in binary fields", stdout,
769 bintab[i].name, bintab[i].name);
770 exit(0);
771 }
772 if (!k->curve) {
773 if (k->bits <= 40) k->curve = "p1363-40";
774 else if (k->bits <= 56) k->curve = "p1363-56";
775 else if (k->bits <= 64) k->curve = "p1363-64";
776 else if (k->bits <= 80) k->curve = "p1363-80";
777 else if (k->bits <= 112) k->curve = "p1363-112";
778 else if (k->bits <= 128) k->curve = "p1363-128";
779 else {
780 die(EXIT_FAILURE,
781 "no built-in binary fields provide %u-bit security",
782 k->bits);
783 }
784 }
785
786 /* --- Check it --- */
787
788 qd.e = 0;
789 qd.p = k->curve;
790 if (dhbin_parse(&qd, &gb))
791 die(EXIT_FAILURE, "error in field spec: %s", qd.e);
792 if (!qd_eofp(&qd))
793 die(EXIT_FAILURE, "junk at end of field spec");
794 if ((g = group_binary(&gb)) == 0)
795 die(EXIT_FAILURE, "invalid binary field");
796 if (!(k->f & f_quiet) && (e = G_CHECK(g, &rand_global)) != 0)
797 moan("WARNING! group check failed: %s", e);
798 G_DESTROYGROUP(g);
799
800 /* --- Write out the answer --- */
801
ef13e9a4 802 kd = key_newstruct();
803 key_structsteal(kd, "p", key_newmp(KCAT_SHARE, gb.p));
804 key_structsteal(kd, "q", key_newmp(KCAT_SHARE, gb.q));
805 key_structsteal(kd, "g", key_newmp(KCAT_SHARE, gb.g));
3688eb75 806 mp_drop(gb.q);
807 mp_drop(gb.p);
808 mp_drop(gb.g);
ef13e9a4 809 key_setkeydata(k->kf, k->k, kd);
810 key_drop(kd);
3688eb75 811 }
812}
813
814static void alg_bin(keyopts *k)
815{
816 mp *x, *y;
817 mp *p, *q, *g;
818 gfreduce r;
ef13e9a4 819 key_data *kd, *kkd;
3688eb75 820
821 /* --- Get the shared parameters --- */
822
823 alg_binparam(k);
ef13e9a4 824 key_split(&k->k->k); kd = k->k->k;
3688eb75 825 p = getmp(kd, "p");
826 q = getmp(kd, "q");
827 g = getmp(kd, "g");
828
829 /* --- Choose a suitable private key --- *
830 *
831 * Since %$g$% has order %$q$%, choose %$x < q$%.
832 */
833
834 x = mprand_range(MP_NEWSEC, q, k->r, 0);
835
836 /* --- Compute the public key %$y = g^x \bmod p$% --- */
837
838 gfreduce_create(&r, p);
839 y = gfreduce_exp(&r, MP_NEW, g, x);
840 gfreduce_destroy(&r);
841
842 /* --- Store everything away --- */
843
ef13e9a4 844 key_structsteal(kd, "y", key_newmp(KCAT_PUB, y));
3688eb75 845
ef13e9a4 846 kkd = key_newstruct();
847 key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
848 dolock(k, &kkd, "private");
849 key_structsteal(kd, "private", kkd);
3688eb75 850
851 mp_drop(x); mp_drop(y);
852}
853
1ba83484 854static void alg_ecparam(keyopts *k)
855{
856 static const char *pl[] = { "curve", 0 };
857 if (!copyparam(k, pl)) {
858 ec_info ei;
859 const char *e;
ef13e9a4 860 key_data *kd;
1ba83484 861
862 /* --- Decide on a curve --- */
863
864 if (!k->bits) k->bits = 256;
3563e365 865 if (k->curve && strcmp(k->curve, "list") == 0) {
c65df279 866 unsigned i, w;
867 LIST("Built-in elliptic curves", stdout,
868 ectab[i].name, ectab[i].name);
3563e365 869 exit(0);
870 }
1ba83484 871 if (!k->curve) {
872 if (k->bits <= 56) k->curve = "secp112r1";
873 else if (k->bits <= 64) k->curve = "secp128r1";
874 else if (k->bits <= 80) k->curve = "secp160r1";
875 else if (k->bits <= 96) k->curve = "secp192r1";
876 else if (k->bits <= 112) k->curve = "secp224r1";
877 else if (k->bits <= 128) k->curve = "secp256r1";
878 else if (k->bits <= 192) k->curve = "secp384r1";
879 else if (k->bits <= 256) k->curve = "secp521r1";
880 else
881 die(EXIT_FAILURE, "no built-in curves provide %u-bit security",
882 k->bits);
883 }
884
885 /* --- Check it --- */
886
887 if ((e = ec_getinfo(&ei, k->curve)) != 0)
888 die(EXIT_FAILURE, "error in curve spec: %s", e);
34e4f738 889 if (!(k->f & f_quiet) && (e = ec_checkinfo(&ei, k->r)) != 0)
1ba83484 890 moan("WARNING! curve check failed: %s", e);
891 ec_freeinfo(&ei);
892
893 /* --- Write out the answer --- */
894
ef13e9a4 895 kd = key_newstruct();
896 key_structsteal(kd, "curve", key_newstring(KCAT_SHARE, k->curve));
897 key_setkeydata(k->kf, k->k, kd);
898 key_drop(kd);
1ba83484 899 }
900}
901
902static void alg_ec(keyopts *k)
903{
ef13e9a4 904 key_data *kd;
1ba83484 905 key_data *kkd;
906 mp *x = MP_NEW;
907 ec p = EC_INIT;
908 const char *e;
909 ec_info ei;
910
911 /* --- Get the curve --- */
912
913 alg_ecparam(k);
ef13e9a4 914 key_split(&k->k->k); kd = k->k->k;
1ba83484 915 if ((kkd = key_structfind(kd, "curve")) == 0)
916 die(EXIT_FAILURE, "unexpected failure looking up subkey `curve')");
917 if ((kkd->e & KF_ENCMASK) != KENC_STRING)
918 die(EXIT_FAILURE, "subkey `curve' is not a string");
919 if ((e = ec_getinfo(&ei, kkd->u.p)) != 0)
920 die(EXIT_FAILURE, "error in curve spec: %s", e);
921
922 /* --- Invent a private exponent and compute the public key --- */
923
34e4f738 924 x = mprand_range(MP_NEWSEC, ei.r, k->r, 0);
1ba83484 925 ec_mul(ei.c, &p, &ei.g, x);
926
927 /* --- Store everything away --- */
928
ef13e9a4 929 key_structsteal(kd, "p", key_newec(KCAT_PUB, &p));
930
931 kkd = key_newstruct();
932 key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
933 dolock(k, &kkd, "private");
934 key_structsteal(kd, "private", kkd);
1ba83484 935
936 /* --- Done --- */
937
938 ec_freeinfo(&ei);
939 mp_drop(x);
940}
941
fc2d44af
MW
942static void alg_x25519(keyopts *k)
943{
944 key_data *kd, *kkd;
945 octet priv[X25519_KEYSZ], pub[X25519_PUBSZ];
946
947 copyparam(k, 0);
948 k->r->ops->fill(k->r, priv, sizeof(priv));
949 x25519(pub, priv, x25519_base);
950 kkd = key_newstruct();
951 key_structsteal(kkd, "priv",
952 key_newbinary(KCAT_PRIV | KF_BURN, priv, sizeof(priv)));
953 kd = key_newstruct();
954 key_structsteal(kd, "private", kkd);
955 key_structsteal(kd, "pub", key_newbinary(KCAT_PUB, pub, sizeof(pub)));
956
957 key_setkeydata(k->kf, k->k, kd);
958}
959
643eb1bb
MW
960static void alg_x448(keyopts *k)
961{
962 key_data *kd, *kkd;
963 octet priv[X448_KEYSZ], pub[X448_PUBSZ];
964
965 copyparam(k, 0);
966 k->r->ops->fill(k->r, priv, sizeof(priv));
967 x448(pub, priv, x448_base);
968 kkd = key_newstruct();
969 key_structsteal(kkd, "priv",
970 key_newbinary(KCAT_PRIV | KF_BURN, priv, sizeof(priv)));
971 kd = key_newstruct();
972 key_structsteal(kd, "private", kkd);
973 key_structsteal(kd, "pub", key_newbinary(KCAT_PUB, pub, sizeof(pub)));
974
975 key_setkeydata(k->kf, k->k, kd);
976}
977
d56fd9d1
MW
978static void alg_ed25519(keyopts *k)
979{
980 key_data *kd, *kkd;
981 octet priv[ED25519_KEYSZ], pub[ED25519_PUBSZ];
982
983 copyparam(k, 0);
984 k->r->ops->fill(k->r, priv, sizeof(priv));
985 ed25519_pubkey(pub, priv, sizeof(priv));
986 kkd = key_newstruct();
987 key_structsteal(kkd, "priv",
988 key_newbinary(KCAT_PRIV | KF_BURN, priv, sizeof(priv)));
989 kd = key_newstruct();
990 key_structsteal(kd, "private", kkd);
991 key_structsteal(kd, "pub", key_newbinary(KCAT_PUB, pub, sizeof(pub)));
992
993 key_setkeydata(k->kf, k->k, kd);
994}
995
252c122d 996/* --- The algorithm tables --- */
997
998typedef struct keyalg {
999 const char *name;
1000 void (*proc)(keyopts *o);
1001 const char *help;
1002} keyalg;
1003
1004static keyalg algtab[] = {
1005 { "binary", alg_binary, "Plain binary data" },
1006 { "des", alg_des, "Binary with DES-style parity" },
1007 { "rsa", alg_rsa, "RSA public-key encryption" },
3688eb75 1008 { "bbs", alg_bbs, "Blum-Blum-Shub generator" },
252c122d 1009 { "dsa", alg_dsa, "DSA digital signatures" },
1010 { "dsa-param", alg_dsaparam, "DSA shared parameters" },
1011 { "dh", alg_dh, "Diffie-Hellman key exchange" },
1012 { "dh-param", alg_dhparam, "Diffie-Hellman parameters" },
3688eb75 1013 { "bindh", alg_bin, "DH over a binary field" },
1014 { "bindh-param", alg_binparam, "Binary-field DH parameters" },
1ba83484 1015 { "ec-param", alg_ecparam, "Elliptic curve parameters" },
1016 { "ec", alg_ec, "Elliptic curve crypto" },
fc2d44af 1017 { "x25519", alg_x25519, "X25519 key exchange" },
643eb1bb 1018 { "x448", alg_x448, "X448 key exchange" },
d56fd9d1 1019 { "ed25519", alg_ed25519, "Ed25519 digital signatures" },
7532e25e 1020 { "empty", alg_empty, "Empty parametrs-only key" },
252c122d 1021 { 0, 0 }
1022};
d03ab969 1023
1024/* --- @cmd_add@ --- */
1025
1026static int cmd_add(int argc, char *argv[])
1027{
1028 key_file f;
d03ab969 1029 time_t exp = KEXP_EXPIRE;
90a88ae3 1030 uint32 kid = rand_global.ops->word(&rand_global);
252c122d 1031 const char *tag = 0, *ptag = 0;
d03ab969 1032 const char *c = 0;
252c122d 1033 keyalg *alg = algtab;
052b36d0 1034 const char *rtag = 0;
34e4f738 1035 const struct seedalg *sa = SEEDALG_DEFAULT;
1036 keyopts k = { 0, 0, DSTR_INIT, 0, 0, 0, 0, 0 };
1037 const char *seed = 0;
1038 k.r = &rand_global;
d03ab969 1039
1040 /* --- Parse options for the subcommand --- */
1041
1042 for (;;) {
1043 static struct option opt[] = {
252c122d 1044 { "algorithm", OPTF_ARGREQ, 0, 'a' },
d03ab969 1045 { "bits", OPTF_ARGREQ, 0, 'b' },
252c122d 1046 { "qbits", OPTF_ARGREQ, 0, 'B' },
1047 { "parameters", OPTF_ARGREQ, 0, 'p' },
d03ab969 1048 { "expire", OPTF_ARGREQ, 0, 'e' },
1049 { "comment", OPTF_ARGREQ, 0, 'c' },
252c122d 1050 { "tag", OPTF_ARGREQ, 0, 't' },
ce70ec47 1051 { "rand-id", OPTF_ARGREQ, 0, 'R' },
90a88ae3 1052 { "key-id", OPTF_ARGREQ, 0, 'I' },
1ba83484 1053 { "curve", OPTF_ARGREQ, 0, 'C' },
34e4f738 1054 { "seedalg", OPTF_ARGREQ, 0, 'A' },
1055 { "seed", OPTF_ARGREQ, 0, 's' },
1056 { "newseed", OPTF_ARGREQ, 0, 'n' },
252c122d 1057 { "lock", 0, 0, 'l' },
1058 { "quiet", 0, 0, 'q' },
40d5a112 1059 { "lim-lee", 0, 0, 'L' },
1060 { "subgroup", 0, 0, 'S' },
4e67e30b 1061 { "kcdsa", 0, 0, 'K' },
d03ab969 1062 { 0, 0, 0, 0 }
1063 };
90a88ae3 1064 int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:R:I:C:A:s:n:lqrLKS",
a9fcea0e 1065 opt, 0, 0, 0);
d03ab969 1066 if (i < 0)
1067 break;
1068
1069 /* --- Handle the various options --- */
1070
1071 switch (i) {
1072
252c122d 1073 /* --- Read an algorithm name --- */
1074
1075 case 'a': {
1076 keyalg *a;
1077 size_t sz = strlen(optarg);
1078
1079 if (strcmp(optarg, "list") == 0) {
1080 for (a = algtab; a->name; a++)
1081 printf("%-10s %s\n", a->name, a->help);
1082 return (0);
1083 }
1084
1085 alg = 0;
1086 for (a = algtab; a->name; a++) {
1087 if (strncmp(optarg, a->name, sz) == 0) {
1088 if (a->name[sz] == 0) {
1089 alg = a;
1090 break;
1091 } else if (alg)
1092 die(EXIT_FAILURE, "ambiguous algorithm name `%s'", optarg);
1093 else
1094 alg = a;
1095 }
1096 }
1097 if (!alg)
1098 die(EXIT_FAILURE, "unknown algorithm name `%s'", optarg);
1099 } break;
1100
d03ab969 1101 /* --- Bits must be nonzero and a multiple of 8 --- */
1102
252c122d 1103 case 'b': {
1104 char *p;
1105 k.bits = strtoul(optarg, &p, 0);
1106 if (k.bits == 0 || *p != 0)
1107 die(EXIT_FAILURE, "bad bitlength `%s'", optarg);
1108 } break;
1109
1110 case 'B': {
1111 char *p;
1112 k.qbits = strtoul(optarg, &p, 0);
1113 if (k.qbits == 0 || *p != 0)
1114 die(EXIT_FAILURE, "bad bitlength `%s'", optarg);
1115 } break;
1116
1117 /* --- Parameter selection --- */
1118
1119 case 'p':
1120 ptag = optarg;
d03ab969 1121 break;
1122
1123 /* --- Expiry dates get passed to @get_date@ for parsing --- */
1124
1125 case 'e':
9cea6911 1126 if (strcmp(optarg, "forever") == 0)
d03ab969 1127 exp = KEXP_FOREVER;
1128 else {
1129 exp = get_date(optarg, 0);
1130 if (exp == -1)
252c122d 1131 die(EXIT_FAILURE, "bad expiry date `%s'", optarg);
d03ab969 1132 }
1133 break;
1134
1135 /* --- Store comments without interpretation --- */
1136
1137 case 'c':
252c122d 1138 if (key_chkcomment(optarg))
1139 die(EXIT_FAILURE, "bad comment string `%s'", optarg);
d03ab969 1140 c = optarg;
1141 break;
1142
1ba83484 1143 /* --- Elliptic curve parameters --- */
1144
1145 case 'C':
1ba83484 1146 k.curve = optarg;
1147 break;
1148
252c122d 1149 /* --- Store tags --- */
1150
1151 case 't':
1152 if (key_chkident(optarg))
1153 die(EXIT_FAILURE, "bad tag string `%s'", optarg);
1154 tag = optarg;
1155 break;
ce70ec47 1156 case 'r':
1157 k.f |= f_retag;
1158 break;
252c122d 1159
34e4f738 1160 /* --- Seeding --- */
1161
1162 case 'A': {
1163 const struct seedalg *ss;
1164 if (strcmp(optarg, "list") == 0) {
1165 printf("Seed algorithms:\n");
1166 for (ss = seedtab; ss->p; ss++)
1167 printf(" %s\n", ss->p);
1168 exit(0);
1169 }
1170 if (seed) die(EXIT_FAILURE, "seed already set -- put -A first");
1171 sa = 0;
1172 for (ss = seedtab; ss->p; ss++) {
1173 if (strcmp(optarg, ss->p) == 0)
1174 sa = ss;
1175 }
1176 if (!sa)
1177 die(EXIT_FAILURE, "seed algorithm `%s' not known", optarg);
1178 } break;
1179
1180 case 's': {
2b4be81b
MW
1181 codec *c;
1182 int rc;
34e4f738 1183 dstr d = DSTR_INIT;
45c0fd36 1184 if (seed) die(EXIT_FAILURE, "seed already set");
2b4be81b
MW
1185 c = base64_class.decoder(CDCF_IGNEQPAD);
1186 if ((rc = c->ops->code(c, optarg, strlen(optarg), &d)) != 0 ||
1187 (rc = c->ops->code(c, 0, 0, &d)) != 0)
1188 die(EXIT_FAILURE, "invalid seed base64: %s", codec_strerror(rc));
1189 c->ops->destroy(c);
34e4f738 1190 k.r = sa->gen(d.buf, d.len);
1191 seed = optarg;
1192 dstr_destroy(&d);
1193 } break;
45c0fd36 1194
34e4f738 1195 case 'n': {
2b4be81b 1196 codec *c;
34e4f738 1197 dstr d = DSTR_INIT;
1198 char *p;
1199 unsigned n = strtoul(optarg, &p, 0);
1200 if (n == 0 || *p != 0 || n % 8 != 0)
1201 die(EXIT_FAILURE, "bad seed length `%s'", optarg);
45c0fd36 1202 if (seed) die(EXIT_FAILURE, "seed already set");
34e4f738 1203 n /= 8;
1204 p = xmalloc(n);
1205 rand_get(RAND_GLOBAL, p, n);
2b4be81b
MW
1206 c = base64_class.encoder(0, "", 0);
1207 c->ops->code(c, p, n, &d); c->ops->code(c, 0, 0, &d);
1208 c->ops->destroy(c);
34e4f738 1209 seed = d.buf;
1210 k.r = sa->gen(p, n);
1211 } break;
90a88ae3
MW
1212
1213 /* --- Key id --- */
1214
1215 case 'I': {
1216 char *p;
1217 unsigned long id;
1218
1219 errno = 0;
1220 id = strtoul(optarg, &p, 16);
1221 if (errno || *p || id > MASK32)
1222 die(EXIT_FAILURE, "bad key-id `%s'", optarg);
1223 kid = id;
1224 } break;
45c0fd36 1225
252c122d 1226 /* --- Other flags --- */
1227
ce70ec47 1228 case 'R':
052b36d0 1229 rtag = optarg;
1230 break;
252c122d 1231 case 'l':
1232 k.f |= f_lock;
1233 break;
1234 case 'q':
1235 k.f |= f_quiet;
1236 break;
40d5a112 1237 case 'L':
1238 k.f |= f_limlee;
1239 break;
4e67e30b
MW
1240 case 'K':
1241 k.f |= f_kcdsa;
1242 break;
40d5a112 1243 case 'S':
1244 k.f |= f_subgroup;
1245 break;
252c122d 1246
d03ab969 1247 /* --- Other things are bogus --- */
1248
1249 default:
252c122d 1250 k.f |= f_bogus;
d03ab969 1251 break;
1252 }
1253 }
1254
252c122d 1255 /* --- Various sorts of bogosity --- */
d03ab969 1256
252c122d 1257 if ((k.f & f_bogus) || optind + 1 > argc) {
d03ab969 1258 die(EXIT_FAILURE,
c65df279 1259 "Usage: add [OPTIONS] TYPE [ATTR...]");
d03ab969 1260 }
252c122d 1261 if (key_chkident(argv[optind]))
1262 die(EXIT_FAILURE, "bad key type `%s'", argv[optind]);
1263
1264 /* --- Set up various bits of the state --- */
1265
d03ab969 1266 if (exp == KEXP_EXPIRE)
1267 exp = time(0) + 14 * 24 * 60 * 60;
1268
252c122d 1269 /* --- Open the file and create the basic key block --- *
1270 *
1271 * Keep on generating keyids until one of them doesn't collide.
1272 */
d03ab969 1273
252c122d 1274 doopen(&f, KOPEN_WRITE);
1275 k.kf = &f;
1276
052b36d0 1277 /* --- Key the generator --- */
1278
1279 keyrand(&f, rtag);
1280
252c122d 1281 for (;;) {
252c122d 1282 int err;
90a88ae3 1283 if ((err = key_new(&f, kid, argv[optind], exp, &k.k)) == 0)
252c122d 1284 break;
ef13e9a4 1285 else if (err != KERR_DUPID)
252c122d 1286 die(EXIT_FAILURE, "error adding new key: %s", key_strerror(err));
1287 }
d03ab969 1288
252c122d 1289 /* --- Set various simple attributes --- */
d03ab969 1290
252c122d 1291 if (tag) {
ce70ec47 1292 int err;
1293 key *kk;
1294 if (k.f & f_retag) {
694fc3a8 1295 if ((kk = key_bytag(&f, tag)) != 0 &&
1296 kk->tag &&
1297 strcmp(kk->tag, tag) == 0)
ce70ec47 1298 key_settag(&f, kk, 0);
1299 }
1300 if ((err = key_settag(&f, k.k, tag)) != 0)
252c122d 1301 die(EXIT_FAILURE, "error setting key tag: %s", key_strerror(err));
1302 }
d03ab969 1303
252c122d 1304 if (c) {
1305 int err = key_setcomment(&f, k.k, c);
1306 if (err)
1307 die(EXIT_FAILURE, "error setting key comment: %s", key_strerror(err));
1308 }
1309
1310 setattr(&f, k.k, argv + optind + 1);
34e4f738 1311 if (seed) {
1312 key_putattr(&f, k.k, "genseed", seed);
1313 key_putattr(&f, k.k, "seedalg", sa->p);
1314 }
252c122d 1315
1316 key_fulltag(k.k, &k.tag);
1317
1318 /* --- Find the parameter key --- */
1319
131babe4
MW
1320 if (ptag && (k.p = key_bytag(&f, ptag)) == 0)
1321 die(EXIT_FAILURE, "parameter key `%s' not found", ptag);
252c122d 1322
1323 /* --- Now generate the actual key data --- */
1324
1325 alg->proc(&k);
1326
1327 /* --- Done --- */
d03ab969 1328
ef13e9a4 1329 dstr_destroy(&k.tag);
d03ab969 1330 doclose(&f);
1331 return (0);
1332}
1333
252c122d 1334/*----- Key listing -------------------------------------------------------*/
1335
1336/* --- Listing options --- */
1337
1338typedef struct listopts {
1339 const char *tfmt; /* Date format (@strftime@-style) */
1340 int v; /* Verbosity level */
1341 unsigned f; /* Various flags */
1342 time_t t; /* Time now (for key expiry) */
1343 key_filter kf; /* Filter for matching keys */
1344} listopts;
1345
1346/* --- Listing flags --- */
1347
16efd15b 1348#define f_newline 2u /* Write newline before next entry */
1349#define f_attr 4u /* Written at least one attribute */
1350#define f_utc 8u /* Emit UTC time, not local time */
252c122d 1351
1352/* --- @showkeydata@ --- *
1353 *
1354 * Arguments: @key_data *k@ = pointer to key to write
1355 * @int ind@ = indentation level
1356 * @listopts *o@ = listing options
1357 * @dstr *d@ = tag string for this subkey
1358 *
1359 * Returns: ---
1360 *
1361 * Use: Emits a piece of key data in a human-readable format.
1362 */
1363
1364static void showkeydata(key_data *k, int ind, listopts *o, dstr *d)
1365{
1366#define INDENT(i) do { \
1367 int _i; \
1368 for (_i = 0; _i < (i); _i++) { \
1369 putchar(' '); \
1370 } \
1371} while (0)
1372
1373 switch (k->e & KF_ENCMASK) {
1374
1375 /* --- Binary key data --- *
1376 *
1377 * Emit as a simple hex dump.
1378 */
1379
1380 case KENC_BINARY: {
1381 const octet *p = k->u.k.k;
1382 const octet *l = p + k->u.k.sz;
1383 size_t sz = 0;
1384
1385 fputs(" {", stdout);
1386 while (p < l) {
1387 if (sz % 16 == 0) {
1388 putchar('\n');
1389 INDENT(ind + 2);
1390 } else if (sz % 8 == 0)
1391 fputs(" ", stdout);
1392 else
1393 putc(' ', stdout);
1394 printf("%02x", *p++);
1395 sz++;
1396 }
1397 putchar('\n');
1398 INDENT(ind);
1399 fputs("}\n", stdout);
1400 } break;
1401
1402 /* --- Encrypted data --- *
1403 *
1404 * If the user is sufficiently keen, ask for a passphrase and decrypt the
1405 * key. Otherwise just say that it's encrypted and move on.
1406 */
1407
1408 case KENC_ENCRYPT:
1409 if (o->v <= 3)
1410 fputs(" encrypted\n", stdout);
1411 else {
ef13e9a4 1412 key_data *kd;
1413 if (key_punlock(&kd, k, d->buf))
252c122d 1414 printf(" <failed to unlock %s>\n", d->buf);
1415 else {
1416 fputs(" encrypted", stdout);
ef13e9a4 1417 showkeydata(kd, ind, o, d);
1418 key_drop(kd);
252c122d 1419 }
1420 }
1421 break;
1422
1423 /* --- Integer keys --- *
1424 *
1425 * Emit as a large integer in decimal. This makes using the key in
1426 * `calc' or whatever easier.
1427 */
1428
1429 case KENC_MP:
1430 putchar(' ');
1431 mp_writefile(k->u.m, stdout, 10);
1432 putchar('\n');
1433 break;
1434
1ba83484 1435 /* --- Strings --- */
1436
1437 case KENC_STRING:
1438 printf(" `%s'\n", k->u.p);
1439 break;
1440
1441 /* --- Elliptic curve points --- */
1442
1443 case KENC_EC:
d1ee65aa 1444 if (EC_ATINF(&k->u.e))
a9fcea0e 1445 fputs(" inf\n", stdout);
d1ee65aa 1446 else {
1447 fputs(" 0x", stdout); mp_writefile(k->u.e.x, stdout, 16);
1448 fputs(", 0x", stdout); mp_writefile(k->u.e.y, stdout, 16);
1449 putchar('\n');
1450 }
45c0fd36 1451 break;
1ba83484 1452
252c122d 1453 /* --- Structured keys --- *
1454 *
1455 * Just iterate over the subkeys.
1456 */
1457
1458 case KENC_STRUCT: {
ef13e9a4 1459 key_subkeyiter i;
1460 const char *tag;
252c122d 1461 size_t n = d->len;
1462
1463 fputs(" {\n", stdout);
ef13e9a4 1464 for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &k); ) {
1465 if (!key_match(k, &o->kf))
252c122d 1466 continue;
1467 INDENT(ind + 2);
ef13e9a4 1468 printf("%s =", tag);
252c122d 1469 d->len = n;
ef13e9a4 1470 dstr_putf(d, ".%s", tag);
1471 showkeydata(k, ind + 2, o, d);
252c122d 1472 }
1473 INDENT(ind);
1474 fputs("}\n", stdout);
45c0fd36 1475 } break;
252c122d 1476 }
1477
1478#undef INDENT
1479}
1480
1481/* --- @showkey@ --- *
1482 *
1483 * Arguments: @key *k@ = pointer to key to show
1484 * @listopts *o@ = pointer to listing options
1485 *
1486 * Returns: ---
1487 *
1488 * Use: Emits a listing of a particular key.
1489 */
1490
1491static void showkey(key *k, listopts *o)
1492{
1493 char ebuf[24], dbuf[24];
1494 struct tm *tm;
1495
1496 /* --- Skip the key if the filter doesn't match --- */
1497
ef13e9a4 1498 if (!key_match(k->k, &o->kf))
252c122d 1499 return;
1500
1501 /* --- Sort out the expiry and deletion times --- */
1502
1503 if (KEY_EXPIRED(o->t, k->exp))
1504 strcpy(ebuf, "expired");
1505 else if (k->exp == KEXP_FOREVER)
1506 strcpy(ebuf, "forever");
1507 else {
1508 tm = (o->f & f_utc) ? gmtime(&k->exp) : localtime(&k->exp);
1509 strftime(ebuf, sizeof(ebuf), o->tfmt, tm);
1510 }
1511
1512 if (KEY_EXPIRED(o->t, k->del))
1513 strcpy(dbuf, "deleted");
1514 else if (k->del == KEXP_FOREVER)
1515 strcpy(dbuf, "forever");
1516 else {
1517 tm = (o->f & f_utc) ? gmtime(&k->del) : localtime(&k->del);
1518 strftime(dbuf, sizeof(dbuf), o->tfmt, tm);
1519 }
1520
1521 /* --- If in compact format, just display and quit --- */
1522
1523 if (!o->v) {
1524 if (!(o->f & f_newline)) {
8cd9f01d 1525 printf("%8s %-20s %-20s %-10s %s\n",
252c122d 1526 "Id", "Tag", "Type", "Expire", "Delete");
1527 }
8cd9f01d 1528 printf("%08lx %-20s %-20s %-10s %s\n",
252c122d 1529 (unsigned long)k->id, k->tag ? k->tag : "<none>",
1530 k->type, ebuf, dbuf);
1531 o->f |= f_newline;
1532 return;
1533 }
1534
1535 /* --- Display the standard header --- */
1536
1537 if (o->f & f_newline)
1538 fputc('\n', stdout);
1539 printf("keyid: %08lx\n", (unsigned long)k->id);
1540 printf("tag: %s\n", k->tag ? k->tag : "<none>");
1541 printf("type: %s\n", k->type);
1542 printf("expiry: %s\n", ebuf);
1543 printf("delete: %s\n", dbuf);
1544 printf("comment: %s\n", k->c ? k->c : "<none>");
1545
1546 /* --- Display the attributes --- */
1547
1548 if (o->v > 1) {
1549 key_attriter i;
1550 const char *av, *an;
1551
1552 o->f &= ~f_attr;
1553 printf("attributes:");
1554 for (key_mkattriter(&i, k); key_nextattr(&i, &an, &av); ) {
dce3fb0d 1555 printf("\n %s = %s", an, av);
252c122d 1556 o->f |= f_attr;
1557 }
1558 if (o->f & f_attr)
1559 fputc('\n', stdout);
1560 else
1561 puts(" <none>");
1562 }
1563
1564 /* --- If dumping requested, dump the raw key data --- */
1565
1566 if (o->v > 2) {
1567 dstr d = DSTR_INIT;
1568 fputs("key:", stdout);
1569 key_fulltag(k, &d);
ef13e9a4 1570 showkeydata(k->k, 0, o, &d);
252c122d 1571 dstr_destroy(&d);
1572 }
45c0fd36 1573
252c122d 1574 o->f |= f_newline;
1575}
1576
1577/* --- @cmd_list@ --- */
1578
1579static int cmd_list(int argc, char *argv[])
1580{
1581 key_file f;
1582 key *k;
1583 listopts o = { 0, 0, 0, 0, { 0, 0 } };
1584
1585 /* --- Parse subcommand options --- */
1586
1587 for (;;) {
1588 static struct option opt[] = {
1589 { "quiet", 0, 0, 'q' },
1590 { "verbose", 0, 0, 'v' },
1591 { "utc", 0, 0, 'u' },
1592 { "filter", OPTF_ARGREQ, 0, 'f' },
1593 { 0, 0, 0, 0 }
1594 };
1595 int i = mdwopt(argc, argv, "+uqvf:", opt, 0, 0, 0);
1596 if (i < 0)
1597 break;
1598
1599 switch (i) {
1600 case 'u':
1601 o.f |= f_utc;
1602 break;
1603 case 'q':
1604 if (o.v)
1605 o.v--;
1606 break;
1607 case 'v':
1608 o.v++;
1609 break;
1610 case 'f': {
1611 char *p;
1612 int e = key_readflags(optarg, &p, &o.kf.f, &o.kf.m);
1613 if (e || *p)
1614 die(EXIT_FAILURE, "bad filter string `%s'", optarg);
45c0fd36 1615 } break;
252c122d 1616 default:
1617 o.f |= f_bogus;
1618 break;
1619 }
1620 }
1621
1622 if (o.f & f_bogus)
c65df279 1623 die(EXIT_FAILURE, "Usage: list [-uqv] [-f FILTER] [TAG...]");
252c122d 1624
1625 /* --- Open the key file --- */
1626
1627 doopen(&f, KOPEN_READ);
1628 o.t = time(0);
1629
1630 /* --- Set up the time format --- */
1631
1632 if (!o.v)
1633 o.tfmt = "%Y-%m-%d";
1634 else if (o.f & f_utc)
1635 o.tfmt = "%Y-%m-%d %H:%M:%S UTC";
1636 else
1637 o.tfmt = "%Y-%m-%d %H:%M:%S %Z";
1638
1639 /* --- If specific keys were requested use them, otherwise do all --- *
1640 *
1641 * Some day, this might turn into a wildcard match.
1642 */
1643
1644 if (optind < argc) {
1645 do {
1646 if ((k = key_bytag(&f, argv[optind])) != 0)
1647 showkey(k, &o);
1648 else {
1649 moan("key `%s' not found", argv[optind]);
1650 o.f |= f_bogus;
1651 }
1652 optind++;
1653 } while (optind < argc);
1654 } else {
1655 key_iter i;
1656 for (key_mkiter(&i, &f); (k = key_next(&i)) != 0; )
1657 showkey(k, &o);
1658 }
1659
1660 /* --- Done --- */
1661
1662 doclose(&f);
1663 if (o.f & f_bogus)
1664 return (EXIT_FAILURE);
1665 else
1666 return (0);
1667}
1668
1669/*----- Command implementation --------------------------------------------*/
1670
d03ab969 1671/* --- @cmd_expire@ --- */
1672
1673static int cmd_expire(int argc, char *argv[])
1674{
1675 key_file f;
1676 key *k;
d03ab969 1677 int i;
1678 int rc = 0;
1679
1680 if (argc < 2)
c65df279 1681 die(EXIT_FAILURE, "Usage: expire TAG...");
d03ab969 1682 doopen(&f, KOPEN_WRITE);
1683 for (i = 1; i < argc; i++) {
252c122d 1684 if ((k = key_bytag(&f, argv[i])) != 0)
d03ab969 1685 key_expire(&f, k);
1686 else {
252c122d 1687 moan("key `%s' not found", argv[i]);
d03ab969 1688 rc = 1;
1689 }
1690 }
1691 doclose(&f);
1692 return (rc);
1693}
1694
1695/* --- @cmd_delete@ --- */
1696
1697static int cmd_delete(int argc, char *argv[])
1698{
1699 key_file f;
1700 key *k;
d03ab969 1701 int i;
1702 int rc = 0;
1703
1704 if (argc < 2)
c65df279 1705 die(EXIT_FAILURE, "Usage: delete TAG...");
d03ab969 1706 doopen(&f, KOPEN_WRITE);
1707 for (i = 1; i < argc; i++) {
252c122d 1708 if ((k = key_bytag(&f, argv[i])) != 0)
d03ab969 1709 key_delete(&f, k);
1710 else {
252c122d 1711 moan("key `%s' not found", argv[i]);
d03ab969 1712 rc = 1;
1713 }
1714 }
1715 doclose(&f);
1716 return (rc);
1717}
1718
1719/* --- @cmd_setattr@ --- */
1720
1721static int cmd_setattr(int argc, char *argv[])
1722{
1723 key_file f;
1724 key *k;
d03ab969 1725
1726 if (argc < 3)
c65df279 1727 die(EXIT_FAILURE, "Usage: setattr TAG ATTR...");
d03ab969 1728 doopen(&f, KOPEN_WRITE);
252c122d 1729 if ((k = key_bytag(&f, argv[1])) == 0)
1730 die(EXIT_FAILURE, "key `%s' not found", argv[1]);
d03ab969 1731 setattr(&f, k, argv + 2);
1732 doclose(&f);
1733 return (0);
1734}
1735
e9be047b 1736/* --- @cmd_getattr@ --- */
1737
1738static int cmd_getattr(int argc, char *argv[])
1739{
1740 key_file f;
1741 key *k;
1742 dstr d = DSTR_INIT;
1743 const char *p;
1744
1745 if (argc != 3)
1746 die(EXIT_FAILURE, "Usage: getattr TAG ATTR");
1747 doopen(&f, KOPEN_READ);
1748 if ((k = key_bytag(&f, argv[1])) == 0)
1749 die(EXIT_FAILURE, "key `%s' not found", argv[1]);
1750 key_fulltag(k, &d);
1751 if ((p = key_getattr(&f, k, argv[2])) == 0)
1752 die(EXIT_FAILURE, "no attribute `%s' for key `%s'", argv[2], d.buf);
1753 puts(p);
1754 dstr_destroy(&d);
1755 doclose(&f);
1756 return (0);
1757}
1758
252c122d 1759/* --- @cmd_finger@ --- */
d03ab969 1760
16810bbd
MW
1761static const struct fpres {
1762 const char *name;
1763 const codec_class *cdc;
1764 unsigned short ival;
1765 const char *sep;
1766} fprestab[] = {
1767 { "hex", &hex_class, 8, "-:" },
1768 { "base32", &base32_class, 6, ":" },
1769 { 0, 0 }
1770};
1771
1772static void fingerprint(key *k, const struct fpres *fpres,
1773 const gchash *ch, const key_filter *kf)
d03ab969 1774{
981bf127 1775 ghash *h;
16810bbd 1776 dstr d = DSTR_INIT, dd = DSTR_INIT;
981bf127 1777 const octet *p;
1778 size_t i;
16810bbd 1779 codec *c;
d03ab969 1780
981bf127 1781 h = GH_INIT(ch);
1782 if (key_fingerprint(k, h, kf)) {
1783 p = GH_DONE(h, 0);
16810bbd
MW
1784 c = fpres->cdc->encoder(CDCF_LOWERC | CDCF_NOEQPAD, "", 0);
1785 c->ops->code(c, p, ch->hashsz, &dd); c->ops->code(c, 0, 0, &dd);
1786 c->ops->destroy(c);
1787 for (i = 0; i < dd.len; i++) {
1788 if (i && i%fpres->ival == 0) dstr_putc(&d, fpres->sep[0]);
1789 dstr_putc(&d, dd.buf[i]);
981bf127 1790 }
16810bbd
MW
1791 dstr_putc(&d, ' '); key_fulltag(k, &d); dstr_putc(&d, '\n');
1792 dstr_write(&d, stdout);
252c122d 1793 }
16810bbd 1794 dstr_destroy(&d); dstr_destroy(&dd);
981bf127 1795 GH_DESTROY(h);
252c122d 1796}
d03ab969 1797
16810bbd
MW
1798static const struct fpres *lookup_fpres(const char *name)
1799{
1800 const struct fpres *fpres;
1801 for (fpres = fprestab; fpres->name; fpres++)
1802 if (strcmp(fpres->name, name) == 0) return (fpres);
1803 die(EXIT_FAILURE, "unknown presentation syle `%s'", name);
1804}
1805
252c122d 1806static int cmd_finger(int argc, char *argv[])
1807{
1808 key_file f;
1809 int rc = 0;
16810bbd 1810 const struct fpres *fpres = fprestab;
981bf127 1811 const gchash *ch = &rmd160;
252c122d 1812 key_filter kf = { KF_NONSECRET, KF_NONSECRET };
d03ab969 1813
1814 for (;;) {
1815 static struct option opt[] = {
252c122d 1816 { "filter", OPTF_ARGREQ, 0, 'f' },
16810bbd 1817 { "presentation", OPTF_ARGREQ, 0, 'p' },
981bf127 1818 { "algorithm", OPTF_ARGREQ, 0, 'a' },
252c122d 1819 { 0, 0, 0, 0 }
d03ab969 1820 };
16810bbd 1821 int i = mdwopt(argc, argv, "+f:a:p:", opt, 0, 0, 0);
d03ab969 1822 if (i < 0)
1823 break;
d03ab969 1824 switch (i) {
252c122d 1825 case 'f': {
1826 char *p;
1827 int err = key_readflags(optarg, &p, &kf.f, &kf.m);
1828 if (err || *p)
1829 die(EXIT_FAILURE, "bad filter string `%s'", optarg);
1830 } break;
16810bbd
MW
1831 case 'p':
1832 fpres = lookup_fpres(optarg);
1833 break;
981bf127 1834 case 'a':
1835 if ((ch = ghash_byname(optarg)) == 0)
1836 die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg);
1837 break;
d03ab969 1838 default:
252c122d 1839 rc = 1;
d03ab969 1840 break;
1841 }
1842 }
1843
252c122d 1844 argv += optind; argc -= optind;
16810bbd
MW
1845 if (rc) {
1846 die(EXIT_FAILURE,
1847 "Usage: fingerprint [-a HASHALG] [-p STYLE] [-f FILTER] [TAG...]");
1848 }
d03ab969 1849
1850 doopen(&f, KOPEN_READ);
d03ab969 1851
252c122d 1852 if (argc) {
1853 int i;
1854 for (i = 0; i < argc; i++) {
1855 key *k = key_bytag(&f, argv[i]);
1856 if (k)
16810bbd 1857 fingerprint(k, fpres, ch, &kf);
252c122d 1858 else {
1859 rc = 1;
1860 moan("key `%s' not found", argv[i]);
1861 }
1862 }
1863 } else {
1864 key_iter i;
1865 key *k;
1866 for (key_mkiter(&i, &f); (k = key_next(&i)) != 0; )
16810bbd 1867 fingerprint(k, fpres, ch, &kf);
252c122d 1868 }
1869 return (rc);
1870}
d03ab969 1871
58507325 1872/* --- @cmd_verify@ --- */
1873
58507325 1874static int cmd_verify(int argc, char *argv[])
1875{
1876 key_file f;
1877 int rc = 0;
1878 const gchash *ch = &rmd160;
1879 ghash *h;
1880 key *k;
58507325 1881 const octet *fpr;
16810bbd
MW
1882 dstr d = DSTR_INIT, dd = DSTR_INIT;
1883 codec *c;
1884 const char *p;
1885 const struct fpres *fpres = fprestab;
58507325 1886 key_filter kf = { KF_NONSECRET, KF_NONSECRET };
1887
1888 for (;;) {
1889 static struct option opt[] = {
1890 { "filter", OPTF_ARGREQ, 0, 'f' },
16810bbd 1891 { "presentation", OPTF_ARGREQ, 0, 'p' },
58507325 1892 { "algorithm", OPTF_ARGREQ, 0, 'a' },
1893 { 0, 0, 0, 0 }
1894 };
16810bbd 1895 int i = mdwopt(argc, argv, "+f:a:p:", opt, 0, 0, 0);
58507325 1896 if (i < 0)
1897 break;
1898 switch (i) {
1899 case 'f': {
1900 char *p;
1901 int err = key_readflags(optarg, &p, &kf.f, &kf.m);
1902 if (err || *p)
1903 die(EXIT_FAILURE, "bad filter string `%s'", optarg);
1904 } break;
16810bbd
MW
1905 case 'p':
1906 fpres = lookup_fpres(optarg);
1907 break;
58507325 1908 case 'a':
1909 if ((ch = ghash_byname(optarg)) == 0)
1910 die(EXIT_FAILURE, "unknown hash algorithm `%s'", optarg);
1911 break;
1912 default:
1913 rc = 1;
1914 break;
1915 }
1916 }
1917
1918 argv += optind; argc -= optind;
16810bbd
MW
1919 if (rc || argc != 2) {
1920 die(EXIT_FAILURE,
1921 "Usage: verify [-a HASHALG] [-p STYLE] [-f FILTER] TAG FINGERPRINT");
1922 }
58507325 1923
1924 doopen(&f, KOPEN_READ);
1925
1926 if ((k = key_bytag(&f, argv[0])) == 0)
1927 die(EXIT_FAILURE, "key `%s' not found", argv[0]);
16810bbd
MW
1928 for (p = argv[1]; *p; p++) {
1929 if (strchr(fpres->sep, *p)) continue;
1930 dstr_putc(&dd, *p);
1931 }
1932 c = fpres->cdc->decoder(CDCF_IGNCASE | CDCF_IGNEQPAD |
1933 CDCF_IGNSPC | CDCF_IGNNEWL);
1934 if ((rc = c->ops->code(c, dd.buf, dd.len, &d)) != 0 ||
1935 (rc = c->ops->code(c, 0, 0, &d)) != 0)
1936 die(EXIT_FAILURE, "invalid fingerprint: %s", codec_strerror(rc));
1937 c->ops->destroy(c);
1938 if (d.len != ch->hashsz) {
1939 die(EXIT_FAILURE, "incorrect fingerprint length (%lu != %lu)",
1940 (unsigned long)d.len, (unsigned long)ch->hashsz);
1941 }
58507325 1942 h = GH_INIT(ch);
1943 if (!key_fingerprint(k, h, &kf))
1944 die(EXIT_FAILURE, "key has no fingerprintable components (as filtered)");
1945 fpr = GH_DONE(h, 0);
16810bbd 1946 if (memcmp(fpr, d.buf, ch->hashsz) != 0)
58507325 1947 die(EXIT_FAILURE, "key fingerprint mismatch");
16810bbd 1948 dstr_destroy(&d); dstr_destroy(&dd);
e9be047b 1949 doclose(&f);
58507325 1950 return (0);
1951}
45c0fd36 1952
252c122d 1953/* --- @cmd_comment@ --- */
d03ab969 1954
252c122d 1955static int cmd_comment(int argc, char *argv[])
1956{
1957 key_file f;
1958 key *k;
1959 int err;
d03ab969 1960
252c122d 1961 if (argc < 2 || argc > 3)
c65df279 1962 die(EXIT_FAILURE, "Usage: comment TAG [COMMENT]");
252c122d 1963 doopen(&f, KOPEN_WRITE);
1964 if ((k = key_bytag(&f, argv[1])) == 0)
1965 die(EXIT_FAILURE, "key `%s' not found", argv[1]);
1966 if ((err = key_setcomment(&f, k, argv[2])) != 0)
1967 die(EXIT_FAILURE, "bad comment `%s': %s", argv[2], key_strerror(err));
1968 doclose(&f);
1969 return (0);
1970}
d03ab969 1971
252c122d 1972/* --- @cmd_tag@ --- */
d03ab969 1973
252c122d 1974static int cmd_tag(int argc, char *argv[])
1975{
1976 key_file f;
1977 key *k;
1978 int err;
ce70ec47 1979 unsigned flags = 0;
1980 int rc = 0;
d03ab969 1981
ce70ec47 1982 for (;;) {
1983 static struct option opt[] = {
1984 { "retag", 0, 0, 'r' },
1985 { 0, 0, 0, 0 }
1986 };
1987 int i = mdwopt(argc, argv, "+r", opt, 0, 0, 0);
1988 if (i < 0)
1989 break;
1990 switch (i) {
1991 case 'r':
1992 flags |= f_retag;
1993 break;
1994 default:
1995 rc = 1;
1996 break;
1997 }
1998 }
1999
2000 argv += optind; argc -= optind;
2001 if (argc < 1 || argc > 2 || rc)
c65df279 2002 die(EXIT_FAILURE, "Usage: tag [-r] TAG [NEW-TAG]");
252c122d 2003 doopen(&f, KOPEN_WRITE);
ce70ec47 2004 if (flags & f_retag) {
2005 if ((k = key_bytag(&f, argv[1])) != 0 && strcmp(k->tag, argv[1]) == 0)
2006 key_settag(&f, k, 0);
2007 }
2008 if ((k = key_bytag(&f, argv[0])) == 0)
2009 die(EXIT_FAILURE, "key `%s' not found", argv[0]);
2010 if ((err = key_settag(&f, k, argv[1])) != 0)
2011 die(EXIT_FAILURE, "bad tag `%s': %s", argv[1], key_strerror(err));
252c122d 2012 doclose(&f);
2013 return (0);
2014}
d03ab969 2015
252c122d 2016/* --- @cmd_lock@ --- */
d03ab969 2017
252c122d 2018static int cmd_lock(int argc, char *argv[])
2019{
2020 key_file f;
2021 key *k;
ef13e9a4 2022 key_data **kd;
252c122d 2023 dstr d = DSTR_INIT;
d03ab969 2024
252c122d 2025 if (argc != 2)
c65df279 2026 die(EXIT_FAILURE, "Usage: lock QTAG");
252c122d 2027 doopen(&f, KOPEN_WRITE);
2028 if (key_qtag(&f, argv[1], &d, &k, &kd))
2029 die(EXIT_FAILURE, "key `%s' not found", argv[1]);
ef13e9a4 2030 if ((*kd)->e == KENC_ENCRYPT && key_punlock(kd, 0, d.buf))
252c122d 2031 die(EXIT_FAILURE, "couldn't unlock key `%s'", d.buf);
ef13e9a4 2032 if (key_plock(kd, 0, d.buf))
252c122d 2033 die(EXIT_FAILURE, "failed to lock key `%s'", d.buf);
2034 f.f |= KF_MODIFIED;
2035 doclose(&f);
2036 return (0);
2037}
d03ab969 2038
252c122d 2039/* --- @cmd_unlock@ --- */
d03ab969 2040
252c122d 2041static int cmd_unlock(int argc, char *argv[])
2042{
2043 key_file f;
2044 key *k;
ef13e9a4 2045 key_data **kd;
252c122d 2046 dstr d = DSTR_INIT;
d03ab969 2047
252c122d 2048 if (argc != 2)
c65df279 2049 die(EXIT_FAILURE, "Usage: unlock QTAG");
252c122d 2050 doopen(&f, KOPEN_WRITE);
2051 if (key_qtag(&f, argv[1], &d, &k, &kd))
2052 die(EXIT_FAILURE, "key `%s' not found", argv[1]);
ef13e9a4 2053 if ((*kd)->e != KENC_ENCRYPT)
252c122d 2054 die(EXIT_FAILURE, "key `%s' is not encrypted", d.buf);
ef13e9a4 2055 if (key_punlock(kd, 0, d.buf))
252c122d 2056 die(EXIT_FAILURE, "couldn't unlock key `%s'", d.buf);
2057 f.f |= KF_MODIFIED;
d03ab969 2058 doclose(&f);
2059 return (0);
2060}
2061
2062/* --- @cmd_extract@ --- */
2063
2064static int cmd_extract(int argc, char *argv[])
2065{
2066 key_file f;
2067 key *k;
d03ab969 2068 int i;
2069 int rc = 0;
252c122d 2070 key_filter kf = { 0, 0 };
694fc3a8 2071 dstr d = DSTR_INIT;
2072 const char *outfile = 0;
d03ab969 2073 FILE *fp;
2074
252c122d 2075 for (;;) {
2076 static struct option opt[] = {
2077 { "filter", OPTF_ARGREQ, 0, 'f' },
2078 { 0, 0, 0, 0 }
2079 };
2080 int i = mdwopt(argc, argv, "f:", opt, 0, 0, 0);
2081 if (i < 0)
2082 break;
2083 switch (i) {
2084 case 'f': {
2085 char *p;
2086 int err = key_readflags(optarg, &p, &kf.f, &kf.m);
2087 if (err || *p)
2088 die(EXIT_FAILURE, "bad filter string `%s'", optarg);
2089 } break;
2090 default:
2091 rc = 1;
2092 break;
2093 }
2094 }
2095
2096 argv += optind; argc -= optind;
2097 if (rc || argc < 1)
c65df279 2098 die(EXIT_FAILURE, "Usage: extract [-f FILTER] FILE [TAG...]");
252c122d 2099 if (strcmp(*argv, "-") == 0)
d03ab969 2100 fp = stdout;
694fc3a8 2101 else {
2102 outfile = *argv;
2103 dstr_putf(&d, "%s.new", outfile);
2104 if (!(fp = fopen(d.buf, "w"))) {
2105 die(EXIT_FAILURE, "couldn't open `%s' for writing: %s",
2106 d.buf, strerror(errno));
2107 }
d03ab969 2108 }
2109
252c122d 2110 doopen(&f, KOPEN_READ);
2111 if (argc < 2) {
2112 key_iter i;
2113 key *k;
2114 for (key_mkiter(&i, &f); (k = key_next(&i)) != 0; )
2115 key_extract(&f, k, fp, &kf);
45c0fd36 2116 } else {
252c122d 2117 for (i = 1; i < argc; i++) {
2118 if ((k = key_bytag(&f, argv[i])) != 0)
2119 key_extract(&f, k, fp, &kf);
2120 else {
2121 moan("key `%s' not found", argv[i]);
2122 rc = 1;
2123 }
d03ab969 2124 }
2125 }
694fc3a8 2126 if (fclose(fp) || (outfile && rename(d.buf, outfile)))
252c122d 2127 die(EXIT_FAILURE, "error writing file: %s", strerror(errno));
694fc3a8 2128 dstr_destroy(&d);
d03ab969 2129 doclose(&f);
2130 return (rc);
2131}
2132
2133/* --- @cmd_tidy@ --- */
2134
2135static int cmd_tidy(int argc, char *argv[])
2136{
2137 key_file f;
2138 if (argc != 1)
c65df279 2139 die(EXIT_FAILURE, "Usage: tidy");
d03ab969 2140 doopen(&f, KOPEN_WRITE);
2141 f.f |= KF_MODIFIED; /* Nasty hack */
2142 doclose(&f);
2143 return (0);
2144}
2145
2146/* --- @cmd_merge@ --- */
2147
2148static int cmd_merge(int argc, char *argv[])
2149{
2150 key_file f;
2151 FILE *fp;
2152
2153 if (argc != 2)
c65df279 2154 die(EXIT_FAILURE, "Usage: merge FILE");
d03ab969 2155 if (strcmp(argv[1], "-") == 0)
2156 fp = stdin;
2157 else if (!(fp = fopen(argv[1], "r"))) {
d3296500 2158 die(EXIT_FAILURE, "couldn't open `%s' for reading: %s",
d03ab969 2159 argv[1], strerror(errno));
2160 }
2161
2162 doopen(&f, KOPEN_WRITE);
252c122d 2163 key_merge(&f, argv[1], fp, key_moan, 0);
d03ab969 2164 doclose(&f);
2165 return (0);
2166}
2167
c65df279 2168/* --- @cmd_show@ --- */
2169
2170#define LISTS(LI) \
2171 LI("Lists", list, \
2172 listtab[i].name, listtab[i].name) \
2173 LI("Hash functions", hash, \
2174 ghashtab[i], ghashtab[i]->name) \
2175 LI("Elliptic curves", ec, \
2176 ectab[i].name, ectab[i].name) \
3688eb75 2177 LI("Prime Diffie-Hellman groups", dh, \
c65df279 2178 ptab[i].name, ptab[i].name) \
3688eb75 2179 LI("Binary Diffie-Hellman groups", bindh, \
2180 bintab[i].name, bintab[i].name) \
c65df279 2181 LI("Key-generation algorithms", keygen, \
2182 algtab[i].name, algtab[i].name) \
2183 LI("Random seeding algorithms", seed, \
16810bbd
MW
2184 seedtab[i].p, seedtab[i].p) \
2185 LI("Fingerprint presentation styles", fpres, \
2186 fprestab[i].name, fprestab[i].name)
c65df279 2187
2188MAKELISTTAB(listtab, LISTS)
2189
2190static int cmd_show(int argc, char *argv[])
2191{
2192 return (displaylists(listtab, argv + 1));
2193}
2194
d03ab969 2195/*----- Main command table ------------------------------------------------*/
2196
c65df279 2197static int cmd_help(int argc, char *argv[]);
2198
2199static cmd cmds[] = {
2200 { "help", cmd_help, "help [COMMAND...]" },
2201 { "show", cmd_show, "show [ITEM...]" },
2202 { "list", cmd_list, "list [-uqv] [-f FILTER] [TAG...]", "\
2203Options:\n\
2204\n\
2205-u, --utc Display expiry times etc. in UTC, not local time.\n\
2206-q, --quiet Show less information.\n\
2207-v, --verbose Show more information.\n\
2208" },
16810bbd
MW
2209 { "fingerprint", cmd_finger,
2210 "fingerprint [-a HASHALG] [-p STYLE] [-f FILTER] [TAG...]", "\
c65df279 2211Options:\n\
2212\n\
2213-f, --filter=FILT Only hash key components matching FILT.\n\
16810bbd 2214-p, --presentation=STYLE Use STYLE for presenting fingerprints.\n\
c65df279 2215-a, --algorithm=HASH Use the named HASH algorithm.\n\
2216 ($ show hash for list.)\n\
2217" },
16810bbd
MW
2218 { "verify", cmd_verify,
2219 "verify [-a HASH] [-p STYLE] [-f FILTER] TAG FINGERPRINT", "\
58507325 2220Options:\n\
2221\n\
2222-f, --filter=FILT Only hash key components matching FILT.\n\
16810bbd 2223-p, --presentation=STYLE Expect FINGERPRINT in the given STYLE.\n\
58507325 2224-a, --algorithm=HASH Use the named HASH algorithm.\n\
2225 ($ show hash for list.)\n\
2226" },
c65df279 2227 { "extract", cmd_extract, "extract [-f FILTER] FILE [TAG...]", "\
2228Options:\n\
2229\n\
2230-f, --filter=FILT Only extract key components matching FILT.\n\
2231" },
2232 { "merge", cmd_merge, "merge FILE" },
2233 { "expire", cmd_expire, "expire TAG..." },
2234 { "delete", cmd_delete, "delete TAG..." },
2235 { "setattr", cmd_setattr, "setattr TAG ATTR..." },
e9be047b 2236 { "getattr", cmd_getattr, "getattr TAG ATTR" },
c65df279 2237 { "comment", cmd_comment, "comment TAG [COMMENT]" },
2238 { "lock", cmd_lock, "lock QTAG" },
2239 { "unlock", cmd_unlock, "unlock QTAG" },
2240 { "tag", cmd_tag, "tag [-r] TAG [NEW-TAG]", "\
2241Options:\n\
2242\n\
2243-r, --retag Untag any key currently called new-tag.\n\
2244" },
2245 { "tidy", cmd_tidy, "tidy" },
d03ab969 2246 { "add", cmd_add,
c65df279 2247 "add [-OPTIONS] TYPE [ATTR...]\n\
4e67e30b 2248 Options: [-lqrLKS] [-a ALG] [-bB BITS] [-p PARAM] [-R TAG]\n\
45c0fd36
MW
2249 [-A SEEDALG] [-s SEED] [-n BITS] [-I KEYID]\n\
2250 [-e EXPIRE] [-t TAG] [-c COMMENT]", "\
ce70ec47 2251Options:\n\
2252\n\
2253-a, --algorithm=ALG Generate keys suitable for ALG.\n\
c65df279 2254 ($ show keygen for list.)\n\
ce70ec47 2255-b, --bits=N Generate an N-bit key.\n\
2256-B, --qbits=N Use an N-bit subgroup or factors.\n\
2257-p, --parameters=TAG Get group parameters from TAG.\n\
c65df279 2258-C, --curve=NAME Use elliptic curve or DH group NAME.\n\
2259 ($ show ec or $ show dh for list.)\n\
2260-A, --seedalg=ALG Use pseudorandom generator ALG to generate key.\n\
2261 ($ show seed for list.)\n\
2262-s, --seed=BASE64 Use Base64-encoded string BASE64 as seed.\n\
2263-n, --newseed=COUNT Generate new COUNT-bit seed.\n\
ce70ec47 2264-e, --expire=TIME Make the key expire after TIME.\n\
2265-c, --comment=STRING Attach the command STRING to the key.\n\
2266-t, --tag=TAG Tag the key with the name TAG.\n\
2267-r, --retag Untag any key currently with that tag.\n\
2268-R, --rand-id=TAG Use key named TAG for the random number generator.\n\
90a88ae3 2269-I, --key-id=ID Force the key-id for the new key.\n\
ce70ec47 2270-l, --lock Lock the generated key with a passphrase.\n\
2271-q, --quiet Don't give progress indicators while working.\n\
2272-L, --lim-lee Generate Lim-Lee primes for Diffie-Hellman groups.\n\
4e67e30b 2273-K, --kcdsa Generate KCDSA-style Lim-Lee primes for DH groups.\n\
ce70ec47 2274-S, --subgroup Use a prime-order subgroup for Diffie-Hellman.\n\
2275" },
d03ab969 2276 { 0, 0, 0 }
2277};
2278
c65df279 2279static int cmd_help(int argc, char *argv[])
ce70ec47 2280{
c65df279 2281 sc_help(cmds, stdout, argv + 1);
2282 return (0);
ce70ec47 2283}
2284
c65df279 2285/*----- Main code ---------------------------------------------------------*/
2286
d03ab969 2287/* --- Helpful GNUy functions --- */
2288
c65df279 2289static void usage(FILE *fp)
d03ab969 2290{
c65df279 2291 pquis(fp, "Usage: $ [-k KEYRING] COMMAND [ARGS]\n");
d03ab969 2292}
2293
2294void version(FILE *fp)
2295{
052b36d0 2296 pquis(fp, "$, Catacomb version " VERSION "\n");
d03ab969 2297}
2298
c65df279 2299void help_global(FILE *fp)
d03ab969 2300{
c65df279 2301 usage(fp);
2302 fputs("\n\
2303Performs various simple key management operations.\n\
2304\n\
2305Global command line options:\n\
d03ab969 2306\n\
c65df279 2307-h, --help [COMMAND...] Display this help text (or help for COMMANDs).\n\
d03ab969 2308-v, --version Display version number.\n\
2309-u, --usage Display short usage summary.\n\
2310\n\
c65df279 2311-k, --keyring=FILE Read and write keys in FILE.\n",
2312 fp);
d03ab969 2313}
2314
2315/* --- @main@ --- *
2316 *
2317 * Arguments: @int argc@ = number of command line arguments
2318 * @char *argv[]@ = array of command line arguments
2319 *
2320 * Returns: Nonzero on failure.
2321 *
2322 * Use: Main program. Performs simple key management functions.
2323 */
2324
2325int main(int argc, char *argv[])
2326{
2327 unsigned f = 0;
2328
16efd15b 2329#define f_bogus 1u
d03ab969 2330
2331 /* --- Initialization --- */
2332
2333 ego(argv[0]);
2334 sub_init();
2335
2336 /* --- Parse command line options --- */
2337
2338 for (;;) {
2339 static struct option opt[] = {
2340
2341 /* --- Standard GNUy help options --- */
2342
2343 { "help", 0, 0, 'h' },
2344 { "version", 0, 0, 'v' },
2345 { "usage", 0, 0, 'u' },
2346
2347 /* --- Real live useful options --- */
2348
2349 { "keyring", OPTF_ARGREQ, 0, 'k' },
2350
2351 /* --- Magic terminator --- */
2352
2353 { 0, 0, 0, 0 }
2354 };
99dde2f4 2355 int i = mdwopt(argc, argv, "+hvu k:", opt, 0, 0, 0);
d03ab969 2356
2357 if (i < 0)
2358 break;
2359 switch (i) {
2360
2361 /* --- GNU help options --- */
ce70ec47 2362
d03ab969 2363 case 'h':
c65df279 2364 sc_help(cmds, stdout, argv + optind);
d03ab969 2365 exit(0);
2366 case 'v':
2367 version(stdout);
2368 exit(0);
2369 case 'u':
2370 usage(stdout);
2371 exit(0);
2372
2373 /* --- Real useful options --- */
2374
2375 case 'k':
2376 keyfile = optarg;
2377 break;
2378
2379 /* --- Bogosity --- */
2380
2381 default:
2382 f |= f_bogus;
2383 break;
2384 }
2385 }
2386
2387 /* --- Complain about excessive bogons --- */
2388
2389 if (f & f_bogus || optind == argc) {
2390 usage(stderr);
2391 exit(1);
2392 }
2393
052b36d0 2394 /* --- Initialize the Catacomb random number generator --- */
2395
052b36d0 2396 rand_noisesrc(RAND_GLOBAL, &noise_source);
9219a5d6 2397 rand_seed(RAND_GLOBAL, 160);
052b36d0 2398
d03ab969 2399 /* --- Dispatch to appropriate command handler --- */
2400
2401 argc -= optind;
2402 argv += optind;
2403 optind = 0;
c65df279 2404 return (findcmd(cmds, argv[0])->cmd(argc, argv));
d03ab969 2405}
2406
2407/*----- That's all, folks -------------------------------------------------*/