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