NeoMutt  2022-04-29-81-g9c5a59
Teaching an old dog new tricks
DOXYGEN
smime.c
Go to the documentation of this file.
1 
32 #include "config.h"
33 #include <limits.h>
34 #include <stdbool.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <time.h>
40 #include "private.h"
41 #include "mutt/lib.h"
42 #include "address/lib.h"
43 #include "config/lib.h"
44 #include "email/lib.h"
45 #include "core/lib.h"
46 #include "alias/lib.h"
47 #include "gui/lib.h"
48 #include "mutt.h"
49 #include "lib.h"
50 #include "question/lib.h"
51 #include "send/lib.h"
52 #include "copy.h"
53 #include "crypt.h"
54 #include "cryptglue.h"
55 #include "format_flags.h"
56 #include "handler.h"
57 #include "mutt_logging.h"
58 #include "muttlib.h"
59 #ifdef CRYPT_BACKEND_CLASSIC_SMIME
60 #include "smime.h"
61 #endif
62 
67 {
68  const char *key;
69  const char *cryptalg;
70  const char *digestalg;
71  const char *fname;
72  const char *sig_fname;
73  const char *certificates;
74  const char *intermediates;
75 };
76 
77 char SmimePass[256];
78 time_t SmimeExpTime = 0; /* when does the cached passphrase expire? */
79 
80 static struct Buffer SmimeKeyToUse = { 0 };
81 static struct Buffer SmimeCertToUse = { 0 };
82 static struct Buffer SmimeIntermediateToUse = { 0 };
83 
87 void smime_init(void)
88 {
92 }
93 
97 void smime_cleanup(void)
98 {
102 }
103 
108 static void smime_key_free(struct SmimeKey **keylist)
109 {
110  if (!keylist)
111  return;
112 
113  struct SmimeKey *key = NULL;
114 
115  while (*keylist)
116  {
117  key = *keylist;
118  *keylist = (*keylist)->next;
119 
120  FREE(&key->email);
121  FREE(&key->hash);
122  FREE(&key->label);
123  FREE(&key->issuer);
124  FREE(&key);
125  }
126 }
127 
133 static struct SmimeKey *smime_copy_key(struct SmimeKey *key)
134 {
135  if (!key)
136  return NULL;
137 
138  struct SmimeKey *copy = NULL;
139 
140  copy = mutt_mem_calloc(1, sizeof(struct SmimeKey));
141  copy->email = mutt_str_dup(key->email);
142  copy->hash = mutt_str_dup(key->hash);
143  copy->label = mutt_str_dup(key->label);
144  copy->issuer = mutt_str_dup(key->issuer);
145  copy->trust = key->trust;
146  copy->flags = key->flags;
147 
148  return copy;
149 }
150 
151 /*
152  * Queries and passphrase handling.
153  */
154 
159 {
160  memset(SmimePass, 0, sizeof(SmimePass));
161  SmimeExpTime = 0;
162 }
163 
168 {
169  const time_t now = mutt_date_epoch();
170  if (now < SmimeExpTime)
171  {
172  /* Use cached copy. */
173  return true;
174  }
175 
177 
178  struct Buffer *buf = mutt_buffer_pool_get();
179  const int rc = mutt_get_field_unbuffered(_("Enter S/MIME passphrase:"), buf, MUTT_COMP_PASS);
182 
183  if (rc == 0)
184  {
185  const short c_smime_timeout = cs_subset_number(NeoMutt->sub, "smime_timeout");
186  SmimeExpTime = mutt_date_add_timeout(now, c_smime_timeout);
187  return true;
188  }
189  else
190  {
191  SmimeExpTime = 0;
192  }
193 
194  return false;
195 }
196 
197 /*
198  * The OpenSSL interface
199  */
200 
215 static const char *smime_command_format_str(char *buf, size_t buflen, size_t col,
216  int cols, char op, const char *src,
217  const char *prec, const char *if_str,
218  const char *else_str, intptr_t data,
219  MuttFormatFlags flags)
220 {
221  char fmt[128];
222  struct SmimeCommandContext *cctx = (struct SmimeCommandContext *) data;
223  bool optional = (flags & MUTT_FORMAT_OPTIONAL);
224 
225  switch (op)
226  {
227  case 'C':
228  {
229  const char *const c_smime_ca_location = cs_subset_path(NeoMutt->sub, "smime_ca_location");
230  if (!optional)
231  {
232  struct Buffer *path = mutt_buffer_pool_get();
233  struct Buffer *buf1 = mutt_buffer_pool_get();
234  struct Buffer *buf2 = mutt_buffer_pool_get();
235  struct stat st = { 0 };
236 
237  mutt_buffer_strcpy(path, c_smime_ca_location);
240 
241  if ((stat(mutt_buffer_string(path), &st) != 0) || !S_ISDIR(st.st_mode))
242  mutt_buffer_printf(buf2, "-CAfile %s", mutt_buffer_string(buf1));
243  else
244  mutt_buffer_printf(buf2, "-CApath %s", mutt_buffer_string(buf1));
245 
246  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
247  snprintf(buf, buflen, fmt, mutt_buffer_string(buf2));
248 
252  }
253  else if (!c_smime_ca_location)
254  optional = false;
255  break;
256  }
257 
258  case 'c':
259  { /* certificate (list) */
260  if (!optional)
261  {
262  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
263  snprintf(buf, buflen, fmt, NONULL(cctx->certificates));
264  }
265  else if (!cctx->certificates)
266  optional = false;
267  break;
268  }
269 
270  case 'i':
271  { /* intermediate certificates */
272  if (!optional)
273  {
274  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
275  snprintf(buf, buflen, fmt, NONULL(cctx->intermediates));
276  }
277  else if (!cctx->intermediates)
278  optional = false;
279  break;
280  }
281 
282  case 's':
283  { /* detached signature */
284  if (!optional)
285  {
286  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
287  snprintf(buf, buflen, fmt, NONULL(cctx->sig_fname));
288  }
289  else if (!cctx->sig_fname)
290  optional = false;
291  break;
292  }
293 
294  case 'k':
295  { /* private key */
296  if (!optional)
297  {
298  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
299  snprintf(buf, buflen, fmt, NONULL(cctx->key));
300  }
301  else if (!cctx->key)
302  optional = false;
303  break;
304  }
305 
306  case 'a':
307  { /* algorithm for encryption */
308  if (!optional)
309  {
310  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
311  snprintf(buf, buflen, fmt, NONULL(cctx->cryptalg));
312  }
313  else if (!cctx->key)
314  optional = false;
315  break;
316  }
317 
318  case 'f':
319  { /* file to process */
320  if (!optional)
321  {
322  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
323  snprintf(buf, buflen, fmt, NONULL(cctx->fname));
324  }
325  else if (!cctx->fname)
326  optional = false;
327  break;
328  }
329 
330  case 'd':
331  { /* algorithm for the signature message digest */
332  if (!optional)
333  {
334  snprintf(fmt, sizeof(fmt), "%%%ss", prec);
335  snprintf(buf, buflen, fmt, NONULL(cctx->digestalg));
336  }
337  else if (!cctx->key)
338  optional = false;
339  break;
340  }
341 
342  default:
343  *buf = '\0';
344  break;
345  }
346 
347  if (optional)
348  {
349  mutt_expando_format(buf, buflen, col, cols, if_str,
351  }
352  else if (flags & MUTT_FORMAT_OPTIONAL)
353  {
354  mutt_expando_format(buf, buflen, col, cols, else_str,
356  }
357 
358  /* We return the format string, unchanged */
359  return src;
360 }
361 
371 static void smime_command(char *buf, size_t buflen,
372  struct SmimeCommandContext *cctx, const char *fmt)
373 {
374  mutt_expando_format(buf, buflen, 0, buflen, NONULL(fmt), smime_command_format_str,
375  (intptr_t) cctx, MUTT_FORMAT_NO_FLAGS);
376  mutt_debug(LL_DEBUG2, "%s\n", buf);
377 }
378 
401 static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err,
402  int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd,
403  const char *fname, const char *sig_fname, const char *cryptalg,
404  const char *digestalg, const char *key, const char *certificates,
405  const char *intermediates, const char *format)
406 {
407  struct SmimeCommandContext cctx = { 0 };
408  char cmd[STR_COMMAND];
409 
410  if (!format || (*format == '\0'))
411  return (pid_t) -1;
412 
413  cctx.fname = fname;
414  cctx.sig_fname = sig_fname;
415  cctx.key = key;
416  cctx.cryptalg = cryptalg;
417  cctx.digestalg = digestalg;
418  cctx.certificates = certificates;
420 
421  smime_command(cmd, sizeof(cmd), &cctx, format);
422 
423  return filter_create_fd(cmd, fp_smime_in, fp_smime_out, fp_smime_err,
424  fp_smime_infd, fp_smime_outfd, fp_smime_errfd);
425 }
426 
433 static struct SmimeKey *smime_parse_key(char *buf)
434 {
435  char *pend = NULL, *p = NULL;
436  int field = 0;
437 
438  struct SmimeKey *key = mutt_mem_calloc(1, sizeof(struct SmimeKey));
439 
440  for (p = buf; p; p = pend)
441  {
442  /* Some users manually maintain their .index file, and use a tab
443  * as a delimiter, which the old parsing code (using fscanf)
444  * happened to allow. smime_keys uses a space, so search for both. */
445  if ((pend = strchr(p, ' ')) || (pend = strchr(p, '\t')) || (pend = strchr(p, '\n')))
446  *pend++ = 0;
447 
448  /* For backward compatibility, don't count consecutive delimiters
449  * as an empty field. */
450  if (*p == '\0')
451  continue;
452 
453  field++;
454 
455  switch (field)
456  {
457  case 1: /* mailbox */
458  key->email = mutt_str_dup(p);
459  break;
460  case 2: /* hash */
461  key->hash = mutt_str_dup(p);
462  break;
463  case 3: /* label */
464  key->label = mutt_str_dup(p);
465  break;
466  case 4: /* issuer */
467  key->issuer = mutt_str_dup(p);
468  break;
469  case 5: /* trust */
470  key->trust = *p;
471  break;
472  case 6: /* purpose */
473  while (*p)
474  {
475  switch (*p++)
476  {
477  case 'e':
478  key->flags |= KEYFLAG_CANENCRYPT;
479  break;
480 
481  case 's':
482  key->flags |= KEYFLAG_CANSIGN;
483  break;
484  }
485  }
486  break;
487  }
488  }
489 
490  /* Old index files could be missing issuer, trust, and purpose,
491  * but anything less than that is an error. */
492  if (field < 3)
493  {
494  smime_key_free(&key);
495  return NULL;
496  }
497 
498  if (field < 4)
499  key->issuer = mutt_str_dup("?");
500 
501  if (field < 5)
502  key->trust = 't';
503 
504  if (field < 6)
506 
507  return key;
508 }
509 
516 static struct SmimeKey *smime_get_candidates(const char *search, bool only_public_key)
517 {
518  char buf[1024];
519  struct SmimeKey *key = NULL, *results = NULL;
520  struct SmimeKey **results_end = &results;
521 
522  struct Buffer *index_file = mutt_buffer_pool_get();
523  const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
524  const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
525  mutt_buffer_printf(index_file, "%s/.index",
526  only_public_key ? NONULL(c_smime_certificates) : NONULL(c_smime_keys));
527 
528  FILE *fp = mutt_file_fopen(mutt_buffer_string(index_file), "r");
529  if (!fp)
530  {
531  mutt_perror(mutt_buffer_string(index_file));
532  mutt_buffer_pool_release(&index_file);
533  return NULL;
534  }
535  mutt_buffer_pool_release(&index_file);
536 
537  while (fgets(buf, sizeof(buf), fp))
538  {
539  if (((*search == '\0')) || mutt_istr_find(buf, search))
540  {
541  key = smime_parse_key(buf);
542  if (key)
543  {
544  *results_end = key;
545  results_end = &key->next;
546  }
547  }
548  }
549 
550  mutt_file_fclose(&fp);
551 
552  return results;
553 }
554 
564 static struct SmimeKey *smime_get_key_by_hash(const char *hash, bool only_public_key)
565 {
566  struct SmimeKey *match = NULL;
567  struct SmimeKey *results = smime_get_candidates(hash, only_public_key);
568  for (struct SmimeKey *result = results; result; result = result->next)
569  {
570  if (mutt_istr_equal(hash, result->hash))
571  {
572  match = smime_copy_key(result);
573  break;
574  }
575  }
576 
577  smime_key_free(&results);
578 
579  return match;
580 }
581 
590 static struct SmimeKey *smime_get_key_by_addr(char *mailbox, KeyFlags abilities,
591  bool only_public_key, bool oppenc_mode)
592 {
593  if (!mailbox)
594  return NULL;
595 
596  struct SmimeKey *results = NULL, *result = NULL;
597  struct SmimeKey *matches = NULL;
598  struct SmimeKey **matches_end = &matches;
599  struct SmimeKey *match = NULL;
600  struct SmimeKey *trusted_match = NULL;
601  struct SmimeKey *valid_match = NULL;
602  struct SmimeKey *return_key = NULL;
603  bool multi_trusted_matches = false;
604 
605  results = smime_get_candidates(mailbox, only_public_key);
606  for (result = results; result; result = result->next)
607  {
608  if (abilities && !(result->flags & abilities))
609  {
610  continue;
611  }
612 
613  if (mutt_istr_equal(mailbox, result->email))
614  {
615  match = smime_copy_key(result);
616  *matches_end = match;
617  matches_end = &match->next;
618 
619  if (match->trust == 't')
620  {
621  if (trusted_match && !mutt_istr_equal(match->hash, trusted_match->hash))
622  {
623  multi_trusted_matches = true;
624  }
625  trusted_match = match;
626  }
627  else if ((match->trust == 'u') || (match->trust == 'v'))
628  {
629  valid_match = match;
630  }
631  }
632  }
633 
634  smime_key_free(&results);
635 
636  if (matches)
637  {
638  if (oppenc_mode)
639  {
640  const bool c_crypt_opportunistic_encrypt_strong_keys =
641  cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
642  if (trusted_match)
643  return_key = smime_copy_key(trusted_match);
644  else if (valid_match && !c_crypt_opportunistic_encrypt_strong_keys)
645  return_key = smime_copy_key(valid_match);
646  else
647  return_key = NULL;
648  }
649  else if (trusted_match && !multi_trusted_matches)
650  {
651  return_key = smime_copy_key(trusted_match);
652  }
653  else
654  {
655  return_key = smime_copy_key(dlg_select_smime_key(matches, mailbox));
656  }
657 
658  smime_key_free(&matches);
659  }
660 
661  return return_key;
662 }
663 
671 static struct SmimeKey *smime_get_key_by_str(const char *str, KeyFlags abilities, bool only_public_key)
672 {
673  if (!str)
674  return NULL;
675 
676  struct SmimeKey *results = NULL, *result = NULL;
677  struct SmimeKey *matches = NULL;
678  struct SmimeKey **matches_end = &matches;
679  struct SmimeKey *match = NULL;
680  struct SmimeKey *return_key = NULL;
681 
682  results = smime_get_candidates(str, only_public_key);
683  for (result = results; result; result = result->next)
684  {
685  if (abilities && !(result->flags & abilities))
686  {
687  continue;
688  }
689 
690  if (mutt_istr_equal(str, result->hash) ||
691  mutt_istr_find(result->email, str) || mutt_istr_find(result->label, str))
692  {
693  match = smime_copy_key(result);
694  *matches_end = match;
695  matches_end = &match->next;
696  }
697  }
698 
699  smime_key_free(&results);
700 
701  if (matches)
702  {
703  return_key = smime_copy_key(dlg_select_smime_key(matches, str));
704  smime_key_free(&matches);
705  }
706 
707  return return_key;
708 }
709 
717 static struct SmimeKey *smime_ask_for_key(char *prompt, KeyFlags abilities, bool only_public_key)
718 {
719  struct SmimeKey *key = NULL;
720  struct Buffer *resp = mutt_buffer_pool_get();
721 
722  if (!prompt)
723  prompt = _("Enter keyID: ");
724 
726 
727  while (true)
728  {
729  mutt_buffer_reset(resp);
730  if (mutt_buffer_get_field(prompt, resp, MUTT_COMP_NO_FLAGS, false, NULL, NULL, NULL) != 0)
731  {
732  goto done;
733  }
734 
735  key = smime_get_key_by_str(mutt_buffer_string(resp), abilities, only_public_key);
736  if (key)
737  goto done;
738 
739  mutt_error(_("No matching keys found for \"%s\""), mutt_buffer_string(resp));
740  }
741 
742 done:
744  return key;
745 }
746 
754 static void getkeys(char *mailbox)
755 {
756  const char *k = NULL;
757 
758  struct SmimeKey *key = smime_get_key_by_addr(mailbox, KEYFLAG_CANENCRYPT, false, false);
759 
760  if (!key)
761  {
762  char buf[256];
763  snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), mailbox);
764  key = smime_ask_for_key(buf, KEYFLAG_CANENCRYPT, false);
765  }
766 
767  const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
768  size_t smime_keys_len = mutt_str_len(c_smime_keys);
769 
770  const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
771  k = key ? key->hash : NONULL(c_smime_default_key);
772 
773  /* if the key is different from last time */
774  if ((mutt_buffer_len(&SmimeKeyToUse) <= smime_keys_len) ||
775  !mutt_istr_equal(k, SmimeKeyToUse.data + smime_keys_len + 1))
776  {
778  mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), k);
779  const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
780  mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates), k);
781  }
782 
783  smime_key_free(&key);
784 }
785 
789 void smime_class_getkeys(struct Envelope *env)
790 {
791  const bool c_smime_decrypt_use_default_key = cs_subset_bool(NeoMutt->sub, "smime_decrypt_use_default_key");
792  const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
793  if (c_smime_decrypt_use_default_key && c_smime_default_key)
794  {
795  const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
796  mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), c_smime_default_key);
797  const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
798  mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates),
799  c_smime_default_key);
800  return;
801  }
802 
803  struct Address *a = NULL;
804  TAILQ_FOREACH(a, &env->to, entries)
805  {
806  if (mutt_addr_is_user(a))
807  {
808  getkeys(a->mailbox);
809  return;
810  }
811  }
812 
813  TAILQ_FOREACH(a, &env->cc, entries)
814  {
815  if (mutt_addr_is_user(a))
816  {
817  getkeys(a->mailbox);
818  return;
819  }
820  }
821 
822  struct Address *f = mutt_default_from(NeoMutt->sub);
823  getkeys(f->mailbox);
824  mutt_addr_free(&f);
825 }
826 
830 char *smime_class_find_keys(const struct AddressList *al, bool oppenc_mode)
831 {
832  struct SmimeKey *key = NULL;
833  char *keyid = NULL, *keylist = NULL;
834  size_t keylist_size = 0;
835  size_t keylist_used = 0;
836 
837  struct Address *a = NULL;
838  TAILQ_FOREACH(a, al, entries)
839  {
840  key = smime_get_key_by_addr(a->mailbox, KEYFLAG_CANENCRYPT, true, oppenc_mode);
841  if (!key && !oppenc_mode)
842  {
843  char buf[1024];
844  snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), a->mailbox);
845  key = smime_ask_for_key(buf, KEYFLAG_CANENCRYPT, true);
846  }
847  if (!key)
848  {
849  if (!oppenc_mode)
850  mutt_message(_("No (valid) certificate found for %s"), a->mailbox);
851  FREE(&keylist);
852  return NULL;
853  }
854 
855  keyid = key->hash;
856  keylist_size += mutt_str_len(keyid) + 2;
857  mutt_mem_realloc(&keylist, keylist_size);
858  sprintf(keylist + keylist_used, "%s%s", keylist_used ? " " : "", keyid);
859  keylist_used = mutt_str_len(keylist);
860 
861  smime_key_free(&key);
862  }
863  return keylist;
864 }
865 
877 static int smime_handle_cert_email(char *certificate, char *mailbox, bool copy,
878  char ***buffer, int *num)
879 {
880  char email[256];
881  int rc = -1, count = 0;
882  pid_t pid;
883 
884  FILE *fp_err = mutt_file_mkstemp();
885  if (!fp_err)
886  {
887  mutt_perror(_("Can't create temporary file"));
888  return 1;
889  }
890 
891  FILE *fp_out = mutt_file_mkstemp();
892  if (!fp_out)
893  {
894  mutt_file_fclose(&fp_err);
895  mutt_perror(_("Can't create temporary file"));
896  return 1;
897  }
898 
899  const char *const c_smime_get_cert_email_command = cs_subset_string(NeoMutt->sub, "smime_get_cert_email_command");
900  pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), certificate,
901  NULL, NULL, NULL, NULL, NULL, NULL, c_smime_get_cert_email_command);
902  if (pid == -1)
903  {
904  mutt_message(_("Error: unable to create OpenSSL subprocess"));
905  mutt_file_fclose(&fp_err);
906  mutt_file_fclose(&fp_out);
907  return 1;
908  }
909 
910  filter_wait(pid);
911 
912  fflush(fp_out);
913  rewind(fp_out);
914  fflush(fp_err);
915  rewind(fp_err);
916 
917  while ((fgets(email, sizeof(email), fp_out)))
918  {
919  size_t len = mutt_str_len(email);
920  if (len && (email[len - 1] == '\n'))
921  email[len - 1] = '\0';
922  if (mutt_istr_startswith(email, mailbox))
923  rc = 1;
924 
925  rc = (rc < 0) ? 0 : rc;
926  count++;
927  }
928 
929  if (rc == -1)
930  {
931  mutt_endwin();
932  mutt_file_copy_stream(fp_err, stdout);
933  mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
934  rc = 1;
935  }
936  else if (rc == 0)
937  rc = 1;
938  else
939  rc = 0;
940 
941  if (copy && buffer && num)
942  {
943  (*num) = count;
944  *buffer = mutt_mem_calloc(count, sizeof(char *));
945  count = 0;
946 
947  rewind(fp_out);
948  while ((fgets(email, sizeof(email), fp_out)))
949  {
950  size_t len = mutt_str_len(email);
951  if (len && (email[len - 1] == '\n'))
952  email[len - 1] = '\0';
953  (*buffer)[count] = mutt_mem_calloc(mutt_str_len(email) + 1, sizeof(char));
954  strncpy((*buffer)[count], email, mutt_str_len(email));
955  count++;
956  }
957  }
958  else if (copy)
959  rc = 2;
960 
961  mutt_file_fclose(&fp_out);
962  mutt_file_fclose(&fp_err);
963 
964  return rc;
965 }
966 
972 static char *smime_extract_certificate(const char *infile)
973 {
974  FILE *fp_err = NULL;
975  FILE *fp_out = NULL;
976  FILE *fp_cert = NULL;
977  char *retval = NULL;
978  pid_t pid;
979  int empty;
980 
981  struct Buffer *pk7out = mutt_buffer_pool_get();
982  struct Buffer *certfile = mutt_buffer_pool_get();
983 
984  fp_err = mutt_file_mkstemp();
985  if (!fp_err)
986  {
987  mutt_perror(_("Can't create temporary file"));
988  goto cleanup;
989  }
990 
991  mutt_buffer_mktemp(pk7out);
992  fp_out = mutt_file_fopen(mutt_buffer_string(pk7out), "w+");
993  if (!fp_out)
994  {
996  goto cleanup;
997  }
998 
999  /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
1000  * extract the full set of certificates directly. */
1001  const char *const c_smime_pk7out_command = cs_subset_string(NeoMutt->sub, "smime_pk7out_command");
1002  pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), infile,
1003  NULL, NULL, NULL, NULL, NULL, NULL, c_smime_pk7out_command);
1004  if (pid == -1)
1005  {
1006  mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1007  goto cleanup;
1008  }
1009 
1010  filter_wait(pid);
1011 
1012  fflush(fp_out);
1013  rewind(fp_out);
1014  fflush(fp_err);
1015  rewind(fp_err);
1016  empty = (fgetc(fp_out) == EOF);
1017  if (empty)
1018  {
1020  mutt_file_copy_stream(fp_err, stdout);
1021  goto cleanup;
1022  }
1023  mutt_file_fclose(&fp_out);
1024 
1025  mutt_buffer_mktemp(certfile);
1026  fp_cert = mutt_file_fopen(mutt_buffer_string(certfile), "w+");
1027  if (!fp_cert)
1028  {
1029  mutt_perror(mutt_buffer_string(certfile));
1031  goto cleanup;
1032  }
1033 
1034  // Step 2: Extract the certificates from a PKCS#7 structure.
1035  const char *const c_smime_get_cert_command = cs_subset_string(NeoMutt->sub, "smime_get_cert_command");
1036  pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_cert), fileno(fp_err),
1037  mutt_buffer_string(pk7out), NULL, NULL, NULL, NULL, NULL,
1038  NULL, c_smime_get_cert_command);
1039  if (pid == -1)
1040  {
1041  mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1043  goto cleanup;
1044  }
1045 
1046  filter_wait(pid);
1047 
1049 
1050  fflush(fp_cert);
1051  rewind(fp_cert);
1052  fflush(fp_err);
1053  rewind(fp_err);
1054  empty = (fgetc(fp_cert) == EOF);
1055  if (empty)
1056  {
1057  mutt_file_copy_stream(fp_err, stdout);
1058  goto cleanup;
1059  }
1060 
1061  mutt_file_fclose(&fp_cert);
1062 
1063  retval = mutt_buffer_strdup(certfile);
1064 
1065 cleanup:
1066  mutt_file_fclose(&fp_err);
1067  if (fp_out)
1068  {
1069  mutt_file_fclose(&fp_out);
1071  }
1072  if (fp_cert)
1073  {
1074  mutt_file_fclose(&fp_cert);
1076  }
1077  mutt_buffer_pool_release(&pk7out);
1078  mutt_buffer_pool_release(&certfile);
1079  return retval;
1080 }
1081 
1087 static char *smime_extract_signer_certificate(const char *infile)
1088 {
1089  char *cert = NULL;
1090  struct Buffer *certfile = NULL;
1091  pid_t pid;
1092  int empty;
1093 
1094  FILE *fp_err = mutt_file_mkstemp();
1095  if (!fp_err)
1096  {
1097  mutt_perror(_("Can't create temporary file"));
1098  return NULL;
1099  }
1100 
1101  certfile = mutt_buffer_pool_get();
1102  mutt_buffer_mktemp(certfile);
1103  FILE *fp_out = mutt_file_fopen(mutt_buffer_string(certfile), "w+");
1104  if (!fp_out)
1105  {
1106  mutt_file_fclose(&fp_err);
1107  mutt_perror(mutt_buffer_string(certfile));
1108  goto cleanup;
1109  }
1110 
1111  /* Extract signer's certificate
1112  */
1113  const char *const c_smime_get_signer_cert_command = cs_subset_string(NeoMutt->sub, "smime_get_signer_cert_command");
1114  pid = smime_invoke(NULL, NULL, NULL, -1, -1, fileno(fp_err), infile, NULL,
1115  NULL, NULL, NULL, mutt_buffer_string(certfile), NULL,
1116  c_smime_get_signer_cert_command);
1117  if (pid == -1)
1118  {
1119  mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
1120  goto cleanup;
1121  }
1122 
1123  filter_wait(pid);
1124 
1125  fflush(fp_out);
1126  rewind(fp_out);
1127  fflush(fp_err);
1128  rewind(fp_err);
1129  empty = (fgetc(fp_out) == EOF);
1130  if (empty)
1131  {
1132  mutt_endwin();
1133  mutt_file_copy_stream(fp_err, stdout);
1135  goto cleanup;
1136  }
1137 
1138  mutt_file_fclose(&fp_out);
1139  cert = mutt_buffer_strdup(certfile);
1140 
1141 cleanup:
1142  mutt_file_fclose(&fp_err);
1143  if (fp_out)
1144  {
1145  mutt_file_fclose(&fp_out);
1147  }
1148  mutt_buffer_pool_release(&certfile);
1149  return cert;
1150 }
1151 
1155 void smime_class_invoke_import(const char *infile, const char *mailbox)
1156 {
1157  char *certfile = NULL;
1158  struct Buffer *buf = NULL;
1159 
1160  FILE *fp_err = mutt_file_mkstemp();
1161  if (!fp_err)
1162  {
1163  mutt_perror(_("Can't create temporary file"));
1164  goto done;
1165  }
1166 
1167  FILE *fp_out = mutt_file_mkstemp();
1168  if (!fp_out)
1169  {
1170  mutt_perror(_("Can't create temporary file"));
1171  goto done;
1172  }
1173 
1174  buf = mutt_buffer_pool_get();
1175  const bool c_smime_ask_cert_label = cs_subset_bool(NeoMutt->sub, "smime_ask_cert_label");
1176  if (c_smime_ask_cert_label)
1177  {
1178  if ((mutt_buffer_get_field(_("Label for certificate: "), buf,
1179  MUTT_COMP_NO_FLAGS, false, NULL, NULL, NULL) != 0) ||
1180  mutt_buffer_is_empty(buf))
1181  {
1182  goto done;
1183  }
1184  }
1185 
1186  mutt_endwin();
1187  certfile = smime_extract_certificate(infile);
1188  if (certfile)
1189  {
1190  mutt_endwin();
1191 
1192  const char *const c_smime_import_cert_command = cs_subset_string(NeoMutt->sub, "smime_import_cert_command");
1193  FILE *fp_smime_in = NULL;
1194  pid_t pid = smime_invoke(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1195  fileno(fp_err), certfile, NULL, NULL, NULL, NULL,
1196  NULL, NULL, c_smime_import_cert_command);
1197  if (pid == -1)
1198  {
1199  mutt_message(_("Error: unable to create OpenSSL subprocess"));
1200  goto done;
1201  }
1202  fputs(mutt_buffer_string(buf), fp_smime_in);
1203  fputc('\n', fp_smime_in);
1204  mutt_file_fclose(&fp_smime_in);
1205 
1206  filter_wait(pid);
1207 
1208  mutt_file_unlink(certfile);
1209  FREE(&certfile);
1210  }
1211 
1212  fflush(fp_out);
1213  rewind(fp_out);
1214  fflush(fp_err);
1215  rewind(fp_err);
1216 
1217  mutt_file_copy_stream(fp_out, stdout);
1218  mutt_file_copy_stream(fp_err, stdout);
1219 
1220 done:
1221  mutt_file_fclose(&fp_out);
1222  mutt_file_fclose(&fp_err);
1224 }
1225 
1229 int smime_class_verify_sender(struct Email *e, struct Message *msg)
1230 {
1231  char *mbox = NULL, *certfile = NULL;
1232  int rc = 1;
1233 
1234  struct Buffer *tempfname = mutt_buffer_pool_get();
1235  mutt_buffer_mktemp(tempfname);
1236  FILE *fp_out = mutt_file_fopen(mutt_buffer_string(tempfname), "w");
1237  if (!fp_out)
1238  {
1239  mutt_perror(mutt_buffer_string(tempfname));
1240  goto cleanup;
1241  }
1242 
1243  const bool encrypt = e->security & SEC_ENCRYPT;
1244  mutt_copy_message(fp_out, e, msg,
1246  encrypt ? (CH_MIME | CH_WEED | CH_NONEWLINE) : CH_NO_FLAGS, 0);
1247 
1248  fflush(fp_out);
1249  mutt_file_fclose(&fp_out);
1250 
1251  if (!TAILQ_EMPTY(&e->env->from))
1252  {
1254  mbox = TAILQ_FIRST(&e->env->from)->mailbox;
1255  }
1256  else if (!TAILQ_EMPTY(&e->env->sender))
1257  {
1259  mbox = TAILQ_FIRST(&e->env->sender)->mailbox;
1260  }
1261 
1262  if (mbox)
1263  {
1265  if (certfile)
1266  {
1268  if (smime_handle_cert_email(certfile, mbox, false, NULL, NULL))
1269  {
1270  if (isendwin())
1272  }
1273  else
1274  rc = 0;
1275  mutt_file_unlink(certfile);
1276  FREE(&certfile);
1277  }
1278  else
1279  mutt_any_key_to_continue(_("no certfile"));
1280  }
1281  else
1282  mutt_any_key_to_continue(_("no mbox"));
1283 
1285 
1286 cleanup:
1287  mutt_buffer_pool_release(&tempfname);
1288  return rc;
1289 }
1290 
1307 static pid_t smime_invoke_encrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1308  FILE **fp_smime_err, int fp_smime_infd,
1309  int fp_smime_outfd, int fp_smime_errfd,
1310  const char *fname, const char *uids)
1311 {
1312  const char *const c_smime_encrypt_with = cs_subset_string(NeoMutt->sub, "smime_encrypt_with");
1313  const char *const c_smime_encrypt_command = cs_subset_string(NeoMutt->sub, "smime_encrypt_command");
1314  return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1315  fp_smime_outfd, fp_smime_errfd, fname, NULL, c_smime_encrypt_with,
1316  NULL, NULL, uids, NULL, c_smime_encrypt_command);
1317 }
1318 
1334 static pid_t smime_invoke_sign(FILE **fp_smime_in, FILE **fp_smime_out,
1335  FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1336  int fp_smime_errfd, const char *fname)
1337 {
1338  const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1339  const char *const c_smime_sign_command = cs_subset_string(NeoMutt->sub, "smime_sign_command");
1340  return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1341  fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL,
1342  c_smime_sign_digest_alg, mutt_buffer_string(&SmimeKeyToUse),
1344  mutt_buffer_string(&SmimeIntermediateToUse), c_smime_sign_command);
1345 }
1346 
1350 struct Body *smime_class_build_smime_entity(struct Body *a, char *certlist)
1351 {
1352  char buf[1024], certfile[PATH_MAX];
1353  char *cert_end = NULL;
1354  FILE *fp_smime_in = NULL, *fp_smime_err = NULL, *fp_out = NULL, *fp_tmp = NULL;
1355  struct Body *t = NULL;
1356  int err = 0, empty, off;
1357  pid_t pid;
1358 
1359  struct Buffer *tempfile = mutt_buffer_pool_get();
1360  struct Buffer *smime_infile = mutt_buffer_pool_get();
1361 
1362  mutt_buffer_mktemp(tempfile);
1363  fp_out = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
1364  if (!fp_out)
1365  {
1366  mutt_perror(mutt_buffer_string(tempfile));
1367  goto cleanup;
1368  }
1369 
1370  fp_smime_err = mutt_file_mkstemp();
1371  if (!fp_smime_err)
1372  {
1373  mutt_perror(_("Can't create temporary file"));
1374  goto cleanup;
1375  }
1376 
1377  mutt_buffer_mktemp(smime_infile);
1378  fp_tmp = mutt_file_fopen(mutt_buffer_string(smime_infile), "w+");
1379  if (!fp_tmp)
1380  {
1381  mutt_perror(mutt_buffer_string(smime_infile));
1382  goto cleanup;
1383  }
1384 
1385  *certfile = '\0';
1386  for (char *cert_start = certlist; cert_start; cert_start = cert_end)
1387  {
1388  cert_end = strchr(cert_start, ' ');
1389  if (cert_end)
1390  *cert_end = '\0';
1391  if (*cert_start)
1392  {
1393  off = mutt_str_len(certfile);
1394  const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
1395  snprintf(certfile + off, sizeof(certfile) - off, "%s%s/%s",
1396  (off != 0) ? " " : "", NONULL(c_smime_certificates), cert_start);
1397  }
1398  if (cert_end)
1399  *cert_end++ = ' ';
1400  }
1401 
1402  /* write a MIME entity */
1403  mutt_write_mime_header(a, fp_tmp, NeoMutt->sub);
1404  fputc('\n', fp_tmp);
1405  mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
1406  mutt_file_fclose(&fp_tmp);
1407 
1408  pid = smime_invoke_encrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1409  fileno(fp_smime_err),
1410  mutt_buffer_string(smime_infile), certfile);
1411  if (pid == -1)
1412  {
1413  mutt_file_unlink(mutt_buffer_string(smime_infile));
1414  goto cleanup;
1415  }
1416 
1417  mutt_file_fclose(&fp_smime_in);
1418 
1419  filter_wait(pid);
1420  mutt_file_unlink(mutt_buffer_string(smime_infile));
1421 
1422  fflush(fp_out);
1423  rewind(fp_out);
1424  empty = (fgetc(fp_out) == EOF);
1425  mutt_file_fclose(&fp_out);
1426 
1427  fflush(fp_smime_err);
1428  rewind(fp_smime_err);
1429  while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1430  {
1431  err = 1;
1432  fputs(buf, stdout);
1433  }
1434  mutt_file_fclose(&fp_smime_err);
1435 
1436  /* pause if there is any error output from SMIME */
1437  if (err)
1439 
1440  if (empty)
1441  {
1442  /* fatal error while trying to encrypt message */
1443  if (err == 0)
1444  mutt_any_key_to_continue(_("No output from OpenSSL..."));
1446  goto cleanup;
1447  }
1448 
1449  t = mutt_body_new();
1450  t->type = TYPE_APPLICATION;
1451  t->subtype = mutt_str_dup("x-pkcs7-mime");
1452  mutt_param_set(&t->parameter, "name", "smime.p7m");
1453  mutt_param_set(&t->parameter, "smime-type", "enveloped-data");
1454  t->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1455  t->use_disp = true;
1456  t->disposition = DISP_ATTACH;
1457  t->d_filename = mutt_str_dup("smime.p7m");
1458  t->filename = mutt_buffer_strdup(tempfile);
1459  t->unlink = true; /* delete after sending the message */
1460  t->parts = NULL;
1461  t->next = NULL;
1462 
1463 cleanup:
1464  if (fp_out)
1465  {
1466  mutt_file_fclose(&fp_out);
1468  }
1469  mutt_file_fclose(&fp_smime_err);
1470  if (fp_tmp)
1471  {
1472  mutt_file_fclose(&fp_tmp);
1473  mutt_file_unlink(mutt_buffer_string(smime_infile));
1474  }
1475  mutt_buffer_pool_release(&tempfile);
1476  mutt_buffer_pool_release(&smime_infile);
1477 
1478  return t;
1479 }
1480 
1493 static char *openssl_md_to_smime_micalg(const char *md)
1494 {
1495  if (!md)
1496  return 0;
1497 
1498  char *micalg = NULL;
1499  if (mutt_istr_startswith(md, "sha"))
1500  {
1501  const size_t l = strlen(md) + 2;
1502  micalg = mutt_mem_malloc(l);
1503  snprintf(micalg, l, "sha-%s", md + 3);
1504  }
1505  else
1506  {
1507  micalg = mutt_str_dup(md);
1508  }
1509 
1510  return micalg;
1511 }
1512 
1516 struct Body *smime_class_sign_message(struct Body *a, const struct AddressList *from)
1517 {
1518  struct Body *t = NULL;
1519  struct Body *retval = NULL;
1520  char buf[1024];
1521  struct Buffer *filetosign = NULL, *signedfile = NULL;
1522  FILE *fp_smime_in = NULL, *fp_smime_out = NULL, *fp_smime_err = NULL, *fp_sign = NULL;
1523  int err = 0;
1524  int empty = 0;
1525  pid_t pid;
1526  const char *intermediates = NULL;
1527 
1528  const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
1529  const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
1530  const char *signas = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
1531  if (!signas || (*signas == '\0'))
1532  {
1533  mutt_error(_("Can't sign: No key specified. Use Sign As."));
1534  return NULL;
1535  }
1536 
1537  crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1538 
1539  filetosign = mutt_buffer_pool_get();
1540  signedfile = mutt_buffer_pool_get();
1541 
1542  mutt_buffer_mktemp(filetosign);
1543  fp_sign = mutt_file_fopen(mutt_buffer_string(filetosign), "w+");
1544  if (!fp_sign)
1545  {
1546  mutt_perror(mutt_buffer_string(filetosign));
1547  goto cleanup;
1548  }
1549 
1550  mutt_buffer_mktemp(signedfile);
1551  fp_smime_out = mutt_file_fopen(mutt_buffer_string(signedfile), "w+");
1552  if (!fp_smime_out)
1553  {
1554  mutt_perror(mutt_buffer_string(signedfile));
1555  goto cleanup;
1556  }
1557 
1558  mutt_write_mime_header(a, fp_sign, NeoMutt->sub);
1559  fputc('\n', fp_sign);
1560  mutt_write_mime_body(a, fp_sign, NeoMutt->sub);
1561  mutt_file_fclose(&fp_sign);
1562 
1563  const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
1564  const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
1565  mutt_buffer_printf(&SmimeKeyToUse, "%s/%s", NONULL(c_smime_keys), signas);
1566  mutt_buffer_printf(&SmimeCertToUse, "%s/%s", NONULL(c_smime_certificates), signas);
1567 
1568  struct SmimeKey *signas_key = smime_get_key_by_hash(signas, 1);
1569  if (!signas_key || mutt_str_equal("?", signas_key->issuer))
1570  intermediates = signas; /* so openssl won't complain in any case */
1571  else
1572  intermediates = signas_key->issuer;
1573 
1575  NONULL(c_smime_certificates), intermediates);
1576 
1577  smime_key_free(&signas_key);
1578 
1579  pid = smime_invoke_sign(&fp_smime_in, NULL, &fp_smime_err, -1,
1580  fileno(fp_smime_out), -1, mutt_buffer_string(filetosign));
1581  if (pid == -1)
1582  {
1583  mutt_perror(_("Can't open OpenSSL subprocess"));
1584  mutt_file_unlink(mutt_buffer_string(filetosign));
1585  goto cleanup;
1586  }
1587  fputs(SmimePass, fp_smime_in);
1588  fputc('\n', fp_smime_in);
1589  mutt_file_fclose(&fp_smime_in);
1590 
1591  filter_wait(pid);
1592 
1593  /* check for errors from OpenSSL */
1594  err = 0;
1595  fflush(fp_smime_err);
1596  rewind(fp_smime_err);
1597  while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1598  {
1599  err = 1;
1600  fputs(buf, stdout);
1601  }
1602  mutt_file_fclose(&fp_smime_err);
1603 
1604  fflush(fp_smime_out);
1605  rewind(fp_smime_out);
1606  empty = (fgetc(fp_smime_out) == EOF);
1607  mutt_file_fclose(&fp_smime_out);
1608 
1609  mutt_file_unlink(mutt_buffer_string(filetosign));
1610 
1611  if (err)
1613 
1614  if (empty)
1615  {
1616  mutt_any_key_to_continue(_("No output from OpenSSL..."));
1617  mutt_file_unlink(mutt_buffer_string(signedfile));
1618  goto cleanup; /* fatal error while signing */
1619  }
1620 
1621  t = mutt_body_new();
1622  t->type = TYPE_MULTIPART;
1623  t->subtype = mutt_str_dup("signed");
1624  t->encoding = ENC_7BIT;
1625  t->use_disp = false;
1626  t->disposition = DISP_INLINE;
1627 
1629 
1630  const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1631  char *micalg = openssl_md_to_smime_micalg(c_smime_sign_digest_alg);
1632  mutt_param_set(&t->parameter, "micalg", micalg);
1633  FREE(&micalg);
1634 
1635  mutt_param_set(&t->parameter, "protocol", "application/x-pkcs7-signature");
1636 
1637  t->parts = a;
1638  retval = t;
1639 
1640  t->parts->next = mutt_body_new();
1641  t = t->parts->next;
1642  t->type = TYPE_APPLICATION;
1643  t->subtype = mutt_str_dup("x-pkcs7-signature");
1644  t->filename = mutt_buffer_strdup(signedfile);
1645  t->d_filename = mutt_str_dup("smime.p7s");
1646  t->use_disp = true;
1647  t->disposition = DISP_ATTACH;
1648  t->encoding = ENC_BASE64;
1649  t->unlink = true; /* ok to remove this file after sending. */
1650 
1651 cleanup:
1652  if (fp_sign)
1653  {
1654  mutt_file_fclose(&fp_sign);
1655  mutt_file_unlink(mutt_buffer_string(filetosign));
1656  }
1657  if (fp_smime_out)
1658  {
1659  mutt_file_fclose(&fp_smime_out);
1660  mutt_file_unlink(mutt_buffer_string(signedfile));
1661  }
1662  mutt_buffer_pool_release(&filetosign);
1663  mutt_buffer_pool_release(&signedfile);
1664  return retval;
1665 }
1666 
1684 static pid_t smime_invoke_verify(FILE **fp_smime_in, FILE **fp_smime_out,
1685  FILE **fp_smime_err, int fp_smime_infd,
1686  int fp_smime_outfd, int fp_smime_errfd,
1687  const char *fname, const char *sig_fname, int opaque)
1688 {
1689  const char *const c_smime_verify_opaque_command = cs_subset_string(NeoMutt->sub, "smime_verify_opaque_command");
1690  const char *const c_smime_verify_command = cs_subset_string(NeoMutt->sub, "smime_verify_command");
1691  return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1692  fp_smime_errfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL,
1693  (opaque ? c_smime_verify_opaque_command : c_smime_verify_command));
1694 }
1695 
1711 static pid_t smime_invoke_decrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1712  FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1713  int fp_smime_errfd, const char *fname)
1714 {
1715  const char *const c_smime_decrypt_command = cs_subset_string(NeoMutt->sub, "smime_decrypt_command");
1716  return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1717  fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL, NULL,
1719  mutt_buffer_string(&SmimeCertToUse), NULL, c_smime_decrypt_command);
1720 }
1721 
1725 int smime_class_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
1726 {
1727  FILE *fp = NULL, *fp_smime_out = NULL, *fp_smime_err = NULL;
1728  pid_t pid;
1729  int badsig = -1;
1730 
1731  LOFF_T tmpoffset = 0;
1732  size_t tmplength = 0;
1733  int orig_type = sigbdy->type;
1734 
1735  struct Buffer *signedfile = mutt_buffer_pool_get();
1736 
1737  mutt_buffer_printf(signedfile, "%s.sig", tempfile);
1738 
1739  /* decode to a tempfile, saving the original destination */
1740  fp = s->fp_out;
1741  s->fp_out = mutt_file_fopen(mutt_buffer_string(signedfile), "w");
1742  if (!s->fp_out)
1743  {
1744  mutt_perror(mutt_buffer_string(signedfile));
1745  goto cleanup;
1746  }
1747  /* decoding the attachment changes the size and offset, so save a copy
1748  * of the "real" values now, and restore them after processing */
1749  tmplength = sigbdy->length;
1750  tmpoffset = sigbdy->offset;
1751 
1752  /* if we are decoding binary bodies, we don't want to prefix each
1753  * line with the prefix or else the data will get corrupted. */
1754  char *save_prefix = s->prefix;
1755  s->prefix = NULL;
1756 
1757  mutt_decode_attachment(sigbdy, s);
1758 
1759  sigbdy->length = ftello(s->fp_out);
1760  sigbdy->offset = 0;
1761  mutt_file_fclose(&s->fp_out);
1762 
1763  /* restore final destination and substitute the tempfile for input */
1764  s->fp_out = fp;
1765  fp = s->fp_in;
1766  s->fp_in = fopen(mutt_buffer_string(signedfile), "r");
1767 
1768  /* restore the prefix */
1769  s->prefix = save_prefix;
1770 
1771  sigbdy->type = orig_type;
1772 
1773  fp_smime_err = mutt_file_mkstemp();
1774  if (!fp_smime_err)
1775  {
1776  mutt_perror(_("Can't create temporary file"));
1777  goto cleanup;
1778  }
1779 
1780  crypt_current_time(s, "OpenSSL");
1781 
1782  pid = smime_invoke_verify(NULL, &fp_smime_out, NULL, -1, -1, fileno(fp_smime_err),
1783  tempfile, mutt_buffer_string(signedfile), 0);
1784  if (pid != -1)
1785  {
1786  fflush(fp_smime_out);
1787  mutt_file_fclose(&fp_smime_out);
1788 
1789  if (filter_wait(pid))
1790  badsig = -1;
1791  else
1792  {
1793  char *line = NULL;
1794  size_t linelen;
1795 
1796  fflush(fp_smime_err);
1797  rewind(fp_smime_err);
1798 
1799  line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NO_FLAGS);
1800  if (linelen && mutt_istr_equal(line, "verification successful"))
1801  badsig = 0;
1802 
1803  FREE(&line);
1804  }
1805  }
1806 
1807  fflush(fp_smime_err);
1808  rewind(fp_smime_err);
1809  mutt_file_copy_stream(fp_smime_err, s->fp_out);
1810  mutt_file_fclose(&fp_smime_err);
1811 
1812  state_attach_puts(s, _("[-- End of OpenSSL output --]\n\n"));
1813 
1814  mutt_file_unlink(mutt_buffer_string(signedfile));
1815 
1816  sigbdy->length = tmplength;
1817  sigbdy->offset = tmpoffset;
1818 
1819  /* restore the original source stream */
1820  mutt_file_fclose(&s->fp_in);
1821  s->fp_in = fp;
1822 
1823 cleanup:
1824  mutt_buffer_pool_release(&signedfile);
1825  return badsig;
1826 }
1827 
1837 static struct Body *smime_handle_entity(struct Body *m, struct State *s, FILE *fp_out_file)
1838 {
1839  struct Buffer tmpfname = mutt_buffer_make(0);
1840  FILE *fp_smime_out = NULL, *fp_smime_in = NULL, *fp_smime_err = NULL;
1841  FILE *fp_tmp = NULL, *fp_out = NULL;
1842  struct Body *p = NULL;
1843  pid_t pid = -1;
1845 
1846  if (!(type & APPLICATION_SMIME))
1847  return NULL;
1848 
1849  /* Because of the mutt_body_handler() we avoid the buffer pool. */
1850  fp_smime_out = mutt_file_mkstemp();
1851  if (!fp_smime_out)
1852  {
1853  mutt_perror(_("Can't create temporary file"));
1854  goto cleanup;
1855  }
1856 
1857  fp_smime_err = mutt_file_mkstemp();
1858  if (!fp_smime_err)
1859  {
1860  mutt_perror(_("Can't create temporary file"));
1861  goto cleanup;
1862  }
1863 
1864  mutt_buffer_mktemp(&tmpfname);
1865  fp_tmp = mutt_file_fopen(mutt_buffer_string(&tmpfname), "w+");
1866  if (!fp_tmp)
1867  {
1868  mutt_perror(mutt_buffer_string(&tmpfname));
1869  goto cleanup;
1870  }
1871 
1872  if (!mutt_file_seek(s->fp_in, m->offset, SEEK_SET))
1873  {
1874  goto cleanup;
1875  }
1876 
1877  mutt_file_copy_bytes(s->fp_in, fp_tmp, m->length);
1878 
1879  fflush(fp_tmp);
1880  mutt_file_fclose(&fp_tmp);
1881 
1882  if ((type & SEC_ENCRYPT) &&
1883  ((pid = smime_invoke_decrypt(&fp_smime_in, NULL, NULL, -1,
1884  fileno(fp_smime_out), fileno(fp_smime_err),
1885  mutt_buffer_string(&tmpfname))) == -1))
1886  {
1888  if (s->flags & MUTT_DISPLAY)
1889  {
1890  state_attach_puts(s, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1891  }
1892  goto cleanup;
1893  }
1894  else if ((type & SEC_SIGNOPAQUE) &&
1895  ((pid = smime_invoke_verify(&fp_smime_in, NULL, NULL, -1,
1896  fileno(fp_smime_out), fileno(fp_smime_err), NULL,
1897  mutt_buffer_string(&tmpfname), SEC_SIGNOPAQUE)) == -1))
1898  {
1900  if (s->flags & MUTT_DISPLAY)
1901  {
1902  state_attach_puts(s, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1903  }
1904  goto cleanup;
1905  }
1906 
1907  if (type & SEC_ENCRYPT)
1908  {
1911  fputs(SmimePass, fp_smime_in);
1912  fputc('\n', fp_smime_in);
1913  }
1914 
1915  mutt_file_fclose(&fp_smime_in);
1916 
1917  filter_wait(pid);
1919 
1920  if (s->flags & MUTT_DISPLAY)
1921  {
1922  fflush(fp_smime_err);
1923  rewind(fp_smime_err);
1924 
1925  const int c = fgetc(fp_smime_err);
1926  if (c != EOF)
1927  {
1928  ungetc(c, fp_smime_err);
1929 
1930  crypt_current_time(s, "OpenSSL");
1931  mutt_file_copy_stream(fp_smime_err, s->fp_out);
1932  state_attach_puts(s, _("[-- End of OpenSSL output --]\n\n"));
1933  }
1934 
1935  if (type & SEC_ENCRYPT)
1936  {
1937  state_attach_puts(s, _("[-- The following data is S/MIME encrypted --]\n"));
1938  }
1939  else
1940  state_attach_puts(s, _("[-- The following data is S/MIME signed --]\n"));
1941  }
1942 
1943  fflush(fp_smime_out);
1944  rewind(fp_smime_out);
1945 
1946  if (type & SEC_ENCRYPT)
1947  {
1948  /* void the passphrase, even if that wasn't the problem */
1949  if (fgetc(fp_smime_out) == EOF)
1950  {
1951  mutt_error(_("Decryption failed"));
1953  }
1954  rewind(fp_smime_out);
1955  }
1956 
1957  if (fp_out_file)
1958  fp_out = fp_out_file;
1959  else
1960  {
1961  fp_out = mutt_file_mkstemp();
1962  if (!fp_out)
1963  {
1964  mutt_perror(_("Can't create temporary file"));
1965  goto cleanup;
1966  }
1967  }
1968  char buf[8192];
1969  while (fgets(buf, sizeof(buf) - 1, fp_smime_out))
1970  {
1971  const size_t len = mutt_str_len(buf);
1972  if ((len > 1) && (buf[len - 2] == '\r'))
1973  {
1974  buf[len - 2] = '\n';
1975  buf[len - 1] = '\0';
1976  }
1977  fputs(buf, fp_out);
1978  }
1979  fflush(fp_out);
1980  rewind(fp_out);
1981 
1982  const long size = mutt_file_get_size_fp(fp_out);
1983  if (size == 0)
1984  {
1985  goto cleanup;
1986  }
1987  p = mutt_read_mime_header(fp_out, 0);
1988  if (p)
1989  {
1990  p->length = size - p->offset;
1991 
1992  mutt_parse_part(fp_out, p);
1993 
1994  if (s->flags & MUTT_DISPLAY)
1996 
1997  /* Store any protected headers in the parent so they can be
1998  * accessed for index updates after the handler recursion is done.
1999  * This is done before the handler to prevent a nested encrypted
2000  * handler from freeing the headers. */
2002  m->mime_headers = p->mime_headers;
2003  p->mime_headers = NULL;
2004 
2005  if (s->fp_out)
2006  {
2007  rewind(fp_out);
2008  FILE *fp_tmp_buffer = s->fp_in;
2009  s->fp_in = fp_out;
2010  mutt_body_handler(p, s);
2011  s->fp_in = fp_tmp_buffer;
2012  }
2013 
2014  /* Embedded multipart signed protected headers override the
2015  * encrypted headers. We need to do this after the handler so
2016  * they can be printed in the pager. */
2017  if (!(type & SMIME_SIGN) && mutt_is_multipart_signed(p) && p->parts &&
2018  p->parts->mime_headers)
2019  {
2021  m->mime_headers = p->parts->mime_headers;
2022  p->parts->mime_headers = NULL;
2023  }
2024  }
2025  mutt_file_fclose(&fp_smime_out);
2026 
2027  if (!fp_out_file)
2028  {
2029  mutt_file_fclose(&fp_out);
2031  }
2032  fp_out = NULL;
2033 
2034  if (s->flags & MUTT_DISPLAY)
2035  {
2036  if (type & SEC_ENCRYPT)
2037  state_attach_puts(s, _("\n[-- End of S/MIME encrypted data. --]\n"));
2038  else
2039  state_attach_puts(s, _("\n[-- End of S/MIME signed data. --]\n"));
2040  }
2041 
2042  if (type & SEC_SIGNOPAQUE)
2043  {
2044  char *line = NULL;
2045  size_t linelen;
2046 
2047  rewind(fp_smime_err);
2048 
2049  line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NO_FLAGS);
2050  if (linelen && mutt_istr_equal(line, "verification successful"))
2051  m->goodsig = true;
2052  FREE(&line);
2053  }
2054  else if (p)
2055  {
2056  m->goodsig = p->goodsig;
2057  m->badsig = p->badsig;
2058  }
2059 
2060 cleanup:
2061  mutt_file_fclose(&fp_smime_out);
2062  mutt_file_fclose(&fp_smime_err);
2063  mutt_file_fclose(&fp_tmp);
2064  mutt_file_fclose(&fp_out);
2065  mutt_buffer_dealloc(&tmpfname);
2066  return p;
2067 }
2068 
2072 int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
2073 {
2074  struct State s = { 0 };
2075  LOFF_T tmpoffset = b->offset;
2076  size_t tmplength = b->length;
2077  int rc = -1;
2078 
2079  if (!mutt_is_application_smime(b))
2080  return -1;
2081 
2082  if (b->parts)
2083  return -1;
2084 
2085  s.fp_in = fp_in;
2086  if (!mutt_file_seek(s.fp_in, b->offset, SEEK_SET))
2087  {
2088  return -1;
2089  }
2090 
2091  FILE *fp_tmp = mutt_file_mkstemp();
2092  if (!fp_tmp)
2093  {
2094  mutt_perror(_("Can't create temporary file"));
2095  return -1;
2096  }
2097 
2098  s.fp_out = fp_tmp;
2099  mutt_decode_attachment(b, &s);
2100  fflush(fp_tmp);
2101  b->length = ftello(s.fp_out);
2102  b->offset = 0;
2103  rewind(fp_tmp);
2104  s.fp_in = fp_tmp;
2105  s.fp_out = 0;
2106 
2108  if (!*fp_out)
2109  {
2110  mutt_perror(_("Can't create temporary file"));
2111  goto bail;
2112  }
2113 
2114  *cur = smime_handle_entity(b, &s, *fp_out);
2115  if (!*cur)
2116  goto bail;
2117 
2118  (*cur)->goodsig = b->goodsig;
2119  (*cur)->badsig = b->badsig;
2120  rc = 0;
2121 
2122 bail:
2123  b->length = tmplength;
2124  b->offset = tmpoffset;
2125  mutt_file_fclose(&fp_tmp);
2126  if (*fp_out)
2127  rewind(*fp_out);
2128 
2129  return rc;
2130 }
2131 
2135 int smime_class_application_handler(struct Body *m, struct State *s)
2136 {
2137  int rc = -1;
2138 
2139  /* clear out any mime headers before the handler, so they can't be spoofed. */
2141 
2142  struct Body *tattach = smime_handle_entity(m, s, NULL);
2143  if (tattach)
2144  {
2145  rc = 0;
2146  mutt_body_free(&tattach);
2147  }
2148  return rc;
2149 }
2150 
2155 {
2156  struct SmimeKey *key = NULL;
2157  const char *prompt = NULL;
2158  const char *letters = NULL;
2159  const char *choices = NULL;
2160  int choice;
2161 
2162  if (!(WithCrypto & APPLICATION_SMIME))
2163  return e->security;
2164 
2166 
2167  /* Opportunistic encrypt is controlling encryption.
2168  * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
2169  * letter choices for those. */
2170  const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
2171  if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
2172  {
2173  /* L10N: S/MIME options (opportunistic encryption is on) */
2174  prompt = _("S/MIME (s)ign, encrypt (w)ith, sign (a)s, (c)lear, or (o)ppenc mode off?");
2175  /* L10N: S/MIME options (opportunistic encryption is on) */
2176  letters = _("swaco");
2177  choices = "SwaCo";
2178  }
2179  /* Opportunistic encryption option is set, but is toggled off
2180  * for this message. */
2181  else if (c_crypt_opportunistic_encrypt)
2182  {
2183  /* L10N: S/MIME options (opportunistic encryption is off) */
2184  prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, (c)lear, or (o)ppenc mode?");
2185  /* L10N: S/MIME options (opportunistic encryption is off) */
2186  letters = _("eswabco");
2187  choices = "eswabcO";
2188  }
2189  /* Opportunistic encryption is unset */
2190  else
2191  {
2192  /* L10N: S/MIME options */
2193  prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear?");
2194  /* L10N: S/MIME options */
2195  letters = _("eswabc");
2196  choices = "eswabc";
2197  }
2198 
2199  choice = mutt_multi_choice(prompt, letters);
2200  if (choice > 0)
2201  {
2202  switch (choices[choice - 1])
2203  {
2204  case 'a': /* sign (a)s */
2205  key = smime_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN, false);
2206  if (key)
2207  {
2208  cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", key->hash, NULL);
2209  smime_key_free(&key);
2210 
2211  e->security |= SEC_SIGN;
2212 
2213  /* probably need a different passphrase */
2215  }
2216 
2217  break;
2218 
2219  case 'b': /* (b)oth */
2220  e->security |= (SEC_ENCRYPT | SEC_SIGN);
2221  break;
2222 
2223  case 'c': /* (c)lear */
2224  e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2225  break;
2226 
2227  case 'C':
2228  e->security &= ~SEC_SIGN;
2229  break;
2230 
2231  case 'e': /* (e)ncrypt */
2232  e->security |= SEC_ENCRYPT;
2233  e->security &= ~SEC_SIGN;
2234  break;
2235 
2236  case 'O': /* oppenc mode on */
2237  e->security |= SEC_OPPENCRYPT;
2239  break;
2240 
2241  case 'o': /* oppenc mode off */
2242  e->security &= ~SEC_OPPENCRYPT;
2243  break;
2244 
2245  case 'S': /* (s)ign in oppenc mode */
2246  e->security |= SEC_SIGN;
2247  break;
2248 
2249  case 's': /* (s)ign */
2250  e->security &= ~SEC_ENCRYPT;
2251  e->security |= SEC_SIGN;
2252  break;
2253 
2254  case 'w': /* encrypt (w)ith */
2255  {
2256  e->security |= SEC_ENCRYPT;
2257  do
2258  {
2259  struct Buffer errmsg = mutt_buffer_make(0);
2260  int rc = CSR_SUCCESS;
2261  switch (mutt_multi_choice(_("Choose algorithm family: (1) DES, (2) RC2, (3) AES, or (c)lear?"),
2262  // L10N: Options for: Choose algorithm family: (1) DES, (2) RC2, (3) AES, or (c)lear?
2263  _("123c")))
2264  {
2265  case 1:
2266  switch (choice = mutt_multi_choice(_("(1) DES, (2) Triple-DES?"),
2267  // L10N: Options for: (1) DES, (2) Triple-DES
2268  _("12")))
2269  {
2270  case 1:
2271  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2272  "des", &errmsg);
2273  break;
2274  case 2:
2275  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2276  "des3", &errmsg);
2277  break;
2278  }
2279  break;
2280 
2281  case 2:
2282  switch (choice = mutt_multi_choice(_("(1) RC2-40, (2) RC2-64, (3) RC2-128?"),
2283  // L10N: Options for: (1) RC2-40, (2) RC2-64, (3) RC2-128
2284  _("123")))
2285  {
2286  case 1:
2287  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2288  "rc2-40", &errmsg);
2289  break;
2290  case 2:
2291  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2292  "rc2-64", &errmsg);
2293  break;
2294  case 3:
2295  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2296  "rc2-128", &errmsg);
2297  break;
2298  }
2299  break;
2300 
2301  case 3:
2302  switch (choice = mutt_multi_choice(_("(1) AES128, (2) AES192, (3) AES256?"),
2303  // L10N: Options for: (1) AES128, (2) AES192, (3) AES256
2304  _("123")))
2305  {
2306  case 1:
2307  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2308  "aes128", &errmsg);
2309  break;
2310  case 2:
2311  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2312  "aes192", &errmsg);
2313  break;
2314  case 3:
2315  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2316  "aes256", &errmsg);
2317  break;
2318  }
2319  break;
2320 
2321  case 4:
2322  rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2323  NULL, &errmsg);
2324  /* (c)lear */
2325  /* fallthrough */
2326  case -1: /* Ctrl-G or Enter */
2327  choice = 0;
2328  break;
2329  }
2330 
2331  if ((CSR_RESULT(rc) != CSR_SUCCESS) && !mutt_buffer_is_empty(&errmsg))
2332  mutt_error("%s", mutt_buffer_string(&errmsg));
2333 
2334  mutt_buffer_dealloc(&errmsg);
2335  } while (choice == -1);
2336  break;
2337  }
2338  }
2339  }
2340 
2341  return e->security;
2342 }
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition: address.c:440
Email Address Handling.
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:297
bool mutt_addr_is_user(const struct Address *addr)
Does the address belong to the user.
Definition: alias.c:573
struct Buffer mutt_buffer_make(size_t size)
Make a new buffer on the stack.
Definition: buffer.c:61
void mutt_buffer_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition: buffer.c:265
bool mutt_buffer_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:252
size_t mutt_buffer_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:312
void mutt_buffer_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition: buffer.c:294
size_t mutt_buffer_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:356
char * mutt_buffer_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:432
int mutt_buffer_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition: buffer.c:160
void mutt_buffer_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:79
static const char * mutt_buffer_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:77
Convenience wrapper for the config headers.
int mutt_copy_message(FILE *fp_out, struct Email *e, struct Message *msg, CopyMessageFlags cmflags, CopyHeaderFlags chflags, int wraplen)
Copy a message from a Mailbox.
Definition: copy.c:864
Duplicate the structure of an entire email.
#define CH_NONEWLINE
Don't output terminating newline after the header.
Definition: copy.h:60
#define CH_WEED
Weed the headers?
Definition: copy.h:53
#define MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition: copy.h:46
#define CH_MIME
Ignore MIME fields.
Definition: copy.h:61
#define MUTT_CM_NO_FLAGS
No flags are set.
Definition: copy.h:35
#define MUTT_CM_DECODE_CRYPT
Definition: copy.h:48
#define CH_NO_FLAGS
No flags are set.
Definition: copy.h:51
Convenience wrapper for the core headers.
void crypt_current_time(struct State *s, const char *app_name)
Print the current time.
Definition: crypt.c:70
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1025
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:402
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:601
void crypt_convert_to_7bit(struct Body *a)
Convert an email to 7bit encoding.
Definition: crypt.c:795
Signing/encryption multiplexor.
void crypt_smime_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase()
Definition: cryptglue.c:413
Wrapper around crypto functions.
int mutt_get_field_unbuffered(const char *msg, struct Buffer *buf, CompletionFlags flags)
Ask the user for a string (ignoring macro buffer)
Definition: curs_lib.c:402
int mutt_buffer_get_field(const char *field, struct Buffer *buf, CompletionFlags complete, bool multiple, struct Mailbox *m, char ***files, int *numfiles)
Ask the user for a string.
Definition: curs_lib.c:337
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition: curs_lib.c:498
void mutt_endwin(void)
Shutdown curses.
Definition: curs_lib.c:465
time_t mutt_date_epoch(void)
Return the number of seconds since the Unix epoch.
Definition: date.c:427
time_t mutt_date_add_timeout(time_t now, time_t timeout)
Safely add a timeout to a given time_t value.
Definition: date.c:636
struct SmimeKey * dlg_select_smime_key(struct SmimeKey *keys, const char *query)
Get the user to select a key.
Definition: dlg_smime.c:194
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition: body.c:57
struct Body * mutt_body_new(void)
Create a new Body.
Definition: body.c:43
Structs that make up an email.
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:97
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition: file.c:260
int mutt_file_copy_bytes(FILE *fp_in, FILE *fp_out, size_t size)
Copy some content from one file to another.
Definition: file.c:230
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:152
char * mutt_file_read_line(char *line, size_t *size, FILE *fp, int *line_num, ReadLineFlags flags)
Read a line from a file.
Definition: file.c:720
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1569
void mutt_buffer_quote_filename(struct Buffer *buf, const char *filename, bool add_outer)
Quote a filename to survive the shell's quoting rules.
Definition: file.c:891
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:690
FILE * mutt_file_fopen(const char *path, const char *mode)
Call fopen() safely.
Definition: file.c:618
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition: file.c:194
#define mutt_file_mkstemp()
Definition: file.h:112
#define MUTT_RL_NO_FLAGS
No flags are set.
Definition: file.h:38
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition: filter.c:217
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr)
Run a command on a pipe (optionally connect stdin/stdout)
Definition: filter.c:61
Flags to control mutt_expando_format()
#define MUTT_FORMAT_NO_FLAGS
No flags are set.
Definition: format_flags.h:30
#define MUTT_FORMAT_OPTIONAL
Allow optional field processing.
Definition: format_flags.h:33
uint8_t MuttFormatFlags
Flags for mutt_expando_format(), e.g. MUTT_FORMAT_FORCESUBJ.
Definition: format_flags.h:29
int smime_class_application_handler(struct Body *m, struct State *s)
Implements CryptModuleSpecs::application_handler() -.
Definition: smime.c:2135
int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
Implements CryptModuleSpecs::decrypt_mime() -.
Definition: smime.c:2072
char * smime_class_find_keys(const struct AddressList *al, bool oppenc_mode)
Implements CryptModuleSpecs::find_keys() -.
Definition: smime.c:830
SecurityFlags smime_class_send_menu(struct Email *e)
Implements CryptModuleSpecs::send_menu() -.
Definition: smime.c:2154
struct Body * smime_class_sign_message(struct Body *a, const struct AddressList *from)
Implements CryptModuleSpecs::sign_message() -.
Definition: smime.c:1516
struct Body * smime_class_build_smime_entity(struct Body *a, char *certlist)
Implements CryptModuleSpecs::smime_build_smime_entity() -.
Definition: smime.c:1350
void smime_class_getkeys(struct Envelope *env)
Implements CryptModuleSpecs::smime_getkeys() -.
Definition: smime.c:789
void smime_class_invoke_import(const char *infile, const char *mailbox)
Implements CryptModuleSpecs::smime_invoke_import() -.
Definition: smime.c:1155
int smime_class_verify_sender(struct Email *e, struct Message *msg)
Implements CryptModuleSpecs::smime_verify_sender() -.
Definition: smime.c:1229
bool smime_class_valid_passphrase(void)
Implements CryptModuleSpecs::valid_passphrase() -.
Definition: smime.c:167
int smime_class_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
Implements CryptModuleSpecs::verify_one() -.
Definition: smime.c:1725
void smime_class_void_passphrase(void)
Implements CryptModuleSpecs::void_passphrase() -.
Definition: smime.c:158
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:776
static const char * smime_command_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 an SMIME command - Implements format_t -.
Definition: smime.c:215
int mutt_protected_headers_handler(struct Body *b, struct State *s)
Process a protected header - Implements handler_t -.
Definition: crypt.c:1095
#define mutt_error(...)
Definition: logging.h:87
#define mutt_message(...)
Definition: logging.h:86
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
Convenience wrapper for the gui headers.
void mutt_decode_attachment(struct Body *b, struct State *s)
Decode an email's attachment.
Definition: handler.c:1867
int mutt_body_handler(struct Body *b, struct State *s)
Handler for the Body of an email.
Definition: handler.c:1597
Decide how to display email content.
int mutt_write_mime_header(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:760
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition: helpers.c:169
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition: helpers.c:194
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition: helpers.c:73
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
#define FREE(x)
Definition: memory.h:40
static int search(struct Menu *menu, int op)
Search a menu.
Definition: functions.c:56
@ ENC_7BIT
7-bit text
Definition: mime.h:49
@ ENC_BASE64
Base-64 encoded text.
Definition: mime.h:52
@ TYPE_MULTIPART
Type: 'multipart/*'.
Definition: mime.h:37
@ TYPE_APPLICATION
Type: 'application/*'.
Definition: mime.h:33
@ DISP_ATTACH
Content is attached.
Definition: mime.h:63
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
void state_attach_puts(struct State *s, const char *t)
Write a string to the state.
Definition: state.c:100
#define MUTT_DISPLAY
Output is displayed to the user.
Definition: state.h:32
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:796
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:569
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:250
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:784
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:544
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:629
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition: string.c:239
Many unsorted constants and some structs.
#define MUTT_COMP_PASS
Password mode (no echo)
Definition: mutt.h:63
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:52
#define PATH_MAX
Definition: mutt.h:40
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
void mutt_buffer_expand_path(struct Buffer *buf)
Create the canonical path.
Definition: muttlib.c:321
Some miscellaneous functions.
#define mutt_buffer_mktemp(buf)
Definition: muttlib.h:74
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:74
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:86
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:125
#define SEC_SIGNOPAQUE
Email has an opaque signature (encrypted)
Definition: lib.h:83
#define SMIME_SIGN
Definition: lib.h:103
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:128
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:91
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:78
#define WithCrypto
Definition: lib.h:116
#define SEC_SIGN
Email is signed.
Definition: lib.h:79
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:127
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition: parameter.c:110
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1737
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1318
void mutt_buffer_pool_release(struct Buffer **pbuf)
Free a Buffer from the pool.
Definition: pool.c:112
struct Buffer * mutt_buffer_pool_get(void)
Get a Buffer from the pool.
Definition: pool.c:101
Ask the user a question.
int mutt_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question.
Definition: question.c:54
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:725
#define TAILQ_FIRST(head)
Definition: queue.h:723
#define TAILQ_EMPTY(head)
Definition: queue.h:721
int mutt_write_mime_body(struct Body *a, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:314
Convenience wrapper for the send headers.
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition: send.c:1458
#define CSR_RESULT(x)
Definition: set.h:52
#define CSR_SUCCESS
Action completed successfully.
Definition: set.h:35
GUI display the mailboxes in a side panel.
static struct SmimeKey * smime_copy_key(struct SmimeKey *key)
Copy an SMIME key.
Definition: smime.c:133
static struct Buffer SmimeIntermediateToUse
Definition: smime.c:82
static struct Body * smime_handle_entity(struct Body *m, struct State *s, FILE *fp_out_file)
Handle type application/pkcs7-mime.
Definition: smime.c:1837
static struct SmimeKey * smime_get_key_by_str(const char *str, KeyFlags abilities, bool only_public_key)
Find an SMIME key by string.
Definition: smime.c:671
static pid_t smime_invoke_sign(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
Use SMIME to sign a file.
Definition: smime.c:1334
char SmimePass[256]
Definition: smime.c:77
static char * smime_extract_certificate(const char *infile)
Extract an SMIME certificate from a file.
Definition: smime.c:972
time_t SmimeExpTime
Definition: smime.c:78
static void smime_command(char *buf, size_t buflen, struct SmimeCommandContext *cctx, const char *fmt)
Format an SMIME command string.
Definition: smime.c:371
static char * openssl_md_to_smime_micalg(const char *md)
Change the algorithm names.
Definition: smime.c:1493
static char * smime_extract_signer_certificate(const char *infile)
Extract the signer's certificate.
Definition: smime.c:1087
void smime_init(void)
Initialise smime globals.
Definition: smime.c:87
static pid_t smime_invoke_verify(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, int opaque)
Use SMIME to verify a file.
Definition: smime.c:1684
void smime_cleanup(void)
Clean up smime globals.
Definition: smime.c:97
static int smime_handle_cert_email(char *certificate, char *mailbox, bool copy, char ***buffer, int *num)
Process an email containing certificates.
Definition: smime.c:877
static pid_t smime_invoke_decrypt(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname)
Use SMIME to decrypt a file.
Definition: smime.c:1711
static struct SmimeKey * smime_get_key_by_addr(char *mailbox, KeyFlags abilities, bool only_public_key, bool oppenc_mode)
Find an SIME key by address.
Definition: smime.c:590
static struct Buffer SmimeKeyToUse
Definition: smime.c:80
static struct SmimeKey * smime_parse_key(char *buf)
Parse an SMIME key block.
Definition: smime.c:433
static struct Buffer SmimeCertToUse
Definition: smime.c:81
static struct SmimeKey * smime_ask_for_key(char *prompt, KeyFlags abilities, bool only_public_key)
Ask the user to select a key.
Definition: smime.c:717
static struct SmimeKey * smime_get_candidates(const char *search, bool only_public_key)
Find keys matching a string.
Definition: smime.c:516
static pid_t smime_invoke_encrypt(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *uids)
Use SMIME to encrypt a file.
Definition: smime.c:1307
static struct SmimeKey * smime_get_key_by_hash(const char *hash, bool only_public_key)
Find a key by its hash.
Definition: smime.c:564
static void smime_key_free(struct SmimeKey **keylist)
Free a list of SMIME keys.
Definition: smime.c:108
static void getkeys(char *mailbox)
Get the keys for a mailbox.
Definition: smime.c:754
static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd, const char *fname, const char *sig_fname, const char *cryptalg, const char *digestalg, const char *key, const char *certificates, const char *intermediates, const char *format)
Run an SMIME command.
Definition: smime.c:401
SMIME helper routines.
Key value store.
#define NONULL(x)
Definition: string2.h:37
#define STR_COMMAND
Enough space for a long command line.
Definition: string2.h:35
An email address.
Definition: address.h:36
char * mailbox
Mailbox and host address.
Definition: address.h:38
The body of an email.
Definition: body.h:36
char * d_filename
filename to be used for the content-disposition header If NULL, filename is used instead.
Definition: body.h:56
struct Body * parts
parts of a multipart or message/rfc822
Definition: body.h:72
LOFF_T offset
offset where the actual data begins
Definition: body.h:52
bool unlink
If true, filename should be unlink()ed before free()ing this structure.
Definition: body.h:67
bool badsig
Bad cryptographic signature (needed to check encrypted s/mime-signatures)
Definition: body.h:43
struct Envelope * mime_headers
Memory hole protected headers.
Definition: body.h:75
LOFF_T length
length (in bytes) of attachment
Definition: body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition: body.h:62
bool use_disp
Content-Disposition uses filename= ?
Definition: body.h:47
unsigned int disposition
content-disposition, ContentDisposition
Definition: body.h:42
struct Body * next
next attachment in the list
Definition: body.h:71
char * subtype
content-type subtype
Definition: body.h:60
unsigned int encoding
content-transfer-encoding, ContentEncoding
Definition: body.h:41
bool goodsig
Good cryptographic signature.
Definition: body.h:45
unsigned int type
content-type primary type, ContentType
Definition: body.h:40
char * filename
When sending a message, this is the file to which this structure refers.
Definition: body.h:58
String manipulation buffer.
Definition: buffer.h:34
char * data
Pointer to data.
Definition: buffer.h:35
The envelope/body of an email.
Definition: email.h:37
struct Envelope * env
Envelope information.
Definition: email.h:66
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition: email.h:41
The header of an Email.
Definition: envelope.h:57
struct AddressList to
Email's 'To' list.
Definition: envelope.h:60
struct AddressList cc
Email's 'Cc' list.
Definition: envelope.h:61
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
A local copy of an email.
Definition: mxapi.h:43
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39
Data for a SIME command.
Definition: smime.c:67
const char * sig_fname
s
Definition: smime.c:72
const char * intermediates
i
Definition: smime.c:74
const char * digestalg
d
Definition: smime.c:70
const char * cryptalg
a
Definition: smime.c:69
const char * key
k
Definition: smime.c:68
const char * fname
f
Definition: smime.c:71
const char * certificates
c
Definition: smime.c:73
An SIME key.
Definition: smime.h:44
KeyFlags flags
Definition: smime.h:50
char * hash
Definition: smime.h:46
struct SmimeKey * next
Definition: smime.h:51
char * issuer
Definition: smime.h:48
char * email
Definition: smime.h:45
char * label
Definition: smime.h:47
char trust
i=Invalid r=revoked e=expired u=unverified v=verified t=trusted
Definition: smime.h:49
Keep track when processing files.
Definition: state.h:46
StateFlags flags
Flags, e.g. MUTT_DISPLAY.
Definition: state.h:50
FILE * fp_out
File to write to.
Definition: state.h:48
char * prefix
String to add to the beginning of each output line.
Definition: state.h:49
FILE * fp_in
File to read from.
Definition: state.h:47
int cs_subset_str_string_set(const struct ConfigSubset *sub, const char *name, const char *value, struct Buffer *err)
Set a config item by string.
Definition: subset.c:408