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