NeoMutt  2025-01-09-117-gace867
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
crypt_gpgme.c
Go to the documentation of this file.
1
35#include "config.h"
36#include <errno.h>
37#include <gpg-error.h>
38#include <gpgme.h>
39#include <langinfo.h>
40#include <locale.h>
41#include <stdbool.h>
42#include <stdio.h>
43#include <string.h>
44#include <sys/types.h>
45#include <unistd.h>
46#include "private.h"
47#include "mutt/lib.h"
48#include "address/lib.h"
49#include "config/lib.h"
50#include "email/lib.h"
51#include "core/lib.h"
52#include "alias/lib.h"
53#include "gui/lib.h"
54#include "mutt.h"
55#include "crypt_gpgme.h"
56#include "lib.h"
57#include "attach/lib.h"
58#include "editor/lib.h"
59#include "history/lib.h"
60#include "question/lib.h"
61#include "send/lib.h"
62#include "crypt.h"
63#include "globals.h"
64#include "gpgme_functions.h"
65#include "handler.h"
66#include "hook.h"
67#include "mutt_logging.h"
68#ifdef USE_AUTOCRYPT
69#include "autocrypt/lib.h"
70#endif
71
72// clang-format off
73/* Values used for comparing addresses. */
74#define CRYPT_KV_VALID (1 << 0)
75#define CRYPT_KV_ADDR (1 << 1)
76#define CRYPT_KV_STRING (1 << 2)
77#define CRYPT_KV_STRONGID (1 << 3)
78#define CRYPT_KV_MATCH (CRYPT_KV_ADDR | CRYPT_KV_STRING)
79// clang-format on
80
85{
86 char *what;
87 char *dflt;
89};
90
92static struct CryptCache *IdDefaults = NULL;
94static gpgme_key_t SignatureKey = NULL;
96static char *CurrentSender = NULL;
97
98#define PKA_NOTATION_NAME "pka-address@gnupg.org"
99
100#define _LINE_COMPARE(_x, _y) line_compare(_x, sizeof(_x) - 1, _y)
101#define MESSAGE(_y) _LINE_COMPARE("MESSAGE-----", _y)
102#define SIGNED_MESSAGE(_y) _LINE_COMPARE("SIGNED MESSAGE-----", _y)
103#define PUBLIC_KEY_BLOCK(_y) _LINE_COMPARE("PUBLIC KEY BLOCK-----", _y)
104#define BEGIN_PGP_SIGNATURE(_y) \
105 _LINE_COMPARE("-----BEGIN PGP SIGNATURE-----", _y)
106
112static bool is_pka_notation(gpgme_sig_notation_t notation)
113{
114 return mutt_str_equal(notation->name, PKA_NOTATION_NAME);
115}
116
121static void redraw_if_needed(gpgme_ctx_t ctx)
122{
123 const char *s = gpgme_get_ctx_flag(ctx, "redraw");
124 if (!s /* flag not known */ || *s /* flag true */)
125 {
127 }
128}
129
138const char *crypt_keyid(struct CryptKeyInfo *k)
139{
140 const char *s = "????????";
141
142 if (k->kobj && k->kobj->subkeys)
143 {
144 s = k->kobj->subkeys->keyid;
145 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
146 if ((!c_pgp_long_ids) && (strlen(s) == 16))
147 {
148 /* Return only the short keyID. */
149 s += 8;
150 }
151 }
152
153 return s;
154}
155
163static const char *crypt_long_keyid(struct CryptKeyInfo *k)
164{
165 const char *s = "????????????????";
166
167 if (k->kobj && k->kobj->subkeys)
168 {
169 s = k->kobj->subkeys->keyid;
170 }
171
172 return s;
173}
174
180static const char *crypt_short_keyid(struct CryptKeyInfo *k)
181{
182 const char *s = "????????";
183
184 if (k->kobj && k->kobj->subkeys)
185 {
186 s = k->kobj->subkeys->keyid;
187 if (strlen(s) == 16)
188 s += 8;
189 }
190
191 return s;
192}
193
199static const char *crypt_fpr(struct CryptKeyInfo *k)
200{
201 const char *s = "";
202
203 if (k->kobj && k->kobj->subkeys)
204 s = k->kobj->subkeys->fpr;
205
206 return s;
207}
208
214const char *crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
215{
216 const char *s = "????????????????";
217
218 if (k->kobj && k->kobj->subkeys)
219 {
220 if (k->kobj->subkeys->fpr)
221 s = k->kobj->subkeys->fpr;
222 else
223 s = k->kobj->subkeys->keyid;
224 }
225
226 return s;
227}
228
235{
236 struct CryptKeyInfo *k = NULL;
237
238 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
239 k->kobj = key->kobj;
240 gpgme_key_ref(key->kobj);
241 k->idx = key->idx;
242 k->uid = key->uid;
243 k->flags = key->flags;
244 k->validity = key->validity;
245
246 return k;
247}
248
253static void crypt_key_free(struct CryptKeyInfo **keylist)
254{
255 if (!keylist)
256 return;
257
258 struct CryptKeyInfo *k = NULL;
259
260 while (*keylist)
261 {
262 k = *keylist;
263 *keylist = (*keylist)->next;
264
265 gpgme_key_unref(k->kobj);
266 FREE(&k);
267 }
268}
269
276{
277 if (!key)
278 return false;
279
280 bool is_strong = false;
281
282 if ((key->flags & KEYFLAG_ISX509))
283 return true;
284
285 switch (key->validity)
286 {
287 case GPGME_VALIDITY_MARGINAL:
288 case GPGME_VALIDITY_NEVER:
289 case GPGME_VALIDITY_UNDEFINED:
290 case GPGME_VALIDITY_UNKNOWN:
291 is_strong = false;
292 break;
293
294 case GPGME_VALIDITY_FULL:
295 case GPGME_VALIDITY_ULTIMATE:
296 is_strong = true;
297 break;
298 }
299
300 return is_strong;
301}
302
311{
312 if (!key)
313 return 0;
314
315 return !(key->flags & KEYFLAG_CANTUSE);
316}
317
328static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr,
329 struct CryptKeyInfo *key)
330{
331 int rc = 0;
332
333 if (crypt_id_is_valid(key))
334 rc |= CRYPT_KV_VALID;
335
336 if (crypt_id_is_strong(key))
337 rc |= CRYPT_KV_STRONGID;
338
339 if (addr && u_addr)
340 {
341 if (addr->mailbox && u_addr->mailbox && buf_istr_equal(addr->mailbox, u_addr->mailbox))
342 {
343 rc |= CRYPT_KV_ADDR;
344 }
345
346 if (addr->personal && u_addr->personal &&
347 buf_istr_equal(addr->personal, u_addr->personal))
348 {
349 rc |= CRYPT_KV_STRING;
350 }
351 }
352
353 return rc;
354}
355
361gpgme_ctx_t create_gpgme_context(bool for_smime)
362{
363 gpgme_ctx_t ctx = NULL;
364
365 gpgme_error_t err = gpgme_new(&ctx);
366
367#ifdef USE_AUTOCRYPT
368 const char *const c_autocrypt_dir = cs_subset_path(NeoMutt->sub, "autocrypt_dir");
369 if ((err == GPG_ERR_NO_ERROR) && OptAutocryptGpgme)
370 err = gpgme_ctx_set_engine_info(ctx, GPGME_PROTOCOL_OpenPGP, NULL, c_autocrypt_dir);
371#endif
372
373 if (err != GPG_ERR_NO_ERROR)
374 {
375 mutt_error(_("error creating GPGME context: %s"), gpgme_strerror(err));
376 mutt_exit(1);
377 }
378
379 if (for_smime)
380 {
381 err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
382 if (err != GPG_ERR_NO_ERROR)
383 {
384 mutt_error(_("error enabling CMS protocol: %s"), gpgme_strerror(err));
385 mutt_exit(1);
386 }
387 }
388
389 return ctx;
390}
391
400static gpgme_data_t create_gpgme_data(void)
401{
402 gpgme_data_t data = NULL;
403
404 gpgme_error_t err = gpgme_data_new(&data);
405 if (err != GPG_ERR_NO_ERROR)
406 {
407 mutt_error(_("error creating GPGME data object: %s"), gpgme_strerror(err));
408 mutt_exit(1);
409 }
410 return data;
411}
412
419static gpgme_data_t body_to_data_object(struct Body *b, bool convert)
420{
421 gpgme_error_t err = GPG_ERR_NO_ERROR;
422 gpgme_data_t data = NULL;
423
424 struct Buffer *tempfile = buf_pool_get();
425 buf_mktemp(tempfile);
426 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "w+");
427 if (!fp_tmp)
428 {
429 mutt_perror("%s", buf_string(tempfile));
430 goto cleanup;
431 }
432
434 fputc('\n', fp_tmp);
435 mutt_write_mime_body(b, fp_tmp, NeoMutt->sub);
436
437 if (convert)
438 {
439 int c, hadcr = 0;
440 unsigned char buf[1];
441
443 rewind(fp_tmp);
444 while ((c = fgetc(fp_tmp)) != EOF)
445 {
446 if (c == '\r')
447 {
448 hadcr = 1;
449 }
450 else
451 {
452 if ((c == '\n') && !hadcr)
453 {
454 buf[0] = '\r';
455 gpgme_data_write(data, buf, 1);
456 }
457
458 hadcr = 0;
459 }
460 /* FIXME: This is quite suboptimal */
461 buf[0] = c;
462 gpgme_data_write(data, buf, 1);
463 }
464 mutt_file_fclose(&fp_tmp);
465 gpgme_data_seek(data, 0, SEEK_SET);
466 }
467 else
468 {
469 mutt_file_fclose(&fp_tmp);
470 err = gpgme_data_new_from_file(&data, buf_string(tempfile), 1);
471 if (err != GPG_ERR_NO_ERROR)
472 {
473 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
474 gpgme_data_release(data);
475 data = NULL;
476 /* fall through to unlink the tempfile */
477 }
478 }
479 unlink(buf_string(tempfile));
480
481cleanup:
482 buf_pool_release(&tempfile);
483 return data;
484}
485
493static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
494{
495 gpgme_data_t data = NULL;
496
497 gpgme_error_t err = gpgme_data_new_from_filepart(&data, NULL, fp, offset, length);
498 if (err != GPG_ERR_NO_ERROR)
499 {
500 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
501 return NULL;
502 }
503
504 return data;
505}
506
514static int data_object_to_stream(gpgme_data_t data, FILE *fp)
515{
516 char buf[4096] = { 0 };
517 ssize_t nread;
518
519 gpgme_error_t err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ?
520 gpgme_error_from_errno(errno) :
521 GPG_ERR_NO_ERROR);
522 if (err != GPG_ERR_NO_ERROR)
523 {
524 mutt_error(_("error rewinding data object: %s"), gpgme_strerror(err));
525 return -1;
526 }
527
528 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
529 {
530 /* fixme: we are not really converting CRLF to LF but just
531 * skipping CR. Doing it correctly needs a more complex logic */
532 for (char *p = buf; nread; p++, nread--)
533 {
534 if (*p != '\r')
535 putc(*p, fp);
536 }
537
538 if (ferror(fp))
539 {
540 mutt_perror(_("[tempfile]"));
541 return -1;
542 }
543 }
544 if (nread == -1)
545 {
546 mutt_error(_("error reading data object: %s"), strerror(errno));
547 return -1;
548 }
549 return 0;
550}
551
563static char *data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
564{
565 ssize_t nread = 0;
566 char *rv = NULL;
567 struct Buffer *tempfile = buf_pool_get();
568
569 buf_mktemp(tempfile);
570
571 FILE *fp = mutt_file_fopen(buf_string(tempfile), "w+");
572 if (!fp)
573 {
574 mutt_perror(_("Can't create temporary file"));
575 goto cleanup;
576 }
577
578 gpgme_error_t err = ((gpgme_data_seek(data, 0, SEEK_SET) == -1) ?
579 gpgme_error_from_errno(errno) :
580 GPG_ERR_NO_ERROR);
581 if (err == GPG_ERR_NO_ERROR)
582 {
583 char buf[4096] = { 0 };
584
585 while ((nread = gpgme_data_read(data, buf, sizeof(buf))) > 0)
586 {
587 if (fwrite(buf, nread, 1, fp) != 1)
588 {
589 mutt_perror("%s", buf_string(tempfile));
590 mutt_file_fclose(&fp);
591 unlink(buf_string(tempfile));
592 goto cleanup;
593 }
594 }
595 }
596 if (fp_ret)
597 rewind(fp);
598 else
599 mutt_file_fclose(&fp);
600 if (nread == -1)
601 {
602 mutt_error(_("error reading data object: %s"), gpgme_strerror(err));
603 unlink(buf_string(tempfile));
604 mutt_file_fclose(&fp);
605 goto cleanup;
606 }
607 if (fp_ret)
608 *fp_ret = fp;
609 rv = buf_strdup(tempfile);
610
611cleanup:
612 buf_pool_release(&tempfile);
613 return rv;
614}
615
622static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
623{
624 unsigned int n = 0;
625
626 const char *s = keylist;
627 do
628 {
629 while (*s == ' ')
630 s++;
631 if (*s != '\0')
632 {
633 if (n == 0)
634 {
635 if (!use_smime)
636 buf_addstr(recpstring, "--\n");
637 }
638 else
639 {
640 buf_addch(recpstring, '\n');
641 }
642 n++;
643
644 while ((*s != '\0') && (*s != ' '))
645 buf_addch(recpstring, *s++);
646 }
647 } while (*s != '\0');
648}
649
658static bool set_signer_from_address(gpgme_ctx_t ctx, const char *address, bool for_smime)
659{
660 gpgme_key_t key = NULL;
661 gpgme_key_t key2 = NULL;
662
663 gpgme_ctx_t listctx = create_gpgme_context(for_smime);
664 gpgme_error_t err = gpgme_op_keylist_start(listctx, address, 1);
665 if (err == GPG_ERR_NO_ERROR)
666 err = gpgme_op_keylist_next(listctx, &key);
667 if (err != GPG_ERR_NO_ERROR)
668 {
669 gpgme_release(listctx);
670 mutt_error(_("secret key '%s' not found: %s"), address, gpgme_strerror(err));
671 return false;
672 }
673
674 char *fpr = "fpr1";
675 if (key->subkeys)
676 fpr = key->subkeys->fpr ? key->subkeys->fpr : key->subkeys->keyid;
677 while (gpgme_op_keylist_next(listctx, &key2) == 0)
678 {
679 char *fpr2 = "fpr2";
680 if (key2->subkeys)
681 fpr2 = key2->subkeys->fpr ? key2->subkeys->fpr : key2->subkeys->keyid;
682 if (!mutt_str_equal(fpr, fpr2))
683 {
684 gpgme_key_unref(key);
685 gpgme_key_unref(key2);
686 gpgme_release(listctx);
687 mutt_error(_("ambiguous specification of secret key '%s'"), address);
688 return false;
689 }
690 else
691 {
692 gpgme_key_unref(key2);
693 }
694 }
695 gpgme_op_keylist_end(listctx);
696 gpgme_release(listctx);
697
698 gpgme_signers_clear(ctx);
699 err = gpgme_signers_add(ctx, key);
700 gpgme_key_unref(key);
701 if (err != GPG_ERR_NO_ERROR)
702 {
703 mutt_error(_("error setting secret key '%s': %s"), address, gpgme_strerror(err));
704 return false;
705 }
706 return true;
707}
708
717static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
718{
719 const char *signid = NULL;
720
721 const char *const c_smime_sign_as = cs_subset_string(NeoMutt->sub, "smime_sign_as");
722 const char *const c_pgp_sign_as = cs_subset_string(NeoMutt->sub, "pgp_sign_as");
723 const char *const c_pgp_default_key = cs_subset_string(NeoMutt->sub, "pgp_default_key");
724 const char *const c_smime_default_key = cs_subset_string(NeoMutt->sub, "smime_default_key");
725 if (for_smime)
726 signid = c_smime_sign_as ? c_smime_sign_as : c_smime_default_key;
727#ifdef USE_AUTOCRYPT
728 else if (OptAutocryptGpgme)
729 signid = AutocryptSignAs;
730#endif
731 else
732 signid = c_pgp_sign_as ? c_pgp_sign_as : c_pgp_default_key;
733
734 /* Try getting the signing key from config entries */
735 if (signid && set_signer_from_address(ctx, signid, for_smime))
736 {
737 return 0;
738 }
739
740 /* Try getting the signing key from the From line */
741 if (al)
742 {
743 struct Address *a;
744 TAILQ_FOREACH(a, al, entries)
745 {
746 if (a->mailbox && set_signer_from_address(ctx, buf_string(a->mailbox), for_smime))
747 {
748 return 0;
749 }
750 }
751 }
752
753 return (!signid && !al) ? 0 : -1;
754}
755
761static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
762{
763 gpgme_error_t err = gpgme_sig_notation_add(ctx, PKA_NOTATION_NAME, CurrentSender, 0);
764 if (err != GPG_ERR_NO_ERROR)
765 {
766 mutt_error(_("error setting PKA signature notation: %s"), gpgme_strerror(err));
767 }
768
769 return err;
770}
771
781static char *encrypt_gpgme_object(gpgme_data_t plaintext, char *keylist, bool use_smime,
782 bool combined_signed, const struct AddressList *from)
783{
784 gpgme_error_t err = GPG_ERR_NO_ERROR;
785 gpgme_ctx_t ctx = NULL;
786 gpgme_data_t ciphertext = NULL;
787 char *outfile = NULL;
788
789 struct Buffer *recpstring = buf_pool_get();
790 create_recipient_string(keylist, recpstring, use_smime);
791 if (buf_is_empty(recpstring))
792 {
793 buf_pool_release(&recpstring);
794 return NULL;
795 }
796
797 ctx = create_gpgme_context(use_smime);
798 if (!use_smime)
799 gpgme_set_armor(ctx, 1);
800
801 ciphertext = create_gpgme_data();
802
803 if (combined_signed)
804 {
805 if (set_signer(ctx, from, use_smime))
806 goto cleanup;
807
808 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
809 if (c_crypt_use_pka)
810 {
811 err = set_pka_sig_notation(ctx);
812 if (err != GPG_ERR_NO_ERROR)
813 goto cleanup;
814 }
815
816 err = gpgme_op_encrypt_sign_ext(ctx, NULL, buf_string(recpstring),
817 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
818 }
819 else
820 {
821 err = gpgme_op_encrypt_ext(ctx, NULL, buf_string(recpstring),
822 GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, ciphertext);
823 }
824
825 redraw_if_needed(ctx);
826 if (err != GPG_ERR_NO_ERROR)
827 {
828 mutt_error(_("error encrypting data: %s"), gpgme_strerror(err));
829 goto cleanup;
830 }
831
832 outfile = data_object_to_tempfile(ciphertext, NULL);
833
834cleanup:
835 buf_pool_release(&recpstring);
836 gpgme_release(ctx);
837 gpgme_data_release(ciphertext);
838 return outfile;
839}
840
853static int get_micalg(gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
854{
855 gpgme_sign_result_t result = NULL;
856 const char *algorithm_name = NULL;
857
858 if (buflen < 5)
859 return -1;
860
861 *buf = '\0';
862 result = gpgme_op_sign_result(ctx);
863 if (result && result->signatures)
864 {
865 algorithm_name = gpgme_hash_algo_name(result->signatures->hash_algo);
866 if (algorithm_name)
867 {
868 if (use_smime)
869 {
870 /* convert GPGME raw hash name to RFC2633 format */
871 snprintf(buf, buflen, "%s", algorithm_name);
872 mutt_str_lower(buf);
873 }
874 else
875 {
876 /* convert GPGME raw hash name to RFC3156 format */
877 snprintf(buf, buflen, "pgp-%s", algorithm_name);
878 mutt_str_lower(buf + 4);
879 }
880 }
881 }
882
883 return (buf[0] != '\0') ? 0 : -1;
884}
885
891static void print_time(time_t t, struct State *state)
892{
893 char p[256] = { 0 };
894 mutt_date_localtime_format(p, sizeof(p), nl_langinfo(D_T_FMT), t);
895 state_puts(state, p);
896}
897
906static struct Body *sign_message(struct Body *b, const struct AddressList *from, bool use_smime)
907{
908 struct Body *b_sign = NULL;
909 char *sigfile = NULL;
910 gpgme_error_t err = GPG_ERR_NO_ERROR;
911 char buf[100] = { 0 };
912 gpgme_ctx_t ctx = NULL;
913 gpgme_data_t message = NULL, signature = NULL;
914 gpgme_sign_result_t sigres = NULL;
915
916 crypt_convert_to_7bit(b); /* Signed data _must_ be in 7-bit format. */
917
918 message = body_to_data_object(b, true);
919 if (!message)
920 return NULL;
921 signature = create_gpgme_data();
922
923 ctx = create_gpgme_context(use_smime);
924 if (!use_smime)
925 gpgme_set_armor(ctx, 1);
926
927 if (set_signer(ctx, from, use_smime))
928 {
929 gpgme_data_release(signature);
930 gpgme_data_release(message);
931 gpgme_release(ctx);
932 return NULL;
933 }
934
935 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
936 if (c_crypt_use_pka)
937 {
938 err = set_pka_sig_notation(ctx);
939 if (err != GPG_ERR_NO_ERROR)
940 {
941 gpgme_data_release(signature);
942 gpgme_data_release(message);
943 gpgme_release(ctx);
944 return NULL;
945 }
946 }
947
948 err = gpgme_op_sign(ctx, message, signature, GPGME_SIG_MODE_DETACH);
949 redraw_if_needed(ctx);
950 gpgme_data_release(message);
951 if (err != GPG_ERR_NO_ERROR)
952 {
953 gpgme_data_release(signature);
954 gpgme_release(ctx);
955 mutt_error(_("error signing data: %s"), gpgme_strerror(err));
956 return NULL;
957 }
958 /* Check for zero signatures generated. This can occur when $pgp_sign_as is
959 * unset and there is no default key specified in ~/.gnupg/gpg.conf */
960 sigres = gpgme_op_sign_result(ctx);
961 if (!sigres->signatures)
962 {
963 gpgme_data_release(signature);
964 gpgme_release(ctx);
965 mutt_error(_("$pgp_sign_as unset and no default key specified in ~/.gnupg/gpg.conf"));
966 return NULL;
967 }
968
969 sigfile = data_object_to_tempfile(signature, NULL);
970 gpgme_data_release(signature);
971 if (!sigfile)
972 {
973 gpgme_release(ctx);
974 return NULL;
975 }
976
977 b_sign = mutt_body_new();
978 b_sign->type = TYPE_MULTIPART;
979 b_sign->subtype = mutt_str_dup("signed");
980 b_sign->encoding = ENC_7BIT;
981 b_sign->use_disp = false;
982 b_sign->disposition = DISP_INLINE;
983
985 mutt_param_set(&b_sign->parameter, "protocol",
986 use_smime ? "application/pkcs7-signature" : "application/pgp-signature");
987 /* Get the micalg from GPGME. Old gpgme versions don't support this
988 * for S/MIME so we assume sha-1 in this case. */
989 if (get_micalg(ctx, use_smime, buf, sizeof(buf)) == 0)
990 mutt_param_set(&b_sign->parameter, "micalg", buf);
991 else if (use_smime)
992 mutt_param_set(&b_sign->parameter, "micalg", "sha1");
993 gpgme_release(ctx);
994
995 b_sign->parts = b;
996 b = b_sign;
997
998 b_sign->parts->next = mutt_body_new();
999 b_sign = b_sign->parts->next;
1000 b_sign->type = TYPE_APPLICATION;
1001 if (use_smime)
1002 {
1003 b_sign->subtype = mutt_str_dup("pkcs7-signature");
1004 mutt_param_set(&b_sign->parameter, "name", "smime.p7s");
1005 b_sign->encoding = ENC_BASE64;
1006 b_sign->use_disp = true;
1007 b_sign->disposition = DISP_ATTACH;
1008 b_sign->d_filename = mutt_str_dup("smime.p7s");
1009 }
1010 else
1011 {
1012 b_sign->subtype = mutt_str_dup("pgp-signature");
1013 mutt_param_set(&b_sign->parameter, "name", "signature.asc");
1014 b_sign->use_disp = false;
1015 b_sign->disposition = DISP_NONE;
1016 b_sign->encoding = ENC_7BIT;
1017 }
1018 b_sign->filename = sigfile;
1019 b_sign->unlink = true; /* ok to remove this file after sending. */
1020
1021 return b;
1022}
1023
1027struct Body *pgp_gpgme_sign_message(struct Body *b, const struct AddressList *from)
1028{
1029 return sign_message(b, from, false);
1030}
1031
1035struct Body *smime_gpgme_sign_message(struct Body *b, const struct AddressList *from)
1036{
1037 return sign_message(b, from, true);
1038}
1039
1043struct Body *pgp_gpgme_encrypt_message(struct Body *b, char *keylist, bool sign,
1044 const struct AddressList *from)
1045{
1046 if (sign)
1048 gpgme_data_t plaintext = body_to_data_object(b, false);
1049 if (!plaintext)
1050 return NULL;
1051
1052 char *outfile = encrypt_gpgme_object(plaintext, keylist, false, sign, from);
1053 gpgme_data_release(plaintext);
1054 if (!outfile)
1055 return NULL;
1056
1057 struct Body *b_enc = mutt_body_new();
1058 b_enc->type = TYPE_MULTIPART;
1059 b_enc->subtype = mutt_str_dup("encrypted");
1060 b_enc->encoding = ENC_7BIT;
1061 b_enc->use_disp = false;
1062 b_enc->disposition = DISP_INLINE;
1063
1065 mutt_param_set(&b_enc->parameter, "protocol", "application/pgp-encrypted");
1066
1067 b_enc->parts = mutt_body_new();
1068 b_enc->parts->type = TYPE_APPLICATION;
1069 b_enc->parts->subtype = mutt_str_dup("pgp-encrypted");
1070 b_enc->parts->encoding = ENC_7BIT;
1071
1072 b_enc->parts->next = mutt_body_new();
1073 b_enc->parts->next->type = TYPE_APPLICATION;
1074 b_enc->parts->next->subtype = mutt_str_dup("octet-stream");
1075 b_enc->parts->next->encoding = ENC_7BIT;
1076 b_enc->parts->next->filename = outfile;
1077 b_enc->parts->next->use_disp = true;
1078 b_enc->parts->next->disposition = DISP_ATTACH;
1079 b_enc->parts->next->unlink = true; /* delete after sending the message */
1080 b_enc->parts->next->d_filename = mutt_str_dup("msg.asc"); /* non pgp/mime
1081 can save */
1082
1083 return b_enc;
1084}
1085
1089struct Body *smime_gpgme_build_smime_entity(struct Body *b, char *keylist)
1090{
1091 /* OpenSSL converts line endings to crlf when encrypting. Some clients
1092 * depend on this for signed+encrypted messages: they do not convert line
1093 * endings between decrypting and checking the signature. */
1094 gpgme_data_t plaintext = body_to_data_object(b, true);
1095 if (!plaintext)
1096 return NULL;
1097
1098 char *outfile = encrypt_gpgme_object(plaintext, keylist, true, false, NULL);
1099 gpgme_data_release(plaintext);
1100 if (!outfile)
1101 return NULL;
1102
1103 struct Body *b_enc = mutt_body_new();
1104 b_enc->type = TYPE_APPLICATION;
1105 b_enc->subtype = mutt_str_dup("pkcs7-mime");
1106 mutt_param_set(&b_enc->parameter, "name", "smime.p7m");
1107 mutt_param_set(&b_enc->parameter, "smime-type", "enveloped-data");
1108 b_enc->encoding = ENC_BASE64; /* The output of OpenSSL SHOULD be binary */
1109 b_enc->use_disp = true;
1110 b_enc->disposition = DISP_ATTACH;
1111 b_enc->d_filename = mutt_str_dup("smime.p7m");
1112 b_enc->filename = outfile;
1113 b_enc->unlink = true; /* delete after sending the message */
1114 b_enc->parts = 0;
1115 b_enc->next = 0;
1116
1117 return b_enc;
1118}
1119
1133static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key,
1134 int idx, struct State *state, gpgme_signature_t sig)
1135{
1136 if (!key)
1137 return 1;
1138
1139 bool severe = false;
1140
1141 if ((sum & GPGME_SIGSUM_KEY_REVOKED))
1142 {
1143 state_puts(state, _("Warning: One of the keys has been revoked\n"));
1144 severe = true;
1145 }
1146
1147 if ((sum & GPGME_SIGSUM_KEY_EXPIRED))
1148 {
1149 time_t at = key->subkeys->expires ? key->subkeys->expires : 0;
1150 if (at)
1151 {
1152 state_puts(state, _("Warning: The key used to create the signature expired at: "));
1153 print_time(at, state);
1154 state_puts(state, "\n");
1155 }
1156 else
1157 {
1158 state_puts(state, _("Warning: At least one certification key has expired\n"));
1159 }
1160 }
1161
1162 if ((sum & GPGME_SIGSUM_SIG_EXPIRED))
1163 {
1164 gpgme_signature_t sig2 = NULL;
1165 unsigned int i;
1166
1167 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1168
1169 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1170 ; // do nothing
1171
1172 state_puts(state, _("Warning: The signature expired at: "));
1173 print_time(sig2 ? sig2->exp_timestamp : 0, state);
1174 state_puts(state, "\n");
1175 }
1176
1177 if ((sum & GPGME_SIGSUM_KEY_MISSING))
1178 {
1179 state_puts(state, _("Can't verify due to a missing key or certificate\n"));
1180 }
1181
1182 if ((sum & GPGME_SIGSUM_CRL_MISSING))
1183 {
1184 state_puts(state, _("The CRL is not available\n"));
1185 severe = true;
1186 }
1187
1188 if ((sum & GPGME_SIGSUM_CRL_TOO_OLD))
1189 {
1190 state_puts(state, _("Available CRL is too old\n"));
1191 severe = true;
1192 }
1193
1194 if ((sum & GPGME_SIGSUM_BAD_POLICY))
1195 state_puts(state, _("A policy requirement was not met\n"));
1196
1197 if ((sum & GPGME_SIGSUM_SYS_ERROR))
1198 {
1199 const char *t0 = NULL, *t1 = NULL;
1200 gpgme_verify_result_t result = NULL;
1201 gpgme_signature_t sig2 = NULL;
1202 unsigned int i;
1203
1204 state_puts(state, _("A system error occurred"));
1205
1206 /* Try to figure out some more detailed system error information. */
1207 result = gpgme_op_verify_result(ctx);
1208 for (sig2 = result->signatures, i = 0; sig2 && (i < idx); sig2 = sig2->next, i++)
1209 ; // do nothing
1210
1211 if (sig2)
1212 {
1213 t0 = "";
1214 t1 = sig2->wrong_key_usage ? "Wrong_Key_Usage" : "";
1215 }
1216
1217 if (t0 || t1)
1218 {
1219 state_puts(state, ": ");
1220 if (t0)
1221 state_puts(state, t0);
1222 if (t1 && !(t0 && (mutt_str_equal(t0, t1))))
1223 {
1224 if (t0)
1225 state_puts(state, ",");
1226 state_puts(state, t1);
1227 }
1228 }
1229 state_puts(state, "\n");
1230 }
1231
1232 const bool c_crypt_use_pka = cs_subset_bool(NeoMutt->sub, "crypt_use_pka");
1233 if (c_crypt_use_pka)
1234 {
1235 if ((sig->pka_trust == 1) && sig->pka_address)
1236 {
1237 state_puts(state, _("WARNING: PKA entry does not match signer's address: "));
1238 state_puts(state, sig->pka_address);
1239 state_puts(state, "\n");
1240 }
1241 else if ((sig->pka_trust == 2) && sig->pka_address)
1242 {
1243 state_puts(state, _("PKA verified signer's address is: "));
1244 state_puts(state, sig->pka_address);
1245 state_puts(state, "\n");
1246 }
1247 }
1248
1249 return severe;
1250}
1251
1257static void show_fingerprint(gpgme_key_t key, struct State *state)
1258{
1259 if (!key)
1260 return;
1261
1262 const char *prefix = _("Fingerprint: ");
1263
1264 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1265 if (!s)
1266 return;
1267 bool is_pgp = (key->protocol == GPGME_PROTOCOL_OpenPGP);
1268
1269 char *buf = MUTT_MEM_MALLOC(strlen(prefix) + strlen(s) * 4 + 2, char);
1270 strcpy(buf, prefix);
1271 char *p = buf + strlen(buf);
1272 if (is_pgp && (strlen(s) == 40))
1273 { /* PGP v4 style formatted. */
1274 for (int i = 0; *s && s[1] && s[2] && s[3] && s[4]; s += 4, i++)
1275 {
1276 *p++ = s[0];
1277 *p++ = s[1];
1278 *p++ = s[2];
1279 *p++ = s[3];
1280 *p++ = ' ';
1281 if (i == 4)
1282 *p++ = ' ';
1283 }
1284 }
1285 else
1286 {
1287 for (int i = 0; *s && s[1] && s[2]; s += 2, i++)
1288 {
1289 *p++ = s[0];
1290 *p++ = s[1];
1291 *p++ = is_pgp ? ' ' : ':';
1292 if (is_pgp && (i == 7))
1293 *p++ = ' ';
1294 }
1295 }
1296
1297 /* just in case print remaining odd digits */
1298 for (; *s; s++)
1299 *p++ = *s;
1300 *p++ = '\n';
1301 *p = '\0';
1302 state_puts(state, buf);
1303 FREE(&buf);
1304}
1305
1312static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *state)
1313{
1314 gpgme_signature_t sig = NULL;
1315 const char *txt = NULL;
1316
1317 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1318 if (result)
1319 for (sig = result->signatures; sig && (idx > 0); sig = sig->next, idx--)
1320 ; // do nothing
1321
1322 switch (sig ? sig->validity : 0)
1323 {
1324 case GPGME_VALIDITY_UNKNOWN:
1325 txt = _("WARNING: We have NO indication whether the key belongs to the person named as shown above\n");
1326 break;
1327 case GPGME_VALIDITY_UNDEFINED:
1328 break;
1329 case GPGME_VALIDITY_NEVER:
1330 txt = _("WARNING: The key does NOT BELONG to the person named as shown above\n");
1331 break;
1332 case GPGME_VALIDITY_MARGINAL:
1333 txt = _("WARNING: It is NOT certain that the key belongs to the person named as shown above\n");
1334 break;
1335 case GPGME_VALIDITY_FULL:
1336 case GPGME_VALIDITY_ULTIMATE:
1337 txt = NULL;
1338 break;
1339 }
1340 if (txt)
1341 state_puts(state, txt);
1342}
1343
1351static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig,
1352 gpgme_key_t key, struct State *state)
1353{
1354 int msgwid;
1355
1356 state_puts(state, msg);
1357 state_puts(state, " ");
1358 /* key is NULL when not present in the user's keyring */
1359 if (key)
1360 {
1361 bool aka = false;
1362 for (gpgme_user_id_t uids = key->uids; uids; uids = uids->next)
1363 {
1364 if (uids->revoked)
1365 continue;
1366 if (aka)
1367 {
1368 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("aka: ")) + 1;
1369 if (msgwid < 0)
1370 msgwid = 0;
1371 for (int i = 0; i < msgwid; i++)
1372 state_puts(state, " ");
1373 state_puts(state, _("aka: "));
1374 }
1375 state_puts(state, uids->uid);
1376 state_puts(state, "\n");
1377
1378 aka = true;
1379 }
1380 }
1381 else
1382 {
1383 if (sig->fpr)
1384 {
1385 state_puts(state, _("KeyID "));
1386 state_puts(state, sig->fpr);
1387 }
1388 else
1389 {
1390 /* L10N: You will see this message in place of "KeyID "
1391 if the S/MIME key has no ID. This is quite an error. */
1392 state_puts(state, _("no signature fingerprint available"));
1393 }
1394 state_puts(state, "\n");
1395 }
1396
1397 /* timestamp is 0 when verification failed.
1398 * "Jan 1 1970" is not the created date. */
1399 if (sig->timestamp)
1400 {
1401 msgwid = mutt_strwidth(msg) - mutt_strwidth(_("created: ")) + 1;
1402 if (msgwid < 0)
1403 msgwid = 0;
1404 for (int i = 0; i < msgwid; i++)
1405 state_puts(state, " ");
1406 state_puts(state, _("created: "));
1407 print_time(sig->timestamp, state);
1408 state_puts(state, "\n");
1409 }
1410}
1411
1417static void show_one_recipient(struct State *state, gpgme_recipient_t r)
1418{
1419 const char *algo = gpgme_pubkey_algo_name(r->pubkey_algo);
1420 if (!algo)
1421 algo = "?";
1422
1423 // L10N: Show the algorithm and key ID of the encryption recipients, e.g
1424 // Recipient: RSA key, ID 1111111111111111
1425 state_printf(state, _("Recipient: %s key, ID %s\n"), algo, r->keyid);
1426}
1427
1433static void show_encryption_info(struct State *state, gpgme_decrypt_result_t result)
1434{
1435 if (!cs_subset_bool(NeoMutt->sub, "crypt_encryption_info"))
1436 return;
1437
1438 state_attach_puts(state, _("[-- Begin encryption information --]\n"));
1439
1440 for (gpgme_recipient_t r = result->recipients; r; r = r->next)
1441 show_one_recipient(state, r);
1442
1443 state_attach_puts(state, _("[-- End encryption information --]\n\n"));
1444}
1445
1458static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
1459{
1460 const char *fpr = NULL;
1461 gpgme_key_t key = NULL;
1462 bool anybad = false, anywarn = false;
1463 gpgme_signature_t sig = NULL;
1464 gpgme_error_t err = GPG_ERR_NO_ERROR;
1465
1466 gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
1467 if (result)
1468 {
1469 /* FIXME: this code should use a static variable and remember
1470 * the current position in the list of signatures, IMHO.
1471 * -moritz. */
1472 int i;
1473 for (i = 0, sig = result->signatures; sig && (i < idx); i++, sig = sig->next)
1474 ; // do nothing
1475
1476 if (!sig)
1477 return -1; /* Signature not found. */
1478
1479 if (SignatureKey)
1480 {
1481 gpgme_key_unref(SignatureKey);
1482 SignatureKey = NULL;
1483 }
1484
1485 fpr = sig->fpr;
1486 const unsigned int sum = sig->summary;
1487
1488 if (gpg_err_code(sig->status) != GPG_ERR_NO_ERROR)
1489 anybad = true;
1490
1491 if (gpg_err_code(sig->status) != GPG_ERR_NO_PUBKEY)
1492 {
1493 err = gpgme_get_key(ctx, fpr, &key, 0); /* secret key? */
1494 if (err == GPG_ERR_NO_ERROR)
1495 {
1496 if (!SignatureKey)
1497 SignatureKey = key;
1498 }
1499 else
1500 {
1501 key = NULL; /* Old GPGME versions did not set KEY to NULL on
1502 error. Do it here to avoid a double free. */
1503 }
1504 }
1505 else
1506 {
1507 /* pubkey not present */
1508 }
1509
1510 if (!state || !state->fp_out || !(state->flags & STATE_DISPLAY))
1511 {
1512 ; /* No state information so no way to print anything. */
1513 }
1514 else if (err != GPG_ERR_NO_ERROR)
1515 {
1516 char buf[1024] = { 0 };
1517 snprintf(buf, sizeof(buf), _("Error getting key information for KeyID %s: %s\n"),
1518 fpr, gpgme_strerror(err));
1519 state_puts(state, buf);
1520 anybad = true;
1521 }
1522 else if ((sum & GPGME_SIGSUM_GREEN))
1523 {
1524 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1525 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1526 anywarn = true;
1527 show_one_sig_validity(ctx, idx, state);
1528 }
1529 else if ((sum & GPGME_SIGSUM_RED))
1530 {
1531 print_smime_keyinfo(_("*BAD* signature from:"), sig, key, state);
1532 show_sig_summary(sum, ctx, key, idx, state, sig);
1533 }
1534 else if (!anybad && key && (key->protocol == GPGME_PROTOCOL_OpenPGP))
1535 { /* We can't decide (yellow) but this is a PGP key with a good
1536 signature, so we display what a PGP user expects: The name,
1537 fingerprint and the key validity (which is neither fully or
1538 ultimate). */
1539 print_smime_keyinfo(_("Good signature from:"), sig, key, state);
1540 show_one_sig_validity(ctx, idx, state);
1541 show_fingerprint(key, state);
1542 if (show_sig_summary(sum, ctx, key, idx, state, sig))
1543 anywarn = true;
1544 }
1545 else /* can't decide (yellow) */
1546 {
1547 print_smime_keyinfo(_("Problem signature from:"), sig, key, state);
1548 /* 0 indicates no expiration */
1549 if (sig->exp_timestamp)
1550 {
1551 /* L10N: This is trying to match the width of the
1552 "Problem signature from:" translation just above. */
1553 state_puts(state, _(" expires: "));
1554 print_time(sig->exp_timestamp, state);
1555 state_puts(state, "\n");
1556 }
1557 show_sig_summary(sum, ctx, key, idx, state, sig);
1558 anywarn = true;
1559 }
1560
1561 if (key != SignatureKey)
1562 gpgme_key_unref(key);
1563 }
1564
1565 return anybad ? 1 : anywarn ? 2 : 0;
1566}
1567
1581static int verify_one(struct Body *b, struct State *state, const char *tempfile, bool is_smime)
1582{
1583 int badsig = -1;
1584 int anywarn = 0;
1585 gpgme_ctx_t ctx = NULL;
1586 gpgme_data_t message = NULL;
1587
1588 gpgme_data_t signature = file_to_data_object(state->fp_in, b->offset, b->length);
1589 if (!signature)
1590 return -1;
1591
1592 /* We need to tell GPGME about the encoding because the backend can't
1593 * auto-detect plain base-64 encoding which is used by S/MIME. */
1594 if (is_smime)
1595 gpgme_data_set_encoding(signature, GPGME_DATA_ENCODING_BASE64);
1596
1597 gpgme_error_t err = gpgme_data_new_from_file(&message, tempfile, 1);
1598 if (err != GPG_ERR_NO_ERROR)
1599 {
1600 gpgme_data_release(signature);
1601 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
1602 return -1;
1603 }
1604 ctx = create_gpgme_context(is_smime);
1605
1606 /* Note: We don't need a current time output because GPGME avoids
1607 * such an attack by separating the meta information from the data. */
1608 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1609
1610 err = gpgme_op_verify(ctx, signature, message, NULL);
1611 gpgme_data_release(message);
1612 gpgme_data_release(signature);
1613
1614 redraw_if_needed(ctx);
1615 if (err != GPG_ERR_NO_ERROR)
1616 {
1617 char buf[200] = { 0 };
1618
1619 snprintf(buf, sizeof(buf) - 1, _("Error: verification failed: %s\n"),
1620 gpgme_strerror(err));
1621 state_puts(state, buf);
1622 }
1623 else
1624 { /* Verification succeeded, see what the result is. */
1625 gpgme_verify_result_t verify_result = NULL;
1626
1627 if (SignatureKey)
1628 {
1629 gpgme_key_unref(SignatureKey);
1630 SignatureKey = NULL;
1631 }
1632
1633 verify_result = gpgme_op_verify_result(ctx);
1634 if (verify_result && verify_result->signatures)
1635 {
1636 bool anybad = false;
1637 int res;
1638 for (int idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1639 {
1640 if (res == 1)
1641 anybad = true;
1642 else if (res == 2)
1643 anywarn = 2;
1644 }
1645 if (!anybad)
1646 badsig = 0;
1647 }
1648 }
1649
1650 if (badsig == 0)
1651 {
1652 gpgme_verify_result_t result = NULL;
1653 gpgme_sig_notation_t notation = NULL;
1654 gpgme_signature_t sig = NULL;
1655
1656 result = gpgme_op_verify_result(ctx);
1657 if (result)
1658 {
1659 for (sig = result->signatures; sig; sig = sig->next)
1660 {
1661 int non_pka_notations = 0;
1662 for (notation = sig->notations; notation; notation = notation->next)
1663 if (!is_pka_notation(notation))
1664 non_pka_notations++;
1665
1666 if (non_pka_notations)
1667 {
1668 char buf[128] = { 0 };
1669 snprintf(buf, sizeof(buf),
1670 _("*** Begin Notation (signature by: %s) ***\n"), sig->fpr);
1671 state_puts(state, buf);
1672 for (notation = sig->notations; notation; notation = notation->next)
1673 {
1674 if (is_pka_notation(notation))
1675 continue;
1676
1677 if (notation->name)
1678 {
1679 state_puts(state, notation->name);
1680 state_puts(state, "=");
1681 }
1682 if (notation->value)
1683 {
1684 state_puts(state, notation->value);
1685 if (!(*notation->value && (notation->value[strlen(notation->value) - 1] == '\n')))
1686 state_puts(state, "\n");
1687 }
1688 }
1689 state_puts(state, _("*** End Notation ***\n"));
1690 }
1691 }
1692 }
1693 }
1694
1695 gpgme_release(ctx);
1696
1697 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1698 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
1699
1700 return badsig ? 1 : anywarn ? 2 : 0;
1701}
1702
1706int pgp_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
1707{
1708 return verify_one(b, state, tempfile, false);
1709}
1710
1714int smime_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
1715{
1716 return verify_one(b, state, tempfile, true);
1717}
1718
1732static struct Body *decrypt_part(struct Body *b, struct State *state,
1733 FILE *fp_out, bool is_smime, int *r_is_signed)
1734{
1735 if (!b || !state || !fp_out)
1736 return NULL;
1737
1738 struct Body *tattach = NULL;
1739 gpgme_error_t err = GPG_ERR_NO_ERROR;
1740 gpgme_data_t ciphertext = NULL, plaintext = NULL;
1741 gpgme_decrypt_result_t result = NULL;
1742 bool maybe_signed = false;
1743 bool anywarn = false;
1744 int sig_stat = 0;
1745
1746 if (r_is_signed)
1747 *r_is_signed = 0;
1748
1749 gpgme_ctx_t ctx = NULL;
1750restart:
1751 ctx = create_gpgme_context(is_smime);
1752
1753 if (b->length < 0)
1754 return NULL;
1755 /* Make a data object from the body, create context etc. */
1756 ciphertext = file_to_data_object(state->fp_in, b->offset, b->length);
1757 if (!ciphertext)
1758 goto cleanup;
1759 plaintext = create_gpgme_data();
1760
1761 /* Do the decryption or the verification in case of the S/MIME hack. */
1762 if ((!is_smime) || maybe_signed)
1763 {
1764 if (!is_smime)
1765 err = gpgme_op_decrypt_verify(ctx, ciphertext, plaintext);
1766 else if (maybe_signed)
1767 err = gpgme_op_verify(ctx, ciphertext, NULL, plaintext);
1768
1769 if (err == GPG_ERR_NO_ERROR)
1770 {
1771 /* Check whether signatures have been verified. */
1772 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
1773 if (verify_result->signatures)
1774 sig_stat = 1;
1775 }
1776 }
1777 else
1778 {
1779 err = gpgme_op_decrypt(ctx, ciphertext, plaintext);
1780 }
1781 gpgme_data_release(ciphertext);
1782 ciphertext = NULL;
1783
1784#ifdef USE_AUTOCRYPT
1785 // Abort right away and silently. Autocrypt will retry on the normal keyring.
1786 if (OptAutocryptGpgme && (err != GPG_ERR_NO_ERROR))
1787 goto cleanup;
1788#endif
1789
1790 const bool c_devel_security = cs_subset_bool(NeoMutt->sub, "devel_security");
1791
1792 result = gpgme_op_decrypt_result(ctx);
1793 if (c_devel_security && result && (state->flags & STATE_DISPLAY))
1794 show_encryption_info(state, result);
1795
1796 if (err != GPG_ERR_NO_ERROR)
1797 {
1798 if (is_smime && !maybe_signed && (gpg_err_code(err) == GPG_ERR_NO_DATA))
1799 {
1800 /* Check whether this might be a signed message despite what the mime
1801 * header told us. Retry then. gpgsm returns the error information
1802 * "unsupported Algorithm '?'" but GPGME will not store this unknown
1803 * algorithm, thus we test that it has not been set. */
1804 if (result && !result->unsupported_algorithm)
1805 {
1806 maybe_signed = true;
1807 gpgme_data_release(plaintext);
1808 plaintext = NULL;
1809 /* gpgsm ends the session after an error; restart it */
1810 gpgme_release(ctx);
1811 goto restart;
1812 }
1813 }
1814 redraw_if_needed(ctx);
1815 if ((state->flags & STATE_DISPLAY))
1816 {
1817 char buf[200] = { 0 };
1818
1819 snprintf(buf, sizeof(buf) - 1,
1820 _("[-- Error: decryption failed: %s --]\n\n"), gpgme_strerror(err));
1821 state_attach_puts(state, buf);
1822 }
1823 goto cleanup;
1824 }
1825 redraw_if_needed(ctx);
1826
1827 /* Read the output from GPGME, and make sure to change CRLF to LF,
1828 * otherwise read_mime_header has a hard time parsing the message. */
1829 if (data_object_to_stream(plaintext, fp_out))
1830 {
1831 goto cleanup;
1832 }
1833 gpgme_data_release(plaintext);
1834 plaintext = NULL;
1835
1836 if (sig_stat)
1837 {
1838 int res, idx;
1839 int anybad = 0;
1840
1841 if (r_is_signed)
1842 *r_is_signed = -1; /* A signature exists. */
1843
1844 if ((state->flags & STATE_DISPLAY))
1845 {
1846 state_attach_puts(state, _("[-- Begin signature information --]\n"));
1847 }
1848 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
1849 {
1850 if (res == 1)
1851 anybad = 1;
1852 else if (res == 2)
1853 anywarn = true;
1854 }
1855 if (!anybad && idx && r_is_signed && *r_is_signed)
1856 *r_is_signed = anywarn ? 2 : 1; /* Good signature. */
1857
1858 if ((state->flags & STATE_DISPLAY))
1859 {
1860 state_attach_puts(state, _("[-- End signature information --]\n\n"));
1861 }
1862 }
1863 gpgme_release(ctx);
1864 ctx = NULL;
1865
1866 fflush(fp_out);
1867 rewind(fp_out);
1868 const long size = mutt_file_get_size_fp(fp_out);
1869 if (size == 0)
1870 {
1871 goto cleanup;
1872 }
1873 tattach = mutt_read_mime_header(fp_out, 0);
1874 if (tattach)
1875 {
1876 /* Need to set the length of this body part. */
1877 tattach->length = size - tattach->offset;
1878
1879 tattach->warnsig = anywarn;
1880
1881 /* See if we need to recurse on this MIME part. */
1882 mutt_parse_part(fp_out, tattach);
1883 }
1884
1885cleanup:
1886 gpgme_data_release(ciphertext);
1887 gpgme_data_release(plaintext);
1888 gpgme_release(ctx);
1889
1890 return tattach;
1891}
1892
1896int pgp_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1897{
1898 struct State state = { 0 };
1899 struct Body *first_part = b;
1900 int is_signed = 0;
1901 bool need_decode = false;
1902 LOFF_T saved_offset = 0;
1903 size_t saved_length = 0;
1904 FILE *fp_decoded = NULL;
1905 int rc = 0;
1906
1907 first_part->goodsig = false;
1908 first_part->warnsig = false;
1909
1911 {
1912 b = b->parts->next;
1913 /* Some clients improperly encode the octetstream part. */
1914 if (b->encoding != ENC_7BIT)
1915 need_decode = true;
1916 }
1918 {
1919 b = b->parts->next->next;
1920 need_decode = true;
1921 }
1922 else
1923 {
1924 return -1;
1925 }
1926
1927 state.fp_in = fp_in;
1928
1929 if (need_decode)
1930 {
1931 saved_offset = b->offset;
1932 saved_length = b->length;
1933
1934 fp_decoded = mutt_file_mkstemp();
1935 if (!fp_decoded)
1936 {
1937 mutt_perror(_("Can't create temporary file"));
1938 return -1;
1939 }
1940
1941 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
1942 {
1943 rc = -1;
1944 goto bail;
1945 }
1946 state.fp_out = fp_decoded;
1947
1948 mutt_decode_attachment(b, &state);
1949
1950 fflush(fp_decoded);
1951 b->length = ftello(fp_decoded);
1952 b->offset = 0;
1953 rewind(fp_decoded);
1954 state.fp_in = fp_decoded;
1955 state.fp_out = 0;
1956 }
1957
1958 *fp_out = mutt_file_mkstemp();
1959 if (!*fp_out)
1960 {
1961 mutt_perror(_("Can't create temporary file"));
1962 rc = -1;
1963 goto bail;
1964 }
1965
1966 *b_dec = decrypt_part(b, &state, *fp_out, false, &is_signed);
1967 if (*b_dec)
1968 {
1969 rewind(*fp_out);
1970 if (is_signed > 0)
1971 first_part->goodsig = true;
1972 }
1973 else
1974 {
1975 rc = -1;
1976 mutt_file_fclose(fp_out);
1977 }
1978
1979bail:
1980 if (need_decode)
1981 {
1982 b->length = saved_length;
1983 b->offset = saved_offset;
1984 mutt_file_fclose(&fp_decoded);
1985 }
1986
1987 return rc;
1988}
1989
1993int smime_gpgme_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **b_dec)
1994{
1995 struct State state = { 0 };
1996 int is_signed;
1997 LOFF_T saved_b_offset;
1998 size_t saved_b_length;
1999
2001 return -1;
2002
2003 if (b->parts)
2004 return -1;
2005
2006 /* Decode the body - we need to pass binary CMS to the
2007 * backend. The backend allows for Base64 encoded data but it does
2008 * not allow for QP which I have seen in some messages. So better
2009 * do it here. */
2010 saved_b_offset = b->offset;
2011 saved_b_length = b->length;
2012 state.fp_in = fp_in;
2013 if (!mutt_file_seek(state.fp_in, b->offset, SEEK_SET))
2014 {
2015 return -1;
2016 }
2017 FILE *fp_tmp = mutt_file_mkstemp();
2018 if (!fp_tmp)
2019 {
2020 mutt_perror(_("Can't create temporary file"));
2021 return -1;
2022 }
2023
2024 state.fp_out = fp_tmp;
2025 mutt_decode_attachment(b, &state);
2026 fflush(fp_tmp);
2027 b->length = ftello(state.fp_out);
2028 b->offset = 0;
2029 rewind(fp_tmp);
2030
2031 memset(&state, 0, sizeof(state));
2032 state.fp_in = fp_tmp;
2033 state.fp_out = 0;
2035 if (!*fp_out)
2036 {
2037 mutt_perror(_("Can't create temporary file"));
2038 mutt_file_fclose(&fp_tmp);
2039 return -1;
2040 }
2041
2042 *b_dec = decrypt_part(b, &state, *fp_out, true, &is_signed);
2043 if (*b_dec)
2044 (*b_dec)->goodsig = is_signed > 0;
2045 b->length = saved_b_length;
2046 b->offset = saved_b_offset;
2047 mutt_file_fclose(&fp_tmp);
2048 rewind(*fp_out);
2049 if (*b_dec && !is_signed && !(*b_dec)->parts && mutt_is_application_smime(*b_dec))
2050 {
2051 /* Assume that this is a opaque signed s/mime message. This is an ugly way
2052 * of doing it but we have anyway a problem with arbitrary encoded S/MIME
2053 * messages: Only the outer part may be encrypted. The entire mime parsing
2054 * should be revamped, probably by keeping the temporary files so that we
2055 * don't need to decrypt them all the time. Inner parts of an encrypted
2056 * part can then point into this file and there won't ever be a need to
2057 * decrypt again. This needs a partial rewrite of the MIME engine. */
2058 struct Body *bb = *b_dec;
2059
2060 saved_b_offset = bb->offset;
2061 saved_b_length = bb->length;
2062 memset(&state, 0, sizeof(state));
2063 state.fp_in = *fp_out;
2064 if (!mutt_file_seek(state.fp_in, bb->offset, SEEK_SET))
2065 {
2066 return -1;
2067 }
2068 FILE *fp_tmp2 = mutt_file_mkstemp();
2069 if (!fp_tmp2)
2070 {
2071 mutt_perror(_("Can't create temporary file"));
2072 return -1;
2073 }
2074
2075 state.fp_out = fp_tmp2;
2076 mutt_decode_attachment(bb, &state);
2077 fflush(fp_tmp2);
2078 bb->length = ftello(state.fp_out);
2079 bb->offset = 0;
2080 rewind(fp_tmp2);
2081 mutt_file_fclose(fp_out);
2082
2083 memset(&state, 0, sizeof(state));
2084 state.fp_in = fp_tmp2;
2085 state.fp_out = 0;
2086 *fp_out = mutt_file_mkstemp();
2087 if (!*fp_out)
2088 {
2089 mutt_perror(_("Can't create temporary file"));
2090 return -1;
2091 }
2092
2093 struct Body *b_tmp = decrypt_part(bb, &state, *fp_out, true, &is_signed);
2094 if (b_tmp)
2095 b_tmp->goodsig = is_signed > 0;
2096 bb->length = saved_b_length;
2097 bb->offset = saved_b_offset;
2098 mutt_file_fclose(&fp_tmp2);
2099 rewind(*fp_out);
2100 mutt_body_free(b_dec);
2101 *b_dec = b_tmp;
2102 }
2103 return *b_dec ? 0 : -1;
2104}
2105
2113static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
2114{
2115 gpgme_ctx_t tmpctx = NULL;
2116 gpgme_key_t key = NULL;
2117 gpgme_user_id_t uid = NULL;
2118 gpgme_subkey_t subkey = NULL;
2119 const char *shortid = NULL;
2120 size_t len;
2121 char date[256] = { 0 };
2122 bool more;
2123 int rc = -1;
2124 time_t tt;
2125
2126 *fp = mutt_file_mkstemp();
2127 if (!*fp)
2128 {
2129 mutt_perror(_("Can't create temporary file"));
2130 return -1;
2131 }
2132
2133 tmpctx = create_gpgme_context(false);
2134
2135 gpgme_error_t err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2136 while (err == GPG_ERR_NO_ERROR)
2137 {
2138 err = gpgme_op_keylist_next(tmpctx, &key);
2139 if (err != GPG_ERR_NO_ERROR)
2140 break;
2141 uid = key->uids;
2142 subkey = key->subkeys;
2143 more = false;
2144 while (subkey)
2145 {
2146 shortid = subkey->keyid;
2147 len = mutt_str_len(subkey->keyid);
2148 if (len > 8)
2149 shortid += len - 8;
2150 tt = subkey->timestamp;
2151 mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2152
2153 fprintf(*fp, "%s %5.5s %u/%8s %s\n", more ? "sub" : "pub",
2154 gpgme_pubkey_algo_name(subkey->pubkey_algo), subkey->length, shortid, date);
2155 if (!more)
2156 {
2157 while (uid)
2158 {
2159 fprintf(*fp, "uid %s\n", NONULL(uid->uid));
2160 uid = uid->next;
2161 }
2162 }
2163 subkey = subkey->next;
2164 more = true;
2165 }
2166 gpgme_key_unref(key);
2167 }
2168 if (gpg_err_code(err) != GPG_ERR_EOF)
2169 {
2170 mutt_debug(LL_DEBUG1, "Error listing keys\n");
2171 goto err_fp;
2172 }
2173
2174 rc = 0;
2175
2176err_fp:
2177 if (rc)
2178 mutt_file_fclose(fp);
2179
2180 gpgme_release(tmpctx);
2181
2182 return rc;
2183}
2184
2196static int line_compare(const char *a, size_t n, const char *b)
2197{
2198 if (mutt_strn_equal(a, b, n))
2199 {
2200 /* at this point we know that 'b' is at least 'n' chars long */
2201 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2202 return true;
2203 }
2204 return false;
2205}
2206
2214static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
2215{
2216 char buf[8192] = { 0 };
2217 bool rc = false;
2218
2219 bool sgn = false;
2220 bool enc = false;
2221
2222 if (b->type != TYPE_TEXT)
2223 return 0;
2224
2225 struct Buffer *tempfile = buf_pool_get();
2226 buf_mktemp(tempfile);
2228 MUTT_SAVE_NO_FLAGS) != 0)
2229 {
2230 unlink(buf_string(tempfile));
2231 goto cleanup;
2232 }
2233
2234 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2235 if (!fp_tmp)
2236 {
2237 unlink(buf_string(tempfile));
2238 goto cleanup;
2239 }
2240
2241 while (fgets(buf, sizeof(buf), fp_tmp))
2242 {
2243 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2244 if (plen != 0)
2245 {
2246 if (MESSAGE(buf + plen))
2247 {
2248 enc = true;
2249 break;
2250 }
2251 else if (SIGNED_MESSAGE(buf + plen))
2252 {
2253 sgn = true;
2254 break;
2255 }
2256 }
2257 }
2258 mutt_file_fclose(&fp_tmp);
2259 unlink(buf_string(tempfile));
2260
2261 if (!enc && !sgn)
2262 goto cleanup;
2263
2264 /* fix the content type */
2265
2266 mutt_param_set(&b->parameter, "format", "fixed");
2267 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2268
2269 rc = true;
2270
2271cleanup:
2272 buf_pool_release(&tempfile);
2273 return rc;
2274}
2275
2279bool pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
2280{
2281 bool rc = false;
2282 for (; b; b = b->next)
2283 {
2284 if (!just_one && is_multipart(b))
2285 {
2286 rc = (pgp_gpgme_check_traditional(fp, b->parts, false) || rc);
2287 }
2288 else if (b->type == TYPE_TEXT)
2289 {
2291 if (r)
2292 rc = (rc || r);
2293 else
2294 rc = (pgp_check_traditional_one_body(fp, b) || rc);
2295 }
2296
2297 if (just_one)
2298 break;
2299 }
2300 return rc;
2301}
2302
2306void pgp_gpgme_invoke_import(const char *fname)
2307{
2308 gpgme_ctx_t ctx = create_gpgme_context(false);
2309 gpgme_data_t keydata = NULL;
2310 gpgme_import_result_t impres = NULL;
2311 gpgme_import_status_t st = NULL;
2312 bool any;
2313
2314 FILE *fp_in = mutt_file_fopen(fname, "r");
2315 if (!fp_in)
2316 {
2317 mutt_perror("%s", fname);
2318 goto leave;
2319 }
2320 /* Note that the stream, "fp_in", needs to be kept open while the keydata
2321 * is used. */
2322 gpgme_error_t err = gpgme_data_new_from_stream(&keydata, fp_in);
2323 if (err != GPG_ERR_NO_ERROR)
2324 {
2325 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
2326 goto leave;
2327 }
2328
2329 err = gpgme_op_import(ctx, keydata);
2330 if (err != GPG_ERR_NO_ERROR)
2331 {
2332 mutt_error(_("Error importing key: %s"), gpgme_strerror(err));
2333 goto leave;
2334 }
2335
2336 /* Print infos about the imported keys to stdout. */
2337 impres = gpgme_op_import_result(ctx);
2338 if (!impres)
2339 {
2340 fputs("oops: no import result returned\n", stdout);
2341 goto leave;
2342 }
2343
2344 for (st = impres->imports; st; st = st->next)
2345 {
2346 if (st->result)
2347 continue;
2348 printf("key %s imported (", NONULL(st->fpr));
2349 /* Note that we use the singular even if it is possible that
2350 * several uids etc are new. This simply looks better. */
2351 any = false;
2352 if (st->status & GPGME_IMPORT_SECRET)
2353 {
2354 printf("secret parts");
2355 any = true;
2356 }
2357 if ((st->status & GPGME_IMPORT_NEW))
2358 {
2359 printf("%snew key", any ? ", " : "");
2360 any = true;
2361 }
2362 if ((st->status & GPGME_IMPORT_UID))
2363 {
2364 printf("%snew uid", any ? ", " : "");
2365 any = true;
2366 }
2367 if ((st->status & GPGME_IMPORT_SIG))
2368 {
2369 printf("%snew sig", any ? ", " : "");
2370 any = true;
2371 }
2372 if ((st->status & GPGME_IMPORT_SUBKEY))
2373 {
2374 printf("%snew subkey", any ? ", " : "");
2375 any = true;
2376 }
2377 printf("%s)\n", any ? "" : "not changed");
2378 /* Fixme: Should we lookup each imported key and print more infos? */
2379 }
2380 /* Now print keys which failed the import. Unfortunately in most
2381 * cases gpg will bail out early and not tell GPGME about. */
2382 /* FIXME: We could instead use the new GPGME_AUDITLOG_DIAG to show
2383 * the actual gpg diagnostics. But I fear that would clutter the
2384 * output too much. Maybe a dedicated prompt or option to do this
2385 * would be helpful. */
2386 for (st = impres->imports; st; st = st->next)
2387 {
2388 if (st->result == 0)
2389 continue;
2390 printf("key %s import failed: %s\n", NONULL(st->fpr), gpgme_strerror(st->result));
2391 }
2392 fflush(stdout);
2393
2394leave:
2395 gpgme_release(ctx);
2396 gpgme_data_release(keydata);
2397 mutt_file_fclose(&fp_in);
2398}
2399
2415static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
2416{
2417 char buf[8192] = { 0 };
2418 bool complete, armor_header;
2419 FILE *fp = NULL;
2420
2421 char *fname = data_object_to_tempfile(data, &fp);
2422 if (!fname)
2423 {
2424 mutt_file_fclose(&fp);
2425 return;
2426 }
2427 unlink(fname);
2428 FREE(&fname);
2429
2430 /* fromcode comes from the MIME Content-Type charset label. It might
2431 * be a wrong label, so we want the ability to do corrections via
2432 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2434
2435 for (complete = true, armor_header = true;
2436 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2437 {
2438 if (!complete)
2439 {
2440 if (!armor_header)
2441 state_puts(state, buf);
2442 continue;
2443 }
2444
2445 if (BEGIN_PGP_SIGNATURE(buf))
2446 break;
2447
2448 if (armor_header)
2449 {
2450 if (buf[0] == '\n')
2451 armor_header = false;
2452 continue;
2453 }
2454
2455 if (state->prefix)
2456 state_puts(state, state->prefix);
2457
2458 if ((buf[0] == '-') && (buf[1] == ' '))
2459 state_puts(state, buf + 2);
2460 else
2461 state_puts(state, buf);
2462 }
2463
2466}
2467
2471int pgp_gpgme_application_handler(struct Body *b, struct State *state)
2472{
2473 int needpass = -1;
2474 bool pgp_keyblock = false;
2475 bool clearsign = false;
2476 long bytes;
2477 LOFF_T last_pos;
2478 LOFF_T block_begin;
2479 LOFF_T block_end;
2480 char buf[8192] = { 0 };
2481 FILE *fp_out = NULL;
2482
2483 gpgme_error_t err = GPG_ERR_NO_ERROR;
2484 gpgme_data_t armored_data = NULL;
2485
2486 bool maybe_goodsig = true;
2487 bool have_any_sigs = false;
2488
2489 char body_charset[256] = { 0 }; /* Only used for clearsigned messages. */
2490 char *gpgcharset = NULL;
2491
2492 mutt_debug(LL_DEBUG2, "Entering handler\n");
2493
2494 /* For clearsigned messages we won't be able to get a character set
2495 * but we know that this may only be text thus we assume Latin-1 here. */
2496 if (!mutt_body_get_charset(b, body_charset, sizeof(body_charset)))
2497 mutt_str_copy(body_charset, "iso-8859-1", sizeof(body_charset));
2498
2499 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
2500 {
2501 return -1;
2502 }
2503 last_pos = b->offset;
2504
2505 for (bytes = b->length; bytes > 0;)
2506 {
2507 // record before the fgets in case it is a BEGIN block
2508 block_begin = last_pos;
2509
2510 if (!fgets(buf, sizeof(buf), state->fp_in))
2511 break;
2512
2513 LOFF_T offset = ftello(state->fp_in);
2514 if (offset < 0)
2515 {
2516 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2517 offset = 0;
2518 }
2519 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
2520 last_pos = offset;
2521
2522 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2523 if (plen != 0)
2524 {
2525 needpass = 0;
2526 clearsign = false;
2527 pgp_keyblock = false;
2528
2529 if (MESSAGE(buf + plen))
2530 {
2531 needpass = 1;
2532 }
2533 else if (SIGNED_MESSAGE(buf + plen))
2534 {
2535 clearsign = true;
2536 }
2537 else if (PUBLIC_KEY_BLOCK(buf + plen))
2538 {
2539 pgp_keyblock = true;
2540 }
2541 else
2542 {
2543 /* XXX we may wish to recode here */
2544 if (state->prefix)
2545 state_puts(state, state->prefix);
2546 state_puts(state, buf);
2547 continue;
2548 }
2549
2550 /* Find the end of armored block. */
2551 while ((bytes > 0) && (fgets(buf, sizeof(buf) - 1, state->fp_in) != NULL))
2552 {
2553 offset = ftello(state->fp_in);
2554 if (offset < 0)
2555 {
2556 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2557 offset = 0;
2558 }
2559 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
2560 last_pos = offset;
2561
2562 if (needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
2563 {
2564 break;
2565 }
2566
2567 if (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
2568 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf)))
2569 {
2570 break;
2571 }
2572
2573 // remember optional Charset: armor header as defined by rfc4880
2574 if (mutt_strn_equal("Charset: ", buf, 9))
2575 {
2576 size_t l = 0;
2577 FREE(&gpgcharset);
2578 gpgcharset = mutt_str_dup(buf + 9);
2579 if ((l = mutt_str_len(gpgcharset)) > 0 && gpgcharset[l - 1] == '\n')
2580 gpgcharset[l - 1] = 0;
2581 if (!mutt_ch_check_charset(gpgcharset, 0))
2582 mutt_str_replace(&gpgcharset, "UTF-8");
2583 }
2584 }
2585 block_end = ftello(state->fp_in);
2586 if (block_end < 0)
2587 {
2588 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2589 block_end = 0;
2590 }
2591
2592 have_any_sigs = (have_any_sigs || (clearsign && (state->flags & STATE_VERIFY)));
2593
2594 /* Copy PGP material to an data container */
2595 armored_data = file_to_data_object(state->fp_in, block_begin, block_end - block_begin);
2596 fseeko(state->fp_in, block_end, 0);
2597
2598 /* Invoke PGP if needed */
2599 if (pgp_keyblock)
2600 {
2601 pgp_gpgme_extract_keys(armored_data, &fp_out);
2602 }
2603 else if (!clearsign || (state->flags & STATE_VERIFY))
2604 {
2605 gpgme_data_t plaintext = create_gpgme_data();
2606 gpgme_ctx_t ctx = create_gpgme_context(false);
2607
2608 if (clearsign)
2609 {
2610 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2611 }
2612 else
2613 {
2614 err = gpgme_op_decrypt_verify(ctx, armored_data, plaintext);
2615 if (gpg_err_code(err) == GPG_ERR_NO_DATA)
2616 {
2617 /* Decrypt verify can't handle signed only messages. */
2618 gpgme_data_seek(armored_data, 0, SEEK_SET);
2619 /* Must release plaintext so that we supply an uninitialized object. */
2620 gpgme_data_release(plaintext);
2621 plaintext = create_gpgme_data();
2622 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2623 }
2624 }
2625 redraw_if_needed(ctx);
2626
2627 const bool c_devel_security = cs_subset_bool(NeoMutt->sub, "devel_security");
2628 gpgme_decrypt_result_t result = gpgme_op_decrypt_result(ctx);
2629 if (c_devel_security && result && (state->flags & STATE_DISPLAY))
2630 show_encryption_info(state, result);
2631
2632 if (err != GPG_ERR_NO_ERROR)
2633 {
2634 char errbuf[200] = { 0 };
2635
2636 snprintf(errbuf, sizeof(errbuf) - 1,
2637 _("Error: decryption/verification failed: %s\n"), gpgme_strerror(err));
2638 state_puts(state, errbuf);
2639 }
2640 else
2641 {
2642 /* Decryption/Verification succeeded */
2643
2644 mutt_message(_("PGP message successfully decrypted"));
2645
2646 bool sig_stat = false;
2647 char *tmpfname = NULL;
2648
2649 /* Check whether signatures have been verified. */
2650 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2651 if (verify_result->signatures)
2652 sig_stat = true;
2653
2654 have_any_sigs = false;
2655 maybe_goodsig = false;
2656 if ((state->flags & STATE_DISPLAY) && sig_stat)
2657 {
2658 int res, idx;
2659 bool anybad = false;
2660
2661 state_attach_puts(state, _("[-- Begin signature information --]\n"));
2662 have_any_sigs = true;
2663 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
2664 {
2665 if (res == 1)
2666 anybad = true;
2667 }
2668 if (!anybad && idx)
2669 maybe_goodsig = true;
2670
2671 state_attach_puts(state, _("[-- End signature information --]\n\n"));
2672 }
2673
2674 tmpfname = data_object_to_tempfile(plaintext, &fp_out);
2675 if (tmpfname)
2676 {
2677 unlink(tmpfname);
2678 FREE(&tmpfname);
2679 }
2680 else
2681 {
2682 mutt_file_fclose(&fp_out);
2683 state_puts(state, _("Error: copy data failed\n"));
2684 }
2685 }
2686 gpgme_data_release(plaintext);
2687 gpgme_release(ctx);
2688 }
2689
2690 /* Now, copy cleartext to the screen. NOTE - we expect that PGP
2691 * outputs utf-8 cleartext. This may not always be true, but it
2692 * seems to be a reasonable guess. */
2693 if (state->flags & STATE_DISPLAY)
2694 {
2695 if (needpass)
2696 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
2697 else if (pgp_keyblock)
2698 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
2699 else
2700 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
2701 }
2702
2703 if (clearsign)
2704 {
2705 copy_clearsigned(armored_data, state, body_charset);
2706 }
2707 else if (fp_out)
2708 {
2709 int c;
2710 char *expected_charset = gpgcharset && *gpgcharset ? gpgcharset : "utf-8";
2711 rewind(fp_out);
2712 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_out, expected_charset,
2714 while ((c = mutt_ch_fgetconv(fc)) != EOF)
2715 {
2716 state_putc(state, c);
2717 if ((c == '\n') && state->prefix)
2718 state_puts(state, state->prefix);
2719 }
2721 }
2722
2723 if (state->flags & STATE_DISPLAY)
2724 {
2725 state_putc(state, '\n');
2726 if (needpass)
2727 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
2728 else if (pgp_keyblock)
2729 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
2730 else
2731 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
2732 }
2733
2734 // Multiple PGP blocks can exist, so clean these up in each loop
2735 gpgme_data_release(armored_data);
2736 mutt_file_fclose(&fp_out);
2737 }
2738 else
2739 {
2740 /* A traditional PGP part may mix signed and unsigned content */
2741 /* XXX we may wish to recode here */
2742 if (state->prefix)
2743 state_puts(state, state->prefix);
2744 state_puts(state, buf);
2745 }
2746 }
2747 FREE(&gpgcharset);
2748
2749 b->goodsig = (maybe_goodsig && have_any_sigs);
2750
2751 if (needpass == -1)
2752 {
2753 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
2754 return 1;
2755 }
2756 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2757
2758 return err;
2759}
2760
2767int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
2768{
2769 int is_signed;
2770 int rc = 0;
2771
2772 mutt_debug(LL_DEBUG2, "Entering handler\n");
2773
2774 FILE *fp_out = mutt_file_mkstemp();
2775 if (!fp_out)
2776 {
2777 mutt_perror(_("Can't create temporary file"));
2778 if (state->flags & STATE_DISPLAY)
2779 {
2780 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2781 }
2782 return -1;
2783 }
2784
2785 struct Body *tattach = decrypt_part(b, state, fp_out, false, &is_signed);
2786 if (tattach)
2787 {
2788 tattach->goodsig = is_signed > 0;
2789
2790 if (state->flags & STATE_DISPLAY)
2791 {
2792 state_attach_puts(state, is_signed ?
2793 _("[-- The following data is PGP/MIME signed and encrypted --]\n") :
2794 _("[-- The following data is PGP/MIME encrypted --]\n"));
2795 mutt_protected_headers_handler(tattach, state);
2796 }
2797
2798 /* Store any protected headers in the parent so they can be
2799 * accessed for index updates after the handler recursion is done.
2800 * This is done before the handler to prevent a nested encrypted
2801 * handler from freeing the headers. */
2803 b->mime_headers = tattach->mime_headers;
2804 tattach->mime_headers = NULL;
2805
2806 FILE *fp_save = state->fp_in;
2807 state->fp_in = fp_out;
2808 rc = mutt_body_handler(tattach, state);
2809 state->fp_in = fp_save;
2810
2811 /* Embedded multipart signed protected headers override the
2812 * encrypted headers. We need to do this after the handler so
2813 * they can be printed in the pager. */
2814 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2815 {
2817 b->mime_headers = tattach->parts->mime_headers;
2818 tattach->parts->mime_headers = NULL;
2819 }
2820
2821 /* if a multipart/signed is the _only_ sub-part of a
2822 * multipart/encrypted, cache signature verification
2823 * status. */
2824 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2825 b->goodsig |= tattach->goodsig;
2826
2827 if (state->flags & STATE_DISPLAY)
2828 {
2829 state_attach_puts(state, is_signed ?
2830 _("[-- End of PGP/MIME signed and encrypted data --]\n") :
2831 _("[-- End of PGP/MIME encrypted data --]\n"));
2832 }
2833
2834 mutt_body_free(&tattach);
2835 mutt_message(_("PGP message successfully decrypted"));
2836 }
2837 else
2838 {
2839#ifdef USE_AUTOCRYPT
2840 if (!OptAutocryptGpgme)
2841#endif
2842 {
2843 mutt_error(_("Could not decrypt PGP message"));
2844 }
2845 rc = -1;
2846 }
2847
2848 mutt_file_fclose(&fp_out);
2849 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2850
2851 return rc;
2852}
2853
2857int smime_gpgme_application_handler(struct Body *b, struct State *state)
2858{
2859 int is_signed = 0;
2860 int rc = 0;
2861
2862 mutt_debug(LL_DEBUG2, "Entering handler\n");
2863
2864 /* clear out any mime headers before the handler, so they can't be spoofed. */
2866 b->warnsig = false;
2867 FILE *fp_out = mutt_file_mkstemp();
2868 if (!fp_out)
2869 {
2870 mutt_perror(_("Can't create temporary file"));
2871 if (state->flags & STATE_DISPLAY)
2872 {
2873 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2874 }
2875 return -1;
2876 }
2877
2878 struct Body *tattach = decrypt_part(b, state, fp_out, true, &is_signed);
2879 if (tattach)
2880 {
2881 tattach->goodsig = is_signed > 0;
2882
2883 if (state->flags & STATE_DISPLAY)
2884 {
2885 state_attach_puts(state, is_signed ?
2886 _("[-- The following data is S/MIME signed --]\n") :
2887 _("[-- The following data is S/MIME encrypted --]\n"));
2888 mutt_protected_headers_handler(tattach, state);
2889 }
2890
2891 /* Store any protected headers in the parent so they can be
2892 * accessed for index updates after the handler recursion is done.
2893 * This is done before the handler to prevent a nested encrypted
2894 * handler from freeing the headers. */
2896 b->mime_headers = tattach->mime_headers;
2897 tattach->mime_headers = NULL;
2898
2899 FILE *fp_save = state->fp_in;
2900 state->fp_in = fp_out;
2901 rc = mutt_body_handler(tattach, state);
2902 state->fp_in = fp_save;
2903
2904 /* Embedded multipart signed protected headers override the
2905 * encrypted headers. We need to do this after the handler so
2906 * they can be printed in the pager. */
2907 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2908 {
2910 b->mime_headers = tattach->parts->mime_headers;
2911 tattach->parts->mime_headers = NULL;
2912 }
2913
2914 /* if a multipart/signed is the _only_ sub-part of a multipart/encrypted,
2915 * cache signature verification status. */
2916 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2917 {
2918 b->goodsig = tattach->goodsig;
2919 if (!b->goodsig)
2920 b->warnsig = tattach->warnsig;
2921 }
2922 else if (tattach->goodsig)
2923 {
2924 b->goodsig = true;
2925 b->warnsig = tattach->warnsig;
2926 }
2927
2928 if (state->flags & STATE_DISPLAY)
2929 {
2930 state_attach_puts(state, is_signed ? _("[-- End of S/MIME signed data --]\n") :
2931 _("[-- End of S/MIME encrypted data --]\n"));
2932 }
2933
2934 mutt_body_free(&tattach);
2935 }
2936
2937 mutt_file_fclose(&fp_out);
2938 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2939
2940 return rc;
2941}
2942
2949unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
2950{
2951 unsigned int rc = 0;
2952
2953 switch (cap)
2954 {
2956 rc = key->can_encrypt;
2957 if (rc == 0)
2958 {
2959 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2960 {
2961 rc = subkey->can_encrypt;
2962 if (rc != 0)
2963 break;
2964 }
2965 }
2966 break;
2967 case KEY_CAP_CAN_SIGN:
2968 rc = key->can_sign;
2969 if (rc == 0)
2970 {
2971 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2972 {
2973 rc = subkey->can_sign;
2974 if (rc != 0)
2975 break;
2976 }
2977 }
2978 break;
2980 rc = key->can_certify;
2981 if (rc == 0)
2982 {
2983 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2984 {
2985 rc = subkey->can_certify;
2986 if (rc != 0)
2987 break;
2988 }
2989 }
2990 break;
2991 }
2992
2993 return rc;
2994}
2995
3005static char *list_to_pattern(struct ListHead *list)
3006{
3007 char *pattern = NULL, *p = NULL;
3008 const char *s = NULL;
3009 size_t n;
3010
3011 n = 0;
3012 struct ListNode *np = NULL;
3013 STAILQ_FOREACH(np, list, entries)
3014 {
3015 for (s = np->data; *s; s++)
3016 {
3017 if ((*s == '%') || (*s == '+'))
3018 n += 2;
3019 n++;
3020 }
3021 n++; /* delimiter or end of string */
3022 }
3023 n++; /* make sure to allocate at least one byte */
3024 p = MUTT_MEM_CALLOC(n, char);
3025 pattern = p;
3026 STAILQ_FOREACH(np, list, entries)
3027 {
3028 s = np->data;
3029 if (*s)
3030 {
3031 if (np != STAILQ_FIRST(list))
3032 *p++ = ' ';
3033 for (s = np->data; *s; s++)
3034 {
3035 if (*s == '%')
3036 {
3037 *p++ = '%';
3038 *p++ = '2';
3039 *p++ = '5';
3040 }
3041 else if (*s == '+')
3042 {
3043 *p++ = '%';
3044 *p++ = '2';
3045 *p++ = 'B';
3046 }
3047 else if (*s == ' ')
3048 {
3049 *p++ = '+';
3050 }
3051 else
3052 {
3053 *p++ = *s;
3054 }
3055 }
3056 }
3057 }
3058 *p = '\0';
3059 return pattern;
3060}
3061
3072static struct CryptKeyInfo *get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
3073{
3074 struct CryptKeyInfo *db = NULL, *k = NULL, **kend = NULL;
3075 gpgme_error_t err = GPG_ERR_NO_ERROR;
3076 gpgme_ctx_t ctx = NULL;
3077 gpgme_key_t key = NULL;
3078 int idx;
3079 gpgme_user_id_t uid = NULL;
3080
3081 char *pattern = list_to_pattern(hints);
3082 if (!pattern)
3083 return NULL;
3084
3085 ctx = create_gpgme_context(0);
3086 db = NULL;
3087 kend = &db;
3088
3089 if ((app & APPLICATION_PGP))
3090 {
3091 /* It's all a mess. That old GPGME expects different things depending on
3092 * the protocol. For gpg we don't need percent escaped pappert but simple
3093 * strings passed in an array to the keylist_ext_start function. */
3094 size_t n = 0;
3095 struct ListNode *np = NULL;
3096 STAILQ_FOREACH(np, hints, entries)
3097 {
3098 if (np->data && *np->data)
3099 n++;
3100 }
3101 if (n == 0)
3102 goto no_pgphints;
3103
3104 char **patarr = MUTT_MEM_CALLOC(n + 1, char *);
3105 n = 0;
3106 STAILQ_FOREACH(np, hints, entries)
3107 {
3108 if (np->data && *np->data)
3109 patarr[n++] = mutt_str_dup(np->data);
3110 }
3111 patarr[n] = NULL;
3112 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3113 for (n = 0; patarr[n]; n++)
3114 FREE(&patarr[n]);
3115 FREE(&patarr);
3116 if (err != GPG_ERR_NO_ERROR)
3117 {
3118 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3119 gpgme_release(ctx);
3120 FREE(&pattern);
3121 return NULL;
3122 }
3123
3124 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3125 {
3126 KeyFlags flags = KEYFLAG_NO_FLAGS;
3127
3129 flags |= KEYFLAG_CANENCRYPT;
3131 flags |= KEYFLAG_CANSIGN;
3132
3133 if (key->revoked)
3134 flags |= KEYFLAG_REVOKED;
3135 if (key->expired)
3136 flags |= KEYFLAG_EXPIRED;
3137 if (key->disabled)
3138 flags |= KEYFLAG_DISABLED;
3139
3140 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3141 {
3142 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3143 k->kobj = key;
3144 gpgme_key_ref(k->kobj);
3145 k->idx = idx;
3146 k->uid = uid->uid;
3147 k->flags = flags;
3148 if (uid->revoked)
3149 k->flags |= KEYFLAG_REVOKED;
3150 k->validity = uid->validity;
3151 *kend = k;
3152 kend = &k->next;
3153 }
3154 gpgme_key_unref(key);
3155 }
3156 if (gpg_err_code(err) != GPG_ERR_EOF)
3157 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3158 gpgme_op_keylist_end(ctx);
3159 no_pgphints:;
3160 }
3161
3162 if ((app & APPLICATION_SMIME))
3163 {
3164 /* and now look for x509 certificates */
3165 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3166 err = gpgme_op_keylist_start(ctx, pattern, 0);
3167 if (err != GPG_ERR_NO_ERROR)
3168 {
3169 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3170 gpgme_release(ctx);
3171 FREE(&pattern);
3172 return NULL;
3173 }
3174
3175 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3176 {
3177 KeyFlags flags = KEYFLAG_ISX509;
3178
3180 flags |= KEYFLAG_CANENCRYPT;
3182 flags |= KEYFLAG_CANSIGN;
3183
3184 if (key->revoked)
3185 flags |= KEYFLAG_REVOKED;
3186 if (key->expired)
3187 flags |= KEYFLAG_EXPIRED;
3188 if (key->disabled)
3189 flags |= KEYFLAG_DISABLED;
3190
3191 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3192 {
3193 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3194 k->kobj = key;
3195 gpgme_key_ref(k->kobj);
3196 k->idx = idx;
3197 k->uid = uid->uid;
3198 k->flags = flags;
3199 if (uid->revoked)
3200 k->flags |= KEYFLAG_REVOKED;
3201 k->validity = uid->validity;
3202 *kend = k;
3203 kend = &k->next;
3204 }
3205 gpgme_key_unref(key);
3206 }
3207 if (gpg_err_code(err) != GPG_ERR_EOF)
3208 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3209 gpgme_op_keylist_end(ctx);
3210 }
3211
3212 gpgme_release(ctx);
3213 FREE(&pattern);
3214 return db;
3215}
3216
3225static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
3226{
3227 char *scratch = mutt_str_dup(str);
3228 if (!scratch)
3229 return;
3230
3231 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3232 {
3233 if (strlen(t) > 3)
3235 }
3236
3237 FREE(&scratch);
3238}
3239
3249static struct CryptKeyInfo *crypt_getkeybyaddr(struct Address *a,
3250 KeyFlags abilities, unsigned int app,
3251 bool *forced_valid, bool oppenc_mode)
3252{
3253 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3254
3255 int multi = false;
3256 int this_key_has_strong = false;
3257 int this_key_has_addr_match = false;
3258 int match = false;
3259
3260 struct CryptKeyInfo *keys = NULL, *k = NULL;
3261 struct CryptKeyInfo *the_strong_valid_key = NULL;
3262 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3263 struct CryptKeyInfo *matches = NULL;
3264 struct CryptKeyInfo **matches_endp = &matches;
3265
3266 if (a && a->mailbox)
3268 if (a && a->personal)
3270
3271 if (!oppenc_mode)
3272 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3273 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3274
3275 mutt_list_free(&hints);
3276
3277 if (!keys)
3278 return NULL;
3279
3280 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3281 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3282
3283 for (k = keys; k; k = k->next)
3284 {
3285 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3286
3287 if (abilities && !(k->flags & abilities))
3288 {
3289 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3290 continue;
3291 }
3292
3293 this_key_has_strong = false; /* strong and valid match */
3294 this_key_has_addr_match = false;
3295 match = false; /* any match */
3296
3297 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3298 mutt_addrlist_parse(&alist, k->uid);
3299 struct Address *ka = NULL;
3300 TAILQ_FOREACH(ka, &alist, entries)
3301 {
3302 int validity = crypt_id_matches_addr(a, ka, k);
3303
3304 if (validity & CRYPT_KV_MATCH) /* something matches */
3305 {
3306 match = true;
3307
3308 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3309 {
3310 if (validity & CRYPT_KV_STRONGID)
3311 {
3312 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3313 multi = true;
3314 this_key_has_strong = true;
3315 }
3316 else
3317 {
3318 this_key_has_addr_match = true;
3319 }
3320 }
3321 }
3322 }
3323 mutt_addrlist_clear(&alist);
3324
3325 if (match)
3326 {
3327 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3328 *matches_endp = tmp;
3329 matches_endp = &tmp->next;
3330
3331 if (this_key_has_strong)
3332 the_strong_valid_key = tmp;
3333 else if (this_key_has_addr_match)
3334 a_valid_addrmatch_key = tmp;
3335 }
3336 }
3337
3338 crypt_key_free(&keys);
3339
3340 if (matches)
3341 {
3342 if (oppenc_mode || !isatty(STDIN_FILENO))
3343 {
3344 const bool c_crypt_opportunistic_encrypt_strong_keys =
3345 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3346 if (the_strong_valid_key)
3347 k = crypt_copy_key(the_strong_valid_key);
3348 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3349 k = crypt_copy_key(a_valid_addrmatch_key);
3350 else
3351 k = NULL;
3352 }
3353 else if (the_strong_valid_key && !multi)
3354 {
3355 /* There was precisely one strong match on a valid ID.
3356 * Proceed without asking the user. */
3357 k = crypt_copy_key(the_strong_valid_key);
3358 }
3359 else
3360 {
3361 /* Else: Ask the user. */
3362 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3363 }
3364
3365 crypt_key_free(&matches);
3366 }
3367 else
3368 {
3369 k = NULL;
3370 }
3371
3372 return k;
3373}
3374
3383static struct CryptKeyInfo *crypt_getkeybystr(const char *p, KeyFlags abilities,
3384 unsigned int app, bool *forced_valid)
3385{
3386 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3387 struct CryptKeyInfo *matches = NULL;
3388 struct CryptKeyInfo **matches_endp = &matches;
3389 struct CryptKeyInfo *k = NULL;
3390 const char *ps = NULL, *pl = NULL, *phint = NULL;
3391
3392 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3393
3394 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3395 crypt_add_string_to_hints(phint, &hints);
3396 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3397 mutt_list_free(&hints);
3398
3399 if (!keys)
3400 {
3401 FREE(&pfcopy);
3402 return NULL;
3403 }
3404
3405 for (k = keys; k; k = k->next)
3406 {
3407 if (abilities && !(k->flags & abilities))
3408 continue;
3409
3410 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3411 crypt_long_keyid(k), k->uid);
3412
3413 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3414 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3415 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3416 {
3417 mutt_debug(LL_DEBUG5, "match\n");
3418
3419 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3420 *matches_endp = tmp;
3421 matches_endp = &tmp->next;
3422 }
3423 else
3424 {
3425 mutt_debug(LL_DEBUG5, "no match\n");
3426 }
3427 }
3428
3429 FREE(&pfcopy);
3430 crypt_key_free(&keys);
3431
3432 if (matches)
3433 {
3434 if (isatty(STDIN_FILENO))
3435 {
3436 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3437
3438 crypt_key_free(&matches);
3439 return k;
3440 }
3441 else
3442 {
3443 if (crypt_keys_are_valid(matches))
3444 return matches;
3445
3446 crypt_key_free(&matches);
3447 return NULL;
3448 }
3449 }
3450
3451 return NULL;
3452}
3453
3466static struct CryptKeyInfo *crypt_ask_for_key(const char *tag, const char *whatfor,
3467 KeyFlags abilities,
3468 unsigned int app, bool *forced_valid)
3469{
3470 struct CryptKeyInfo *key = NULL;
3471 struct CryptCache *l = NULL;
3472 struct Buffer *resp = buf_pool_get();
3473
3475
3476 if (whatfor)
3477 {
3478 for (l = IdDefaults; l; l = l->next)
3479 {
3480 if (mutt_istr_equal(whatfor, l->what))
3481 {
3482 buf_strcpy(resp, l->dflt);
3483 break;
3484 }
3485 }
3486 }
3487
3488 while (true)
3489 {
3490 buf_reset(resp);
3491 if (mw_get_field(tag, resp, MUTT_COMP_NO_FLAGS, HC_OTHER, NULL, NULL) != 0)
3492 {
3493 goto done;
3494 }
3495
3496 if (whatfor)
3497 {
3498 if (l)
3499 {
3500 mutt_str_replace(&l->dflt, buf_string(resp));
3501 }
3502 else
3503 {
3504 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3505 l->next = IdDefaults;
3506 IdDefaults = l;
3507 l->what = mutt_str_dup(whatfor);
3508 l->dflt = buf_strdup(resp);
3509 }
3510 }
3511
3512 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3513 if (key)
3514 goto done;
3515
3516 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3517 }
3518
3519done:
3520 buf_pool_release(&resp);
3521 return key;
3522}
3523
3535static char *find_keys(const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
3536{
3537 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3538 struct ListNode *crypt_hook = NULL;
3539 const char *keyid = NULL;
3540 char *keylist = NULL;
3541 size_t keylist_size = 0;
3542 size_t keylist_used = 0;
3543 struct Address *p = NULL;
3544 struct CryptKeyInfo *k_info = NULL;
3545 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3546 char buf[1024] = { 0 };
3547 bool forced_valid = false;
3548 bool key_selected;
3549 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3550
3551 struct Address *a = NULL;
3552 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3553 TAILQ_FOREACH(a, addrlist, entries)
3554 {
3555 key_selected = false;
3556 mutt_crypt_hook(&crypt_hook_list, a);
3557 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3558 do
3559 {
3560 p = a;
3561 forced_valid = false;
3562 k_info = NULL;
3563
3564 if (crypt_hook)
3565 {
3566 keyid = crypt_hook->data;
3567 enum QuadOption ans = MUTT_YES;
3568 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3569 {
3570 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3571 buf_string(p->mailbox));
3572 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3573 }
3574 if (ans == MUTT_YES)
3575 {
3576 if (crypt_is_numerical_keyid(keyid))
3577 {
3578 if (mutt_strn_equal(keyid, "0x", 2))
3579 keyid += 2;
3580 goto bypass_selection; /* you don't see this. */
3581 }
3582
3583 /* check for e-mail address */
3584 mutt_addrlist_clear(&hookal);
3585 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3586 {
3587 mutt_addrlist_qualify(&hookal, fqdn);
3588 p = TAILQ_FIRST(&hookal);
3589 }
3590 else if (!oppenc_mode)
3591 {
3592 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3593 }
3594 }
3595 else if (ans == MUTT_NO)
3596 {
3597 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3598 {
3599 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3600 continue;
3601 }
3602 }
3603 else if (ans == MUTT_ABORT)
3604 {
3605 FREE(&keylist);
3606 mutt_addrlist_clear(&hookal);
3607 mutt_list_free(&crypt_hook_list);
3608 return NULL;
3609 }
3610 }
3611
3612 if (!k_info)
3613 {
3614 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3615 }
3616
3617 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3618 {
3619 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3620
3621 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3622 KEYFLAG_CANENCRYPT, app, &forced_valid);
3623 }
3624
3625 if (!k_info)
3626 {
3627 FREE(&keylist);
3628 mutt_addrlist_clear(&hookal);
3629 mutt_list_free(&crypt_hook_list);
3630 return NULL;
3631 }
3632
3633 keyid = crypt_fpr_or_lkeyid(k_info);
3634
3635 bypass_selection:
3636 keylist_size += mutt_str_len(keyid) + 4 + 1;
3637 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3638 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3639 keyid, forced_valid ? "!" : "");
3640 keylist_used = mutt_str_len(keylist);
3641
3642 key_selected = true;
3643
3644 crypt_key_free(&k_info);
3645 mutt_addrlist_clear(&hookal);
3646
3647 if (crypt_hook)
3648 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3649
3650 } while (crypt_hook);
3651
3652 mutt_list_free(&crypt_hook_list);
3653 }
3654 return keylist;
3655}
3656
3660char *pgp_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3661{
3662 return find_keys(addrlist, APPLICATION_PGP, oppenc_mode);
3663}
3664
3668char *smime_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3669{
3670 return find_keys(addrlist, APPLICATION_SMIME, oppenc_mode);
3671}
3672
3673#ifdef USE_AUTOCRYPT
3687{
3688 int rc = -1;
3689 gpgme_error_t err = GPG_ERR_NO_ERROR;
3690 gpgme_key_t key = NULL;
3691 gpgme_user_id_t uid = NULL;
3692 struct CryptKeyInfo *results = NULL, *k = NULL;
3693 struct CryptKeyInfo **kend = NULL;
3694 struct CryptKeyInfo *choice = NULL;
3695
3696 gpgme_ctx_t ctx = create_gpgme_context(false);
3697
3698 /* list all secret keys */
3699 if (gpgme_op_keylist_start(ctx, NULL, 1))
3700 goto cleanup;
3701
3702 kend = &results;
3703
3704 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3705 {
3707
3712
3713 if (key->revoked)
3715 if (key->expired)
3717 if (key->disabled)
3719
3720 int idx;
3721 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3722 {
3723 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3724 k->kobj = key;
3725 gpgme_key_ref(k->kobj);
3726 k->idx = idx;
3727 k->uid = uid->uid;
3728 k->flags = flags;
3729 if (uid->revoked)
3730 k->flags |= KEYFLAG_REVOKED;
3731 k->validity = uid->validity;
3732 *kend = k;
3733 kend = &k->next;
3734 }
3735 gpgme_key_unref(key);
3736 }
3737 if (gpg_err_code(err) != GPG_ERR_EOF)
3738 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3739 gpgme_op_keylist_end(ctx);
3740
3741 if (!results)
3742 {
3743 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3744 from. This error is displayed if no results were found. */
3745 mutt_error(_("No secret keys found"));
3746 goto cleanup;
3747 }
3748
3749 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3750 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3751 goto cleanup;
3752 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3753
3754 rc = 0;
3755
3756cleanup:
3757 crypt_key_free(&choice);
3758 crypt_key_free(&results);
3759 gpgme_release(ctx);
3760 return rc;
3761}
3762#endif
3763
3768{
3769 gpgme_ctx_t ctx = NULL;
3770 gpgme_key_t export_keys[2] = { 0 };
3771 gpgme_data_t keydata = NULL;
3772 struct Body *att = NULL;
3773 char buf[1024] = { 0 };
3774
3775 OptPgpCheckTrust = false;
3776
3777 struct CryptKeyInfo *key = crypt_ask_for_key(_("Please enter the key ID: "), NULL,
3779 if (!key)
3780 goto bail;
3781 export_keys[0] = key->kobj;
3782 export_keys[1] = NULL;
3783
3784 ctx = create_gpgme_context(false);
3785 gpgme_set_armor(ctx, 1);
3786 keydata = create_gpgme_data();
3787 gpgme_error_t err = gpgme_op_export_keys(ctx, export_keys, 0, keydata);
3788 if (err != GPG_ERR_NO_ERROR)
3789 {
3790 mutt_error(_("Error exporting key: %s"), gpgme_strerror(err));
3791 goto bail;
3792 }
3793
3794 char *tempf = data_object_to_tempfile(keydata, NULL);
3795 if (!tempf)
3796 goto bail;
3797
3798 att = mutt_body_new();
3799 /* tempf is a newly allocated string, so this is correct: */
3800 att->filename = tempf;
3801 att->unlink = true;
3802 att->use_disp = false;
3803 att->type = TYPE_APPLICATION;
3804 att->subtype = mutt_str_dup("pgp-keys");
3805 /* L10N: MIME description for exported (attached) keys.
3806 You can translate this entry to a non-ASCII string (it will be encoded),
3807 but it may be safer to keep it untranslated. */
3808 snprintf(buf, sizeof(buf), _("PGP Key 0x%s"), crypt_keyid(key));
3809 att->description = mutt_str_dup(buf);
3811
3812 att->length = mutt_file_get_size(tempf);
3813
3814bail:
3815 crypt_key_free(&key);
3816 gpgme_data_release(keydata);
3817 gpgme_release(ctx);
3818
3819 return att;
3820}
3821
3825static void init_common(void)
3826{
3827 /* this initialization should only run one time, but it may be called by
3828 * either pgp_gpgme_init or smime_gpgme_init */
3829 static bool has_run = false;
3830 if (has_run)
3831 return;
3832
3833 gpgme_check_version(NULL);
3834 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3835#ifdef ENABLE_NLS
3836 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3837#endif
3838 has_run = true;
3839}
3840
3844static void init_pgp(void)
3845{
3846 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3847 {
3848 mutt_error(_("GPGME: OpenPGP protocol not available"));
3849 }
3850}
3851
3855static void init_smime(void)
3856{
3857 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3858 {
3859 mutt_error(_("GPGME: CMS protocol not available"));
3860 }
3861}
3862
3867{
3868 init_common();
3869 init_pgp();
3870}
3871
3876{
3877 init_common();
3878 init_smime();
3879}
3880
3887static SecurityFlags gpgme_send_menu(struct Email *e, bool is_smime)
3888{
3889 struct CryptKeyInfo *p = NULL;
3890 const char *prompt = NULL;
3891 const char *letters = NULL;
3892 const char *choices = NULL;
3893 int choice;
3894
3895 if (is_smime)
3897 else
3899
3900 /* Opportunistic encrypt is controlling encryption.
3901 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3902 * letter choices for those.
3903 */
3904 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3905 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3906 {
3907 if (is_smime)
3908 {
3909 /* L10N: S/MIME options (opportunistic encryption is on) */
3910 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3911 /* L10N: S/MIME options (opportunistic encryption is on) */
3912 letters = _("sapco");
3913 choices = "SapCo";
3914 }
3915 else
3916 {
3917 /* L10N: PGP options (opportunistic encryption is on) */
3918 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3919 /* L10N: PGP options (opportunistic encryption is on) */
3920 letters = _("samco");
3921 choices = "SamCo";
3922 }
3923 }
3924 else if (c_crypt_opportunistic_encrypt)
3925 {
3926 /* Opportunistic encryption option is set, but is toggled off for this message. */
3927 if (is_smime)
3928 {
3929 /* L10N: S/MIME options (opportunistic encryption is off) */
3930 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3931 /* L10N: S/MIME options (opportunistic encryption is off) */
3932 letters = _("esabpco");
3933 choices = "esabpcO";
3934 }
3935 else
3936 {
3937 /* L10N: PGP options (opportunistic encryption is off) */
3938 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3939 /* L10N: PGP options (opportunistic encryption is off) */
3940 letters = _("esabmco");
3941 choices = "esabmcO";
3942 }
3943 }
3944 else
3945 {
3946 /* Opportunistic encryption is unset */
3947 if (is_smime)
3948 {
3949 /* L10N: S/MIME options */
3950 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
3951 /* L10N: S/MIME options */
3952 letters = _("esabpc");
3953 choices = "esabpc";
3954 }
3955 else
3956 {
3957 /* L10N: PGP options */
3958 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
3959 /* L10N: PGP options */
3960 letters = _("esabmc");
3961 choices = "esabmc";
3962 }
3963 }
3964
3965 choice = mw_multi_choice(prompt, letters);
3966 if (choice > 0)
3967 {
3968 switch (choices[choice - 1])
3969 {
3970 case 'a': /* sign (a)s */
3971 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
3972 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
3973 if (p)
3974 {
3975 char input_signas[128] = { 0 };
3976 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
3977
3978 if (is_smime)
3979 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
3980 else
3981 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
3982
3983 crypt_key_free(&p);
3984
3985 e->security |= SEC_SIGN;
3986 }
3987 break;
3988
3989 case 'b': /* (b)oth */
3990 e->security |= (SEC_ENCRYPT | SEC_SIGN);
3991 break;
3992
3993 case 'C':
3994 e->security &= ~SEC_SIGN;
3995 break;
3996
3997 case 'c': /* (c)lear */
3998 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
3999 break;
4000
4001 case 'e': /* (e)ncrypt */
4002 e->security |= SEC_ENCRYPT;
4003 e->security &= ~SEC_SIGN;
4004 break;
4005
4006 case 'm': /* (p)gp or s/(m)ime */
4007 case 'p':
4008 is_smime = !is_smime;
4009 if (is_smime)
4010 {
4011 e->security &= ~APPLICATION_PGP;
4013 }
4014 else
4015 {
4016 e->security &= ~APPLICATION_SMIME;
4018 }
4020 break;
4021
4022 case 'O': /* oppenc mode on */
4025 break;
4026
4027 case 'o': /* oppenc mode off */
4028 e->security &= ~SEC_OPPENCRYPT;
4029 break;
4030
4031 case 'S': /* (s)ign in oppenc mode */
4032 e->security |= SEC_SIGN;
4033 break;
4034
4035 case 's': /* (s)ign */
4036 e->security &= ~SEC_ENCRYPT;
4037 e->security |= SEC_SIGN;
4038 break;
4039 }
4040 }
4041
4042 return e->security;
4043}
4044
4049{
4050 return gpgme_send_menu(e, false);
4051}
4052
4057{
4058 return gpgme_send_menu(e, true);
4059}
4060
4066static bool verify_sender(struct Email *e)
4067{
4068 struct Address *sender = NULL;
4069 bool rc = true;
4070
4071 if (!TAILQ_EMPTY(&e->env->from))
4072 {
4074 sender = TAILQ_FIRST(&e->env->from);
4075 }
4076 else if (!TAILQ_EMPTY(&e->env->sender))
4077 {
4079 sender = TAILQ_FIRST(&e->env->sender);
4080 }
4081
4082 if (sender)
4083 {
4084 if (SignatureKey)
4085 {
4086 gpgme_key_t key = SignatureKey;
4087 gpgme_user_id_t uid = NULL;
4088 int sender_length = buf_len(sender->mailbox);
4089 for (uid = key->uids; uid && rc; uid = uid->next)
4090 {
4091 int uid_length = strlen(uid->email);
4092 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4093 (uid_length == (sender_length + 2)))
4094 {
4095 const char *at_sign = strchr(uid->email + 1, '@');
4096 if (at_sign)
4097 {
4098 /* Assume address is 'mailbox@domainname'.
4099 * The mailbox part is case-sensitive,
4100 * the domainname is not. (RFC2821) */
4101 const char *tmp_email = uid->email + 1;
4102 const char *tmp_sender = buf_string(sender->mailbox);
4103 /* length of mailbox part including '@' */
4104 int mailbox_length = at_sign - tmp_email + 1;
4105 int domainname_length = sender_length - mailbox_length;
4106 int mailbox_match, domainname_match;
4107
4108 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4109 tmp_email += mailbox_length;
4110 tmp_sender += mailbox_length;
4111 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4112 if (mailbox_match && domainname_match)
4113 rc = false;
4114 }
4115 else
4116 {
4117 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4118 rc = false;
4119 }
4120 }
4121 }
4122 }
4123 else
4124 {
4125 mutt_any_key_to_continue(_("Failed to verify sender"));
4126 }
4127 }
4128 else
4129 {
4130 mutt_any_key_to_continue(_("Failed to figure out sender"));
4131 }
4132
4133 if (SignatureKey)
4134 {
4135 gpgme_key_unref(SignatureKey);
4136 SignatureKey = NULL;
4137 }
4138
4139 return rc;
4140}
4141
4145int smime_gpgme_verify_sender(struct Email *e, struct Message *msg)
4146{
4147 return verify_sender(e);
4148}
4149
4153void pgp_gpgme_set_sender(const char *sender)
4154{
4155 mutt_debug(LL_DEBUG2, "setting to: %s\n", sender);
4157 CurrentSender = mutt_str_dup(sender);
4158}
4159
4165{
4166 return GPGME_VERSION;
4167}
void mutt_addrlist_qualify(struct AddressList *al, const char *host)
Expand local names in an Address list using a hostname.
Definition: address.c:680
void mutt_addrlist_clear(struct AddressList *al)
Unlink and free all Address in an AddressList.
Definition: address.c:1460
int mutt_addrlist_parse(struct AddressList *al, const char *s)
Parse a list of email addresses.
Definition: address.c:480
Email Address Handling.
Email Aliases.
void mutt_expand_aliases(struct AddressList *al)
Expand aliases in a List of Addresses.
Definition: alias.c:295
GUI display the mailboxes in a side panel.
char * AutocryptSignAs
Autocrypt Key id to sign as.
Definition: config.c:37
Autocrypt end-to-end encryption.
bool buf_istr_equal(const struct Buffer *a, const struct Buffer *b)
Return if two buffers are equal, case insensitive.
Definition: buffer.c:695
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:491
void buf_reset(struct Buffer *buf)
Reset an existing Buffer.
Definition: buffer.c:76
bool buf_is_empty(const struct Buffer *buf)
Is the Buffer empty?
Definition: buffer.c:291
size_t buf_addch(struct Buffer *buf, char c)
Add a single character to a Buffer.
Definition: buffer.c:241
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:226
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:395
char * buf_strdup(const struct Buffer *buf)
Copy a Buffer's string.
Definition: buffer.c:571
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
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
Convenience wrapper for the config headers.
const char * cc_charset(void)
Get the cached value of $charset.
Definition: config_cache.c:116
Convenience wrapper for the core headers.
void crypt_opportunistic_encrypt(struct Email *e)
Can all recipients be determined.
Definition: crypt.c:1045
bool crypt_is_numerical_keyid(const char *s)
Is this a numerical keyid.
Definition: crypt.c:1474
SecurityFlags mutt_is_multipart_signed(struct Body *b)
Is a message signed?
Definition: crypt.c:408
SecurityFlags mutt_is_application_smime(struct Body *b)
Does the message use S/MIME?
Definition: crypt.c:609
int mutt_is_valid_multipart_pgp_encrypted(struct Body *b)
Is this a valid multi-part encrypted message?
Definition: crypt.c:467
const char * crypt_get_fingerprint_or_id(const char *p, const char **pphint, const char **ppl, const char **pps)
Get the fingerprint or long key ID.
Definition: crypt.c:1385
SecurityFlags mutt_is_malformed_multipart_pgp_encrypted(struct Body *b)
Check for malformed layout.
Definition: crypt.c:504
void crypt_convert_to_7bit(struct Body *b)
Convert an email to 7bit encoding.
Definition: crypt.c:809
SecurityFlags mutt_is_application_pgp(const struct Body *b)
Does the message use PGP?
Definition: crypt.c:548
Signing/encryption multiplexor.
static const char * crypt_short_keyid(struct CryptKeyInfo *k)
Get the short keyID for a key.
Definition: crypt_gpgme.c:180
static gpgme_error_t set_pka_sig_notation(gpgme_ctx_t ctx)
Set the signature notation.
Definition: crypt_gpgme.c:761
static struct CryptKeyInfo * crypt_getkeybyaddr(struct Address *a, KeyFlags abilities, unsigned int app, bool *forced_valid, bool oppenc_mode)
Find a key by email address.
Definition: crypt_gpgme.c:3249
static char * find_keys(const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
Find keys of the recipients of the message.
Definition: crypt_gpgme.c:3535
static bool verify_sender(struct Email *e)
Verify the sender of a message.
Definition: crypt_gpgme.c:4066
static void init_common(void)
Initialise code common to PGP and SMIME parts of GPGME.
Definition: crypt_gpgme.c:3825
static struct CryptCache * IdDefaults
Cache of GPGME keys.
Definition: crypt_gpgme.c:92
struct CryptKeyInfo * crypt_copy_key(struct CryptKeyInfo *key)
Return a copy of KEY.
Definition: crypt_gpgme.c:234
#define CRYPT_KV_STRING
Definition: crypt_gpgme.c:76
static int verify_one(struct Body *b, struct State *state, const char *tempfile, bool is_smime)
Do the actual verification step.
Definition: crypt_gpgme.c:1581
static char * CurrentSender
Email address of the sender.
Definition: crypt_gpgme.c:96
int mutt_gpgme_select_secret_key(struct Buffer *keyid)
Select a private Autocrypt key for a new account.
Definition: crypt_gpgme.c:3686
const char * mutt_gpgme_print_version(void)
Get version of GPGME.
Definition: crypt_gpgme.c:4164
static void show_encryption_info(struct State *state, gpgme_decrypt_result_t result)
Show encryption information.
Definition: crypt_gpgme.c:1433
static gpgme_data_t body_to_data_object(struct Body *b, bool convert)
Create GPGME object from the mail body.
Definition: crypt_gpgme.c:419
int crypt_id_is_valid(struct CryptKeyInfo *key)
Is key ID valid.
Definition: crypt_gpgme.c:310
static gpgme_data_t create_gpgme_data(void)
Create a new GPGME data object.
Definition: crypt_gpgme.c:400
static int show_sig_summary(unsigned long sum, gpgme_ctx_t ctx, gpgme_key_t key, int idx, struct State *state, gpgme_signature_t sig)
Show a signature summary.
Definition: crypt_gpgme.c:1133
static void show_fingerprint(gpgme_key_t key, struct State *state)
Write a key's fingerprint.
Definition: crypt_gpgme.c:1257
gpgme_ctx_t create_gpgme_context(bool for_smime)
Create a new GPGME context.
Definition: crypt_gpgme.c:361
static void create_recipient_string(const char *keylist, struct Buffer *recpstring, int use_smime)
Create a string of recipients.
Definition: crypt_gpgme.c:622
static struct CryptKeyInfo * crypt_getkeybystr(const char *p, KeyFlags abilities, unsigned int app, bool *forced_valid)
Find a key by string.
Definition: crypt_gpgme.c:3383
static void print_smime_keyinfo(const char *msg, gpgme_signature_t sig, gpgme_key_t key, struct State *state)
Print key info about an SMIME key.
Definition: crypt_gpgme.c:1351
static int crypt_id_matches_addr(struct Address *addr, struct Address *u_addr, struct CryptKeyInfo *key)
Does the key ID match the address.
Definition: crypt_gpgme.c:328
bool crypt_id_is_strong(struct CryptKeyInfo *key)
Is the key strong.
Definition: crypt_gpgme.c:275
static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
Split a string and add the parts to a List.
Definition: crypt_gpgme.c:3225
const char * crypt_fpr_or_lkeyid(struct CryptKeyInfo *k)
Find the fingerprint of a key.
Definition: crypt_gpgme.c:214
static char * encrypt_gpgme_object(gpgme_data_t plaintext, char *keylist, bool use_smime, bool combined_signed, const struct AddressList *from)
Encrypt the GPGPME data object.
Definition: crypt_gpgme.c:781
static void show_one_recipient(struct State *state, gpgme_recipient_t r)
Show information about one encryption recipient.
Definition: crypt_gpgme.c:1417
#define BEGIN_PGP_SIGNATURE(_y)
Definition: crypt_gpgme.c:104
#define SIGNED_MESSAGE(_y)
Definition: crypt_gpgme.c:102
#define PKA_NOTATION_NAME
Definition: crypt_gpgme.c:98
static char * list_to_pattern(struct ListHead *list)
Convert STailQ to GPGME-compatible pattern.
Definition: crypt_gpgme.c:3005
#define CRYPT_KV_VALID
Definition: crypt_gpgme.c:74
static int get_micalg(gpgme_ctx_t ctx, int use_smime, char *buf, size_t buflen)
Find the "micalg" parameter from the last GPGME operation.
Definition: crypt_gpgme.c:853
static int data_object_to_stream(gpgme_data_t data, FILE *fp)
Write a GPGME data object to a file.
Definition: crypt_gpgme.c:514
static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
Check one inline PGP body part.
Definition: crypt_gpgme.c:2214
static const char * crypt_long_keyid(struct CryptKeyInfo *k)
Find the Long ID for the key.
Definition: crypt_gpgme.c:163
#define CRYPT_KV_STRONGID
Definition: crypt_gpgme.c:77
static struct CryptKeyInfo * get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
Get a list of keys which are candidates for the selection.
Definition: crypt_gpgme.c:3072
static gpgme_data_t file_to_data_object(FILE *fp, long offset, size_t length)
Create GPGME data object from file.
Definition: crypt_gpgme.c:493
static struct Body * decrypt_part(struct Body *b, struct State *state, FILE *fp_out, bool is_smime, int *r_is_signed)
Decrypt a PGP or SMIME message.
Definition: crypt_gpgme.c:1732
#define PUBLIC_KEY_BLOCK(_y)
Definition: crypt_gpgme.c:103
static int set_signer(gpgme_ctx_t ctx, const struct AddressList *al, bool for_smime)
Make sure that the correct signer is set.
Definition: crypt_gpgme.c:717
static char * data_object_to_tempfile(gpgme_data_t data, FILE **fp_ret)
Copy a data object to a temporary file.
Definition: crypt_gpgme.c:563
static void show_one_sig_validity(gpgme_ctx_t ctx, int idx, struct State *state)
Show the validity of a key used for one signature.
Definition: crypt_gpgme.c:1312
static void init_smime(void)
Initialise the SMIME crypto backend.
Definition: crypt_gpgme.c:3855
static struct CryptKeyInfo * crypt_ask_for_key(const char *tag, const char *whatfor, KeyFlags abilities, unsigned int app, bool *forced_valid)
Ask the user for a key.
Definition: crypt_gpgme.c:3466
unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
Check the capabilities of a key.
Definition: crypt_gpgme.c:2949
static const char * crypt_fpr(struct CryptKeyInfo *k)
Get the hexstring fingerprint from a key.
Definition: crypt_gpgme.c:199
const char * crypt_keyid(struct CryptKeyInfo *k)
Find the ID for the key.
Definition: crypt_gpgme.c:138
static SecurityFlags gpgme_send_menu(struct Email *e, bool is_smime)
Show the user the encryption/signing menu.
Definition: crypt_gpgme.c:3887
#define CRYPT_KV_ADDR
Definition: crypt_gpgme.c:75
static struct Body * sign_message(struct Body *b, const struct AddressList *from, bool use_smime)
Sign a message.
Definition: crypt_gpgme.c:906
static bool is_pka_notation(gpgme_sig_notation_t notation)
Is this the standard pka email address.
Definition: crypt_gpgme.c:112
static void redraw_if_needed(gpgme_ctx_t ctx)
Accommodate for a redraw if needed.
Definition: crypt_gpgme.c:121
static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
Write PGP keys to a file.
Definition: crypt_gpgme.c:2113
static int line_compare(const char *a, size_t n, const char *b)
Compare two strings ignore line endings.
Definition: crypt_gpgme.c:2196
static gpgme_key_t SignatureKey
PGP Key to sign with.
Definition: crypt_gpgme.c:94
static void crypt_key_free(struct CryptKeyInfo **keylist)
Release all the keys in a list.
Definition: crypt_gpgme.c:253
static bool set_signer_from_address(gpgme_ctx_t ctx, const char *address, bool for_smime)
Try to set the context's signer from the address.
Definition: crypt_gpgme.c:658
#define CRYPT_KV_MATCH
Definition: crypt_gpgme.c:78
static void init_pgp(void)
Initialise the PGP crypto backend.
Definition: crypt_gpgme.c:3844
static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
Copy a clearsigned message.
Definition: crypt_gpgme.c:2415
static int show_one_sig_status(gpgme_ctx_t ctx, int idx, struct State *state)
Show information about one signature.
Definition: crypt_gpgme.c:1458
static void print_time(time_t t, struct State *state)
Print the date/time according to the locale.
Definition: crypt_gpgme.c:891
#define MESSAGE(_y)
Definition: crypt_gpgme.c:101
Wrapper for PGP/SMIME calls to GPGME.
KeyCap
PGP/SMIME Key Capabilities.
Definition: crypt_gpgme.h:76
@ KEY_CAP_CAN_CERTIFY
Key can be used to certify.
Definition: crypt_gpgme.h:79
@ KEY_CAP_CAN_ENCRYPT
Key can be used for encryption.
Definition: crypt_gpgme.h:77
@ KEY_CAP_CAN_SIGN
Key can be used for signing.
Definition: crypt_gpgme.h:78
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_need_hard_redraw(void)
Force a hard refresh.
Definition: curs_lib.c:101
size_t mutt_strwidth(const char *s)
Measure a string's width in screen cells.
Definition: curs_lib.c:445
Edit a string.
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
char * mutt_body_get_charset(struct Body *b, char *buf, size_t buflen)
Get a body's character set.
Definition: body.c:133
Structs that make up an email.
void mutt_parse_part(FILE *fp, struct Body *b)
Parse a MIME part.
Definition: parse.c:1822
struct Body * mutt_read_mime_header(FILE *fp, bool digest)
Parse a MIME header.
Definition: parse.c:1362
void mutt_env_free(struct Envelope **ptr)
Free an Envelope.
Definition: envelope.c:126
void mutt_exit(int code)
Leave NeoMutt NOW.
Definition: exit.c:41
long mutt_file_get_size_fp(FILE *fp)
Get the size of a file.
Definition: file.c:1430
bool mutt_file_seek(FILE *fp, LOFF_T offset, int whence)
Wrapper for fseeko with error handling.
Definition: file.c:655
long mutt_file_get_size(const char *path)
Get the size of a file.
Definition: file.c:1412
#define mutt_file_fclose(FP)
Definition: file.h:139
#define mutt_file_fopen(PATH, MODE)
Definition: file.h:138
bool OptAutocryptGpgme
(pseudo) use Autocrypt context inside ncrypt/crypt_gpgme.c
Definition: globals.c:56
bool OptPgpCheckTrust
(pseudo) used by dlg_pgp()
Definition: globals.c:67
bool crypt_keys_are_valid(struct CryptKeyInfo *keys)
Are all these keys valid?
Gpgme functions.
int pgp_gpgme_application_handler(struct Body *b, struct State *state)
Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::applicat...
Definition: crypt_gpgme.c:2471
int smime_gpgme_application_handler(struct Body *b, struct State *state)
Manage the MIME type "application/pgp" or "application/smime" - Implements CryptModuleSpecs::applicat...
Definition: crypt_gpgme.c:2857
int smime_gpgme_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: crypt_gpgme.c:1993
int pgp_gpgme_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: crypt_gpgme.c:1896
int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
Manage a PGP or S/MIME encrypted MIME part - Implements CryptModuleSpecs::encrypted_handler() -.
Definition: crypt_gpgme.c:2767
char * smime_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
Definition: crypt_gpgme.c:3668
char * pgp_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
Find the keyids of the recipients of a message - Implements CryptModuleSpecs::find_keys() -.
Definition: crypt_gpgme.c:3660
void smime_gpgme_init(void)
Initialise the crypto module - Implements CryptModuleSpecs::init() -.
Definition: crypt_gpgme.c:3875
void pgp_gpgme_init(void)
Initialise the crypto module - Implements CryptModuleSpecs::init() -.
Definition: crypt_gpgme.c:3866
bool pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
Look for inline (non-MIME) PGP content - Implements CryptModuleSpecs::pgp_check_traditional() -.
Definition: crypt_gpgme.c:2279
struct Body * pgp_gpgme_encrypt_message(struct Body *b, char *keylist, bool sign, const struct AddressList *from)
PGP encrypt an email - Implements CryptModuleSpecs::pgp_encrypt_message() -.
Definition: crypt_gpgme.c:1043
void pgp_gpgme_invoke_import(const char *fname)
Import a key from a message into the user's public key ring - Implements CryptModuleSpecs::pgp_invoke...
Definition: crypt_gpgme.c:2306
struct Body * pgp_gpgme_make_key_attachment(void)
Generate a public key attachment - Implements CryptModuleSpecs::pgp_make_key_attachment() -.
Definition: crypt_gpgme.c:3767
SecurityFlags pgp_gpgme_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
Definition: crypt_gpgme.c:4048
SecurityFlags smime_gpgme_send_menu(struct Email *e)
Ask the user whether to sign and/or encrypt the email - Implements CryptModuleSpecs::send_menu() -.
Definition: crypt_gpgme.c:4056
void pgp_gpgme_set_sender(const char *sender)
Set the sender of the email - Implements CryptModuleSpecs::set_sender() -.
Definition: crypt_gpgme.c:4153
struct Body * smime_gpgme_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
Definition: crypt_gpgme.c:1035
struct Body * pgp_gpgme_sign_message(struct Body *b, const struct AddressList *from)
Cryptographically sign the Body of a message - Implements CryptModuleSpecs::sign_message() -.
Definition: crypt_gpgme.c:1027
struct Body * smime_gpgme_build_smime_entity(struct Body *b, char *keylist)
Encrypt the email body to all recipients - Implements CryptModuleSpecs::smime_build_smime_entity() -.
Definition: crypt_gpgme.c:1089
int smime_gpgme_verify_sender(struct Email *e, struct Message *msg)
Does the sender match the certificate? - Implements CryptModuleSpecs::smime_verify_sender() -.
Definition: crypt_gpgme.c:4145
int pgp_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
Definition: crypt_gpgme.c:1706
int smime_gpgme_verify_one(struct Body *b, struct State *state, const char *tempfile)
Check a signed MIME part against a signature - Implements CryptModuleSpecs::verify_one() -.
Definition: crypt_gpgme.c:1714
struct CryptKeyInfo * dlg_gpgme(struct CryptKeyInfo *keys, struct Address *p, const char *s, unsigned int app, bool *forced_valid)
Get the user to select a key -.
Definition: dlg_gpgme.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:273
int mw_multi_choice(const char *prompt, const char *letters)
Offer the user a multiple choice question -.
Definition: question.c:63
int mutt_protected_headers_handler(struct Body *b_email, struct State *state)
Handler for protected headers - Implements handler_t -.
Definition: crypt.c:1117
#define mutt_error(...)
Definition: logging2.h:93
#define mutt_message(...)
Definition: logging2.h:92
#define mutt_debug(LEVEL,...)
Definition: logging2.h:90
#define mutt_perror(...)
Definition: logging2.h:94
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:1633
void mutt_decode_attachment(const struct Body *b, struct State *state)
Decode an email's attachment.
Definition: handler.c:1907
Decide how to display email content.
int mutt_write_mime_header(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Create a MIME header.
Definition: header.c:756
Read/write command history from/to a file.
@ HC_OTHER
Miscellaneous strings.
Definition: lib.h:58
void mutt_crypt_hook(struct ListHead *list, struct Address *addr)
Find crypto hooks for an Address.
Definition: hook.c:879
Parse and execute user-defined hooks.
struct ListNode * mutt_list_insert_tail(struct ListHead *h, char *s)
Append a string to the end of a List.
Definition: list.c:65
void mutt_list_free(struct ListHead *h)
Free a List AND its strings.
Definition: list.c:123
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:48
@ LL_DEBUG2
Log at debug level 2.
Definition: logging2.h:45
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:44
#define FREE(x)
Definition: memory.h:55
#define MUTT_MEM_CALLOC(n, type)
Definition: memory.h:40
#define MUTT_MEM_REALLOC(pptr, n, type)
Definition: memory.h:43
#define MUTT_MEM_MALLOC(n, type)
Definition: memory.h:41
@ 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
@ TYPE_TEXT
Type: 'text/*'.
Definition: mime.h:38
@ DISP_ATTACH
Content is attached.
Definition: mime.h:63
@ DISP_INLINE
Content is inline.
Definition: mime.h:62
@ DISP_NONE
No preferred disposition.
Definition: mime.h:65
#define is_multipart(body)
Definition: mime.h:82
void mutt_generate_boundary(struct ParameterList *pl)
Create a unique boundary id for a MIME part.
Definition: multipart.c:86
bool mutt_ch_check_charset(const char *cs, bool strict)
Does iconv understand a character set?
Definition: charset.c:894
int mutt_ch_fgetconv(struct FgetConv *fc)
Convert a file's character set.
Definition: charset.c:980
struct FgetConv * mutt_ch_fgetconv_open(FILE *fp, const char *from, const char *to, uint8_t flags)
Prepare a file for charset conversion.
Definition: charset.c:933
char * mutt_ch_fgetconvs(char *buf, size_t buflen, struct FgetConv *fc)
Convert a file's charset into a string buffer.
Definition: charset.c:1042
void mutt_ch_fgetconv_close(struct FgetConv **ptr)
Close an fgetconv handle.
Definition: charset.c:962
#define MUTT_ICONV_HOOK_FROM
apply charset-hooks to fromcode
Definition: charset.h:65
size_t mutt_date_localtime_format(char *buf, size_t buflen, const char *format, time_t t)
Format localtime.
Definition: date.c:951
Convenience wrapper for the library headers.
#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
int state_printf(struct State *state, const char *fmt,...)
Write a formatted string to the State.
Definition: state.c:187
#define state_puts(STATE, STR)
Definition: state.h:58
#define STATE_DISPLAY
Output is displayed to the user.
Definition: state.h:33
#define state_putc(STATE, STR)
Definition: state.h:59
#define STATE_VERIFY
Perform signature verification.
Definition: state.h:34
#define STATE_NO_FLAGS
No flags are set.
Definition: state.h:32
int mutt_istrn_cmp(const char *a, const char *b, size_t num)
Compare two strings ignoring case (to a maximum), safely.
Definition: string.c:440
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:673
char * mutt_str_dup(const char *str)
Copy a string, safely.
Definition: string.c:254
char * mutt_str_lower(char *str)
Convert all characters in the string to lowercase.
Definition: string.c:314
bool mutt_str_equal(const char *a, const char *b)
Compare two strings.
Definition: string.c:661
bool mutt_strn_equal(const char *a, const char *b, size_t num)
Check for equality of two strings (to a maximum), safely.
Definition: string.c:426
const char * mutt_istr_find(const char *haystack, const char *needle)
Find first occurrence of string (ignoring case)
Definition: string.c:522
size_t mutt_str_startswith(const char *str, const char *prefix)
Check whether a string starts with a prefix.
Definition: string.c:231
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:497
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:582
char * mutt_str_replace(char **p, const char *s)
Replace one string with another.
Definition: string.c:281
Many unsorted constants and some structs.
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
int mutt_decode_save_attachment(FILE *fp, struct Body *b, const char *path, StateFlags flags, enum SaveAttach opt)
Decode, then save an attachment.
Definition: mutt_attach.c:1039
@ MUTT_SAVE_NO_FLAGS
Overwrite existing file (the default)
Definition: mutt_attach.h:58
void mutt_clear_error(void)
Clear the message line (bottom line of screen)
Definition: mutt_logging.c:74
NeoMutt Logging.
#define KEYFLAG_EXPIRED
Key is expired.
Definition: lib.h:137
uint16_t SecurityFlags
Flags, e.g. SEC_ENCRYPT.
Definition: lib.h:82
#define SEC_OPPENCRYPT
Opportunistic encrypt mode.
Definition: lib.h:92
#define KEYFLAG_ISX509
Key is an X.509 key.
Definition: lib.h:135
uint16_t KeyFlags
Flags describing PGP/SMIME keys, e.g. KEYFLAG_CANSIGN.
Definition: lib.h:131
#define APPLICATION_PGP
Use PGP to encrypt/sign.
Definition: lib.h:96
#define KEYFLAG_CANENCRYPT
Key is suitable for encryption.
Definition: lib.h:134
#define KEYFLAG_CANTUSE
Definition: lib.h:145
#define APPLICATION_SMIME
Use SMIME to encrypt/sign.
Definition: lib.h:97
#define KEYFLAG_NO_FLAGS
No flags are set.
Definition: lib.h:132
#define SEC_NO_FLAGS
No flags are set.
Definition: lib.h:83
#define KEYFLAG_DISABLED
Key is marked disabled.
Definition: lib.h:139
#define SEC_ENCRYPT
Email is encrypted.
Definition: lib.h:84
#define KEYFLAG_REVOKED
Key is revoked.
Definition: lib.h:138
#define SEC_SIGN
Email is signed.
Definition: lib.h:85
#define KEYFLAG_CANSIGN
Key is suitable for signing.
Definition: lib.h:133
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:82
void buf_pool_release(struct Buffer **ptr)
Return a Buffer to the pool.
Definition: pool.c:96
QuadOption
Possible values for a quad-option.
Definition: quad.h:36
@ MUTT_ABORT
User aborted the question (with Ctrl-G)
Definition: quad.h:37
@ MUTT_NO
User answered 'No', or assume 'No'.
Definition: quad.h:38
@ MUTT_YES
User answered 'Yes', or assume 'Yes'.
Definition: quad.h:39
Ask the user a question.
enum QuadOption query_yesorno_help(const char *prompt, enum QuadOption def, struct ConfigSubset *sub, const char *name)
Ask the user a Yes/No question offering help.
Definition: question.c:355
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:782
#define STAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define STAILQ_FIRST(head)
Definition: queue.h:388
#define STAILQ_FOREACH(var, head, field)
Definition: queue.h:390
#define TAILQ_FIRST(head)
Definition: queue.h:780
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:694
#define TAILQ_EMPTY(head)
Definition: queue.h:778
#define STAILQ_NEXT(elm, field)
Definition: queue.h:439
int mutt_write_mime_body(struct Body *b, FILE *fp, struct ConfigSubset *sub)
Write a MIME part.
Definition: body.c:300
Convenience wrapper for the send headers.
void mutt_update_encoding(struct Body *b, struct ConfigSubset *sub)
Update the encoding type.
Definition: sendlib.c:422
const char * mutt_fqdn(bool may_hide_host, const struct ConfigSubset *sub)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:707
GUI display the mailboxes in a side panel.
Key value store.
#define NONULL(x)
Definition: string2.h:37
An email address.
Definition: address.h:36
struct Buffer * personal
Real name of address.
Definition: address.h:37
struct Buffer * 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: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
char * description
content-description
Definition: body.h:55
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
bool warnsig
Maybe good signature.
Definition: body.h:48
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
char * data
Pointer to data.
Definition: buffer.h:37
Internal cache for GPGME.
Definition: crypt_gpgme.c:85
char * what
Definition: crypt_gpgme.c:86
char * dflt
Definition: crypt_gpgme.c:87
struct CryptCache * next
Definition: crypt_gpgme.c:88
A stored PGP key.
Definition: crypt_gpgme.h:44
gpgme_validity_t validity
uid validity (cached for convenience)
Definition: crypt_gpgme.h:50
KeyFlags flags
global and per uid flags (for convenience)
Definition: crypt_gpgme.h:49
int idx
and the user ID at this index
Definition: crypt_gpgme.h:47
struct CryptKeyInfo * next
Linked list.
Definition: crypt_gpgme.h:45
const char * uid
and for convenience point to this user ID
Definition: crypt_gpgme.h:48
gpgme_key_t kobj
Definition: crypt_gpgme.h:46
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
struct AddressList sender
Email's sender.
Definition: envelope.h:63
struct AddressList from
Email's 'From' list.
Definition: envelope.h:59
Cursor for converting a file's encoding.
Definition: charset.h:43
FILE * fp
Definition: charset.h:44
A List node for strings.
Definition: list.h:37
char * data
String.
Definition: list.h:38
A local copy of an email.
Definition: message.h:34
Container for Accounts, Notifications.
Definition: neomutt.h:43
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:47
Keep track when processing files.
Definition: state.h:48
StateFlags flags
Flags, e.g. STATE_DISPLAY.
Definition: state.h:52
FILE * fp_out
File to write to.
Definition: state.h:50
FILE * fp_in
File to read from.
Definition: state.h:49
const char * prefix
String to add to the beginning of each output line.
Definition: state.h:51
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:388
#define buf_mktemp(buf)
Definition: tmp.h:33
#define mutt_file_mkstemp()
Definition: tmp.h:36