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