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