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