2 * Copyright notice from original mutt:
3 * Copyright (C) 1997-2001 Thomas Roessler <roessler@does-not-exist.org>
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.
11 * This is a "simple" PGP key ring dumper.
13 * The output format is supposed to be compatible to the one GnuPG
14 * emits and Mutt expects.
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
20 * You can actually use this to put together some fairly general
21 * PGP key management applications.
29 #include <lib-lib/lib-lib.h>
30 #include <lib-hash/hash.h>
45 short Umask; /* dirty hack because we need Umask in lib.c but don't want globals.h there */
48 #include <lib-crypt/pgplib.h>
49 #include <lib-crypt/pgppacket.h>
51 #define MD5_DIGEST_LENGTH 16
54 #define FGETPOS(fp,pos) fgetpos((fp),&(pos))
55 #define FSETPOS(fp,pos) fsetpos((fp),&(pos))
57 #define FGETPOS(fp,pos) pos=ftello((fp));
58 #define FSETPOS(fp,pos) fseeko((fp),(pos),SEEK_SET)
62 static short dump_signatures = 0;
63 static short dump_fingerprints = 0;
66 static void pgpring_find_candidates (char *ringfile, const char *hints[],
68 static void pgpring_dump_keyblock (pgp_key_t p);
70 int main (int argc, char *const argv[])
77 const char *_kring = NULL;
78 char *env_pgppath, *env_home;
80 char pgppath[_POSIX_PATH_MAX];
81 char kring[_POSIX_PATH_MAX];
83 while ((c = getopt (argc, argv, "f25sk:S")) != EOF) {
93 dump_fingerprints = 1;
119 "usage: %s [-k <key ring> | [-2 | -5] [ -s] [-S] [-f]] [hints]\n",
127 m_strcpy(kring, sizeof(kring), _kring);
129 if ((env_pgppath = getenv ("PGPPATH")))
130 m_strcpy(pgppath, sizeof(pgppath), env_pgppath);
131 else if ((env_home = getenv ("HOME")))
132 snprintf (pgppath, sizeof (pgppath), "%s/.pgp", env_home);
134 fprintf (stderr, "%s: Can't determine your PGPPATH.\n", argv[0]);
139 snprintf (kring, sizeof (kring), "%s/secring.%s", pgppath,
140 version == 2 ? "pgp" : "skr");
142 snprintf (kring, sizeof (kring), "%s/pubring.%s", pgppath,
143 version == 2 ? "pgp" : "pkr");
146 pgpring_find_candidates (kring, (const char **) argv + optind,
153 /* The actual key ring parser */
155 static void pgp_make_pgp2_fingerprint (unsigned char *buff,
156 unsigned char *digest)
160 unsigned int size = 0;
165 size = (buff[0] << 8) + buff[1];
166 size = ((size + 7) / 8);
169 MD5Update (&context, buff, size);
172 size = (buff[0] << 8) + buff[1];
173 size = ((size + 7) / 8);
176 MD5Update (&context, buff, size);
178 MD5Final (digest, &context);
180 } /* pgp_make_pgp2_fingerprint() */
182 static pgp_key_t pgp_parse_pgp2_key (unsigned char *buff, size_t l)
186 unsigned char digest[MD5_DIGEST_LENGTH];
190 unsigned short exp_days = 0;
193 unsigned char scratch[LONG_STRING];
198 p = pgp_new_keyinfo ();
200 for (i = 0, j = 2; i < 4; i++)
201 gen_time = (gen_time << 8) + buff[j++];
203 p->gen_time = gen_time;
205 for (i = 0; i < 2; i++)
206 exp_days = (exp_days << 8) + buff[j++];
208 if (exp_days && time (NULL) > gen_time + exp_days * 24 * 3600)
209 p->flags |= KEYFLAG_EXPIRED;
214 p->algorithm = pgp_pkalgbytype (alg);
215 p->flags |= pgp_get_abilities (alg);
217 if (dump_fingerprints) {
218 /* j now points to the key material, which we need for the fingerprint */
219 p->fp_len = MD5_DIGEST_LENGTH;
220 pgp_make_pgp2_fingerprint (&buff[j], digest);
221 memcpy (p->fingerprint, digest, MD5_DIGEST_LENGTH);
223 else /* just to be usre */
224 p_clear(p->fingerprint, MD5_DIGEST_LENGTH);
227 for (i = 0; i < 2; i++)
228 expl = (expl << 8) + buff[j++];
232 expl = (expl + 7) / 8;
239 for (k = 0; k < 2; k++) {
240 for (id = 0, i = 0; i < 4; i++)
241 id = (id << 8) + buff[j++];
243 snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8,
247 p->keyid = m_strdup((char *) scratch);
257 static void pgp_make_pgp3_fingerprint (unsigned char *buff, size_t l,
258 unsigned char *digest)
263 SHA1_Init (&context);
265 dummy = buff[0] & 0x3f;
267 if (dummy == PT_SUBSECKEY || dummy == PT_SUBKEY || dummy == PT_SECKEY)
270 dummy = (dummy << 2) | 0x81;
271 SHA1_Update (&context, &dummy, 1);
272 dummy = ((l - 1) >> 8) & 0xff;
273 SHA1_Update (&context, &dummy, 1);
274 dummy = (l - 1) & 0xff;
275 SHA1_Update (&context, &dummy, 1);
276 SHA1_Update (&context, buff + 1, l - 1);
277 SHA1_Final (digest, &context);
281 static void skip_bignum (unsigned char *buff, size_t l, size_t j,
282 size_t * toff, size_t n)
287 len = (buff[j] << 8) + buff[j + 1];
288 j += (len + 7) / 8 + 2;
290 while (j <= l && --n > 0);
297 static pgp_key_t pgp_parse_pgp3_key (unsigned char *buff, size_t l)
301 unsigned char digest[SHA_DIGEST_LENGTH];
302 unsigned char scratch[LONG_STRING];
309 p = pgp_new_keyinfo ();
312 for (i = 0; i < 4; i++)
313 gen_time = (gen_time << 8) + buff[j++];
315 p->gen_time = gen_time;
320 p->algorithm = pgp_pkalgbytype (alg);
321 p->flags |= pgp_get_abilities (alg);
324 skip_bignum (buff, l, j, &j, 3);
325 else if (alg == 16 || alg == 20)
326 skip_bignum (buff, l, j, &j, 2);
328 len = (buff[j] << 8) + buff[j + 1];
332 if (alg >= 1 && alg <= 3)
333 skip_bignum (buff, l, j, &j, 2);
334 else if (alg == 17 || alg == 16 || alg == 20)
335 skip_bignum (buff, l, j, &j, 1);
337 pgp_make_pgp3_fingerprint (buff, j, digest);
338 p->fp_len = SHA_DIGEST_LENGTH;
340 for (k = 0; k < 2; k++) {
341 for (id = 0, i = SHA_DIGEST_LENGTH - 8 + k * 4;
342 i < SHA_DIGEST_LENGTH + (k - 1) * 4; i++)
343 id = (id << 8) + digest[i];
345 snprintf ((char *) scratch + k * 8, sizeof (scratch) - k * 8, "%08lX",
349 p->keyid = m_strdup((char *) scratch);
354 static pgp_key_t pgp_parse_keyinfo (unsigned char *buff, size_t l)
362 return pgp_parse_pgp2_key (buff, l);
364 return pgp_parse_pgp3_key (buff, l);
370 static int pgp_parse_pgp2_sig (unsigned char *buff, size_t l,
371 pgp_key_t p, pgp_sig_t * s)
373 unsigned char sigtype;
375 unsigned long signerid1;
376 unsigned long signerid2;
387 for (i = 0; i < 4; i++)
388 sig_gen_time = (sig_gen_time << 8) + buff[j++];
390 signerid1 = signerid2 = 0;
391 for (i = 0; i < 4; i++)
392 signerid1 = (signerid1 << 8) + buff[j++];
394 for (i = 0; i < 4; i++)
395 signerid2 = (signerid2 << 8) + buff[j++];
398 if (sigtype == 0x20 || sigtype == 0x28)
399 p->flags |= KEYFLAG_REVOKED;
402 s->sigtype = sigtype;
410 static int pgp_parse_pgp3_sig (unsigned char *buff, size_t l,
411 pgp_key_t p, pgp_sig_t * s)
413 unsigned char sigtype;
415 unsigned char hashalg;
417 time_t sig_gen_time = -1;
419 long key_validity = -1;
420 unsigned long signerid1 = 0;
421 unsigned long signerid2 = 0;
426 short have_critical_spks = 0;
437 for (ii = 0; ii < 2; ii++) {
441 ml = (buff[j] << 8) + buff[j + 1];
455 skl = (skl - 192) * 256 + buff[j++] + 192;
460 if ((int) ml - (int) skl < 0)
467 switch (skt & 0x7f) {
468 case 2: /* creation time */
473 for (i = 0; i < 4; i++)
474 sig_gen_time = (sig_gen_time << 8) + buff[j++];
478 case 3: /* expiration time */
483 for (i = 0; i < 4; i++)
484 validity = (validity << 8) + buff[j++];
487 case 9: /* key expiration time */
492 for (i = 0; i < 4; i++)
493 key_validity = (key_validity << 8) + buff[j++];
496 case 16: /* issuer key ID */
500 signerid2 = signerid1 = 0;
501 for (i = 0; i < 4; i++)
502 signerid1 = (signerid1 << 8) + buff[j++];
503 for (i = 0; i < 4; i++)
504 signerid2 = (signerid2 << 8) + buff[j++];
508 case 10: /* CMR key */
510 case 4: /* exportable */
513 case 7: /* revocable */
514 case 11: /* Pref. symm. alg. */
515 case 12: /* revocation key */
516 case 20: /* notation data */
517 case 21: /* pref. hash */
518 case 22: /* pref. comp.alg. */
519 case 23: /* key server prefs. */
520 case 24: /* pref. key server */
524 have_critical_spks = 1;
531 if (sigtype == 0x20 || sigtype == 0x28)
532 p->flags |= KEYFLAG_REVOKED;
533 if (key_validity != -1 && time (NULL) > p->gen_time + key_validity)
534 p->flags |= KEYFLAG_EXPIRED;
535 if (have_critical_spks)
536 p->flags |= KEYFLAG_CRITICAL;
539 s->sigtype = sigtype;
550 static int pgp_parse_sig (unsigned char *buff, size_t l,
551 pgp_key_t p, pgp_sig_t * sig)
553 if (!buff || l < 2 || !p)
559 return pgp_parse_pgp2_sig (buff, l, p, sig);
561 return pgp_parse_pgp3_sig (buff, l, p, sig);
567 /* parse one key block, including all subkeys. */
569 static pgp_key_t pgp_parse_keyblock (FILE * fp)
572 unsigned char pt = 0;
573 unsigned char last_pt;
583 pgp_key_t root = NULL;
584 pgp_key_t *last = &root;
586 pgp_uid_t *uid = NULL;
587 pgp_uid_t **addr = NULL;
588 pgp_sig_t **lsig = NULL;
592 while (!err && (buff = pgp_read_packet (fp, &l)) != NULL) {
596 /* check if we have read the complete key block. */
598 if ((pt == PT_SECKEY || pt == PT_PUBKEY) && root) {
609 if (!(*last = p = pgp_parse_keyinfo (buff, l))) {
618 if (pt == PT_SUBKEY || pt == PT_SUBSECKEY) {
619 p->flags |= KEYFLAG_SUBKEY;
622 p->address = pgp_copy_uids (root->address, p);
624 addr = &(*addr)->next;
628 if (pt == PT_SECKEY || pt == PT_SUBSECKEY)
629 p->flags |= KEYFLAG_SECRET;
637 pgp_sig_t *signature = p_new(pgp_sig_t, 1);
640 lsig = &signature->next;
642 pgp_parse_sig (buff, l, p, signature);
649 if (p && (last_pt == PT_SECKEY || last_pt == PT_PUBKEY ||
650 last_pt == PT_SUBKEY || last_pt == PT_SUBSECKEY)) {
651 if (buff[1] & 0x20) {
652 p->flags |= KEYFLAG_DISABLED;
655 else if (last_pt == PT_NAME && uid) {
656 uid->trust = buff[1];
668 chr = p_dupstr(buff + 1, l - 1);
670 *addr = uid = p_new(pgp_uid_t, 1); /* XXX */
677 /* the following tags are generated by
681 if (strstr (chr, "ENCR"))
682 p->flags |= KEYFLAG_PREFER_ENCRYPTION;
683 if (strstr (chr, "SIGN"))
684 p->flags |= KEYFLAG_PREFER_SIGNING;
694 pgp_free_key (&root);
699 static int pgpring_string_matches_hint (const char *s, const char *hints[],
704 if (!hints || !nhints)
707 for (i = 0; i < nhints; i++) {
708 if (m_stristr(s, hints[i]) != NULL)
716 * Go through the key ring file and look for keys with
720 static void pgpring_find_candidates (char *ringfile, const char *hints[],
731 unsigned char *buff = NULL;
732 unsigned char pt = 0;
737 if ((rfp = fopen (ringfile, "r")) == NULL) {
739 size_t error_buf_len;
741 error_buf_len = sizeof ("fopen: ") - 1 + m_strlen(ringfile) + 1;
742 error_buf = p_new(char, error_buf_len);
743 snprintf (error_buf, error_buf_len, "fopen: %s", ringfile);
745 p_delete(&error_buf);
750 FGETPOS (rfp, keypos);
752 while (!err && (buff = pgp_read_packet (rfp, &l)) != NULL) {
758 if ((pt == PT_SECKEY) || (pt == PT_PUBKEY)) {
761 else if (pt == PT_NAME) {
762 char *tmp = p_dupstr(buff + 1, l - 1);
764 /* mutt_decode_utf8_string (tmp, chs); */
766 if (pgpring_string_matches_hint (tmp, hints, nhints)) {
769 FSETPOS (rfp, keypos);
771 /* Not bailing out here would lead us into an endless loop. */
773 if ((p = pgp_parse_keyblock (rfp)) == NULL)
776 pgpring_dump_keyblock (p);
790 static void print_userid (const char *id)
792 for (; id && *id; id++) {
793 if (*id >= ' ' && *id <= 'z' && *id != ':')
796 printf ("\\x%02x", (*id) & 0xff);
800 static void print_fingerprint (pgp_key_t p)
804 printf ("fpr:::::::::");
805 for (i = 0; i < p->fp_len; i++)
806 printf ("%02X", p->fingerprint[i]);
809 } /* print_fingerprint() */
812 static void pgpring_dump_signatures (pgp_sig_t * sig)
814 for (; sig; sig = sig->next) {
815 if (sig->sigtype == 0x10 || sig->sigtype == 0x11 ||
816 sig->sigtype == 0x12 || sig->sigtype == 0x13)
817 printf ("sig::::%08lX%08lX::::::%X:\n",
818 sig->sid1, sig->sid2, sig->sigtype);
819 else if (sig->sigtype == 0x20)
820 printf ("rev::::%08lX%08lX::::::%X:\n",
821 sig->sid1, sig->sid2, sig->sigtype);
826 static char gnupg_trustletter (int t)
839 static void pgpring_dump_keyblock (pgp_key_t p)
846 for (; p; p = p->next) {
849 if (p->flags & KEYFLAG_SECRET) {
850 if (p->flags & KEYFLAG_SUBKEY)
856 if (p->flags & KEYFLAG_SUBKEY)
862 if (p->flags & KEYFLAG_REVOKED)
864 if (p->flags & KEYFLAG_EXPIRED)
866 if (p->flags & KEYFLAG_DISABLED)
869 for (uid = p->address; uid; uid = uid->next, first = 0) {
871 printf ("uid:%c::::::::", gnupg_trustletter (uid->trust));
872 print_userid (uid->addr);
876 if (p->flags & KEYFLAG_SECRET)
879 putchar (gnupg_trustletter (uid->trust));
884 printf (":%d:%d:%s:%04d-%02d-%02d::::", p->keylen, p->numalg,
885 p->keyid, 1900 + tp->tm_year, tp->tm_mon + 1, tp->tm_mday);
887 print_userid (uid->addr);
890 if (pgp_canencrypt (p->numalg))
892 if (pgp_cansign (p->numalg))
894 if (p->flags & KEYFLAG_DISABLED)
898 if (dump_fingerprints)
899 print_fingerprint (p);
902 if (dump_signatures) {
904 pgpring_dump_signatures (p->sigs);
905 pgpring_dump_signatures (uid->sigs);
912 * The mutt_gettext () defined in gettext.c requires iconv,
913 * so we do without charset conversion here.
916 char *mutt_gettext (const char *message)
918 return (char *) message;