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