2 * Copyright notice from original mutt:
3 * Copyright (C) 1996,1997 Michael R. Elkins <me@mutt.org>
4 * Copyright (c) 1998,1999 Thomas Roessler <roessler@does-not-exist.org>
6 * This file is part of mutt-ng, see http://www.muttng.org/.
7 * It's licensed under the GNU General Public License,
8 * please see the file GPL in the top level source directory.
18 #include "recvattach.h"
19 #include "mutt_curses.h"
20 #include "mutt_menu.h"
29 #include "lib/debug.h"
40 #ifdef CRYPT_BACKEND_CLASSIC_PGP
45 struct pgp_cache *next;
48 static struct pgp_cache *id_defaults = NULL;
50 static char trust_flags[] = "?- +";
52 static char *pgp_key_abilities (int flags)
56 if (!(flags & KEYFLAG_CANENCRYPT))
58 else if (flags & KEYFLAG_PREFER_SIGNING)
63 if (!(flags & KEYFLAG_CANSIGN))
65 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
75 static char pgp_flags (int flags)
77 if (flags & KEYFLAG_REVOKED)
79 else if (flags & KEYFLAG_EXPIRED)
81 else if (flags & KEYFLAG_DISABLED)
83 else if (flags & KEYFLAG_CRITICAL)
89 static pgp_key_t pgp_principal_key (pgp_key_t key)
91 if (key->flags & KEYFLAG_SUBKEY && key->parent)
98 * Format an entry on the PGP key selection menu.
101 * %k key id %K key id of the principal key
103 * %a algorithm %A algorithm of the princ. key
104 * %l length %L length of the princ. key
105 * %f flags %F flags of the princ. key
106 * %c capabilities %C capabilities of the princ. key
107 * %t trust/validity of the key-uid association
108 * %[...] date of key using strftime(3)
111 typedef struct pgp_entry {
116 static const char *pgp_entry_fmt (char *dest,
121 const char *ifstring,
122 const char *elsestring,
123 unsigned long data, format_flag flags)
130 int optional = (flags & M_FORMAT_OPTIONAL);
132 entry = (pgp_entry_t *) data;
135 pkey = pgp_principal_key (key);
137 if (isupper ((unsigned char) op))
140 kflags = key->flags | (pkey->flags & KEYFLAG_RESTRICTIONS)
143 switch (ascii_tolower (op)) {
148 char buf2[SHORT_STRING], *p;
164 while (len > 0 && *cp != ']') {
173 break; /* not enough space */
183 if (do_locales && Locale)
184 setlocale (LC_TIME, Locale);
186 tm = localtime (&key->gen_time);
188 strftime (buf2, sizeof (buf2), dest, tm);
191 setlocale (LC_TIME, "C");
193 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
194 snprintf (dest, destlen, fmt, buf2);
201 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
202 snprintf (dest, destlen, fmt, entry->num);
207 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
208 snprintf (dest, destlen, fmt, _pgp_keyid (key));
213 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
214 snprintf (dest, destlen, fmt, uid->addr);
219 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
220 snprintf (dest, destlen, fmt, key->algorithm);
225 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
226 snprintf (dest, destlen, fmt, key->keylen);
231 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
232 snprintf (dest, destlen, fmt, pgp_flags (kflags));
234 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
239 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
240 snprintf (dest, destlen, fmt, pgp_key_abilities (kflags));
242 else if (!(kflags & (KEYFLAG_ABILITIES)))
247 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
248 snprintf (dest, destlen, fmt, trust_flags[uid->trust & 0x03]);
250 else if (!(uid->trust & 0x03))
251 /* undefined trust */
259 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
260 else if (flags & M_FORMAT_OPTIONAL)
261 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
265 static void pgp_entry (char *s, size_t l, MUTTMENU * menu, int num)
267 pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data;
270 entry.uid = KeyTable[num];
273 mutt_FormatString (s, l, NONULL (PgpEntryFormat), pgp_entry_fmt,
274 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
277 static int _pgp_compare_address (const void *a, const void *b)
281 pgp_uid_t **s = (pgp_uid_t **) a;
282 pgp_uid_t **t = (pgp_uid_t **) b;
284 if ((r = str_casecmp ((*s)->addr, (*t)->addr)))
287 return (str_casecmp (_pgp_keyid ((*s)->parent),
288 _pgp_keyid ((*t)->parent)) > 0);
291 static int pgp_compare_address (const void *a, const void *b)
293 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_address (a, b)
294 : _pgp_compare_address (a, b));
299 static int _pgp_compare_keyid (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 = str_casecmp (_pgp_keyid ((*s)->parent),
307 _pgp_keyid ((*t)->parent))))
310 return (str_casecmp ((*s)->addr, (*t)->addr)) > 0;
313 static int pgp_compare_keyid (const void *a, const void *b)
315 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_keyid (a, b)
316 : _pgp_compare_keyid (a, b));
319 static int _pgp_compare_date (const void *a, const void *b)
322 pgp_uid_t **s = (pgp_uid_t **) a;
323 pgp_uid_t **t = (pgp_uid_t **) b;
325 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
327 return (str_casecmp ((*s)->addr, (*t)->addr)) > 0;
330 static int pgp_compare_date (const void *a, const void *b)
332 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_date (a, b)
333 : _pgp_compare_date (a, b));
336 static int _pgp_compare_trust (const void *a, const void *b)
340 pgp_uid_t **s = (pgp_uid_t **) a;
341 pgp_uid_t **t = (pgp_uid_t **) b;
343 if ((r = (((*s)->parent->flags & (KEYFLAG_RESTRICTIONS))
344 - ((*t)->parent->flags & (KEYFLAG_RESTRICTIONS)))))
346 if ((r = ((*s)->trust - (*t)->trust)))
348 if ((r = ((*s)->parent->keylen - (*t)->parent->keylen)))
350 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
352 if ((r = str_casecmp ((*s)->addr, (*t)->addr)))
354 return (str_casecmp (_pgp_keyid ((*s)->parent),
355 _pgp_keyid ((*t)->parent))) > 0;
358 static int pgp_compare_trust (const void *a, const void *b)
360 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_trust (a, b)
361 : _pgp_compare_trust (a, b));
364 static int pgp_key_is_valid (pgp_key_t k)
366 pgp_key_t pk = pgp_principal_key (k);
368 if (k->flags & KEYFLAG_CANTUSE)
370 if (pk->flags & KEYFLAG_CANTUSE)
376 static int pgp_id_is_strong (pgp_uid_t * uid)
378 if ((uid->trust & 3) < 3)
384 static int pgp_id_is_valid (pgp_uid_t * uid)
386 if (!pgp_key_is_valid (uid->parent))
388 if (uid->flags & KEYFLAG_CANTUSE)
394 #define PGP_KV_VALID 1
395 #define PGP_KV_ADDR 2
396 #define PGP_KV_STRING 4
397 #define PGP_KV_STRONGID 8
399 #define PGP_KV_MATCH (PGP_KV_ADDR|PGP_KV_STRING)
401 static int pgp_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
406 if (pgp_id_is_valid (uid))
409 if (pgp_id_is_strong (uid))
410 rv |= PGP_KV_STRONGID;
412 if (addr->mailbox && u_addr->mailbox
413 && str_casecmp (addr->mailbox, u_addr->mailbox) == 0)
416 if (addr->personal && u_addr->personal
417 && str_casecmp (addr->personal, u_addr->personal) == 0)
423 static pgp_key_t pgp_select_key (pgp_key_t keys, ADDRESS * p, const char *s)
426 pgp_uid_t **KeyTable;
429 char helpstr[SHORT_STRING], buf[LONG_STRING], tmpbuf[STRING];
430 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
435 int (*f) (const void *, const void *);
442 for (i = 0, kp = keys; kp; kp = kp->next) {
443 if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE)) {
448 for (a = kp->address; a; a = a->next) {
449 if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE)) {
456 mem_realloc (&KeyTable, sizeof (pgp_uid_t *) * keymax);
463 if (!i && unusable) {
464 mutt_error _("All matching keys are expired, revoked, or disabled.");
470 switch (PgpSortKeys & SORT_MASK) {
472 f = pgp_compare_date;
475 f = pgp_compare_keyid;
478 f = pgp_compare_address;
482 f = pgp_compare_trust;
485 qsort (KeyTable, i, sizeof (pgp_uid_t *), f);
488 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT);
489 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
490 mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP,
491 OP_GENERIC_SELECT_ENTRY);
492 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
493 mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP,
495 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
496 mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP);
497 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
499 menu = mutt_new_menu ();
501 menu->make_entry = pgp_entry;
502 menu->menu = MENU_PGP;
503 menu->help = helpstr;
504 menu->data = KeyTable;
507 snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox);
509 snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s);
519 switch (mutt_menuLoop (menu)) {
523 mutt_mktemp (tempfile);
524 if ((devnull = fopen ("/dev/null", "w")) == NULL) { /* __FOPEN_CHECKED__ */
525 mutt_perror (_("Can't open /dev/null"));
529 if ((fp = safe_fopen (tempfile, "w")) == NULL) {
531 mutt_perror (_("Can't create temporary file"));
536 mutt_message _("Invoking PGP...");
538 snprintf (tmpbuf, sizeof (tmpbuf), "0x%s",
539 pgp_keyid (pgp_principal_key
540 (KeyTable[menu->current]->parent)));
542 if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1,
543 fileno (fp), fileno (devnull),
545 mutt_perror (_("Can't create filter"));
552 mutt_wait_filter (thepid);
556 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),
557 pgp_keyid (pgp_principal_key
558 (KeyTable[menu->current]->parent)));
559 mutt_do_pager (cmd, tempfile, 0, NULL);
560 menu->redraw = REDRAW_FULL;
566 mutt_message ("%s", KeyTable[menu->current]->addr);
569 case OP_GENERIC_SELECT_ENTRY:
572 /* XXX make error reporting more verbose */
574 if (option (OPTPGPCHECKTRUST))
575 if (!pgp_key_is_valid (KeyTable[menu->current]->parent)) {
576 mutt_error _("This key can't be used: expired/disabled/revoked.");
581 if (option (OPTPGPCHECKTRUST) &&
582 (!pgp_id_is_valid (KeyTable[menu->current])
583 || !pgp_id_is_strong (KeyTable[menu->current]))) {
585 char buff[LONG_STRING];
587 if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE)
588 s = N_("ID is expired/disabled/revoked.");
590 switch (KeyTable[menu->current]->trust & 0x03) {
592 s = N_("ID has undefined validity.");
595 s = N_("ID is not valid.");
598 s = N_("ID is only marginally valid.");
602 snprintf (buff, sizeof (buff),
603 _("%s Do you really want to use the key?"), _(s));
605 if (mutt_yesorno (buff, M_NO) != M_YES) {
612 kp = pgp_principal_key (KeyTable[menu->current]->parent);
614 kp = KeyTable[menu->current]->parent;
627 mutt_menuDestroy (&menu);
628 mem_free (&KeyTable);
630 set_option (OPTNEEDREDRAW);
635 pgp_key_t pgp_ask_for_key (char *tag, char *whatfor,
636 short abilities, pgp_ring_t keyring)
639 char resp[SHORT_STRING];
640 struct pgp_cache *l = NULL;
647 for (l = id_defaults; l; l = l->next)
648 if (!str_casecmp (whatfor, l->what)) {
649 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
657 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
662 str_replace (&l->dflt, resp);
664 l = mem_malloc (sizeof (struct pgp_cache));
665 l->next = id_defaults;
667 l->what = str_dup (whatfor);
668 l->dflt = str_dup (resp);
672 if ((key = pgp_getkeybystr (resp, abilities, keyring)))
680 /* generate a public key attachment */
682 BODY *pgp_make_key_attachment (char *tempf)
685 char buff[LONG_STRING];
686 char tempfb[_POSIX_PATH_MAX], tmp[STRING];
693 unset_option (OPTPGPCHECKTRUST);
696 pgp_ask_for_key (_("Please enter the key ID: "), NULL, 0, PGP_PUBRING);
701 snprintf (tmp, sizeof (tmp), "0x%s", pgp_keyid (pgp_principal_key (key)));
705 mutt_mktemp (tempfb);
709 if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL) {
710 mutt_perror (_("Can't create temporary file"));
715 if ((devnull = fopen ("/dev/null", "w")) == NULL) { /* __FOPEN_CHECKED__ */
716 mutt_perror (_("Can't open /dev/null"));
724 mutt_message _("Invoking pgp...");
728 pgp_invoke_export (NULL, NULL, NULL, -1,
729 fileno (tempfp), fileno (devnull), tmp)) == -1) {
730 mutt_perror (_("Can't create filter"));
738 mutt_wait_filter (thepid);
743 att = mutt_new_body ();
744 att->filename = str_dup (tempf);
747 att->type = TYPEAPPLICATION;
748 att->subtype = str_dup ("pgp-keys");
749 snprintf (buff, sizeof (buff), _("PGP Key %s."), tmp);
750 att->description = str_dup (buff);
751 mutt_update_encoding (att);
754 att->length = sb.st_size;
759 static LIST *pgp_add_string_to_hints (LIST * hints, const char *str)
764 if ((scratch = str_dup (str)) == NULL)
767 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
768 t = strtok (NULL, " ,.:\"()<>\n")) {
770 hints = mutt_add_list (hints, t);
777 static pgp_key_t *pgp_get_lastp (pgp_key_t p)
779 for (; p; p = p->next)
786 pgp_key_t pgp_getkeybyaddr (ADDRESS * a, short abilities, pgp_ring_t keyring)
794 int this_key_has_strong;
795 int this_key_has_weak;
796 int this_key_has_invalid;
799 pgp_key_t keys, k, kn;
800 pgp_key_t the_valid_key = NULL;
801 pgp_key_t matches = NULL;
802 pgp_key_t *last = &matches;
806 hints = pgp_add_string_to_hints (hints, a->mailbox);
807 if (a && a->personal)
808 hints = pgp_add_string_to_hints (hints, a->personal);
810 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
811 keys = pgp_get_candidates (keyring, hints);
813 mutt_free_list (&hints);
818 debug_print (5, ("looking for %s <%s>\n", a->personal, a->mailbox));
820 for (k = keys; k; k = kn) {
823 debug_print (5, (" looking at key: %s\n", pgp_keyid (k)));
825 if (abilities && !(k->flags & abilities)) {
826 debug_print (5, (" insufficient abilities: Has %x, want %x\n",
827 k->flags, abilities));
831 this_key_has_weak = 0; /* weak but valid match */
832 this_key_has_invalid = 0; /* invalid match */
833 this_key_has_strong = 0; /* strong and valid match */
834 match = 0; /* any match */
836 for (q = k->address; q; q = q->next) {
837 r = rfc822_parse_adrlist (NULL, q->addr);
839 for (p = r; p; p = p->next) {
840 int validity = pgp_id_matches_addr (a, p, q);
842 if (validity & PGP_KV_MATCH) /* something matches */
845 /* is this key a strong candidate? */
846 if ((validity & PGP_KV_VALID) && (validity & PGP_KV_STRONGID)
847 && (validity & PGP_KV_ADDR)) {
848 if (the_valid_key && the_valid_key != k)
851 this_key_has_strong = 1;
853 else if ((validity & PGP_KV_MATCH) && !(validity & PGP_KV_VALID))
854 this_key_has_invalid = 1;
855 else if ((validity & PGP_KV_MATCH)
856 && (!(validity & PGP_KV_STRONGID)
857 || !(validity & PGP_KV_ADDR)))
858 this_key_has_weak = 1;
861 rfc822_free_address (&r);
864 if (match && !this_key_has_strong && this_key_has_invalid)
866 if (match && !this_key_has_strong && this_key_has_weak)
870 *last = pgp_principal_key (k);
871 kn = pgp_remove_key (&keys, *last);
872 last = pgp_get_lastp (k);
876 pgp_free_key (&keys);
879 if (the_valid_key && !multi /* && !weak
880 && !(invalid && option (OPTPGPSHOWUNUSABLE)) */ ) {
882 * There was precisely one strong match on a valid ID.
884 * Proceed without asking the user.
886 pgp_remove_key (&matches, the_valid_key);
887 pgp_free_key (&matches);
892 * Else: Ask the user.
894 if ((k = pgp_select_key (matches, a, NULL)))
895 pgp_remove_key (&matches, k);
896 pgp_free_key (&matches);
905 pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring)
909 pgp_key_t matches = NULL;
910 pgp_key_t *last = &matches;
915 mutt_message (_("Looking for keys matching \"%s\"..."), p);
917 hints = pgp_add_string_to_hints (hints, p);
918 keys = pgp_get_candidates (keyring, hints);
919 mutt_free_list (&hints);
925 for (k = keys; k; k = kn) {
927 if (abilities && !(k->flags & abilities))
932 for (a = k->address; a; a = a->next) {
933 debug_print (5, ("matching \"%s\" against key %s, \"%s\":\n", p, pgp_keyid (k), a->addr));
934 if (!*p || str_casecmp (p, pgp_keyid (k)) == 0
935 || (!str_ncasecmp (p, "0x", 2)
936 && !str_casecmp (p + 2, pgp_keyid (k)))
937 || (option (OPTPGPLONGIDS) && !str_ncasecmp (p, "0x", 2)
938 && !str_casecmp (p + 2, k->keyid + 8))
939 || str_isstr (a->addr, p)) {
940 debug_print (5, ("match.\n"));
947 *last = pgp_principal_key (k);
948 kn = pgp_remove_key (&keys, *last);
949 last = pgp_get_lastp (k);
953 pgp_free_key (&keys);
956 if ((k = pgp_select_key (matches, NULL, p)))
957 pgp_remove_key (&matches, k);
959 pgp_free_key (&matches);
968 #endif /* CRYPT_BACKEND_CLASSIC_PGP */