2 * Copyright (C) 1996,1997 Michael R. Elkins <me@mutt.org>
3 * Copyright (c) 1998,1999 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., 59 Temple Place - Suite 330,
20 * Boston, MA 02111, USA.
24 #include "mutt_curses.h"
25 #include "mutt_menu.h"
40 #ifdef CRYPT_BACKEND_CLASSIC_PGP
46 struct pgp_cache *next;
49 static struct pgp_cache *id_defaults = NULL;
51 static char trust_flags[] = "?- +";
53 static char *pgp_key_abilities (int flags)
57 if (!(flags & KEYFLAG_CANENCRYPT))
59 else if (flags & KEYFLAG_PREFER_SIGNING)
64 if (!(flags & KEYFLAG_CANSIGN))
66 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
76 static char pgp_flags (int flags)
78 if (flags & KEYFLAG_REVOKED)
80 else if (flags & KEYFLAG_EXPIRED)
82 else if (flags & KEYFLAG_DISABLED)
84 else if (flags & KEYFLAG_CRITICAL)
90 static pgp_key_t pgp_principal_key (pgp_key_t key)
92 if (key->flags & KEYFLAG_SUBKEY && key->parent)
99 * Format an entry on the PGP key selection menu.
102 * %k key id %K key id of the principal key
104 * %a algorithm %A algorithm of the princ. key
105 * %l length %L length of the princ. key
106 * %f flags %F flags of the princ. key
107 * %c capabilities %C capabilities of the princ. key
108 * %t trust/validity of the key-uid association
109 * %[...] date of key using strftime(3)
112 typedef struct pgp_entry
118 static const char *pgp_entry_fmt (char *dest,
123 const char *ifstring,
124 const char *elsestring,
133 int optional = (flags & M_FORMAT_OPTIONAL);
135 entry = (pgp_entry_t *) data;
138 pkey = pgp_principal_key (key);
140 if (isupper ((unsigned char) op))
143 kflags = key->flags | (pkey->flags & KEYFLAG_RESTRICTIONS)
146 switch (ascii_tolower (op))
152 char buf2[SHORT_STRING], *p;
169 while (len > 0 && *cp != ']')
181 break; /* not enough space */
192 if (do_locales && Locale)
193 setlocale (LC_TIME, Locale);
195 tm = localtime (&key->gen_time);
197 strftime (buf2, sizeof (buf2), dest, tm);
200 setlocale (LC_TIME, "C");
202 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
203 snprintf (dest, destlen, fmt, buf2);
211 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
212 snprintf (dest, destlen, fmt, entry->num);
218 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
219 snprintf (dest, destlen, fmt, _pgp_keyid (key));
225 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
226 snprintf (dest, destlen, fmt, uid->addr);
232 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
233 snprintf (dest, destlen, fmt, key->algorithm);
239 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
240 snprintf (dest, destlen, fmt, key->keylen);
246 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
247 snprintf (dest, destlen, fmt, pgp_flags (kflags));
249 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
255 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
256 snprintf (dest, destlen, fmt, pgp_key_abilities (kflags));
258 else if (!(kflags & (KEYFLAG_ABILITIES)))
264 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
265 snprintf (dest, destlen, fmt, trust_flags[uid->trust & 0x03]);
267 else if (!(uid->trust & 0x03))
268 /* undefined trust */
276 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
277 else if (flags & M_FORMAT_OPTIONAL)
278 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
282 static void pgp_entry (char *s, size_t l, MUTTMENU * menu, int num)
284 pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data;
287 entry.uid = KeyTable[num];
290 mutt_FormatString (s, l, NONULL (PgpEntryFormat), pgp_entry_fmt,
291 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
294 static int _pgp_compare_address (const void *a, const void *b)
298 pgp_uid_t **s = (pgp_uid_t **) a;
299 pgp_uid_t **t = (pgp_uid_t **) b;
301 if ((r = mutt_strcasecmp ((*s)->addr, (*t)->addr)))
304 return (mutt_strcasecmp (_pgp_keyid ((*s)->parent),
305 _pgp_keyid ((*t)->parent)) > 0);
308 static int pgp_compare_address (const void *a, const void *b)
310 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_address (a, b)
311 : _pgp_compare_address (a, b));
316 static int _pgp_compare_keyid (const void *a, const void *b)
320 pgp_uid_t **s = (pgp_uid_t **) a;
321 pgp_uid_t **t = (pgp_uid_t **) b;
323 if ((r = mutt_strcasecmp (_pgp_keyid ((*s)->parent),
324 _pgp_keyid ((*t)->parent))))
327 return (mutt_strcasecmp ((*s)->addr, (*t)->addr)) > 0;
330 static int pgp_compare_keyid (const void *a, const void *b)
332 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_keyid (a, b)
333 : _pgp_compare_keyid (a, b));
336 static int _pgp_compare_date (const void *a, const void *b)
339 pgp_uid_t **s = (pgp_uid_t **) a;
340 pgp_uid_t **t = (pgp_uid_t **) b;
342 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
344 return (mutt_strcasecmp ((*s)->addr, (*t)->addr)) > 0;
347 static int pgp_compare_date (const void *a, const void *b)
349 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_date (a, b)
350 : _pgp_compare_date (a, b));
353 static int _pgp_compare_trust (const void *a, const void *b)
357 pgp_uid_t **s = (pgp_uid_t **) a;
358 pgp_uid_t **t = (pgp_uid_t **) b;
360 if ((r = (((*s)->parent->flags & (KEYFLAG_RESTRICTIONS))
361 - ((*t)->parent->flags & (KEYFLAG_RESTRICTIONS)))))
363 if ((r = ((*s)->trust - (*t)->trust)))
365 if ((r = ((*s)->parent->keylen - (*t)->parent->keylen)))
367 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
369 if ((r = mutt_strcasecmp ((*s)->addr, (*t)->addr)))
371 return (mutt_strcasecmp (_pgp_keyid ((*s)->parent),
372 _pgp_keyid ((*t)->parent))) > 0;
375 static int pgp_compare_trust (const void *a, const void *b)
377 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_trust (a, b)
378 : _pgp_compare_trust (a, b));
381 static int pgp_key_is_valid (pgp_key_t k)
383 pgp_key_t pk = pgp_principal_key (k);
384 if (k->flags & KEYFLAG_CANTUSE)
386 if (pk->flags & KEYFLAG_CANTUSE)
392 static int pgp_id_is_strong (pgp_uid_t *uid)
394 if ((uid->trust & 3) < 3)
400 static int pgp_id_is_valid (pgp_uid_t *uid)
402 if (!pgp_key_is_valid (uid->parent))
404 if (uid->flags & KEYFLAG_CANTUSE)
410 #define PGP_KV_VALID 1
411 #define PGP_KV_ADDR 2
412 #define PGP_KV_STRING 4
413 #define PGP_KV_STRONGID 8
415 #define PGP_KV_MATCH (PGP_KV_ADDR|PGP_KV_STRING)
417 static int pgp_id_matches_addr (ADDRESS *addr, ADDRESS *u_addr, pgp_uid_t *uid)
421 if (pgp_id_is_valid (uid))
424 if (pgp_id_is_strong (uid))
425 rv |= PGP_KV_STRONGID;
427 if (addr->mailbox && u_addr->mailbox
428 && mutt_strcasecmp (addr->mailbox, u_addr->mailbox) == 0)
431 if (addr->personal && u_addr->personal
432 && mutt_strcasecmp (addr->personal, u_addr->personal) == 0)
438 static pgp_key_t pgp_select_key (pgp_key_t keys,
439 ADDRESS * p, const char *s)
442 pgp_uid_t **KeyTable;
445 char helpstr[SHORT_STRING], buf[LONG_STRING], tmpbuf[STRING];
446 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
451 int (*f) (const void *, const void *);
458 for (i = 0, kp = keys; kp; kp = kp->next)
460 if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE))
466 for (a = kp->address; a; a = a->next)
468 if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE))
477 safe_realloc (&KeyTable, sizeof (pgp_uid_t *) * keymax);
486 mutt_error _("All matching keys are expired, revoked, or disabled.");
491 switch (PgpSortKeys & SORT_MASK)
494 f = pgp_compare_date;
497 f = pgp_compare_keyid;
500 f = pgp_compare_address;
504 f = pgp_compare_trust;
507 qsort (KeyTable, i, sizeof (pgp_uid_t *), f);
510 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT);
511 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
512 mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP,
513 OP_GENERIC_SELECT_ENTRY);
514 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
515 mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP, OP_VERIFY_KEY);
516 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
517 mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP);
518 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
520 menu = mutt_new_menu ();
522 menu->make_entry = pgp_entry;
523 menu->menu = MENU_PGP;
524 menu->help = helpstr;
525 menu->data = KeyTable;
528 snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox);
530 snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s);
541 switch (mutt_menuLoop (menu))
546 mutt_mktemp (tempfile);
547 if ((devnull = fopen ("/dev/null", "w")) == NULL) /* __FOPEN_CHECKED__ */
549 mutt_perror _("Can't open /dev/null");
552 if ((fp = safe_fopen (tempfile, "w")) == NULL)
555 mutt_perror _("Can't create temporary file");
559 mutt_message _("Invoking PGP...");
561 snprintf (tmpbuf, sizeof (tmpbuf), "0x%s", pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent)));
563 if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1,
564 fileno (fp), fileno (devnull), tmpbuf)) == -1)
566 mutt_perror _("Can't create filter");
572 mutt_wait_filter (thepid);
576 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),
577 pgp_keyid (pgp_principal_key (KeyTable[menu->current]->parent)));
578 mutt_do_pager (cmd, tempfile, 0, NULL);
579 menu->redraw = REDRAW_FULL;
585 mutt_message ("%s", KeyTable[menu->current]->addr);
588 case OP_GENERIC_SELECT_ENTRY:
591 /* XXX make error reporting more verbose */
593 if (option (OPTPGPCHECKTRUST))
594 if (!pgp_key_is_valid (KeyTable[menu->current]->parent))
596 mutt_error _("This key can't be used: expired/disabled/revoked.");
600 if (option (OPTPGPCHECKTRUST) &&
601 (!pgp_id_is_valid (KeyTable[menu->current])
602 || !pgp_id_is_strong (KeyTable[menu->current])))
605 char buff[LONG_STRING];
607 if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE)
608 s = N_("ID is expired/disabled/revoked.");
609 else switch (KeyTable[menu->current]->trust & 0x03)
612 s = N_("ID has undefined validity.");
615 s = N_("ID is not valid.");
618 s = N_("ID is only marginally valid.");
622 snprintf (buff, sizeof (buff), _("%s Do you really want to use the key?"),
625 if (mutt_yesorno (buff, M_NO) != M_YES)
633 kp = pgp_principal_key (KeyTable[menu->current]->parent);
635 kp = KeyTable[menu->current]->parent;
648 mutt_menuDestroy (&menu);
651 set_option (OPTNEEDREDRAW);
656 pgp_key_t pgp_ask_for_key (char *tag, char *whatfor,
657 short abilities, pgp_ring_t keyring)
660 char resp[SHORT_STRING];
661 struct pgp_cache *l = NULL;
669 for (l = id_defaults; l; l = l->next)
670 if (!mutt_strcasecmp (whatfor, l->what))
672 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
681 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
687 mutt_str_replace (&l->dflt, resp);
690 l = safe_malloc (sizeof (struct pgp_cache));
691 l->next = id_defaults;
693 l->what = safe_strdup (whatfor);
694 l->dflt = safe_strdup (resp);
698 if ((key = pgp_getkeybystr (resp, abilities, keyring)))
706 /* generate a public key attachment */
708 BODY *pgp_make_key_attachment (char *tempf)
711 char buff[LONG_STRING];
712 char tempfb[_POSIX_PATH_MAX], tmp[STRING];
718 unset_option (OPTPGPCHECKTRUST);
720 key = pgp_ask_for_key (_("Please enter the key ID: "), NULL, 0, PGP_PUBRING);
722 if (!key) return NULL;
724 snprintf (tmp, sizeof (tmp), "0x%s", pgp_keyid (pgp_principal_key (key)));
729 mutt_mktemp (tempfb);
733 if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL)
735 mutt_perror _("Can't create temporary file");
739 if ((devnull = fopen ("/dev/null", "w")) == NULL) /* __FOPEN_CHECKED__ */
741 mutt_perror _("Can't open /dev/null");
748 mutt_message _("Invoking pgp...");
752 pgp_invoke_export (NULL, NULL, NULL, -1,
753 fileno (tempfp), fileno (devnull), tmp)) == -1)
755 mutt_perror _("Can't create filter");
762 mutt_wait_filter (thepid);
767 att = mutt_new_body ();
768 att->filename = safe_strdup (tempf);
771 att->type = TYPEAPPLICATION;
772 att->subtype = safe_strdup ("pgp-keys");
773 snprintf (buff, sizeof (buff), _("PGP Key %s."), tmp);
774 att->description = safe_strdup (buff);
775 mutt_update_encoding (att);
778 att->length = sb.st_size;
783 static LIST *pgp_add_string_to_hints (LIST *hints, const char *str)
788 if ((scratch = safe_strdup (str)) == NULL)
791 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
792 t = strtok (NULL, " ,.:\"()<>\n"))
795 hints = mutt_add_list (hints, t);
802 static pgp_key_t *pgp_get_lastp (pgp_key_t p)
804 for (; p; p = p->next)
811 pgp_key_t pgp_getkeybyaddr (ADDRESS * a, short abilities, pgp_ring_t keyring)
819 int this_key_has_strong;
820 int this_key_has_weak;
821 int this_key_has_invalid;
824 pgp_key_t keys, k, kn;
825 pgp_key_t the_valid_key = NULL;
826 pgp_key_t matches = NULL;
827 pgp_key_t *last = &matches;
831 hints = pgp_add_string_to_hints (hints, a->mailbox);
832 if (a && a->personal)
833 hints = pgp_add_string_to_hints (hints, a->personal);
835 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
836 keys = pgp_get_candidates (keyring, hints);
838 mutt_free_list (&hints);
843 dprint (5, (debugfile, "pgp_getkeybyaddr: looking for %s <%s>.",
844 a->personal, a->mailbox));
847 for (k = keys; k; k = kn)
851 dprint (5, (debugfile, " looking at key: %s\n",
854 if (abilities && !(k->flags & abilities))
856 dprint (5, (debugfile, " insufficient abilities: Has %x, want %x\n",
857 k->flags, abilities));
861 this_key_has_weak = 0; /* weak but valid match */
862 this_key_has_invalid = 0; /* invalid match */
863 this_key_has_strong = 0; /* strong and valid match */
864 match = 0; /* any match */
866 for (q = k->address; q; q = q->next)
868 r = rfc822_parse_adrlist (NULL, 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 /* is this key a strong candidate? */
878 if ((validity & PGP_KV_VALID) && (validity & PGP_KV_STRONGID)
879 && (validity & PGP_KV_ADDR))
881 if (the_valid_key && the_valid_key != k)
884 this_key_has_strong = 1;
886 else if ((validity & PGP_KV_MATCH) && !(validity & PGP_KV_VALID))
887 this_key_has_invalid = 1;
888 else if ((validity & PGP_KV_MATCH)
889 && (!(validity & PGP_KV_STRONGID) || !(validity & PGP_KV_ADDR)))
890 this_key_has_weak = 1;
893 rfc822_free_address (&r);
896 if (match && !this_key_has_strong && this_key_has_invalid)
898 if (match && !this_key_has_strong && this_key_has_weak)
903 *last = pgp_principal_key (k);
904 kn = pgp_remove_key (&keys, *last);
905 last = pgp_get_lastp (k);
909 pgp_free_key (&keys);
913 if (the_valid_key && !multi /* && !weak
914 && !(invalid && option (OPTPGPSHOWUNUSABLE)) */)
917 * There was precisely one strong match on a valid ID.
919 * Proceed without asking the user.
921 pgp_remove_key (&matches, the_valid_key);
922 pgp_free_key (&matches);
928 * Else: Ask the user.
930 if ((k = pgp_select_key (matches, a, NULL)))
931 pgp_remove_key (&matches, k);
932 pgp_free_key (&matches);
941 pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring)
945 pgp_key_t matches = NULL;
946 pgp_key_t *last = &matches;
951 mutt_message (_("Looking for keys matching \"%s\"..."), p);
953 hints = pgp_add_string_to_hints (hints, p);
954 keys = pgp_get_candidates (keyring, hints);
955 mutt_free_list (&hints);
961 for (k = keys; k; k = kn)
964 if (abilities && !(k->flags & abilities))
969 for (a = k->address; a; a = a->next)
971 dprint (5, (debugfile, "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\": ",
972 p, pgp_keyid (k), a->addr));
973 if (!*p || mutt_strcasecmp (p, pgp_keyid (k)) == 0 ||
974 (!mutt_strncasecmp (p, "0x", 2) && !mutt_strcasecmp (p + 2, pgp_keyid (k))) ||
975 (option (OPTPGPLONGIDS) && !mutt_strncasecmp (p, "0x", 2) &&
976 !mutt_strcasecmp (p + 2, k->keyid + 8)) ||
977 mutt_stristr (a->addr, p))
979 dprint (5, (debugfile, "match.\n"));
987 *last = pgp_principal_key (k);
988 kn = pgp_remove_key (&keys, *last);
989 last = pgp_get_lastp (k);
993 pgp_free_key (&keys);
997 if ((k = pgp_select_key (matches, NULL, p)))
998 pgp_remove_key (&matches, k);
1000 pgp_free_key (&matches);
1009 #endif /* CRYPT_BACKEND_CLASSIC_PGP */