NeoMutt  2025-12-11-1059-g2f5469
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 mutt_body_free(b_dec);
2090 goto done;
2091 }
2092 FILE *fp_tmp2 = mutt_file_mkstemp();
2093 if (!fp_tmp2)
2094 {
2095 mutt_perror(_("Can't create temporary file"));
2096 mutt_body_free(b_dec);
2097 goto done;
2098 }
2099
2100 state.fp_out = fp_tmp2;
2101 mutt_decode_attachment(bb, &state);
2102 fflush(fp_tmp2);
2103 bb->length = ftello(state.fp_out);
2104 bb->offset = 0;
2105 fseek(fp_tmp2, 0, SEEK_SET);
2106 clearerr(fp_tmp2);
2107 mutt_file_fclose(fp_out);
2108
2109 memset(&state, 0, sizeof(state));
2110 state.fp_in = fp_tmp2;
2111 state.fp_out = 0;
2112 *fp_out = mutt_file_mkstemp();
2113 if (!*fp_out)
2114 {
2115 mutt_perror(_("Can't create temporary file"));
2116 mutt_file_fclose(&fp_tmp2);
2117 mutt_body_free(b_dec);
2118 return -1;
2119 }
2120
2121 struct Body *b_tmp = decrypt_part(bb, &state, *fp_out, true, &is_signed);
2122 if (b_tmp)
2123 b_tmp->goodsig = is_signed > 0;
2124 bb->length = saved_b_length;
2125 bb->offset = saved_b_offset;
2126 mutt_file_fclose(&fp_tmp2);
2127 fseek(*fp_out, 0, SEEK_SET);
2128 clearerr(*fp_out);
2129 mutt_body_free(b_dec);
2130 *b_dec = b_tmp;
2131 }
2132
2133done:
2134 if (!*b_dec)
2135 {
2136 mutt_file_fclose(fp_out);
2137 return -1;
2138 }
2139 return 0;
2140}
2141
2149static int pgp_gpgme_extract_keys(gpgme_data_t keydata, FILE **fp)
2150{
2151 gpgme_ctx_t tmpctx = NULL;
2152 gpgme_key_t key = NULL;
2153 gpgme_user_id_t uid = NULL;
2154 gpgme_subkey_t subkey = NULL;
2155 const char *shortid = NULL;
2156 size_t len;
2157 char date[256] = { 0 };
2158 bool more;
2159 int rc = -1;
2160 time_t tt;
2161
2162 *fp = mutt_file_mkstemp();
2163 if (!*fp)
2164 {
2165 mutt_perror(_("Can't create temporary file"));
2166 return -1;
2167 }
2168
2169 tmpctx = create_gpgme_context(false);
2170
2171 gpgme_error_t err = gpgme_op_keylist_from_data_start(tmpctx, keydata, 0);
2172 while (err == GPG_ERR_NO_ERROR)
2173 {
2174 err = gpgme_op_keylist_next(tmpctx, &key);
2175 if (err != GPG_ERR_NO_ERROR)
2176 break;
2177 uid = key->uids;
2178 subkey = key->subkeys;
2179 more = false;
2180 while (subkey)
2181 {
2182 shortid = subkey->keyid;
2183 len = mutt_str_len(subkey->keyid);
2184 if (len > 8)
2185 shortid += len - 8;
2186 tt = subkey->timestamp;
2187 mutt_date_localtime_format(date, sizeof(date), "%Y-%m-%d", tt);
2188
2189 fprintf(*fp, "%s %5.5s %u/%8s %s\n", more ? "sub" : "pub",
2190 gpgme_pubkey_algo_name(subkey->pubkey_algo), subkey->length, shortid, date);
2191 if (!more)
2192 {
2193 while (uid)
2194 {
2195 fprintf(*fp, "uid %s\n", NONULL(uid->uid));
2196 uid = uid->next;
2197 }
2198 }
2199 subkey = subkey->next;
2200 more = true;
2201 }
2202 gpgme_key_unref(key);
2203 }
2204 if (gpg_err_code(err) != GPG_ERR_EOF)
2205 {
2206 mutt_debug(LL_DEBUG1, "Error listing keys\n");
2207 goto err_fp;
2208 }
2209
2210 rc = 0;
2211
2212err_fp:
2213 if (rc)
2214 mutt_file_fclose(fp);
2215
2216 gpgme_release(tmpctx);
2217
2218 return rc;
2219}
2220
2232static int line_compare(const char *a, size_t n, const char *b)
2233{
2234 if (mutt_strn_equal(a, b, n))
2235 {
2236 /* at this point we know that 'b' is at least 'n' chars long */
2237 if ((b[n] == '\n') || ((b[n] == '\r') && (b[n + 1] == '\n')))
2238 return true;
2239 }
2240 return false;
2241}
2242
2250static int pgp_check_traditional_one_body(FILE *fp, struct Body *b)
2251{
2252 char buf[8192] = { 0 };
2253 bool rc = false;
2254
2255 bool sgn = false;
2256 bool enc = false;
2257
2258 if (b->type != TYPE_TEXT)
2259 return 0;
2260
2261 struct Buffer *tempfile = buf_pool_get();
2262 buf_mktemp(tempfile);
2264 {
2265 unlink(buf_string(tempfile));
2266 goto cleanup;
2267 }
2268
2269 FILE *fp_tmp = mutt_file_fopen(buf_string(tempfile), "r");
2270 if (!fp_tmp)
2271 {
2272 unlink(buf_string(tempfile));
2273 goto cleanup;
2274 }
2275
2276 while (fgets(buf, sizeof(buf), fp_tmp))
2277 {
2278 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2279 if (plen != 0)
2280 {
2281 if (MESSAGE(buf + plen))
2282 {
2283 enc = true;
2284 break;
2285 }
2286 else if (SIGNED_MESSAGE(buf + plen))
2287 {
2288 sgn = true;
2289 break;
2290 }
2291 }
2292 }
2293 mutt_file_fclose(&fp_tmp);
2294 unlink(buf_string(tempfile));
2295
2296 if (!enc && !sgn)
2297 goto cleanup;
2298
2299 /* fix the content type */
2300
2301 mutt_param_set(&b->parameter, "format", "fixed");
2302 mutt_param_set(&b->parameter, "x-action", enc ? "pgp-encrypted" : "pgp-signed");
2303
2304 rc = true;
2305
2306cleanup:
2307 buf_pool_release(&tempfile);
2308 return rc;
2309}
2310
2314bool pgp_gpgme_check_traditional(FILE *fp, struct Body *b, bool just_one)
2315{
2316 bool rc = false;
2317 for (; b; b = b->next)
2318 {
2319 if (!just_one && is_multipart(b))
2320 {
2321 rc = (pgp_gpgme_check_traditional(fp, b->parts, false) || rc);
2322 }
2323 else if (b->type == TYPE_TEXT)
2324 {
2326 if (r)
2327 rc = (rc || r);
2328 else
2329 rc = (pgp_check_traditional_one_body(fp, b) || rc);
2330 }
2331
2332 if (just_one)
2333 break;
2334 }
2335 return rc;
2336}
2337
2341void pgp_gpgme_invoke_import(const char *fname)
2342{
2343 gpgme_ctx_t ctx = create_gpgme_context(false);
2344 gpgme_data_t keydata = NULL;
2345 gpgme_import_result_t impres = NULL;
2346 gpgme_import_status_t st = NULL;
2347 bool any;
2348
2349 FILE *fp_in = mutt_file_fopen(fname, "r");
2350 if (!fp_in)
2351 {
2352 mutt_perror("%s", fname);
2353 goto leave;
2354 }
2355 /* Note that the stream, "fp_in", needs to be kept open while the keydata
2356 * is used. */
2357 gpgme_error_t err = gpgme_data_new_from_stream(&keydata, fp_in);
2358 if (err != GPG_ERR_NO_ERROR)
2359 {
2360 mutt_error(_("error allocating data object: %s"), gpgme_strerror(err));
2361 goto leave;
2362 }
2363
2364 err = gpgme_op_import(ctx, keydata);
2365 if (err != GPG_ERR_NO_ERROR)
2366 {
2367 mutt_error(_("Error importing key: %s"), gpgme_strerror(err));
2368 goto leave;
2369 }
2370
2371 /* Print infos about the imported keys to stdout. */
2372 impres = gpgme_op_import_result(ctx);
2373 if (!impres)
2374 {
2375 fputs("oops: no import result returned\n", stdout);
2376 goto leave;
2377 }
2378
2379 for (st = impres->imports; st; st = st->next)
2380 {
2381 if (st->result)
2382 continue;
2383 printf("key %s imported (", NONULL(st->fpr));
2384 /* Note that we use the singular even if it is possible that
2385 * several uids etc are new. This simply looks better. */
2386 any = false;
2387 if (st->status & GPGME_IMPORT_SECRET)
2388 {
2389 printf("secret parts");
2390 any = true;
2391 }
2392 if ((st->status & GPGME_IMPORT_NEW))
2393 {
2394 printf("%snew key", any ? ", " : "");
2395 any = true;
2396 }
2397 if ((st->status & GPGME_IMPORT_UID))
2398 {
2399 printf("%snew uid", any ? ", " : "");
2400 any = true;
2401 }
2402 if ((st->status & GPGME_IMPORT_SIG))
2403 {
2404 printf("%snew sig", any ? ", " : "");
2405 any = true;
2406 }
2407 if ((st->status & GPGME_IMPORT_SUBKEY))
2408 {
2409 printf("%snew subkey", any ? ", " : "");
2410 any = true;
2411 }
2412 printf("%s)\n", any ? "" : "not changed");
2413 /* Fixme: Should we lookup each imported key and print more infos? */
2414 }
2415 /* Now print keys which failed the import. Unfortunately in most
2416 * cases gpg will bail out early and not tell GPGME about. */
2417 /* FIXME: We could instead use the new GPGME_AUDITLOG_DIAG to show
2418 * the actual gpg diagnostics. But I fear that would clutter the
2419 * output too much. Maybe a dedicated prompt or option to do this
2420 * would be helpful. */
2421 for (st = impres->imports; st; st = st->next)
2422 {
2423 if (st->result == 0)
2424 continue;
2425 printf("key %s import failed: %s\n", NONULL(st->fpr), gpgme_strerror(st->result));
2426 }
2427 fflush(stdout);
2428
2429leave:
2430 gpgme_release(ctx);
2431 gpgme_data_release(keydata);
2432 mutt_file_fclose(&fp_in);
2433}
2434
2450static void copy_clearsigned(gpgme_data_t data, struct State *state, char *charset)
2451{
2452 char buf[8192] = { 0 };
2453 bool complete, armor_header;
2454 FILE *fp = NULL;
2455
2456 char *fname = data_object_to_tempfile(data, &fp);
2457 if (!fname)
2458 {
2459 mutt_file_fclose(&fp);
2460 return;
2461 }
2462 unlink(fname);
2463 FREE(&fname);
2464
2465 /* fromcode comes from the MIME Content-Type charset label. It might
2466 * be a wrong label, so we want the ability to do corrections via
2467 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
2469
2470 for (complete = true, armor_header = true;
2471 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
2472 {
2473 if (!complete)
2474 {
2475 if (!armor_header)
2476 state_puts(state, buf);
2477 continue;
2478 }
2479
2480 if (BEGIN_PGP_SIGNATURE(buf))
2481 break;
2482
2483 if (armor_header)
2484 {
2485 if (buf[0] == '\n')
2486 armor_header = false;
2487 continue;
2488 }
2489
2490 if (state->prefix)
2491 state_puts(state, state->prefix);
2492
2493 if ((buf[0] == '-') && (buf[1] == ' '))
2494 state_puts(state, buf + 2);
2495 else
2496 state_puts(state, buf);
2497 }
2498
2501}
2502
2506int pgp_gpgme_application_handler(struct Body *b, struct State *state)
2507{
2508 int needpass = -1;
2509 bool pgp_keyblock = false;
2510 bool clearsign = false;
2511 long bytes;
2512 LOFF_T last_pos;
2513 LOFF_T block_begin;
2514 LOFF_T block_end;
2515 char buf[8192] = { 0 };
2516 FILE *fp_out = NULL;
2517
2518 gpgme_error_t err = GPG_ERR_NO_ERROR;
2519 gpgme_data_t armored_data = NULL;
2520
2521 bool maybe_goodsig = true;
2522 bool have_any_sigs = false;
2523
2524 char body_charset[256] = { 0 }; /* Only used for clearsigned messages. */
2525 char *gpgcharset = NULL;
2526
2527 mutt_debug(LL_DEBUG2, "Entering handler\n");
2528
2529 /* For clearsigned messages we won't be able to get a character set
2530 * but we know that this may only be text thus we assume Latin-1 here. */
2531 if (!mutt_body_get_charset(b, body_charset, sizeof(body_charset)))
2532 mutt_str_copy(body_charset, "iso-8859-1", sizeof(body_charset));
2533
2534 if (!mutt_file_seek(state->fp_in, b->offset, SEEK_SET))
2535 {
2536 return -1;
2537 }
2538 last_pos = b->offset;
2539
2540 for (bytes = b->length; bytes > 0;)
2541 {
2542 // record before the fgets in case it is a BEGIN block
2543 block_begin = last_pos;
2544
2545 if (!fgets(buf, sizeof(buf), state->fp_in))
2546 break;
2547
2548 LOFF_T offset = ftello(state->fp_in);
2549 if (offset < 0)
2550 {
2551 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2552 offset = 0;
2553 }
2554 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
2555 last_pos = offset;
2556
2557 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
2558 if (plen != 0)
2559 {
2560 needpass = 0;
2561 clearsign = false;
2562 pgp_keyblock = false;
2563
2564 if (MESSAGE(buf + plen))
2565 {
2566 needpass = 1;
2567 }
2568 else if (SIGNED_MESSAGE(buf + plen))
2569 {
2570 clearsign = true;
2571 }
2572 else if (PUBLIC_KEY_BLOCK(buf + plen))
2573 {
2574 pgp_keyblock = true;
2575 }
2576 else
2577 {
2578 /* XXX we may wish to recode here */
2579 if (state->prefix)
2580 state_puts(state, state->prefix);
2581 state_puts(state, buf);
2582 continue;
2583 }
2584
2585 /* Find the end of armored block. */
2586 while ((bytes > 0) && (fgets(buf, sizeof(buf) - 1, state->fp_in) != NULL))
2587 {
2588 offset = ftello(state->fp_in);
2589 if (offset < 0)
2590 {
2591 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2592 offset = 0;
2593 }
2594 bytes -= (offset - last_pos); /* don't rely on mutt_strlen(buf) */
2595 last_pos = offset;
2596
2597 if (needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
2598 {
2599 break;
2600 }
2601
2602 if (!needpass && (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
2603 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf)))
2604 {
2605 break;
2606 }
2607
2608 // remember optional Charset: armor header as defined by rfc4880
2609 if (mutt_strn_equal("Charset: ", buf, 9))
2610 {
2611 size_t l = 0;
2612 FREE(&gpgcharset);
2613 gpgcharset = mutt_str_dup(buf + 9);
2614 if ((l = mutt_str_len(gpgcharset)) > 0 && gpgcharset[l - 1] == '\n')
2615 gpgcharset[l - 1] = 0;
2616 if (!mutt_ch_check_charset(gpgcharset, 0))
2617 mutt_str_replace(&gpgcharset, "UTF-8");
2618 }
2619 }
2620 block_end = ftello(state->fp_in);
2621 if (block_end < 0)
2622 {
2623 mutt_debug(LL_DEBUG1, "ftello() failed on fd %d\n", fileno(state->fp_in));
2624 block_end = 0;
2625 }
2626
2627 have_any_sigs = (have_any_sigs || (clearsign && (state->flags & STATE_VERIFY)));
2628
2629 /* Copy PGP material to an data container */
2630 armored_data = file_to_data_object(state->fp_in, block_begin, block_end - block_begin);
2631 fseeko(state->fp_in, block_end, 0);
2632
2633 /* Invoke PGP if needed */
2634 if (pgp_keyblock)
2635 {
2636 pgp_gpgme_extract_keys(armored_data, &fp_out);
2637 }
2638 else if (!clearsign || (state->flags & STATE_VERIFY))
2639 {
2640 gpgme_data_t plaintext = create_gpgme_data();
2641 gpgme_ctx_t ctx = create_gpgme_context(false);
2642
2643 if (clearsign)
2644 {
2645 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2646 }
2647 else
2648 {
2649 err = gpgme_op_decrypt_verify(ctx, armored_data, plaintext);
2650 if (gpg_err_code(err) == GPG_ERR_NO_DATA)
2651 {
2652 /* Decrypt verify can't handle signed only messages. */
2653 gpgme_data_seek(armored_data, 0, SEEK_SET);
2654 /* Must release plaintext so that we supply an uninitialized object. */
2655 gpgme_data_release(plaintext);
2656 plaintext = create_gpgme_data();
2657 err = gpgme_op_verify(ctx, armored_data, NULL, plaintext);
2658 }
2659 }
2660 redraw_if_needed(ctx);
2661
2662 gpgme_decrypt_result_t result = gpgme_op_decrypt_result(ctx);
2663 if (result && (state->flags & STATE_DISPLAY))
2664 show_encryption_info(state, result);
2665
2666 if (err != GPG_ERR_NO_ERROR)
2667 {
2668 char errbuf[200] = { 0 };
2669
2670 snprintf(errbuf, sizeof(errbuf) - 1,
2671 _("Error: decryption/verification failed: %s\n"), gpgme_strerror(err));
2672 state_puts(state, errbuf);
2673 }
2674 else
2675 {
2676 /* Decryption/Verification succeeded */
2677
2678 mutt_message(_("PGP message successfully decrypted"));
2679
2680 bool sig_stat = false;
2681 char *tmpfname = NULL;
2682
2683 /* Check whether signatures have been verified. */
2684 gpgme_verify_result_t verify_result = gpgme_op_verify_result(ctx);
2685 if (verify_result->signatures)
2686 sig_stat = true;
2687
2688 have_any_sigs = false;
2689 maybe_goodsig = false;
2690 if ((state->flags & STATE_DISPLAY) && sig_stat)
2691 {
2692 int res;
2693 int idx;
2694 bool anybad = false;
2695
2696 state_attach_puts(state, _("[-- Begin signature information --]\n"));
2697 have_any_sigs = true;
2698 for (idx = 0; (res = show_one_sig_status(ctx, idx, state)) != -1; idx++)
2699 {
2700 if (res == 1)
2701 anybad = true;
2702 }
2703 if (!anybad && idx)
2704 maybe_goodsig = true;
2705
2706 state_attach_puts(state, _("[-- End signature information --]\n\n"));
2707 }
2708
2709 tmpfname = data_object_to_tempfile(plaintext, &fp_out);
2710 if (tmpfname)
2711 {
2712 unlink(tmpfname);
2713 FREE(&tmpfname);
2714 }
2715 else
2716 {
2717 mutt_file_fclose(&fp_out);
2718 state_puts(state, _("Error: copy data failed\n"));
2719 }
2720 }
2721 gpgme_data_release(plaintext);
2722 gpgme_release(ctx);
2723 }
2724
2725 /* Now, copy cleartext to the screen. NOTE - we expect that PGP
2726 * outputs utf-8 cleartext. This may not always be true, but it
2727 * seems to be a reasonable guess. */
2728 if (state->flags & STATE_DISPLAY)
2729 {
2730 if (needpass)
2731 state_attach_puts(state, _("[-- BEGIN PGP MESSAGE --]\n\n"));
2732 else if (pgp_keyblock)
2733 state_attach_puts(state, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
2734 else
2735 state_attach_puts(state, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
2736 }
2737
2738 if (clearsign)
2739 {
2740 copy_clearsigned(armored_data, state, body_charset);
2741 }
2742 else if (fp_out)
2743 {
2744 int c;
2745 char *expected_charset = gpgcharset && *gpgcharset ? gpgcharset : "utf-8";
2746 fseek(fp_out, 0, SEEK_SET);
2747 clearerr(fp_out);
2748 struct FgetConv *fc = mutt_ch_fgetconv_open(fp_out, expected_charset,
2750 while ((c = mutt_ch_fgetconv(fc)) != EOF)
2751 {
2752 state_putc(state, c);
2753 if ((c == '\n') && state->prefix)
2754 state_puts(state, state->prefix);
2755 }
2757 }
2758
2759 if (state->flags & STATE_DISPLAY)
2760 {
2761 state_putc(state, '\n');
2762 if (needpass)
2763 state_attach_puts(state, _("[-- END PGP MESSAGE --]\n"));
2764 else if (pgp_keyblock)
2765 state_attach_puts(state, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
2766 else
2767 state_attach_puts(state, _("[-- END PGP SIGNED MESSAGE --]\n"));
2768 }
2769
2770 // Multiple PGP blocks can exist, so clean these up in each loop
2771 gpgme_data_release(armored_data);
2772 mutt_file_fclose(&fp_out);
2773 }
2774 else
2775 {
2776 /* A traditional PGP part may mix signed and unsigned content */
2777 /* XXX we may wish to recode here */
2778 if (state->prefix)
2779 state_puts(state, state->prefix);
2780 state_puts(state, buf);
2781 }
2782 }
2783 FREE(&gpgcharset);
2784
2785 b->goodsig = (maybe_goodsig && have_any_sigs);
2786
2787 if (needpass == -1)
2788 {
2789 state_attach_puts(state, _("[-- Error: could not find beginning of PGP message --]\n\n"));
2790 return 1;
2791 }
2792 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2793
2794 return err;
2795}
2796
2803int pgp_gpgme_encrypted_handler(struct Body *b, struct State *state)
2804{
2805 int is_signed = 0;
2806 int rc = 0;
2807
2808 mutt_debug(LL_DEBUG2, "Entering handler\n");
2809
2810 FILE *fp_out = mutt_file_mkstemp();
2811 if (!fp_out)
2812 {
2813 mutt_perror(_("Can't create temporary file"));
2814 if (state->flags & STATE_DISPLAY)
2815 {
2816 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2817 }
2818 return -1;
2819 }
2820
2821 struct Body *tattach = decrypt_part(b, state, fp_out, false, &is_signed);
2822 if (tattach)
2823 {
2824 tattach->goodsig = is_signed > 0;
2825
2826 if (state->flags & STATE_DISPLAY)
2827 {
2828 state_attach_puts(state, is_signed ?
2829 _("[-- The following data is PGP/MIME signed and encrypted --]\n") :
2830 _("[-- The following data is PGP/MIME encrypted --]\n"));
2831 mutt_protected_headers_handler(tattach, state);
2832 }
2833
2834 /* Store any protected headers in the parent so they can be
2835 * accessed for index updates after the handler recursion is done.
2836 * This is done before the handler to prevent a nested encrypted
2837 * handler from freeing the headers. */
2839 b->mime_headers = tattach->mime_headers;
2840 tattach->mime_headers = NULL;
2841
2842 FILE *fp_save = state->fp_in;
2843 state->fp_in = fp_out;
2844 rc = mutt_body_handler(tattach, state);
2845 state->fp_in = fp_save;
2846
2847 /* Embedded multipart signed protected headers override the
2848 * encrypted headers. We need to do this after the handler so
2849 * they can be printed in the pager. */
2850 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2851 {
2853 b->mime_headers = tattach->parts->mime_headers;
2854 tattach->parts->mime_headers = NULL;
2855 }
2856
2857 /* if a multipart/signed is the _only_ sub-part of a
2858 * multipart/encrypted, cache signature verification
2859 * status. */
2860 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2861 b->goodsig |= tattach->goodsig;
2862
2863 if (state->flags & STATE_DISPLAY)
2864 {
2865 state_attach_puts(state, is_signed ?
2866 _("[-- End of PGP/MIME signed and encrypted data --]\n") :
2867 _("[-- End of PGP/MIME encrypted data --]\n"));
2868 }
2869
2870 mutt_body_free(&tattach);
2871 mutt_message(_("PGP message successfully decrypted"));
2872 }
2873 else
2874 {
2875#ifdef USE_AUTOCRYPT
2876 if (!OptAutocryptGpgme)
2877#endif
2878 {
2879 mutt_error(_("Could not decrypt PGP message"));
2880 }
2881 rc = -1;
2882 }
2883
2884 mutt_file_fclose(&fp_out);
2885 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2886
2887 return rc;
2888}
2889
2893int smime_gpgme_application_handler(struct Body *b, struct State *state)
2894{
2895 int is_signed = 0;
2896 int rc = 0;
2897
2898 mutt_debug(LL_DEBUG2, "Entering handler\n");
2899
2900 /* clear out any mime headers before the handler, so they can't be spoofed. */
2902 b->warnsig = false;
2903 FILE *fp_out = mutt_file_mkstemp();
2904 if (!fp_out)
2905 {
2906 mutt_perror(_("Can't create temporary file"));
2907 if (state->flags & STATE_DISPLAY)
2908 {
2909 state_attach_puts(state, _("[-- Error: could not create temporary file --]\n"));
2910 }
2911 return -1;
2912 }
2913
2914 struct Body *tattach = decrypt_part(b, state, fp_out, true, &is_signed);
2915 if (tattach)
2916 {
2917 tattach->goodsig = is_signed > 0;
2918
2919 if (state->flags & STATE_DISPLAY)
2920 {
2921 state_attach_puts(state, is_signed ?
2922 _("[-- The following data is S/MIME signed --]\n") :
2923 _("[-- The following data is S/MIME encrypted --]\n"));
2924 mutt_protected_headers_handler(tattach, state);
2925 }
2926
2927 /* Store any protected headers in the parent so they can be
2928 * accessed for index updates after the handler recursion is done.
2929 * This is done before the handler to prevent a nested encrypted
2930 * handler from freeing the headers. */
2932 b->mime_headers = tattach->mime_headers;
2933 tattach->mime_headers = NULL;
2934
2935 FILE *fp_save = state->fp_in;
2936 state->fp_in = fp_out;
2937 rc = mutt_body_handler(tattach, state);
2938 state->fp_in = fp_save;
2939
2940 /* Embedded multipart signed protected headers override the
2941 * encrypted headers. We need to do this after the handler so
2942 * they can be printed in the pager. */
2943 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
2944 {
2946 b->mime_headers = tattach->parts->mime_headers;
2947 tattach->parts->mime_headers = NULL;
2948 }
2949
2950 /* if a multipart/signed is the _only_ sub-part of a multipart/encrypted,
2951 * cache signature verification status. */
2952 if (mutt_is_multipart_signed(tattach) && !tattach->next)
2953 {
2954 b->goodsig = tattach->goodsig;
2955 if (!b->goodsig)
2956 b->warnsig = tattach->warnsig;
2957 }
2958 else if (tattach->goodsig)
2959 {
2960 b->goodsig = true;
2961 b->warnsig = tattach->warnsig;
2962 }
2963
2964 if (state->flags & STATE_DISPLAY)
2965 {
2966 state_attach_puts(state, is_signed ? _("[-- End of S/MIME signed data --]\n") :
2967 _("[-- End of S/MIME encrypted data --]\n"));
2968 }
2969
2970 mutt_body_free(&tattach);
2971 }
2972
2973 mutt_file_fclose(&fp_out);
2974 mutt_debug(LL_DEBUG2, "Leaving handler\n");
2975
2976 return rc;
2977}
2978
2985unsigned int key_check_cap(gpgme_key_t key, enum KeyCap cap)
2986{
2987 unsigned int rc = 0;
2988
2989 switch (cap)
2990 {
2992 rc = key->can_encrypt;
2993 if (rc == 0)
2994 {
2995 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
2996 {
2997 rc = subkey->can_encrypt;
2998 if (rc != 0)
2999 break;
3000 }
3001 }
3002 break;
3003 case KEY_CAP_CAN_SIGN:
3004 rc = key->can_sign;
3005 if (rc == 0)
3006 {
3007 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3008 {
3009 rc = subkey->can_sign;
3010 if (rc != 0)
3011 break;
3012 }
3013 }
3014 break;
3016 rc = key->can_certify;
3017 if (rc == 0)
3018 {
3019 for (gpgme_subkey_t subkey = key->subkeys; subkey; subkey = subkey->next)
3020 {
3021 rc = subkey->can_certify;
3022 if (rc != 0)
3023 break;
3024 }
3025 }
3026 break;
3027 }
3028
3029 return rc;
3030}
3031
3041static char *list_to_pattern(struct ListHead *list)
3042{
3043 char *pattern = NULL;
3044 char *p = NULL;
3045 const char *s = NULL;
3046 size_t n;
3047
3048 n = 0;
3049 struct ListNode *np = NULL;
3050 STAILQ_FOREACH(np, list, entries)
3051 {
3052 for (s = np->data; *s; s++)
3053 {
3054 if ((*s == '%') || (*s == '+'))
3055 n += 2;
3056 n++;
3057 }
3058 n++; /* delimiter or end of string */
3059 }
3060 n++; /* make sure to allocate at least one byte */
3061 p = MUTT_MEM_CALLOC(n, char);
3062 pattern = p;
3063 STAILQ_FOREACH(np, list, entries)
3064 {
3065 s = np->data;
3066 if (*s)
3067 {
3068 if (np != STAILQ_FIRST(list))
3069 *p++ = ' ';
3070 for (s = np->data; *s; s++)
3071 {
3072 if (*s == '%')
3073 {
3074 *p++ = '%';
3075 *p++ = '2';
3076 *p++ = '5';
3077 }
3078 else if (*s == '+')
3079 {
3080 *p++ = '%';
3081 *p++ = '2';
3082 *p++ = 'B';
3083 }
3084 else if (*s == ' ')
3085 {
3086 *p++ = '+';
3087 }
3088 else
3089 {
3090 *p++ = *s;
3091 }
3092 }
3093 }
3094 }
3095 *p = '\0';
3096 return pattern;
3097}
3098
3109static struct CryptKeyInfo *get_candidates(struct ListHead *hints, SecurityFlags app, int secret)
3110{
3111 struct CryptKeyInfo *db = NULL;
3112 struct CryptKeyInfo *k = NULL;
3113 struct CryptKeyInfo **kend = NULL;
3114 gpgme_error_t err = GPG_ERR_NO_ERROR;
3115 gpgme_ctx_t ctx = NULL;
3116 gpgme_key_t key = NULL;
3117 int idx;
3118 gpgme_user_id_t uid = NULL;
3119
3120 char *pattern = list_to_pattern(hints);
3121 if (!pattern)
3122 return NULL;
3123
3124 ctx = create_gpgme_context(0);
3125 db = NULL;
3126 kend = &db;
3127
3128 if ((app & APPLICATION_PGP))
3129 {
3130 /* It's all a mess. That old GPGME expects different things depending on
3131 * the protocol. For gpg we don't need percent escaped pappert but simple
3132 * strings passed in an array to the keylist_ext_start function. */
3133 size_t n = 0;
3134 struct ListNode *np = NULL;
3135 STAILQ_FOREACH(np, hints, entries)
3136 {
3137 if (np->data && *np->data)
3138 n++;
3139 }
3140 if (n == 0)
3141 goto no_pgphints;
3142
3143 char **patarr = MUTT_MEM_CALLOC(n + 1, char *);
3144 n = 0;
3145 STAILQ_FOREACH(np, hints, entries)
3146 {
3147 if (np->data && *np->data)
3148 patarr[n++] = mutt_str_dup(np->data);
3149 }
3150 patarr[n] = NULL;
3151 err = gpgme_op_keylist_ext_start(ctx, (const char **) patarr, secret, 0);
3152 for (n = 0; patarr[n]; n++)
3153 FREE(&patarr[n]);
3154 FREE(&patarr);
3155 if (err != GPG_ERR_NO_ERROR)
3156 {
3157 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3158 gpgme_release(ctx);
3159 FREE(&pattern);
3160 return NULL;
3161 }
3162
3163 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3164 {
3165 KeyFlags flags = KEYFLAG_NONE;
3166
3168 flags |= KEYFLAG_CANENCRYPT;
3170 flags |= KEYFLAG_CANSIGN;
3171
3172 if (key->revoked)
3173 flags |= KEYFLAG_REVOKED;
3174 if (key->expired)
3175 flags |= KEYFLAG_EXPIRED;
3176 if (key->disabled)
3177 flags |= KEYFLAG_DISABLED;
3178
3179 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3180 {
3181 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3182 k->kobj = key;
3183 gpgme_key_ref(k->kobj);
3184 k->idx = idx;
3185 k->uid = uid->uid;
3186 k->flags = flags;
3187 if (uid->revoked)
3188 k->flags |= KEYFLAG_REVOKED;
3189 k->validity = uid->validity;
3190 *kend = k;
3191 kend = &k->next;
3192 }
3193 gpgme_key_unref(key);
3194 }
3195 if (gpg_err_code(err) != GPG_ERR_EOF)
3196 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3197 gpgme_op_keylist_end(ctx);
3198 no_pgphints:;
3199 }
3200
3201 if ((app & APPLICATION_SMIME))
3202 {
3203 /* and now look for x509 certificates */
3204 gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS);
3205 err = gpgme_op_keylist_start(ctx, pattern, 0);
3206 if (err != GPG_ERR_NO_ERROR)
3207 {
3208 mutt_error(_("gpgme_op_keylist_start failed: %s"), gpgme_strerror(err));
3209 gpgme_release(ctx);
3210 FREE(&pattern);
3211 return NULL;
3212 }
3213
3214 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3215 {
3216 KeyFlags flags = KEYFLAG_ISX509;
3217
3219 flags |= KEYFLAG_CANENCRYPT;
3221 flags |= KEYFLAG_CANSIGN;
3222
3223 if (key->revoked)
3224 flags |= KEYFLAG_REVOKED;
3225 if (key->expired)
3226 flags |= KEYFLAG_EXPIRED;
3227 if (key->disabled)
3228 flags |= KEYFLAG_DISABLED;
3229
3230 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3231 {
3232 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3233 k->kobj = key;
3234 gpgme_key_ref(k->kobj);
3235 k->idx = idx;
3236 k->uid = uid->uid;
3237 k->flags = flags;
3238 if (uid->revoked)
3239 k->flags |= KEYFLAG_REVOKED;
3240 k->validity = uid->validity;
3241 *kend = k;
3242 kend = &k->next;
3243 }
3244 gpgme_key_unref(key);
3245 }
3246 if (gpg_err_code(err) != GPG_ERR_EOF)
3247 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3248 gpgme_op_keylist_end(ctx);
3249 }
3250
3251 gpgme_release(ctx);
3252 FREE(&pattern);
3253 return db;
3254}
3255
3264static void crypt_add_string_to_hints(const char *str, struct ListHead *hints)
3265{
3266 char *scratch = mutt_str_dup(str);
3267 if (!scratch)
3268 return;
3269
3270 for (char *t = strtok(scratch, " ,.:\"()<>\n"); t; t = strtok(NULL, " ,.:\"()<>\n"))
3271 {
3272 if (strlen(t) > 3)
3274 }
3275
3276 FREE(&scratch);
3277}
3278
3288static struct CryptKeyInfo *crypt_getkeybyaddr(struct Address *a,
3289 KeyFlags abilities, unsigned int app,
3290 bool *forced_valid, bool oppenc_mode)
3291{
3292 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3293
3294 int multi = false;
3295 int this_key_has_strong = false;
3296 int this_key_has_addr_match = false;
3297 int match = false;
3298
3299 struct CryptKeyInfo *keys = NULL;
3300 struct CryptKeyInfo *k = NULL;
3301 struct CryptKeyInfo *the_strong_valid_key = NULL;
3302 struct CryptKeyInfo *a_valid_addrmatch_key = NULL;
3303 struct CryptKeyInfo *matches = NULL;
3304 struct CryptKeyInfo **matches_endp = &matches;
3305
3306 if (a && a->mailbox)
3308 if (a && a->personal)
3310
3311 if (!oppenc_mode)
3312 mutt_message(_("Looking for keys matching \"%s\"..."), a ? buf_string(a->mailbox) : "");
3313 keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3314
3315 mutt_list_free(&hints);
3316
3317 if (!keys)
3318 return NULL;
3319
3320 mutt_debug(LL_DEBUG5, "looking for %s <%s>\n",
3321 a ? buf_string(a->personal) : "", a ? buf_string(a->mailbox) : "");
3322
3323 for (k = keys; k; k = k->next)
3324 {
3325 mutt_debug(LL_DEBUG5, " looking at key: %s '%.15s'\n", crypt_keyid(k), k->uid);
3326
3327 if (abilities && !(k->flags & abilities))
3328 {
3329 mutt_debug(LL_DEBUG2, " insufficient abilities: Has %x, want %x\n", k->flags, abilities);
3330 continue;
3331 }
3332
3333 this_key_has_strong = false; /* strong and valid match */
3334 this_key_has_addr_match = false;
3335 match = false; /* any match */
3336
3337 struct AddressList alist = TAILQ_HEAD_INITIALIZER(alist);
3338 mutt_addrlist_parse(&alist, k->uid);
3339 struct Address *ka = NULL;
3340 TAILQ_FOREACH(ka, &alist, entries)
3341 {
3342 int validity = crypt_id_matches_addr(a, ka, k);
3343
3344 if (validity & CRYPT_KV_MATCH) /* something matches */
3345 {
3346 match = true;
3347
3348 if ((validity & CRYPT_KV_VALID) && (validity & CRYPT_KV_ADDR))
3349 {
3350 if (validity & CRYPT_KV_STRONGID)
3351 {
3352 if (the_strong_valid_key && (the_strong_valid_key->kobj != k->kobj))
3353 multi = true;
3354 this_key_has_strong = true;
3355 }
3356 else
3357 {
3358 this_key_has_addr_match = true;
3359 }
3360 }
3361 }
3362 }
3363 mutt_addrlist_clear(&alist);
3364
3365 if (match)
3366 {
3367 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3368 *matches_endp = tmp;
3369 matches_endp = &tmp->next;
3370
3371 if (this_key_has_strong)
3372 the_strong_valid_key = tmp;
3373 else if (this_key_has_addr_match)
3374 a_valid_addrmatch_key = tmp;
3375 }
3376 }
3377
3378 crypt_key_free(&keys);
3379
3380 if (matches)
3381 {
3382 if (oppenc_mode || !isatty(STDIN_FILENO))
3383 {
3384 const bool c_crypt_opportunistic_encrypt_strong_keys =
3385 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt_strong_keys");
3386 if (the_strong_valid_key)
3387 k = crypt_copy_key(the_strong_valid_key);
3388 else if (a_valid_addrmatch_key && !c_crypt_opportunistic_encrypt_strong_keys)
3389 k = crypt_copy_key(a_valid_addrmatch_key);
3390 else
3391 k = NULL;
3392 }
3393 else if (the_strong_valid_key && !multi)
3394 {
3395 /* There was precisely one strong match on a valid ID.
3396 * Proceed without asking the user. */
3397 k = crypt_copy_key(the_strong_valid_key);
3398 }
3399 else
3400 {
3401 /* Else: Ask the user. */
3402 k = dlg_gpgme(matches, a, NULL, app, forced_valid);
3403 }
3404
3405 crypt_key_free(&matches);
3406 }
3407 else
3408 {
3409 k = NULL;
3410 }
3411
3412 return k;
3413}
3414
3423static struct CryptKeyInfo *crypt_getkeybystr(const char *p, KeyFlags abilities,
3424 unsigned int app, bool *forced_valid)
3425{
3426 struct ListHead hints = STAILQ_HEAD_INITIALIZER(hints);
3427 struct CryptKeyInfo *matches = NULL;
3428 struct CryptKeyInfo **matches_endp = &matches;
3429 struct CryptKeyInfo *k = NULL;
3430 const char *ps = NULL;
3431 const char *pl = NULL;
3432 const char *phint = NULL;
3433
3434 mutt_message(_("Looking for keys matching \"%s\"..."), p);
3435
3436 const char *pfcopy = crypt_get_fingerprint_or_id(p, &phint, &pl, &ps);
3437 crypt_add_string_to_hints(phint, &hints);
3438 struct CryptKeyInfo *keys = get_candidates(&hints, app, (abilities & KEYFLAG_CANSIGN));
3439 mutt_list_free(&hints);
3440
3441 if (!keys)
3442 {
3443 FREE(&pfcopy);
3444 return NULL;
3445 }
3446
3447 for (k = keys; k; k = k->next)
3448 {
3449 if (abilities && !(k->flags & abilities))
3450 continue;
3451
3452 mutt_debug(LL_DEBUG5, "matching \"%s\" against key %s, \"%s\": ", p,
3453 crypt_long_keyid(k), k->uid);
3454
3455 if ((*p == '\0') || (pfcopy && mutt_istr_equal(pfcopy, crypt_fpr(k))) ||
3456 (pl && mutt_istr_equal(pl, crypt_long_keyid(k))) ||
3457 (ps && mutt_istr_equal(ps, crypt_short_keyid(k))) || mutt_istr_find(k->uid, p))
3458 {
3459 mutt_debug(LL_DEBUG5, "match\n");
3460
3461 struct CryptKeyInfo *tmp = crypt_copy_key(k);
3462 *matches_endp = tmp;
3463 matches_endp = &tmp->next;
3464 }
3465 else
3466 {
3467 mutt_debug(LL_DEBUG5, "no match\n");
3468 }
3469 }
3470
3471 FREE(&pfcopy);
3472 crypt_key_free(&keys);
3473
3474 if (matches)
3475 {
3476 if (isatty(STDIN_FILENO))
3477 {
3478 k = dlg_gpgme(matches, NULL, p, app, forced_valid);
3479
3480 crypt_key_free(&matches);
3481 return k;
3482 }
3483 else
3484 {
3485 if (crypt_keys_are_valid(matches))
3486 return matches;
3487
3488 crypt_key_free(&matches);
3489 return NULL;
3490 }
3491 }
3492
3493 return NULL;
3494}
3495
3508static struct CryptKeyInfo *crypt_ask_for_key(const char *tag, const char *whatfor,
3509 KeyFlags abilities,
3510 unsigned int app, bool *forced_valid)
3511{
3513 struct CryptKeyInfo *key = NULL;
3514 struct CryptCache *l = NULL;
3515 struct Buffer *resp = buf_pool_get();
3516
3518
3519 if (whatfor)
3520 {
3521 for (l = (struct CryptCache *) mod_data->gpgme_id_defaults; l; l = l->next)
3522 {
3523 if (mutt_istr_equal(whatfor, l->what))
3524 {
3525 buf_strcpy(resp, l->dflt);
3526 break;
3527 }
3528 }
3529 }
3530
3531 while (true)
3532 {
3533 buf_reset(resp);
3534 if (mw_get_field(tag, resp, MUTT_COMP_NONE, HC_OTHER, NULL, NULL) != 0)
3535 {
3536 goto done;
3537 }
3538
3539 if (buf_is_empty(resp))
3540 goto done;
3541
3542 if (whatfor)
3543 {
3544 if (l)
3545 {
3546 mutt_str_replace(&l->dflt, buf_string(resp));
3547 }
3548 else
3549 {
3550 l = MUTT_MEM_MALLOC(1, struct CryptCache);
3551 l->next = (struct CryptCache *) mod_data->gpgme_id_defaults;
3552 mod_data->gpgme_id_defaults = l;
3553 l->what = mutt_str_dup(whatfor);
3554 l->dflt = buf_strdup(resp);
3555 }
3556 }
3557
3558 key = crypt_getkeybystr(buf_string(resp), abilities, app, forced_valid);
3559 if (key)
3560 goto done;
3561
3562 mutt_error(_("No matching keys found for \"%s\""), buf_string(resp));
3563 }
3564
3565done:
3566 buf_pool_release(&resp);
3567 return key;
3568}
3569
3581static char *find_keys(const struct AddressList *addrlist, unsigned int app, bool oppenc_mode)
3582{
3583 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
3584 struct ListNode *crypt_hook = NULL;
3585 const char *keyid = NULL;
3586 char *keylist = NULL;
3587 size_t keylist_size = 0;
3588 size_t keylist_used = 0;
3589 struct Address *p = NULL;
3590 struct CryptKeyInfo *k_info = NULL;
3591 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
3592 char buf[1024] = { 0 };
3593 bool forced_valid = false;
3594 bool key_selected;
3595 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
3596
3597 struct Address *a = NULL;
3598 const bool c_crypt_confirm_hook = cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
3599 /* Iterate through each recipient address to find an encryption key */
3600 TAILQ_FOREACH(a, addrlist, entries)
3601 {
3602 key_selected = false;
3603 /* Check for crypt-hook overrides for this recipient */
3604 mutt_crypt_hook(&crypt_hook_list, a);
3605 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
3606 do
3607 {
3608 p = a;
3609 forced_valid = false;
3610 k_info = NULL;
3611
3612 /* If a crypt-hook provides a key ID, confirm with the user unless
3613 * in opportunistic encryption mode */
3614 if (crypt_hook)
3615 {
3616 keyid = crypt_hook->data;
3617 enum QuadOption ans = MUTT_YES;
3618 if (!oppenc_mode && c_crypt_confirm_hook && isatty(STDIN_FILENO))
3619 {
3620 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid,
3621 buf_string(p->mailbox));
3622 ans = query_yesorno_help(buf, MUTT_YES, NeoMutt->sub, "crypt_confirm_hook");
3623 }
3624 if (ans == MUTT_YES)
3625 {
3626 if (crypt_is_numerical_keyid(keyid))
3627 {
3628 if (mutt_strn_equal(keyid, "0x", 2))
3629 keyid += 2;
3630 goto bypass_selection; /* you don't see this. */
3631 }
3632
3633 /* check for e-mail address */
3634 mutt_addrlist_clear(&hookal);
3635 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
3636 {
3637 mutt_addrlist_qualify(&hookal, fqdn);
3638 p = TAILQ_FIRST(&hookal);
3639 }
3640 else if (!oppenc_mode)
3641 {
3642 k_info = crypt_getkeybystr(keyid, KEYFLAG_CANENCRYPT, app, &forced_valid);
3643 }
3644 }
3645 else if (ans == MUTT_NO)
3646 {
3647 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
3648 {
3649 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3650 continue;
3651 }
3652 }
3653 else if (ans == MUTT_ABORT)
3654 {
3655 FREE(&keylist);
3656 mutt_addrlist_clear(&hookal);
3657 mutt_list_free(&crypt_hook_list);
3658 return NULL;
3659 }
3660 }
3661
3662 /* If no key found yet, try looking up by address in the keyring */
3663 if (!k_info)
3664 {
3665 k_info = crypt_getkeybyaddr(p, KEYFLAG_CANENCRYPT, app, &forced_valid, oppenc_mode);
3666 }
3667
3668 /* Last resort: prompt the user to enter a key ID interactively */
3669 if (!k_info && !oppenc_mode && isatty(STDIN_FILENO))
3670 {
3671 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), buf_string(p->mailbox));
3672
3673 k_info = crypt_ask_for_key(buf, buf_string(p->mailbox),
3674 KEYFLAG_CANENCRYPT, app, &forced_valid);
3675 }
3676
3677 if (!k_info)
3678 {
3679 FREE(&keylist);
3680 mutt_addrlist_clear(&hookal);
3681 mutt_list_free(&crypt_hook_list);
3682 return NULL;
3683 }
3684
3685 keyid = crypt_fpr_or_lkeyid(k_info);
3686
3687 bypass_selection:
3688 /* Append the selected key ID to the space-separated keylist string */
3689 keylist_size += mutt_str_len(keyid) + 4 + 1;
3690 MUTT_MEM_REALLOC(&keylist, keylist_size, char);
3691 sprintf(keylist + keylist_used, "%s0x%s%s", keylist_used ? " " : "",
3692 keyid, forced_valid ? "!" : "");
3693 keylist_used = mutt_str_len(keylist);
3694
3695 key_selected = true;
3696
3697 crypt_key_free(&k_info);
3698 mutt_addrlist_clear(&hookal);
3699
3700 if (crypt_hook)
3701 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
3702
3703 } while (crypt_hook);
3704
3705 mutt_list_free(&crypt_hook_list);
3706 }
3707 return keylist;
3708}
3709
3713char *pgp_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3714{
3715 return find_keys(addrlist, APPLICATION_PGP, oppenc_mode);
3716}
3717
3721char *smime_gpgme_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
3722{
3723 return find_keys(addrlist, APPLICATION_SMIME, oppenc_mode);
3724}
3725
3726#ifdef USE_AUTOCRYPT
3740{
3741 int rc = -1;
3742 gpgme_error_t err = GPG_ERR_NO_ERROR;
3743 gpgme_key_t key = NULL;
3744 gpgme_user_id_t uid = NULL;
3745 struct CryptKeyInfo *results = NULL;
3746 struct CryptKeyInfo *k = NULL;
3747 struct CryptKeyInfo **kend = NULL;
3748 struct CryptKeyInfo *choice = NULL;
3749
3750 gpgme_ctx_t ctx = create_gpgme_context(false);
3751
3752 /* list all secret keys */
3753 if (gpgme_op_keylist_start(ctx, NULL, 1))
3754 goto cleanup;
3755
3756 kend = &results;
3757
3758 while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR)
3759 {
3761
3766
3767 if (key->revoked)
3769 if (key->expired)
3771 if (key->disabled)
3773
3774 int idx;
3775 for (idx = 0, uid = key->uids; uid; idx++, uid = uid->next)
3776 {
3777 k = MUTT_MEM_CALLOC(1, struct CryptKeyInfo);
3778 k->kobj = key;
3779 gpgme_key_ref(k->kobj);
3780 k->idx = idx;
3781 k->uid = uid->uid;
3782 k->flags = flags;
3783 if (uid->revoked)
3784 k->flags |= KEYFLAG_REVOKED;
3785 k->validity = uid->validity;
3786 *kend = k;
3787 kend = &k->next;
3788 }
3789 gpgme_key_unref(key);
3790 }
3791 if (gpg_err_code(err) != GPG_ERR_EOF)
3792 mutt_error(_("gpgme_op_keylist_next failed: %s"), gpgme_strerror(err));
3793 gpgme_op_keylist_end(ctx);
3794
3795 if (!results)
3796 {
3797 /* L10N: mutt_gpgme_select_secret_key() tries to list all secret keys to choose
3798 from. This error is displayed if no results were found. */
3799 mutt_error(_("No secret keys found"));
3800 goto cleanup;
3801 }
3802
3803 choice = dlg_gpgme(results, NULL, "*", APPLICATION_PGP, NULL);
3804 if (!(choice && choice->kobj && choice->kobj->subkeys && choice->kobj->subkeys->fpr))
3805 goto cleanup;
3806 buf_strcpy(keyid, choice->kobj->subkeys->fpr);
3807
3808 rc = 0;
3809
3810cleanup:
3811 crypt_key_free(&choice);
3812 crypt_key_free(&results);
3813 gpgme_release(ctx);
3814 return rc;
3815}
3816#endif
3817
3822{
3823 gpgme_ctx_t ctx = NULL;
3824 gpgme_key_t export_keys[2] = { 0 };
3825 gpgme_data_t keydata = NULL;
3826 struct Body *att = NULL;
3827 char buf[1024] = { 0 };
3828
3829 OptPgpCheckTrust = false;
3830
3831 struct CryptKeyInfo *key = crypt_ask_for_key(_("Please enter the key ID: "), NULL,
3833 if (!key)
3834 goto bail;
3835 export_keys[0] = key->kobj;
3836 export_keys[1] = NULL;
3837
3838 ctx = create_gpgme_context(false);
3839 gpgme_set_armor(ctx, 1);
3840 keydata = create_gpgme_data();
3841 gpgme_error_t err = gpgme_op_export_keys(ctx, export_keys, 0, keydata);
3842 if (err != GPG_ERR_NO_ERROR)
3843 {
3844 mutt_error(_("Error exporting key: %s"), gpgme_strerror(err));
3845 goto bail;
3846 }
3847
3848 char *tempf = data_object_to_tempfile(keydata, NULL);
3849 if (!tempf)
3850 goto bail;
3851
3852 att = mutt_body_new();
3853 /* tempf is a newly allocated string, so this is correct: */
3854 att->filename = tempf;
3855 att->unlink = true;
3856 att->use_disp = false;
3857 att->type = TYPE_APPLICATION;
3858 att->subtype = mutt_str_dup("pgp-keys");
3859 /* L10N: MIME description for exported (attached) keys.
3860 You can translate this entry to a non-ASCII string (it will be encoded),
3861 but it may be safer to keep it untranslated. */
3862 snprintf(buf, sizeof(buf), _("PGP Key 0x%s"), crypt_keyid(key));
3863 att->description = mutt_str_dup(buf);
3865
3866 att->length = mutt_file_get_size(tempf);
3867
3868bail:
3869 crypt_key_free(&key);
3870 gpgme_data_release(keydata);
3871 gpgme_release(ctx);
3872
3873 return att;
3874}
3875
3879static void init_common(void)
3880{
3881 /* this initialization should only run one time, but it may be called by
3882 * either pgp_gpgme_init or smime_gpgme_init */
3883 static bool has_run = false;
3884 if (has_run)
3885 return;
3886
3887 gpgme_check_version(NULL);
3888 gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
3889#ifdef ENABLE_NLS
3890 gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
3891#endif
3892 has_run = true;
3893}
3894
3898static void init_pgp(void)
3899{
3900 if (gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP) != GPG_ERR_NO_ERROR)
3901 {
3902 mutt_error(_("GPGME: OpenPGP protocol not available"));
3903 }
3904}
3905
3909static void init_smime(void)
3910{
3911 if (gpgme_engine_check_version(GPGME_PROTOCOL_CMS) != GPG_ERR_NO_ERROR)
3912 {
3913 mutt_error(_("GPGME: CMS protocol not available"));
3914 }
3915}
3916
3921{
3922 init_common();
3923 init_pgp();
3924}
3925
3930{
3931 init_common();
3932 init_smime();
3933}
3934
3941static SecurityFlags gpgme_send_menu(struct Email *e, bool is_smime)
3942{
3943 struct CryptKeyInfo *p = NULL;
3944 const char *prompt = NULL;
3945 const char *letters = NULL;
3946 const char *choices = NULL;
3947 int choice;
3948
3949 if (is_smime)
3951 else
3953
3954 /* Opportunistic encrypt is controlling encryption.
3955 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
3956 * letter choices for those.
3957 */
3958 const bool c_crypt_opportunistic_encrypt = cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
3959 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
3960 {
3961 if (is_smime)
3962 {
3963 /* L10N: S/MIME options (opportunistic encryption is on) */
3964 prompt = _("S/MIME (s)ign, sign (a)s, (p)gp, (c)lear, or (o)ppenc mode off?");
3965 /* L10N: S/MIME options (opportunistic encryption is on) */
3966 letters = _("sapco");
3967 choices = "SapCo";
3968 }
3969 else
3970 {
3971 /* L10N: PGP options (opportunistic encryption is on) */
3972 prompt = _("PGP (s)ign, sign (a)s, s/(m)ime, (c)lear, or (o)ppenc mode off?");
3973 /* L10N: PGP options (opportunistic encryption is on) */
3974 letters = _("samco");
3975 choices = "SamCo";
3976 }
3977 }
3978 else if (c_crypt_opportunistic_encrypt)
3979 {
3980 /* Opportunistic encryption option is set, but is toggled off for this message. */
3981 if (is_smime)
3982 {
3983 /* L10N: S/MIME options (opportunistic encryption is off) */
3984 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp, (c)lear, or (o)ppenc mode?");
3985 /* L10N: S/MIME options (opportunistic encryption is off) */
3986 letters = _("esabpco");
3987 choices = "esabpcO";
3988 }
3989 else
3990 {
3991 /* L10N: PGP options (opportunistic encryption is off) */
3992 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime, (c)lear, or (o)ppenc mode?");
3993 /* L10N: PGP options (opportunistic encryption is off) */
3994 letters = _("esabmco");
3995 choices = "esabmcO";
3996 }
3997 }
3998 else
3999 {
4000 /* Opportunistic encryption is unset */
4001 if (is_smime)
4002 {
4003 /* L10N: S/MIME options */
4004 prompt = _("S/MIME (e)ncrypt, (s)ign, sign (a)s, (b)oth, (p)gp or (c)lear?");
4005 /* L10N: S/MIME options */
4006 letters = _("esabpc");
4007 choices = "esabpc";
4008 }
4009 else
4010 {
4011 /* L10N: PGP options */
4012 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, s/(m)ime or (c)lear?");
4013 /* L10N: PGP options */
4014 letters = _("esabmc");
4015 choices = "esabmc";
4016 }
4017 }
4018
4019 choice = mw_multi_choice(prompt, letters);
4020 if (choice > 0)
4021 {
4022 switch (choices[choice - 1])
4023 {
4024 case 'a': /* sign (a)s */
4025 p = crypt_ask_for_key(_("Sign as: "), NULL, KEYFLAG_CANSIGN,
4026 is_smime ? APPLICATION_SMIME : APPLICATION_PGP, NULL);
4027 if (p)
4028 {
4029 char input_signas[128] = { 0 };
4030 snprintf(input_signas, sizeof(input_signas), "0x%s", crypt_fpr_or_lkeyid(p));
4031
4032 if (is_smime)
4033 cs_subset_str_string_set(NeoMutt->sub, "smime_sign_as", input_signas, NULL);
4034 else
4035 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
4036
4037 crypt_key_free(&p);
4038
4039 e->security |= SEC_SIGN;
4040 }
4041 break;
4042
4043 case 'b': /* (b)oth */
4044 e->security |= (SEC_ENCRYPT | SEC_SIGN);
4045 break;
4046
4047 case 'C':
4048 e->security &= ~SEC_SIGN;
4049 break;
4050
4051 case 'c': /* (c)lear */
4052 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
4053 break;
4054
4055 case 'e': /* (e)ncrypt */
4056 e->security |= SEC_ENCRYPT;
4057 e->security &= ~SEC_SIGN;
4058 break;
4059
4060 case 'm': /* (p)gp or s/(m)ime */
4061 case 'p':
4062 is_smime = !is_smime;
4063 if (is_smime)
4064 {
4067 }
4068 else
4069 {
4072 }
4074 break;
4075
4076 case 'O': /* oppenc mode on */
4079 break;
4080
4081 case 'o': /* oppenc mode off */
4083 break;
4084
4085 case 'S': /* (s)ign in oppenc mode */
4086 e->security |= SEC_SIGN;
4087 break;
4088
4089 case 's': /* (s)ign */
4090 e->security &= ~SEC_ENCRYPT;
4091 e->security |= SEC_SIGN;
4092 break;
4093
4094 default:
4095 break;
4096 }
4097 }
4098
4099 return e->security;
4100}
4101
4106{
4107 return gpgme_send_menu(e, false);
4108}
4109
4114{
4115 return gpgme_send_menu(e, true);
4116}
4117
4123static bool verify_sender(struct Email *e)
4124{
4126 struct Address *sender = NULL;
4127 bool rc = true;
4128
4129 if (!TAILQ_EMPTY(&e->env->from))
4130 {
4132 sender = TAILQ_FIRST(&e->env->from);
4133 }
4134 else if (!TAILQ_EMPTY(&e->env->sender))
4135 {
4137 sender = TAILQ_FIRST(&e->env->sender);
4138 }
4139
4140 if (sender)
4141 {
4142 if ((gpgme_key_t) mod_data->signature_key)
4143 {
4144 gpgme_key_t key = (gpgme_key_t) mod_data->signature_key;
4145 gpgme_user_id_t uid = NULL;
4146 int sender_length = buf_len(sender->mailbox);
4147 for (uid = key->uids; uid && rc; uid = uid->next)
4148 {
4149 int uid_length = strlen(uid->email);
4150 if ((uid->email[0] == '<') && (uid->email[uid_length - 1] == '>') &&
4151 (uid_length == (sender_length + 2)))
4152 {
4153 const char *at_sign = strchr(uid->email + 1, '@');
4154 if (at_sign)
4155 {
4156 /* Assume address is 'mailbox@domainname'.
4157 * The mailbox part is case-sensitive,
4158 * the domainname is not. (RFC2821) */
4159 const char *tmp_email = uid->email + 1;
4160 const char *tmp_sender = buf_string(sender->mailbox);
4161 /* length of mailbox part including '@' */
4162 int mailbox_length = at_sign - tmp_email + 1;
4163 int domainname_length = sender_length - mailbox_length;
4164 int mailbox_match;
4165 int domainname_match;
4166
4167 mailbox_match = mutt_strn_equal(tmp_email, tmp_sender, mailbox_length);
4168 tmp_email += mailbox_length;
4169 tmp_sender += mailbox_length;
4170 domainname_match = (mutt_istrn_cmp(tmp_email, tmp_sender, domainname_length) == 0);
4171 if (mailbox_match && domainname_match)
4172 rc = false;
4173 }
4174 else
4175 {
4176 if (mutt_strn_equal(uid->email + 1, buf_string(sender->mailbox), sender_length))
4177 rc = false;
4178 }
4179 }
4180 }
4181 }
4182 else
4183 {
4184 mutt_any_key_to_continue(_("Failed to verify sender"));
4185 }
4186 }
4187 else
4188 {
4189 mutt_any_key_to_continue(_("Failed to figure out sender"));
4190 }
4191
4192 if ((gpgme_key_t) mod_data->signature_key)
4193 {
4194 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4195 mod_data->signature_key = NULL;
4196 }
4197
4198 return rc;
4199}
4200
4204int smime_gpgme_verify_sender(struct Email *e, struct Message *msg)
4205{
4206 return verify_sender(e);
4207}
4208
4212void pgp_gpgme_set_sender(const char *sender)
4213{
4215 mutt_debug(LL_DEBUG2, "setting to: %s\n", sender);
4216 FREE(&mod_data->current_sender);
4217 mod_data->current_sender = mutt_str_dup(sender);
4218}
4219
4225{
4226 return GPGME_VERSION;
4227}
4228
4234{
4235 struct CryptCache *l = mod_data->gpgme_id_defaults;
4236 while (l)
4237 {
4238 struct CryptCache *next = l->next;
4239 FREE(&l->what);
4240 FREE(&l->dflt);
4241 FREE(&l);
4242 l = next;
4243 }
4244 mod_data->gpgme_id_defaults = NULL;
4245
4246 if ((gpgme_key_t) mod_data->signature_key)
4247 {
4248 gpgme_key_unref((gpgme_key_t) mod_data->signature_key);
4249 mod_data->signature_key = NULL;
4250 }
4251}
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:99
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 MUTT_MEM_MALLOC(n, T)
Definition memory.h:73
#define FREE(x)
Free memory and set the pointer to NULL.
Definition memory.h:92
#define MUTT_MEM_REALLOC(pptr, n, T)
Definition memory.h:78
#define MUTT_MEM_CALLOC(n, T)
Definition memory.h:68
@ 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:37
char * data
Pointer to data.
Definition buffer.h:38
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