2 * Copyright (C) 1996-1997,2007 Michael R. Elkins <me@mutt.org>
3 * Copyright (c) 1998-2003 Thomas Roessler <roessler@does-not-exist.org>
5 * This program is free software; you can redistribute it
6 * and/or modify it under the terms of the GNU General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later
11 * This program is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
28 #include "mutt_curses.h"
29 #include "mutt_menu.h"
44 #ifdef CRYPT_BACKEND_CLASSIC_PGP
50 struct pgp_cache *next;
53 static struct pgp_cache *id_defaults = NULL;
55 static const char trust_flags[] = "?- +";
57 static char *pgp_key_abilities (int flags)
61 if (!(flags & KEYFLAG_CANENCRYPT))
63 else if (flags & KEYFLAG_PREFER_SIGNING)
68 if (!(flags & KEYFLAG_CANSIGN))
70 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
80 static char pgp_flags (int flags)
82 if (flags & KEYFLAG_REVOKED)
84 else if (flags & KEYFLAG_EXPIRED)
86 else if (flags & KEYFLAG_DISABLED)
88 else if (flags & KEYFLAG_CRITICAL)
94 static pgp_key_t pgp_principal_key (pgp_key_t key)
96 if (key->flags & KEYFLAG_SUBKEY && key->parent)
103 * Format an entry on the PGP key selection menu.
106 * %k key id %K key id of the principal key
108 * %a algorithm %A algorithm of the princ. key
109 * %l length %L length of the princ. key
110 * %f flags %F flags of the princ. key
111 * %c capabilities %C capabilities of the princ. key
112 * %t trust/validity of the key-uid association
113 * %[...] date of key using strftime(3)
116 typedef struct pgp_entry
122 static const char *pgp_entry_fmt (char *dest,
129 const char *ifstring,
130 const char *elsestring,
139 int optional = (flags & MUTT_FORMAT_OPTIONAL);
141 entry = (pgp_entry_t *) data;
144 pkey = pgp_principal_key (key);
146 if (isupper ((unsigned char) op))
149 kflags = key->flags | (pkey->flags & KEYFLAG_RESTRICTIONS)
152 switch (ascii_tolower (op))
158 char buf2[SHORT_STRING], *p;
175 while (len > 0 && *cp != ']')
187 break; /* not enough space */
199 tm = localtime (&key->gen_time);
202 setlocale (LC_TIME, "C");
203 strftime (buf2, sizeof (buf2), dest, tm);
205 setlocale (LC_TIME, "");
207 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
208 snprintf (dest, destlen, fmt, buf2);
216 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
217 snprintf (dest, destlen, fmt, entry->num);
223 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
224 snprintf (dest, destlen, fmt, _pgp_keyid (key));
230 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
231 snprintf (dest, destlen, fmt, NONULL (uid->addr));
237 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
238 snprintf (dest, destlen, fmt, key->algorithm);
244 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
245 snprintf (dest, destlen, fmt, key->keylen);
251 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
252 snprintf (dest, destlen, fmt, pgp_flags (kflags));
254 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
260 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
261 snprintf (dest, destlen, fmt, pgp_key_abilities (kflags));
263 else if (!(kflags & (KEYFLAG_ABILITIES)))
269 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
270 snprintf (dest, destlen, fmt, trust_flags[uid->trust & 0x03]);
272 else if (!(uid->trust & 0x03))
273 /* undefined trust */
281 mutt_FormatString (dest, destlen, col, cols, ifstring, mutt_attach_fmt, data, 0);
282 else if (flags & MUTT_FORMAT_OPTIONAL)
283 mutt_FormatString (dest, destlen, col, cols, elsestring, mutt_attach_fmt, data, 0);
287 static void pgp_entry (char *s, size_t l, MUTTMENU * menu, int num)
289 pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data;
292 entry.uid = KeyTable[num];
295 mutt_FormatString (s, l, 0, MuttIndexWindow->cols, NONULL (PgpEntryFormat), pgp_entry_fmt,
296 (unsigned long) &entry, MUTT_FORMAT_ARROWCURSOR);
299 static int _pgp_compare_address (const void *a, const void *b)
303 pgp_uid_t **s = (pgp_uid_t **) a;
304 pgp_uid_t **t = (pgp_uid_t **) b;
306 if ((r = mutt_strcasecmp ((*s)->addr, (*t)->addr)))
309 return (mutt_strcasecmp (pgp_fpr_or_lkeyid ((*s)->parent),
310 pgp_fpr_or_lkeyid ((*t)->parent)) > 0);
313 static int pgp_compare_address (const void *a, const void *b)
315 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_address (a, b)
316 : _pgp_compare_address (a, b));
321 static int _pgp_compare_keyid (const void *a, const void *b)
325 pgp_uid_t **s = (pgp_uid_t **) a;
326 pgp_uid_t **t = (pgp_uid_t **) b;
328 if ((r = mutt_strcasecmp (pgp_fpr_or_lkeyid ((*s)->parent),
329 pgp_fpr_or_lkeyid ((*t)->parent))))
332 return (mutt_strcasecmp ((*s)->addr, (*t)->addr)) > 0;
335 static int pgp_compare_keyid (const void *a, const void *b)
337 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_keyid (a, b)
338 : _pgp_compare_keyid (a, b));
341 static int _pgp_compare_date (const void *a, const void *b)
344 pgp_uid_t **s = (pgp_uid_t **) a;
345 pgp_uid_t **t = (pgp_uid_t **) b;
347 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
349 return (mutt_strcasecmp ((*s)->addr, (*t)->addr)) > 0;
352 static int pgp_compare_date (const void *a, const void *b)
354 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_date (a, b)
355 : _pgp_compare_date (a, b));
358 static int _pgp_compare_trust (const void *a, const void *b)
362 pgp_uid_t **s = (pgp_uid_t **) a;
363 pgp_uid_t **t = (pgp_uid_t **) b;
365 if ((r = (((*s)->parent->flags & (KEYFLAG_RESTRICTIONS))
366 - ((*t)->parent->flags & (KEYFLAG_RESTRICTIONS)))))
368 if ((r = ((*s)->trust - (*t)->trust)))
370 if ((r = ((*s)->parent->keylen - (*t)->parent->keylen)))
372 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
374 if ((r = mutt_strcasecmp ((*s)->addr, (*t)->addr)))
376 return (mutt_strcasecmp (pgp_fpr_or_lkeyid ((*s)->parent),
377 pgp_fpr_or_lkeyid ((*t)->parent))) > 0;
380 static int pgp_compare_trust (const void *a, const void *b)
382 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_trust (a, b)
383 : _pgp_compare_trust (a, b));
386 static int pgp_key_is_valid (pgp_key_t k)
388 pgp_key_t pk = pgp_principal_key (k);
389 if (k->flags & KEYFLAG_CANTUSE)
391 if (pk->flags & KEYFLAG_CANTUSE)
397 static int pgp_id_is_strong (pgp_uid_t *uid)
399 if ((uid->trust & 3) < 3)
405 static int pgp_id_is_valid (pgp_uid_t *uid)
407 if (!pgp_key_is_valid (uid->parent))
409 if (uid->flags & KEYFLAG_CANTUSE)
415 #define PGP_KV_VALID 1
416 #define PGP_KV_ADDR 2
417 #define PGP_KV_STRING 4
418 #define PGP_KV_STRONGID 8
420 #define PGP_KV_MATCH (PGP_KV_ADDR|PGP_KV_STRING)
422 static int pgp_id_matches_addr (ADDRESS *addr, ADDRESS *u_addr, pgp_uid_t *uid)
426 if (pgp_id_is_valid (uid))
429 if (pgp_id_is_strong (uid))
430 rv |= PGP_KV_STRONGID;
432 if (addr->mailbox && u_addr->mailbox
433 && mutt_strcasecmp (addr->mailbox, u_addr->mailbox) == 0)
436 if (addr->personal && u_addr->personal
437 && mutt_strcasecmp (addr->personal, u_addr->personal) == 0)
443 static pgp_key_t pgp_select_key (pgp_key_t keys,
444 ADDRESS * p, const char *s)
447 pgp_uid_t **KeyTable;
450 char helpstr[LONG_STRING], buf[LONG_STRING], tmpbuf[STRING];
451 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
456 int (*f) (const void *, const void *);
463 for (i = 0, kp = keys; kp; kp = kp->next)
465 if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE))
471 for (a = kp->address; a; a = a->next)
473 if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE))
482 safe_realloc (&KeyTable, sizeof (pgp_uid_t *) * keymax);
491 mutt_error _("All matching keys are expired, revoked, or disabled.");
496 switch (PgpSortKeys & SORT_MASK)
499 f = pgp_compare_date;
502 f = pgp_compare_keyid;
505 f = pgp_compare_address;
509 f = pgp_compare_trust;
512 qsort (KeyTable, i, sizeof (pgp_uid_t *), f);
515 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT);
516 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
517 mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP,
518 OP_GENERIC_SELECT_ENTRY);
519 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
520 mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP, OP_VERIFY_KEY);
521 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
522 mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP);
523 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
525 menu = mutt_new_menu (MENU_PGP);
527 menu->make_entry = pgp_entry;
528 menu->help = helpstr;
529 menu->data = KeyTable;
530 mutt_push_current_menu (menu);
533 snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox);
535 snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s);
546 switch (mutt_menuLoop (menu))
551 mutt_mktemp (tempfile, sizeof (tempfile));
552 if ((devnull = fopen ("/dev/null", "w")) == NULL) /* __FOPEN_CHECKED__ */
554 mutt_perror _("Can't open /dev/null");
557 if ((fp = safe_fopen (tempfile, "w")) == NULL)
559 safe_fclose (&devnull);
560 mutt_perror _("Can't create temporary file");
564 mutt_message _("Invoking PGP...");
566 snprintf (tmpbuf, sizeof (tmpbuf), "0x%s",
567 pgp_fpr_or_lkeyid (pgp_principal_key (KeyTable[menu->current]->parent)));
569 if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1,
570 fileno (fp), fileno (devnull), tmpbuf)) == -1)
572 mutt_perror _("Can't create filter");
575 safe_fclose (&devnull);
578 mutt_wait_filter (thepid);
580 safe_fclose (&devnull);
582 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),
583 pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent)));
584 mutt_do_pager (cmd, tempfile, 0, NULL);
585 menu->redraw = REDRAW_FULL;
591 mutt_message ("%s", NONULL (KeyTable[menu->current]->addr));
594 case OP_GENERIC_SELECT_ENTRY:
597 /* XXX make error reporting more verbose */
599 if (option (OPTPGPCHECKTRUST))
600 if (!pgp_key_is_valid (KeyTable[menu->current]->parent))
602 mutt_error _("This key can't be used: expired/disabled/revoked.");
606 if (option (OPTPGPCHECKTRUST) &&
607 (!pgp_id_is_valid (KeyTable[menu->current])
608 || !pgp_id_is_strong (KeyTable[menu->current])))
611 char buff[LONG_STRING];
613 if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE)
614 s = N_("ID is expired/disabled/revoked.");
615 else switch (KeyTable[menu->current]->trust & 0x03)
618 s = N_("ID has undefined validity.");
621 s = N_("ID is not valid.");
624 s = N_("ID is only marginally valid.");
628 snprintf (buff, sizeof (buff), _("%s Do you really want to use the key?"),
631 if (mutt_yesorno (buff, MUTT_NO) != MUTT_YES)
639 kp = pgp_principal_key (KeyTable[menu->current]->parent);
641 kp = KeyTable[menu->current]->parent;
654 mutt_pop_current_menu (menu);
655 mutt_menuDestroy (&menu);
661 pgp_key_t pgp_ask_for_key (char *tag, char *whatfor,
662 short abilities, pgp_ring_t keyring)
665 char resp[SHORT_STRING];
666 struct pgp_cache *l = NULL;
674 for (l = id_defaults; l; l = l->next)
675 if (!mutt_strcasecmp (whatfor, l->what))
677 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
686 if (mutt_get_field (tag, resp, sizeof (resp), MUTT_CLEAR) != 0)
692 mutt_str_replace (&l->dflt, resp);
695 l = safe_malloc (sizeof (struct pgp_cache));
696 l->next = id_defaults;
698 l->what = safe_strdup (whatfor);
699 l->dflt = safe_strdup (resp);
703 if ((key = pgp_getkeybystr (resp, abilities, keyring)))
711 /* generate a public key attachment */
713 BODY *pgp_make_key_attachment (char *tempf)
716 char buff[LONG_STRING];
717 char tempfb[_POSIX_PATH_MAX], tmp[STRING];
723 unset_option (OPTPGPCHECKTRUST);
725 key = pgp_ask_for_key (_("Please enter the key ID: "), NULL, 0, PGP_PUBRING);
727 if (!key) return NULL;
729 snprintf (tmp, sizeof (tmp), "0x%s", pgp_fpr_or_lkeyid (pgp_principal_key (key)));
734 mutt_mktemp (tempfb, sizeof (tempfb));
738 if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL)
740 mutt_perror _("Can't create temporary file");
744 if ((devnull = fopen ("/dev/null", "w")) == NULL) /* __FOPEN_CHECKED__ */
746 mutt_perror _("Can't open /dev/null");
747 safe_fclose (&tempfp);
753 mutt_message _("Invoking PGP...");
757 pgp_invoke_export (NULL, NULL, NULL, -1,
758 fileno (tempfp), fileno (devnull), tmp)) == -1)
760 mutt_perror _("Can't create filter");
762 safe_fclose (&tempfp);
763 safe_fclose (&devnull);
767 mutt_wait_filter (thepid);
769 safe_fclose (&tempfp);
770 safe_fclose (&devnull);
772 att = mutt_new_body ();
773 att->filename = safe_strdup (tempf);
776 att->type = TYPEAPPLICATION;
777 att->subtype = safe_strdup ("pgp-keys");
778 snprintf (buff, sizeof (buff), _("PGP Key %s."), tmp);
779 att->description = safe_strdup (buff);
780 mutt_update_encoding (att);
783 att->length = sb.st_size;
788 static LIST *pgp_add_string_to_hints (LIST *hints, const char *str)
793 if ((scratch = safe_strdup (str)) == NULL)
796 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
797 t = strtok (NULL, " ,.:\"()<>\n"))
800 hints = mutt_add_list (hints, t);
807 static pgp_key_t *pgp_get_lastp (pgp_key_t p)
809 for (; p; p = p->next)
816 pgp_key_t pgp_getkeybyaddr (ADDRESS * a, short abilities, pgp_ring_t keyring,
825 pgp_key_t keys, k, kn;
826 pgp_key_t the_strong_valid_key = NULL;
827 pgp_key_t a_valid_addrmatch_key = NULL;
828 pgp_key_t matches = NULL;
829 pgp_key_t *last = &matches;
833 hints = pgp_add_string_to_hints (hints, a->mailbox);
834 if (a && a->personal)
835 hints = pgp_add_string_to_hints (hints, a->personal);
838 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
839 keys = pgp_get_candidates (keyring, hints);
841 mutt_free_list (&hints);
846 dprint (5, (debugfile, "pgp_getkeybyaddr: looking for %s <%s>.",
847 a->personal, a->mailbox));
850 for (k = keys; k; k = kn)
854 dprint (5, (debugfile, " looking at key: %s\n",
857 if (abilities && !(k->flags & abilities))
859 dprint (5, (debugfile, " insufficient abilities: Has %x, want %x\n",
860 k->flags, abilities));
864 match = 0; /* any match */
866 for (q = k->address; q; q = q->next)
868 r = rfc822_parse_adrlist (NULL, NONULL (q->addr));
870 for (p = r; p; p = p->next)
872 int validity = pgp_id_matches_addr (a, p, q);
874 if (validity & PGP_KV_MATCH) /* something matches */
877 if ((validity & PGP_KV_VALID)
878 && (validity & PGP_KV_ADDR))
880 if (validity & PGP_KV_STRONGID)
882 if (the_strong_valid_key && the_strong_valid_key != k)
884 the_strong_valid_key = k;
888 a_valid_addrmatch_key = k;
893 rfc822_free_address (&r);
898 *last = pgp_principal_key (k);
899 kn = pgp_remove_key (&keys, *last);
900 last = pgp_get_lastp (k);
904 pgp_free_key (&keys);
910 if (the_strong_valid_key)
912 pgp_remove_key (&matches, the_strong_valid_key);
913 k = the_strong_valid_key;
915 else if (a_valid_addrmatch_key)
917 pgp_remove_key (&matches, a_valid_addrmatch_key);
918 k = a_valid_addrmatch_key;
923 else if (the_strong_valid_key && !multi)
926 * There was precisely one strong match on a valid ID.
928 * Proceed without asking the user.
930 pgp_remove_key (&matches, the_strong_valid_key);
931 k = the_strong_valid_key;
936 * Else: Ask the user.
938 if ((k = pgp_select_key (matches, a, NULL)))
939 pgp_remove_key (&matches, k);
942 pgp_free_key (&matches);
950 pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring)
954 pgp_key_t matches = NULL;
955 pgp_key_t *last = &matches;
960 const char *ps, *pl, *pfcopy, *phint;
962 if ((l = mutt_strlen (p)) && p[l-1] == '!')
965 mutt_message (_("Looking for keys matching \"%s\"..."), p);
967 pfcopy = crypt_get_fingerprint_or_id (p, &phint, &pl, &ps);
968 hints = pgp_add_string_to_hints (hints, phint);
969 keys = pgp_get_candidates (keyring, hints);
970 mutt_free_list (&hints);
975 for (k = keys; k; k = kn)
978 if (abilities && !(k->flags & abilities))
981 /* This shouldn't happen, but keys without any addresses aren't selectable
982 * in pgp_select_key().
989 dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s:\n",
990 p, pgp_long_keyid (k)));
993 (pfcopy && mutt_strcasecmp (pfcopy, k->fingerprint) == 0) ||
994 (pl && mutt_strcasecmp (pl, pgp_long_keyid (k)) == 0) ||
995 (ps && mutt_strcasecmp (ps, pgp_short_keyid (k)) == 0))
997 dprint (5, (debugfile, "\t\tmatch.\n"));
1002 for (a = k->address; a; a = a->next)
1004 dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\":\n",
1005 p, pgp_long_keyid (k), NONULL (a->addr)));
1006 if (mutt_stristr (a->addr, p))
1008 dprint (5, (debugfile, "\t\tmatch.\n"));
1017 *last = pgp_principal_key (k);
1018 kn = pgp_remove_key (&keys, *last);
1019 last = pgp_get_lastp (k);
1023 pgp_free_key (&keys);
1027 if ((k = pgp_select_key (matches, NULL, p)))
1028 pgp_remove_key (&matches, k);
1030 pgp_free_key (&matches);
1044 #endif /* CRYPT_BACKEND_CLASSIC_PGP */