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