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