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