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