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