2 * Copyright (C) 1997-2001 Thomas Roessler <roessler@does-not-exist.org>
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
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
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.
23 * This is a "simple" PGP key ring dumper.
25 * The output format is supposed to be compatible to the one GnuPG
26 * emits and Mutt expects.
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
32 * You can actually use this to put together some fairly general
33 * PGP key management applications.
55 #include "pgppacket.h"
59 #define FGETPOS(fp,pos) fgetpos((fp),&(pos))
60 #define FSETPOS(fp,pos) fsetpos((fp),&(pos))
62 #define FGETPOS(fp,pos) pos=ftell((fp));
63 #define FSETPOS(fp,pos) fseek((fp),(pos),SEEK_SET)
67 static short dump_signatures
= 0;
70 static void pgpring_find_candidates (char *ringfile
, const char *hints
[], int nhints
);
71 static void pgpring_dump_keyblock (pgp_key_t
*p
);
73 int main (int argc
, char * const argv
[])
80 const char *_kring
= NULL
;
81 char *env_pgppath
, *env_home
;
83 char pgppath
[_POSIX_PATH_MAX
];
84 char kring
[_POSIX_PATH_MAX
];
86 while ((c
= getopt (argc
, argv
, "25sk:S")) != EOF
)
116 fprintf (stderr
, "usage: %s [-k <key ring> | [-2 | -5] [ -s]] [hints]\n",
124 strfcpy (kring
, _kring
, sizeof (kring
));
127 if ((env_pgppath
= getenv ("PGPPATH")))
128 strfcpy (pgppath
, env_pgppath
, sizeof (pgppath
));
129 else if ((env_home
= getenv ("HOME")))
130 snprintf (pgppath
, sizeof (pgppath
), "%s/.pgp", env_home
);
133 fprintf (stderr
, "%s: Can't determine your PGPPATH.\n", argv
[0]);
138 snprintf (kring
, sizeof (kring
), "%s/secring.%s", pgppath
, version
== 2 ? "pgp" : "skr");
140 snprintf (kring
, sizeof (kring
), "%s/pubring.%s", pgppath
, version
== 2 ? "pgp" : "pkr");
143 pgpring_find_candidates (kring
, (const char**) argv
+ optind
, argc
- optind
);
149 /* The actual key ring parser */
151 static pgp_key_t
*pgp_parse_pgp2_key (unsigned char *buff
, size_t l
)
158 unsigned short exp_days
= 0;
161 unsigned char scratch
[LONG_STRING
];
166 p
= pgp_new_keyinfo();
168 for (i
= 0, j
= 2; i
< 4; i
++)
169 gen_time
= (gen_time
<< 8) + buff
[j
++];
171 p
->gen_time
= gen_time
;
173 for (i
= 0; i
< 2; i
++)
174 exp_days
= (exp_days
<< 8) + buff
[j
++];
176 if (exp_days
&& time (NULL
) > gen_time
+ exp_days
* 24 * 3600)
177 p
->flags
|= KEYFLAG_EXPIRED
;
182 p
->algorithm
= pgp_pkalgbytype (alg
);
183 p
->flags
|= pgp_get_abilities (alg
);
186 for (i
= 0; i
< 2; i
++)
187 expl
= (expl
<< 8) + buff
[j
++];
191 expl
= (expl
+ 7) / 8;
198 for (k
= 0; k
< 2; k
++)
200 for (id
= 0, i
= 0; i
< 4; i
++)
201 id
= (id
<< 8) + buff
[j
++];
203 snprintf ((char *) scratch
+ k
* 8, sizeof (scratch
) - k
* 8,
207 p
->keyid
= safe_strdup ((char *) scratch
);
213 safe_free ((void *)&p
);
217 static void pgp_make_pgp3_fingerprint (unsigned char *buff
, size_t l
,
218 unsigned char *digest
)
223 SHA1_Init (&context
);
225 dummy
= buff
[0] & 0x3f;
227 if (dummy
== PT_SUBSECKEY
|| dummy
== PT_SUBKEY
|| dummy
== PT_SECKEY
)
230 dummy
= (dummy
<< 2) | 0x81;
231 SHA1_Update (&context
, &dummy
, 1);
232 dummy
= ((l
- 1) >> 8) & 0xff;
233 SHA1_Update (&context
, &dummy
, 1);
234 dummy
= (l
- 1) & 0xff;
235 SHA1_Update (&context
, &dummy
, 1);
236 SHA1_Update (&context
, buff
+ 1, l
- 1);
237 SHA1_Final (digest
, &context
);
241 static void skip_bignum (unsigned char *buff
, size_t l
, size_t j
,
242 size_t * toff
, size_t n
)
248 len
= (buff
[j
] << 8) + buff
[j
+ 1];
249 j
+= (len
+ 7) / 8 + 2;
251 while (j
<= l
&& --n
> 0);
258 static pgp_key_t
*pgp_parse_pgp3_key (unsigned char *buff
, size_t l
)
262 unsigned char digest
[SHA_DIGEST_LENGTH
];
263 unsigned char scratch
[LONG_STRING
];
270 p
= pgp_new_keyinfo ();
273 for (i
= 0; i
< 4; i
++)
274 gen_time
= (gen_time
<< 8) + buff
[j
++];
276 p
->gen_time
= gen_time
;
281 p
->algorithm
= pgp_pkalgbytype (alg
);
282 p
->flags
|= pgp_get_abilities (alg
);
285 skip_bignum (buff
, l
, j
, &j
, 3);
286 else if (alg
== 16 || alg
== 20)
287 skip_bignum (buff
, l
, j
, &j
, 2);
289 len
= (buff
[j
] << 8) + buff
[j
+ 1];
292 if (alg
>= 1 && alg
<= 3)
293 skip_bignum (buff
, l
, j
, &j
, 2);
294 else if (alg
== 17 || alg
== 16 || alg
== 20)
295 skip_bignum (buff
, l
, j
, &j
, 1);
297 pgp_make_pgp3_fingerprint (buff
, j
, digest
);
299 for (k
= 0; k
< 2; k
++)
301 for (id
= 0, i
= SHA_DIGEST_LENGTH
- 8 + k
* 4;
302 i
< SHA_DIGEST_LENGTH
+ (k
- 1) * 4; i
++)
303 id
= (id
<< 8) + digest
[i
];
305 snprintf ((char *) scratch
+ k
* 8, sizeof (scratch
) - k
* 8, "%08lX", id
);
308 p
->keyid
= safe_strdup ((char *) scratch
);
313 static pgp_key_t
*pgp_parse_keyinfo (unsigned char *buff
, size_t l
)
322 return pgp_parse_pgp2_key (buff
, l
);
324 return pgp_parse_pgp3_key (buff
, l
);
330 static int pgp_parse_pgp2_sig (unsigned char *buff
, size_t l
, pgp_key_t
* p
, pgp_sig_t
*s
)
332 unsigned char sigtype
;
334 unsigned long signerid1
;
335 unsigned long signerid2
;
346 for (i
= 0; i
< 4; i
++)
347 sig_gen_time
= (sig_gen_time
<< 8) + buff
[j
++];
349 signerid1
= signerid2
= 0;
350 for (i
= 0; i
< 4; i
++)
351 signerid1
= (signerid1
<< 8) + buff
[j
++];
353 for (i
= 0; i
< 4; i
++)
354 signerid2
= (signerid2
<< 8) + buff
[j
++];
357 if (sigtype
== 0x20 || sigtype
== 0x28)
358 p
->flags
|= KEYFLAG_REVOKED
;
362 s
->sigtype
= sigtype
;
370 static int pgp_parse_pgp3_sig (unsigned char *buff
, size_t l
, pgp_key_t
* p
, pgp_sig_t
*s
)
372 unsigned char sigtype
;
374 unsigned char hashalg
;
376 time_t sig_gen_time
= -1;
378 long key_validity
= -1;
379 unsigned long signerid1
= 0;
380 unsigned long signerid2
= 0;
385 short have_critical_spks
= 0;
396 for (ii
= 0; ii
< 2; ii
++)
401 ml
= (buff
[j
] << 8) + buff
[j
+ 1];
417 skl
= (skl
- 192) * 256 + buff
[j
++] + 192;
422 if ((int) ml
- (int) skl
< 0)
431 case 2: /* creation time */
436 for (i
= 0; i
< 4; i
++)
437 sig_gen_time
= (sig_gen_time
<< 8) + buff
[j
++];
441 case 3: /* expiration time */
446 for (i
= 0; i
< 4; i
++)
447 validity
= (validity
<< 8) + buff
[j
++];
450 case 9: /* key expiration time */
455 for (i
= 0; i
< 4; i
++)
456 key_validity
= (key_validity
<< 8) + buff
[j
++];
459 case 16: /* issuer key ID */
463 signerid2
= signerid1
= 0;
464 for (i
= 0; i
< 4; i
++)
465 signerid1
= (signerid1
<< 8) + buff
[j
++];
466 for (i
= 0; i
< 4; i
++)
467 signerid2
= (signerid2
<< 8) + buff
[j
++];
471 case 10: /* CMR key */
473 case 4: /* exportable */
476 case 7: /* revocable */
477 case 11: /* Pref. symm. alg. */
478 case 12: /* revocation key */
479 case 20: /* notation data */
480 case 21: /* pref. hash */
481 case 22: /* pref. comp.alg. */
482 case 23: /* key server prefs. */
483 case 24: /* pref. key server */
487 have_critical_spks
= 1;
494 if (sigtype
== 0x20 || sigtype
== 0x28)
495 p
->flags
|= KEYFLAG_REVOKED
;
496 if (key_validity
!= -1 && time (NULL
) > p
->gen_time
+ key_validity
)
497 p
->flags
|= KEYFLAG_EXPIRED
;
498 if (have_critical_spks
)
499 p
->flags
|= KEYFLAG_CRITICAL
;
503 s
->sigtype
= sigtype
;
514 static int pgp_parse_sig (unsigned char *buff
, size_t l
, pgp_key_t
* p
, pgp_sig_t
*sig
)
516 if (!buff
|| l
< 2 || !p
)
523 return pgp_parse_pgp2_sig (buff
, l
, p
, sig
);
525 return pgp_parse_pgp3_sig (buff
, l
, p
, sig
);
531 /* parse one key block, including all subkeys. */
533 static pgp_key_t
*pgp_parse_keyblock (FILE * fp
)
536 unsigned char pt
= 0;
537 unsigned char last_pt
;
547 pgp_key_t
*root
= NULL
;
548 pgp_key_t
**last
= &root
;
550 pgp_uid_t
*uid
= NULL
;
551 pgp_uid_t
**addr
= NULL
;
552 pgp_sig_t
**lsig
= NULL
;
556 while (!err
&& (buff
= pgp_read_packet (fp
, &l
)) != NULL
)
561 /* check if we have read the complete key block. */
563 if ((pt
== PT_SECKEY
|| pt
== PT_PUBKEY
) && root
)
576 if (!(*last
= p
= pgp_parse_keyinfo (buff
, l
)))
586 if (pt
== PT_SUBKEY
|| pt
== PT_SUBSECKEY
)
588 p
->flags
|= KEYFLAG_SUBKEY
;
592 p
->address
= pgp_copy_uids (root
->address
, p
);
593 while (*addr
) addr
= &(*addr
)->next
;
597 if (pt
== PT_SECKEY
|| pt
== PT_SUBSECKEY
)
598 p
->flags
|= KEYFLAG_SECRET
;
607 pgp_sig_t
*signature
= safe_calloc (sizeof (pgp_sig_t
), 1);
609 lsig
= &signature
->next
;
611 pgp_parse_sig (buff
, l
, p
, signature
);
618 if (p
&& (last_pt
== PT_SECKEY
|| last_pt
== PT_PUBKEY
||
619 last_pt
== PT_SUBKEY
|| last_pt
== PT_SUBSECKEY
))
623 p
->flags
|= KEYFLAG_DISABLED
;
626 else if (last_pt
== PT_NAME
&& uid
)
628 uid
->trust
= buff
[1];
640 chr
= safe_malloc (l
);
641 memcpy (chr
, buff
+ 1, l
- 1);
645 *addr
= uid
= safe_calloc (1, sizeof (pgp_uid_t
)); /* XXX */
652 /* the following tags are generated by
656 if (strstr (chr
, "ENCR"))
657 p
->flags
|= KEYFLAG_PREFER_ENCRYPTION
;
658 if (strstr (chr
, "SIGN"))
659 p
->flags
|= KEYFLAG_PREFER_SIGNING
;
669 pgp_free_key (&root
);
674 static int pgpring_string_matches_hint (const char *s
, const char *hints
[], int nhints
)
678 if (!hints
|| !nhints
)
681 for (i
= 0; i
< nhints
; i
++)
683 if (mutt_stristr (s
, hints
[i
]) != NULL
)
691 * Go through the key ring file and look for keys with
695 static void pgpring_find_candidates (char *ringfile
, const char *hints
[], int nhints
)
704 unsigned char *buff
= NULL
;
705 unsigned char pt
= 0;
710 if ((rfp
= fopen (ringfile
, "r")) == NULL
)
719 while (!err
&& (buff
= pgp_read_packet (rfp
, &l
)) != NULL
)
726 if ((pt
== PT_SECKEY
) || (pt
== PT_PUBKEY
))
730 else if (pt
== PT_NAME
)
732 char *tmp
= safe_malloc (l
);
734 memcpy (tmp
, buff
+ 1, l
- 1);
737 /* mutt_decode_utf8_string (tmp, chs); */
739 if (pgpring_string_matches_hint (tmp
, hints
, nhints
))
743 FSETPOS(rfp
, keypos
);
745 /* Not bailing out here would lead us into an endless loop. */
747 if ((p
= pgp_parse_keyblock (rfp
)) == NULL
)
750 pgpring_dump_keyblock (p
);
764 static void print_userid (const char *id
)
766 for (; id
&& *id
; id
++)
768 if (*id
>= ' ' && *id
<= 'z' && *id
!= ':')
771 printf ("\\x%02x", *id
);
775 static void pgpring_dump_signatures (pgp_sig_t
*sig
)
777 for (; sig
; sig
= sig
->next
)
779 if (sig
->sigtype
== 0x10 || sig
->sigtype
== 0x11 ||
780 sig
->sigtype
== 0x12 || sig
->sigtype
== 0x13)
781 printf ("sig::::%08lX%08lX::::::%X:\n",
782 sig
->sid1
, sig
->sid2
, sig
->sigtype
);
783 else if (sig
->sigtype
== 0x20)
784 printf ("rev::::%08lX%08lX::::::%X:\n",
785 sig
->sid1
, sig
->sid2
, sig
->sigtype
);
790 static char gnupg_trustletter (int t
)
801 static void pgpring_dump_keyblock (pgp_key_t
*p
)
808 for (; p
; p
= p
->next
)
812 if (p
->flags
& KEYFLAG_SECRET
)
814 if (p
->flags
& KEYFLAG_SUBKEY
)
821 if (p
->flags
& KEYFLAG_SUBKEY
)
827 if (p
->flags
& KEYFLAG_REVOKED
)
829 if (p
->flags
& KEYFLAG_EXPIRED
)
831 if (p
->flags
& KEYFLAG_DISABLED
)
834 for (uid
= p
->address
; uid
; uid
= uid
->next
, first
= 0)
838 printf ("uid:%c::::::::", gnupg_trustletter (uid
->trust
));
839 print_userid (uid
->addr
);
844 if (p
->flags
& KEYFLAG_SECRET
)
847 putchar (gnupg_trustletter (uid
->trust
));
852 printf (":%d:%d:%s:%04d-%02d-%02d::::", p
->keylen
, p
->numalg
, p
->keyid
,
853 1900 + tp
->tm_year
, tp
->tm_mon
+ 1, tp
->tm_mday
);
855 print_userid (uid
->addr
);
861 if (first
) pgpring_dump_signatures (p
->sigs
);
862 pgpring_dump_signatures (uid
->sigs
);
869 * The mutt_gettext () defined in gettext.c requires iconv,
870 * so we do without charset conversion here.
873 char *mutt_gettext (const char *message
)
875 return (char *)message
;