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