NeoMutt  2019-12-07-168-gc45f47
Teaching an old dog new tricks
DOXYGEN
crypt_gpgme.c
Go to the documentation of this file.
1 
37 #include "config.h"
38 #include <ctype.h>
39 #include <errno.h>
40 #include <gpg-error.h>
41 #include <gpgme.h>
42 #include <langinfo.h>
43 #include <limits.h>
44 #include <locale.h>
45 #include <stdbool.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <sys/stat.h>
51 #include <time.h>
52 #include <unistd.h>
53 #include "mutt/lib.h"
54 #include "address/lib.h"
55 #include "config/lib.h"
56 #include "email/lib.h"
57 #include "gui/lib.h"
58 #include "mutt.h"
59 #include "crypt_gpgme.h"
60 #include "lib.h"
61 #include "alias.h"
62 #include "crypt.h"
63 #include "format_flags.h"
64 #include "globals.h"
65 #include "handler.h"
66 #include "hook.h"
67 #include "keymap.h"
68 #include "mutt_attach.h"
69 #include "mutt_logging.h"
70 #include "mutt_menu.h"
71 #include "muttlib.h"
72 #include "opcodes.h"
73 #include "options.h"
74 #include "pager.h"
75 #include "protos.h"
76 #include "recvattach.h"
77 #include "sendlib.h"
78 #include "sort.h"
79 #include "state.h"
80 #ifdef ENABLE_NLS
81 #include <libintl.h>
82 #endif
83 
84 struct Mailbox;
85 
86 // clang-format off
87 /* Values used for comparing addresses. */
88 #define CRYPT_KV_VALID (1 << 0)
89 #define CRYPT_KV_ADDR (1 << 1)
90 #define CRYPT_KV_STRING (1 << 2)
91 #define CRYPT_KV_STRONGID (1 << 3)
92 #define CRYPT_KV_MATCH (CRYPT_KV_ADDR | CRYPT_KV_STRING)
93 // clang-format on
94 
98 struct CryptCache
99 {
100  char *what;
101  char *dflt;
102  struct CryptCache *next;
103 };
104 
108 struct DnArray
109 {
110  char *key;
111  char *value;
112 };
113 
114 /* We work based on user IDs, getting from a user ID to the key is
115  * check and does not need any memory (gpgme uses reference counting). */
120 {
122  gpgme_key_t kobj;
123  int idx;
124  const char *uid;
126  gpgme_validity_t validity;
127 };
128 
133 {
134  size_t num;
135  struct CryptKeyInfo *key;
136 };
137 
138 static struct CryptCache *id_defaults = NULL;
139 static gpgme_key_t signature_key = NULL;
140 static char *current_sender = NULL;
141 
142 #define PKA_NOTATION_NAME "pka-address@gnupg.org"
143 
144 #define _LINE_COMPARE(_x, _y) line_compare(_x, sizeof(_x) - 1, _y)
145 #define MESSAGE(_y) _LINE_COMPARE("MESSAGE-----", _y)
146 #define SIGNED_MESSAGE(_y) _LINE_COMPARE("SIGNED MESSAGE-----", _y)
147 #define PUBLIC_KEY_BLOCK(_y) _LINE_COMPARE("PUBLIC KEY BLOCK-----", _y)
148 #define BEGIN_PGP_SIGNATURE(_y) \
149  _LINE_COMPARE("-----BEGIN PGP SIGNATURE-----", _y)
150 
154 enum KeyCap
155 {
159 };
160 
165 {
166  KIP_NAME = 0,
177 };
178 
179 static const char *const KeyInfoPrompts[] = {
180  /* L10N: The following are the headers for the "verify key" output from the
181  GPGME key selection menu (bound to "c" in the key selection menu).
182  They will be automatically aligned. */
183  N_("Name: "), N_("aka: "), N_("Valid From: "), N_("Valid To: "),
184  N_("Key Type: "), N_("Key Usage: "), N_("Fingerprint: "), N_("Serial-No: "),
185  N_("Issued By: "), N_("Subkey: ")
186 };
187 
188 int KeyInfoPadding[KIP_MAX] = { 0 };
189 
195 static bool is_pka_notation(gpgme_sig_notation_t notation)
196 {
197  return mutt_str_strcmp(notation->name, PKA_NOTATION_NAME) == 0;
198 }
199 
204 static void redraw_if_needed(gpgme_ctx_t ctx)
205 {
206 #if (GPGME_VERSION_NUMBER < 0x010800)
207  /* gpgme_get_ctx_flag is not available in gpgme < 1.8.0. In this case, stay
208  * on the safe side and always redraw. */
209  (void) ctx;
211 #else
212  const char *s = gpgme_get_ctx_flag(ctx, "redraw");
213  if (!s /* flag not known */ || *s /* flag true */)
214  {
216  }
217 #endif
218 }
219 
225 static int digit(const char *s)
226 {
227  return (*s >= '0' && *s <= '9');
228 }
229 
235 static int digit_or_letter(const char *s)
236 {
237  return digit(s) || (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z');
238 }
239 
248 static void print_utf8(FILE *fp, const char *buf, size_t len)
249 {
250  char *tstr = mutt_mem_malloc(len + 1);
251  memcpy(tstr, buf, len);
252  tstr[len] = 0;
253 
254  /* fromcode "utf-8" is sure, so we don't want
255  * charset-hook corrections: flags must be 0. */
256  mutt_ch_convert_string(&tstr, "utf-8", C_Charset, 0);
257  fputs(tstr, fp);
258  FREE(&tstr);
259 }
260 
261 #if GPGRT_VERSION_NUMBER >= 0x012100 /* libgpg-error >= 1.33 */
262 
280 static int cmp_version_strings(const char *a, const char *b, int level)
281 {
282  return gpgrt_cmp_version(a, b, level);
283 }
284 #elif (GPGME_VERSION_NUMBER >= 0x010900) /* gpgme >= 1.9.0 */
285 
298 static const char *parse_version_number(const char *s, int *number)
299 {
300  int val = 0;
301 
302  if ((*s == '0') && digit(s + 1))
303  return NULL; /* Leading zeros are not allowed. */
304  for (; digit(s); s++)
305  {
306  val *= 10;
307  val += *s - '0';
308  }
309  *number = val;
310  return (val < 0) ? NULL : s;
311 }
312 
331 static const char *parse_version_string(const char *s, int *major, int *minor, int *micro)
332 {
333  s = parse_version_number(s, major);
334  if (!s)
335  return NULL;
336  if (minor)
337  {
338  if (*s != '.')
339  return NULL;
340  s++;
341  s = parse_version_number(s, minor);
342  if (!s)
343  return NULL;
344  if (micro)
345  {
346  if (*s != '.')
347  return NULL;
348  s++;
349  s = parse_version_number(s, micro);
350  if (!s)
351  return NULL;
352  }
353  else
354  {
355  if (*s == '.')
356  s++;
357  }
358  }
359  else
360  {
361  if (*s == '.')
362  s++;
363  }
364  return s; /* patchlevel */
365 }
366 
376 static int cmp_version_strings(const char *a, const char *b, int level)
377 {
378  int a_major, a_minor, a_micro;
379  int b_major, b_minor, b_micro;
380  const char *a_plvl = NULL, *b_plvl = NULL;
381  int r;
382  int ignore_plvl;
383  int positive, negative;
384 
385  if (level < 0)
386  {
387  positive = -1;
388  negative = 1;
389  level = 0 - level;
390  }
391  else
392  {
393  positive = 1;
394  negative = -1;
395  }
396  if ((ignore_plvl = (level > 9)))
397  level %= 10;
398 
399  a_major = a_minor = a_micro = 0;
400  a_plvl = parse_version_string(a, &a_major, (level > 1) ? &a_minor : NULL,
401  (level > 2) ? &a_micro : NULL);
402  if (!a_plvl)
403  a_major = a_minor = a_micro = 0; /* Error. */
404 
405  b_major = b_minor = b_micro = 0;
406  b_plvl = parse_version_string(b, &b_major, (level > 1) ? &b_minor : NULL,
407  (level > 2) ? &b_micro : NULL);
408  if (!b_plvl)
409  b_major = b_minor = b_micro = 0;
410 
411  if (!ignore_plvl)
412  {
413  if (!a_plvl && !b_plvl)
414  return negative; /* Put invalid strings at the end. */
415  if (a_plvl && !b_plvl)
416  return positive;
417  if (!a_plvl && b_plvl)
418  return negative;
419  }
420 
421  if (a_major > b_major)
422  return positive;
423  if (a_major < b_major)
424  return negative;
425 
426  if (a_minor > b_minor)
427  return positive;
428  if (a_minor < b_minor)
429  return negative;
430 
431  if (a_micro > b_micro)
432  return positive;
433  if (a_micro < b_micro)
434  return negative;
435 
436  if (ignore_plvl)
437  return 0;
438 
439  for (; *a_plvl && *b_plvl; a_plvl++, b_plvl++)
440  {
441  if ((*a_plvl == '.') && (*b_plvl == '.'))
442  {
443  r = strcmp(a_plvl, b_plvl);
444  if (!r)
445  return 0;
446  if (r > 0)
447  return positive;
448  return negative;
449  }
450  if (*a_plvl == '.')
451  return negative; /* B is larger. */
452  if (*b_plvl == '.')
453  return positive; /* A is larger. */
454  if (*a_plvl != *b_plvl)
455  break;
456  }
457  if (*a_plvl == *b_plvl)
458  return 0;
459  if ((*(signed char *) a_plvl - *(signed char *) b_plvl) > 0)
460  return positive;
461  return negative;
462 }
463 #endif /* gpgme >= 1.9.0 */
464 
473 static const char *crypt_keyid(struct CryptKeyInfo *k)
474 {
475  const char *s = "????????";
476 
477  if (k->kobj && k->kobj->subkeys)
478  {
479  s = k->kobj->subkeys->keyid;
480  if ((!C_PgpLongIds) && (strlen(s) == 16))
481  {
482  /* Return only the short keyID. */
483  s += 8;
484  }
485  }
486 
487  return s;
488 }
489 
497 static const char *crypt_long_keyid(struct CryptKeyInfo *k)
498 {
499  const char *s = "????????????????";
500 
501  if (k->kobj && k->kobj->subkeys)
502  {
503  s = k->kobj->subkeys->keyid;
504  }
505 
506  return s;
507 }
508 
514 static const char *crypt_short_keyid(struct CryptKeyInfo *k)
515 {
516  const char *s = "????????";
517 
518  if (k->kobj && k->kobj->subkeys)
519  {
520  s = k->kobj->subkeys->keyid;
521  if (strlen(s) == 16)
522  s += 8;
523  }
524 
525  return s;
526 }
527 
533 static const char *crypt_fpr(struct CryptKeyInfo *k)
534 {
535  const char *s = "";
536 
537  if (k->kobj && k->kobj->subkeys)
538  s = k->kobj->subkeys->fpr;
539 
540  return s;
541 }
542 
549 static const char *crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
550 {
551  const char *s = "????????????????";
552 
553  if (k->kobj && k->kobj->subkeys)
554  {
555  if (k->kobj->subkeys->fpr)
556  s = k->kobj->subkeys->fpr;
557  else
558  s = k->kobj->subkeys->keyid;
559  }
560 
561  return s;
562 }
563 
571 static char *crypt_key_abilities(KeyFlags flags)
572 {
573  static char buf[3];
574 
575  if (!(flags & KEYFLAG_CANENCRYPT))
576  buf[0] = '-';
577  else if (flags & KEYFLAG_PREFER_SIGNING)
578  buf[0] = '.';
579  else
580  buf[0] = 'e';
581 
582  if (!(flags & KEYFLAG_CANSIGN))
583  buf[1] = '-';
584  else if (flags & KEYFLAG_PREFER_ENCRYPTION)
585  buf[1] = '.';
586  else
587  buf[1] = 's';
588 
589  buf[2] = '\0';
590 
591  return buf;
592 }
593 
601 static char crypt_flags(KeyFlags flags)
602 {
603  if (flags & KEYFLAG_REVOKED)
604  return 'R';
605  if (flags & KEYFLAG_EXPIRED)
606  return 'X';
607  if (flags & KEYFLAG_DISABLED)
608  return 'd';
609  if (flags & KEYFLAG_CRITICAL)
610  return 'c';
611 
612  return ' ';
613 }
614 
620 static struct CryptKeyInfo *crypt_copy_key(struct CryptKeyInfo *key)
621 {
622  struct CryptKeyInfo *k = NULL;
623 
624  k = mutt_mem_calloc(1, sizeof(*k));
625  k->kobj = key->kobj;
626  gpgme_key_ref(key->kobj);
627  k->idx = key->idx;
628  k->uid = key->uid;
629  k->flags = key->flags;
630  k->validity = key->validity;
631 
632  return k;
633 }
634 
639 static void crypt_key_free(struct CryptKeyInfo **keylist)
640 {
641  if (!keylist)
642  return;
643 
644  struct CryptKeyInfo *k = NULL;
645 
646  while (*keylist)
647  {
648  k = *keylist;
649  *keylist = (*keylist)->next;
650 
651  gpgme_key_unref(k->kobj);
652  FREE(&k);
653  }
654 }
655 
661 static bool crypt_key_is_valid(struct CryptKeyInfo *k)
662 {
663  if (k->flags & KEYFLAG_CANTUSE)
664  return false;
665  return true;
666 }
667 
673 static bool crypt_id_is_strong(struct CryptKeyInfo *key)
674 {
675  if (!key)
676  return false;
677 
678  bool is_strong = false;
679 
680  if ((key->flags & KEYFLAG_ISX509))
681  return true;
682 
683  switch (key->validity)
684  {
685  case GPGME_VALIDITY_MARGINAL:
686  case GPGME_VALIDITY_NEVER:
687  case GPGME_VALIDITY_UNDEFINED:
688  case GPGME_VALIDITY_UNKNOWN:
689  is_strong = false;
690  break;
691 
692  case GPGME_VALIDITY_FULL:
693  case GPGME_VALIDITY_ULTIMATE:
694  is_strong = true;
695  break;
696  }
697 
698  return is_strong;
699 }
700 
708 static int crypt_id_is_valid(struct CryptKeyInfo *key)
709 {
710  if (!key)
711  return 0;
712 
713  return !(key->flags & KEYFLAG_CANTUSE);
714 }
715 
726 static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr,
727  struct CryptKeyInfo *key)
728 {
729  int rc = 0;
730 
731  if (crypt_id_is_valid(key))
732  rc |= CRYPT_KV_VALID;
733 
734  if (crypt_id_is_strong(key))
735  rc |= CRYPT_KV_STRONGID;
736 
737  if (addr && u_addr)
738  {
739  if (addr->mailbox && u_addr->mailbox &&
740  (mutt_str_strcasecmp(addr->mailbox, u_addr->mailbox) == 0))
741  {
742  rc |= CRYPT_KV_ADDR;
743  }
744 
745  if (addr->personal && u_addr->personal &&
746  (mutt_str_strcasecmp(addr->personal, u_addr->personal) == 0))
747  {
748  rc |= CRYPT_KV_STRING;
749  }
750  }
751 
752  return rc;
753 }
754 
760 static gpgme_ctx_t create_gpgme_context(bool for_smime)
761 {
762  gpgme_ctx_t ctx = NULL;
763 
764  gpgme_error_t err = gpgme_new(&ctx);
765 
766 #ifdef USE_AUTOCRYPT
767  if (!err && OptAutocryptGpgme)
768  err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, C_AutocryptDir);
769 #endif
770 
771  if (err != 0)
772  {
773  mutt_error(_("error creating gpgme context: %s"), gpgme_strerror(err));
774  mutt_exit(1);
775  }
776 
777  if (for_smime)
778  {
779  err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
780  if (err != 0)
781  {
782  mutt_error(_("error enabling CMS protocol: %s"), gpgme_strerror(err));
783  mutt_exit(1);
784  }
785  }
786 
787  return ctx;
788 }
789 
798 static gpgme_data_t create_gpgme_data(void)
799 {
800  gpgme_data_t data = NULL;
801 
802  gpgme_error_t err = gpgme_data_new(&data);
803  if (err != 0)
804  {
805  mutt_error(_("error creating gpgme data object: %s"), gpgme_strerror(err));
806  mutt_exit(1);
807  }
808  return data;
809 }
810 
811 #if GPGME_VERSION_NUMBER >= 0x010900 /* gpgme >= 1.9.0 */
812 
819 static bool have_gpg_version(const char *version)
820 {
821  static char *engine_version = NULL;
822 
823  if (!engine_version)
824  {
825  gpgme_ctx_t ctx = NULL;
826  gpgme_engine_info_t engineinfo = NULL;
827 
828  ctx = create_gpgme_context(false);
829  engineinfo = gpgme_ctx_get_engine_info(ctx);
830  while (engineinfo && (engineinfo->protocol != GPGME_PROTOCOL_OpenPGP))
831  engineinfo = engineinfo->next;
832  if (engineinfo)
833  {
834  engine_version = mutt_str_strdup(engineinfo->version);
835  }
836  else
837  {
838  mutt_debug(LL_DEBUG1, "Error finding GPGME PGP engine\n");
839  engine_version = mutt_str_strdup("0.0.0");
840  }
841  gpgme_release(ctx);
842  }
843 
844  return cmp_version_strings(engine_version, version, 3) >= 0;
845 }
846 #endif
847 
854 static gpgme_data_t body_to_data_object(struct Body *a, bool convert)
855 {
856  int err = 0;
857  gpgme_data_t data = NULL;
858 
859  struct Buffer *tempfile = mutt_buffer_pool_get();
860  mutt_buffer_mktemp(tempfile);
861  FILE *fp_tmp = mutt_file_fopen(mutt_b2s(tempfile), "w+");
862  if (!fp_tmp)
863  {
864  mutt_perror(mutt_b2s(tempfile));
865  goto cleanup;
866  }
867 
868  mutt_write_mime_header(a, fp_tmp);
869  fputc('\n', fp_tmp);
870  mutt_write_mime_body(a, fp_tmp);
871 
872  if (convert)
873  {
874  int c, hadcr = 0;
875  unsigned char buf[1];
876 
877  data = create_gpgme_data();
878  rewind(fp_tmp);
879  while ((c = fgetc(fp_tmp)) != EOF)
880  {
881  if (c == '\r')
882  hadcr = 1;
883  else
884  {
885  if ((c == '\n') && !hadcr)
886  {
887  buf[0] = '\r';
888  gpgme_data_write(data, buf, 1);
889  }
890 
891  hadcr = 0;
892  }
893  /* FIXME: This is quite suboptimal */
894  buf[0] = c;
895  gpgme_data_write(data, buf, 1);
896  }
897  mutt_file_fclose(&fp_tmp);
898  gpgme_data_seek(data, 0, SEEK_SET);
899  }
900  else
901  {
902  mutt_file_fclose(&fp_tmp);
903  err = gpgme_data_new_from_file(&data, mutt_b2s(tempfile), 1);
904  if (err != 0)
905  {
906  mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
907  gpgme_data_release(data);
908  data = NULL;
909  /* fall through to unlink the tempfile */
910  }
911  }
912  unlink(mutt_b2s(tempfile));
913 
914 cleanup:
915  mutt_buffer_pool_release(&tempfile);
916  return data;
917 }
918 
926 static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
927 {
928  gpgme_data_t data = NULL;
929 
930  int err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
931  if (err != 0)
932  {
933  mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
934  return NULL;
935  }
936 
937  return data;
938 }
939 
947 static int data_object_to_stream(gpgme_data_t data, FILE *fp)
948 {
949  char buf[4096];
950  ssize_t nread;
951 
952  int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
953  if (err != 0)
954  {
955  mutt_error(_("error rewinding data object: %s"), gpgme_strerror(err));
956  return -1;
957  }
958 
959  while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
960  {
961  /* fixme: we are not really converting CRLF to LF but just
962  * skipping CR. Doing it correctly needs a more complex logic */
963  for (char *p = buf; nread; p++, nread--)
964  {
965  if (*p != '\r')
966  putc(*p, fp);
967  }
968 
969  if (ferror(fp))
970  {
971  mutt_perror(_("[tempfile]"));
972  return -1;
973  }
974  }
975  if (nread == -1)
976  {
977  mutt_error(_("error reading data object: %s"), strerror(errno));
978  return -1;
979  }
980  return 0;
981 }
982 
994 static char *data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
995 {
996  ssize_t nread = 0;
997  char *rv = NULL;
998  struct Buffer *tempf = mutt_buffer_pool_get();
999 
1000  mutt_buffer_mktemp(tempf);
1001 
1002  FILE *fp = mutt_file_fopen(mutt_b2s(tempf), "w+");
1003  if (!fp)
1004  {
1005  mutt_perror(_("Can't create temporary file"));
1006  goto cleanup;
1007  }
1008 
1009  int err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ? gpgme_error_from_errno(errno) : 0);
1010  if (err == 0)
1011  {
1012  char buf[4096];
1013 
1014  while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
1015  {
1016  if (fwrite(buf, nread, 1, fp) != 1)
1017  {
1018  mutt_perror(mutt_b2s(tempf));
1019  mutt_file_fclose(&fp);
1020  unlink(mutt_b2s(tempf));
1021  goto cleanup;
1022  }
1023  }
1024  }
1025  if (fp_ret)
1026  rewind(fp);
1027  else
1028  mutt_file_fclose(&fp);
1029  if (nread == -1)
1030  {
1031  mutt_error(_("error reading data object: %s"), gpgme_strerror(err));
1032  unlink(mutt_b2s(tempf));
1033  mutt_file_fclose(&fp);
1034  goto cleanup;
1035  }
1036  if (fp_ret)
1037  *fp_ret = fp;
1038  rv = mutt_buffer_strdup(tempf);
1039 
1040 cleanup:
1041  mutt_buffer_pool_release(&tempf);
1042  return rv;
1043 }
1044 
1045 #if (GPGME_VERSION_NUMBER >= 0x010b00) /* gpgme >= 1.11.0 */
1046 
1052 static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
1053 {
1054  unsigned int n = 0;
1055 
1056  const char *s = keylist;
1057  do
1058  {
1059  while (*s == ' ')
1060  s++;
1061  if (*s != '\0')
1062  {
1063  if (n == 0)
1064  {
1065  if (!use_smime)
1066  mutt_buffer_addstr(recpstring, "--\n");
1067  }
1068  else
1069  mutt_buffer_addch(recpstring, '\n');
1070  n++;
1071 
1072  while ((*s != '\0') && (*s != ' '))
1073  mutt_buffer_addch(recpstring, *s++);
1074  }
1075  } while (*s != '\0');
1076 }
1077 
1078 #else
1079 
1083 static void recipient_set_free(gpgme_key_t **p_rset)
1084 {
1085  gpgme_key_t *rset = NULL;
1086 
1087  if (!p_rset)
1088  return;
1089 
1090  rset = *p_rset;
1091  if (!rset)
1092  return;
1093 
1094  while (*rset)
1095  {
1096  gpgme_key_t k = *rset;
1097  gpgme_key_unref(k);
1098  rset++;
1099  }
1100 
1101  FREE(p_rset);
1102 }
1103 
1110 static gpgme_key_t *create_recipient_set(const char *keylist, bool use_smime)
1111 {
1112  int err;
1113  const char *s = NULL;
1114  char buf[100];
1115  gpgme_key_t *rset = NULL;
1116  unsigned int rset_n = 0;
1117  gpgme_key_t key = NULL;
1118 
1119  gpgme_ctx_t context = create_gpgme_context(use_smime);
1120  s = keylist;
1121  do
1122  {
1123  while (*s == ' ')
1124  s++;
1125  int i;
1126  for (i = 0; *s && *s != ' ' && i < sizeof(buf) - 1;)
1127  buf[i++] = *s++;
1128  buf[i] = '\0';
1129  if (*buf != '\0')
1130  {
1131  if ((i > 1) && (buf[i - 1] == '!'))
1132  {
1133  /* The user selected to override the validity of that key. */
1134  buf[i - 1] = '\0';
1135 
1136  err = gpgme_get_key(context, buf, &key, 0);
1137  if (err == 0)
1138  key->uids->validity = GPGME_VALIDITY_FULL;
1139  buf[i - 1] = '!';
1140  }
1141  else
1142  err = gpgme_get_key(context, buf, &key, 0);
1143  mutt_mem_realloc(&rset, sizeof(*rset) * (rset_n + 1));
1144  if (err == 0)
1145  rset[rset_n++] = key;
1146  else
1147  {
1148  mutt_error(_("error adding recipient '%s': %s"), buf, gpgme_strerror(err));
1149  rset[rset_n] = NULL;
1150  recipient_set_free(&rset);
1151  gpgme_release(context);
1152  return NULL;
1153  }
1154  }
1155  } while (*s);
1156 
1157  /* NULL terminate. */
1158  mutt_mem_realloc(&rset, sizeof(*rset) * (rset_n + 1));
1159  rset[rset_n++] = NULL;
1160 
1161  gpgme_release(context);
1162 
1163  return rset;
1164 }
1165 #endif /* GPGME_VERSION_NUMBER >= 0x010b00 */
1166 
1175 static bool set_signer_from_address(gpgme_ctx_t ctx, const char *address, bool for_smime)
1176 {
1177  gpgme_error_t err;
1178  gpgme_key_t key = NULL, key2 = NULL;
1179  gpgme_ctx_t listctx = create_gpgme_context(for_smime);
1180  err = gpgme_op_keylist_start(listctx, address, 1);
1181  if (err == 0)
1182  err = gpgme_op_keylist_next(listctx, &key);
1183  if (err)
1184  {
1185  gpgme_release(listctx);
1186  mutt_error(_("secret key '%s' not found: %s"), address, gpgme_strerror(err));
1187  return false;
1188  }
1189 
1190  char *fpr = "fpr1";
1191  if (key->subkeys)
1192  fpr = key->subkeys->fpr ? key->subkeys->fpr : key->subkeys->keyid;
1193  while (gpgme_op_keylist_next(listctx, &key2) == 0)
1194  {
1195  char *fpr2 = "fpr2";
1196  if (key2->subkeys)
1197  fpr2 = key2->subkeys->fpr ? key2->subkeys->fpr : key2->subkeys->keyid;
1198  if (mutt_str_strcmp(fpr, fpr2))
1199  {
1200  gpgme_key_unref(key);
1201  gpgme_key_unref(key2);
1202  gpgme_release(listctx);
1203  mutt_error(_("ambiguous specification of secret key '%s'\n"), address);
1204  return false;
1205  }
1206  else
1207  {
1208  gpgme_key_unref(key2);
1209  }
1210  }
1211  gpgme_op_keylist_end(listctx);
1212  gpgme_release(listctx);
1213 
1214  gpgme_signers_clear(ctx);
1215  err = gpgme_signers_add(ctx, key);
1216  gpgme_key_unref(key);
1217  if (err)
1218  {
1219  mutt_error(_("error setting secret key '%s': %s"), address, gpgme_strerror(err));
1220  return false;
1221  }
1222  return true;
1223 }
1224 
1233 static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
1234 {
1235  char *signid = NULL;
1236 
1237  if (for_smime)
1239 #ifdef USE_AUTOCRYPT
1240  else if (OptAutocryptGpgme)
1241  signid = AutocryptSignAs;
1242 #endif
1243  else
1245 
1246  /* Try getting the signing key from config entries */
1247  if (signid && set_signer_from_address(ctx, signid, for_smime))
1248  {
1249  return 0;
1250  }
1251 
1252  /* Try getting the signing key from the From line */
1253  if (al)
1254  {
1255  struct Address *a;
1256  TAILQ_FOREACH(a, al, entries)
1257  {
1258  if (a->mailbox && set_signer_from_address(ctx, a->mailbox, for_smime))
1259  {
1260  return 0;
1261  }
1262  }
1263  }
1264 
1265  return (!signid && !al) ? 0 : -1;
1266 }
1267 
1273 static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
1274 {
1275  gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, current_sender, 0);
1276  if (err)
1277  {
1278  mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
1279  }
1280 
1281  return err;
1282 }
1283 
1293 static char *encrypt_gpgme_object(gpgme_data_t plaintext, char *keylist, bool use_smime,
1294  bool combined_signed, const struct AddressList *from)
1295 {
1296  gpgme_error_t err;
1297  gpgme_ctx_t ctx = NULL;
1298  gpgme_data_t ciphertext = NULL;
1299  char *outfile = NULL;
1300 
1301 #if GPGME_VERSION_NUMBER >= 0x010b00 /* gpgme >= 1.11.0 */
1302  struct Buffer *recpstring = mutt_buffer_pool_get();
1303  create_recipient_string(keylist, recpstring, use_smime);
1304  if (mutt_buffer_is_empty(recpstring))
1305  {
1306  mutt_buffer_pool_release(&recpstring);
1307  return NULL;
1308  }
1309 #else
1310  gpgme_key_t *rset = create_recipient_set(keylist, use_smime);
1311  if (!rset)
1312  return NULL;
1313 #endif /* GPGME_VERSION_NUMBER >= 0x010b00 */
1314 
1315  ctx = create_gpgme_context(use_smime);
1316  if (!use_smime)
1317  gpgme_set_armor(ctx, 1);
1318 
1319  ciphertext = create_gpgme_data();
1320 
1321  if (combined_signed)
1322  {
1323  if (set_signer(ctx, from, use_smime))
1324  goto cleanup;
1325 
1326  if (C_CryptUsePka)
1327  {
1328  err = set_pka_sig_notation(ctx);
1329  if (err != 0)
1330  goto cleanup;
1331  }
1332 
1333 #if (GPGME_VERSION_NUMBER >= 0x010b00) /* gpgme >= 1.11.0 */
1334  err = gpgme_op_encrypt_sign_ext(ctx, NULL, mutt_b2s(recpstring),
1335  GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1336 #else
1337  err = gpgme_op_encrypt_sign(ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1338 #endif
1339  }
1340  else
1341  {
1342 #if (GPGME_VERSION_NUMBER >= 0x010b00) /* gpgme >= 1.11.0 */
1343  err = gpgme_op_encrypt_ext(ctx, NULL, mutt_b2s(recpstring),
1344  GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1345 #else
1346  err = gpgme_op_encrypt(ctx, rset, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
1347 #endif
1348  }
1349 
1350  redraw_if_needed(ctx);
1351  if (err != 0)
1352  {
1353  mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
1354  goto cleanup;
1355  }
1356 
1357  outfile = data_object_to_tempfile(ciphertext, NULL);
1358 
1359 cleanup:
1360 #if (GPGME_VERSION_NUMBER >= 0x010b00) /* gpgme >= 1.11.0 */
1361  mutt_buffer_pool_release(&recpstring);
1362 #else
1363  recipient_set_free(&rset);
1364 #endif
1365  gpgme_release(ctx);
1366  gpgme_data_release(ciphertext);
1367  return outfile;
1368 }
1369 
1382 static int get_micalg(gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
1383 {
1384  gpgme_sign_result_t result = NULL;
1385  const char *algorithm_name = NULL;
1386 
1387  if (buflen < 5)
1388  return -1;
1389 
1390  *buf = '\0';
1391  result = gpgme_op_sign_result(ctx);
1392  if (result && result->signatures)
1393  {
1394  algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
1395  if (algorithm_name)
1396  {
1397  if (use_smime)
1398  {
1399  /* convert GPGME raw hash name to RFC2633 format */
1400  snprintf(buf, buflen, "%s", algorithm_name);
1401  mutt_str_strlower(buf);
1402  }
1403  else
1404  {
1405  /* convert GPGME raw hash name to RFC3156 format */
1406  snprintf(buf, buflen, "pgp-%s", algorithm_name);
1407  mutt_str_strlower(buf + 4);
1408  }
1409  }
1410  }
1411 
1412  return (buf[0] != '\0') ? 0 : -1;
1413 }
1414 
1420 static void print_time(time_t t, struct State *s)
1421 {
1422  char p[256];
1423  mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
1424  state_puts(s, p);
1425 }
1426 
1435 static struct Body *sign_message(struct Body *a, const struct AddressList *from, bool use_smime)
1436 {
1437  struct Body *t = NULL;
1438  char *sigfile = NULL;
1439  int err = 0;
1440  char buf[100];
1441  gpgme_ctx_t ctx = NULL;
1442  gpgme_data_t message = NULL, signature = NULL;
1443  gpgme_sign_result_t sigres = NULL;
1444 
1445  crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1446 
1447  message = body_to_data_object(a, true);
1448  if (!message)
1449  return NULL;
1450  signature = create_gpgme_data();
1451 
1452  ctx = create_gpgme_context(use_smime);
1453  if (!use_smime)
1454  gpgme_set_armor(ctx, 1);
1455 
1456  if (set_signer(ctx, from, use_smime))
1457  {
1458  gpgme_data_release(signature);
1459  gpgme_data_release(message);
1460  gpgme_release(ctx);
1461  return NULL;
1462  }
1463 
1464  if (C_CryptUsePka)
1465  {
1466  err = set_pka_sig_notation(ctx);
1467  if (err != 0)
1468  {
1469  gpgme_data_release(signature);
1470  gpgme_data_release(message);
1471  gpgme_release(ctx);
1472  return NULL;
1473  }
1474  }
1475 
1476  err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
1477  redraw_if_needed(ctx);
1478  gpgme_data_release(message);
1479  if (err != 0)
1480  {
1481  gpgme_data_release(signature);
1482  gpgme_release(ctx);
1483  mutt_error(_("error signing data: %s"), gpgme_strerror(err));
1484  return NULL;
1485  }
1486  /* Check for zero signatures generated. This can occur when $pgp_sign_as is
1487  * unset and there is no default key specified in ~/.gnupg/gpg.conf */
1488  sigres = gpgme_op_sign_result(ctx);
1489  if (!sigres->signatures)
1490  {
1491  gpgme_data_release(signature);
1492  gpgme_release(ctx);
1493  mutt_error(_("$pgp_sign_as unset and no default key specified in "
1494  "~/.gnupg/gpg.conf"));
1495  return NULL;
1496  }
1497 
1498  sigfile = data_object_to_tempfile(signature, NULL);
1499  gpgme_data_release(signature);
1500  if (!sigfile)
1501  {
1502  gpgme_release(ctx);
1503  return NULL;
1504  }
1505 
1506  t = mutt_body_new();
1507  t->type = TYPE_MULTIPART;
1508  t->subtype = mutt_str_strdup("signed");
1509  t->encoding = ENC_7BIT;
1510  t->use_disp = false;
1511  t->disposition = DISP_INLINE;
1512 
1514  mutt_param_set(&t->parameter, "protocol",
1515  use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
1516  /* Get the micalg from gpgme. Old gpgme versions don't support this
1517  * for S/MIME so we assume sha-1 in this case. */
1518  if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
1519  mutt_param_set(&t->parameter, "micalg", buf);
1520  else if (use_smime)
1521  mutt_param_set(&t->parameter, "micalg", "sha1");
1522  gpgme_release(ctx);
1523 
1524  t->parts = a;
1525  a = t;
1526 
1527  t->parts->next = mutt_body_new();
1528  t = t->parts->next;
1529  t->type = TYPE_APPLICATION;
1530  if (use_smime)
1531  {
1532  t->subtype = mutt_str_strdup("pkcs7-signature");
1533  mutt_param_set(&t->parameter, "name", "smime.p7s");
1534  t->encoding = ENC_BASE64;
1535  t->use_disp = true;
1536  t->disposition = DISP_ATTACH;
1537  t->d_filename = mutt_str_strdup("smime.p7s");
1538  }
1539  else
1540  {
1541  t->subtype = mutt_str_strdup("pgp-signature");
1542  mutt_param_set(&t->parameter, "name", "signature.asc");
1543  t->use_disp = false;
1544  t->disposition = DISP_NONE;
1545  t->encoding = ENC_7BIT;
1546  }
1547  t->filename = sigfile;
1548  t->unlink = true; /* ok to remove this file after sending. */
1549 
1550  return a;
1551 }
1552 
1556 struct Body *pgp_gpgme_sign_message(struct Body *a, const struct AddressList *from)
1557 {
1558  return sign_message(a, from, false);
1559 }
1560 
1564 struct Body *smime_gpgme_sign_message(struct Body *a, const struct AddressList *from)
1565 {
1566  return sign_message(a, from, true);
1567 }
1568 
1572 struct Body *pgp_gpgme_encrypt_message(struct Body *a, char *keylist, bool sign,
1573  const struct AddressList *from)
1574 {
1575  if (sign)
1577  gpgme_data_t plaintext = body_to_data_object(a, false);
1578  if (!plaintext)
1579  return NULL;
1580 
1581  char *outfile = encrypt_gpgme_object(plaintext, keylist, false, sign, from);
1582  gpgme_data_release(plaintext);
1583  if (!outfile)
1584  return NULL;
1585 
1586  struct Body *t = mutt_body_new();
1587  t->type = TYPE_MULTIPART;
1588  t->subtype = mutt_str_strdup("encrypted");
1589  t->encoding = ENC_7BIT;
1590  t->use_disp = false;
1591  t->disposition = DISP_INLINE;
1592 
1594  mutt_param_set(&t->parameter, "protocol", "application/pgp-encrypted");
1595 
1596  t->parts = mutt_body_new();
1597  t->parts->type = TYPE_APPLICATION;
1598  t->parts->subtype = mutt_str_strdup("pgp-encrypted");
1599  t->parts->encoding = ENC_7BIT;
1600 
1601  t->parts->next = mutt_body_new();
1603  t->parts->next->subtype = mutt_str_strdup("octet-stream");
1604  t->parts->next->encoding = ENC_7BIT;
1605  t->parts->next->filename = outfile;
1606  t->parts->next->use_disp = true;
1608  t->parts->next->unlink = true; /* delete after sending the message */
1609  t->parts->next->d_filename = mutt_str_strdup("msg.asc"); /* non pgp/mime
1610  can save */
1611 
1612  return t;
1613 }
1614 
1618 struct Body *smime_gpgme_build_smime_entity(struct Body *a, char *keylist)
1619 {
1620  /* OpenSSL converts line endings to crlf when encrypting. Some clients
1621  * depend on this for signed+encrypted messages: they do not convert line
1622  * endings between decrypting and checking the signature. */
1623  gpgme_data_t plaintext = body_to_data_object(a, true);
1624  if (!plaintext)
1625  return NULL;
1626 
1627  char *outfile = encrypt_gpgme_object(plaintext, keylist, true, false, NULL);
1628  gpgme_data_release(plaintext);
1629  if (!outfile)
1630  return NULL;
1631 
1632  struct Body *t = mutt_body_new();
1633  t->type = TYPE_APPLICATION;
1634  t->subtype = mutt_str_strdup("pkcs7-mime");
1635  mutt_param_set(&t->parameter, "name", "smime.p7m");
1636  mutt_param_set(&t->parameter, "smime-type", "enveloped-data");
1637  t->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1638  t->use_disp = true;
1639  t->disposition = DISP_ATTACH;
1640  t->d_filename = mutt_str_strdup("smime.p7m");
1641  t->filename = outfile;
1642  t->unlink = true; /* delete after sending the message */
1643  t->parts = 0;
1644  t->next = 0;
1645 
1646  return t;
1647 }
1648 
1662 static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key,
1663  int idx, struct State *s, gpgme_signature_t sig)
1664 {
1665  if (!key)
1666  return 1;
1667 
1668  bool severe = false;
1669 
1670  if ((sum & GPGME_SIGSUM_KEY_REVOKED))
1671  {
1672  state_puts(s, _("Warning: One of the keys has been revoked\n"));
1673  severe = true;
1674  }
1675 
1676  if ((sum & GPGME_SIGSUM_KEY_EXPIRED))
1677  {
1678  time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
1679  if (at)
1680  {
1681  state_puts(
1682  s, _("Warning: The key used to create the signature expired at: "));
1683  print_time(at, s);
1684  state_puts(s, "\n");
1685  }
1686  else
1687  {
1688  state_puts(s, _("Warning: At least one certification key has expired\n"));
1689  }
1690  }
1691 
1692  if ((sum & GPGME_SIGSUM_SIG_EXPIRED))
1693  {
1694  gpgme_signature_t sig2 = NULL;
1695  unsigned int i;
1696 
1697  gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1698 
1699  for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1700  ;
1701 
1702  state_puts(s, _("Warning: The signature expired at: "));
1703  print_time(sig2 ? sig2->exp_timestamp : 0, s);
1704  state_puts(s, "\n");
1705  }
1706 
1707  if ((sum & GPGME_SIGSUM_KEY_MISSING))
1708  {
1709  state_puts(s, _("Can't verify due to a missing key or certificate\n"));
1710  }
1711 
1712  if ((sum & GPGME_SIGSUM_CRL_MISSING))
1713  {
1714  state_puts(s, _("The CRL is not available\n"));
1715  severe = true;
1716  }
1717 
1718  if ((sum & GPGME_SIGSUM_CRL_TOO_OLD))
1719  {
1720  state_puts(s, _("Available CRL is too old\n"));
1721  severe = true;
1722  }
1723 
1724  if ((sum & GPGME_SIGSUM_BAD_POLICY))
1725  state_puts(s, _("A policy requirement was not met\n"));
1726 
1727  if ((sum & GPGME_SIGSUM_SYS_ERROR))
1728  {
1729  const char *t0 = NULL, *t1 = NULL;
1730  gpgme_verify_result_t result = NULL;
1731  gpgme_signature_t sig2 = NULL;
1732  unsigned int i;
1733 
1734  state_puts(s, _("A system error occurred"));
1735 
1736  /* Try to figure out some more detailed system error information. */
1737  result = gpgme_op_verify_result(ctx);
1738  for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1739  ;
1740  if (sig2)
1741  {
1742  t0 = "";
1743  t1 = sig2->wrong_key_usage ? "Wrong_Key_Usage" : "";
1744  }
1745 
1746  if (t0 || t1)
1747  {
1748  state_puts(s, ": ");
1749  if (t0)
1750  state_puts(s, t0);
1751  if (t1 && !(t0 && (strcmp(t0, t1) == 0)))
1752  {
1753  if (t0)
1754  state_puts(s, ",");
1755  state_puts(s, t1);
1756  }
1757  }
1758  state_puts(s, "\n");
1759  }
1760 
1761  if (C_CryptUsePka)
1762  {
1763  if ((sig->pka_trust == 1) && sig->pka_address)
1764  {
1765  state_puts(s, _("WARNING: PKA entry does not match signer's address: "));
1766  state_puts(s, sig->pka_address);
1767  state_puts(s, "\n");
1768  }
1769  else if ((sig->pka_trust == 2) && sig->pka_address)
1770  {
1771  state_puts(s, _("PKA verified signer's address is: "));
1772  state_puts(s, sig->pka_address);
1773  state_puts(s, "\n");
1774  }
1775  }
1776 
1777  return severe;
1778 }
1779 
1785 static void show_fingerprint(gpgme_key_t key, struct State *state)
1786 {
1787  if (!key)
1788  return;
1789 
1790  const char *prefix = _("Fingerprint: ");
1791 
1792  const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1793  if (!s)
1794  return;
1795  bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1796 
1797  char *buf = mutt_mem_malloc(strlen(prefix) + strlen(s) * 4 + 2);
1798  strcpy(buf, prefix);
1799  char *p = buf + strlen(buf);
1800  if (is_pgp && (strlen(s) == 40))
1801  { /* PGP v4 style formatted. */
1802  for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1803  {
1804  *p++ = s[0];
1805  *p++ = s[1];
1806  *p++ = s[2];
1807  *p++ = s[3];
1808  *p++ = ' ';
1809  if (i == 4)
1810  *p++ = ' ';
1811  }
1812  }
1813  else
1814  {
1815  for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1816  {
1817  *p++ = s[0];
1818  *p++ = s[1];
1819  *p++ = is_pgp ? ' ' : ':';
1820  if (is_pgp && (i == 7))
1821  *p++ = ' ';
1822  }
1823  }
1824 
1825  /* just in case print remaining odd digits */
1826  for (; *s; s++)
1827  *p++ = *s;
1828  *p++ = '\n';
1829  *p = '\0';
1830  state_puts(state, buf);
1831  FREE(&buf);
1832 }
1833 
1840 static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *s)
1841 {
1842  gpgme_signature_t sig = NULL;
1843  const char *txt = NULL;
1844 
1845  gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1846  if (result)
1847  for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1848  ;
1849 
1850  switch (sig ? sig->validity : 0)
1851  {
1852  case GPGME_VALIDITY_UNKNOWN:
1853  txt = _("WARNING: We have NO indication whether "
1854  "the key belongs to the person named "
1855  "as shown above\n");
1856  break;
1857  case GPGME_VALIDITY_UNDEFINED:
1858  break;
1859  case GPGME_VALIDITY_NEVER:
1860  txt = _("WARNING: The key does NOT BELONG to "
1861  "the person named as shown above\n");
1862  break;
1863  case GPGME_VALIDITY_MARGINAL:
1864  txt = _("WARNING: It is NOT certain that the key "
1865  "belongs to the person named as shown above\n");
1866  break;
1867  case GPGME_VALIDITY_FULL:
1868  case GPGME_VALIDITY_ULTIMATE:
1869  txt = NULL;
1870  break;
1871  }
1872  if (txt)
1873  state_puts(s, txt);
1874 }
1875 
1883 static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig,
1884  gpgme_key_t key, struct State *s)
1885 {
1886  int msgwid;
1887 
1888  state_puts(s, msg);
1889  state_puts(s, " ");
1890  /* key is NULL when not present in the user's keyring */
1891  if (key)
1892  {
1893  bool aka = false;
1894  for (gpgme_user_id_t uids = key->uids; uids; uids = uids->next)
1895  {
1896  if (uids->revoked)
1897  continue;
1898  if (aka)
1899  {
1900  msgwid = mutt_strwidth(msg) - mutt_strwidth(_("aka: ")) + 1;
1901  if (msgwid < 0)
1902  msgwid = 0;
1903  for (int i = 0; i < msgwid; i++)
1904  state_puts(s, " ");
1905  state_puts(s, _("aka: "));
1906  }
1907  state_puts(s, uids->uid);
1908  state_puts(s, "\n");
1909 
1910  aka = true;
1911  }
1912  }
1913  else
1914  {
1915  if (sig->fpr)
1916  {
1917  state_puts(s, _("KeyID "));
1918  state_puts(s, sig->fpr);
1919  }
1920  else
1921  {
1922  /* L10N: You will see this message in place of "KeyID "
1923  if the S/MIME key has no ID. This is quite an error. */
1924  state_puts(s, _("no signature fingerprint available"));
1925  }
1926  state_puts(s, "\n");
1927  }
1928 
1929  /* timestamp is 0 when verification failed.
1930  * "Jan 1 1970" is not the created date. */
1931  if (sig->timestamp)
1932  {
1933  msgwid = mutt_strwidth(msg) - mutt_strwidth(_("created: ")) + 1;
1934  if (msgwid < 0)
1935  msgwid = 0;
1936  for (int i = 0; i < msgwid; i++)
1937  state_puts(s, " ");
1938  state_puts(s, _("created: "));
1939  print_time(sig->timestamp, s);
1940  state_puts(s, "\n");
1941  }
1942 }
1943 
1956 static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *s)
1957 {
1958  const char *fpr = NULL;
1959  gpgme_key_t key = NULL;
1960  bool anybad = false, anywarn = false;
1961  gpgme_signature_t sig = NULL;
1962  gpgme_error_t err = GPG_ERR_NO_ERROR;
1963 
1964  gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1965  if (result)
1966  {
1967  /* FIXME: this code should use a static variable and remember
1968  * the current position in the list of signatures, IMHO.
1969  * -moritz. */
1970  int i;
1971  for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next)
1972  ;
1973  if (!sig)
1974  return -1; /* Signature not found. */
1975 
1976  if (signature_key)
1977  {
1978  gpgme_key_unref(signature_key);
1979  signature_key = NULL;
1980  }
1981 
1982  fpr = sig->fpr;
1983  const unsigned int sum = sig->summary;
1984 
1985  if (gpg_err_code(sig->status) != GPG_ERR_NO_ERROR)
1986  anybad = true;
1987 
1988  if (gpg_err_code(sig->status) != GPG_ERR_NO_PUBKEY)
1989  {
1990  err = gpgme_get_key(ctx, fpr, &key, 0); /* secret key? */
1991  if (err == 0)
1992  {
1993  if (!signature_key)
1994  signature_key = key;
1995  }
1996  else
1997  {
1998  key = NULL; /* Old gpgme versions did not set KEY to NULL on
1999  error. Do it here to avoid a double free. */
2000  }
2001  }
2002  else
2003  {
2004  /* pubkey not present */
2005  }
2006 
2007  if (!s || !s->fp_out || !(s->flags & MUTT_DISPLAY))
2008  ; /* No state information so no way to print anything. */
2009  else if (err != 0)
2010  {
2011  char buf[1024];
2012  snprintf(buf, sizeof(buf), _("Error getting key information for KeyID %s: %s\n"),
2013  fpr, gpgme_strerror(err));
2014  state_puts(s, buf);
2015  anybad = true;
2016  }
2017  else if ((sum & GPGME_SIGSUM_GREEN))
2018  {
2019  print_smime_keyinfo(_("Good signature from:"), sig, key, s);
2020  if (show_sig_summary(sum, ctx, key, idx, s, sig))
2021  anywarn = true;
2022  show_one_sig_validity(ctx, idx, s);
2023  }
2024  else if ((sum & GPGME_SIGSUM_RED))
2025  {
2026  print_smime_keyinfo(_("*BAD* signature from:"), sig, key, s);
2027  show_sig_summary(sum, ctx, key, idx, s, sig);
2028  }
2029  else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
2030  { /* We can't decide (yellow) but this is a PGP key with a good
2031  signature, so we display what a PGP user expects: The name,
2032  fingerprint and the key validity (which is neither fully or
2033  ultimate). */
2034  print_smime_keyinfo(_("Good signature from:"), sig, key, s);
2035  show_one_sig_validity(ctx, idx, s);
2036  show_fingerprint(key, s);
2037  if (show_sig_summary(sum, ctx, key, idx, s, sig))
2038  anywarn = true;
2039  }
2040  else /* can't decide (yellow) */
2041  {
2042  print_smime_keyinfo(_("Problem signature from:"), sig, key, s);
2043  /* 0 indicates no expiration */
2044  if (sig->exp_timestamp)
2045  {
2046  /* L10N: This is trying to match the width of the
2047  "Problem signature from:" translation just above. */
2048  state_puts(s, _(" expires: "));
2049  print_time(sig->exp_timestamp, s);
2050  state_puts(s, "\n");
2051  }
2052  show_sig_summary(sum, ctx, key, idx, s, sig);
2053  anywarn = true;
2054  }
2055 
2056  if (key != signature_key)
2057  gpgme_key_unref(key);
2058  }
2059 
2060  return anybad ? 1 : anywarn ? 2 : 0;
2061 }
2062 
2076 static int verify_one(struct Body *sigbdy, struct State *s, const char *tempfile, bool is_smime)
2077 {
2078  int badsig = -1;
2079  int anywarn = 0;
2080  gpgme_ctx_t ctx = NULL;
2081  gpgme_data_t message = NULL;
2082 
2083  gpgme_data_t signature = file_to_data_object(s->fp_in, sigbdy->offset, sigbdy->length);
2084  if (!signature)
2085  return -1;
2086 
2087  /* We need to tell gpgme about the encoding because the backend can't
2088  * auto-detect plain base-64 encoding which is used by S/MIME. */
2089  if (is_smime)
2090  gpgme_data_set_encoding(signature, GPGME_DATA_ENCODING_BASE64);
2091 
2092  int err = gpgme_data_new_from_file(&message, tempfile, 1);
2093  if (err != 0)
2094  {
2095  gpgme_data_release(signature);
2096  mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
2097  return -1;
2098  }
2099  ctx = create_gpgme_context(is_smime);
2100 
2101  /* Note: We don't need a current time output because GPGME avoids
2102  * such an attack by separating the meta information from the data. */
2103  state_attach_puts(s, _("[-- Begin signature information --]\n"));
2104 
2105  err = gpgme_op_verify(ctx, signature, message, NULL);
2106  gpgme_data_release(message);
2107  gpgme_data_release(signature);
2108 
2109  redraw_if_needed(ctx);
2110  if (err != 0)
2111  {
2112  char buf[200];
2113 
2114  snprintf(buf, sizeof(buf) - 1, _("Error: verification failed: %s\n"),
2115  gpgme_strerror(err));
2116  state_puts(s, buf);
2117  }
2118  else
2119  { /* Verification succeeded, see what the result is. */
2120  gpgme_verify_result_t verify_result = NULL;
2121 
2122  if (signature_key)
2123  {
2124  gpgme_key_unref(signature_key);
2125  signature_key = NULL;
2126  }
2127 
2128  verify_result = gpgme_op_verify_result(ctx);
2129  if (verify_result && verify_result->signatures)
2130  {
2131  bool anybad = false;
2132  int res;
2133  for (int idx = 0; (res = show_one_sig_status(ctx, idx, s)) != -1; idx++)
2134  {
2135  if (res == 1)
2136  anybad = true;
2137  else if (res == 2)
2138  anywarn = 2;
2139  }
2140  if (!anybad)
2141  badsig = 0;
2142  }
2143  }
2144 
2145  if (badsig == 0)
2146  {
2147  gpgme_verify_result_t result = NULL;
2148  gpgme_sig_notation_t notation = NULL;
2149  gpgme_signature_t sig = NULL;
2150 
2151  result = gpgme_op_verify_result(ctx);
2152  if (result)
2153  {
2154  for (sig = result->signatures; sig; sig = sig->next)
2155  {
2156  int non_pka_notations = 0;
2157  for (notation = sig->notations; notation; notation = notation->next)
2158  if (!is_pka_notation(notation))
2159  non_pka_notations++;
2160 
2161  if (non_pka_notations)
2162  {
2163  char buf[128];
2164  snprintf(buf, sizeof(buf),
2165  _("*** Begin Notation (signature by: %s) ***\n"), sig->fpr);
2166  state_puts(s, buf);
2167  for (notation = sig->notations; notation; notation = notation->next)
2168  {
2169  if (is_pka_notation(notation))
2170  continue;
2171 
2172  if (notation->name)
2173  {
2174  state_puts(s, notation->name);
2175  state_puts(s, "=");
2176  }
2177  if (notation->value)
2178  {
2179  state_puts(s, notation->value);
2180  if (!(*notation->value && (notation->value[strlen(notation->value) - 1] == '\n')))
2181  state_puts(s, "\n");
2182  }
2183  }
2184  state_puts(s, _("*** End Notation ***\n"));
2185  }
2186  }
2187  }
2188  }
2189 
2190  gpgme_release(ctx);
2191 
2192  state_attach_puts(s, _("[-- End signature information --]\n\n"));
2193  mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
2194 
2195  return badsig ? 1 : anywarn ? 2 : 0;
2196 }
2197 
2201 int pgp_gpgme_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
2202 {
2203  return verify_one(sigbdy, s, tempfile, false);
2204 }
2205 
2209 int smime_gpgme_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
2210 {
2211  return verify_one(sigbdy, s, tempfile, true);
2212 }
2213 
2227 static struct Body *decrypt_part(struct Body *a, struct State *s, FILE *fp_out,
2228  bool is_smime, int *r_is_signed)
2229 {
2230  if (!a || !s || !fp_out)
2231  return NULL;
2232 
2233  struct stat info;
2234  struct Body *tattach = NULL;
2235  int err = 0;
2236  gpgme_data_t ciphertext = NULL, plaintext = NULL;
2237  bool maybe_signed = false;
2238  bool anywarn = false;
2239  int sig_stat = 0;
2240 
2241  if (r_is_signed)
2242  *r_is_signed = 0;
2243 
2244  gpgme_ctx_t ctx = create_gpgme_context(is_smime);
2245 
2246 restart:
2247  if (a->length < 0)
2248  return NULL;
2249  /* Make a data object from the body, create context etc. */
2250  ciphertext = file_to_data_object(s->fp_in, a->offset, a->length);
2251  if (!ciphertext)
2252  goto cleanup;
2253  plaintext = create_gpgme_data();
2254 
2255  /* Do the decryption or the verification in case of the S/MIME hack. */
2256  if ((!is_smime) || maybe_signed)
2257  {
2258  if (!is_smime)
2259  err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
2260  else if (maybe_signed)
2261  err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
2262 
2263  if (err == GPG_ERR_NO_ERROR)
2264  {
2265  /* Check whether signatures have been verified. */
2266  gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2267  if (verify_result->signatures)
2268  sig_stat = 1;
2269  }
2270  }
2271  else
2272  err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
2273  gpgme_data_release(ciphertext);
2274  ciphertext = NULL;
2275  if (err != 0)
2276  {
2277  /* Abort right away and silently.
2278  * Autocrypt will retry on the normal keyring. */
2279  if (OptAutocryptGpgme)
2280  goto cleanup;
2281  if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
2282  {
2283  /* Check whether this might be a signed message despite what the mime
2284  * header told us. Retry then. gpgsm returns the error information
2285  * "unsupported Algorithm '?'" but gpgme will not store this unknown
2286  * algorithm, thus we test that it has not been set. */
2287  gpgme_decrypt_result_t result;
2288 
2289  result = gpgme_op_decrypt_result(ctx);
2290  if (!result->unsupported_algorithm)
2291  {
2292  maybe_signed = true;
2293  gpgme_data_release(plaintext);
2294  plaintext = NULL;
2295  /* gpgsm ends the session after an error; restart it */
2296  gpgme_release(ctx);
2297  ctx = NULL;
2298  goto restart;
2299  }
2300  }
2301  redraw_if_needed(ctx);
2302  if ((s->flags & MUTT_DISPLAY))
2303  {
2304  char buf[200];
2305 
2306  snprintf(buf, sizeof(buf) - 1,
2307  _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
2308  state_attach_puts(s, buf);
2309  }
2310  goto cleanup;
2311  }
2312  redraw_if_needed(ctx);
2313 
2314  /* Read the output from GPGME, and make sure to change CRLF to LF,
2315  * otherwise read_mime_header has a hard time parsing the message. */
2316  if (data_object_to_stream(plaintext, fp_out))
2317  {
2318  goto cleanup;
2319  }
2320  gpgme_data_release(plaintext);
2321  plaintext = NULL;
2322 
2323  if (sig_stat)
2324  {
2325  int res, idx;
2326  int anybad = 0;
2327 
2328  if (r_is_signed)
2329  *r_is_signed = -1; /* A signature exists. */
2330 
2331  if ((s->flags & MUTT_DISPLAY))
2332  {
2333  state_attach_puts(s, _("[-- Begin signature information --]\n"));
2334  }
2335  for (idx = 0; (res = show_one_sig_status(ctx, idx, s)) != -1; idx++)
2336  {
2337  if (res == 1)
2338  anybad = 1;
2339  else if (res == 2)
2340  anywarn = true;
2341  }
2342  if (!anybad && idx && r_is_signed && *r_is_signed)
2343  *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
2344 
2345  if ((s->flags & MUTT_DISPLAY))
2346  {
2347  state_attach_puts(s, _("[-- End signature information --]\n\n"));
2348  }
2349  }
2350  gpgme_release(ctx);
2351  ctx = NULL;
2352 
2353  fflush(fp_out);
2354  rewind(fp_out);
2355  tattach = mutt_read_mime_header(fp_out, 0);
2356  if (tattach)
2357  {
2358  /* Need to set the length of this body part. */
2359  fstat(fileno(fp_out), &info);
2360  tattach->length = info.st_size - tattach->offset;
2361 
2362  tattach->warnsig = anywarn;
2363 
2364  /* See if we need to recurse on this MIME part. */
2365  mutt_parse_part(fp_out, tattach);
2366  }
2367 
2368 cleanup:
2369  gpgme_data_release(ciphertext);
2370  gpgme_data_release(plaintext);
2371  gpgme_release(ctx);
2372 
2373  return tattach;
2374 }
2375 
2379 int pgp_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
2380 {
2381  struct State s = { 0 };
2382  struct Body *first_part = b;
2383  int is_signed = 0;
2384  bool need_decode = false;
2385  int saved_type = 0;
2386  LOFF_T saved_offset = 0;
2387  size_t saved_length = 0;
2388  FILE *fp_decoded = NULL;
2389  int rc = 0;
2390 
2391  first_part->goodsig = false;
2392  first_part->warnsig = false;
2393 
2395  {
2396  b = b->parts->next;
2397  /* Some clients improperly encode the octetstream part. */
2398  if (b->encoding != ENC_7BIT)
2399  need_decode = true;
2400  }
2402  {
2403  b = b->parts->next->next;
2404  need_decode = true;
2405  }
2406  else
2407  return -1;
2408 
2409  s.fp_in = fp_in;
2410 
2411  if (need_decode)
2412  {
2413  saved_type = b->type;
2414  saved_offset = b->offset;
2415  saved_length = b->length;
2416 
2417  fp_decoded = mutt_file_mkstemp();
2418  if (!fp_decoded)
2419  {
2420  mutt_perror(_("Can't create temporary file"));
2421  return -1;
2422  }
2423 
2424  fseeko(s.fp_in, b->offset, SEEK_SET);
2425  s.fp_out = fp_decoded;
2426 
2427  mutt_decode_attachment(b, &s);
2428 
2429  fflush(fp_decoded);
2430  b->length = ftello(fp_decoded);
2431  b->offset = 0;
2432  rewind(fp_decoded);
2433  s.fp_in = fp_decoded;
2434  s.fp_out = 0;
2435  }
2436 
2437  *fp_out = mutt_file_mkstemp();
2438  if (!*fp_out)
2439  {
2440  mutt_perror(_("Can't create temporary file"));
2441  rc = -1;
2442  goto bail;
2443  }
2444 
2445  *cur = decrypt_part(b, &s, *fp_out, false, &is_signed);
2446  if (*cur)
2447  {
2448  rewind(*fp_out);
2449  if (is_signed > 0)
2450  first_part->goodsig = true;
2451  }
2452  else
2453  {
2454  rc = -1;
2455  mutt_file_fclose(fp_out);
2456  }
2457 
2458 bail:
2459  if (need_decode)
2460  {
2461  b->type = saved_type;
2462  b->length = saved_length;
2463  b->offset = saved_offset;
2464  mutt_file_fclose(&fp_decoded);
2465  }
2466 
2467  return rc;
2468 }
2469 
2473 int smime_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
2474 {
2475  struct State s = { 0 };
2476  int is_signed;
2477  LOFF_T saved_b_offset;
2478  size_t saved_b_length;
2479  int saved_b_type;
2480 
2482  return -1;
2483 
2484  if (b->parts)
2485  return -1;
2486 
2487  /* Decode the body - we need to pass binary CMS to the
2488  * backend. The backend allows for Base64 encoded data but it does
2489  * not allow for QP which I have seen in some messages. So better
2490  * do it here. */
2491  saved_b_type = b->type;
2492  saved_b_offset = b->offset;
2493  saved_b_length = b->length;
2494  s.fp_in = fp_in;
2495  fseeko(s.fp_in, b->offset, SEEK_SET);
2496  FILE *fp_tmp = mutt_file_mkstemp();
2497  if (!fp_tmp)
2498  {
2499  mutt_perror(_("Can't create temporary file"));
2500  return -1;
2501  }
2502 
2503  s.fp_out = fp_tmp;
2504  mutt_decode_attachment(b, &s);
2505  fflush(fp_tmp);
2506  b->length = ftello(s.fp_out);
2507  b->offset = 0;
2508  rewind(fp_tmp);
2509 
2510  memset(&s, 0, sizeof(s));
2511  s.fp_in = fp_tmp;
2512  s.fp_out = 0;
2513  *fp_out = mutt_file_mkstemp();
2514  if (!*fp_out)
2515  {
2516  mutt_perror(_("Can't create temporary file"));
2517  return -1;
2518  }
2519 
2520  *cur = decrypt_part(b, &s, *fp_out, true, &is_signed);
2521  if (*cur)
2522  (*cur)->goodsig = is_signed > 0;
2523  b->type = saved_b_type;
2524  b->length = saved_b_length;
2525  b->offset = saved_b_offset;
2526  mutt_file_fclose(&fp_tmp);
2527  rewind(*fp_out);
2528  if (*cur && !is_signed && !(*cur)->parts && mutt_is_application_smime(*cur))
2529  {
2530  /* Assume that this is a opaque signed s/mime message. This is an ugly way
2531  * of doing it but we have anyway a problem with arbitrary encoded S/MIME
2532  * messages: Only the outer part may be encrypted. The entire mime parsing
2533  * should be revamped, probably by keeping the temporary files so that we
2534  * don't need to decrypt them all the time. Inner parts of an encrypted
2535  * part can then point into this file and there won't ever be a need to
2536  * decrypt again. This needs a partial rewrite of the MIME engine. */
2537  struct Body *bb = *cur;
2538 
2539  saved_b_type = bb->type;
2540  saved_b_offset = bb->offset;
2541  saved_b_length = bb->length;
2542  memset(&s, 0, sizeof(s));
2543  s.fp_in = *fp_out;
2544  fseeko(s.fp_in, bb->offset, SEEK_SET);
2545  FILE *fp_tmp2 = mutt_file_mkstemp();
2546  if (!fp_tmp2)
2547  {
2548  mutt_perror(_("Can't create temporary file"));
2549  return -1;
2550  }
2551 
2552  s.fp_out = fp_tmp2;
2553  mutt_decode_attachment(bb, &s);
2554  fflush(fp_tmp2);
2555  bb->length = ftello(s.fp_out);
2556  bb->offset = 0;
2557  rewind(fp_tmp2);
2558  mutt_file_fclose(fp_out);
2559 
2560  memset(&s, 0, sizeof(s));
2561  s.fp_in = fp_tmp2;
2562  s.fp_out = 0;
2563  *fp_out = mutt_file_mkstemp();
2564  if (!*fp_out)
2565  {
2566  mutt_perror(_("Can't create temporary file"));
2567  return -1;
2568  }
2569 
2570  struct Body *b_tmp = decrypt_part(bb, &s, *fp_out, true, &is_signed);
2571  if (b_tmp)
2572  b_tmp->goodsig = is_signed > 0;
2573  bb->type = saved_b_type;
2574  bb->length = saved_b_length;
2575  bb->offset = saved_b_offset;
2576  mutt_file_fclose(&fp_tmp2);
2577  rewind(*fp_out);
2578  mutt_body_free(cur);
2579  *cur = b_tmp;
2580  }
2581  return *cur ? 0 : -1;
2582 }
2583 
2591 static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
2592 {
2593  /* Before gpgme 1.9.0 and gpg 2.1.14 there was no side-effect free
2594  * way to view key data in GPGME, so we import the key into a
2595  * temporary keyring if we detect an older system. */
2596  bool legacy_api;
2597  struct Buffer *tmpdir = NULL;
2598  gpgme_ctx_t tmpctx = NULL;
2599  gpgme_error_t err;
2600  gpgme_engine_info_t engineinfo = NULL;
2601  gpgme_key_t key = NULL;
2602  gpgme_user_id_t uid = NULL;
2603  gpgme_subkey_t subkey = NULL;
2604  const char *shortid = NULL;
2605  size_t len;
2606  char date[256];
2607  bool more;
2608  int rc = -1;
2609  time_t tt;
2610 
2611 #if GPGME_VERSION_NUMBER >= 0x010900 /* gpgme >= 1.9.0 */
2612  legacy_api = !have_gpg_version("2.1.14");
2613 #else /* gpgme < 1.9.0 */
2614  legacy_api = true;
2615 #endif
2616 
2617  tmpctx = create_gpgme_context(false);
2618 
2619  if (legacy_api)
2620  {
2621  tmpdir = mutt_buffer_pool_get();
2622  mutt_buffer_printf(tmpdir, "%s/neomutt-gpgme-XXXXXX", NONULL(C_Tmpdir));
2623  if (!mkdtemp(tmpdir->data))
2624  {
2625  mutt_debug(LL_DEBUG1, "Error creating temporary GPGME home\n");
2626  goto err_ctx;
2627  }
2628 
2629  engineinfo = gpgme_ctx_get_engine_info(tmpctx);
2630  while (engineinfo && (engineinfo->protocol != GPGME_PROTOCOL_OpenPGP))
2631  engineinfo = engineinfo->next;
2632  if (!engineinfo)
2633  {
2634  mutt_debug(LL_DEBUG1, "Error finding GPGME PGP engine\n");
2635  goto err_tmpdir;
2636  }
2637 
2638  err = gpgme_ctx_set_engine_info(tmpctx, GPGME_PROTOCOL_OpenPGP,
2639  engineinfo->file_name, mutt_b2s(tmpdir));
2640  if (err != GPG_ERR_NO_ERROR)
2641  {
2642  mutt_debug(LL_DEBUG1, "Error setting GPGME context home\n");
2643  goto err_tmpdir;
2644  }
2645  }
2646 
2647  *fp = mutt_file_mkstemp();
2648  if (!*fp)
2649  {
2650  mutt_perror(_("Can't create temporary file"));
2651  goto err_tmpdir;
2652  }
2653 
2654 #if GPGME_VERSION_NUMBER >= 0x010900 /* 1.9.0 */
2655  if (!legacy_api)
2656  err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2657  else
2658 #endif /* gpgme >= 1.9.0 */
2659  {
2660  err = gpgme_op_keylist_start(tmpctx, NULL, 0);
2661  }
2662  while (err == 0)
2663  {
2664  err = gpgme_op_keylist_next(tmpctx, &key);
2665  if (err != 0)
2666  break;
2667  uid = key->uids;
2668  subkey = key->subkeys;
2669  more = false;
2670  while (subkey)
2671  {
2672  shortid = subkey->keyid;
2673  len = mutt_str_strlen(subkey->keyid);
2674  if (len > 8)
2675  shortid += len - 8;
2676  tt = subkey->timestamp;
2677  mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2678 
2679  if (more)
2680  {
2681  fprintf(*fp, "sub %5.5s %u/%8s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2682  subkey->length, shortid, date);
2683  }
2684  else
2685  {
2686  fprintf(*fp, "pub %5.5s %u/%8s %s %s\n", gpgme_pubkey_algo_name(subkey->pubkey_algo),
2687  subkey->length, shortid, date, uid->uid);
2688  }
2689  subkey = subkey->next;
2690  more = true;
2691  }
2692  gpgme_key_unref(key);
2693  }
2694  if (gpg_err_code(err) != GPG_ERR_EOF)
2695  {
2696  mutt_debug(LL_DEBUG1, "Error listing keys\n");
2697  goto err_fp;
2698  }
2699 
2700  rc = 0;
2701 
2702 err_fp:
2703  if (rc)
2704  mutt_file_fclose(fp);
2705 err_tmpdir:
2706  if (legacy_api)
2707  mutt_file_rmtree(mutt_b2s(tmpdir));
2708 err_ctx:
2709  gpgme_release(tmpctx);
2710 
2711  mutt_buffer_pool_release(&tmpdir);
2712 
2713  return rc;
2714 }
2715 
2727 static int line_compare(const char *a, size_t n, const char *b)
2728 {
2729  if (mutt_str_strncmp(a, b, n) == 0)
2730  {
2731  /* at this point we know that 'b' is at least 'n' chars long */
2732  if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2733  return true;
2734  }
2735  return false;
2736 }
2737 
2745 static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
2746 {
2747  char buf[8192];
2748  int rv = 0;
2749 
2750  bool sgn = false;
2751  bool enc = false;
2752 
2753  if (b->type != TYPE_TEXT)
2754  return 0;
2755 
2756  struct Buffer *tempfile = mutt_buffer_pool_get();
2757  mutt_buffer_mktemp(tempfile);
2758  if (mutt_decode_save_attachment(fp, b, mutt_b2s(tempfile), 0, MUTT_SAVE_NO_FLAGS) != 0)
2759  {
2760  unlink(mutt_b2s(tempfile));
2761  goto cleanup;
2762  }
2763 
2764  FILE *fp_tmp = fopen(mutt_b2s(tempfile), "r");
2765  if (!fp_tmp)
2766  {
2767  unlink(mutt_b2s(tempfile));
2768  goto cleanup;
2769  }
2770 
2771  while (fgets(buf, sizeof(buf), fp_tmp))
2772  {
2773  size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ", CASE_MATCH);
2774  if (plen != 0)
2775  {
2776  if (MESSAGE(buf + plen))
2777  {
2778  enc = true;
2779  break;
2780  }
2781  else if (SIGNED_MESSAGE(buf + plen))
2782  {
2783  sgn = true;
2784  break;
2785  }
2786  }
2787  }
2788  mutt_file_fclose(&fp_tmp);
2789  unlink(mutt_b2s(tempfile));
2790 
2791  if (!enc && !sgn)
2792  goto cleanup;
2793 
2794  /* fix the content type */
2795 
2796  mutt_param_set(&b->parameter, "format", "fixed");
2797  mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2798 
2799  rv = 1;
2800 
2801 cleanup:
2802  mutt_buffer_pool_release(&tempfile);
2803  return rv;
2804 }
2805 
2809 int pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
2810 {
2811  int rc = 0;
2812  for (; b; b = b->next)
2813  {
2814  if (!just_one && is_multipart(b))
2815  rc = (pgp_gpgme_check_traditional(fp, b->parts, false) || rc);
2816  else if (b->type == TYPE_TEXT)
2817  {
2819  if (r)
2820  rc = (rc || r);
2821  else
2822  rc = (pgp_check_traditional_one_body(fp, b) || rc);
2823  }
2824 
2825  if (just_one)
2826  break;
2827  }
2828  return rc;
2829 }
2830 
2834 void pgp_gpgme_invoke_import(const char *fname)
2835 {
2836  gpgme_ctx_t ctx = create_gpgme_context(false);
2837  gpgme_data_t keydata = NULL;
2838  gpgme_import_result_t impres;
2839  gpgme_import_status_t st;
2840  bool any;
2841 
2842  FILE *fp_in = mutt_file_fopen(fname, "r");
2843  if (!fp_in)
2844  {
2845  mutt_perror(fname);
2846  goto leave;
2847  }
2848  /* Note that the stream, "fp_in", needs to be kept open while the keydata
2849  * is used. */
2850  gpgme_error_t err = gpgme_data_new_from_stream(&keydata, fp_in);
2851  if (err != GPG_ERR_NO_ERROR)
2852  {
2853  mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
2854  goto leave;
2855  }
2856 
2857  err = gpgme_op_import(ctx, keydata);
2858  if (err != 0)
2859  {
2860  mutt_error(_("Error importing key: %s"), gpgme_strerror(err));
2861  goto leave;
2862  }
2863 
2864  /* Print infos about the imported keys to stdout. */
2865  impres = gpgme_op_import_result(ctx);
2866  if (!impres)
2867  {
2868  fputs("oops: no import result returned\n", stdout);
2869  goto leave;
2870  }
2871 
2872  for (st = impres->imports; st; st = st->next)
2873  {
2874  if (st->result)
2875  continue;
2876  printf("key %s imported (", NONULL(st->fpr));
2877  /* Note that we use the singular even if it is possible that
2878  * several uids etc are new. This simply looks better. */
2879  any = false;
2880  if (st->status & GPGME_IMPORT_SECRET)
2881  {
2882  printf("secret parts");
2883  any = true;
2884  }
2885  if ((st->status & GPGME_IMPORT_NEW))
2886  {
2887  printf("%snew key", any ? ", " : "");
2888  any = true;
2889  }
2890  if ((st->status & GPGME_IMPORT_UID))
2891  {
2892  printf("%snew uid", any ? ", " : "");
2893  any = true;
2894  }
2895  if ((st->status & GPGME_IMPORT_SIG))
2896  {
2897  printf("%snew sig", any ? ", " : "");
2898  any = true;
2899  }
2900  if ((st->status & GPGME_IMPORT_SUBKEY))
2901  {
2902  printf("%snew subkey", any ? ", " : "");
2903  any = true;
2904  }
2905  printf("%s)\n", any ? "" : "not changed");
2906  /* Fixme: Should we lookup each imported key and print more infos? */
2907  }
2908  /* Now print keys which failed the import. Unfortunately in most
2909  * cases gpg will bail out early and not tell gpgme about. */
2910  /* FIXME: We could instead use the new GPGME_AUDITLOG_DIAG to show
2911  * the actual gpg diagnostics. But I fear that would clutter the
2912  * output too much. Maybe a dedicated prompt or option to do this
2913  * would be helpful. */
2914  for (st = impres->imports; st; st = st->next)
2915  {
2916  if (st->result == 0)
2917  continue;
2918  printf("key %s import failed: %s\n", NONULL(st->fpr), gpgme_strerror(st->result));
2919  }
2920  fflush(stdout);
2921 
2922 leave:
2923  gpgme_release(ctx);
2924  gpgme_data_release(keydata);
2925  mutt_file_fclose(&fp_in);
2926 }
2927 
2943 static void copy_clearsigned(gpgme_data_t data, struct State *s, char *charset)
2944 {
2945  char buf[8192];
2946  bool complete, armor_header;
2947  FILE *fp = NULL;
2948 
2949  char *fname = data_object_to_tempfile(data, &fp);
2950  if (!fname)
2951  {
2952  mutt_file_fclose(&fp);
2953  return;
2954  }
2955  unlink(fname);
2956  FREE(&fname);
2957 
2958  /* fromcode comes from the MIME Content-Type charset label. It might
2959  * be a wrong label, so we want the ability to do corrections via
2960  * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2961  struct FgetConv *fc = mutt_ch_fgetconv_open(fp, charset, C_Charset, MUTT_ICONV_HOOK_FROM);
2962 
2963  for (complete = true, armor_header = true;
2964  mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2965  {
2966  if (!complete)
2967  {
2968  if (!armor_header)
2969  state_puts(s, buf);
2970  continue;
2971  }
2972 
2973  if (BEGIN_PGP_SIGNATURE(buf))
2974  break;
2975 
2976  if (armor_header)
2977  {
2978  if (buf[0] == '\n')
2979  armor_header = false;
2980  continue;
2981  }
2982 
2983  if (s->prefix)
2984  state_puts(s, s->prefix);
2985 
2986  if ((buf[0] == '-') && (buf[1] == ' '))
2987  state_puts(s, buf + 2);
2988  else
2989  state_puts(s, buf);
2990  }
2991 
2993  mutt_file_fclose(&fp);
2994 }
2995 
2999 int pgp_gpgme_application_handler(struct Body *m, struct State *s)
3000 {
3001  int needpass = -1;
3002  bool pgp_keyblock = false;
3003  bool clearsign = false;
3004  long bytes;
3005  LOFF_T last_pos;
3006  char buf[8192];
3007  FILE *fp_out = NULL;
3008 
3009  gpgme_error_t err = 0;
3010  gpgme_data_t armored_data = NULL;
3011 
3012  bool maybe_goodsig = true;
3013  bool have_any_sigs = false;
3014 
3015  char body_charset[256]; /* Only used for clearsigned messages. */
3016 
3017  mutt_debug(LL_DEBUG2, "Entering handler\n");
3018 
3019  /* For clearsigned messages we won't be able to get a character set
3020  * but we know that this may only be text thus we assume Latin-1 here. */
3021  if (!mutt_body_get_charset(m, body_charset, sizeof(body_charset)))
3022  mutt_str_strfcpy(body_charset, "iso-8859-1", sizeof(body_charset));
3023 
3024  fseeko(s->fp_in, m->offset, SEEK_SET);
3025  last_pos = m->offset;
3026 
3027  for (bytes = m->length; bytes > 0;)
3028  {
3029  if (!fgets(buf, sizeof(buf), s->fp_in))
3030  break;
3031 
3032  LOFF_T offset = ftello(s->fp_in);
3033  bytes -= (offset - last_pos); /* don't rely on mutt_str_strlen(buf) */
3034  last_pos = offset;
3035 
3036  size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ", CASE_MATCH);
3037  if (plen != 0)
3038  {
3039  clearsign = false;
3040 
3041  if (MESSAGE(buf + plen))
3042  needpass = 1;
3043  else if (SIGNED_MESSAGE(buf + plen))
3044  {
3045  clearsign = true;
3046  needpass = 0;
3047  }
3048  else if (PUBLIC_KEY_BLOCK(buf + plen))
3049  {
3050  needpass = 0;
3051  pgp_keyblock = true;
3052  }
3053  else
3054  {
3055  /* XXX we may wish to recode here */
3056  if (s->prefix)
3057  state_puts(s, s->prefix);
3058  state_puts(s, buf);
3059  continue;
3060  }
3061 
3062  have_any_sigs = (have_any_sigs || (clearsign && (s->flags & MUTT_VERIFY)));
3063 
3064  /* Copy PGP material to an data container */
3065  armored_data = file_to_data_object(s->fp_in, m->offset, m->length);
3066  /* Invoke PGP if needed */
3067  if (pgp_keyblock)
3068  {
3069  pgp_gpgme_extract_keys(armored_data, &fp_out);
3070  }
3071  else if (!clearsign || (s->flags & MUTT_VERIFY))
3072  {
3073  gpgme_data_t plaintext = create_gpgme_data();
3074  gpgme_ctx_t ctx = create_gpgme_context(false);
3075 
3076  if (clearsign)
3077  err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
3078  else
3079  {
3080  err = gpgme_op_decrypt_verify(ctx, armored_data, plaintext);
3081  if (gpg_err_code(err) == GPG_ERR_NO_DATA)
3082  {
3083  /* Decrypt verify can't handle signed only messages. */
3084  gpgme_data_seek(armored_data, 0, SEEK_SET);
3085  /* Must release plaintext so that we supply an uninitialized object. */
3086  gpgme_data_release(plaintext);
3087  plaintext = create_gpgme_data();
3088  err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
3089  }
3090  }
3091  redraw_if_needed(ctx);
3092 
3093  if (err != 0)
3094  {
3095  char errbuf[200];
3096 
3097  snprintf(errbuf, sizeof(errbuf) - 1,
3098  _("Error: decryption/verification failed: %s\n"), gpgme_strerror(err));
3099  state_puts(s, errbuf);
3100  }
3101  else
3102  {
3103  /* Decryption/Verification succeeded */
3104 
3105  mutt_message(_("PGP message successfully decrypted"));
3106 
3107  bool sig_stat = false;
3108  char *tmpfname = NULL;
3109 
3110  {
3111  /* Check whether signatures have been verified. */
3112  gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
3113  if (verify_result->signatures)
3114  sig_stat = true;
3115  }
3116 
3117  have_any_sigs = false;
3118  maybe_goodsig = false;
3119  if ((s->flags & MUTT_DISPLAY) && sig_stat)
3120  {
3121  int res, idx;
3122  bool anybad = false;
3123 
3124  state_attach_puts(s, _("[-- Begin signature information --]\n"));
3125  have_any_sigs = true;
3126  for (idx = 0; (res = show_one_sig_status(ctx, idx, s)) != -1; idx++)
3127  {
3128  if (res == 1)
3129  anybad = true;
3130  }
3131  if (!anybad && idx)
3132  maybe_goodsig = true;
3133 
3134  state_attach_puts(s, _("[-- End signature information --]\n\n"));
3135  }
3136 
3137  tmpfname = data_object_to_tempfile(plaintext, &fp_out);
3138  if (tmpfname)
3139  {
3140  unlink(tmpfname);
3141  FREE(&tmpfname);
3142  }
3143  else
3144  {
3145  mutt_file_fclose(&fp_out);
3146  state_puts(s, _("Error: copy data failed\n"));
3147  }
3148  }
3149  gpgme_data_release(plaintext);
3150  gpgme_release(ctx);
3151  }
3152 
3153  /* Now, copy cleartext to the screen. NOTE - we expect that PGP
3154  * outputs utf-8 cleartext. This may not always be true, but it
3155  * seems to be a reasonable guess. */
3156  if (s->flags & MUTT_DISPLAY)
3157  {
3158  if (needpass)
3159  state_attach_puts(s, _("[-- BEGIN PGP MESSAGE --]\n\n"));
3160  else if (pgp_keyblock)
3161  state_attach_puts(s, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
3162  else
3163  state_attach_puts(s, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
3164  }
3165 
3166  if (clearsign)
3167  {
3168  copy_clearsigned(armored_data, s, body_charset);
3169  }
3170  else if (fp_out)
3171  {
3172  int c;
3173  rewind(fp_out);
3174  struct FgetConv *fc = mutt_ch_fgetconv_open(fp_out, "utf-8", C_Charset, 0);
3175  while ((c = mutt_ch_fgetconv(fc)) != EOF)
3176  {
3177  state_putc(s, c);
3178  if ((c == '\n') && s->prefix)
3179  state_puts(s, s->prefix);
3180  }
3182  }
3183 
3184  if (s->flags & MUTT_DISPLAY)
3185  {
3186  state_putc(s, '\n');
3187  if (needpass)
3188  state_attach_puts(s, _("[-- END PGP MESSAGE --]\n"));
3189  else if (pgp_keyblock)
3190  state_attach_puts(s, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
3191  else
3192  state_attach_puts(s, _("[-- END PGP SIGNED MESSAGE --]\n"));
3193  }
3194 
3195  gpgme_data_release(armored_data);
3196  mutt_file_fclose(&fp_out);
3197  }
3198  else
3199  {
3200  /* A traditional PGP part may mix signed and unsigned content */
3201  /* XXX we may wish to recode here */
3202  if (s->prefix)
3203  state_puts(s, s->prefix);
3204  state_puts(s, buf);
3205  }
3206  }
3207 
3208  m->goodsig = (maybe_goodsig && have_any_sigs);
3209 
3210  if (needpass == -1)
3211  {
3213  s, _("[-- Error: could not find beginning of PGP message --]\n\n"));
3214  return 1;
3215  }
3216  mutt_debug(LL_DEBUG2, "Leaving handler\n");
3217 
3218  return err;
3219 }
3220 
3227 int pgp_gpgme_encrypted_handler(struct Body *a, struct State *s)
3228 {
3229  int is_signed;
3230  int rc = 0;
3231 
3232  mutt_debug(LL_DEBUG2, "Entering handler\n");
3233 
3234  FILE *fp_out = mutt_file_mkstemp();
3235  if (!fp_out)
3236  {
3237  mutt_perror(_("Can't create temporary file"));
3238  if (s->flags & MUTT_DISPLAY)
3239  {
3241  _("[-- Error: could not create temporary file --]\n"));
3242  }
3243  return -1;
3244  }
3245 
3246  struct Body *tattach = decrypt_part(a, s, fp_out, false, &is_signed);
3247  if (tattach)
3248  {
3249  tattach->goodsig = is_signed > 0;
3250 
3251  if (s->flags & MUTT_DISPLAY)
3252  {
3254  s, is_signed ?
3255  _("[-- The following data is PGP/MIME signed and encrypted "
3256  "--]\n\n") :
3257  _("[-- The following data is PGP/MIME encrypted --]\n\n"));
3258  mutt_protected_headers_handler(tattach, s);
3259  }
3260 
3261  /* Store any protected headers in the parent so they can be
3262  * accessed for index updates after the handler recursion is done.
3263  * This is done before the handler to prevent a nested encrypted
3264  * handler from freeing the headers. */
3266  a->mime_headers = tattach->mime_headers;
3267  tattach->mime_headers = NULL;
3268 
3269  {
3270  FILE *fp_save = s->fp_in;
3271  s->fp_in = fp_out;
3272  rc = mutt_body_handler(tattach, s);
3273  s->fp_in = fp_save;
3274  }
3275 
3276  /* Embedded multipart signed protected headers override the
3277  * encrypted headers. We need to do this after the handler so
3278  * they can be printed in the pager. */
3279  if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
3280  {
3282  a->mime_headers = tattach->parts->mime_headers;
3283  tattach->parts->mime_headers = NULL;
3284  }
3285 
3286  /* if a multipart/signed is the _only_ sub-part of a
3287  * multipart/encrypted, cache signature verification
3288  * status. */
3289  if (mutt_is_multipart_signed(tattach) && !tattach->next)
3290  a->goodsig |= tattach->goodsig;
3291 
3292  if (s->flags & MUTT_DISPLAY)
3293  {
3294  state_puts(s, "\n");
3296  s, is_signed ?
3297  _("[-- End of PGP/MIME signed and encrypted data --]\n") :
3298  _("[-- End of PGP/MIME encrypted data --]\n"));
3299  }
3300 
3301  mutt_body_free(&tattach);
3302  mutt_message(_("PGP message successfully decrypted"));
3303  }
3304  else
3305  {
3306  if (!OptAutocryptGpgme)
3307  {
3308  mutt_error(_("Could not decrypt PGP message"));
3309  }
3310  rc = -1;
3311  }
3312 
3313  mutt_file_fclose(&fp_out);
3314  mutt_debug(LL_DEBUG2, "Leaving handler\n");
3315 
3316  return rc;
3317 }
3318 
3322 int smime_gpgme_application_handler(struct Body *a, struct State *s)
3323 {
3324  int is_signed = 0;
3325  int rc = 0;
3326 
3327  mutt_debug(LL_DEBUG2, "Entering handler\n");
3328 
3329  /* clear out any mime headers before the handler, so they can't be spoofed. */
3331  a->warnsig = false;
3332  FILE *fp_out = mutt_file_mkstemp();
3333  if (!fp_out)
3334  {
3335  mutt_perror(_("Can't create temporary file"));
3336  if (s->flags & MUTT_DISPLAY)
3337  {
3339  _("[-- Error: could not create temporary file --]\n"));
3340  }
3341  return -1;
3342  }
3343 
3344  struct Body *tattach = decrypt_part(a, s, fp_out, true, &is_signed);
3345  if (tattach)
3346  {
3347  tattach->goodsig = is_signed > 0;
3348 
3349  if (s->flags & MUTT_DISPLAY)
3350  {
3352  s, is_signed ?
3353  _("[-- The following data is S/MIME signed --]\n\n") :
3354  _("[-- The following data is S/MIME encrypted --]\n\n"));
3355  mutt_protected_headers_handler(tattach, s);
3356  }
3357 
3358  /* Store any protected headers in the parent so they can be
3359  * accessed for index updates after the handler recursion is done.
3360  * This is done before the handler to prevent a nested encrypted
3361  * handler from freeing the headers. */
3363  a->mime_headers = tattach->mime_headers;
3364  tattach->mime_headers = NULL;
3365 
3366  {
3367  FILE *fp_save = s->fp_in;
3368  s->fp_in = fp_out;
3369  rc = mutt_body_handler(tattach, s);
3370  s->fp_in = fp_save;
3371  }
3372 
3373  /* Embedded multipart signed protected headers override the
3374  * encrypted headers. We need to do this after the handler so
3375  * they can be printed in the pager. */
3376  if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
3377  {
3379  a->mime_headers = tattach->parts->mime_headers;
3380  tattach->parts->mime_headers = NULL;
3381  }
3382 
3383  /* if a multipart/signed is the _only_ sub-part of a multipart/encrypted,
3384  * cache signature verification status. */
3385  if (mutt_is_multipart_signed(tattach) && !tattach->next)
3386  {
3387  a->goodsig = tattach->goodsig;
3388  if (!a->goodsig)
3389  a->warnsig = tattach->warnsig;
3390  }
3391  else if (tattach->goodsig)
3392  {
3393  a->goodsig = true;
3394  a->warnsig = tattach->warnsig;
3395  }
3396 
3397  if (s->flags & MUTT_DISPLAY)
3398  {
3399  state_puts(s, "\n");
3400  state_attach_puts(s, is_signed ?
3401  _("[-- End of S/MIME signed data --]\n") :
3402  _("[-- End of S/MIME encrypted data --]\n"));
3403  }
3404 
3405  mutt_body_free(&tattach);
3406  }
3407 
3408  mutt_file_fclose(&fp_out);
3409  mutt_debug(LL_DEBUG2, "Leaving handler\n");
3410 
3411  return rc;
3412 }
3413 
3437 static const char *crypt_format_str(char *buf, size_t buflen, size_t col, int cols,
3438  char op, const char *src, const char *prec,
3439  const char *if_str, const char *else_str,
3440  unsigned long data, MuttFormatFlags flags)
3441 {
3442  char fmt[128];
3443  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
3444 
3445  struct CryptEntry *entry = (struct CryptEntry *) data;
3446  struct CryptKeyInfo *key = entry->key;
3447 
3448  /* if (isupper ((unsigned char) op)) */
3449  /* key = pkey; */
3450 
3451  KeyFlags kflags = (key->flags /* | (pkey->flags & KEYFLAG_RESTRICTIONS)
3452  | uid->flags */);
3453 
3454  switch (tolower(op))
3455  {
3456  case 'a':
3457  if (!optional)
3458  {
3459  const char *s = NULL;
3460  snprintf(fmt, sizeof(fmt), "%%%s.3s", prec);
3461  if (key->kobj->subkeys)
3462  s = gpgme_pubkey_algo_name(key->kobj->subkeys->pubkey_algo);
3463  else
3464  s = "?";
3465  snprintf(buf, buflen, fmt, s);
3466  }
3467  break;
3468 
3469  case 'c':
3470  if (!optional)
3471  {
3472  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
3473  snprintf(buf, buflen, fmt, crypt_key_abilities(kflags));
3474  }
3475  else if (!(kflags & KEYFLAG_ABILITIES))
3476  optional = false;
3477  break;
3478 
3479  case 'f':
3480  if (!optional)
3481  {
3482  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
3483  snprintf(buf, buflen, fmt, crypt_flags(kflags));
3484  }
3485  else if (!(kflags & KEYFLAG_RESTRICTIONS))
3486  optional = false;
3487  break;
3488 
3489  case 'k':
3490  if (!optional)
3491  {
3492  /* fixme: we need a way to distinguish between main and subkeys.
3493  * Store the idx in entry? */
3494  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
3495  snprintf(buf, buflen, fmt, crypt_keyid(key));
3496  }
3497  break;
3498 
3499  case 'l':
3500  if (!optional)
3501  {
3502  snprintf(fmt, sizeof(fmt), "%%%slu", prec);
3503  unsigned long val;
3504  if (key->kobj->subkeys)
3505  val = key->kobj->subkeys->length;
3506  else
3507  val = 0;
3508  snprintf(buf, buflen, fmt, val);
3509  }
3510  break;
3511 
3512  case 'n':
3513  if (!optional)
3514  {
3515  snprintf(fmt, sizeof(fmt), "%%%sd", prec);
3516  snprintf(buf, buflen, fmt, entry->num);
3517  }
3518  break;
3519 
3520  case 'p':
3521  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
3522  snprintf(buf, buflen, fmt, gpgme_get_protocol_name(key->kobj->protocol));
3523  break;
3524 
3525  case 't':
3526  {
3527  char *s = NULL;
3528  if ((kflags & KEYFLAG_ISX509))
3529  s = "x";
3530  else
3531  {
3532  switch (key->validity)
3533  {
3534  case GPGME_VALIDITY_FULL:
3535  s = "f";
3536  break;
3537  case GPGME_VALIDITY_MARGINAL:
3538  s = "m";
3539  break;
3540  case GPGME_VALIDITY_NEVER:
3541  s = "n";
3542  break;
3543  case GPGME_VALIDITY_ULTIMATE:
3544  s = "u";
3545  break;
3546  case GPGME_VALIDITY_UNDEFINED:
3547  s = "q";
3548  break;
3549  case GPGME_VALIDITY_UNKNOWN:
3550  default:
3551  s = "?";
3552  break;
3553  }
3554  }
3555  snprintf(fmt, sizeof(fmt), "%%%sc", prec);
3556  snprintf(buf, buflen, fmt, *s);
3557  break;
3558  }
3559 
3560  case 'u':
3561  if (!optional)
3562  {
3563  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
3564  snprintf(buf, buflen, fmt, key->uid);
3565  }
3566  break;
3567 
3568  case '[':
3569  {
3570  char buf2[128];
3571  bool do_locales = true;
3572  struct tm tm = { 0 };
3573 
3574  char *p = buf;
3575 
3576  const char *cp = src;
3577  if (*cp == '!')
3578  {
3579  do_locales = false;
3580  cp++;
3581  }
3582 
3583  size_t len = buflen - 1;
3584  while ((len > 0) && (*cp != ']'))
3585  {
3586  if (*cp == '%')
3587  {
3588  cp++;
3589  if (len >= 2)
3590  {
3591  *p++ = '%';
3592  *p++ = *cp;
3593  len -= 2;
3594  }
3595  else
3596  break; /* not enough space */
3597  cp++;
3598  }
3599  else
3600  {
3601  *p++ = *cp++;
3602  len--;
3603  }
3604  }
3605  *p = '\0';
3606 
3607  if (key->kobj->subkeys && (key->kobj->subkeys->timestamp > 0))
3608  tm = mutt_date_localtime(key->kobj->subkeys->timestamp);
3609  else
3610  tm = mutt_date_localtime(0); // Default to 1970-01-01
3611 
3612  if (!do_locales)
3613  setlocale(LC_TIME, "C");
3614  strftime(buf2, sizeof(buf2), buf, &tm);
3615  if (!do_locales)
3616  setlocale(LC_TIME, "");
3617 
3618  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
3619  snprintf(buf, buflen, fmt, buf2);
3620  if (len > 0)
3621  src = cp + 1;
3622  break;
3623  }
3624 
3625  default:
3626  *buf = '\0';
3627  }
3628 
3629  if (optional)
3630  {
3631  mutt_expando_format(buf, buflen, col, cols, if_str, attach_format_str, data,
3633  }
3634  else if (flags & MUTT_FORMAT_OPTIONAL)
3635  {
3636  mutt_expando_format(buf, buflen, col, cols, else_str, attach_format_str,
3637  data, MUTT_FORMAT_NO_FLAGS);
3638  }
3639  return src;
3640 }
3641 
3645 static void crypt_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
3646 {
3647  struct CryptKeyInfo **key_table = menu->data;
3648  struct CryptEntry entry;
3649 
3650  entry.key = key_table[line];
3651  entry.num = line + 1;
3652 
3653  mutt_expando_format(buf, buflen, 0, menu->win_index->state.cols,
3655  (unsigned long) &entry, MUTT_FORMAT_ARROWCURSOR);
3656 }
3657 
3666 static int compare_key_address(const void *a, const void *b)
3667 {
3668  struct CryptKeyInfo **s = (struct CryptKeyInfo **) a;
3669  struct CryptKeyInfo **t = (struct CryptKeyInfo **) b;
3670  int r;
3671 
3672  r = mutt_str_strcasecmp((*s)->uid, (*t)->uid);
3673  if (r != 0)
3674  return r > 0;
3676 }
3677 
3686 static int crypt_compare_address(const void *a, const void *b)
3687 {
3688  return (C_PgpSortKeys & SORT_REVERSE) ? !compare_key_address(a, b) :
3689  compare_key_address(a, b);
3690 }
3691 
3700 static int compare_keyid(const void *a, const void *b)
3701 {
3702  struct CryptKeyInfo **s = (struct CryptKeyInfo **) a;
3703  struct CryptKeyInfo **t = (struct CryptKeyInfo **) b;
3704  int r;
3705 
3707  if (r != 0)
3708  return r > 0;
3709  return mutt_str_strcasecmp((*s)->uid, (*t)->uid) > 0;
3710 }
3711 
3720 static int crypt_compare_keyid(const void *a, const void *b)
3721 {
3722  return (C_PgpSortKeys & SORT_REVERSE) ? !compare_keyid(a, b) : compare_keyid(a, b);
3723 }
3724 
3733 static int compare_key_date(const void *a, const void *b)
3734 {
3735  struct CryptKeyInfo **s = (struct CryptKeyInfo **) a;
3736  struct CryptKeyInfo **t = (struct CryptKeyInfo **) b;
3737  unsigned long ts = 0, tt = 0;
3738 
3739  if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
3740  ts = (*s)->kobj->subkeys->timestamp;
3741  if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
3742  tt = (*t)->kobj->subkeys->timestamp;
3743 
3744  if (ts > tt)
3745  return 1;
3746  if (ts < tt)
3747  return 0;
3748 
3749  return mutt_str_strcasecmp((*s)->uid, (*t)->uid) > 0;
3750 }
3751 
3760 static int crypt_compare_date(const void *a, const void *b)
3761 {
3762  return (C_PgpSortKeys & SORT_REVERSE) ? !compare_key_date(a, b) :
3763  compare_key_date(a, b);
3764 }
3765 
3777 static int compare_key_trust(const void *a, const void *b)
3778 {
3779  struct CryptKeyInfo **s = (struct CryptKeyInfo **) a;
3780  struct CryptKeyInfo **t = (struct CryptKeyInfo **) b;
3781  unsigned long ts = 0, tt = 0;
3782  int r;
3783 
3784  r = (((*s)->flags & KEYFLAG_RESTRICTIONS) - ((*t)->flags & KEYFLAG_RESTRICTIONS));
3785  if (r != 0)
3786  return r > 0;
3787 
3788  ts = (*s)->validity;
3789  tt = (*t)->validity;
3790  r = (tt - ts);
3791  if (r != 0)
3792  return r < 0;
3793 
3794  if ((*s)->kobj->subkeys)
3795  ts = (*s)->kobj->subkeys->length;
3796  if ((*t)->kobj->subkeys)
3797  tt = (*t)->kobj->subkeys->length;
3798  if (ts != tt)
3799  return ts > tt;
3800 
3801  if ((*s)->kobj->subkeys && ((*s)->kobj->subkeys->timestamp > 0))
3802  ts = (*s)->kobj->subkeys->timestamp;
3803  if ((*t)->kobj->subkeys && ((*t)->kobj->subkeys->timestamp > 0))
3804  tt = (*t)->kobj->subkeys->timestamp;
3805  if (ts > tt)
3806  return 1;
3807  if (ts < tt)
3808  return 0;
3809 
3810  r = mutt_str_strcasecmp((*s)->uid, (*t)->uid);
3811  if (r != 0)
3812  return r > 0;
3814 }
3815 
3824 static int crypt_compare_trust(const void *a, const void *b)
3825 {
3826  return (C_PgpSortKeys & SORT_REVERSE) ? !compare_key_trust(a, b) :
3827  compare_key_trust(a, b);
3828 }
3829 
3840 static bool print_dn_part(FILE *fp, struct DnArray *dn, const char *key)
3841 {
3842  bool any = false;
3843 
3844  for (; dn->key; dn++)
3845  {
3846  if (strcmp(dn->key, key) == 0)
3847  {
3848  if (any)
3849  fputs(" + ", fp);
3850  print_utf8(fp, dn->value, strlen(dn->value));
3851  any = true;
3852  }
3853  }
3854  return any;
3855 }
3856 
3862 static void print_dn_parts(FILE *fp, struct DnArray *dn)
3863 {
3864  static const char *const stdpart[] = {
3865  "CN", "OU", "O", "STREET", "L", "ST", "C", NULL,
3866  };
3867  bool any = false;
3868  bool any2 = false;
3869 
3870  for (int i = 0; stdpart[i]; i++)
3871  {
3872  if (any)
3873  fputs(", ", fp);
3874  any = print_dn_part(fp, dn, stdpart[i]);
3875  }
3876  /* now print the rest without any specific ordering */
3877  for (; dn->key; dn++)
3878  {
3879  int i;
3880  for (i = 0; stdpart[i]; i++)
3881  {
3882  if (strcmp(dn->key, stdpart[i]) == 0)
3883  break;
3884  }
3885  if (!stdpart[i])
3886  {
3887  if (any)
3888  fputs(", ", fp);
3889  if (!any2)
3890  fputs("(", fp);
3891  any = print_dn_part(fp, dn, dn->key);
3892  any2 = true;
3893  }
3894  }
3895  if (any2)
3896  fputs(")", fp);
3897 }
3898 
3907 static const char *parse_dn_part(struct DnArray *array, const char *str)
3908 {
3909  const char *s = NULL, *s1 = NULL;
3910  size_t n;
3911  char *p = NULL;
3912 
3913  /* parse attribute type */
3914  for (s = str + 1; (s[0] != '\0') && (s[0] != '='); s++)
3915  ;
3916  if (s[0] == '\0')
3917  return NULL; /* error */
3918  n = s - str;
3919  if (n == 0)
3920  return NULL; /* empty key */
3921  array->key = mutt_mem_malloc(n + 1);
3922  p = array->key;
3923  memcpy(p, str, n); /* fixme: trim trailing spaces */
3924  p[n] = 0;
3925  str = s + 1;
3926 
3927  if (*str == '#')
3928  { /* hexstring */
3929  str++;
3930  for (s = str; isxdigit(*s); s++)
3931  s++;
3932  n = s - str;
3933  if ((n == 0) || (n & 1))
3934  return NULL; /* empty or odd number of digits */
3935  n /= 2;
3936  p = mutt_mem_malloc(n + 1);
3937  array->value = (char *) p;
3938  for (s1 = str; n; s1 += 2, n--)
3939  sscanf(s1, "%2hhx", (unsigned char *) p++);
3940  *p = '\0';
3941  }
3942  else
3943  { /* regular v3 quoted string */
3944  for (n = 0, s = str; *s; s++)
3945  {
3946  if (*s == '\\')
3947  { /* pair */
3948  s++;
3949  if ((*s == ',') || (*s == '=') || (*s == '+') || (*s == '<') || (*s == '>') ||
3950  (*s == '#') || (*s == ';') || (*s == '\\') || (*s == '\"') || (*s == ' '))
3951  {
3952  n++;
3953  }
3954  else if (isxdigit(s[0]) && isxdigit(s[1]))
3955  {
3956  s++;
3957  n++;
3958  }
3959  else
3960  return NULL; /* invalid escape sequence */
3961  }
3962  else if (*s == '\"')
3963  return NULL; /* invalid encoding */
3964  else if ((*s == ',') || (*s == '=') || (*s == '+') || (*s == '<') ||
3965  (*s == '>') || (*s == '#') || (*s == ';'))
3966  {
3967  break;
3968  }
3969  else
3970  n++;
3971  }
3972 
3973  p = mutt_mem_malloc(n + 1);
3974  array->value = (char *) p;
3975  for (s = str; n; s++, n--)
3976  {
3977  if (*s == '\\')
3978  {
3979  s++;
3980  if (isxdigit(*s))
3981  {
3982  sscanf(s, "%2hhx", (unsigned char *) p++);
3983  s++;
3984  }
3985  else
3986  *p++ = *s;
3987  }
3988  else
3989  *p++ = *s;
3990  }
3991  *p = '\0';
3992  }
3993  return s;
3994 }
3995 
4004 static struct DnArray *parse_dn(const char *str)
4005 {
4006  struct DnArray *array = NULL;
4007  size_t arrayidx, arraysize;
4008 
4009  arraysize = 7; /* C,ST,L,O,OU,CN,email */
4010  array = mutt_mem_malloc((arraysize + 1) * sizeof(*array));
4011  arrayidx = 0;
4012  while (*str)
4013  {
4014  while (str[0] == ' ')
4015  str++;
4016  if (str[0] == '\0')
4017  break; /* ready */
4018  if (arrayidx >= arraysize)
4019  {
4020  /* neomutt lacks a real mutt_mem_realloc - so we need to copy */
4021  arraysize += 5;
4022  struct DnArray *a2 = mutt_mem_malloc((arraysize + 1) * sizeof(*array));
4023  for (int i = 0; i < arrayidx; i++)
4024  {
4025  a2[i].key = array[i].key;
4026  a2[i].value = array[i].value;
4027  }
4028  FREE(&array);
4029  array = a2;
4030  }
4031  array[arrayidx].key = NULL;
4032  array[arrayidx].value = NULL;
4033  str = parse_dn_part(array + arrayidx, str);
4034  arrayidx++;
4035  if (!str)
4036  goto failure;
4037  while (str[0] == ' ')
4038  str++;
4039  if ((str[0] != '\0') && (str[0] != ',') && (str[0] != ';') && (str[0] != '+'))
4040  goto failure; /* invalid delimiter */
4041  if (str[0] != '\0')
4042  str++;
4043  }
4044  array[arrayidx].key = NULL;
4045  array[arrayidx].value = NULL;
4046  return array;
4047 
4048 failure:
4049  for (int i = 0; i < arrayidx; i++)
4050  {
4051  FREE(&array[i].key);
4052  FREE(&array[i].value);
4053  }
4054  FREE(&array);
4055  return NULL;
4056 }
4057 
4066 static void parse_and_print_user_id(FILE *fp, const char *userid)
4067 {
4068  const char *s = NULL;
4069 
4070  if (*userid == '<')
4071  {
4072  s = strchr(userid + 1, '>');
4073  if (s)
4074  print_utf8(fp, userid + 1, s - userid - 1);
4075  }
4076  else if (*userid == '(')
4077  fputs(_("[Can't display this user ID (unknown encoding)]"), fp);
4078  else if (!digit_or_letter(userid))
4079  fputs(_("[Can't display this user ID (invalid encoding)]"), fp);
4080  else
4081  {
4082  struct DnArray *dn = parse_dn(userid);
4083  if (!dn)
4084  fputs(_("[Can't display this user ID (invalid DN)]"), fp);
4085  else
4086  {
4087  print_dn_parts(fp, dn);
4088  for (int i = 0; dn[i].key; i++)
4089  {
4090  FREE(&dn[i].key);
4091  FREE(&dn[i].value);
4092  }
4093  FREE(&dn);
4094  }
4095  }
4096 }
4097 
4104 static unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
4105 {
4106  unsigned int ret = 0;
4107 
4108  switch (cap)
4109  {
4110  case KEY_CAP_CAN_ENCRYPT:
4111  ret = key->can_encrypt;
4112  if (ret == 0)
4113  {
4114  for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
4115  {
4116  ret = subkey->can_encrypt;
4117  if (ret != 0)
4118  break;
4119  }
4120  }
4121  break;
4122  case KEY_CAP_CAN_SIGN:
4123  ret = key->can_sign;
4124  if (ret == 0)
4125  {
4126  for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
4127  {
4128  ret = subkey->can_sign;
4129  if (ret != 0)
4130  break;
4131  }
4132  }
4133  break;
4134  case KEY_CAP_CAN_CERTIFY:
4135  ret = key->can_certify;
4136  if (ret == 0)
4137  {
4138  for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
4139  {
4140  ret = subkey->can_certify;
4141  if (ret != 0)
4142  break;
4143  }
4144  }
4145  break;
4146  }
4147 
4148  return ret;
4149 }
4150 
4156 static void print_key_info(gpgme_key_t key, FILE *fp)
4157 {
4158  int idx;
4159  const char *s = NULL, *s2 = NULL;
4160  time_t tt = 0;
4161  char shortbuf[128];
4162  unsigned long aval = 0;
4163  const char *delim = NULL;
4164  gpgme_user_id_t uid = NULL;
4165  static int max_header_width = 0;
4166 
4167  if (max_header_width == 0)
4168  {
4169  for (int i = 0; i < KIP_MAX; i++)
4170  {
4172  const int width = mutt_strwidth(_(KeyInfoPrompts[i]));
4173  if (max_header_width < width)
4174  max_header_width = width;
4175  KeyInfoPadding[i] -= width;
4176  }
4177  for (int i = 0; i < KIP_MAX; i++)
4178  KeyInfoPadding[i] += max_header_width;
4179  }
4180 
4181  bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
4182 
4183  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
4184  {
4185  if (uid->revoked)
4186  continue;
4187 
4188  s = uid->uid;
4189  /* L10N: DOTFILL */
4190 
4191  if (idx == 0)
4192  fprintf(fp, "%*s", KeyInfoPadding[KIP_NAME], _(KeyInfoPrompts[KIP_NAME]));
4193  else
4194  fprintf(fp, "%*s", KeyInfoPadding[KIP_AKA], _(KeyInfoPrompts[KIP_AKA]));
4195  if (uid->invalid)
4196  {
4197  /* L10N: comes after the Name or aka if the key is invalid */
4198  fputs(_("[Invalid]"), fp);
4199  putc(' ', fp);
4200  }
4201  if (is_pgp)
4202  print_utf8(fp, s, strlen(s));
4203  else
4204  parse_and_print_user_id(fp, s);
4205  putc('\n', fp);
4206  }
4207 
4208  if (key->subkeys && (key->subkeys->timestamp > 0))
4209  {
4210  tt = key->subkeys->timestamp;
4211 
4212  mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
4213  fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_FROM],
4214  _(KeyInfoPrompts[KIP_VALID_FROM]), shortbuf);
4215  }
4216 
4217  if (key->subkeys && (key->subkeys->expires > 0))
4218  {
4219  tt = key->subkeys->expires;
4220 
4221  mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
4222  fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_TO],
4223  _(KeyInfoPrompts[KIP_VALID_TO]), shortbuf);
4224  }
4225 
4226  if (key->subkeys)
4227  s = gpgme_pubkey_algo_name(key->subkeys->pubkey_algo);
4228  else
4229  s = "?";
4230 
4231  s2 = is_pgp ? "PGP" : "X.509";
4232 
4233  if (key->subkeys)
4234  aval = key->subkeys->length;
4235 
4236  fprintf(fp, "%*s", KeyInfoPadding[KIP_KEY_TYPE], _(KeyInfoPrompts[KIP_KEY_TYPE]));
4237  /* L10N: This is printed after "Key Type: " and looks like this: PGP, 2048 bit RSA */
4238  fprintf(fp, ngettext("%s, %lu bit %s\n", "%s, %lu bit %s\n", aval), s2, aval, s);
4239 
4240  fprintf(fp, "%*s", KeyInfoPadding[KIP_KEY_USAGE], _(KeyInfoPrompts[KIP_KEY_USAGE]));
4241  delim = "";
4242 
4244  {
4245  /* L10N: value in Key Usage: field */
4246  fprintf(fp, "%s%s", delim, _("encryption"));
4247  delim = _(", ");
4248  }
4249  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
4250  {
4251  /* L10N: value in Key Usage: field */
4252  fprintf(fp, "%s%s", delim, _("signing"));
4253  delim = _(", ");
4254  }
4256  {
4257  /* L10N: value in Key Usage: field */
4258  fprintf(fp, "%s%s", delim, _("certification"));
4259  }
4260  putc('\n', fp);
4261 
4262  if (key->subkeys)
4263  {
4264  s = key->subkeys->fpr;
4265  fprintf(fp, "%*s", KeyInfoPadding[KIP_FINGERPRINT], _(KeyInfoPrompts[KIP_FINGERPRINT]));
4266  if (is_pgp && (strlen(s) == 40))
4267  {
4268  for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0') &&
4269  (s[3] != '\0') && (s[4] != '\0');
4270  s += 4, i++)
4271  {
4272  putc(*s, fp);
4273  putc(s[1], fp);
4274  putc(s[2], fp);
4275  putc(s[3], fp);
4276  putc(' ', fp);
4277  if (i == 4)
4278  putc(' ', fp);
4279  }
4280  }
4281  else
4282  {
4283  for (int i = 0; (s[0] != '\0') && (s[1] != '\0') && (s[2] != '\0'); s += 2, i++)
4284  {
4285  putc(*s, fp);
4286  putc(s[1], fp);
4287  putc(is_pgp ? ' ' : ':', fp);
4288  if (is_pgp && (i == 7))
4289  putc(' ', fp);
4290  }
4291  }
4292  fprintf(fp, "%s\n", s);
4293  }
4294 
4295  if (key->issuer_serial)
4296  {
4297  s = key->issuer_serial;
4298  if (s)
4299  {
4300  fprintf(fp, "%*s0x%s\n", KeyInfoPadding[KIP_SERIAL_NO],
4301  _(KeyInfoPrompts[KIP_SERIAL_NO]), s);
4302  }
4303  }
4304 
4305  if (key->issuer_name)
4306  {
4307  s = key->issuer_name;
4308  if (s)
4309  {
4310  fprintf(fp, "%*s", KeyInfoPadding[KIP_ISSUED_BY], _(KeyInfoPrompts[KIP_ISSUED_BY]));
4311  parse_and_print_user_id(fp, s);
4312  putc('\n', fp);
4313  }
4314  }
4315 
4316  /* For PGP we list all subkeys. */
4317  if (is_pgp)
4318  {
4319  gpgme_subkey_t subkey = NULL;
4320 
4321  for (idx = 1, subkey = key->subkeys; subkey; idx++, subkey = subkey->next)
4322  {
4323  s = subkey->keyid;
4324 
4325  putc('\n', fp);
4326  if (strlen(s) == 16)
4327  s += 8; /* display only the short keyID */
4328  fprintf(fp, "%*s0x%s", KeyInfoPadding[KIP_SUBKEY], _(KeyInfoPrompts[KIP_SUBKEY]), s);
4329  if (subkey->revoked)
4330  {
4331  putc(' ', fp);
4332  /* L10N: describes a subkey */
4333  fputs(_("[Revoked]"), fp);
4334  }
4335  if (subkey->invalid)
4336  {
4337  putc(' ', fp);
4338  /* L10N: describes a subkey */
4339  fputs(_("[Invalid]"), fp);
4340  }
4341  if (subkey->expired)
4342  {
4343  putc(' ', fp);
4344  /* L10N: describes a subkey */
4345  fputs(_("[Expired]"), fp);
4346  }
4347  if (subkey->disabled)
4348  {
4349  putc(' ', fp);
4350  /* L10N: describes a subkey */
4351  fputs(_("[Disabled]"), fp);
4352  }
4353  putc('\n', fp);
4354 
4355  if (subkey->timestamp > 0)
4356  {
4357  tt = subkey->timestamp;
4358 
4359  mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
4360  fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_FROM],
4361  _(KeyInfoPrompts[KIP_VALID_FROM]), shortbuf);
4362  }
4363 
4364  if (subkey->expires > 0)
4365  {
4366  tt = subkey->expires;
4367 
4368  mutt_date_localtime_format(shortbuf, sizeof(shortbuf), nl_langinfo(D_T_FMT), tt);
4369  fprintf(fp, "%*s%s\n", KeyInfoPadding[KIP_VALID_TO],
4370  _(KeyInfoPrompts[KIP_VALID_TO]), shortbuf);
4371  }
4372 
4373  s = gpgme_pubkey_algo_name(subkey->pubkey_algo);
4374 
4375  aval = subkey->length;
4376 
4377  fprintf(fp, "%*s", KeyInfoPadding[KIP_KEY_TYPE], _(KeyInfoPrompts[KIP_KEY_TYPE]));
4378  /* L10N: This is printed after "Key Type: " and looks like this: PGP, 2048 bit RSA */
4379  fprintf(fp, ngettext("%s, %lu bit %s\n", "%s, %lu bit %s\n", aval), "PGP", aval, s);
4380 
4381  fprintf(fp, "%*s", KeyInfoPadding[KIP_KEY_USAGE], _(KeyInfoPrompts[KIP_KEY_USAGE]));
4382  delim = "";
4383 
4384  if (subkey->can_encrypt)
4385  {
4386  fprintf(fp, "%s%s", delim, _("encryption"));
4387  delim = _(", ");
4388  }
4389  if (subkey->can_sign)
4390  {
4391  fprintf(fp, "%s%s", delim, _("signing"));
4392  delim = _(", ");
4393  }
4394  if (subkey->can_certify)
4395  {
4396  fprintf(fp, "%s%s", delim, _("certification"));
4397  }
4398  putc('\n', fp);
4399  }
4400  }
4401 }
4402 
4407 static void verify_key(struct CryptKeyInfo *key)
4408 {
4409  char cmd[1024];
4410  const char *s = NULL;
4411  gpgme_ctx_t listctx = NULL;
4412  gpgme_error_t err;
4413  gpgme_key_t k = NULL;
4414  int maxdepth = 100;
4415 
4416  struct Buffer tempfile = mutt_buffer_make(PATH_MAX);
4417  mutt_buffer_mktemp(&tempfile);
4418  FILE *fp = mutt_file_fopen(mutt_b2s(&tempfile), "w");
4419  if (!fp)
4420  {
4421  mutt_perror(_("Can't create temporary file"));
4422  goto cleanup;
4423  }
4424  mutt_message(_("Collecting data..."));
4425 
4426  print_key_info(key->kobj, fp);
4427 
4428  listctx = create_gpgme_context(key->flags & KEYFLAG_ISX509);
4429 
4430  k = key->kobj;
4431  gpgme_key_ref(k);
4432  while ((s = k->chain_id) && k->subkeys && (strcmp(s, k->subkeys->fpr) != 0))
4433  {
4434  putc('\n', fp);
4435  err = gpgme_op_keylist_start(listctx, s, 0);
4436  gpgme_key_unref(k);
4437  k = NULL;
4438  if (err == 0)
4439  err = gpgme_op_keylist_next(listctx, &k);
4440  if (err != 0)
4441  {
4442  fprintf(fp, _("Error finding issuer key: %s\n"), gpgme_strerror(err));
4443  goto leave;
4444  }
4445  gpgme_op_keylist_end(listctx);
4446 
4447  print_key_info(k, fp);
4448  if (!--maxdepth)
4449  {
4450  putc('\n', fp);
4451  fputs(_("Error: certification chain too long - stopping here\n"), fp);
4452  break;
4453  }
4454  }
4455 
4456 leave:
4457  gpgme_key_unref(k);
4458  gpgme_release(listctx);
4459  mutt_file_fclose(&fp);
4460  mutt_clear_error();
4461  snprintf(cmd, sizeof(cmd), _("Key ID: 0x%s"), crypt_keyid(key));
4462  mutt_do_pager(cmd, mutt_b2s(&tempfile), MUTT_PAGER_NO_FLAGS, NULL);
4463 
4464 cleanup:
4465  mutt_buffer_dealloc(&tempfile);
4466 }
4467 
4477 static char *list_to_pattern(struct ListHead *list)
4478 {
4479  char *pattern = NULL, *p = NULL;
4480  const char *s = NULL;
4481  size_t n;
4482 
4483  n = 0;
4484  struct ListNode *np = NULL;
4485  STAILQ_FOREACH(np, list, entries)
4486  {
4487  for (s = np->data; *s; s++)
4488  {
4489  if ((*s == '%') || (*s == '+'))
4490  n += 2;
4491  n++;
4492  }
4493  n++; /* delimiter or end of string */
4494  }
4495  n++; /* make sure to allocate at least one byte */
4496  p = mutt_mem_calloc(1, n);
4497  pattern = p;
4498  STAILQ_FOREACH(np, list, entries)
4499  {
4500  s = np->data;
4501  if (*s)
4502  {
4503  if (np != STAILQ_FIRST(list))
4504  *p++ = ' ';
4505  for (s = np->data; *s; s++)
4506  {
4507  if (*s == '%')
4508  {
4509  *p++ = '%';
4510  *p++ = '2';
4511  *p++ = '5';
4512  }
4513  else if (*s == '+')
4514  {
4515  *p++ = '%';
4516  *p++ = '2';
4517  *p++ = 'B';
4518  }
4519  else if (*s == ' ')
4520  *p++ = '+';
4521  else
4522  *p++ = *s;
4523  }
4524  }
4525  }
4526  *p = '\0';
4527  return pattern;
4528 }
4529 
4540 static struct CryptKeyInfo *get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
4541 {
4542  struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
4543  gpgme_error_t err;
4544  gpgme_ctx_t ctx = NULL;
4545  gpgme_key_t key = NULL;
4546  int idx;
4547  gpgme_user_id_t uid = NULL;
4548 
4549  char *pattern = list_to_pattern(hints);
4550  if (!pattern)
4551  return NULL;
4552 
4553  ctx = create_gpgme_context(0);
4554  db = NULL;
4555  kend = &db;
4556 
4557  if ((app & APPLICATION_PGP))
4558  {
4559  /* It's all a mess. That old GPGME expects different things depending on
4560  * the protocol. For gpg we don't need percent escaped pappert but simple
4561  * strings passed in an array to the keylist_ext_start function. */
4562  size_t n = 0;
4563  struct ListNode *np = NULL;
4564  STAILQ_FOREACH(np, hints, entries)
4565  {
4566  if (np->data && *np->data)
4567  n++;
4568  }
4569  if (n == 0)
4570  goto no_pgphints;
4571 
4572  char **patarr = mutt_mem_calloc(n + 1, sizeof(*patarr));
4573  n = 0;
4574  STAILQ_FOREACH(np, hints, entries)
4575  {
4576  if (np->data && *np->data)
4577  patarr[n++] = mutt_str_strdup(np->data);
4578  }
4579  patarr[n] = NULL;
4580  err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
4581  for (n = 0; patarr[n]; n++)
4582  FREE(&patarr[n]);
4583  FREE(&patarr);
4584  if (err != 0)
4585  {
4586  mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
4587  gpgme_release(ctx);
4588  FREE(&pattern);
4589  return NULL;
4590  }
4591 
4592  while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
4593  {
4594  KeyFlags flags = KEYFLAG_NO_FLAGS;
4595 
4597  flags |= KEYFLAG_CANENCRYPT;
4598  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
4599  flags |= KEYFLAG_CANSIGN;
4600 
4601  if (key->revoked)
4602  flags |= KEYFLAG_REVOKED;
4603  if (key->expired)
4604  flags |= KEYFLAG_EXPIRED;
4605  if (key->disabled)
4606  flags |= KEYFLAG_DISABLED;
4607 
4608  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
4609  {
4610  k = mutt_mem_calloc(1, sizeof(*k));
4611  k->kobj = key;
4612  gpgme_key_ref(k->kobj);
4613  k->idx = idx;
4614  k->uid = uid->uid;
4615  k->flags = flags;
4616  if (uid->revoked)
4617  k->flags |= KEYFLAG_REVOKED;
4618  k->validity = uid->validity;
4619  *kend = k;
4620  kend = &k->next;
4621  }
4622  gpgme_key_unref(key);
4623  }
4624  if (gpg_err_code(err) != GPG_ERR_EOF)
4625  mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
4626  gpgme_op_keylist_end(ctx);
4627  no_pgphints:;
4628  }
4629 
4630  if ((app & APPLICATION_SMIME))
4631  {
4632  /* and now look for x509 certificates */
4633  gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
4634  err = gpgme_op_keylist_start(ctx, pattern, 0);
4635  if (err != 0)
4636  {
4637  mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
4638  gpgme_release(ctx);
4639  FREE(&pattern);
4640  return NULL;
4641  }
4642 
4643  while ((err = gpgme_op_keylist_next(ctx, &key)) == 0)
4644  {
4645  KeyFlags flags = KEYFLAG_ISX509;
4646 
4648  flags |= KEYFLAG_CANENCRYPT;
4649  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
4650  flags |= KEYFLAG_CANSIGN;
4651 
4652  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
4653  {
4654  k = mutt_mem_calloc(1, sizeof(*k));
4655  k->kobj = key;
4656  gpgme_key_ref(k->kobj);
4657  k->idx = idx;
4658  k->uid = uid->uid;
4659  k->flags = flags;
4660  k->validity = uid->validity;
4661  *kend = k;
4662  kend = &k->next;
4663  }
4664  gpgme_key_unref(key);
4665  }
4666  if (gpg_err_code(err) != GPG_ERR_EOF)
4667  mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
4668  gpgme_op_keylist_end(ctx);
4669  }
4670 
4671  gpgme_release(ctx);
4672  FREE(&pattern);
4673  return db;
4674 }
4675 
4684 static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
4685 {
4686  char *scratch = mutt_str_strdup(str);
4687  if (!scratch)
4688  return;
4689 
4690  for (char *t = strtok(scratch, " ,.:\"()<>\n"); t;
4691  t = strtok(NULL, " ,.:\"()<>\n"))
4692  {
4693  if (strlen(t) > 3)
4695  }
4696 
4697  FREE(&scratch);
4698 }
4699 
4711 static struct CryptKeyInfo *crypt_select_key(struct CryptKeyInfo *keys,
4712  struct Address *p, const char *s,
4713  unsigned int app, int *forced_valid)
4714 {
4715  int keymax;
4716  int i;
4717  bool done = false;
4718  char helpstr[1024], buf[1024];
4719  struct CryptKeyInfo *k = NULL;
4720  int (*f)(const void *, const void *);
4721  enum MenuType menu_to_use = MENU_GENERIC;
4722  bool unusable = false;
4723 
4724  *forced_valid = 0;
4725 
4726  /* build the key table */
4727  keymax = 0;
4728  i = 0;
4729  struct CryptKeyInfo **key_table = NULL;
4730  for (k = keys; k; k = k->next)
4731  {
4732  if (!C_PgpShowUnusable && (k->flags & KEYFLAG_CANTUSE))
4733  {
4734  unusable = true;
4735  continue;
4736  }
4737 
4738  if (i == keymax)
4739  {
4740  keymax += 20;
4741  mutt_mem_realloc(&key_table, sizeof(struct CryptKeyInfo *) * keymax);
4742  }
4743 
4744  key_table[i++] = k;
4745  }
4746 
4747  if (!i && unusable)
4748  {
4749  mutt_error(_("All matching keys are marked expired/revoked"));
4750  return NULL;
4751  }
4752 
4753  switch (C_PgpSortKeys & SORT_MASK)
4754  {
4755  case SORT_ADDRESS:
4757  break;
4758  case SORT_DATE:
4759  f = crypt_compare_date;
4760  break;
4761  case SORT_KEYID:
4762  f = crypt_compare_keyid;
4763  break;
4764  case SORT_TRUST:
4765  default:
4766  f = crypt_compare_trust;
4767  break;
4768  }
4769  qsort(key_table, i, sizeof(struct CryptKeyInfo *), f);
4770 
4771  if (app & APPLICATION_PGP)
4772  menu_to_use = MENU_KEY_SELECT_PGP;
4773  else if (app & APPLICATION_SMIME)
4774  menu_to_use = MENU_KEY_SELECT_SMIME;
4775 
4776  helpstr[0] = '\0';
4777  mutt_make_help(buf, sizeof(buf), _("Exit "), menu_to_use, OP_EXIT);
4778  strcat(helpstr, buf);
4779  mutt_make_help(buf, sizeof(buf), _("Select "), menu_to_use, OP_GENERIC_SELECT_ENTRY);
4780  strcat(helpstr, buf);
4781  mutt_make_help(buf, sizeof(buf), _("Check key "), menu_to_use, OP_VERIFY_KEY);
4782  strcat(helpstr, buf);
4783  mutt_make_help(buf, sizeof(buf), _("Help"), menu_to_use, OP_HELP);
4784  strcat(helpstr, buf);
4785 
4786  struct MuttWindow *dlg =
4789  dlg->type = WT_DIALOG;
4790  struct MuttWindow *index =
4793  index->type = WT_INDEX;
4794  struct MuttWindow *ibar = mutt_window_new(
4796  ibar->type = WT_INDEX_BAR;
4797 
4798  if (C_StatusOnTop)
4799  {
4800  mutt_window_add_child(dlg, ibar);
4801  mutt_window_add_child(dlg, index);
4802  }
4803  else
4804  {
4805  mutt_window_add_child(dlg, index);
4806  mutt_window_add_child(dlg, ibar);
4807  }
4808 
4809  dialog_push(dlg);
4810 
4811  struct Menu *menu = mutt_menu_new(menu_to_use);
4812 
4813  menu->pagelen = index->state.rows;
4814  menu->win_index = index;
4815  menu->win_ibar = ibar;
4816 
4817  menu->max = i;
4819  menu->help = helpstr;
4820  menu->data = key_table;
4821  mutt_menu_push_current(menu);
4822 
4823  {
4824  const char *ts = NULL;
4825 
4826  if ((app & APPLICATION_PGP) && (app & APPLICATION_SMIME))
4827  ts = _("PGP and S/MIME keys matching");
4828  else if ((app & APPLICATION_PGP))
4829  ts = _("PGP keys matching");
4830  else if ((app & APPLICATION_SMIME))
4831  ts = _("S/MIME keys matching");
4832  else
4833  ts = _("keys matching");
4834 
4835  if (p)
4836  {
4837  /* L10N:
4838  %1$s is one of the previous four entries.
4839  %2$s is an address.
4840  e.g. "S/MIME keys matching <me@mutt.org>" */
4841  snprintf(buf, sizeof(buf), _("%s <%s>"), ts, p->mailbox);
4842  }
4843  else
4844  {
4845  /* L10N: e.g. 'S/MIME keys matching "Michael Elkins".' */
4846  snprintf(buf, sizeof(buf), _("%s \"%s\""), ts, s);
4847  }
4848  menu->title = buf;
4849  }
4850 
4851  mutt_clear_error();
4852  k = NULL;
4853  while (!done)
4854  {
4855  *forced_valid = 0;
4856  switch (mutt_menu_loop(menu))
4857  {
4858  case OP_VERIFY_KEY:
4859  verify_key(key_table[menu->current]);
4860  menu->redraw = REDRAW_FULL;
4861  break;
4862 
4863  case OP_VIEW_ID:
4864  mutt_message("%s", key_table[menu->current]->uid);
4865  break;
4866 
4867  case OP_GENERIC_SELECT_ENTRY:
4868  /* FIXME make error reporting more verbose - this should be
4869  * easy because gpgme provides more information */
4870  if (OptPgpCheckTrust)
4871  {
4872  if (!crypt_key_is_valid(key_table[menu->current]))
4873  {
4874  mutt_error(_("This key can't be used: "
4875  "expired/disabled/revoked"));
4876  break;
4877  }
4878  }
4879 
4880  if (OptPgpCheckTrust && (!crypt_id_is_valid(key_table[menu->current]) ||
4881  !crypt_id_is_strong(key_table[menu->current])))
4882  {
4883  const char *warn_s = NULL;
4884  char buf2[1024];
4885 
4886  if (key_table[menu->current]->flags & KEYFLAG_CANTUSE)
4887  {
4888  warn_s = _("ID is expired/disabled/revoked. Do you really want to "
4889  "use the key?");
4890  }
4891  else
4892  {
4893  warn_s = "??";
4894  switch (key_table[menu->current]->validity)
4895  {
4896  case GPGME_VALIDITY_NEVER:
4897  warn_s =
4898  _("ID is not valid. Do you really want to use the key?");
4899  break;
4900  case GPGME_VALIDITY_MARGINAL:
4901  warn_s = _("ID is only marginally valid. Do you really want to "
4902  "use the key?");
4903  break;
4904  case GPGME_VALIDITY_FULL:
4905  case GPGME_VALIDITY_ULTIMATE:
4906  break;
4907  case GPGME_VALIDITY_UNKNOWN:
4908  case GPGME_VALIDITY_UNDEFINED:
4909  warn_s = _("ID has undefined validity. Do you really want to "
4910  "use the key?");
4911  break;
4912  }
4913  }
4914 
4915  snprintf(buf2, sizeof(buf2), "%s", warn_s);
4916 
4917  if (mutt_yesorno(buf2, MUTT_NO) != MUTT_YES)
4918  {
4919  mutt_clear_error();
4920  break;
4921  }
4922 
4923  /* A '!' is appended to a key in find_keys() when forced_valid is
4924  * set. Prior to gpgme 1.11.0, encrypt_gpgme_object() called
4925  * create_recipient_set() which interpreted the '!' to mean set
4926  * GPGME_VALIDITY_FULL for the key.
4927  *
4928  * Starting in gpgme 1.11.0, we now use a '\n' delimited recipient
4929  * string, which is passed directly to the gpgme_op_encrypt_ext()
4930  * function. This allows to use the original meaning of '!' to
4931  * force a subkey use. */
4932 #if (GPGME_VERSION_NUMBER < 0x010b00) /* gpgme < 1.11.0 */
4933  *forced_valid = 1;
4934 #endif
4935  }
4936 
4937  k = crypt_copy_key(key_table[menu->current]);
4938  done = true;
4939  break;
4940 
4941  case OP_EXIT:
4942  k = NULL;
4943  done = true;
4944  break;
4945  }
4946  }
4947 
4948  mutt_menu_pop_current(menu);
4949  mutt_menu_free(&menu);
4950  FREE(&key_table);
4951  dialog_pop();
4952  mutt_window_free(&dlg);
4953 
4954  return k;
4955 }
4956 
4966 static struct CryptKeyInfo *crypt_getkeybyaddr(struct Address *a,
4967  KeyFlags abilities, unsigned int app,
4968  int *forced_valid, bool oppenc_mode)
4969 {
4970  struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
4971 
4972  int multi = false;
4973  int this_key_has_strong = false;
4974  int this_key_has_addr_match = false;
4975  int match = false;
4976 
4977  struct CryptKeyInfo *keys = NULL, *k = NULL;
4978  struct CryptKeyInfo *the_strong_valid_key = NULL;
4979  struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
4980  struct CryptKeyInfo *matches = NULL;
4981  struct CryptKeyInfo **matches_endp = &matches;
4982 
4983  *forced_valid = 0;
4984 
4985  if (a && a->mailbox)
4986  crypt_add_string_to_hints(a->mailbox, &hints);
4987  if (a && a->personal)
4988  crypt_add_string_to_hints(a->personal, &hints);
4989 
4990  if (!oppenc_mode)
4991  mutt_message(_("Looking for keys matching \"%s\"..."), a ? a->mailbox : "");
4992  keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
4993 
4994  mutt_list_free(&hints);
4995 
4996  if (!keys)
4997  return NULL;
4998 
4999  mutt_debug(LL_DEBUG5, "looking for %s <%s>\n", a ? a->personal : "", a ? a->mailbox : "");
5000 
5001  for (k = keys; k; k = k->next)
5002  {
5003  mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
5004 
5005  if (abilities && !(k->flags & abilities))
5006  {
5007  mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
5008  continue;
5009  }
5010 
5011  this_key_has_strong = false; /* strong and valid match */
5012  this_key_has_addr_match = false;
5013  match = false; /* any match */
5014 
5015  struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
5016  mutt_addrlist_parse(&alist, k->uid);
5017  struct Address *ka = NULL;
5018  TAILQ_FOREACH(ka, &alist, entries)
5019  {
5020  int validity = crypt_id_matches_addr(a, ka, k);
5021 
5022  if (validity & CRYPT_KV_MATCH) /* something matches */
5023  {
5024  match = true;
5025 
5026  if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
5027  {
5028  if (validity & CRYPT_KV_STRONGID)
5029  {
5030  if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
5031  multi = true;
5032  this_key_has_strong = true;
5033  }
5034  else
5035  this_key_has_addr_match = true;
5036  }
5037  }
5038  }
5039  mutt_addrlist_clear(&alist);
5040 
5041  if (match)
5042  {
5043  struct CryptKeyInfo *tmp = crypt_copy_key(k);
5044  *matches_endp = tmp;
5045  matches_endp = &tmp->next;
5046 
5047  if (this_key_has_strong)
5048  the_strong_valid_key = tmp;
5049  else if (this_key_has_addr_match)
5050  a_valid_addrmatch_key = tmp;
5051  }
5052  }
5053 
5054  crypt_key_free(&keys);
5055 
5056  if (matches)
5057  {
5058  if (oppenc_mode)
5059  {
5060  if (the_strong_valid_key)
5061  k = crypt_copy_key(the_strong_valid_key);
5062  else if (a_valid_addrmatch_key && !C_CryptOpportunisticEncryptStrongKeys)
5063  k = crypt_copy_key(a_valid_addrmatch_key);
5064  else
5065  k = NULL;
5066  }
5067  else if (the_strong_valid_key && !multi)
5068  {
5069  /* There was precisely one strong match on a valid ID.
5070  * Proceed without asking the user. */
5071  k = crypt_copy_key(the_strong_valid_key);
5072  }
5073  else
5074  {
5075  /* Else: Ask the user. */
5076  k = crypt_select_key(matches, a, NULL, app, forced_valid);
5077  }
5078 
5079  crypt_key_free(&matches);
5080  }
5081  else
5082  k = NULL;
5083 
5084  return k;
5085 }
5086 
5095 static struct CryptKeyInfo *crypt_getkeybystr(const char *p, KeyFlags abilities,
5096  unsigned int app, int *forced_valid)
5097 {
5098  struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
5099  struct CryptKeyInfo *matches = NULL;
5100  struct CryptKeyInfo **matches_endp = &matches;
5101  struct CryptKeyInfo *k = NULL;
5102  const char *ps = NULL, *pl = NULL, *phint = NULL;
5103 
5104  mutt_message(_("Looking for keys matching \"%s\"..."), p);
5105 
5106  *forced_valid = 0;
5107 
5108  const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
5109  crypt_add_string_to_hints(phint, &hints);
5110  struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
5111  mutt_list_free(&hints);
5112 
5113  if (!keys)
5114  {
5115  FREE(&pfcopy);
5116  return NULL;
5117  }
5118 
5119  for (k = keys; k; k = k->next)
5120  {
5121  if (abilities && !(k->flags & abilities))
5122  continue;
5123 
5124  mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
5125  crypt_long_keyid(k), k->uid);
5126 
5127  if (!*p || (pfcopy && (mutt_str_strcasecmp(pfcopy, crypt_fpr(k)) == 0)) ||
5128  (pl && (mutt_str_strcasecmp(pl, crypt_long_keyid(k)) == 0)) ||
5129  (ps && (mutt_str_strcasecmp(ps, crypt_short_keyid(k)) == 0)) ||
5130  mutt_str_stristr(k->uid, p))
5131  {
5132  mutt_debug(LL_DEBUG5, "match\n");
5133 
5134  struct CryptKeyInfo *tmp = crypt_copy_key(k);
5135  *matches_endp = tmp;
5136  matches_endp = &tmp->next;
5137  }
5138  else
5139  {
5140  mutt_debug(LL_DEBUG5, "no match\n");
5141  }
5142  }
5143 
5144  FREE(&pfcopy);
5145  crypt_key_free(&keys);
5146 
5147  if (matches)
5148  {
5149  k = crypt_select_key(matches, NULL, p, app, forced_valid);
5150  crypt_key_free(&matches);
5151  return k;
5152  }
5153 
5154  return NULL;
5155 }
5156 
5169 static struct CryptKeyInfo *crypt_ask_for_key(char *tag, char *whatfor, KeyFlags abilities,
5170  unsigned int app, int *forced_valid)
5171 {
5172  struct CryptKeyInfo *key = NULL;
5173  char resp[128];
5174  struct CryptCache *l = NULL;
5175  int dummy;
5176 
5177  if (!forced_valid)
5178  forced_valid = &dummy;
5179 
5180  mutt_clear_error();
5181 
5182  *forced_valid = 0;
5183  resp[0] = '\0';
5184  if (whatfor)
5185  {
5186  for (l = id_defaults; l; l = l->next)
5187  {
5188  if (mutt_str_strcasecmp(whatfor, l->what) == 0)
5189  {
5190  mutt_str_strfcpy(resp, l->dflt, sizeof(resp));
5191  break;
5192  }
5193  }
5194  }
5195 
5196  while (true)
5197  {
5198  resp[0] = '\0';
5199  if (mutt_get_field(tag, resp, sizeof(resp), MUTT_CLEAR) != 0)
5200  return NULL;
5201 
5202  if (whatfor)
5203  {
5204  if (l)
5205  mutt_str_replace(&l->dflt, resp);
5206  else
5207  {
5208  l = mutt_mem_malloc(sizeof(struct CryptCache));
5209  l->next = id_defaults;
5210  id_defaults = l;
5211  l->what = mutt_str_strdup(whatfor);
5212  l->dflt = mutt_str_strdup(resp);
5213  }
5214  }
5215 
5216  key = crypt_getkeybystr(resp, abilities, app, forced_valid);
5217  if (key)
5218  return key;
5219 
5220  mutt_error(_("No matching keys found for \"%s\""), resp);
5221  }
5222  /* not reached */
5223 }
5224 
5236 static char *find_keys(struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
5237 {
5238  struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
5239  struct ListNode *crypt_hook = NULL;
5240  const char *keyid = NULL;
5241  char *keylist = NULL;
5242  size_t keylist_size = 0;
5243  size_t keylist_used = 0;
5244  struct Address *p = NULL;
5245  struct CryptKeyInfo *k_info = NULL;
5246  const char *fqdn = mutt_fqdn(true);
5247  char buf[1024];
5248  int forced_valid;
5249  bool key_selected;
5250  struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
5251 
5252  struct Address *a = NULL;
5253  TAILQ_FOREACH(a, addrlist, entries)
5254  {
5255  key_selected = false;
5256  mutt_crypt_hook(&crypt_hook_list, a);
5257  crypt_hook = STAILQ_FIRST(&crypt_hook_list);
5258  do
5259  {
5260  p = a;
5261  forced_valid = 0;
5262  k_info = NULL;
5263 
5264  if (crypt_hook)
5265  {
5266  keyid = crypt_hook->data;
5267  enum QuadOption ans = MUTT_YES;
5268  if (!oppenc_mode && C_CryptConfirmhook)
5269  {
5270  snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid, p->mailbox);
5271  ans = mutt_yesorno(buf, MUTT_YES);
5272  }
5273  if (ans == MUTT_YES)
5274  {
5275  if (crypt_is_numerical_keyid(keyid))
5276  {
5277  if (strncmp(keyid, "0x", 2) == 0)
5278  keyid += 2;
5279  goto bypass_selection; /* you don't see this. */
5280  }
5281 
5282  /* check for e-mail address */
5283  mutt_addrlist_clear(&hookal);
5284  if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
5285  {
5286  mutt_addrlist_qualify(&hookal, fqdn);
5287  p = TAILQ_FIRST(&hookal);
5288  }
5289  else if (!oppenc_mode)
5290  {
5291  k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
5292  }
5293  }
5294  else if (ans == MUTT_NO)
5295  {
5296  if (key_selected || STAILQ_NEXT(crypt_hook, entries))
5297  {
5298  crypt_hook = STAILQ_NEXT(crypt_hook, entries);
5299  continue;
5300  }
5301  }
5302  else if (ans == MUTT_ABORT)
5303  {
5304  FREE(&keylist);
5305  mutt_addrlist_clear(&hookal);
5306  mutt_list_free(&crypt_hook_list);
5307  return NULL;
5308  }
5309  }
5310 
5311  if (!k_info)
5312  {
5313  k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
5314  }
5315 
5316  if (!k_info && !oppenc_mode)
5317  {
5318  snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), p->mailbox);
5319 
5320  k_info = crypt_ask_for_key(buf, p->mailbox, KEYFLAG_CANENCRYPT, app, &forced_valid);
5321  }
5322 
5323  if (!k_info)
5324  {
5325  FREE(&keylist);
5326  mutt_addrlist_clear(&hookal);
5327  mutt_list_free(&crypt_hook_list);
5328  return NULL;
5329  }
5330 
5331  keyid = crypt_fpr_or_lkeyid(k_info);
5332 
5333  bypass_selection:
5334  keylist_size += mutt_str_strlen(keyid) + 4 + 1;
5335  mutt_mem_realloc(&keylist, keylist_size);
5336  sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
5337  keyid, forced_valid ? "!" : "");
5338  keylist_used = mutt_str_strlen(keylist);
5339 
5340  key_selected = true;
5341 
5342  crypt_key_free(&k_info);
5343  mutt_addrlist_clear(&hookal);
5344 
5345  if (crypt_hook)
5346  crypt_hook = STAILQ_NEXT(crypt_hook, entries);
5347 
5348  } while (crypt_hook);
5349 
5350  mutt_list_free(&crypt_hook_list);
5351  }
5352  return keylist;
5353 }
5354 
5358 char *pgp_gpgme_find_keys(struct AddressList *addrlist, bool oppenc_mode)
5359 {
5360  return find_keys(addrlist, APPLICATION_PGP, oppenc_mode);
5361 }
5362 
5366 char *smime_gpgme_find_keys(struct AddressList *addrlist, bool oppenc_mode)
5367 {
5368  return find_keys(addrlist, APPLICATION_SMIME, oppenc_mode);
5369 }
5370 
5384 {
5385  int rc = -1, junk;
5386  gpgme_error_t err;
5387  gpgme_key_t key = NULL;
5388  gpgme_user_id_t uid = NULL;
5389  struct CryptKeyInfo *results = NULL, *k = NULL;
5390  struct CryptKeyInfo **kend = NULL;
5391  struct CryptKeyInfo *choice = NULL;
5392 
5393  gpgme_ctx_t ctx = create_gpgme_context(false);
5394 
5395  /* list all secret keys */
5396  if (gpgme_op_keylist_start(ctx, NULL, 1))
5397  goto cleanup;
5398 
5399  kend = &results;
5400 
5401  while (!(err = gpgme_op_keylist_next(ctx, &key)))
5402  {
5404 
5406  flags |= KEYFLAG_CANENCRYPT;
5407  if (key_check_cap(key, KEY_CAP_CAN_SIGN))
5408  flags |= KEYFLAG_CANSIGN;
5409 
5410  if (key->revoked)
5411  flags |= KEYFLAG_REVOKED;
5412  if (key->expired)
5413  flags |= KEYFLAG_EXPIRED;
5414  if (key->disabled)
5415  flags |= KEYFLAG_DISABLED;
5416 
5417  int idx;
5418  for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
5419  {
5420  k = mutt_mem_calloc(1, sizeof(*k));
5421  k->kobj = key;
5422  gpgme_key_ref(k->kobj);
5423  k->idx = idx;
5424  k->uid = uid->uid;
5425  k->flags = flags;
5426  if (uid->revoked)
5427  k->flags |= KEYFLAG_REVOKED;
5428  k->validity = uid->validity;
5429  *kend = k;
5430  kend = &k->next;
5431  }
5432  gpgme_key_unref(key);
5433  }
5434  if (gpg_err_code(err) != GPG_ERR_EOF)
5435  mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
5436  gpgme_op_keylist_end(ctx);
5437 
5438  if (!results)
5439  {
5440  /* L10N:
5441  mutt_gpgme_select_secret_key() tries to list all secret keys to choose
5442  from. This error is displayed if no results were found.
5443  */
5444  mutt_error(_("No secret keys found"));
5445  goto cleanup;
5446  }
5447 
5448  choice = crypt_select_key(results, NULL, "*", APPLICATION_PGP, &junk);
5449  if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
5450  goto cleanup;
5451  mutt_buffer_strcpy(keyid, choice->kobj->subkeys->fpr);
5452 
5453  rc = 0;
5454 
5455 cleanup:
5456  crypt_key_free(&choice);
5457  crypt_key_free(&results);
5458  gpgme_release(ctx);
5459  return rc;
5460 }
5461 
5466 {
5467 #ifdef HAVE_GPGME_OP_EXPORT_KEYS
5468  gpgme_ctx_t context = NULL;
5469  gpgme_key_t export_keys[2] = { 0 };
5470  gpgme_data_t keydata = NULL;
5471  gpgme_error_t err;
5472  struct Body *att = NULL;
5473  char buf[1024];
5474  struct stat sb;
5475 
5476  OptPgpCheckTrust = false;
5477 
5478  struct CryptKeyInfo *key = crypt_ask_for_key(_("Please enter the key ID: "), NULL,
5480  if (!key)
5481  goto bail;
5482  export_keys[0] = key->kobj;
5483  export_keys[1] = NULL;
5484 
5485  context = create_gpgme_context(false);
5486  gpgme_set_armor(context, 1);
5487  keydata = create_gpgme_data();
5488  err = gpgme_op_export_keys(context, export_keys, 0, keydata);
5489  if (err != GPG_ERR_NO_ERROR)
5490  {
5491  mutt_error(_("Error exporting key: %s"), gpgme_strerror(err));
5492  goto bail;
5493  }
5494 
5495  char *tempf = data_object_to_tempfile(keydata, NULL);
5496  if (!tempf)
5497  goto bail;
5498 
5499  att = mutt_body_new();
5500  /* tempf is a newly allocated string, so this is correct: */
5501  att->filename = tempf;
5502  att->unlink = true;
5503  att->use_disp = false;
5504  att->type = TYPE_APPLICATION;
5505  att->subtype = mutt_str_strdup("pgp-keys");
5506  /* L10N: MIME description for exported (attached) keys.
5507  You can translate this entry to a non-ASCII string (it will be encoded),
5508  but it may be safer to keep it untranslated. */
5509  snprintf(buf, sizeof(buf), _("PGP Key 0x%s"), crypt_keyid(key));
5510  att->description = mutt_str_strdup(buf);
5511  mutt_update_encoding(att);
5512 
5513  stat(tempf, &sb);
5514  att->length = sb.st_size;
5515 
5516 bail:
5517  crypt_key_free(&key);
5518  gpgme_data_release(keydata);
5519  gpgme_release(context);
5520 
5521  return att;
5522 #else
5523  mutt_error("gpgme_op_export_keys not supported");
5524  return NULL;
5525 #endif
5526 }
5527 
5531 static void init_common(void)
5532 {
5533  /* this initialization should only run one time, but it may be called by
5534  * either pgp_gpgme_init or smime_gpgme_init */
5535  static bool has_run = false;
5536  if (has_run)
5537  return;
5538 
5539  gpgme_check_version(NULL);
5540  gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
5541 #ifdef ENABLE_NLS
5542  gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
5543 #endif
5544  has_run = true;
5545 }
5546 
5550 static void init_pgp(void)
5551 {
5552  if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
5553  {
5554  mutt_error(_("GPGME: OpenPGP protocol not available"));
5555  }
5556 }
5557 
5561 static void init_smime(void)
5562 {
5563  if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
5564  {
5565  mutt_error(_("GPGME: CMS protocol not available"));
5566  }
5567 }
5568 
5572 void pgp_gpgme_init(void)
5573 {
5574  init_common();
5575  init_pgp();
5576 }
5577 
5582 {
5583  init_common();
5584  init_smime();
5585 }
5586 
5593 static int gpgme_send_menu(struct Email *e, int is_smime)
5594 {
5595  struct CryptKeyInfo *p = NULL;
5596  const char *prompt = NULL;
5597  const char *letters = NULL;
5598  const char *choices = NULL;
5599  int choice;
5600 
5601  if (is_smime)
5603  else
5604  e->security |= APPLICATION_PGP;
5605 
5606  /* Opportunistic encrypt is controlling encryption.
5607  * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
5608  * letter choices for those.
5609  */
5611  {
5612  if (is_smime)
5613  {
5614  /* L10N: S/MIME options (opportunistic encryption is on) */
5615  prompt =
5616  _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
5617  /* L10N: S/MIME options (opportunistic encryption is on) */
5618  letters = _("sapco");
5619  choices = "SapCo";
5620  }
5621  else
5622  {
5623  /* L10N: PGP options (opportunistic encryption is on) */
5624  prompt =
5625  _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
5626  /* L10N: PGP options (opportunistic encryption is on) */
5627  letters = _("samco");
5628  choices = "SamCo";
5629  }
5630  }
5631  /* Opportunistic encryption option is set, but is toggled off for this message. */
5632  else if (C_CryptOpportunisticEncrypt)
5633  {
5634  if (is_smime)
5635  {
5636  /* L10N: S/MIME options (opportunistic encryption is off) */
5637  prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, "
5638  "or (o)ppenc mode?");
5639  /* L10N: S/MIME options (opportunistic encryption is off) */
5640  letters = _("esabpco");
5641  choices = "esabpcO";
5642  }
5643  else
5644  {
5645  /* L10N: PGP options (opportunistic encryption is off) */
5646  prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, "
5647  "or (o)ppenc mode?");
5648  /* L10N: PGP options (opportunistic encryption is off) */
5649  letters = _("esabmco");
5650  choices = "esabmcO";
5651  }
5652  }
5653  /* Opportunistic encryption is unset */
5654  else
5655  {
5656  if (is_smime)
5657  {
5658  /* L10N: S/MIME options */
5659  prompt =
5660  _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
5661  /* L10N: S/MIME options */
5662  letters = _("esabpc");
5663  choices = "esabpc";
5664  }
5665  else
5666  {
5667  /* L10N: PGP options */
5668  prompt =
5669  _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
5670  /* L10N: PGP options */
5671  letters = _("esabmc");
5672  choices = "esabmc";
5673  }
5674  }
5675 
5676  choice = mutt_multi_choice(prompt, letters);
5677  if (choice > 0)
5678  {
5679  switch (choices[choice - 1])
5680  {
5681  case 'a': /* sign (a)s */
5682  p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
5683  is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
5684  if (p)
5685  {
5686  char input_signas[128];
5687  snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
5688  mutt_str_replace(is_smime ? &C_SmimeDefaultKey : &C_PgpSignAs, input_signas);
5689  crypt_key_free(&p);
5690 
5691  e->security |= SEC_SIGN;
5692  }
5693  break;
5694 
5695  case 'b': /* (b)oth */
5696  e->security |= (SEC_ENCRYPT | SEC_SIGN);
5697  break;
5698 
5699  case 'C':
5700  e->security &= ~SEC_SIGN;
5701  break;
5702 
5703  case 'c': /* (c)lear */
5704  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
5705  break;
5706 
5707  case 'e': /* (e)ncrypt */
5708  e->security |= SEC_ENCRYPT;
5709  e->security &= ~SEC_SIGN;
5710  break;
5711 
5712  case 'm': /* (p)gp or s/(m)ime */
5713  case 'p':
5714  is_smime = !is_smime;
5715  if (is_smime)
5716  {
5717  e->security &= ~APPLICATION_PGP;
5719  }
5720  else
5721  {
5722  e->security &= ~APPLICATION_SMIME;
5723  e->security |= APPLICATION_PGP;
5724  }
5726  break;
5727 
5728  case 'O': /* oppenc mode on */
5729  e->security |= SEC_OPPENCRYPT;
5731  break;
5732 
5733  case 'o': /* oppenc mode off */
5734  e->security &= ~SEC_OPPENCRYPT;
5735  break;
5736 
5737  case 'S': /* (s)ign in oppenc mode */
5738  e->security |= SEC_SIGN;
5739  break;
5740 
5741  case 's': /* (s)ign */
5742  e->security &= ~SEC_ENCRYPT;
5743  e->security |= SEC_SIGN;
5744  break;
5745  }
5746  }
5747 
5748  return e->security;
5749 }
5750 
5755 {
5756  return gpgme_send_menu(e, 0);
5757 }
5758 
5763 {
5764  return gpgme_send_menu(e, 1);
5765 }
5766 
5772 static bool verify_sender(struct Email *e)
5773 {
5774  struct Address *sender = NULL;
5775  bool rc = true;
5776 
5777  if (!TAILQ_EMPTY(&e->env->from))
5778  {
5780  sender = TAILQ_FIRST(&e->env->from);
5781  }
5782  else if (!TAILQ_EMPTY(&e->env->sender))
5783  {
5785  sender = TAILQ_FIRST(&e->env->sender);
5786  }
5787 
5788  if (sender)
5789  {
5790  if (signature_key)
5791  {
5792  gpgme_key_t key = signature_key;
5793  gpgme_user_id_t uid = NULL;
5794  int sender_length = strlen(sender->mailbox);
5795  for (uid = key->uids; uid && rc; uid = uid->next)
5796  {
5797  int uid_length = strlen(uid->email);
5798  if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
5799  (uid_length == (sender_length + 2)))
5800  {
5801  const char *at_sign = strchr(uid->email + 1, '@');
5802  if (at_sign)
5803  {
5804  /* Assume address is 'mailbox@domainname'.
5805  * The mailbox part is case-sensitive,
5806  * the domainname is not. (RFC2821) */
5807  const char *tmp_email = uid->email + 1;
5808  const char *tmp_sender = sender->mailbox;
5809  /* length of mailbox part including '@' */
5810  int mailbox_length = at_sign - tmp_email + 1;
5811  int domainname_length = sender_length - mailbox_length;
5812  int mailbox_match, domainname_match;
5813 
5814  mailbox_match = (strncmp(tmp_email, tmp_sender, mailbox_length) == 0);
5815  tmp_email += mailbox_length;
5816  tmp_sender += mailbox_length;
5817  domainname_match =
5818  (strncasecmp(tmp_email, tmp_sender, domainname_length) == 0);
5819  if (mailbox_match && domainname_match)
5820  rc = false;
5821  }
5822  else
5823  {
5824  if (strncmp(uid->email + 1, sender->mailbox, sender_length) == 0)
5825  rc = false;
5826  }
5827  }
5828  }
5829  }
5830  else
5831  mutt_any_key_to_continue(_("Failed to verify sender"));
5832  }
5833  else
5834  mutt_any_key_to_continue(_("Failed to figure out sender"));
5835 
5836  if (signature_key)
5837  {
5838  gpgme_key_unref(signature_key);
5839  signature_key = NULL;
5840  }
5841 
5842  return rc;
5843 }
5844 
5848 int smime_gpgme_verify_sender(struct Mailbox *m, struct Email *e)
5849 {
5850  return verify_sender(e);
5851 }
5852 
5856 void pgp_gpgme_set_sender(const char *sender)
5857 {
5858  mutt_debug(LL_DEBUG2, "setting to: %s\n", sender);
5859  FREE(&current_sender);
5860  current_sender = mutt_str_strdup(sender);
5861 }
5862 
5867 const char *mutt_gpgme_print_version(void)
5868 {
5869  return GPGME_VERSION;
5870 }
int mutt_protected_headers_handler(struct Body *a, struct State *s)
Process a protected header - Implements handler_t.
Definition: crypt.c:1100
struct Body * pgp_gpgme_sign_message(struct Body *a, const struct AddressList *from)
Implements CryptModuleSpecs::sign_message()
Definition: crypt_gpgme.c:1556
Convenience wrapper for the gui headers.
static int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:708
static const char *const KeyInfoPrompts[]
Definition: crypt_gpgme.c:179
#define KEYFLAG_PREFER_ENCRYPTION
Key&#39;s owner prefers encryption.
Definition: lib.h:181
const char * crypt_get_fingerprint_or_id(const char *p, const char **pphint, const char **ppl, const char **pps)
Get the fingerprint or long key ID.
Definition: crypt.c:1274
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email&#39;s attachment.
Definition: handler.c:1793
WHERE bool C_StatusOnTop
Config: Display the status bar at the top.
Definition: globals.h:255
int pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
Implements CryptModuleSpecs::pgp_check_traditional()
Definition: crypt_gpgme.c:2809
#define CRYPT_KV_STRONGID
Definition: crypt_gpgme.c:91
static void print_time(time_t t, struct State *s)
Print the date/time according to the locale.
Definition: crypt_gpgme.c:1420
void mutt_expando_format(char *buf, size_t buflen, size_t col, int cols, const char *src, format_t *callback, unsigned long data, MuttFormatFlags flags)
Expand expandos (x) in a string.
Definition: muttlib.c:876
static int compare_key_address(const void *a, const void *b)
Compare Key addresses and IDs for sorting.
Definition: crypt_gpgme.c:3666
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:81
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
Create GPGME data object from file.
Definition: crypt_gpgme.c:926
static const char * parse_dn_part(struct DnArray *array, const char *str)
Parse an RDN.
Definition: crypt_gpgme.c:3907
#define REDRAW_FULL
Redraw everything.
Definition: mutt_menu.h:47
static int gpgme_send_menu(struct Email *e, int is_smime)
Show the user the encryption/signing menu.
Definition: crypt_gpgme.c:5593
char * filename
when sending a message, this is the file to which this structure refers
Definition: body.h:46
Manage keymappings.
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
#define NONULL(x)
Definition: string2.h:37
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
int mutt_ch_convert_string(char **ps, const char *from, const char *to, int flags)
Convert a string between encodings.
Definition: charset.c:748
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:63
#define PKA_NOTATION_NAME
Definition: crypt_gpgme.c:142
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:303
WHERE bool C_CryptConfirmhook
Config: Prompt the user to confirm keys before use.
Definition: globals.h:268
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:774
The envelope/body of an email.
Definition: email.h:37
#define state_puts(STATE, STR)
Definition: state.h:55
#define MUTT_CLEAR
Clear input if printable character is pressed.
Definition: mutt.h:68
static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *s)
Show the validity of a key used for one signature.
Definition: crypt_gpgme.c:1840
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
#define TAILQ_FIRST(head)
Definition: queue.h:716
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
Definition: crypt_gpgme.c:994
#define mutt_perror(...)
Definition: logging.h:85
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:639
GUI selectable list of items.
Definition: mutt_menu.h:82
static int data_object_to_stream(gpgme_data_t data, FILE *fp)
Write a GPGME data object to a file.
Definition: crypt_gpgme.c:947
Wrapper for PGP/SMIME calls to GPGME.
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:718
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file&#39;s character set.
Definition: charset.c:902
Structs that make up an email.
#define CRYPT_KV_ADDR
Definition: crypt_gpgme.c:89
int pgp_gpgme_application_handler(struct Body *m, struct State *s)
Implements CryptModuleSpecs::application_handler()
Definition: crypt_gpgme.c:2999
#define is_multipart(body)
Definition: mime.h:77
static struct CryptKeyInfo * crypt_select_key(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, int *forced_valid)
Get the user to select a key.
Definition: crypt_gpgme.c:4711
struct tm mutt_date_localtime(time_t t)
Converts calendar time to a broken-down time structure expressed in user timezone.
Definition: date.c:737
static int line_compare(const char *a, size_t n, const char *b)
Compare two strings ignore line endings.
Definition: crypt_gpgme.c:2727
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:122
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:458
static void verify_key(struct CryptKeyInfo *key)
Show detailed information about the selected key.
Definition: crypt_gpgme.c:4407
Dialog (nested Windows) displayed to the user.
Definition: mutt_window.h:68
User aborted the question (with Ctrl-G)
Definition: quad.h:38
MenuType
Types of GUI selections.
Definition: keymap.h:69
static char crypt_flags(KeyFlags flags)
Parse the key flags into a single character.
Definition: crypt_gpgme.c:601
#define SIGNED_MESSAGE(_y)
Definition: crypt_gpgme.c:146
7-bit text
Definition: mime.h:49
#define mutt_message(...)
Definition: logging.h:83
Window uses all available vertical space.
Definition: mutt_window.h:33
WHERE char * C_SmimeDefaultKey
Config: Default key for SMIME operations.
Definition: globals.h:163
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:40
void pgp_gpgme_invoke_import(const char *fname)
Implements CryptModuleSpecs::pgp_invoke_import()
Definition: crypt_gpgme.c:2834
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1382
void pgp_gpgme_init(void)
Implements CryptModuleSpecs::init()
Definition: crypt_gpgme.c:5572
struct Body * smime_gpgme_sign_message(struct Body *a, const struct AddressList *from)
Implements CryptModuleSpecs::sign_message()
Definition: crypt_gpgme.c:1564
void dialog_pop(void)
Hide a Window from the user.
Definition: mutt_window.c:623
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:123
void crypt_convert_to_7bit(struct Body *a)
Convert an email to 7bit encoding.
Definition: crypt.c:814
No flags set.
Definition: mutt_attach.h:55
static struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:620
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, int *forced_valid)
Find a key by string.
Definition: crypt_gpgme.c:5095
#define PUBLIC_KEY_BLOCK(_y)
Definition: crypt_gpgme.c:147
NeoMutt Logging.
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition: crypt.c:1363
void dialog_push(struct MuttWindow *dlg)
Display a Window to the user.
Definition: mutt_window.c:603
#define MUTT_FORMAT_ARROWCURSOR
Reserve space for arrow_cursor.
Definition: format_flags.h:35
static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig, gpgme_key_t key, struct State *s)
Print key info about an SMIME key.
Definition: crypt_gpgme.c:1883
static const char * crypt_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, unsigned long data, MuttFormatFlags flags)
Format a string for the key selection menu - Implements format_t.
Definition: crypt_gpgme.c:3437
static bool set_signer_from_address(gpgme_ctx_t ctx, const char *address, bool for_smime)
Try to set the context&#39;s signer from the address.
Definition: crypt_gpgme.c:1175
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
char * mutt_buffer_strdup(struct Buffer *buf)
Copy a Buffer&#39;s string.
Definition: buffer.c:432
static void crypt_make_entry(char *buf, size_t buflen, struct Menu *menu, int line)
Format a menu item for the key selection list - Implements Menu::menu_make_entry() ...
Definition: crypt_gpgme.c:3645
int mutt_file_rmtree(const char *path)
Recursively remove a directory.
Definition: file.c:465
static bool print_dn_part(FILE *fp, struct DnArray *dn, const char *key)
Print the X.500 Distinguished Name.
Definition: crypt_gpgme.c:3840
WHERE bool C_CryptUsePka
Config: Use GPGME to use PKA (lookup PGP keys using DNS)
Definition: globals.h:264
String manipulation buffer.
Definition: buffer.h:33
static int crypt_compare_date(const void *a, const void *b)
Compare the dates of two keys.
Definition: crypt_gpgme.c:3760
PGP Key field: aka (Also Known As)
Definition: crypt_gpgme.c:167
char * prefix
String to add to the beginning of each output line.
Definition: state.h:48
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition: crypt.c:481
LOFF_T offset
offset where the actual data begins
Definition: body.h:44
static char * encrypt_gpgme_object(gpgme_data_t plaintext, char *keylist, bool use_smime, bool combined_signed, const struct AddressList *from)
Encrypt the GPGPME data object.
Definition: crypt_gpgme.c:1293
#define _(a)
Definition: message.h:28
Sort by email address.
Definition: sort2.h:61
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition: lib.h:174
KeyInfo
PGP Key info.
Definition: crypt_gpgme.c:164
struct Body * next
next attachment in the list
Definition: body.h:53
Internal cache for GPGME.
Definition: crypt_gpgme.c:98
An email address.
Definition: address.h:34
WHERE bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: options.h:32
Key can be used to certify.
Definition: crypt_gpgme.c:158
FILE * fp_out
File to write to.
Definition: state.h:47
char * mailbox
Mailbox and host address.
Definition: address.h:37
static void recipient_set_free(gpgme_key_t **p_rset)
Free a set of recipients.
Definition: crypt_gpgme.c:1083
A division of the screen.
Definition: mutt_window.h:86
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:121
Match case when comparing strings.
Definition: string2.h:67
static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key, int idx, struct State *s, gpgme_signature_t sig)
Show a signature summary.
Definition: crypt_gpgme.c:1662
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:689
static char * find_keys(struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
Find keys of the recipients of the message.
Definition: crypt_gpgme.c:5236
char * key
Definition: crypt_gpgme.c:110
char * pgp_gpgme_find_keys(struct AddressList *addrlist, bool oppenc_mode)
Implements CryptModuleSpecs::find_keys()
Definition: crypt_gpgme.c:5358
size_t num
Definition: crypt_gpgme.c:134
WHERE bool C_PgpLongIds
Config: Display long PGP key IDs to the user.
Definition: globals.h:276
#define KEYFLAG_ABILITIES
Definition: lib.h:187
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
struct CryptKeyInfo * next
Definition: crypt_gpgme.c:121
WHERE bool C_CryptOpportunisticEncryptStrongKeys
Config: Enable encryption only when strong a key is available.
Definition: globals.h:270
static void init_smime(void)
Initialise the SMIME crypto backend.
Definition: crypt_gpgme.c:5561
Flags to control mutt_expando_format()
All user-callable functions.
FILE * fp_in
File to read from.
Definition: state.h:46
struct Body * pgp_gpgme_make_key_attachment(void)
Implements CryptModuleSpecs::pgp_make_key_attachment()
Definition: crypt_gpgme.c:5465
void(* menu_make_entry)(char *buf, size_t buflen, struct Menu *menu, int line)
Format a item for a menu.
Definition: mutt_menu.h:120
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:173
Representation of a single alias to an email address.
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
struct Body * pgp_gpgme_encrypt_message(struct Body *a, char *keylist, bool sign, const struct AddressList *from)
Implements CryptModuleSpecs::pgp_encrypt_message()
Definition: crypt_gpgme.c:1572
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define CRYPT_KV_STRING
Definition: crypt_gpgme.c:90
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:90
The body of an email.
Definition: body.h:34
#define KEYFLAG_PREFER_SIGNING
Key&#39;s owner prefers signing.
Definition: lib.h:182
static struct CryptKeyInfo * crypt_getkeybyaddr(struct Address *a, KeyFlags abilities, unsigned int app, int *forced_valid, bool oppenc_mode)
Find a key by email address.
Definition: crypt_gpgme.c:4966
unsigned int disposition
content-disposition
Definition: body.h:67
Convenience wrapper for the config headers.
static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
Definition: crypt_gpgme.c:4684
An Index Window containing a selection list.
Definition: mutt_window.h:72
Hundreds of global variables to back the user variables.
static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
Check one inline PGP body part.
Definition: crypt_gpgme.c:2745
Email Address Handling.
void mutt_window_free(struct MuttWindow **ptr)
Free a Window and its children.
Definition: mutt_window.c:75
Some miscellaneous functions.
A stored PGP key.
Definition: crypt_gpgme.c:119
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:49
static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
Does the key ID match the address.
Definition: crypt_gpgme.c:726
static void init_common(void)
Initialise code common to PGP and SMIME parts of GPGME.
Definition: crypt_gpgme.c:5531
int pgp_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Implements CryptModuleSpecs::decrypt_mime()
Definition: crypt_gpgme.c:2379
#define MESSAGE(_y)
Definition: crypt_gpgme.c:145
enum QuadOption mutt_yesorno(const char *msg, enum QuadOption def)
Ask the user a Yes/No question.
Definition: curs_lib.c:376
Parse and execute user-defined hooks.
int idx
and the user ID at this index
Definition: crypt_gpgme.c:123
static void show_fingerprint(gpgme_key_t key, struct State *state)
Write a key&#39;s fingerprint.
Definition: crypt_gpgme.c:1785
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
Definition: crypt_gpgme.c:533
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Many unsorted constants and some structs.
Log at debug level 2.
Definition: logging.h:41
PGP Key field: Subkey.
Definition: crypt_gpgme.c:175
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: sendlib.c:637
char * mutt_str_strlower(char *s)
Convert all characters in the string to lowercase.
Definition: string.c:509
static struct Body * decrypt_part(struct Body *a, struct State *s, FILE *fp_out, bool is_smime, int *r_is_signed)
Decrypt a PGP or SMIME message.
Definition: crypt_gpgme.c:2227
struct AddressList from
Email&#39;s &#39;From&#39; list.
Definition: envelope.h:57
char * smime_gpgme_find_keys(struct AddressList *addrlist, bool oppenc_mode)
Implements CryptModuleSpecs::find_keys()
Definition: crypt_gpgme.c:5366
struct MuttWindow * win_ibar
Definition: mutt_menu.h:96
void smime_gpgme_init(void)
Implements CryptModuleSpecs::init()
Definition: crypt_gpgme.c:5581
void mutt_update_encoding(struct Body *a)
Update the encoding type.
Definition: sendlib.c:1484
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
struct Envelope * env
Envelope information.
Definition: email.h:89
PGP Key field: Valid To date.
Definition: crypt_gpgme.c:169
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition: body.h:77
int pgp_gpgme_encrypted_handler(struct Body *a, struct State *s)
Implements CryptModuleSpecs::encrypted_handler()
Definition: crypt_gpgme.c:3227
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:753
static void init_pgp(void)
Initialise the PGP crypto backend.
Definition: crypt_gpgme.c:5550
KeyCap
PGP/SMIME Key Capabilities.
Definition: crypt_gpgme.c:154
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
Content is attached.
Definition: mime.h:63
static gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:760
int smime_gpgme_verify_sender(struct Mailbox *m, struct Email *e)
Implements CryptModuleSpecs::smime_verify_sender()
Definition: crypt_gpgme.c:5848
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:416
static int get_micalg(gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
Find the "micalg" parameter from the last GPGME operation.
Definition: crypt_gpgme.c:1382
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:113
unsigned int encoding
content-transfer-encoding
Definition: body.h:66
Base-64 encoded text.
Definition: mime.h:52
#define KEYFLAG_EXPIRED
Key is expired.
Definition: lib.h:176
#define KEYFLAG_CANTUSE
Definition: lib.h:184
size_t mutt_buffer_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:225
static int compare_keyid(const void *a, const void *b)
Compare Key IDs and addresses for sorting.
Definition: crypt_gpgme.c:3700
int smime_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Implements CryptModuleSpecs::decrypt_mime()
Definition: crypt_gpgme.c:2473
Window has a fixed size.
Definition: mutt_window.h:42
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
WHERE short C_PgpSortKeys
Config: Sort order for PGP keys.
Definition: sort.h:62
char * subtype
content-type subtype
Definition: body.h:37
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:56
static gpgme_data_t body_to_data_object(struct Body *a, bool convert)
Create GPGME object from the mail body.
Definition: crypt_gpgme.c:854
#define mutt_b2s(buf)
Definition: buffer.h:41
bool goodsig
Good cryptographic signature.
Definition: body.h:75
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:136
int pgp_gpgme_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
Implements CryptModuleSpecs::verify_one()
Definition: crypt_gpgme.c:2201
Sort by encryption key&#39;s trust level.
Definition: sort2.h:63
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: curs_lib.c:906
Prototypes for many functions.
SecurityFlags mutt_is_application_pgp(struct Body *m)
Does the message use PGP?
Definition: crypt.c:563
const char * line
Definition: common.c:36
#define CRYPT_KV_MATCH
Definition: crypt_gpgme.c:92
const char * uid
and for convenience point to this user ID
Definition: crypt_gpgme.c:124
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:91
WHERE bool C_CryptOpportunisticEncrypt
Config: Enable encryption when the recipient&#39;s key is available.
Definition: globals.h:269
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:135
Signing/encryption multiplexor.
struct MuttWindow * mutt_window_new(enum MuttWindowOrientation orient, enum MuttWindowSize size, int rows, int cols)
Create a new Window.
Definition: mutt_window.c:57
PGP Key field: Issued By.
Definition: crypt_gpgme.c:174
LOFF_T length
length (in bytes) of attachment
Definition: body.h:45
static int crypt_compare_keyid(const void *a, const void *b)
Compare the IDs of two keys.
Definition: crypt_gpgme.c:3720
A mailbox.
Definition: mailbox.h:80
int mutt_strwidth(const char *s)
Measure a string&#39;s width in screen cells.
Definition: curs_lib.c:1332
#define PATH_MAX
Definition: mutt.h:50
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:171
static struct CryptCache * id_defaults
Definition: crypt_gpgme.c:138
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:39
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:47
int mutt_gpgme_select_secret_key(struct Buffer *keyid)
Select a private Autocrypt key for a new account.
Definition: crypt_gpgme.c:5383
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:55
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
static int digit_or_letter(const char *s)
Is the character a number or letter.
Definition: crypt_gpgme.c:235
int mutt_decode_save_attachment(FILE *fp, struct Body *m, const char *path, int displaying, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:961
#define MUTT_VERIFY
Perform signature verification.
Definition: state.h:33
Type: &#39;text/*&#39;.
Definition: mime.h:38
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:170
static char * crypt_key_abilities(KeyFlags flags)
Parse key flags into a string.
Definition: crypt_gpgme.c:571
int mutt_write_mime_body(struct Body *a, FILE *fp)
Write a MIME part.
Definition: sendlib.c:554
gpgme_key_t kobj
Definition: crypt_gpgme.c:122
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:96
int smime_gpgme_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
Implements CryptModuleSpecs::verify_one()
Definition: crypt_gpgme.c:2209
WHERE char * C_PgpEntryFormat
Config: printf-like format string for the PGP key selection menu.
Definition: globals.h:161
char * data
Pointer to data.
Definition: buffer.h:35
static struct CryptKeyInfo * crypt_ask_for_key(char *tag, char *whatfor, KeyFlags abilities, unsigned int app, int *forced_valid)
Ask the user for a key.
Definition: crypt_gpgme.c:5169
struct Body * smime_gpgme_build_smime_entity(struct Body *a, char *keylist)
Implements CryptModuleSpecs::smime_build_smime_entity()
Definition: crypt_gpgme.c:1618
Key can be used for signing.
Definition: crypt_gpgme.c:157
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:54
const char * mutt_str_stristr(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:714
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:773
static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
Write PGP keys to a file.
Definition: crypt_gpgme.c:2591
GUI present the user with a selectable list.
#define mutt_file_mkstemp()
Definition: file.h:105
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:518
static gpgme_key_t * create_recipient_set(const char *keylist, bool use_smime)
Create a GpgmeRecipientSet from a string of keys.
Definition: crypt_gpgme.c:1110
static bool is_pka_notation(gpgme_sig_notation_t notation)
Is this the standard pka email address.
Definition: crypt_gpgme.c:195
static bool crypt_key_is_valid(struct CryptKeyInfo *k)
Is the key valid.
Definition: crypt_gpgme.c:661
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
Definition: crypt_gpgme.c:4477
#define KEYFLAG_DISABLED
Key is marked disabled.
Definition: lib.h:178
WHERE bool OptPgpCheckTrust
(pseudo) used by pgp_select_key()
Definition: options.h:48
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body&#39;s character set.
Definition: sendlib.c:1460
SecurityFlags mutt_is_application_smime(struct Body *m)
Does the message use S/MIME?
Definition: crypt.c:622
Handling of email attachments.
static int crypt_compare_trust(const void *a, const void *b)
Compare the trust levels of two keys.
Definition: crypt_gpgme.c:3824
static int crypt_compare_address(const void *a, const void *b)
Compare the addresses of two keys.
Definition: crypt_gpgme.c:3686
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:349
char * description
content-description
Definition: body.h:40
int pagelen
Number of entries per screen.
Definition: mutt_menu.h:92
static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
Make sure that the correct signer is set.
Definition: crypt_gpgme.c:1233
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:172
size_t mutt_buffer_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:240
#define STAILQ_NEXT(elm, field)
Definition: queue.h:397
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib...
Definition: email.h:39
Key can be used for encryption.
Definition: crypt_gpgme.c:156
static char * current_sender
Definition: crypt_gpgme.c:140
void mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:453
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:131
const char * mutt_fqdn(bool may_hide_host)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:2530
#define KEYFLAG_RESTRICTIONS
Definition: lib.h:185
static void print_key_info(gpgme_key_t key, FILE *fp)
Verbose information about a key or certificate to a file.
Definition: crypt_gpgme.c:4156
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
unsigned int type
content-type primary type
Definition: body.h:65
int max
Number of entries in the menu.
Definition: mutt_menu.h:88
int KeyInfoPadding[KIP_MAX]
Definition: crypt_gpgme.c:188
void mutt_window_add_child(struct MuttWindow *parent, struct MuttWindow *child)
Add a child to Window.
Definition: mutt_window.c:471
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:168
#define BEGIN_PGP_SIGNATURE(_y)
Definition: crypt_gpgme.c:148
MuttRedrawFlags redraw
When to redraw the screen.
Definition: mutt_menu.h:89
static int verify_one(struct Body *sigbdy, struct State *s, const char *tempfile, bool is_smime)
Do the actual verification step.
Definition: crypt_gpgme.c:2076
#define SEC_SIGN
Email is signed.
Definition: lib.h:124
PGP Key field: Key Usage.
Definition: crypt_gpgme.c:171
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: main.c:143
char * personal
Real name of address.
Definition: address.h:36
char * title
Title of this menu.
Definition: mutt_menu.h:84
int mutt_any_key_to_continue(const char *s)
Prompt the user to &#39;press any key&#39; and wait.
Definition: curs_lib.c:578
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:70
Keep track when processing files.
static void print_utf8(FILE *fp, const char *buf, size_t len)
Write a UTF-8 string to a file.
Definition: crypt_gpgme.c:248
const char * mutt_gpgme_print_version(void)
Get version of GPGME.
Definition: crypt_gpgme.c:5867
An entry in the Select-Key menu.
Definition: crypt_gpgme.c:132
GUI display a file/email/help in a viewport with paging.
void mutt_ch_fgetconv_close(struct FgetConv **fc)
Close an fgetconv handle.
Definition: charset.c:882
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1406
static void print_dn_parts(FILE *fp, struct DnArray *dn)
Print all parts of a DN in a standard sequence.
Definition: crypt_gpgme.c:3862
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1034
struct CryptKeyInfo * key
Definition: crypt_gpgme.c:135
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:641
static int digit(const char *s)
Is the character a number.
Definition: crypt_gpgme.c:225
char * data
String.
Definition: list.h:35
Type: &#39;multipart/*&#39;.
Definition: mime.h:37
static struct Body * sign_message(struct Body *a, const struct AddressList *from, bool use_smime)
Sign a message.
Definition: crypt_gpgme.c:1435
PGP Key field: Key Type.
Definition: crypt_gpgme.c:170
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
Definition: crypt_gpgme.c:497
Routines for managing attachments.
Log at debug level 1.
Definition: logging.h:40
#define KEYFLAG_CRITICAL
Key is marked critical.
Definition: lib.h:180
int mutt_do_pager(const char *banner, const char *tempfile, PagerFlags do_color, struct Pager *info)
Display some page-able text to the user.
Definition: curs_lib.c:664
No preferred disposition.
Definition: mime.h:65
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:68
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:380
int mutt_str_strncmp(const char *a, const char *b, size_t l)
Compare two strings (to a maximum), safely.
Definition: string.c:665
const char * attach_format_str(char *buf, size_t buflen, size_t col, int cols, char op, const char *src, const char *prec, const char *if_str, const char *else_str, unsigned long data, MuttFormatFlags flags)
Format a string for the attachment menu - Implements format_t.
Definition: recvattach.c:207
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.c:125
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:798
#define mutt_error(...)
Definition: logging.h:84
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:69
char * C_Tmpdir
Config: Directory for temporary files.
Definition: file.c:55
int mutt_str_strcasecmp(const char *a, const char *b)
Compare two strings ignoring case, safely.
Definition: string.c:651
PGP Key field: Serial number.
Definition: crypt_gpgme.c:173
static struct DnArray * parse_dn(const char *str)
Parse a DN and return an array-ized one.
Definition: crypt_gpgme.c:4004
static const char * crypt_short_keyid(struct CryptKeyInfo *k)
Get the short keyID for a key.
Definition: crypt_gpgme.c:514
int pgp_gpgme_send_menu(struct Email *e)
Implements CryptModuleSpecs::send_menu()
Definition: crypt_gpgme.c:5754
WHERE char * C_PgpDefaultKey
Config: Default key to use for PGP operations.
Definition: globals.h:159
static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
Set the signature notation.
Definition: crypt_gpgme.c:1273
#define FREE(x)
Definition: memory.h:40
void pgp_gpgme_set_sender(const char *sender)
Implements CryptModuleSpecs::set_sender()
Definition: crypt_gpgme.c:5856
#define CRYPT_KV_VALID
Definition: crypt_gpgme.c:88
void * data
Extra data for the current menu.
Definition: mutt_menu.h:86
int mutt_write_mime_header(struct Body *a, FILE *fp)
Create a MIME header.
Definition: sendlib.c:395
static struct CryptKeyInfo * get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
Get a list of keys which are candidates for the selection.
Definition: crypt_gpgme.c:4540
struct CryptCache * next
Definition: crypt_gpgme.c:102
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file&#39;s charset into a string buffer.
Definition: charset.c:964
Keep track when processing files.
Definition: state.h:44
WHERE char * C_AutocryptDir
Config: Location of autocrypt files, including the GPG keyring and sqlite database.
Definition: globals.h:102
static const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:549
gpgme_validity_t validity
uid validity (cached for convenience)
Definition: crypt_gpgme.c:126
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:321
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
char * C_Charset
Config: Default character set for displaying text on screen.
Definition: charset.c:54
struct AddressList sender
Email&#39;s sender.
Definition: envelope.h:61
Sort by the encryption key&#39;s ID.
Definition: sort2.h:62
int smime_gpgme_send_menu(struct Email *e)
Implements CryptModuleSpecs::send_menu()
Definition: crypt_gpgme.c:5762
PGP Key field: Name.
Definition: crypt_gpgme.c:166
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1549
char * d_filename
filename to be used for the content-disposition header.
Definition: body.h:47
void mutt_make_help(char *buf, size_t buflen, const char *txt, enum MenuType menu, int op)
Create one entry for the help bar.
Definition: help.c:93
static void parse_and_print_user_id(FILE *fp, const char *userid)
Print a nice representation of the userid.
Definition: crypt_gpgme.c:4066
Handling of global boolean variables.
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static int compare_key_trust(const void *a, const void *b)
Compare the trust of keys for sorting.
Definition: crypt_gpgme.c:3777
int smime_gpgme_application_handler(struct Body *a, struct State *s)
Implements CryptModuleSpecs::application_handler()
Definition: crypt_gpgme.c:3322
#define state_putc(STATE, STR)
Definition: state.h:56
Miscellaneous functions for sending an email.
char * value
Definition: crypt_gpgme.c:111
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
static bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:673
#define TAILQ_EMPTY(head)
Definition: queue.h:714
int current
Current entry.
Definition: mutt_menu.h:87
static int compare_key_date(const void *a, const void *b)
Compare Key creation dates and addresses for sorting.
Definition: crypt_gpgme.c:3733
Sort by the date the email was sent.
Definition: sort2.h:50
Log at debug level 5.
Definition: logging.h:44
WHERE char * C_PgpSignAs
Config: Use this alternative key for signing messages.
Definition: globals.h:160
struct MuttWindow * win_index
Definition: mutt_menu.h:95
Convenience wrapper for the library headers.
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:585
#define SORT_REVERSE
Reverse the order of the sort.
Definition: sort2.h:86
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:81
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, int flags)
Prepare a file for charset conversion.
Definition: charset.c:852
WHERE char * C_SmimeSignAs
Config: Use this alternative key for signing messages.
Definition: globals.h:164
A List node for strings.
Definition: list.h:33
static void redraw_if_needed(gpgme_ctx_t ctx)
accommodate for a redraw if needed
Definition: crypt_gpgme.c:204
Window wants as much space as possible.
Definition: mutt_window.h:43
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:630
Decide how to display email content.
Content is inline.
Definition: mime.h:62
void mutt_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:128
static gpgme_key_t signature_key
Definition: crypt_gpgme.c:139
struct ParameterList parameter
parameters of the content-type
Definition: body.h:39
#define N_(a)
Definition: message.h:32
Index Bar containing status info about the Index.
Definition: mutt_window.h:73
enum WindowType type
Window type, e.g. WT_SIDEBAR.
Definition: mutt_window.h:101
char * dflt
Definition: crypt_gpgme.c:101
#define STAILQ_FIRST(head)
Definition: queue.h:347
#define KEYFLAG_REVOKED
Key is revoked.
Definition: lib.h:177
char * help
Quickref for the current menu.
Definition: mutt_menu.h:85
Cursor for converting a file&#39;s encoding.
Definition: charset.h:41
int mutt_str_strcmp(const char *a, const char *b)
Compare two strings, safely.
Definition: string.c:638
An X500 Distinguished Name.
Definition: crypt_gpgme.c:108
Type: &#39;application/*&#39;.
Definition: mime.h:33
PGP Key field: Valid From date.
Definition: crypt_gpgme.c:168
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1292
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *s)
Show information about one signature.
Definition: crypt_gpgme.c:1956
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
#define SORT_MASK
Mask for the sort id.
Definition: sort2.h:85
static void copy_clearsigned(gpgme_data_t data, struct State *s, char *charset)
Copy a clearsigned message.
Definition: crypt_gpgme.c:2943
static const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:473
#define MUTT_PAGER_NO_FLAGS
No flags are set.
Definition: pager.h:43
char * what
Definition: crypt_gpgme.c:100
static unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:4104
WHERE char * AutocryptSignAs
Autocrypt Key id to sign as.
Definition: globals.h:87
PGP Key field: Fingerprint.
Definition: crypt_gpgme.c:172
Generic selection list.
Definition: keymap.h:76
bool warnsig
Maybe good signature.
Definition: body.h:76
WHERE bool C_PgpShowUnusable
Config: Show non-usable keys in the key selection.
Definition: globals.h:277
static bool verify_sender(struct Email *e)
Verify the sender of a message.
Definition: crypt_gpgme.c:5772