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.
16 #include "mutt_curses.h"
17 #include "mutt_menu.h"
32 #ifdef CRYPT_BACKEND_CLASSIC_PGP
37 struct pgp_cache *next;
40 static struct pgp_cache *id_defaults = NULL;
42 static char trust_flags[] = "?- +";
44 static char *pgp_key_abilities (int flags)
48 if (!(flags & KEYFLAG_CANENCRYPT))
50 else if (flags & KEYFLAG_PREFER_SIGNING)
55 if (!(flags & KEYFLAG_CANSIGN))
57 else if (flags & KEYFLAG_PREFER_ENCRYPTION)
67 static char pgp_flags (int flags)
69 if (flags & KEYFLAG_REVOKED)
71 else if (flags & KEYFLAG_EXPIRED)
73 else if (flags & KEYFLAG_DISABLED)
75 else if (flags & KEYFLAG_CRITICAL)
81 static pgp_key_t pgp_principal_key (pgp_key_t key)
83 if (key->flags & KEYFLAG_SUBKEY && key->parent)
90 * Format an entry on the PGP key selection menu.
93 * %k key id %K key id of the principal key
95 * %a algorithm %A algorithm of the princ. key
96 * %l length %L length of the princ. key
97 * %f flags %F flags of the princ. key
98 * %c capabilities %C capabilities of the princ. key
99 * %t trust/validity of the key-uid association
100 * %[...] date of key using strftime(3)
103 typedef struct pgp_entry {
108 static const char *pgp_entry_fmt (char *dest,
113 const char *ifstring,
114 const char *elsestring,
115 unsigned long data, format_flag flags)
122 int optional = (flags & M_FORMAT_OPTIONAL);
124 entry = (pgp_entry_t *) data;
127 pkey = pgp_principal_key (key);
129 if (isupper ((unsigned char) op))
132 kflags = key->flags | (pkey->flags & KEYFLAG_RESTRICTIONS)
135 switch (ascii_tolower (op)) {
140 char buf2[SHORT_STRING], *p;
156 while (len > 0 && *cp != ']') {
165 break; /* not enough space */
175 if (do_locales && Locale)
176 setlocale (LC_TIME, Locale);
178 tm = localtime (&key->gen_time);
180 strftime (buf2, sizeof (buf2), dest, tm);
183 setlocale (LC_TIME, "C");
185 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
186 snprintf (dest, destlen, fmt, buf2);
193 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
194 snprintf (dest, destlen, fmt, entry->num);
199 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
200 snprintf (dest, destlen, fmt, _pgp_keyid (key));
205 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
206 snprintf (dest, destlen, fmt, uid->addr);
211 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
212 snprintf (dest, destlen, fmt, key->algorithm);
217 snprintf (fmt, sizeof (fmt), "%%%sd", prefix);
218 snprintf (dest, destlen, fmt, key->keylen);
223 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
224 snprintf (dest, destlen, fmt, pgp_flags (kflags));
226 else if (!(kflags & (KEYFLAG_RESTRICTIONS)))
231 snprintf (fmt, sizeof (fmt), "%%%ss", prefix);
232 snprintf (dest, destlen, fmt, pgp_key_abilities (kflags));
234 else if (!(kflags & (KEYFLAG_ABILITIES)))
239 snprintf (fmt, sizeof (fmt), "%%%sc", prefix);
240 snprintf (dest, destlen, fmt, trust_flags[uid->trust & 0x03]);
242 else if (!(uid->trust & 0x03))
243 /* undefined trust */
251 mutt_FormatString (dest, destlen, ifstring, mutt_attach_fmt, data, 0);
252 else if (flags & M_FORMAT_OPTIONAL)
253 mutt_FormatString (dest, destlen, elsestring, mutt_attach_fmt, data, 0);
257 static void pgp_entry (char *s, size_t l, MUTTMENU * menu, int num)
259 pgp_uid_t **KeyTable = (pgp_uid_t **) menu->data;
262 entry.uid = KeyTable[num];
265 mutt_FormatString (s, l, NONULL (PgpEntryFormat), pgp_entry_fmt,
266 (unsigned long) &entry, M_FORMAT_ARROWCURSOR);
269 static int _pgp_compare_address (const void *a, const void *b)
273 pgp_uid_t **s = (pgp_uid_t **) a;
274 pgp_uid_t **t = (pgp_uid_t **) b;
276 if ((r = mutt_strcasecmp ((*s)->addr, (*t)->addr)))
279 return (mutt_strcasecmp (_pgp_keyid ((*s)->parent),
280 _pgp_keyid ((*t)->parent)) > 0);
283 static int pgp_compare_address (const void *a, const void *b)
285 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_address (a, b)
286 : _pgp_compare_address (a, b));
291 static int _pgp_compare_keyid (const void *a, const void *b)
295 pgp_uid_t **s = (pgp_uid_t **) a;
296 pgp_uid_t **t = (pgp_uid_t **) b;
298 if ((r = mutt_strcasecmp (_pgp_keyid ((*s)->parent),
299 _pgp_keyid ((*t)->parent))))
302 return (mutt_strcasecmp ((*s)->addr, (*t)->addr)) > 0;
305 static int pgp_compare_keyid (const void *a, const void *b)
307 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_keyid (a, b)
308 : _pgp_compare_keyid (a, b));
311 static int _pgp_compare_date (const void *a, const void *b)
314 pgp_uid_t **s = (pgp_uid_t **) a;
315 pgp_uid_t **t = (pgp_uid_t **) b;
317 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
319 return (mutt_strcasecmp ((*s)->addr, (*t)->addr)) > 0;
322 static int pgp_compare_date (const void *a, const void *b)
324 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_date (a, b)
325 : _pgp_compare_date (a, b));
328 static int _pgp_compare_trust (const void *a, const void *b)
332 pgp_uid_t **s = (pgp_uid_t **) a;
333 pgp_uid_t **t = (pgp_uid_t **) b;
335 if ((r = (((*s)->parent->flags & (KEYFLAG_RESTRICTIONS))
336 - ((*t)->parent->flags & (KEYFLAG_RESTRICTIONS)))))
338 if ((r = ((*s)->trust - (*t)->trust)))
340 if ((r = ((*s)->parent->keylen - (*t)->parent->keylen)))
342 if ((r = ((*s)->parent->gen_time - (*t)->parent->gen_time)))
344 if ((r = mutt_strcasecmp ((*s)->addr, (*t)->addr)))
346 return (mutt_strcasecmp (_pgp_keyid ((*s)->parent),
347 _pgp_keyid ((*t)->parent))) > 0;
350 static int pgp_compare_trust (const void *a, const void *b)
352 return ((PgpSortKeys & SORT_REVERSE) ? !_pgp_compare_trust (a, b)
353 : _pgp_compare_trust (a, b));
356 static int pgp_key_is_valid (pgp_key_t k)
358 pgp_key_t pk = pgp_principal_key (k);
360 if (k->flags & KEYFLAG_CANTUSE)
362 if (pk->flags & KEYFLAG_CANTUSE)
368 static int pgp_id_is_strong (pgp_uid_t * uid)
370 if ((uid->trust & 3) < 3)
376 static int pgp_id_is_valid (pgp_uid_t * uid)
378 if (!pgp_key_is_valid (uid->parent))
380 if (uid->flags & KEYFLAG_CANTUSE)
386 #define PGP_KV_VALID 1
387 #define PGP_KV_ADDR 2
388 #define PGP_KV_STRING 4
389 #define PGP_KV_STRONGID 8
391 #define PGP_KV_MATCH (PGP_KV_ADDR|PGP_KV_STRING)
393 static int pgp_id_matches_addr (ADDRESS * addr, ADDRESS * u_addr,
398 if (pgp_id_is_valid (uid))
401 if (pgp_id_is_strong (uid))
402 rv |= PGP_KV_STRONGID;
404 if (addr->mailbox && u_addr->mailbox
405 && mutt_strcasecmp (addr->mailbox, u_addr->mailbox) == 0)
408 if (addr->personal && u_addr->personal
409 && mutt_strcasecmp (addr->personal, u_addr->personal) == 0)
415 static pgp_key_t pgp_select_key (pgp_key_t keys, ADDRESS * p, const char *s)
418 pgp_uid_t **KeyTable;
421 char helpstr[SHORT_STRING], buf[LONG_STRING], tmpbuf[STRING];
422 char cmd[LONG_STRING], tempfile[_POSIX_PATH_MAX];
427 int (*f) (const void *, const void *);
434 for (i = 0, kp = keys; kp; kp = kp->next) {
435 if (!option (OPTPGPSHOWUNUSABLE) && (kp->flags & KEYFLAG_CANTUSE)) {
440 for (a = kp->address; a; a = a->next) {
441 if (!option (OPTPGPSHOWUNUSABLE) && (a->flags & KEYFLAG_CANTUSE)) {
448 safe_realloc (&KeyTable, sizeof (pgp_uid_t *) * keymax);
455 if (!i && unusable) {
456 mutt_error _("All matching keys are expired, revoked, or disabled.");
462 switch (PgpSortKeys & SORT_MASK) {
464 f = pgp_compare_date;
467 f = pgp_compare_keyid;
470 f = pgp_compare_address;
474 f = pgp_compare_trust;
477 qsort (KeyTable, i, sizeof (pgp_uid_t *), f);
480 mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_PGP, OP_EXIT);
481 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
482 mutt_make_help (buf, sizeof (buf), _("Select "), MENU_PGP,
483 OP_GENERIC_SELECT_ENTRY);
484 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
485 mutt_make_help (buf, sizeof (buf), _("Check key "), MENU_PGP,
487 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
488 mutt_make_help (buf, sizeof (buf), _("Help"), MENU_PGP, OP_HELP);
489 strcat (helpstr, buf); /* __STRCAT_CHECKED__ */
491 menu = mutt_new_menu ();
493 menu->make_entry = pgp_entry;
494 menu->menu = MENU_PGP;
495 menu->help = helpstr;
496 menu->data = KeyTable;
499 snprintf (buf, sizeof (buf), _("PGP keys matching <%s>."), p->mailbox);
501 snprintf (buf, sizeof (buf), _("PGP keys matching \"%s\"."), s);
511 switch (mutt_menuLoop (menu)) {
515 mutt_mktemp (tempfile);
516 if ((devnull = fopen ("/dev/null", "w")) == NULL) { /* __FOPEN_CHECKED__ */
517 mutt_perror _("Can't open /dev/null");
521 if ((fp = safe_fopen (tempfile, "w")) == NULL) {
523 mutt_perror _("Can't create temporary file");
528 mutt_message _("Invoking PGP...");
530 snprintf (tmpbuf, sizeof (tmpbuf), "0x%s",
531 pgp_keyid (pgp_principal_key
532 (KeyTable[menu->current]->parent)));
534 if ((thepid = pgp_invoke_verify_key (NULL, NULL, NULL, -1,
535 fileno (fp), fileno (devnull),
537 mutt_perror _("Can't create filter");
544 mutt_wait_filter (thepid);
548 snprintf (cmd, sizeof (cmd), _("Key ID: 0x%s"),
549 pgp_keyid (pgp_principal_key
550 (KeyTable[menu->current]->parent)));
551 mutt_do_pager (cmd, tempfile, 0, NULL);
552 menu->redraw = REDRAW_FULL;
558 mutt_message ("%s", KeyTable[menu->current]->addr);
561 case OP_GENERIC_SELECT_ENTRY:
564 /* XXX make error reporting more verbose */
566 if (option (OPTPGPCHECKTRUST))
567 if (!pgp_key_is_valid (KeyTable[menu->current]->parent)) {
568 mutt_error _("This key can't be used: expired/disabled/revoked.");
573 if (option (OPTPGPCHECKTRUST) &&
574 (!pgp_id_is_valid (KeyTable[menu->current])
575 || !pgp_id_is_strong (KeyTable[menu->current]))) {
577 char buff[LONG_STRING];
579 if (KeyTable[menu->current]->flags & KEYFLAG_CANTUSE)
580 s = N_("ID is expired/disabled/revoked.");
582 switch (KeyTable[menu->current]->trust & 0x03) {
584 s = N_("ID has undefined validity.");
587 s = N_("ID is not valid.");
590 s = N_("ID is only marginally valid.");
594 snprintf (buff, sizeof (buff),
595 _("%s Do you really want to use the key?"), _(s));
597 if (mutt_yesorno (buff, M_NO) != M_YES) {
604 kp = pgp_principal_key (KeyTable[menu->current]->parent);
606 kp = KeyTable[menu->current]->parent;
619 mutt_menuDestroy (&menu);
622 set_option (OPTNEEDREDRAW);
627 pgp_key_t pgp_ask_for_key (char *tag, char *whatfor,
628 short abilities, pgp_ring_t keyring)
631 char resp[SHORT_STRING];
632 struct pgp_cache *l = NULL;
639 for (l = id_defaults; l; l = l->next)
640 if (!mutt_strcasecmp (whatfor, l->what)) {
641 strfcpy (resp, NONULL (l->dflt), sizeof (resp));
649 if (mutt_get_field (tag, resp, sizeof (resp), M_CLEAR) != 0)
654 mutt_str_replace (&l->dflt, resp);
656 l = safe_malloc (sizeof (struct pgp_cache));
657 l->next = id_defaults;
659 l->what = safe_strdup (whatfor);
660 l->dflt = safe_strdup (resp);
664 if ((key = pgp_getkeybystr (resp, abilities, keyring)))
672 /* generate a public key attachment */
674 BODY *pgp_make_key_attachment (char *tempf)
677 char buff[LONG_STRING];
678 char tempfb[_POSIX_PATH_MAX], tmp[STRING];
685 unset_option (OPTPGPCHECKTRUST);
688 pgp_ask_for_key (_("Please enter the key ID: "), NULL, 0, PGP_PUBRING);
693 snprintf (tmp, sizeof (tmp), "0x%s", pgp_keyid (pgp_principal_key (key)));
697 mutt_mktemp (tempfb);
701 if ((tempfp = safe_fopen (tempf, tempf == tempfb ? "w" : "a")) == NULL) {
702 mutt_perror _("Can't create temporary file");
707 if ((devnull = fopen ("/dev/null", "w")) == NULL) { /* __FOPEN_CHECKED__ */
708 mutt_perror _("Can't open /dev/null");
716 mutt_message _("Invoking pgp...");
720 pgp_invoke_export (NULL, NULL, NULL, -1,
721 fileno (tempfp), fileno (devnull), tmp)) == -1) {
722 mutt_perror _("Can't create filter");
730 mutt_wait_filter (thepid);
735 att = mutt_new_body ();
736 att->filename = safe_strdup (tempf);
739 att->type = TYPEAPPLICATION;
740 att->subtype = safe_strdup ("pgp-keys");
741 snprintf (buff, sizeof (buff), _("PGP Key %s."), tmp);
742 att->description = safe_strdup (buff);
743 mutt_update_encoding (att);
746 att->length = sb.st_size;
751 static LIST *pgp_add_string_to_hints (LIST * hints, const char *str)
756 if ((scratch = safe_strdup (str)) == NULL)
759 for (t = strtok (scratch, " ,.:\"()<>\n"); t;
760 t = strtok (NULL, " ,.:\"()<>\n")) {
762 hints = mutt_add_list (hints, t);
769 static pgp_key_t *pgp_get_lastp (pgp_key_t p)
771 for (; p; p = p->next)
778 pgp_key_t pgp_getkeybyaddr (ADDRESS * a, short abilities, pgp_ring_t keyring)
786 int this_key_has_strong;
787 int this_key_has_weak;
788 int this_key_has_invalid;
791 pgp_key_t keys, k, kn;
792 pgp_key_t the_valid_key = NULL;
793 pgp_key_t matches = NULL;
794 pgp_key_t *last = &matches;
798 hints = pgp_add_string_to_hints (hints, a->mailbox);
799 if (a && a->personal)
800 hints = pgp_add_string_to_hints (hints, a->personal);
802 mutt_message (_("Looking for keys matching \"%s\"..."), a->mailbox);
803 keys = pgp_get_candidates (keyring, hints);
805 mutt_free_list (&hints);
810 dprint (5, (debugfile, "pgp_getkeybyaddr: looking for %s <%s>.",
811 a->personal, a->mailbox));
814 for (k = keys; k; k = kn) {
817 dprint (5, (debugfile, " looking at key: %s\n", pgp_keyid (k)));
819 if (abilities && !(k->flags & abilities)) {
820 dprint (5, (debugfile, " insufficient abilities: Has %x, want %x\n",
821 k->flags, abilities));
825 this_key_has_weak = 0; /* weak but valid match */
826 this_key_has_invalid = 0; /* invalid match */
827 this_key_has_strong = 0; /* strong and valid match */
828 match = 0; /* any match */
830 for (q = k->address; q; q = q->next) {
831 r = rfc822_parse_adrlist (NULL, q->addr);
833 for (p = r; p; p = p->next) {
834 int validity = pgp_id_matches_addr (a, p, q);
836 if (validity & PGP_KV_MATCH) /* something matches */
839 /* is this key a strong candidate? */
840 if ((validity & PGP_KV_VALID) && (validity & PGP_KV_STRONGID)
841 && (validity & PGP_KV_ADDR)) {
842 if (the_valid_key && the_valid_key != k)
845 this_key_has_strong = 1;
847 else if ((validity & PGP_KV_MATCH) && !(validity & PGP_KV_VALID))
848 this_key_has_invalid = 1;
849 else if ((validity & PGP_KV_MATCH)
850 && (!(validity & PGP_KV_STRONGID)
851 || !(validity & PGP_KV_ADDR)))
852 this_key_has_weak = 1;
855 rfc822_free_address (&r);
858 if (match && !this_key_has_strong && this_key_has_invalid)
860 if (match && !this_key_has_strong && this_key_has_weak)
864 *last = pgp_principal_key (k);
865 kn = pgp_remove_key (&keys, *last);
866 last = pgp_get_lastp (k);
870 pgp_free_key (&keys);
873 if (the_valid_key && !multi /* && !weak
874 && !(invalid && option (OPTPGPSHOWUNUSABLE)) */ ) {
876 * There was precisely one strong match on a valid ID.
878 * Proceed without asking the user.
880 pgp_remove_key (&matches, the_valid_key);
881 pgp_free_key (&matches);
886 * Else: Ask the user.
888 if ((k = pgp_select_key (matches, a, NULL)))
889 pgp_remove_key (&matches, k);
890 pgp_free_key (&matches);
899 pgp_key_t pgp_getkeybystr (char *p, short abilities, pgp_ring_t keyring)
903 pgp_key_t matches = NULL;
904 pgp_key_t *last = &matches;
909 mutt_message (_("Looking for keys matching \"%s\"..."), p);
911 hints = pgp_add_string_to_hints (hints, p);
912 keys = pgp_get_candidates (keyring, hints);
913 mutt_free_list (&hints);
919 for (k = keys; k; k = kn) {
921 if (abilities && !(k->flags & abilities))
926 for (a = k->address; a; a = a->next) {
929 "pgp_getkeybystr: matching \"%s\" against key %s, \"%s\": ", p,
930 pgp_keyid (k), a->addr));
931 if (!*p || mutt_strcasecmp (p, pgp_keyid (k)) == 0
932 || (!mutt_strncasecmp (p, "0x", 2)
933 && !mutt_strcasecmp (p + 2, pgp_keyid (k)))
934 || (option (OPTPGPLONGIDS) && !mutt_strncasecmp (p, "0x", 2)
935 && !mutt_strcasecmp (p + 2, k->keyid + 8))
936 || mutt_stristr (a->addr, p)) {
937 dprint (5, (debugfile, "match.\n"));
944 *last = pgp_principal_key (k);
945 kn = pgp_remove_key (&keys, *last);
946 last = pgp_get_lastp (k);
950 pgp_free_key (&keys);
953 if ((k = pgp_select_key (matches, NULL, p)))
954 pgp_remove_key (&matches, k);
956 pgp_free_key (&matches);
965 #endif /* CRYPT_BACKEND_CLASSIC_PGP */