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