move list.[hc] into lib-lib.
[apps/madmutt.git] / pgppubring.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1997-2001 Thomas Roessler <roessler@does-not-exist.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 /*
11  * This is a "simple" PGP key ring dumper.
12  * 
13  * The output format is supposed to be compatible to the one GnuPG
14  * emits and Mutt expects.
15  * 
16  * Note that the code of this program could be considerably less
17  * complex, but most of it was taken from mutt's second generation
18  * key ring parser.
19  * 
20  * You can actually use this to put together some fairly general
21  * PGP key management applications.
22  *
23  */
24
25 #if HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <lib-lib/mem.h>
30 #include <lib-lib/str.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <time.h>
37 #ifdef HAVE_GETOPT_H
38 # include <getopt.h>
39 #else
40 extern char *optarg;
41 extern int optind;
42 #endif
43 #include <errno.h>
44
45 short Umask;   /* dirty hack because we need Umask in lib.c but don't want globals.h there */
46
47 #include "sha1.h"
48 #include "md5.h"
49 #include "lib.h"
50 #include "pgplib.h"
51 #include "pgppacket.h"
52
53 #define MD5_DIGEST_LENGTH  16
54
55 #ifdef HAVE_FGETPOS
56 #define FGETPOS(fp,pos) fgetpos((fp),&(pos))
57 #define FSETPOS(fp,pos) fsetpos((fp),&(pos))
58 #else
59 #define FGETPOS(fp,pos) pos=ftello((fp));
60 #define FSETPOS(fp,pos) fseeko((fp),(pos),SEEK_SET)
61 #endif
62
63
64 static short dump_signatures = 0;
65 static short dump_fingerprints = 0;
66
67
68 static void pgpring_find_candidates (char *ringfile, const char *hints[],
69                                      int nhints);
70 static void pgpring_dump_keyblock (pgp_key_t p);
71
72 int main (int argc, char *const argv[])
73 {
74   int c;
75
76   short version = 2;
77   short secring = 0;
78
79   const char *_kring = NULL;
80   char *env_pgppath, *env_home;
81
82   char pgppath[_POSIX_PATH_MAX];
83   char kring[_POSIX_PATH_MAX];
84
85   while ((c = getopt (argc, argv, "f25sk:S")) != EOF) {
86     switch (c) {
87     case 'S':
88       {
89         dump_signatures = 1;
90         break;
91       }
92
93     case 'f':
94       {
95         dump_fingerprints = 1;
96         break;
97       }
98
99     case 'k':
100       {
101         _kring = optarg;
102         break;
103       }
104
105     case '2':
106     case '5':
107       {
108         version = c - '0';
109         break;
110       }
111
112     case 's':
113       {
114         secring = 1;
115         break;
116       }
117
118     default:
119       {
120         fprintf (stderr,
121                  "usage: %s [-k <key ring> | [-2 | -5] [ -s] [-S] [-f]] [hints]\n",
122                  argv[0]);
123         exit (1);
124       }
125     }
126   }
127
128   if (_kring)
129     strfcpy (kring, _kring, sizeof (kring));
130   else {
131     if ((env_pgppath = getenv ("PGPPATH")))
132       strfcpy (pgppath, env_pgppath, sizeof (pgppath));
133     else if ((env_home = getenv ("HOME")))
134       snprintf (pgppath, sizeof (pgppath), "%s/.pgp", env_home);
135     else {
136       fprintf (stderr, "%s: Can't determine your PGPPATH.\n", argv[0]);
137       exit (1);
138     }
139
140     if (secring)
141       snprintf (kring, sizeof (kring), "%s/secring.%s", pgppath,
142                 version == 2 ? "pgp" : "skr");
143     else
144       snprintf (kring, sizeof (kring), "%s/pubring.%s", pgppath,
145                 version == 2 ? "pgp" : "pkr");
146   }
147
148   pgpring_find_candidates (kring, (const char **) argv + optind,
149                            argc - optind);
150
151   return 0;
152 }
153
154
155 /* The actual key ring parser */
156
157 static void pgp_make_pgp2_fingerprint (unsigned char *buff,
158                                        unsigned char *digest)
159 {
160
161   MD5_CTX context;
162   unsigned int size = 0;
163
164
165   MD5Init (&context);
166
167   size = (buff[0] << 8) + buff[1];
168   size = ((size + 7) / 8);
169   buff = &buff[2];
170
171   MD5Update (&context, buff, size);
172   buff = &buff[size];
173
174   size = (buff[0] << 8) + buff[1];
175   size = ((size + 7) / 8);
176   buff = &buff[2];
177
178   MD5Update (&context, buff, size);
179
180   MD5Final (digest, &context);
181
182 }                               /* pgp_make_pgp2_fingerprint() */
183
184 static pgp_key_t pgp_parse_pgp2_key (unsigned char *buff, size_t l)
185 {
186   pgp_key_t p;
187   unsigned char alg;
188   unsigned char digest[MD5_DIGEST_LENGTH];
189   size_t expl;
190   unsigned long id;
191   time_t gen_time = 0;
192   unsigned short exp_days = 0;
193   size_t j;
194   int i, k;
195   unsigned char scratch[LONG_STRING];
196
197   if (l < 12)
198     return NULL;
199
200   p = pgp_new_keyinfo ();
201
202   for (i = 0, j = 2; i < 4; i++)
203     gen_time = (gen_time << 8) + buff[j++];
204
205   p->gen_time = gen_time;
206
207   for (i = 0; i < 2; i++)
208     exp_days = (exp_days << 8) + buff[j++];
209
210   if (exp_days && time (NULL) > gen_time + exp_days * 24 * 3600)
211     p->flags |= KEYFLAG_EXPIRED;
212
213   alg = buff[j++];
214
215   p->numalg = alg;
216   p->algorithm = pgp_pkalgbytype (alg);
217   p->flags |= pgp_get_abilities (alg);
218
219   if (dump_fingerprints) {
220     /* j now points to the key material, which we need for the fingerprint */
221     p->fp_len = MD5_DIGEST_LENGTH;
222     pgp_make_pgp2_fingerprint (&buff[j], digest);
223     memcpy (p->fingerprint, digest, MD5_DIGEST_LENGTH);
224   }
225   else                          /* just to be usre */
226     p_clear(p->fingerprint, MD5_DIGEST_LENGTH);
227
228   expl = 0;
229   for (i = 0; i < 2; i++)
230     expl = (expl << 8) + buff[j++];
231
232   p->keylen = expl;
233
234   expl = (expl + 7) / 8;
235   if (expl < 4)
236     goto bailout;
237
238
239   j += expl - 8;
240
241   for (k = 0; k < 2; k++) {
242     for (id = 0, i = 0; i < 4; i++)
243       id = (id << 8) + buff[j++];
244
245     snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8,
246               "%08lX", id);
247   }
248
249   p->keyid = m_strdup((char *) scratch);
250
251   return p;
252
253 bailout:
254
255   p_delete(&p);
256   return NULL;
257 }
258
259 static void pgp_make_pgp3_fingerprint (unsigned char *buff, size_t l,
260                                        unsigned char *digest)
261 {
262   unsigned char dummy;
263   SHA1_CTX context;
264
265   SHA1_Init (&context);
266
267   dummy = buff[0] & 0x3f;
268
269   if (dummy == PT_SUBSECKEY || dummy == PT_SUBKEY || dummy == PT_SECKEY)
270     dummy = PT_PUBKEY;
271
272   dummy = (dummy << 2) | 0x81;
273   SHA1_Update (&context, &dummy, 1);
274   dummy = ((l - 1) >> 8) & 0xff;
275   SHA1_Update (&context, &dummy, 1);
276   dummy = (l - 1) & 0xff;
277   SHA1_Update (&context, &dummy, 1);
278   SHA1_Update (&context, buff + 1, l - 1);
279   SHA1_Final (digest, &context);
280
281 }
282
283 static void skip_bignum (unsigned char *buff, size_t l, size_t j,
284                          size_t * toff, size_t n)
285 {
286   size_t len;
287
288   do {
289     len = (buff[j] << 8) + buff[j + 1];
290     j += (len + 7) / 8 + 2;
291   }
292   while (j <= l && --n > 0);
293
294   if (toff)
295     *toff = j;
296 }
297
298
299 static pgp_key_t pgp_parse_pgp3_key (unsigned char *buff, size_t l)
300 {
301   pgp_key_t p;
302   unsigned char alg;
303   unsigned char digest[SHA_DIGEST_LENGTH];
304   unsigned char scratch[LONG_STRING];
305   time_t gen_time = 0;
306   unsigned long id;
307   int i, k;
308   short len;
309   size_t j;
310
311   p = pgp_new_keyinfo ();
312   j = 2;
313
314   for (i = 0; i < 4; i++)
315     gen_time = (gen_time << 8) + buff[j++];
316
317   p->gen_time = gen_time;
318
319   alg = buff[j++];
320
321   p->numalg = alg;
322   p->algorithm = pgp_pkalgbytype (alg);
323   p->flags |= pgp_get_abilities (alg);
324
325   if (alg == 17)
326     skip_bignum (buff, l, j, &j, 3);
327   else if (alg == 16 || alg == 20)
328     skip_bignum (buff, l, j, &j, 2);
329
330   len = (buff[j] << 8) + buff[j + 1];
331   p->keylen = len;
332
333
334   if (alg >= 1 && alg <= 3)
335     skip_bignum (buff, l, j, &j, 2);
336   else if (alg == 17 || alg == 16 || alg == 20)
337     skip_bignum (buff, l, j, &j, 1);
338
339   pgp_make_pgp3_fingerprint (buff, j, digest);
340   p->fp_len = SHA_DIGEST_LENGTH;
341
342   for (k = 0; k < 2; k++) {
343     for (id = 0, i = SHA_DIGEST_LENGTH - 8 + k * 4;
344          i < SHA_DIGEST_LENGTH + (k - 1) * 4; i++)
345       id = (id << 8) + digest[i];
346
347     snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8, "%08lX",
348               id);
349   }
350
351   p->keyid = m_strdup((char *) scratch);
352
353   return p;
354 }
355
356 static pgp_key_t pgp_parse_keyinfo (unsigned char *buff, size_t l)
357 {
358   if (!buff || l < 2)
359     return NULL;
360
361   switch (buff[1]) {
362   case 2:
363   case 3:
364     return pgp_parse_pgp2_key (buff, l);
365   case 4:
366     return pgp_parse_pgp3_key (buff, l);
367   default:
368     return NULL;
369   }
370 }
371
372 static int pgp_parse_pgp2_sig (unsigned char *buff, size_t l,
373                                pgp_key_t p, pgp_sig_t * s)
374 {
375   unsigned char sigtype;
376   time_t sig_gen_time;
377   unsigned long signerid1;
378   unsigned long signerid2;
379   size_t j;
380   int i;
381
382   if (l < 22)
383     return -1;
384
385   j = 3;
386   sigtype = buff[j++];
387
388   sig_gen_time = 0;
389   for (i = 0; i < 4; i++)
390     sig_gen_time = (sig_gen_time << 8) + buff[j++];
391
392   signerid1 = signerid2 = 0;
393   for (i = 0; i < 4; i++)
394     signerid1 = (signerid1 << 8) + buff[j++];
395
396   for (i = 0; i < 4; i++)
397     signerid2 = (signerid2 << 8) + buff[j++];
398
399
400   if (sigtype == 0x20 || sigtype == 0x28)
401     p->flags |= KEYFLAG_REVOKED;
402
403   if (s) {
404     s->sigtype = sigtype;
405     s->sid1 = signerid1;
406     s->sid2 = signerid2;
407   }
408
409   return 0;
410 }
411
412 static int pgp_parse_pgp3_sig (unsigned char *buff, size_t l,
413                                pgp_key_t p, pgp_sig_t * s)
414 {
415   unsigned char sigtype;
416   unsigned char pkalg;
417   unsigned char hashalg;
418   unsigned char skt;
419   time_t sig_gen_time = -1;
420   long validity = -1;
421   long key_validity = -1;
422   unsigned long signerid1 = 0;
423   unsigned long signerid2 = 0;
424   size_t ml;
425   size_t j;
426   int i;
427   short ii;
428   short have_critical_spks = 0;
429
430   if (l < 7)
431     return -1;
432
433   j = 2;
434
435   sigtype = buff[j++];
436   pkalg = buff[j++];
437   hashalg = buff[j++];
438
439   for (ii = 0; ii < 2; ii++) {
440     size_t skl;
441     size_t nextone;
442
443     ml = (buff[j] << 8) + buff[j + 1];
444     j += 2;
445
446     if (j + ml > l)
447       break;
448
449     nextone = j;
450     while (ml) {
451       j = nextone;
452       skl = buff[j++];
453       if (!--ml)
454         break;
455
456       if (skl >= 192) {
457         skl = (skl - 192) * 256 + buff[j++] + 192;
458         if (!--ml)
459           break;
460       }
461
462       if ((int) ml - (int) skl < 0)
463         break;
464       ml -= skl;
465
466       nextone = j + skl;
467       skt = buff[j++];
468
469       switch (skt & 0x7f) {
470       case 2:                  /* creation time */
471         {
472           if (skl < 4)
473             break;
474           sig_gen_time = 0;
475           for (i = 0; i < 4; i++)
476             sig_gen_time = (sig_gen_time << 8) + buff[j++];
477
478           break;
479         }
480       case 3:                  /* expiration time */
481         {
482           if (skl < 4)
483             break;
484           validity = 0;
485           for (i = 0; i < 4; i++)
486             validity = (validity << 8) + buff[j++];
487           break;
488         }
489       case 9:                  /* key expiration time */
490         {
491           if (skl < 4)
492             break;
493           key_validity = 0;
494           for (i = 0; i < 4; i++)
495             key_validity = (key_validity << 8) + buff[j++];
496           break;
497         }
498       case 16:                 /* issuer key ID */
499         {
500           if (skl < 8)
501             break;
502           signerid2 = signerid1 = 0;
503           for (i = 0; i < 4; i++)
504             signerid1 = (signerid1 << 8) + buff[j++];
505           for (i = 0; i < 4; i++)
506             signerid2 = (signerid2 << 8) + buff[j++];
507
508           break;
509         }
510       case 10:                 /* CMR key */
511         break;
512       case 4:                  /* exportable */
513       case 5:                  /* trust */
514       case 6:                  /* regexp */
515       case 7:                  /* revocable */
516       case 11:                 /* Pref. symm. alg. */
517       case 12:                 /* revocation key */
518       case 20:                 /* notation data */
519       case 21:                 /* pref. hash */
520       case 22:                 /* pref. comp.alg. */
521       case 23:                 /* key server prefs. */
522       case 24:                 /* pref. key server */
523       default:
524         {
525           if (skt & 0x80)
526             have_critical_spks = 1;
527         }
528       }
529     }
530     j = nextone;
531   }
532
533   if (sigtype == 0x20 || sigtype == 0x28)
534     p->flags |= KEYFLAG_REVOKED;
535   if (key_validity != -1 && time (NULL) > p->gen_time + key_validity)
536     p->flags |= KEYFLAG_EXPIRED;
537   if (have_critical_spks)
538     p->flags |= KEYFLAG_CRITICAL;
539
540   if (s) {
541     s->sigtype = sigtype;
542     s->sid1 = signerid1;
543     s->sid2 = signerid2;
544   }
545
546
547   return 0;
548
549 }
550
551
552 static int pgp_parse_sig (unsigned char *buff, size_t l,
553                           pgp_key_t p, pgp_sig_t * sig)
554 {
555   if (!buff || l < 2 || !p)
556     return -1;
557
558   switch (buff[1]) {
559   case 2:
560   case 3:
561     return pgp_parse_pgp2_sig (buff, l, p, sig);
562   case 4:
563     return pgp_parse_pgp3_sig (buff, l, p, sig);
564   default:
565     return -1;
566   }
567 }
568
569 /* parse one key block, including all subkeys. */
570
571 static pgp_key_t pgp_parse_keyblock (FILE * fp)
572 {
573   unsigned char *buff;
574   unsigned char pt = 0;
575   unsigned char last_pt;
576   size_t l;
577   short err = 0;
578
579 #ifdef HAVE_FGETPOS
580   fpos_t pos;
581 #else
582   off_t pos;
583 #endif
584
585   pgp_key_t root = NULL;
586   pgp_key_t *last = &root;
587   pgp_key_t p = NULL;
588   pgp_uid_t *uid = NULL;
589   pgp_uid_t **addr = NULL;
590   pgp_sig_t **lsig = NULL;
591
592   FGETPOS (fp, pos);
593
594   while (!err && (buff = pgp_read_packet (fp, &l)) != NULL) {
595     last_pt = pt;
596     pt = buff[0] & 0x3f;
597
598     /* check if we have read the complete key block. */
599
600     if ((pt == PT_SECKEY || pt == PT_PUBKEY) && root) {
601       FSETPOS (fp, pos);
602       return root;
603     }
604
605     switch (pt) {
606     case PT_SECKEY:
607     case PT_PUBKEY:
608     case PT_SUBKEY:
609     case PT_SUBSECKEY:
610       {
611         if (!(*last = p = pgp_parse_keyinfo (buff, l))) {
612           err = 1;
613           break;
614         }
615
616         last = &p->next;
617         addr = &p->address;
618         lsig = &p->sigs;
619
620         if (pt == PT_SUBKEY || pt == PT_SUBSECKEY) {
621           p->flags |= KEYFLAG_SUBKEY;
622           if (p != root) {
623             p->parent = root;
624             p->address = pgp_copy_uids (root->address, p);
625             while (*addr)
626               addr = &(*addr)->next;
627           }
628         }
629
630         if (pt == PT_SECKEY || pt == PT_SUBSECKEY)
631           p->flags |= KEYFLAG_SECRET;
632
633         break;
634       }
635
636     case PT_SIG:
637       {
638         if (lsig) {
639           pgp_sig_t *signature = p_new(pgp_sig_t, 1);
640
641           *lsig = signature;
642           lsig = &signature->next;
643
644           pgp_parse_sig (buff, l, p, signature);
645         }
646         break;
647       }
648
649     case PT_TRUST:
650       {
651         if (p && (last_pt == PT_SECKEY || last_pt == PT_PUBKEY ||
652                   last_pt == PT_SUBKEY || last_pt == PT_SUBSECKEY)) {
653           if (buff[1] & 0x20) {
654             p->flags |= KEYFLAG_DISABLED;
655           }
656         }
657         else if (last_pt == PT_NAME && uid) {
658           uid->trust = buff[1];
659         }
660         break;
661       }
662     case PT_NAME:
663       {
664         char *chr;
665
666
667         if (!addr)
668           break;
669
670         chr = p_dupstr(buff + 1, l - 1);
671
672         *addr = uid = p_new(pgp_uid_t, 1);      /* XXX */
673         uid->addr = chr;
674         uid->parent = p;
675         uid->trust = 0;
676         addr = &uid->next;
677         lsig = &uid->sigs;
678
679         /* the following tags are generated by
680          * pgp 2.6.3in.
681          */
682
683         if (strstr (chr, "ENCR"))
684           p->flags |= KEYFLAG_PREFER_ENCRYPTION;
685         if (strstr (chr, "SIGN"))
686           p->flags |= KEYFLAG_PREFER_SIGNING;
687
688         break;
689       }
690     }
691
692     FGETPOS (fp, pos);
693   }
694
695   if (err)
696     pgp_free_key (&root);
697
698   return root;
699 }
700
701 static int pgpring_string_matches_hint (const char *s, const char *hints[],
702                                         int nhints)
703 {
704   int i;
705
706   if (!hints || !nhints)
707     return 1;
708
709   for (i = 0; i < nhints; i++) {
710     if (str_isstr (s, hints[i]) != NULL)
711       return 1;
712   }
713
714   return 0;
715 }
716
717 /* 
718  * Go through the key ring file and look for keys with
719  * matching IDs.
720  */
721
722 static void pgpring_find_candidates (char *ringfile, const char *hints[],
723                                      int nhints)
724 {
725   FILE *rfp;
726
727 #ifdef HAVE_FGETPOS
728   fpos_t pos, keypos;
729 #else
730   off_t pos, keypos;
731 #endif
732
733   unsigned char *buff = NULL;
734   unsigned char pt = 0;
735   size_t l = 0;
736
737   short err = 0;
738
739   if ((rfp = fopen (ringfile, "r")) == NULL) {
740     char *error_buf;
741     size_t error_buf_len;
742
743     error_buf_len = sizeof ("fopen: ") - 1 + m_strlen(ringfile) + 1;
744     error_buf = p_new(char, error_buf_len);
745     snprintf (error_buf, error_buf_len, "fopen: %s", ringfile);
746     perror (error_buf);
747     p_delete(&error_buf);
748     return;
749   }
750
751   FGETPOS (rfp, pos);
752   FGETPOS (rfp, keypos);
753
754   while (!err && (buff = pgp_read_packet (rfp, &l)) != NULL) {
755     pt = buff[0] & 0x3f;
756
757     if (l < 1)
758       continue;
759
760     if ((pt == PT_SECKEY) || (pt == PT_PUBKEY)) {
761       keypos = pos;
762     }
763     else if (pt == PT_NAME) {
764       char *tmp = p_dupstr(buff + 1, l - 1);
765
766       /* mutt_decode_utf8_string (tmp, chs); */
767
768       if (pgpring_string_matches_hint (tmp, hints, nhints)) {
769         pgp_key_t p;
770
771         FSETPOS (rfp, keypos);
772
773         /* Not bailing out here would lead us into an endless loop. */
774
775         if ((p = pgp_parse_keyblock (rfp)) == NULL)
776           err = 1;
777
778         pgpring_dump_keyblock (p);
779         pgp_free_key (&p);
780       }
781
782       p_delete(&tmp);
783     }
784
785     FGETPOS (rfp, pos);
786   }
787
788   fclose (rfp);
789
790 }
791
792 static void print_userid (const char *id)
793 {
794   for (; id && *id; id++) {
795     if (*id >= ' ' && *id <= 'z' && *id != ':')
796       putchar (*id);
797     else
798       printf ("\\x%02x", (*id) & 0xff);
799   }
800 }
801
802 static void print_fingerprint (pgp_key_t p)
803 {
804   int i = 0;
805
806   printf ("fpr:::::::::");
807   for (i = 0; i < p->fp_len; i++)
808     printf ("%02X", p->fingerprint[i]);
809   printf (":\n");
810
811 }                               /* print_fingerprint() */
812
813
814 static void pgpring_dump_signatures (pgp_sig_t * sig)
815 {
816   for (; sig; sig = sig->next) {
817     if (sig->sigtype == 0x10 || sig->sigtype == 0x11 ||
818         sig->sigtype == 0x12 || sig->sigtype == 0x13)
819       printf ("sig::::%08lX%08lX::::::%X:\n",
820               sig->sid1, sig->sid2, sig->sigtype);
821     else if (sig->sigtype == 0x20)
822       printf ("rev::::%08lX%08lX::::::%X:\n",
823               sig->sid1, sig->sid2, sig->sigtype);
824   }
825 }
826
827
828 static char gnupg_trustletter (int t)
829 {
830   switch (t) {
831   case 1:
832     return 'n';
833   case 2:
834     return 'm';
835   case 3:
836     return 'f';
837   }
838   return 'q';
839 }
840
841 static void pgpring_dump_keyblock (pgp_key_t p)
842 {
843   pgp_uid_t *uid;
844   short first;
845   struct tm *tp;
846   time_t t;
847
848   for (; p; p = p->next) {
849     first = 1;
850
851     if (p->flags & KEYFLAG_SECRET) {
852       if (p->flags & KEYFLAG_SUBKEY)
853         printf ("ssb:");
854       else
855         printf ("sec:");
856     }
857     else {
858       if (p->flags & KEYFLAG_SUBKEY)
859         printf ("sub:");
860       else
861         printf ("pub:");
862     }
863
864     if (p->flags & KEYFLAG_REVOKED)
865       putchar ('r');
866     if (p->flags & KEYFLAG_EXPIRED)
867       putchar ('e');
868     if (p->flags & KEYFLAG_DISABLED)
869       putchar ('d');
870
871     for (uid = p->address; uid; uid = uid->next, first = 0) {
872       if (!first) {
873         printf ("uid:%c::::::::", gnupg_trustletter (uid->trust));
874         print_userid (uid->addr);
875         printf (":\n");
876       }
877       else {
878         if (p->flags & KEYFLAG_SECRET)
879           putchar ('u');
880         else
881           putchar (gnupg_trustletter (uid->trust));
882
883         t = p->gen_time;
884         tp = gmtime (&t);
885
886         printf (":%d:%d:%s:%04d-%02d-%02d::::", p->keylen, p->numalg,
887                 p->keyid, 1900 + tp->tm_year, tp->tm_mon + 1, tp->tm_mday);
888
889         print_userid (uid->addr);
890         printf ("::");
891
892         if (pgp_canencrypt (p->numalg))
893           putchar ('e');
894         if (pgp_cansign (p->numalg))
895           putchar ('s');
896         if (p->flags & KEYFLAG_DISABLED)
897           putchar ('D');
898         printf (":\n");
899
900         if (dump_fingerprints)
901           print_fingerprint (p);
902       }
903
904       if (dump_signatures) {
905         if (first)
906           pgpring_dump_signatures (p->sigs);
907         pgpring_dump_signatures (uid->sigs);
908       }
909     }
910   }
911 }
912
913 /*
914  * The mutt_gettext () defined in gettext.c requires iconv,
915  * so we do without charset conversion here.
916  */
917
918 char *mutt_gettext (const char *message)
919 {
920   return (char *) message;
921 }