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