NeoMutt  2025-12-11-1039-g550ac6
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
smime.c
Go to the documentation of this file.
1
27
33
34#include "config.h"
35#include <limits.h>
36#include <stdbool.h>
37#include <stdio.h>
38#include <string.h>
39#include <sys/types.h>
40#include <unistd.h>
41#include "private.h"
42#include "mutt/lib.h"
43#include "address/lib.h"
44#include "config/lib.h"
45#include "email/lib.h"
46#include "core/lib.h"
47#include "alias/lib.h"
48#include "gui/lib.h"
49#include "mutt.h"
50#include "lib.h"
51#include "editor/lib.h"
52#include "expando/lib.h"
53#include "history/lib.h"
54#include "question/lib.h"
55#include "send/lib.h"
56#include "crypt.h"
57#include "cryptglue.h"
58#include "expando_smime.h"
59#include "module_data.h"
60#include "mutt_logging.h"
61#ifdef CRYPT_BACKEND_CLASSIC_SMIME
62#include "smime.h"
63#endif
64
68void smime_init(void)
69{
71 buf_alloc(&mod_data->smime_key_to_use, 256);
72 buf_alloc(&mod_data->smime_cert_to_use, 256);
73 buf_alloc(&mod_data->smime_intermediate_to_use, 256);
74}
75
80void smime_cleanup(struct NcryptModuleData *mod_data)
81{
82 buf_dealloc(&mod_data->smime_key_to_use);
85}
86
91static void smime_key_free(struct SmimeKey **keylist)
92{
93 if (!keylist)
94 return;
95
96 struct SmimeKey *key = NULL;
97
98 while (*keylist)
99 {
100 key = *keylist;
101 *keylist = (*keylist)->next;
102
103 FREE(&key->email);
104 FREE(&key->hash);
105 FREE(&key->label);
106 FREE(&key->issuer);
107 FREE(&key);
108 }
109}
110
116static struct SmimeKey *smime_copy_key(struct SmimeKey *key)
117{
118 if (!key)
119 return NULL;
120
121 struct SmimeKey *copy = NULL;
122
123 copy = MUTT_MEM_CALLOC(1, struct SmimeKey);
124 copy->email = mutt_str_dup(key->email);
125 copy->hash = mutt_str_dup(key->hash);
126 copy->label = mutt_str_dup(key->label);
127 copy->issuer = mutt_str_dup(key->issuer);
128 copy->trust = key->trust;
129 copy->flags = key->flags;
130
131 return copy;
132}
133
138{
140 memset(mod_data->smime_pass, 0, sizeof(mod_data->smime_pass));
141 mod_data->smime_exp_time = 0;
142}
143
148{
150 const time_t now = mutt_date_now();
151 if (now < mod_data->smime_exp_time)
152 {
153 /* Use cached copy. */
154 return true;
155 }
156
158
159 struct Buffer *buf = buf_pool_get();
160 const int rc = mw_get_field(_("Enter S/MIME passphrase:"), buf,
162 mutt_str_copy(mod_data->smime_pass, buf_string(buf), sizeof(mod_data->smime_pass));
163 buf_pool_release(&buf);
164
165 if (rc == 0)
166 {
167 const short c_smime_timeout = cs_subset_number(NeoMutt->sub, "smime_timeout");
168 mod_data->smime_exp_time = mutt_date_add_timeout(now, c_smime_timeout);
169 return true;
170 }
171 else
172 {
173 mod_data->smime_exp_time = 0;
174 }
175
176 return false;
177}
178
185static void smime_command(struct Buffer *buf, struct SmimeCommandContext *cctx,
186 const struct Expando *exp)
187{
189 mutt_debug(LL_DEBUG2, "%s\n", buf_string(buf));
190}
191
214static pid_t smime_invoke(FILE **fp_smime_in, FILE **fp_smime_out, FILE **fp_smime_err,
215 int fp_smime_infd, int fp_smime_outfd, int fp_smime_errfd,
216 const char *fname, const char *sig_fname, const char *cryptalg,
217 const char *digestalg, const char *key, const char *certificates,
218 const char *intermediates, const struct Expando *exp)
219{
220 struct SmimeCommandContext cctx = { 0 };
221
222 if (!exp)
223 return (pid_t) -1;
224
225 cctx.fname = fname;
226 cctx.sig_fname = sig_fname;
227 cctx.key = key;
228 cctx.cryptalg = cryptalg;
229 cctx.digestalg = digestalg;
232
233 struct Buffer *cmd = buf_pool_get();
234 smime_command(cmd, &cctx, exp);
235
236 pid_t pid = filter_create_fd(buf_string(cmd), fp_smime_in, fp_smime_out,
237 fp_smime_err, fp_smime_infd, fp_smime_outfd,
238 fp_smime_errfd, NeoMutt->env);
239 buf_pool_release(&cmd);
240 return pid;
241}
242
249static struct SmimeKey *smime_parse_key(char *buf)
250{
251 char *pend = NULL;
252 char *p = NULL;
253 int field = 0;
254
255 struct SmimeKey *key = MUTT_MEM_CALLOC(1, struct SmimeKey);
256
257 for (p = buf; p; p = pend)
258 {
259 /* Some users manually maintain their .index file, and use a tab
260 * as a delimiter, which the old parsing code (using fscanf)
261 * happened to allow. smime_keys uses a space, so search for both. */
262 if ((pend = strchr(p, ' ')) || (pend = strchr(p, '\t')) || (pend = strchr(p, '\n')))
263 *pend++ = 0;
264
265 /* For backward compatibility, don't count consecutive delimiters
266 * as an empty field. */
267 if (*p == '\0')
268 continue;
269
270 field++;
271
272 switch (field)
273 {
274 case 1: /* mailbox */
275 key->email = mutt_str_dup(p);
276 break;
277 case 2: /* hash */
278 key->hash = mutt_str_dup(p);
279 break;
280 case 3: /* label */
281 key->label = mutt_str_dup(p);
282 break;
283 case 4: /* issuer */
284 key->issuer = mutt_str_dup(p);
285 break;
286 case 5: /* trust */
287 key->trust = *p;
288 break;
289 case 6: /* purpose */
290 while (*p)
291 {
292 switch (*p++)
293 {
294 case 'e':
296 break;
297
298 case 's':
299 key->flags |= KEYFLAG_CANSIGN;
300 break;
301
302 default:
303 break;
304 }
305 }
306 break;
307
308 default:
309 break;
310 }
311 }
312
313 /* Old index files could be missing issuer, trust, and purpose,
314 * but anything less than that is an error. */
315 if (field < 3)
316 {
317 smime_key_free(&key);
318 return NULL;
319 }
320
321 if (field < 4)
322 key->issuer = mutt_str_dup("?");
323
324 if (field < 5)
325 key->trust = 't';
326
327 if (field < 6)
329
330 return key;
331}
332
339static struct SmimeKey *smime_get_candidates(const char *search, bool only_public_key)
340{
341 char buf[1024] = { 0 };
342 struct SmimeKey *key = NULL;
343 struct SmimeKey *results = NULL;
344 struct SmimeKey **results_end = &results;
345
346 struct Buffer *index_file = buf_pool_get();
347 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
348 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
349 buf_printf(index_file, "%s/.index",
350 only_public_key ? NONULL(c_smime_certificates) : NONULL(c_smime_keys));
351
352 FILE *fp = mutt_file_fopen(buf_string(index_file), "r");
353 if (!fp)
354 {
355 mutt_perror("%s", buf_string(index_file));
356 buf_pool_release(&index_file);
357 return NULL;
358 }
359 buf_pool_release(&index_file);
360
361 while (fgets(buf, sizeof(buf), fp))
362 {
363 if (((*search == '\0')) || mutt_istr_find(buf, search))
364 {
365 key = smime_parse_key(buf);
366 if (key)
367 {
368 *results_end = key;
369 results_end = &key->next;
370 }
371 }
372 }
373
374 mutt_file_fclose(&fp);
375
376 return results;
377}
378
388static struct SmimeKey *smime_get_key_by_hash(const char *hash, bool only_public_key)
389{
390 struct SmimeKey *match = NULL;
391 struct SmimeKey *results = smime_get_candidates(hash, only_public_key);
392 for (struct SmimeKey *result = results; result; result = result->next)
393 {
394 if (mutt_istr_equal(hash, result->hash))
395 {
396 match = smime_copy_key(result);
397 break;
398 }
399 }
400
401 smime_key_free(&results);
402
403 return match;
404}
405
414static struct SmimeKey *smime_get_key_by_addr(const char *mailbox, KeyFlags abilities,
415 bool only_public_key, bool oppenc_mode)
416{
417 if (!mailbox)
418 return NULL;
419
420 struct SmimeKey *results = NULL;
421 struct SmimeKey *result = NULL;
422 struct SmimeKey *matches = NULL;
423 struct SmimeKey **matches_end = &matches;
424 struct SmimeKey *match = NULL;
425 struct SmimeKey *trusted_match = NULL;
426 struct SmimeKey *valid_match = NULL;
427 struct SmimeKey *return_key = NULL;
428 bool multi_trusted_matches = false;
429
430 results = smime_get_candidates(mailbox, only_public_key);
431 for (result = results; result; result = result->next)
432 {
433 if (abilities && !(result->flags & abilities))
434 {
435 continue;
436 }
437
438 if (mutt_istr_equal(mailbox, result->email))
439 {
440 match = smime_copy_key(result);
441 *matches_end = match;
442 matches_end = &match->next;
443
444 if (match->trust == 't')
445 {
446 if (trusted_match && !mutt_istr_equal(match->hash, trusted_match->hash))
447 {
448 multi_trusted_matches = true;
449 }
450 trusted_match = match;
451 }
452 else if ((match->trust == 'u') || (match->trust == 'v'))
453 {
454 valid_match = match;
455 }
456 }
457 }
458
459 smime_key_free(&results);
460
461 if (matches)
462 {
463 if (oppenc_mode || !isatty(STDIN_FILENO))
464 {
465 const bool c_crypt_opportunistic_encrypt_strong_keys =
466 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
467 if (trusted_match)
468 return_key = smime_copy_key(trusted_match);
469 else if (valid_match && !c_crypt_opportunistic_encrypt_strong_keys)
470 return_key = smime_copy_key(valid_match);
471 else
472 return_key = NULL;
473 }
474 else if (trusted_match && !multi_trusted_matches)
475 {
476 return_key = smime_copy_key(trusted_match);
477 }
478 else
479 {
480 return_key = smime_copy_key(dlg_smime(matches, mailbox));
481 }
482
483 smime_key_free(&matches);
484 }
485
486 return return_key;
487}
488
496static struct SmimeKey *smime_get_key_by_str(const char *str, KeyFlags abilities, bool only_public_key)
497{
498 if (!str)
499 return NULL;
500
501 struct SmimeKey *results = NULL;
502 struct SmimeKey *result = NULL;
503 struct SmimeKey *matches = NULL;
504 struct SmimeKey **matches_end = &matches;
505 struct SmimeKey *match = NULL;
506 struct SmimeKey *return_key = NULL;
507
508 results = smime_get_candidates(str, only_public_key);
509 for (result = results; result; result = result->next)
510 {
511 if (abilities && !(result->flags & abilities))
512 {
513 continue;
514 }
515
516 if (mutt_istr_equal(str, result->hash) ||
517 mutt_istr_find(result->email, str) || mutt_istr_find(result->label, str))
518 {
519 match = smime_copy_key(result);
520 *matches_end = match;
521 matches_end = &match->next;
522 }
523 }
524
525 smime_key_free(&results);
526
527 if (matches)
528 {
529 return_key = smime_copy_key(dlg_smime(matches, str));
530 smime_key_free(&matches);
531 }
532
533 return return_key;
534}
535
543static struct SmimeKey *smime_ask_for_key(const char *prompt, KeyFlags abilities, bool only_public_key)
544{
545 if (!prompt)
546 return NULL;
547
548 struct SmimeKey *key = NULL;
549 struct Buffer *resp = buf_pool_get();
550
552
553 while (true)
554 {
555 buf_reset(resp);
556 if (mw_get_field(prompt, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
557 {
558 goto done;
559 }
560
561 if (buf_is_empty(resp))
562 goto done;
563
564 key = smime_get_key_by_str(buf_string(resp), abilities, only_public_key);
565 if (key)
566 goto done;
567
568 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
569 }
570
571done:
572 buf_pool_release(&resp);
573 return key;
574}
575
583static void getkeys(const char *mailbox)
584{
586 const char *k = NULL;
587
588 struct SmimeKey *key = smime_get_key_by_addr(mailbox, KEYFLAG_CANENCRYPT, false, false);
589
590 if (!key)
591 {
592 struct Buffer *prompt = buf_pool_get();
593 buf_printf(prompt, _("Enter keyID for %s: "), mailbox);
594 key = smime_ask_for_key(buf_string(prompt), KEYFLAG_CANENCRYPT, false);
595 buf_pool_release(&prompt);
596 }
597
598 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
599 size_t smime_keys_len = mutt_str_len(c_smime_keys);
600
601 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
602 k = key ? key->hash : NONULL(c_smime_default_key);
603
604 /* if the key is different from last time */
605 if ((buf_len(&mod_data->smime_key_to_use) <= smime_keys_len) ||
606 !mutt_istr_equal(k, mod_data->smime_key_to_use.data + smime_keys_len + 1))
607 {
609 buf_printf(&mod_data->smime_key_to_use, "%s/%s", NONULL(c_smime_keys), k);
610 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
611 buf_printf(&mod_data->smime_cert_to_use, "%s/%s", NONULL(c_smime_certificates), k);
612 }
613
614 smime_key_free(&key);
615}
616
621{
623 const bool c_smime_decrypt_use_default_key = cs_subset_bool(NeoMutt->sub, "smime_decrypt_use_default_key");
624 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
625 if (c_smime_decrypt_use_default_key && c_smime_default_key)
626 {
627 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
628 buf_printf(&mod_data->smime_key_to_use, "%s/%s", NONULL(c_smime_keys), c_smime_default_key);
629 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
630 buf_printf(&mod_data->smime_cert_to_use, "%s/%s",
631 NONULL(c_smime_certificates), c_smime_default_key);
632 return;
633 }
634
635 struct Address *a = NULL;
636 TAILQ_FOREACH(a, &env->to, entries)
637 {
638 if (mutt_addr_is_user(a))
639 {
641 return;
642 }
643 }
644
645 TAILQ_FOREACH(a, &env->cc, entries)
646 {
647 if (mutt_addr_is_user(a))
648 {
650 return;
651 }
652 }
653
654 struct Address *f = mutt_default_from(NeoMutt->sub);
656 mutt_addr_free(&f);
657}
658
662char *smime_class_find_keys(const struct AddressList *al, bool oppenc_mode)
663{
664 struct SmimeKey *key = NULL;
665 char *keyid = NULL;
666 char *keylist = NULL;
667 size_t keylist_size = 0;
668 size_t keylist_used = 0;
669
670 struct Address *a = NULL;
671 TAILQ_FOREACH(a, al, entries)
672 {
673 key = smime_get_key_by_addr(buf_string(a->mailbox), KEYFLAG_CANENCRYPT, true, oppenc_mode);
674 if (!key && !oppenc_mode && isatty(STDIN_FILENO))
675 {
676 struct Buffer *prompt = buf_pool_get();
677 buf_printf(prompt, _("Enter keyID for %s: "), buf_string(a->mailbox));
678 key = smime_ask_for_key(buf_string(prompt), KEYFLAG_CANENCRYPT, true);
679 buf_pool_release(&prompt);
680 }
681 if (!key)
682 {
683 if (!oppenc_mode)
684 mutt_message(_("No (valid) certificate found for %s"), buf_string(a->mailbox));
685 FREE(&keylist);
686 return NULL;
687 }
688
689 keyid = key->hash;
690 keylist_size += mutt_str_len(keyid) + 2;
691 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
692 sprintf(keylist + keylist_used, "%s%s", keylist_used ? " " : "", keyid);
693 keylist_used = mutt_str_len(keylist);
694
695 smime_key_free(&key);
696 }
697 return keylist;
698}
699
711static int smime_handle_cert_email(const char *certificate, const char *mailbox,
712 bool copy, char ***buffer, int *num)
713{
714 char email[256] = { 0 };
715 int rc = -1;
716 int count = 0;
717 pid_t pid;
718
719 FILE *fp_err = mutt_file_mkstemp();
720 if (!fp_err)
721 {
722 mutt_perror(_("Can't create temporary file"));
723 return 1;
724 }
725
726 FILE *fp_out = mutt_file_mkstemp();
727 if (!fp_out)
728 {
729 mutt_file_fclose(&fp_err);
730 mutt_perror(_("Can't create temporary file"));
731 return 1;
732 }
733
734 const struct Expando *c_smime_get_cert_email_command =
735 cs_subset_expando(NeoMutt->sub, "smime_get_cert_email_command");
736 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), certificate,
737 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_get_cert_email_command);
738 if (pid == -1)
739 {
740 mutt_message(_("Error: unable to create OpenSSL subprocess"));
741 mutt_file_fclose(&fp_err);
742 mutt_file_fclose(&fp_out);
743 return 1;
744 }
745
746 filter_wait(pid);
747
748 fflush(fp_out);
749 fseek(fp_out, 0, SEEK_SET);
750 clearerr(fp_out);
751 fflush(fp_err);
752 fseek(fp_err, 0, SEEK_SET);
753 clearerr(fp_err);
754
755 while ((fgets(email, sizeof(email), fp_out)))
756 {
757 size_t len = mutt_str_len(email);
758 if (len && (email[len - 1] == '\n'))
759 email[len - 1] = '\0';
760 if (mutt_istr_startswith(email, mailbox))
761 rc = 1;
762
763 rc = (rc < 0) ? 0 : rc;
764 count++;
765 }
766
767 if (rc == -1)
768 {
769 mutt_endwin();
770 mutt_file_copy_stream(fp_err, stdout);
771 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
772 rc = 1;
773 }
774 else if (rc == 0)
775 {
776 rc = 1;
777 }
778 else
779 {
780 rc = 0;
781 }
782
783 if (copy && buffer && num)
784 {
785 (*num) = count;
786 *buffer = MUTT_MEM_CALLOC(count, char *);
787 count = 0;
788
789 fseek(fp_out, 0, SEEK_SET);
790 clearerr(fp_out);
791 while ((fgets(email, sizeof(email), fp_out)))
792 {
793 size_t len = mutt_str_len(email);
794 if (len && (email[len - 1] == '\n'))
795 email[len - 1] = '\0';
796 (*buffer)[count] = MUTT_MEM_CALLOC(mutt_str_len(email) + 1, char);
797 strncpy((*buffer)[count], email, mutt_str_len(email));
798 count++;
799 }
800 }
801 else if (copy)
802 {
803 rc = 2;
804 }
805
806 mutt_file_fclose(&fp_out);
807 mutt_file_fclose(&fp_err);
808
809 return rc;
810}
811
817static char *smime_extract_certificate(const char *infile)
818{
819 FILE *fp_err = NULL;
820 FILE *fp_out = NULL;
821 FILE *fp_cert = NULL;
822 char *rc = NULL;
823 pid_t pid;
824 int empty;
825
826 struct Buffer *pk7out = buf_pool_get();
827 struct Buffer *certfile = buf_pool_get();
828
829 fp_err = mutt_file_mkstemp();
830 if (!fp_err)
831 {
832 mutt_perror(_("Can't create temporary file"));
833 goto cleanup;
834 }
835
836 buf_mktemp(pk7out);
837 fp_out = mutt_file_fopen(buf_string(pk7out), "w+");
838 if (!fp_out)
839 {
840 mutt_perror("%s", buf_string(pk7out));
841 goto cleanup;
842 }
843
844 /* Step 1: Convert the signature to a PKCS#7 structure, as we can't
845 * extract the full set of certificates directly. */
846 const struct Expando *c_smime_pk7out_command = cs_subset_expando(NeoMutt->sub, "smime_pk7out_command");
847 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_out), fileno(fp_err), infile,
848 NULL, NULL, NULL, NULL, NULL, NULL, c_smime_pk7out_command);
849 if (pid == -1)
850 {
851 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
852 goto cleanup;
853 }
854
855 filter_wait(pid);
856
857 fflush(fp_out);
858 fseek(fp_out, 0, SEEK_SET);
859 clearerr(fp_out);
860 fflush(fp_err);
861 fseek(fp_err, 0, SEEK_SET);
862 clearerr(fp_err);
863 empty = (fgetc(fp_out) == EOF);
864 if (empty)
865 {
866 mutt_perror("%s", buf_string(pk7out));
867 mutt_file_copy_stream(fp_err, stdout);
868 goto cleanup;
869 }
870 mutt_file_fclose(&fp_out);
871
872 buf_mktemp(certfile);
873 fp_cert = mutt_file_fopen(buf_string(certfile), "w+");
874 if (!fp_cert)
875 {
876 mutt_perror("%s", buf_string(certfile));
878 goto cleanup;
879 }
880
881 // Step 2: Extract the certificates from a PKCS#7 structure.
882 const struct Expando *c_smime_get_cert_command = cs_subset_expando(NeoMutt->sub, "smime_get_cert_command");
883 pid = smime_invoke(NULL, NULL, NULL, -1, fileno(fp_cert), fileno(fp_err),
884 buf_string(pk7out), NULL, NULL, NULL, NULL, NULL, NULL,
885 c_smime_get_cert_command);
886 if (pid == -1)
887 {
888 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
890 goto cleanup;
891 }
892
893 filter_wait(pid);
894
896
897 fflush(fp_cert);
898 fseek(fp_cert, 0, SEEK_SET);
899 clearerr(fp_cert);
900 fflush(fp_err);
901 fseek(fp_err, 0, SEEK_SET);
902 clearerr(fp_err);
903 empty = (fgetc(fp_cert) == EOF);
904 if (empty)
905 {
906 mutt_file_copy_stream(fp_err, stdout);
907 goto cleanup;
908 }
909
910 mutt_file_fclose(&fp_cert);
911
912 rc = buf_strdup(certfile);
913
914cleanup:
915 mutt_file_fclose(&fp_err);
916 if (fp_out)
917 {
918 mutt_file_fclose(&fp_out);
920 }
921 if (fp_cert)
922 {
923 mutt_file_fclose(&fp_cert);
924 mutt_file_unlink(buf_string(certfile));
925 }
926 buf_pool_release(&pk7out);
927 buf_pool_release(&certfile);
928 return rc;
929}
930
936static char *smime_extract_signer_certificate(const char *infile)
937{
938 char *cert = NULL;
939 struct Buffer *certfile = NULL;
940 pid_t pid;
941 int empty;
942
943 FILE *fp_err = mutt_file_mkstemp();
944 if (!fp_err)
945 {
946 mutt_perror(_("Can't create temporary file"));
947 return NULL;
948 }
949
950 certfile = buf_pool_get();
951 buf_mktemp(certfile);
952 FILE *fp_out = mutt_file_fopen(buf_string(certfile), "w+");
953 if (!fp_out)
954 {
955 mutt_file_fclose(&fp_err);
956 mutt_perror("%s", buf_string(certfile));
957 goto cleanup;
958 }
959
960 /* Extract signer's certificate
961 */
962 const struct Expando *c_smime_get_signer_cert_command =
963 cs_subset_expando(NeoMutt->sub, "smime_get_signer_cert_command");
964 pid = smime_invoke(NULL, NULL, NULL, -1, -1, fileno(fp_err), infile, NULL, NULL, NULL,
965 NULL, buf_string(certfile), NULL, c_smime_get_signer_cert_command);
966 if (pid == -1)
967 {
968 mutt_any_key_to_continue(_("Error: unable to create OpenSSL subprocess"));
969 goto cleanup;
970 }
971
972 filter_wait(pid);
973
974 fflush(fp_out);
975 fseek(fp_out, 0, SEEK_SET);
976 clearerr(fp_out);
977 fflush(fp_err);
978 fseek(fp_err, 0, SEEK_SET);
979 clearerr(fp_err);
980 empty = (fgetc(fp_out) == EOF);
981 if (empty)
982 {
983 mutt_endwin();
984 mutt_file_copy_stream(fp_err, stdout);
986 goto cleanup;
987 }
988
989 mutt_file_fclose(&fp_out);
990 cert = buf_strdup(certfile);
991
992cleanup:
993 mutt_file_fclose(&fp_err);
994 if (fp_out)
995 {
996 mutt_file_fclose(&fp_out);
997 mutt_file_unlink(buf_string(certfile));
998 }
999 buf_pool_release(&certfile);
1000 return cert;
1001}
1002
1006void smime_class_invoke_import(const char *infile, const char *mailbox)
1007{
1008 char *certfile = NULL;
1009 struct Buffer *buf = NULL;
1010
1011 FILE *fp_out = NULL;
1012 FILE *fp_err = mutt_file_mkstemp();
1013 if (!fp_err)
1014 {
1015 mutt_perror(_("Can't create temporary file"));
1016 goto done;
1017 }
1018
1019 fp_out = mutt_file_mkstemp();
1020 if (!fp_out)
1021 {
1022 mutt_perror(_("Can't create temporary file"));
1023 goto done;
1024 }
1025
1026 buf = buf_pool_get();
1027 const bool c_smime_ask_cert_label = cs_subset_bool(NeoMutt->sub, "smime_ask_cert_label");
1028 if (c_smime_ask_cert_label)
1029 {
1030 if ((mw_get_field(_("Label for certificate: "), buf, MUTT_COMP_NONE,
1031 HC_OTHER, NULL, NULL) != 0) ||
1032 buf_is_empty(buf))
1033 {
1034 goto done;
1035 }
1036 }
1037
1038 mutt_endwin();
1039 certfile = smime_extract_certificate(infile);
1040 if (certfile)
1041 {
1042 mutt_endwin();
1043
1044 const struct Expando *c_smime_import_cert_command =
1045 cs_subset_expando(NeoMutt->sub, "smime_import_cert_command");
1046 FILE *fp_smime_in = NULL;
1047 pid_t pid = smime_invoke(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1048 fileno(fp_err), certfile, NULL, NULL, NULL, NULL,
1049 NULL, NULL, c_smime_import_cert_command);
1050 if (pid == -1)
1051 {
1052 mutt_message(_("Error: unable to create OpenSSL subprocess"));
1053 goto done;
1054 }
1055 fputs(buf_string(buf), fp_smime_in);
1056 fputc('\n', fp_smime_in);
1057 mutt_file_fclose(&fp_smime_in);
1058
1059 filter_wait(pid);
1060
1061 mutt_file_unlink(certfile);
1062 FREE(&certfile);
1063 }
1064
1065 fflush(fp_out);
1066 fseek(fp_out, 0, SEEK_SET);
1067 clearerr(fp_out);
1068 fflush(fp_err);
1069 fseek(fp_err, 0, SEEK_SET);
1070 clearerr(fp_err);
1071
1072 mutt_file_copy_stream(fp_out, stdout);
1073 mutt_file_copy_stream(fp_err, stdout);
1074
1075done:
1076 mutt_file_fclose(&fp_out);
1077 mutt_file_fclose(&fp_err);
1078 buf_pool_release(&buf);
1079}
1080
1084int smime_class_verify_sender(struct Email *e, struct Message *msg)
1085{
1086 const char *mbox = NULL;
1087 const char *certfile = NULL;
1088 int rc = 1;
1089
1090 struct Buffer *tempfname = buf_pool_get();
1091 buf_mktemp(tempfname);
1092 FILE *fp_out = mutt_file_fopen(buf_string(tempfname), "w");
1093 if (!fp_out)
1094 {
1095 mutt_perror("%s", buf_string(tempfname));
1096 goto cleanup;
1097 }
1098
1099 const bool encrypt = e->security & SEC_ENCRYPT;
1100 mutt_copy_message(fp_out, e, msg,
1102 encrypt ? (CH_MIME | CH_WEED | CH_NONEWLINE) : CH_NONE, 0);
1103
1104 fflush(fp_out);
1105 mutt_file_fclose(&fp_out);
1106
1107 if (!TAILQ_EMPTY(&e->env->from))
1108 {
1110 mbox = buf_string(TAILQ_FIRST(&e->env->from)->mailbox);
1111 }
1112 else if (!TAILQ_EMPTY(&e->env->sender))
1113 {
1115 mbox = buf_string(TAILQ_FIRST(&e->env->sender)->mailbox);
1116 }
1117
1118 if (mbox)
1119 {
1120 certfile = smime_extract_signer_certificate(buf_string(tempfname));
1121 if (certfile)
1122 {
1123 mutt_file_unlink(buf_string(tempfname));
1124 if (smime_handle_cert_email(certfile, mbox, false, NULL, NULL))
1125 {
1126 if (isendwin())
1128 }
1129 else
1130 {
1131 rc = 0;
1132 }
1133 mutt_file_unlink(certfile);
1134 FREE(&certfile);
1135 }
1136 else
1137 {
1138 mutt_any_key_to_continue(_("no certfile"));
1139 }
1140 }
1141 else
1142 {
1143 mutt_any_key_to_continue(_("no mbox"));
1144 }
1145
1146 mutt_file_unlink(buf_string(tempfname));
1147
1148cleanup:
1149 buf_pool_release(&tempfname);
1150 return rc;
1151}
1152
1169static pid_t smime_invoke_encrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1170 FILE **fp_smime_err, int fp_smime_infd,
1171 int fp_smime_outfd, int fp_smime_errfd,
1172 const char *fname, const char *uids)
1173{
1174 const char *const c_smime_encrypt_with = cs_subset_string(NeoMutt->sub, "smime_encrypt_with");
1175 const struct Expando *c_smime_encrypt_command = cs_subset_expando(NeoMutt->sub, "smime_encrypt_command");
1176 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1177 fp_smime_outfd, fp_smime_errfd, fname, NULL, c_smime_encrypt_with,
1178 NULL, NULL, uids, NULL, c_smime_encrypt_command);
1179}
1180
1196static pid_t smime_invoke_sign(FILE **fp_smime_in, FILE **fp_smime_out,
1197 FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1198 int fp_smime_errfd, const char *fname)
1199{
1201 const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1202 const struct Expando *c_smime_sign_command = cs_subset_expando(NeoMutt->sub, "smime_sign_command");
1203 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1204 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL,
1205 c_smime_sign_digest_alg, buf_string(&mod_data->smime_key_to_use),
1206 buf_string(&mod_data->smime_cert_to_use),
1207 buf_string(&mod_data->smime_intermediate_to_use), c_smime_sign_command);
1208}
1209
1213struct Body *smime_class_build_smime_entity(struct Body *b, char *certlist)
1214{
1215 char buf[1024] = { 0 };
1216 char certfile[PATH_MAX] = { 0 };
1217 char *cert_end = NULL;
1218 FILE *fp_smime_in = NULL;
1219 FILE *fp_smime_err = NULL;
1220 FILE *fp_out = NULL;
1221 FILE *fp_tmp = NULL;
1222 struct Body *b_enc = NULL;
1223 bool err = false;
1224 int empty;
1225 int off;
1226 pid_t pid;
1227
1228 struct Buffer *tempfile = buf_pool_get();
1229 struct Buffer *smime_infile = buf_pool_get();
1230
1231 buf_mktemp(tempfile);
1232 fp_out = mutt_file_fopen(buf_string(tempfile), "w+");
1233 if (!fp_out)
1234 {
1235 mutt_perror("%s", buf_string(tempfile));
1236 goto cleanup;
1237 }
1238
1239 fp_smime_err = mutt_file_mkstemp();
1240 if (!fp_smime_err)
1241 {
1242 mutt_perror(_("Can't create temporary file"));
1243 goto cleanup;
1244 }
1245
1246 buf_mktemp(smime_infile);
1247 fp_tmp = mutt_file_fopen(buf_string(smime_infile), "w+");
1248 if (!fp_tmp)
1249 {
1250 mutt_perror("%s", buf_string(smime_infile));
1251 goto cleanup;
1252 }
1253
1254 *certfile = '\0';
1255 for (char *cert_start = certlist; cert_start; cert_start = cert_end)
1256 {
1257 cert_end = strchr(cert_start, ' ');
1258 if (cert_end)
1259 *cert_end = '\0';
1260 if (*cert_start)
1261 {
1262 off = mutt_str_len(certfile);
1263 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
1264 snprintf(certfile + off, sizeof(certfile) - off, "%s%s/%s",
1265 (off != 0) ? " " : "", NONULL(c_smime_certificates), cert_start);
1266 }
1267 if (cert_end)
1268 *cert_end++ = ' ';
1269 }
1270
1271 /* write a MIME entity */
1272 mutt_write_mime_header(b, fp_tmp, NeoMutt->sub);
1273 fputc('\n', fp_tmp);
1274 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
1275 mutt_file_fclose(&fp_tmp);
1276
1277 pid = smime_invoke_encrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_out),
1278 fileno(fp_smime_err), buf_string(smime_infile), certfile);
1279 if (pid == -1)
1280 {
1281 mutt_file_unlink(buf_string(smime_infile));
1282 goto cleanup;
1283 }
1284
1285 mutt_file_fclose(&fp_smime_in);
1286
1287 filter_wait(pid);
1288 mutt_file_unlink(buf_string(smime_infile));
1289
1290 fflush(fp_out);
1291 fseek(fp_out, 0, SEEK_SET);
1292 clearerr(fp_out);
1293 empty = (fgetc(fp_out) == EOF);
1294 mutt_file_fclose(&fp_out);
1295
1296 fflush(fp_smime_err);
1297 fseek(fp_smime_err, 0, SEEK_SET);
1298 clearerr(fp_smime_err);
1299 while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1300 {
1301 err = true;
1302 fputs(buf, stdout);
1303 }
1304 mutt_file_fclose(&fp_smime_err);
1305
1306 /* pause if there is any error output from SMIME */
1307 if (err)
1309
1310 if (empty)
1311 {
1312 /* fatal error while trying to encrypt message */
1313 if (!err)
1314 mutt_any_key_to_continue(_("No output from OpenSSL..."));
1315 mutt_file_unlink(buf_string(tempfile));
1316 goto cleanup;
1317 }
1318
1319 b_enc = mutt_body_new();
1320 b_enc->type = TYPE_APPLICATION;
1321 b_enc->subtype = mutt_str_dup("pkcs7-mime");
1322 mutt_param_set(&b_enc->parameter, "name", "smime.p7m");
1323 mutt_param_set(&b_enc->parameter, "smime-type", "enveloped-data");
1324 b_enc->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1325 b_enc->use_disp = true;
1326 b_enc->disposition = DISP_ATTACH;
1327 b_enc->d_filename = mutt_str_dup("smime.p7m");
1328 b_enc->filename = buf_strdup(tempfile);
1329 b_enc->unlink = true; /* delete after sending the message */
1330 b_enc->parts = NULL;
1331 b_enc->next = NULL;
1332
1333cleanup:
1334 if (fp_out)
1335 {
1336 mutt_file_fclose(&fp_out);
1337 mutt_file_unlink(buf_string(tempfile));
1338 }
1339 mutt_file_fclose(&fp_smime_err);
1340 if (fp_tmp)
1341 {
1342 mutt_file_fclose(&fp_tmp);
1343 mutt_file_unlink(buf_string(smime_infile));
1344 }
1345 buf_pool_release(&tempfile);
1346 buf_pool_release(&smime_infile);
1347
1348 return b_enc;
1349}
1350
1363static char *openssl_md_to_smime_micalg(const char *md)
1364{
1365 if (!md)
1366 return NULL;
1367
1368 char *micalg = NULL;
1369 if (mutt_istr_startswith(md, "sha"))
1370 {
1371 mutt_str_asprintf(&micalg, "sha-%s", md + 3);
1372 }
1373 else
1374 {
1375 micalg = mutt_str_dup(md);
1376 }
1377
1378 return micalg;
1379}
1380
1384struct Body *smime_class_sign_message(struct Body *b, const struct AddressList *from)
1385{
1387 struct Body *b_sign = NULL;
1388 struct Body *rc = NULL;
1389 char buf[1024] = { 0 };
1390 struct Buffer *filetosign = NULL;
1391 struct Buffer *signedfile = NULL;
1392 FILE *fp_smime_in = NULL;
1393 FILE *fp_smime_out = NULL;
1394 FILE *fp_smime_err = NULL;
1395 FILE *fp_sign = NULL;
1396 bool err = false;
1397 int empty = 0;
1398 pid_t pid;
1399 const char *intermediates = NULL;
1400
1401 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
1402 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
1403 const char *signas = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
1404 if (!signas || (*signas == '\0'))
1405 {
1406 mutt_error(_("Can't sign: No key specified. Use Sign As."));
1407 return NULL;
1408 }
1409
1410 crypt_convert_to_7bit(b); /* Signed data _must_ be in 7-bit format. */
1411
1412 filetosign = buf_pool_get();
1413 signedfile = buf_pool_get();
1414
1415 buf_mktemp(filetosign);
1416 fp_sign = mutt_file_fopen(buf_string(filetosign), "w+");
1417 if (!fp_sign)
1418 {
1419 mutt_perror("%s", buf_string(filetosign));
1420 goto cleanup;
1421 }
1422
1423 buf_mktemp(signedfile);
1424 fp_smime_out = mutt_file_fopen(buf_string(signedfile), "w+");
1425 if (!fp_smime_out)
1426 {
1427 mutt_perror("%s", buf_string(signedfile));
1428 goto cleanup;
1429 }
1430
1431 mutt_write_mime_header(b, fp_sign, NeoMutt->sub);
1432 fputc('\n', fp_sign);
1433 mutt_write_mime_body(b, fp_sign, NeoMutt->sub);
1434 mutt_file_fclose(&fp_sign);
1435
1436 const char *const c_smime_keys = cs_subset_path(NeoMutt->sub, "smime_keys");
1437 const char *const c_smime_certificates = cs_subset_path(NeoMutt->sub, "smime_certificates");
1438 buf_printf(&mod_data->smime_key_to_use, "%s/%s", NONULL(c_smime_keys), signas);
1439 buf_printf(&mod_data->smime_cert_to_use, "%s/%s", NONULL(c_smime_certificates), signas);
1440
1441 struct SmimeKey *signas_key = smime_get_key_by_hash(signas, 1);
1442 if (!signas_key || mutt_str_equal("?", signas_key->issuer))
1443 intermediates = signas; /* so openssl won't complain in any case */
1444 else
1445 intermediates = signas_key->issuer;
1446
1447 buf_printf(&mod_data->smime_intermediate_to_use, "%s/%s",
1448 NONULL(c_smime_certificates), intermediates);
1449
1450 smime_key_free(&signas_key);
1451
1452 pid = smime_invoke_sign(&fp_smime_in, NULL, &fp_smime_err, -1,
1453 fileno(fp_smime_out), -1, buf_string(filetosign));
1454 if (pid == -1)
1455 {
1456 mutt_perror(_("Can't open OpenSSL subprocess"));
1457 mutt_file_unlink(buf_string(filetosign));
1458 goto cleanup;
1459 }
1460 fputs(mod_data->smime_pass, fp_smime_in);
1461 fputc('\n', fp_smime_in);
1462 mutt_file_fclose(&fp_smime_in);
1463
1464 filter_wait(pid);
1465
1466 /* check for errors from OpenSSL */
1467 err = false;
1468 fflush(fp_smime_err);
1469 fseek(fp_smime_err, 0, SEEK_SET);
1470 clearerr(fp_smime_err);
1471 while (fgets(buf, sizeof(buf) - 1, fp_smime_err))
1472 {
1473 err = true;
1474 fputs(buf, stdout);
1475 }
1476 mutt_file_fclose(&fp_smime_err);
1477
1478 fflush(fp_smime_out);
1479 fseek(fp_smime_out, 0, SEEK_SET);
1480 clearerr(fp_smime_out);
1481 empty = (fgetc(fp_smime_out) == EOF);
1482 mutt_file_fclose(&fp_smime_out);
1483
1484 mutt_file_unlink(buf_string(filetosign));
1485
1486 if (err)
1487 {
1490 }
1491
1492 if (empty)
1493 {
1494 mutt_any_key_to_continue(_("No output from OpenSSL..."));
1495 mutt_file_unlink(buf_string(signedfile));
1496 goto cleanup; /* fatal error while signing */
1497 }
1498
1499 b_sign = mutt_body_new();
1500 b_sign->type = TYPE_MULTIPART;
1501 b_sign->subtype = mutt_str_dup("signed");
1502 b_sign->encoding = ENC_7BIT;
1503 b_sign->use_disp = false;
1504 b_sign->disposition = DISP_INLINE;
1505
1507
1508 const char *const c_smime_sign_digest_alg = cs_subset_string(NeoMutt->sub, "smime_sign_digest_alg");
1509 char *micalg = openssl_md_to_smime_micalg(c_smime_sign_digest_alg);
1510 mutt_param_set(&b_sign->parameter, "micalg", micalg);
1511 FREE(&micalg);
1512
1513 mutt_param_set(&b_sign->parameter, "protocol", "application/pkcs7-signature");
1514
1515 b_sign->parts = b;
1516 rc = b_sign;
1517
1518 b_sign->parts->next = mutt_body_new();
1519 b_sign = b_sign->parts->next;
1520 b_sign->type = TYPE_APPLICATION;
1521 b_sign->subtype = mutt_str_dup("pkcs7-signature");
1522 b_sign->filename = buf_strdup(signedfile);
1523 b_sign->d_filename = mutt_str_dup("smime.p7s");
1524 b_sign->use_disp = true;
1525 b_sign->disposition = DISP_ATTACH;
1526 b_sign->encoding = ENC_BASE64;
1527 b_sign->unlink = true; /* ok to remove this file after sending. */
1528
1529cleanup:
1530 if (fp_sign)
1531 {
1532 mutt_file_fclose(&fp_sign);
1533 mutt_file_unlink(buf_string(filetosign));
1534 }
1535 if (fp_smime_out)
1536 {
1537 mutt_file_fclose(&fp_smime_out);
1538 mutt_file_unlink(buf_string(signedfile));
1539 }
1540 buf_pool_release(&filetosign);
1541 buf_pool_release(&signedfile);
1542 return rc;
1543}
1544
1562static pid_t smime_invoke_verify(FILE **fp_smime_in, FILE **fp_smime_out,
1563 FILE **fp_smime_err, int fp_smime_infd,
1564 int fp_smime_outfd, int fp_smime_errfd,
1565 const char *fname, const char *sig_fname, int opaque)
1566{
1567 const struct Expando *c_smime_verify_opaque_command =
1568 cs_subset_expando(NeoMutt->sub, "smime_verify_opaque_command");
1569 const struct Expando *c_smime_verify_command = cs_subset_expando(NeoMutt->sub, "smime_verify_command");
1570 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd, fp_smime_outfd,
1571 fp_smime_errfd, fname, sig_fname, NULL, NULL, NULL, NULL, NULL,
1572 (opaque ? c_smime_verify_opaque_command : c_smime_verify_command));
1573}
1574
1590static pid_t smime_invoke_decrypt(FILE **fp_smime_in, FILE **fp_smime_out,
1591 FILE **fp_smime_err, int fp_smime_infd, int fp_smime_outfd,
1592 int fp_smime_errfd, const char *fname)
1593{
1595 const struct Expando *c_smime_decrypt_command = cs_subset_expando(NeoMutt->sub, "smime_decrypt_command");
1596 return smime_invoke(fp_smime_in, fp_smime_out, fp_smime_err, fp_smime_infd,
1597 fp_smime_outfd, fp_smime_errfd, fname, NULL, NULL, NULL,
1598 buf_string(&mod_data->smime_key_to_use),
1599 buf_string(&mod_data->smime_cert_to_use), NULL,
1600 c_smime_decrypt_command);
1601}
1602
1606int smime_class_verify_one(struct Body *b, struct State *state, const char *tempfile)
1607{
1608 FILE *fp = NULL;
1609 FILE *fp_smime_out = NULL;
1610 FILE *fp_smime_err = NULL;
1611 pid_t pid;
1612 int badsig = -1;
1613
1614 LOFF_T tmpoffset = 0;
1615 size_t tmplength = 0;
1616 int orig_type = b->type;
1617
1618 struct Buffer *signedfile = buf_pool_get();
1619
1620 buf_printf(signedfile, "%s.sig", tempfile);
1621
1622 /* decode to a tempfile, saving the original destination */
1623 fp = state->fp_out;
1624 state->fp_out = mutt_file_fopen(buf_string(signedfile), "w");
1625 if (!state->fp_out)
1626 {
1627 mutt_perror("%s", buf_string(signedfile));
1628 goto cleanup;
1629 }
1630 /* decoding the attachment changes the size and offset, so save a copy
1631 * of the "real" values now, and restore them after processing */
1632 tmplength = b->length;
1633 tmpoffset = b->offset;
1634
1635 /* if we are decoding binary bodies, we don't want to prefix each
1636 * line with the prefix or else the data will get corrupted. */
1637 const char *save_prefix = state->prefix;
1638 state->prefix = NULL;
1639
1640 mutt_decode_attachment(b, state);
1641
1642 b->length = ftello(state->fp_out);
1643 b->offset = 0;
1644 mutt_file_fclose(&state->fp_out);
1645
1646 /* restore final destination and substitute the tempfile for input */
1647 state->fp_out = fp;
1648 fp = state->fp_in;
1649 state->fp_in = mutt_file_fopen(buf_string(signedfile), "r");
1650
1651 /* restore the prefix */
1652 state->prefix = save_prefix;
1653
1654 b->type = orig_type;
1655
1656 fp_smime_err = mutt_file_mkstemp();
1657 if (!fp_smime_err)
1658 {
1659 mutt_perror(_("Can't create temporary file"));
1660 goto cleanup;
1661 }
1662
1663 crypt_current_time(state, "OpenSSL");
1664
1665 pid = smime_invoke_verify(NULL, &fp_smime_out, NULL, -1, -1, fileno(fp_smime_err),
1666 tempfile, buf_string(signedfile), 0);
1667 if (pid != -1)
1668 {
1669 fflush(fp_smime_out);
1670 mutt_file_fclose(&fp_smime_out);
1671
1672 if (filter_wait(pid))
1673 {
1674 badsig = -1;
1675 }
1676 else
1677 {
1678 char *line = NULL;
1679 size_t linelen = 0;
1680
1681 fflush(fp_smime_err);
1682 fseek(fp_smime_err, 0, SEEK_SET);
1683 clearerr(fp_smime_err);
1684
1685 line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NONE);
1686 if (linelen && mutt_istr_equal(line, "verification successful"))
1687 badsig = 0;
1688
1689 FREE(&line);
1690 }
1691 }
1692
1693 fflush(fp_smime_err);
1694 fseek(fp_smime_err, 0, SEEK_SET);
1695 clearerr(fp_smime_err);
1696 mutt_file_copy_stream(fp_smime_err, state->fp_out);
1697 mutt_file_fclose(&fp_smime_err);
1698
1699 state_attach_puts(state, _("[-- End of OpenSSL output --]\n\n"));
1700
1701 mutt_file_unlink(buf_string(signedfile));
1702
1703 b->length = tmplength;
1704 b->offset = tmpoffset;
1705
1706 /* restore the original source stream */
1707 mutt_file_fclose(&state->fp_in);
1708 state->fp_in = fp;
1709
1710cleanup:
1711 buf_pool_release(&signedfile);
1712 return badsig;
1713}
1714
1724static struct Body *smime_handle_entity(struct Body *b, struct State *state, FILE *fp_out_file)
1725{
1727 struct Buffer *tmpfname = buf_pool_get();
1728 FILE *fp_smime_out = NULL;
1729 FILE *fp_smime_in = NULL;
1730 FILE *fp_smime_err = NULL;
1731 FILE *fp_tmp = NULL;
1732 FILE *fp_out = NULL;
1733 struct Body *p = NULL;
1734 pid_t pid = -1;
1736
1737 if (!(type & APPLICATION_SMIME))
1738 return NULL;
1739
1740 /* Because of the mutt_body_handler() we avoid the buffer pool. */
1741 fp_smime_out = mutt_file_mkstemp();
1742 if (!fp_smime_out)
1743 {
1744 mutt_perror(_("Can't create temporary file"));
1745 goto cleanup;
1746 }
1747
1748 fp_smime_err = mutt_file_mkstemp();
1749 if (!fp_smime_err)
1750 {
1751 mutt_perror(_("Can't create temporary file"));
1752 goto cleanup;
1753 }
1754
1755 buf_mktemp(tmpfname);
1756 fp_tmp = mutt_file_fopen(buf_string(tmpfname), "w+");
1757 if (!fp_tmp)
1758 {
1759 mutt_perror("%s", buf_string(tmpfname));
1760 goto cleanup;
1761 }
1762
1763 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
1764 {
1765 goto cleanup;
1766 }
1767
1768 mutt_file_copy_bytes(state->fp_in, fp_tmp, b->length);
1769
1770 fflush(fp_tmp);
1771 mutt_file_fclose(&fp_tmp);
1772
1773 if ((type & SEC_ENCRYPT) &&
1774 ((pid = smime_invoke_decrypt(&fp_smime_in, NULL, NULL, -1, fileno(fp_smime_out),
1775 fileno(fp_smime_err), buf_string(tmpfname))) == -1))
1776 {
1777 mutt_file_unlink(buf_string(tmpfname));
1778 if (state->flags & STATE_DISPLAY)
1779 {
1780 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1781 }
1782 goto cleanup;
1783 }
1784 else if ((type & SEC_SIGNOPAQUE) &&
1785 ((pid = smime_invoke_verify(&fp_smime_in, NULL, NULL, -1,
1786 fileno(fp_smime_out), fileno(fp_smime_err), NULL,
1787 buf_string(tmpfname), SEC_SIGNOPAQUE)) == -1))
1788 {
1789 mutt_file_unlink(buf_string(tmpfname));
1790 if (state->flags & STATE_DISPLAY)
1791 {
1792 state_attach_puts(state, _("[-- Error: unable to create OpenSSL subprocess --]\n"));
1793 }
1794 goto cleanup;
1795 }
1796
1797 if (type & SEC_ENCRYPT)
1798 {
1801 fputs(mod_data->smime_pass, fp_smime_in);
1802 fputc('\n', fp_smime_in);
1803 }
1804
1805 mutt_file_fclose(&fp_smime_in);
1806
1807 filter_wait(pid);
1808 mutt_file_unlink(buf_string(tmpfname));
1809
1810 if (state->flags & STATE_DISPLAY)
1811 {
1812 fflush(fp_smime_err);
1813 fseek(fp_smime_err, 0, SEEK_SET);
1814 clearerr(fp_smime_err);
1815
1816 const int c = fgetc(fp_smime_err);
1817 if (c != EOF)
1818 {
1819 ungetc(c, fp_smime_err);
1820
1821 crypt_current_time(state, "OpenSSL");
1822 mutt_file_copy_stream(fp_smime_err, state->fp_out);
1823 state_attach_puts(state, _("[-- End of OpenSSL output --]\n\n"));
1824 }
1825
1826 if (type & SEC_ENCRYPT)
1827 {
1828 state_attach_puts(state, _("[-- The following data is S/MIME encrypted --]\n"));
1829 }
1830 else
1831 {
1832 state_attach_puts(state, _("[-- The following data is S/MIME signed --]\n"));
1833 }
1834 }
1835
1836 fflush(fp_smime_out);
1837 fseek(fp_smime_out, 0, SEEK_SET);
1838 clearerr(fp_smime_out);
1839
1840 if (type & SEC_ENCRYPT)
1841 {
1842 /* void the passphrase, even if that wasn't the problem */
1843 if (fgetc(fp_smime_out) == EOF)
1844 {
1845 mutt_error(_("Decryption failed"));
1847 }
1848 fseek(fp_smime_out, 0, SEEK_SET);
1849 clearerr(fp_smime_out);
1850 }
1851
1852 if (fp_out_file)
1853 {
1854 fp_out = fp_out_file;
1855 }
1856 else
1857 {
1858 fp_out = mutt_file_mkstemp();
1859 if (!fp_out)
1860 {
1861 mutt_perror(_("Can't create temporary file"));
1862 goto cleanup;
1863 }
1864 }
1865 char buf[8192] = { 0 };
1866 while (fgets(buf, sizeof(buf) - 1, fp_smime_out))
1867 {
1868 const size_t len = mutt_str_len(buf);
1869 if ((len > 1) && (buf[len - 2] == '\r'))
1870 {
1871 buf[len - 2] = '\n';
1872 buf[len - 1] = '\0';
1873 }
1874 fputs(buf, fp_out);
1875 }
1876 fflush(fp_out);
1877 fseek(fp_out, 0, SEEK_SET);
1878 clearerr(fp_out);
1879
1880 const long size = mutt_file_get_size_fp(fp_out);
1881 if (size == 0)
1882 {
1883 goto cleanup;
1884 }
1885 p = mutt_read_mime_header(fp_out, 0);
1886 if (p)
1887 {
1888 p->length = size - p->offset;
1889
1890 mutt_parse_part(fp_out, p);
1891
1892 if (state->flags & STATE_DISPLAY)
1894
1895 /* Store any protected headers in the parent so they can be
1896 * accessed for index updates after the handler recursion is done.
1897 * This is done before the handler to prevent a nested encrypted
1898 * handler from freeing the headers. */
1900 b->mime_headers = p->mime_headers;
1901 p->mime_headers = NULL;
1902
1903 if (state->fp_out)
1904 {
1905 fseek(fp_out, 0, SEEK_SET);
1906 clearerr(fp_out);
1907 FILE *fp_tmp_buffer = state->fp_in;
1908 state->fp_in = fp_out;
1909 mutt_body_handler(p, state);
1910 state->fp_in = fp_tmp_buffer;
1911 }
1912
1913 /* Embedded multipart signed protected headers override the
1914 * encrypted headers. We need to do this after the handler so
1915 * they can be printed in the pager. */
1916 if (!(type & SMIME_SIGN) && mutt_is_multipart_signed(p) && p->parts &&
1917 p->parts->mime_headers)
1918 {
1921 p->parts->mime_headers = NULL;
1922 }
1923 }
1924 mutt_file_fclose(&fp_smime_out);
1925
1926 if (!fp_out_file)
1927 {
1928 mutt_file_fclose(&fp_out);
1929 mutt_file_unlink(buf_string(tmpfname));
1930 }
1931 fp_out = NULL;
1932
1933 if (state->flags & STATE_DISPLAY)
1934 {
1935 if (type & SEC_ENCRYPT)
1936 state_attach_puts(state, _("[-- End of S/MIME encrypted data --]\n"));
1937 else
1938 state_attach_puts(state, _("[-- End of S/MIME signed data --]\n"));
1939 }
1940
1941 if (type & SEC_SIGNOPAQUE)
1942 {
1943 char *line = NULL;
1944 size_t linelen = 0;
1945
1946 fseek(fp_smime_err, 0, SEEK_SET);
1947 clearerr(fp_smime_err);
1948
1949 line = mutt_file_read_line(line, &linelen, fp_smime_err, NULL, MUTT_RL_NONE);
1950 if (linelen && mutt_istr_equal(line, "verification successful"))
1951 b->goodsig = true;
1952 FREE(&line);
1953 }
1954 else if (p)
1955 {
1956 b->goodsig = p->goodsig;
1957 b->badsig = p->badsig;
1958 }
1959
1960cleanup:
1961 mutt_file_fclose(&fp_smime_out);
1962 mutt_file_fclose(&fp_smime_err);
1963 mutt_file_fclose(&fp_tmp);
1964 mutt_file_fclose(&fp_out);
1965 buf_pool_release(&tmpfname);
1966 return p;
1967}
1968
1972int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1973{
1974 struct State state = { 0 };
1975 LOFF_T tmpoffset = b->offset;
1976 size_t tmplength = b->length;
1977 int rc = -1;
1978
1980 return -1;
1981
1982 if (b->parts)
1983 return -1;
1984
1985 state.fp_in = fp_in;
1986 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
1987 {
1988 return -1;
1989 }
1990
1991 FILE *fp_tmp = mutt_file_mkstemp();
1992 if (!fp_tmp)
1993 {
1994 mutt_perror(_("Can't create temporary file"));
1995 return -1;
1996 }
1997
1998 state.fp_out = fp_tmp;
1999 mutt_decode_attachment(b, &state);
2000 fflush(fp_tmp);
2001 b->length = ftello(state.fp_out);
2002 b->offset = 0;
2003 fseek(fp_tmp, 0, SEEK_SET);
2004 clearerr(fp_tmp);
2005 state.fp_in = fp_tmp;
2006 state.fp_out = 0;
2007
2009 if (!*fp_out)
2010 {
2011 mutt_perror(_("Can't create temporary file"));
2012 goto bail;
2013 }
2014
2015 *b_dec = smime_handle_entity(b, &state, *fp_out);
2016 if (!*b_dec)
2017 goto bail;
2018
2019 (*b_dec)->goodsig = b->goodsig;
2020 (*b_dec)->badsig = b->badsig;
2021 rc = 0;
2022
2023bail:
2024 b->length = tmplength;
2025 b->offset = tmpoffset;
2026 mutt_file_fclose(&fp_tmp);
2027 if (*fp_out)
2028 {
2029 fseek(*fp_out, 0, SEEK_SET);
2030 clearerr(*fp_out);
2031 }
2032
2033 return rc;
2034}
2035
2039int smime_class_application_handler(struct Body *b, struct State *state)
2040{
2041 int rc = -1;
2042
2043 /* clear out any mime headers before the handler, so they can't be spoofed. */
2045
2046 struct Body *tattach = smime_handle_entity(b, state, NULL);
2047 if (tattach)
2048 {
2049 rc = 0;
2050 mutt_body_free(&tattach);
2051 }
2052 return rc;
2053}
2054
2059{
2060 struct SmimeKey *key = NULL;
2061 const char *prompt = NULL;
2062 const char *letters = NULL;
2063 const char *choices = NULL;
2064 int choice;
2065
2067 return e->security;
2068
2070
2071 /* Opportunistic encrypt is controlling encryption.
2072 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
2073 * letter choices for those. */
2074 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
2075 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
2076 {
2077 /* L10N: S/MIME options (opportunistic encryption is on) */
2078 prompt = _("S/MIME (s)ign, encrypt (w)ith, sign (a)s, (c)lear, or (o)ppenc mode off?");
2079 /* L10N: S/MIME options (opportunistic encryption is on) */
2080 letters = _("swaco");
2081 choices = "SwaCo";
2082 }
2083 else if (c_crypt_opportunistic_encrypt)
2084 {
2085 /* Opportunistic encryption option is set, but is toggled off
2086 * for this message. */
2087 /* L10N: S/MIME options (opportunistic encryption is off) */
2088 prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, (c)lear, or (o)ppenc mode?");
2089 /* L10N: S/MIME options (opportunistic encryption is off) */
2090 letters = _("eswabco");
2091 choices = "eswabcO";
2092 }
2093 else
2094 {
2095 /* Opportunistic encryption is unset */
2096 /* L10N: S/MIME options */
2097 prompt = _("S/MIME (e)ncrypt, (s)ign, encrypt (w)ith, sign (a)s, (b)oth, or (c)lear?");
2098 /* L10N: S/MIME options */
2099 letters = _("eswabc");
2100 choices = "eswabc";
2101 }
2102
2103 choice = mw_multi_choice(prompt, letters);
2104 if (choice > 0)
2105 {
2106 switch (choices[choice - 1])
2107 {
2108 case 'a': /* sign (a)s */
2109 key = smime_ask_for_key(_("Sign as: "), KEYFLAG_CANSIGN, false);
2110 if (key)
2111 {
2112 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", key->hash, NULL);
2113 smime_key_free(&key);
2114
2115 e->security |= SEC_SIGN;
2116
2117 /* probably need a different passphrase */
2119 }
2120
2121 break;
2122
2123 case 'b': /* (b)oth */
2124 e->security |= (SEC_ENCRYPT | SEC_SIGN);
2125 break;
2126
2127 case 'c': /* (c)lear */
2128 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2129 break;
2130
2131 case 'C':
2132 e->security &= ~SEC_SIGN;
2133 break;
2134
2135 case 'e': /* (e)ncrypt */
2136 e->security |= SEC_ENCRYPT;
2137 e->security &= ~SEC_SIGN;
2138 break;
2139
2140 case 'O': /* oppenc mode on */
2143 break;
2144
2145 case 'o': /* oppenc mode off */
2147 break;
2148
2149 case 'S': /* (s)ign in oppenc mode */
2150 e->security |= SEC_SIGN;
2151 break;
2152
2153 case 's': /* (s)ign */
2154 e->security &= ~SEC_ENCRYPT;
2155 e->security |= SEC_SIGN;
2156 break;
2157
2158 case 'w': /* encrypt (w)ith */
2159 {
2160 e->security |= SEC_ENCRYPT;
2161 do
2162 {
2163 struct Buffer *errmsg = buf_pool_get();
2164 int rc = CSR_SUCCESS;
2165 switch (mw_multi_choice(_("Choose algorithm family: (1) DES, (2) RC2, (3) AES, or (c)lear?"),
2166 // L10N: Options for: Choose algorithm family: (1) DES, (2) RC2, (3) AES, or (c)lear?
2167 _("123c")))
2168 {
2169 case 1:
2170 switch (choice = mw_multi_choice(_("(1) DES, (2) Triple-DES?"),
2171 // L10N: Options for: (1) DES, (2) Triple-DES
2172 _("12")))
2173 {
2174 case 1:
2175 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2176 "des", errmsg);
2177 break;
2178 case 2:
2179 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2180 "des3", errmsg);
2181 break;
2182 default:
2183 break;
2184 }
2185 break;
2186
2187 case 2:
2188 switch (choice = mw_multi_choice(_("(1) RC2-40, (2) RC2-64, (3) RC2-128?"),
2189 // L10N: Options for: (1) RC2-40, (2) RC2-64, (3) RC2-128
2190 _("123")))
2191 {
2192 case 1:
2193 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2194 "rc2-40", errmsg);
2195 break;
2196 case 2:
2197 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2198 "rc2-64", errmsg);
2199 break;
2200 case 3:
2201 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2202 "rc2-128", errmsg);
2203 break;
2204 default:
2205 break;
2206 }
2207 break;
2208
2209 case 3:
2210 switch (choice = mw_multi_choice(_("(1) AES128, (2) AES192, (3) AES256?"),
2211 // L10N: Options for: (1) AES128, (2) AES192, (3) AES256
2212 _("123")))
2213 {
2214 case 1:
2215 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2216 "aes128", errmsg);
2217 break;
2218 case 2:
2219 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2220 "aes192", errmsg);
2221 break;
2222 case 3:
2223 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with",
2224 "aes256", errmsg);
2225 break;
2226 default:
2227 break;
2228 }
2229 break;
2230
2231 case 4:
2232 rc = cs_subset_str_string_set(NeoMutt->sub, "smime_encrypt_with", NULL, errmsg);
2233 /* (c)lear */
2235
2236 case -1: /* Ctrl-G or Enter */
2237 choice = 0;
2238 break;
2239
2240 default:
2241 break;
2242 }
2243
2244 if ((CSR_RESULT(rc) != CSR_SUCCESS) && !buf_is_empty(errmsg))
2245 mutt_error("%s", buf_string(errmsg));
2246
2247 buf_pool_release(&errmsg);
2248 } while (choice == -1);
2249 break;
2250 }
2251
2252 default:
2253 break;
2254 }
2255 }
2256
2257 return e->security;
2258}
void mutt_addr_free(struct Address **ptr)
Free a single Address.
Definition address.c:463
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:601
int buf_printf(struct Buffer *buf, const char *fmt,...)
Format a string overwriting a Buffer.
Definition buffer.c:168
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition buffer.c:497
void buf_dealloc(struct Buffer *buf)
Release the memory allocated by a buffer.
Definition buffer.c:383
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition buffer.c:89
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition buffer.c:298
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition buffer.c:577
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:342
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition buffer.h:96
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition helpers.c:291
short cs_subset_number(const struct ConfigSubset *sub, const char *name)
Get a number config item by name.
Definition helpers.c:143
const char * cs_subset_path(const struct ConfigSubset *sub, const char *name)
Get a path config item by name.
Definition helpers.c:168
bool cs_subset_bool(const struct ConfigSubset *sub, const char *name)
Get a boolean config item by name.
Definition helpers.c:47
const struct Expando * cs_subset_expando(const struct ConfigSubset *sub, const char *name)
Get an Expando config item by name.
Convenience wrapper for the config headers.
#define CSR_RESULT(x)
Extract the result code from CSR_* flags.
Definition set.h:53
#define CSR_SUCCESS
Action completed successfully.
Definition set.h:33
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_email.c:920
@ MUTT_CM_DECODE_SMIME
Used for decoding S/MIME messages.
Definition copy_email.h:52
@ MUTT_CM_NONE
No flags are set.
Definition copy_email.h:41
#define MUTT_CM_DECODE_CRYPT
Combination flag for decoding any kind of cryptography (PGP or S/MIME).
Definition copy_email.h:58
@ CH_WEED
Weed the headers?
Definition copy_email.h:67
@ CH_MIME
Ignore MIME fields.
Definition copy_email.h:75
@ CH_NONE
No flags are set.
Definition copy_email.h:65
@ CH_NONEWLINE
Don't output terminating newline after the header.
Definition copy_email.h:74
Convenience wrapper for the core headers.
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition crypt.c:1052
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition crypt.c:409
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition crypt.c:610
void crypt_current_time(struct State *state, const char *app_name)
Print the current time.
Definition crypt.c:64
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition crypt.c:815
Signing/encryption multiplexor.
void crypt_smime_void_passphrase(void)
Wrapper for CryptModuleSpecs::void_passphrase().
Definition cryptglue.c:484
Wrapper around crypto functions.
int mutt_any_key_to_continue(const char *s)
Prompt the user to 'press any key' and wait.
Definition curs_lib.c:174
void mutt_endwin(void)
Shutdown curses.
Definition curs_lib.c:152
Edit a string.
@ MUTT_COMP_UNBUFFERED
Ignore macro buffer.
Definition wdata.h:49
@ MUTT_COMP_PASS
Password mode (no echo).
Definition wdata.h:48
@ MUTT_COMP_NONE
No flags are set.
Definition wdata.h:46
void mutt_body_free(struct Body **ptr)
Free a Body.
Definition body.c:58
struct Body * mutt_body_new(void)
Create a new Body.
Definition body.c:44
Structs that make up an email.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition parse.c:1982
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition parse.c:1517
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition envelope.c:125
int expando_render(const struct Expando *exp, const struct ExpandoRenderCallback *erc, void *data, MuttFormatFlags flags, int max_cols, struct Buffer *buf)
Render an Expando + data into a string.
Definition expando.c:161
Parse Expando string.
const struct ExpandoRenderCallback SmimeCommandRenderCallbacks[]
Callbacks for Smime Command Expandos.
Ncrypt Smime Expando definitions.
int mutt_file_copy_stream(FILE *fp_in, FILE *fp_out)
Copy the contents of one file into another.
Definition file.c:224
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:678
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:192
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition file.c:1433
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition file.c:648
void mutt_file_unlink(const char *s)
Delete a file, carefully.
Definition file.c:156
#define mutt_file_fclose(FP)
Definition file.h:144
#define mutt_file_fopen(PATH, MODE)
Definition file.h:143
@ MUTT_RL_NONE
No flags are set.
Definition file.h:43
int smime_class_application_handler(struct Body *b, struct State *state)
Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::applicat...
Definition smime.c:2039
int smime_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
Decrypt an encrypted MIME part - Implements CryptModuleSpecs::decrypt_mime() -.
Definition smime.c:1972
char * smime_class_find_keys(const struct AddressList *al, bool oppenc_mode)
Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
Definition smime.c:662
SecurityFlags smime_class_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
Definition smime.c:2058
struct Body * smime_class_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
Definition smime.c:1384
struct Body * smime_class_build_smime_entity(struct Body *b, char *certlist)
Encrypt the email body to all recipients - Implements CryptModuleSpecs::smime_build_smime_entity() -.
Definition smime.c:1213
void smime_class_getkeys(struct Envelope *env)
Get the S/MIME keys required to encrypt this email - Implements CryptModuleSpecs::smime_getkeys() -.
Definition smime.c:620
void smime_class_invoke_import(const char *infile, const char *mailbox)
Add a certificate and update index file (externally) - Implements CryptModuleSpecs::smime_invoke_impo...
Definition smime.c:1006
int smime_class_verify_sender(struct Email *e, struct Message *msg)
Does the sender match the certificate?
Definition smime.c:1084
bool smime_class_valid_passphrase(void)
Ensure we have a valid passphrase - Implements CryptModuleSpecs::valid_passphrase() -.
Definition smime.c:147
int smime_class_verify_one(struct Body *b, struct State *state, const char *tempfile)
Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
Definition smime.c:1606
void smime_class_void_passphrase(void)
Forget the cached passphrase - Implements CryptModuleSpecs::void_passphrase() -.
Definition smime.c:137
struct SmimeKey * dlg_smime(struct SmimeKey *keys, const char *query)
Get the user to select a key -.
Definition dlg_smime.c:195
int mw_get_field(const char *prompt, struct Buffer *buf, CompletionFlags complete, enum HistoryClass hclass, const struct CompleteOps *comp_api, void *cdata)
Ask the user for a string -.
Definition window.c:502
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition question.c:62
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition crypt.c:1124
#define mutt_error(...)
Definition logging2.h:94
#define mutt_message(...)
Definition logging2.h:93
#define mutt_debug(LEVEL,...)
Definition logging2.h:91
#define mutt_perror(...)
Definition logging2.h:95
Convenience wrapper for the gui headers.
int mutt_body_handler(struct Body *b, struct State *state)
Handler for the Body of an email.
Definition handler.c:1675
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition handler.c:1950
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition lib.h:61
@ LL_DEBUG2
Log at debug level 2.
Definition logging2.h:46
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:68
#define MUTT_MEM_CALLOC(n, type)
Definition memory.h:52
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition memory.h:55
static int search(struct Menu *menu, int op, int *match)
Search a menu.
Definition functions.c:59
@ 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
@ MODULE_ID_NCRYPT
ModuleNcrypt, Ncrypt
Definition module_api.h:82
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition multipart.c:93
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:896
time_t mutt_date_now(void)
Return the number of seconds since the Unix epoch.
Definition date.c:459
int filter_wait(pid_t pid)
Wait for the exit of a process and return its status.
Definition filter.c:231
pid_t filter_create_fd(const char *cmd, FILE **fp_in, FILE **fp_out, FILE **fp_err, int fdin, int fdout, int fderr, char **envlist)
Run a command on a pipe (optionally connect stdin/stdout).
Definition filter.c:62
Convenience wrapper for the library headers.
#define FALLTHROUGH
Definition lib.h:117
#define _(a)
Definition message.h:28
void state_attach_puts(struct State *state, const char *t)
Write a string to the state.
Definition state.c:104
@ STATE_DISPLAY
Output is displayed to the user.
Definition state.h:37
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition string.c:678
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition string.c:257
int mutt_str_asprintf(char **strp, const char *fmt,...)
Definition string.c:809
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition string.c:666
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case).
Definition string.c:528
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
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:587
size_t mutt_istr_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix, ignoring case.
Definition string.c:246
Many unsorted constants and some structs.
#define PATH_MAX
Definition mutt.h:49
void mutt_clear_error(void)
Clear the message line (bottom line of screen).
NeoMutt Logging.
API for encryption/signing of emails.
uint16_t SecurityFlags
Definition lib.h:104
@ SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition lib.h:100
@ SEC_SIGNOPAQUE
Email has an opaque signature (encrypted).
Definition lib.h:97
@ SEC_SIGN
Email is signed.
Definition lib.h:93
@ SEC_ENCRYPT
Email is encrypted.
Definition lib.h:92
uint16_t KeyFlags
Definition lib.h:159
#define SMIME_SIGN
Email is S/MIME signed.
Definition lib.h:119
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition lib.h:107
@ KEYFLAG_CANSIGN
Key is suitable for signing.
Definition lib.h:147
@ KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition lib.h:148
#define WithCrypto
Definition lib.h:132
Ncrypt private Module data.
Shared constants/structs that are private to libconn.
void * neomutt_get_module_data(struct NeoMutt *n, enum ModuleId id)
Get the private data for a Module.
Definition neomutt.c:666
void mutt_param_set(struct ParameterList *pl, const char *attribute, const char *value)
Set a Parameter.
Definition parameter.c:111
struct Buffer * buf_pool_get(void)
Get a Buffer from the pool.
Definition pool.c:91
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition pool.c:111
Ask the user a question.
#define TAILQ_FOREACH(var, head, field)
Definition queue.h:782
#define TAILQ_FIRST(head)
Definition queue.h:780
#define TAILQ_EMPTY(head)
Definition queue.h:778
@ MUTT_FORMAT_NONE
No flags are set.
Definition render.h:37
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition body.c:304
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition header.c:763
Convenience wrapper for the send headers.
struct Address * mutt_default_from(struct ConfigSubset *sub)
Get a default 'from' Address.
Definition send.c:1405
static struct SmimeKey * smime_get_key_by_hash(const char *hash, bool only_public_key)
Find a key by its hash.
Definition smime.c:388
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:1196
static void getkeys(const char *mailbox)
Get the keys for a mailbox.
Definition smime.c:583
static struct SmimeKey * smime_copy_key(struct SmimeKey *key)
Copy an SMIME key.
Definition smime.c:116
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:496
void smime_init(void)
Initialise smime globals.
Definition smime.c:68
void smime_cleanup(struct NcryptModuleData *mod_data)
Clean up smime globals.
Definition smime.c:80
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:1562
static char * smime_extract_signer_certificate(const char *infile)
Extract the signer's certificate.
Definition smime.c:936
static struct Body * smime_handle_entity(struct Body *b, struct State *state, FILE *fp_out_file)
Handle type application/pkcs7-mime.
Definition smime.c:1724
static struct SmimeKey * smime_parse_key(char *buf)
Parse an SMIME key block.
Definition smime.c:249
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:1590
static struct SmimeKey * smime_get_candidates(const char *search, bool only_public_key)
Find keys matching a string.
Definition smime.c:339
static char * smime_extract_certificate(const char *infile)
Extract an SMIME certificate from a file.
Definition smime.c:817
static int smime_handle_cert_email(const char *certificate, const char *mailbox, bool copy, char ***buffer, int *num)
Process an email containing certificates.
Definition smime.c:711
static struct SmimeKey * smime_get_key_by_addr(const char *mailbox, KeyFlags abilities, bool only_public_key, bool oppenc_mode)
Find an SIME key by address.
Definition smime.c:414
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 struct Expando *exp)
Run an SMIME command.
Definition smime.c:214
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:1169
static void smime_key_free(struct SmimeKey **keylist)
Free a list of SMIME keys.
Definition smime.c:91
static char * openssl_md_to_smime_micalg(const char *md)
Change the algorithm names.
Definition smime.c:1363
static void smime_command(struct Buffer *buf, struct SmimeCommandContext *cctx, const struct Expando *exp)
Format an SMIME command string.
Definition smime.c:185
static struct SmimeKey * smime_ask_for_key(const char *prompt, KeyFlags abilities, bool only_public_key)
Ask the user to select a key.
Definition smime.c:543
SMIME helper routines.
#define NONULL(x)
Definition string2.h:44
An email address.
Definition address.h:35
struct Buffer * mailbox
Mailbox and host address.
Definition address.h:37
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:73
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:68
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:76
LOFF_T length
length (in bytes) of attachment
Definition body.h:53
struct ParameterList parameter
Parameters of the content-type.
Definition body.h:63
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:72
char * subtype
content-type subtype
Definition body.h:61
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:59
String manipulation buffer.
Definition buffer.h:36
size_t dsize
Length of data.
Definition buffer.h:39
char * data
Pointer to data.
Definition buffer.h:37
The envelope/body of an email.
Definition email.h:39
struct Envelope * env
Envelope information.
Definition email.h:68
SecurityFlags security
bit 0-10: flags, bit 11,12: application, bit 13: traditional pgp See: ncrypt/lib.h pgplib....
Definition email.h:43
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
Parsed Expando trees.
Definition expando.h:41
A local copy of an email.
Definition message.h:34
Ncrypt private Module data.
Definition module_data.h:39
struct Buffer smime_cert_to_use
S/MIME certificate to use.
Definition module_data.h:59
char smime_pass[256]
Cached S/MIME Passphrase.
Definition module_data.h:56
time_t smime_exp_time
Unix time when smime_pass expires.
Definition module_data.h:57
struct Buffer smime_intermediate_to_use
S/MIME intermediate certificate to use.
Definition module_data.h:60
struct Buffer smime_key_to_use
S/MIME key to use.
Definition module_data.h:58
Container for Accounts, Notifications.
Definition neomutt.h:41
char ** env
Private copy of the environment variables.
Definition neomutt.h:57
struct ConfigSubset * sub
Inherited config items.
Definition neomutt.h:49
Data for a SIME command.
Definition smime.h:58
const char * sig_fname
s
Definition smime.h:63
const char * intermediates
i
Definition smime.h:65
const char * digestalg
d
Definition smime.h:61
const char * cryptalg
a
Definition smime.h:60
const char * key
k
Definition smime.h:59
const char * fname
f
Definition smime.h:62
const char * certificates
c
Definition smime.h:64
An SIME key.
Definition smime.h:43
KeyFlags flags
Key flags.
Definition smime.h:49
char * hash
Key hash.
Definition smime.h:45
struct SmimeKey * next
Linked list.
Definition smime.h:50
char * issuer
Key issuer.
Definition smime.h:47
char * email
Email address.
Definition smime.h:44
char * label
Key label.
Definition smime.h:46
char trust
i=Invalid r=revoked e=expired u=unverified v=verified t=trusted
Definition smime.h:48
Keep track when processing files.
Definition state.h:54
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition state.h:58
FILE * fp_out
File to write to.
Definition state.h:56
FILE * fp_in
File to read from.
Definition state.h:55
const char * prefix
String to add to the beginning of each output line.
Definition state.h:57
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:392
#define buf_mktemp(buf)
Definition tmp.h:33
#define mutt_file_mkstemp()
Definition tmp.h:36