1 /**
2 * @file
3 * PGP sign, encrypt, check routines
4 *
5 * @authors
6 * Copyright (C) 1996-1997,2000,2010 Michael R. Elkins <me@mutt.org>
7 * Copyright (C) 1998-2005 Thomas Roessler <roessler@does-not-exist.org>
8 * Copyright (C) 2004 g10 Code GmbH
9 * Copyright (C) 2019 Pietro Cerutti <gahr@gahr.ch>
10 *
11 * @copyright
12 * This program is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free Software
14 * Foundation, either version 2 of the License, or (at your option) any later
15 * version.
16 *
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 /**
27 * @page crypt_pgp PGP sign, encrypt, check routines
28 *
29 * This file contains all of the PGP routines necessary to sign, encrypt,
30 * verify and decrypt PGP messages in either the new PGP/MIME format, or in
31 * the older Application/Pgp format. It also contains some code to cache the
32 * user's passphrase for repeat use when decrypting or signing a message.
33 */
34
35 #include "config.h"
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include "mutt/lib.h"
43 #include "address/lib.h"
44 #include "config/lib.h"
45 #include "email/lib.h"
46 #include "core/lib.h"
47 #include "gui/lib.h"
48 #include "mutt.h"
49 #include "lib.h"
50 #include "attach/lib.h"
51 #include "question/lib.h"
52 #include "send/lib.h"
53 #include "crypt.h"
54 #include "cryptglue.h"
55 #include "handler.h"
56 #include "hook.h"
57 #include "muttlib.h"
58 #include "options.h"
59 #include "pgpinvoke.h"
60 #include "pgpkey.h"
61 #include "pgpmicalg.h"
62 #ifdef CRYPT_BACKEND_CLASSIC_PGP
63 #include "pgp.h"
64 #include "pgplib.h"
65 #endif
66
67 char PgpPass[1024];
68 time_t PgpExptime = 0; /* when does the cached passphrase expire? */
69
70 /**
71 * pgp_class_void_passphrase - Implements CryptModuleSpecs::void_passphrase() - @ingroup crypto_void_passphrase
72 */
pgp_class_void_passphrase(void)73 void pgp_class_void_passphrase(void)
74 {
75 memset(PgpPass, 0, sizeof(PgpPass));
76 PgpExptime = 0;
77 }
78
79 /**
80 * pgp_class_valid_passphrase - Implements CryptModuleSpecs::valid_passphrase() - @ingroup crypto_valid_passphrase
81 */
pgp_class_valid_passphrase(void)82 bool pgp_class_valid_passphrase(void)
83 {
84 if (pgp_use_gpg_agent())
85 {
86 *PgpPass = '\0';
87 return true; /* handled by gpg-agent */
88 }
89
90 if (mutt_date_epoch() < PgpExptime)
91 {
92 /* Use cached copy. */
93 return true;
94 }
95
96 pgp_class_void_passphrase();
97
98 if (mutt_get_field_unbuffered(_("Enter PGP passphrase:"), PgpPass,
99 sizeof(PgpPass), MUTT_PASS) == 0)
100 {
101 const long c_pgp_timeout = cs_subset_long(NeoMutt->sub, "pgp_timeout");
102 PgpExptime = mutt_date_add_timeout(mutt_date_epoch(), c_pgp_timeout);
103 return true;
104 }
105 else
106 PgpExptime = 0;
107
108 return false;
109 }
110
111 /**
112 * pgp_use_gpg_agent - Does the user want to use the gpg agent?
113 * @retval true The user wants to use the gpg agent
114 *
115 * @note This functions sets the environment variable `$GPG_TTY`
116 */
pgp_use_gpg_agent(void)117 bool pgp_use_gpg_agent(void)
118 {
119 char *tty = NULL;
120
121 /* GnuPG 2.1 no longer exports GPG_AGENT_INFO */
122 const bool c_pgp_use_gpg_agent =
123 cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
124 if (!c_pgp_use_gpg_agent)
125 return false;
126
127 tty = ttyname(0);
128 if (tty)
129 {
130 setenv("GPG_TTY", tty, 0);
131 mutt_envlist_set("GPG_TTY", tty, false);
132 }
133
134 return true;
135 }
136
137 /**
138 * key_parent - Find a key's parent (if it's a subkey)
139 * @param k PGP key
140 * @retval ptr Parent key
141 */
key_parent(struct PgpKeyInfo * k)142 static struct PgpKeyInfo *key_parent(struct PgpKeyInfo *k)
143 {
144 const bool c_pgp_ignore_subkeys =
145 cs_subset_bool(NeoMutt->sub, "pgp_ignore_subkeys");
146 if ((k->flags & KEYFLAG_SUBKEY) && k->parent && c_pgp_ignore_subkeys)
147 k = k->parent;
148
149 return k;
150 }
151
152 /**
153 * pgp_long_keyid - Get a key's long id
154 * @param k PGP key
155 * @retval ptr Long key id string
156 */
pgp_long_keyid(struct PgpKeyInfo * k)157 char *pgp_long_keyid(struct PgpKeyInfo *k)
158 {
159 k = key_parent(k);
160
161 return k->keyid;
162 }
163
164 /**
165 * pgp_short_keyid - Get a key's short id
166 * @param k PGP key
167 * @retval ptr Short key id string
168 */
pgp_short_keyid(struct PgpKeyInfo * k)169 char *pgp_short_keyid(struct PgpKeyInfo *k)
170 {
171 k = key_parent(k);
172
173 return k->keyid + 8;
174 }
175
176 /**
177 * pgp_this_keyid - Get the ID of this key
178 * @param k PGP key
179 * @retval ptr Long/Short key id string
180 *
181 * @note The string returned depends on `$pgp_long_ids`
182 */
pgp_this_keyid(struct PgpKeyInfo * k)183 char *pgp_this_keyid(struct PgpKeyInfo *k)
184 {
185 const bool c_pgp_long_ids = cs_subset_bool(NeoMutt->sub, "pgp_long_ids");
186 if (c_pgp_long_ids)
187 return k->keyid;
188 return k->keyid + 8;
189 }
190
191 /**
192 * pgp_keyid - Get the ID of the main (parent) key
193 * @param k PGP key
194 * @retval ptr Long/Short key id string
195 */
pgp_keyid(struct PgpKeyInfo * k)196 char *pgp_keyid(struct PgpKeyInfo *k)
197 {
198 k = key_parent(k);
199
200 return pgp_this_keyid(k);
201 }
202
203 /**
204 * pgp_fingerprint - Get the key's fingerprint
205 * @param k PGP key
206 * @retval ptr Fingerprint string
207 */
pgp_fingerprint(struct PgpKeyInfo * k)208 static char *pgp_fingerprint(struct PgpKeyInfo *k)
209 {
210 k = key_parent(k);
211
212 return k->fingerprint;
213 }
214
215 /**
216 * pgp_fpr_or_lkeyid - Get the fingerprint or long keyid
217 * @param k PGP key
218 * @retval ptr String fingerprint or long keyid
219 *
220 * Grab the longest key identifier available: fingerprint or else
221 * the long keyid.
222 *
223 * The longest available should be used for internally identifying
224 * the key and for invoking pgp commands.
225 */
pgp_fpr_or_lkeyid(struct PgpKeyInfo * k)226 char *pgp_fpr_or_lkeyid(struct PgpKeyInfo *k)
227 {
228 char *fingerprint = pgp_fingerprint(k);
229 return fingerprint ? fingerprint : pgp_long_keyid(k);
230 }
231
232 /* ----------------------------------------------------------------------------
233 * Routines for handing PGP input.
234 */
235
236 /**
237 * pgp_copy_checksig - Copy PGP output and look for signs of a good signature
238 * @param fp_in File to read from
239 * @param fp_out File to write to
240 * @retval 0 Success
241 * @retval -1 Error
242 */
pgp_copy_checksig(FILE * fp_in,FILE * fp_out)243 static int pgp_copy_checksig(FILE *fp_in, FILE *fp_out)
244 {
245 if (!fp_in || !fp_out)
246 return -1;
247
248 int rc = -1;
249
250 const struct Regex *c_pgp_good_sign =
251 cs_subset_regex(NeoMutt->sub, "pgp_good_sign");
252 if (c_pgp_good_sign && c_pgp_good_sign->regex)
253 {
254 char *line = NULL;
255 size_t linelen;
256
257 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NO_FLAGS)))
258 {
259 if (mutt_regex_match(c_pgp_good_sign, line))
260 {
261 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
262 rc = 0;
263 }
264 else
265 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
266
267 if (mutt_strn_equal(line, "[GNUPG:] ", 9))
268 continue;
269 fputs(line, fp_out);
270 fputc('\n', fp_out);
271 }
272 FREE(&line);
273 }
274 else
275 {
276 mutt_debug(LL_DEBUG2, "No pattern\n");
277 mutt_file_copy_stream(fp_in, fp_out);
278 rc = 1;
279 }
280
281 return rc;
282 }
283
284 /**
285 * pgp_check_pgp_decryption_okay_regex - Check PGP output to look for successful outcome
286 * @param fp_in File to read from
287 * @retval 0 Success
288 * @retval -1 Error
289 *
290 * Checks PGP output messages to look for the $pgp_decryption_okay message.
291 * This protects against messages with multipart/encrypted headers but which
292 * aren't actually encrypted.
293 */
pgp_check_pgp_decryption_okay_regex(FILE * fp_in)294 static int pgp_check_pgp_decryption_okay_regex(FILE *fp_in)
295 {
296 int rc = -1;
297
298 const struct Regex *c_pgp_decryption_okay =
299 cs_subset_regex(NeoMutt->sub, "pgp_decryption_okay");
300 if (c_pgp_decryption_okay && c_pgp_decryption_okay->regex)
301 {
302 char *line = NULL;
303 size_t linelen;
304
305 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NO_FLAGS)))
306 {
307 if (mutt_regex_match(c_pgp_decryption_okay, line))
308 {
309 mutt_debug(LL_DEBUG2, "\"%s\" matches regex\n", line);
310 rc = 0;
311 break;
312 }
313 else
314 mutt_debug(LL_DEBUG2, "\"%s\" doesn't match regex\n", line);
315 }
316 FREE(&line);
317 }
318 else
319 {
320 mutt_debug(LL_DEBUG2, "No pattern\n");
321 rc = 1;
322 }
323
324 return rc;
325 }
326
327 /**
328 * pgp_check_decryption_okay - Check GPG output for status codes
329 * @param fp_in File to read from
330 * @retval 1 - no patterns were matched (if delegated to decryption_okay_regex)
331 * @retval 0 - DECRYPTION_OKAY was seen, with no PLAINTEXT outside
332 * @retval -1 - No decryption status codes were encountered
333 * @retval -2 - PLAINTEXT was encountered outside of DECRYPTION delimiters
334 * @retval -3 - DECRYPTION_FAILED was encountered
335 *
336 * Checks GnuPGP status fd output for various status codes indicating
337 * an issue. If $pgp_check_gpg_decrypt_status_fd is unset, it falls
338 * back to the old behavior of just scanning for $pgp_decryption_okay.
339 *
340 * pgp_decrypt_part() should fail if the part is not encrypted, so we return
341 * less than 0 to indicate part or all was NOT actually encrypted.
342 *
343 * On the other hand, for pgp_application_pgp_handler(), a
344 * "BEGIN PGP MESSAGE" could indicate a signed and armored message.
345 * For that we allow -1 and -2 as "valid" (with a warning).
346 */
pgp_check_decryption_okay(FILE * fp_in)347 static int pgp_check_decryption_okay(FILE *fp_in)
348 {
349 int rc = -1;
350 char *line = NULL, *s = NULL;
351 size_t linelen;
352 int inside_decrypt = 0;
353
354 const bool c_pgp_check_gpg_decrypt_status_fd =
355 cs_subset_bool(NeoMutt->sub, "pgp_check_gpg_decrypt_status_fd");
356 if (!c_pgp_check_gpg_decrypt_status_fd)
357 return pgp_check_pgp_decryption_okay_regex(fp_in);
358
359 while ((line = mutt_file_read_line(line, &linelen, fp_in, NULL, MUTT_RL_NO_FLAGS)))
360 {
361 size_t plen = mutt_str_startswith(line, "[GNUPG:] ");
362 if (plen == 0)
363 continue;
364 s = line + plen;
365 mutt_debug(LL_DEBUG2, "checking \"%s\"\n", line);
366 if (mutt_str_startswith(s, "BEGIN_DECRYPTION"))
367 inside_decrypt = 1;
368 else if (mutt_str_startswith(s, "END_DECRYPTION"))
369 inside_decrypt = 0;
370 else if (mutt_str_startswith(s, "PLAINTEXT"))
371 {
372 if (!inside_decrypt)
373 {
374 mutt_debug(LL_DEBUG2,
375 " PLAINTEXT encountered outside of DECRYPTION\n");
376 rc = -2;
377 break;
378 }
379 }
380 else if (mutt_str_startswith(s, "DECRYPTION_FAILED"))
381 {
382 mutt_debug(LL_DEBUG2, " DECRYPTION_FAILED encountered. Failure\n");
383 rc = -3;
384 break;
385 }
386 else if (mutt_str_startswith(s, "DECRYPTION_OKAY"))
387 {
388 /* Don't break out because we still have to check for
389 * PLAINTEXT outside of the decryption boundaries. */
390 mutt_debug(LL_DEBUG2, " DECRYPTION_OKAY encountered\n");
391 rc = 0;
392 }
393 }
394 FREE(&line);
395
396 return rc;
397 }
398
399 /**
400 * pgp_copy_clearsigned - Copy a clearsigned message, stripping the signature
401 * @param fp_in File to read from
402 * @param s State to use
403 * @param charset Charset of file
404 *
405 * XXX charset handling: We assume that it is safe to do character set
406 * decoding first, dash decoding second here, while we do it the other way
407 * around in the main handler.
408 *
409 * (Note that we aren't worse than Outlook &c in this, and also note that we
410 * can successfully handle anything produced by any existing versions of neomutt.)
411 */
pgp_copy_clearsigned(FILE * fp_in,struct State * s,char * charset)412 static void pgp_copy_clearsigned(FILE *fp_in, struct State *s, char *charset)
413 {
414 char buf[8192];
415 bool complete, armor_header;
416
417 rewind(fp_in);
418
419 /* fromcode comes from the MIME Content-Type charset label. It might
420 * be a wrong label, so we want the ability to do corrections via
421 * charset-hooks. Therefore we set flags to MUTT_ICONV_HOOK_FROM. */
422 const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
423 struct FgetConv *fc =
424 mutt_ch_fgetconv_open(fp_in, charset, c_charset, MUTT_ICONV_HOOK_FROM);
425
426 for (complete = true, armor_header = true;
427 mutt_ch_fgetconvs(buf, sizeof(buf), fc); complete = (strchr(buf, '\n')))
428 {
429 if (!complete)
430 {
431 if (!armor_header)
432 state_puts(s, buf);
433 continue;
434 }
435
436 if (mutt_str_equal(buf, "-----BEGIN PGP SIGNATURE-----\n"))
437 break;
438
439 if (armor_header)
440 {
441 char *p = mutt_str_skip_whitespace(buf);
442 if (*p == '\0')
443 armor_header = false;
444 continue;
445 }
446
447 if (s->prefix)
448 state_puts(s, s->prefix);
449
450 if ((buf[0] == '-') && (buf[1] == ' '))
451 state_puts(s, buf + 2);
452 else
453 state_puts(s, buf);
454 }
455
456 mutt_ch_fgetconv_close(&fc);
457 }
458
459 /**
460 * pgp_class_application_handler - Implements CryptModuleSpecs::application_handler() - @ingroup crypto_application_handler
461 */
pgp_class_application_handler(struct Body * m,struct State * s)462 int pgp_class_application_handler(struct Body *m, struct State *s)
463 {
464 bool could_not_decrypt = false;
465 int decrypt_okay_rc = 0;
466 int needpass = -1;
467 bool pgp_keyblock = false;
468 bool clearsign = false;
469 int rc = -1;
470 int c = 1;
471 long bytes;
472 LOFF_T last_pos, offset;
473 char buf[8192];
474 FILE *fp_pgp_out = NULL, *fp_pgp_in = NULL, *fp_pgp_err = NULL;
475 FILE *fp_tmp = NULL;
476 pid_t pid;
477 struct Buffer *tmpfname = mutt_buffer_pool_get();
478
479 bool maybe_goodsig = true;
480 bool have_any_sigs = false;
481
482 char *gpgcharset = NULL;
483 char body_charset[256];
484 mutt_body_get_charset(m, body_charset, sizeof(body_charset));
485
486 if (fseeko(s->fp_in, m->offset, SEEK_SET) != 0)
487 {
488 mutt_perror("fseeko");
489 return -1;
490 }
491 last_pos = m->offset;
492
493 for (bytes = m->length; bytes > 0;)
494 {
495 if (!fgets(buf, sizeof(buf), s->fp_in))
496 break;
497
498 offset = ftello(s->fp_in);
499 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
500 last_pos = offset;
501
502 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
503 if (plen != 0)
504 {
505 clearsign = false;
506 could_not_decrypt = false;
507 decrypt_okay_rc = 0;
508
509 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
510 needpass = 1;
511 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
512 {
513 clearsign = true;
514 needpass = 0;
515 }
516 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
517 {
518 needpass = 0;
519 pgp_keyblock = true;
520 }
521 else
522 {
523 /* XXX we may wish to recode here */
524 if (s->prefix)
525 state_puts(s, s->prefix);
526 state_puts(s, buf);
527 continue;
528 }
529
530 have_any_sigs = have_any_sigs || (clearsign && (s->flags & MUTT_VERIFY));
531
532 /* Copy PGP material to temporary file */
533 mutt_buffer_mktemp(tmpfname);
534 fp_tmp = mutt_file_fopen(mutt_buffer_string(tmpfname), "w+");
535 if (!fp_tmp)
536 {
537 mutt_perror(mutt_buffer_string(tmpfname));
538 FREE(&gpgcharset);
539 goto out;
540 }
541
542 fputs(buf, fp_tmp);
543 while ((bytes > 0) && fgets(buf, sizeof(buf) - 1, s->fp_in))
544 {
545 offset = ftello(s->fp_in);
546 bytes -= (offset - last_pos); /* don't rely on mutt_str_len(buf) */
547 last_pos = offset;
548
549 fputs(buf, fp_tmp);
550
551 if ((needpass && mutt_str_equal("-----END PGP MESSAGE-----\n", buf)) ||
552 (!needpass &&
553 (mutt_str_equal("-----END PGP SIGNATURE-----\n", buf) ||
554 mutt_str_equal("-----END PGP PUBLIC KEY BLOCK-----\n", buf))))
555 {
556 break;
557 }
558 /* remember optional Charset: armor header as defined by RFC4880 */
559 if (mutt_str_startswith(buf, "Charset: "))
560 {
561 size_t l = 0;
562 FREE(&gpgcharset);
563 gpgcharset = mutt_str_dup(buf + 9);
564 l = mutt_str_len(gpgcharset);
565 if ((l > 0) && (gpgcharset[l - 1] == '\n'))
566 gpgcharset[l - 1] = 0;
567 if (!mutt_ch_check_charset(gpgcharset, false))
568 mutt_str_replace(&gpgcharset, "UTF-8");
569 }
570 }
571
572 /* leave fp_tmp open in case we still need it - but flush it! */
573 fflush(fp_tmp);
574
575 /* Invoke PGP if needed */
576 if (!clearsign || (s->flags & MUTT_VERIFY))
577 {
578 fp_pgp_out = mutt_file_mkstemp();
579 if (!fp_pgp_out)
580 {
581 mutt_perror(_("Can't create temporary file"));
582 goto out;
583 }
584
585 fp_pgp_err = mutt_file_mkstemp();
586 if (!fp_pgp_err)
587 {
588 mutt_perror(_("Can't create temporary file"));
589 goto out;
590 }
591
592 pid = pgp_invoke_decode(&fp_pgp_in, NULL, NULL, -1, fileno(fp_pgp_out),
593 fileno(fp_pgp_err),
594 mutt_buffer_string(tmpfname), (needpass != 0));
595 if (pid == -1)
596 {
597 mutt_file_fclose(&fp_pgp_out);
598 maybe_goodsig = false;
599 fp_pgp_in = NULL;
600 state_attach_puts(
601 s, _("[-- Error: unable to create PGP subprocess --]\n"));
602 }
603 else /* PGP started successfully */
604 {
605 if (needpass)
606 {
607 if (!pgp_class_valid_passphrase())
608 pgp_class_void_passphrase();
609 if (pgp_use_gpg_agent())
610 *PgpPass = '\0';
611 fprintf(fp_pgp_in, "%s\n", PgpPass);
612 }
613
614 mutt_file_fclose(&fp_pgp_in);
615
616 int wait_filter_rc = filter_wait(pid);
617
618 fflush(fp_pgp_err);
619 /* If we are expecting an encrypted message, verify status fd output.
620 * Note that BEGIN PGP MESSAGE does not guarantee the content is encrypted,
621 * so we need to be more selective about the value of decrypt_okay_rc.
622 *
623 * -3 indicates we actively found a DECRYPTION_FAILED.
624 * -2 and -1 indicate part or all of the content was plaintext. */
625 if (needpass)
626 {
627 rewind(fp_pgp_err);
628 decrypt_okay_rc = pgp_check_decryption_okay(fp_pgp_err);
629 if (decrypt_okay_rc <= -3)
630 mutt_file_fclose(&fp_pgp_out);
631 }
632
633 if (s->flags & MUTT_DISPLAY)
634 {
635 rewind(fp_pgp_err);
636 crypt_current_time(s, "PGP");
637 int checksig_rc = pgp_copy_checksig(fp_pgp_err, s->fp_out);
638
639 if (checksig_rc == 0)
640 have_any_sigs = true;
641 /* Sig is bad if
642 * gpg_good_sign-pattern did not match || pgp_decode_command returned not 0
643 * Sig _is_ correct if
644 * gpg_good_sign="" && pgp_decode_command returned 0 */
645 if (checksig_rc == -1 || (wait_filter_rc != 0))
646 maybe_goodsig = false;
647
648 state_attach_puts(s, _("[-- End of PGP output --]\n\n"));
649 }
650 if (pgp_use_gpg_agent())
651 {
652 mutt_need_hard_redraw();
653 }
654 }
655
656 /* treat empty result as sign of failure */
657 /* TODO: maybe on failure neomutt should include the original undecoded text. */
658 if (fp_pgp_out)
659 {
660 rewind(fp_pgp_out);
661 c = fgetc(fp_pgp_out);
662 ungetc(c, fp_pgp_out);
663 }
664 if (!clearsign && (!fp_pgp_out || (c == EOF)))
665 {
666 could_not_decrypt = true;
667 pgp_class_void_passphrase();
668 }
669
670 if ((could_not_decrypt || (decrypt_okay_rc <= -3)) && !(s->flags & MUTT_DISPLAY))
671 {
672 mutt_error(_("Could not decrypt PGP message"));
673 goto out;
674 }
675 }
676
677 /* Now, copy cleartext to the screen. */
678 if (s->flags & MUTT_DISPLAY)
679 {
680 if (needpass)
681 state_attach_puts(s, _("[-- BEGIN PGP MESSAGE --]\n\n"));
682 else if (pgp_keyblock)
683 state_attach_puts(s, _("[-- BEGIN PGP PUBLIC KEY BLOCK --]\n"));
684 else
685 state_attach_puts(s, _("[-- BEGIN PGP SIGNED MESSAGE --]\n\n"));
686 }
687
688 if (clearsign)
689 {
690 rewind(fp_tmp);
691 pgp_copy_clearsigned(fp_tmp, s, body_charset);
692 }
693 else if (fp_pgp_out)
694 {
695 struct FgetConv *fc = NULL;
696 int ch;
697 char *expected_charset = (gpgcharset && *gpgcharset) ? gpgcharset : "utf-8";
698
699 const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
700 mutt_debug(LL_DEBUG3, "pgp: recoding inline from [%s] to [%s]\n",
701 expected_charset, c_charset);
702
703 rewind(fp_pgp_out);
704 state_set_prefix(s);
705 fc = mutt_ch_fgetconv_open(fp_pgp_out, expected_charset, c_charset, MUTT_ICONV_HOOK_FROM);
706 while ((ch = mutt_ch_fgetconv(fc)) != EOF)
707 state_prefix_putc(s, ch);
708 mutt_ch_fgetconv_close(&fc);
709 }
710
711 /* Multiple PGP blocks can exist, so these need to be closed and
712 * unlinked inside the loop. */
713 mutt_file_fclose(&fp_tmp);
714 mutt_file_unlink(mutt_buffer_string(tmpfname));
715 mutt_file_fclose(&fp_pgp_out);
716 mutt_file_fclose(&fp_pgp_err);
717
718 if (s->flags & MUTT_DISPLAY)
719 {
720 state_putc(s, '\n');
721 if (needpass)
722 {
723 state_attach_puts(s, _("[-- END PGP MESSAGE --]\n"));
724 if (could_not_decrypt || (decrypt_okay_rc <= -3))
725 mutt_error(_("Could not decrypt PGP message"));
726 else if (decrypt_okay_rc < 0)
727 {
728 /* L10N: You will see this error message if (1) you are decrypting
729 (not encrypting) something and (2) it is a plaintext. So the
730 message does not mean "You failed to encrypt the message." */
731 mutt_error(_("PGP message is not encrypted"));
732 }
733 else
734 mutt_message(_("PGP message successfully decrypted"));
735 }
736 else if (pgp_keyblock)
737 state_attach_puts(s, _("[-- END PGP PUBLIC KEY BLOCK --]\n"));
738 else
739 state_attach_puts(s, _("[-- END PGP SIGNED MESSAGE --]\n"));
740 }
741 }
742 else
743 {
744 /* A traditional PGP part may mix signed and unsigned content */
745 /* XXX we may wish to recode here */
746 if (s->prefix)
747 state_puts(s, s->prefix);
748 state_puts(s, buf);
749 }
750 }
751
752 rc = 0;
753
754 out:
755 m->goodsig = (maybe_goodsig && have_any_sigs);
756
757 if (fp_tmp)
758 {
759 mutt_file_fclose(&fp_tmp);
760 mutt_file_unlink(mutt_buffer_string(tmpfname));
761 }
762 mutt_file_fclose(&fp_pgp_out);
763 mutt_file_fclose(&fp_pgp_err);
764
765 mutt_buffer_pool_release(&tmpfname);
766
767 FREE(&gpgcharset);
768
769 if (needpass == -1)
770 {
771 state_attach_puts(
772 s, _("[-- Error: could not find beginning of PGP message --]\n\n"));
773 return -1;
774 }
775
776 return rc;
777 }
778
779 /**
780 * pgp_check_traditional_one_body - Check the body of an inline PGP message
781 * @param fp File to read
782 * @param b Body to populate
783 * @retval true Success
784 * @retval false Error
785 */
pgp_check_traditional_one_body(FILE * fp,struct Body * b)786 static bool pgp_check_traditional_one_body(FILE *fp, struct Body *b)
787 {
788 struct Buffer *tempfile = NULL;
789 char buf[8192];
790 bool rc = false;
791
792 bool sgn = false;
793 bool enc = false;
794 bool key = false;
795
796 if (b->type != TYPE_TEXT)
797 goto cleanup;
798
799 tempfile = mutt_buffer_pool_get();
800 mutt_buffer_mktemp(tempfile);
801 if (mutt_decode_save_attachment(fp, b, mutt_buffer_string(tempfile), 0,
802 MUTT_SAVE_NO_FLAGS) != 0)
803 {
804 unlink(mutt_buffer_string(tempfile));
805 goto cleanup;
806 }
807
808 FILE *fp_tmp = fopen(mutt_buffer_string(tempfile), "r");
809 if (!fp_tmp)
810 {
811 unlink(mutt_buffer_string(tempfile));
812 goto cleanup;
813 }
814
815 while (fgets(buf, sizeof(buf), fp_tmp))
816 {
817 size_t plen = mutt_str_startswith(buf, "-----BEGIN PGP ");
818 if (plen != 0)
819 {
820 if (mutt_str_startswith(buf + plen, "MESSAGE-----\n"))
821 enc = true;
822 else if (mutt_str_startswith(buf + plen, "SIGNED MESSAGE-----\n"))
823 sgn = true;
824 else if (mutt_str_startswith(buf + plen, "PUBLIC KEY BLOCK-----\n"))
825 key = true;
826 }
827 }
828 mutt_file_fclose(&fp_tmp);
829 unlink(mutt_buffer_string(tempfile));
830
831 if (!enc && !sgn && !key)
832 goto cleanup;
833
834 /* fix the content type */
835
836 mutt_param_set(&b->parameter, "format", "fixed");
837 if (enc)
838 mutt_param_set(&b->parameter, "x-action", "pgp-encrypted");
839 else if (sgn)
840 mutt_param_set(&b->parameter, "x-action", "pgp-signed");
841 else if (key)
842 mutt_param_set(&b->parameter, "x-action", "pgp-keys");
843
844 rc = true;
845
846 cleanup:
847 mutt_buffer_pool_release(&tempfile);
848 return rc;
849 }
850
851 /**
852 * pgp_class_check_traditional - Implements CryptModuleSpecs::pgp_check_traditional() - @ingroup crypto_pgp_check_traditional
853 */
pgp_class_check_traditional(FILE * fp,struct Body * b,bool just_one)854 bool pgp_class_check_traditional(FILE *fp, struct Body *b, bool just_one)
855 {
856 bool rc = false;
857 int r;
858 for (; b; b = b->next)
859 {
860 if (!just_one && is_multipart(b))
861 rc = pgp_class_check_traditional(fp, b->parts, false) || rc;
862 else if (b->type == TYPE_TEXT)
863 {
864 r = mutt_is_application_pgp(b);
865 if (r)
866 rc = rc || r;
867 else
868 rc = pgp_check_traditional_one_body(fp, b) || rc;
869 }
870
871 if (just_one)
872 break;
873 }
874
875 return rc;
876 }
877
878 /**
879 * pgp_class_verify_one - Implements CryptModuleSpecs::verify_one() - @ingroup crypto_verify_one
880 */
pgp_class_verify_one(struct Body * sigbdy,struct State * s,const char * tempfile)881 int pgp_class_verify_one(struct Body *sigbdy, struct State *s, const char *tempfile)
882 {
883 FILE *fp_pgp_out = NULL;
884 pid_t pid;
885 int badsig = -1;
886 struct Buffer *sigfile = mutt_buffer_pool_get();
887
888 mutt_buffer_printf(sigfile, "%s.asc", tempfile);
889
890 FILE *fp_sig = mutt_file_fopen(mutt_buffer_string(sigfile), "w");
891 if (!fp_sig)
892 {
893 mutt_perror(mutt_buffer_string(sigfile));
894 goto cleanup;
895 }
896
897 if (fseeko(s->fp_in, sigbdy->offset, SEEK_SET) != 0)
898 {
899 mutt_perror("fseeko");
900 mutt_file_fclose(&fp_sig);
901 goto cleanup;
902 }
903 mutt_file_copy_bytes(s->fp_in, fp_sig, sigbdy->length);
904 mutt_file_fclose(&fp_sig);
905
906 FILE *fp_pgp_err = mutt_file_mkstemp();
907 if (!fp_pgp_err)
908 {
909 mutt_perror(_("Can't create temporary file"));
910 unlink(mutt_buffer_string(sigfile));
911 goto cleanup;
912 }
913
914 crypt_current_time(s, "PGP");
915
916 pid = pgp_invoke_verify(NULL, &fp_pgp_out, NULL, -1, -1, fileno(fp_pgp_err),
917 tempfile, mutt_buffer_string(sigfile));
918 if (pid != -1)
919 {
920 if (pgp_copy_checksig(fp_pgp_out, s->fp_out) >= 0)
921 badsig = 0;
922
923 mutt_file_fclose(&fp_pgp_out);
924 fflush(fp_pgp_err);
925 rewind(fp_pgp_err);
926
927 if (pgp_copy_checksig(fp_pgp_err, s->fp_out) >= 0)
928 badsig = 0;
929
930 const int rv = filter_wait(pid);
931 if (rv)
932 badsig = -1;
933
934 mutt_debug(LL_DEBUG1, "filter_wait returned %d\n", rv);
935 }
936
937 mutt_file_fclose(&fp_pgp_err);
938
939 state_attach_puts(s, _("[-- End of PGP output --]\n\n"));
940
941 mutt_file_unlink(mutt_buffer_string(sigfile));
942
943 cleanup:
944 mutt_buffer_pool_release(&sigfile);
945
946 mutt_debug(LL_DEBUG1, "returning %d\n", badsig);
947 return badsig;
948 }
949
950 /**
951 * pgp_extract_keys_from_attachment - Extract pgp keys from messages/attachments
952 * @param fp File to read from
953 * @param top Top Attachment
954 */
pgp_extract_keys_from_attachment(FILE * fp,struct Body * top)955 static void pgp_extract_keys_from_attachment(FILE *fp, struct Body *top)
956 {
957 struct State s = { 0 };
958 struct Buffer *tempfname = mutt_buffer_pool_get();
959
960 mutt_buffer_mktemp(tempfname);
961 FILE *fp_tmp = mutt_file_fopen(mutt_buffer_string(tempfname), "w");
962 if (!fp_tmp)
963 {
964 mutt_perror(mutt_buffer_string(tempfname));
965 goto cleanup;
966 }
967
968 s.fp_in = fp;
969 s.fp_out = fp_tmp;
970
971 mutt_body_handler(top, &s);
972
973 mutt_file_fclose(&fp_tmp);
974
975 pgp_class_invoke_import(mutt_buffer_string(tempfname));
976 mutt_any_key_to_continue(NULL);
977
978 mutt_file_unlink(mutt_buffer_string(tempfname));
979
980 cleanup:
981 mutt_buffer_pool_release(&tempfname);
982 }
983
984 /**
985 * pgp_class_extract_key_from_attachment - Implements CryptModuleSpecs::pgp_extract_key_from_attachment() - @ingroup crypto_pgp_extract_key_from_attachment
986 */
pgp_class_extract_key_from_attachment(FILE * fp,struct Body * top)987 void pgp_class_extract_key_from_attachment(FILE *fp, struct Body *top)
988 {
989 if (!fp)
990 {
991 mutt_error(_("Internal error. Please submit a bug report."));
992 return;
993 }
994
995 mutt_endwin();
996
997 OptDontHandlePgpKeys = true;
998 pgp_extract_keys_from_attachment(fp, top);
999 OptDontHandlePgpKeys = false;
1000 }
1001
1002 /**
1003 * pgp_decrypt_part - Decrypt part of a PGP message
1004 * @param a Body of attachment
1005 * @param s State to use
1006 * @param fp_out File to write to
1007 * @param p Body of parent (main email)
1008 * @retval ptr New Body for the attachment
1009 */
pgp_decrypt_part(struct Body * a,struct State * s,FILE * fp_out,struct Body * p)1010 static struct Body *pgp_decrypt_part(struct Body *a, struct State *s,
1011 FILE *fp_out, struct Body *p)
1012 {
1013 if (!a || !s || !fp_out || !p)
1014 return NULL;
1015
1016 char buf[1024];
1017 FILE *fp_pgp_in = NULL, *fp_pgp_out = NULL, *fp_pgp_tmp = NULL;
1018 struct Body *tattach = NULL;
1019 pid_t pid;
1020 int rv;
1021 struct Buffer *pgptmpfile = mutt_buffer_pool_get();
1022
1023 FILE *fp_pgp_err = mutt_file_mkstemp();
1024 if (!fp_pgp_err)
1025 {
1026 mutt_perror(_("Can't create temporary file"));
1027 goto cleanup;
1028 }
1029
1030 mutt_buffer_mktemp(pgptmpfile);
1031 fp_pgp_tmp = mutt_file_fopen(mutt_buffer_string(pgptmpfile), "w");
1032 if (!fp_pgp_tmp)
1033 {
1034 mutt_perror(mutt_buffer_string(pgptmpfile));
1035 mutt_file_fclose(&fp_pgp_err);
1036 goto cleanup;
1037 }
1038
1039 /* Position the stream at the beginning of the body, and send the data to
1040 * the temporary file. */
1041
1042 if (fseeko(s->fp_in, a->offset, SEEK_SET) != 0)
1043 {
1044 mutt_perror("fseeko");
1045 mutt_file_fclose(&fp_pgp_tmp);
1046 mutt_file_fclose(&fp_pgp_err);
1047 goto cleanup;
1048 }
1049 mutt_file_copy_bytes(s->fp_in, fp_pgp_tmp, a->length);
1050 mutt_file_fclose(&fp_pgp_tmp);
1051
1052 pid = pgp_invoke_decrypt(&fp_pgp_in, &fp_pgp_out, NULL, -1, -1,
1053 fileno(fp_pgp_err), mutt_buffer_string(pgptmpfile));
1054 if (pid == -1)
1055 {
1056 mutt_file_fclose(&fp_pgp_err);
1057 unlink(mutt_buffer_string(pgptmpfile));
1058 if (s->flags & MUTT_DISPLAY)
1059 {
1060 state_attach_puts(
1061 s, _("[-- Error: could not create a PGP subprocess --]\n\n"));
1062 }
1063 goto cleanup;
1064 }
1065
1066 /* send the PGP passphrase to the subprocess. Never do this if the agent is
1067 * active, because this might lead to a passphrase send as the message. */
1068 if (!pgp_use_gpg_agent())
1069 fputs(PgpPass, fp_pgp_in);
1070 fputc('\n', fp_pgp_in);
1071 mutt_file_fclose(&fp_pgp_in);
1072
1073 /* Read the output from PGP, and make sure to change CRLF to LF, otherwise
1074 * read_mime_header has a hard time parsing the message. */
1075 while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1076 {
1077 size_t len = mutt_str_len(buf);
1078 if ((len > 1) && (buf[len - 2] == '\r'))
1079 strcpy(buf + len - 2, "\n");
1080 fputs(buf, fp_out);
1081 }
1082
1083 mutt_file_fclose(&fp_pgp_out);
1084
1085 rv = filter_wait(pid);
1086 const bool c_pgp_use_gpg_agent =
1087 cs_subset_bool(NeoMutt->sub, "pgp_use_gpg_agent");
1088 if (c_pgp_use_gpg_agent)
1089 mutt_need_hard_redraw();
1090
1091 mutt_file_unlink(mutt_buffer_string(pgptmpfile));
1092
1093 fflush(fp_pgp_err);
1094 rewind(fp_pgp_err);
1095 if (pgp_check_decryption_okay(fp_pgp_err) < 0)
1096 {
1097 mutt_error(_("Decryption failed"));
1098 pgp_class_void_passphrase();
1099 mutt_file_fclose(&fp_pgp_err);
1100 goto cleanup;
1101 }
1102
1103 if (s->flags & MUTT_DISPLAY)
1104 {
1105 rewind(fp_pgp_err);
1106 if ((pgp_copy_checksig(fp_pgp_err, s->fp_out) == 0) && !rv)
1107 p->goodsig = true;
1108 else
1109 p->goodsig = false;
1110 state_attach_puts(s, _("[-- End of PGP output --]\n\n"));
1111 }
1112 mutt_file_fclose(&fp_pgp_err);
1113
1114 fflush(fp_out);
1115 rewind(fp_out);
1116
1117 if (fgetc(fp_out) == EOF)
1118 {
1119 mutt_error(_("Decryption failed"));
1120 pgp_class_void_passphrase();
1121 goto cleanup;
1122 }
1123
1124 rewind(fp_out);
1125 const long size = mutt_file_get_size_fp(fp_out);
1126 if (size == 0)
1127 {
1128 goto cleanup;
1129 }
1130
1131 tattach = mutt_read_mime_header(fp_out, 0);
1132 if (tattach)
1133 {
1134 /* Need to set the length of this body part. */
1135 tattach->length = size - tattach->offset;
1136
1137 /* See if we need to recurse on this MIME part. */
1138 mutt_parse_part(fp_out, tattach);
1139 }
1140
1141 cleanup:
1142 mutt_buffer_pool_release(&pgptmpfile);
1143 return tattach;
1144 }
1145
1146 /**
1147 * pgp_class_decrypt_mime - Implements CryptModuleSpecs::decrypt_mime() - @ingroup crypto_decrypt_mime
1148 */
pgp_class_decrypt_mime(FILE * fp_in,FILE ** fp_out,struct Body * b,struct Body ** cur)1149 int pgp_class_decrypt_mime(FILE *fp_in, FILE **fp_out, struct Body *b, struct Body **cur)
1150 {
1151 struct State s = { 0 };
1152 struct Body *p = b;
1153 bool need_decode = false;
1154 LOFF_T saved_offset = 0;
1155 size_t saved_length = 0;
1156 FILE *fp_decoded = NULL;
1157 int rc = 0;
1158
1159 if (mutt_is_valid_multipart_pgp_encrypted(b))
1160 {
1161 b = b->parts->next;
1162 /* Some clients improperly encode the octetstream part. */
1163 if (b->encoding != ENC_7BIT)
1164 need_decode = true;
1165 }
1166 else if (mutt_is_malformed_multipart_pgp_encrypted(b))
1167 {
1168 b = b->parts->next->next;
1169 need_decode = true;
1170 }
1171 else
1172 return -1;
1173
1174 s.fp_in = fp_in;
1175
1176 if (need_decode)
1177 {
1178 saved_offset = b->offset;
1179 saved_length = b->length;
1180
1181 fp_decoded = mutt_file_mkstemp();
1182 if (!fp_decoded)
1183 {
1184 mutt_perror(_("Can't create temporary file"));
1185 return -1;
1186 }
1187
1188 if (fseeko(s.fp_in, b->offset, SEEK_SET) != 0)
1189 {
1190 mutt_perror("fseeko");
1191 rc = -1;
1192 goto bail;
1193 }
1194 s.fp_out = fp_decoded;
1195
1196 mutt_decode_attachment(b, &s);
1197
1198 fflush(fp_decoded);
1199 b->length = ftello(fp_decoded);
1200 b->offset = 0;
1201 rewind(fp_decoded);
1202 s.fp_in = fp_decoded;
1203 s.fp_out = 0;
1204 }
1205
1206 *fp_out = mutt_file_mkstemp();
1207 if (!*fp_out)
1208 {
1209 mutt_perror(_("Can't create temporary file"));
1210 rc = -1;
1211 goto bail;
1212 }
1213
1214 *cur = pgp_decrypt_part(b, &s, *fp_out, p);
1215 if (!*cur)
1216 rc = -1;
1217 rewind(*fp_out);
1218
1219 bail:
1220 if (need_decode)
1221 {
1222 b->length = saved_length;
1223 b->offset = saved_offset;
1224 mutt_file_fclose(&fp_decoded);
1225 }
1226
1227 return rc;
1228 }
1229
1230 /**
1231 * pgp_class_encrypted_handler - Implements CryptModuleSpecs::encrypted_handler() - @ingroup crypto_encrypted_handler
1232 */
pgp_class_encrypted_handler(struct Body * a,struct State * s)1233 int pgp_class_encrypted_handler(struct Body *a, struct State *s)
1234 {
1235 FILE *fp_in = NULL;
1236 struct Body *tattach = NULL;
1237 int rc = 0;
1238
1239 FILE *fp_out = mutt_file_mkstemp();
1240 if (!fp_out)
1241 {
1242 mutt_perror(_("Can't create temporary file"));
1243 if (s->flags & MUTT_DISPLAY)
1244 {
1245 state_attach_puts(s,
1246 _("[-- Error: could not create temporary file --]\n"));
1247 }
1248 return -1;
1249 }
1250
1251 if (s->flags & MUTT_DISPLAY)
1252 crypt_current_time(s, "PGP");
1253
1254 tattach = pgp_decrypt_part(a, s, fp_out, a);
1255 if (tattach)
1256 {
1257 if (s->flags & MUTT_DISPLAY)
1258 {
1259 state_attach_puts(
1260 s, _("[-- The following data is PGP/MIME encrypted --]\n\n"));
1261 mutt_protected_headers_handler(tattach, s);
1262 }
1263
1264 /* Store any protected headers in the parent so they can be
1265 * accessed for index updates after the handler recursion is done.
1266 * This is done before the handler to prevent a nested encrypted
1267 * handler from freeing the headers. */
1268 mutt_env_free(&a->mime_headers);
1269 a->mime_headers = tattach->mime_headers;
1270 tattach->mime_headers = NULL;
1271
1272 fp_in = s->fp_in;
1273 s->fp_in = fp_out;
1274 rc = mutt_body_handler(tattach, s);
1275 s->fp_in = fp_in;
1276
1277 /* Embedded multipart signed protected headers override the
1278 * encrypted headers. We need to do this after the handler so
1279 * they can be printed in the pager. */
1280 if (mutt_is_multipart_signed(tattach) && tattach->parts && tattach->parts->mime_headers)
1281 {
1282 mutt_env_free(&a->mime_headers);
1283 a->mime_headers = tattach->parts->mime_headers;
1284 tattach->parts->mime_headers = NULL;
1285 }
1286
1287 /* if a multipart/signed is the _only_ sub-part of a
1288 * multipart/encrypted, cache signature verification
1289 * status. */
1290 if (mutt_is_multipart_signed(tattach) && !tattach->next)
1291 a->goodsig |= tattach->goodsig;
1292
1293 if (s->flags & MUTT_DISPLAY)
1294 {
1295 state_puts(s, "\n");
1296 state_attach_puts(s, _("[-- End of PGP/MIME encrypted data --]\n"));
1297 }
1298
1299 mutt_body_free(&tattach);
1300 /* clear 'Invoking...' message, since there's no error */
1301 mutt_message(_("PGP message successfully decrypted"));
1302 }
1303 else
1304 {
1305 mutt_error(_("Could not decrypt PGP message"));
1306 /* void the passphrase, even if it's not necessarily the problem */
1307 pgp_class_void_passphrase();
1308 rc = -1;
1309 }
1310
1311 mutt_file_fclose(&fp_out);
1312
1313 return rc;
1314 }
1315
1316 /* ----------------------------------------------------------------------------
1317 * Routines for sending PGP/MIME messages.
1318 */
1319
1320 /**
1321 * pgp_class_sign_message - Implements CryptModuleSpecs::sign_message() - @ingroup crypto_sign_message
1322 */
pgp_class_sign_message(struct Body * a,const struct AddressList * from)1323 struct Body *pgp_class_sign_message(struct Body *a, const struct AddressList *from)
1324 {
1325 struct Body *t = NULL, *rv = NULL;
1326 char buf[1024];
1327 FILE *fp_pgp_in = NULL, *fp_pgp_out = NULL, *fp_pgp_err = NULL, *fp_signed = NULL;
1328 bool err = false;
1329 bool empty = true;
1330 pid_t pid;
1331 struct Buffer *sigfile = mutt_buffer_pool_get();
1332 struct Buffer *signedfile = mutt_buffer_pool_get();
1333
1334 crypt_convert_to_7bit(a); /* Signed data _must_ be in 7-bit format. */
1335
1336 mutt_buffer_mktemp(sigfile);
1337 FILE *fp_sig = mutt_file_fopen(mutt_buffer_string(sigfile), "w");
1338 if (!fp_sig)
1339 {
1340 goto cleanup;
1341 }
1342
1343 mutt_buffer_mktemp(signedfile);
1344 fp_signed = mutt_file_fopen(mutt_buffer_string(signedfile), "w");
1345 if (!fp_signed)
1346 {
1347 mutt_perror(mutt_buffer_string(signedfile));
1348 mutt_file_fclose(&fp_sig);
1349 unlink(mutt_buffer_string(sigfile));
1350 goto cleanup;
1351 }
1352
1353 mutt_write_mime_header(a, fp_signed, NeoMutt->sub);
1354 fputc('\n', fp_signed);
1355 mutt_write_mime_body(a, fp_signed, NeoMutt->sub);
1356 mutt_file_fclose(&fp_signed);
1357
1358 pid = pgp_invoke_sign(&fp_pgp_in, &fp_pgp_out, &fp_pgp_err, -1, -1, -1,
1359 mutt_buffer_string(signedfile));
1360 if (pid == -1)
1361 {
1362 mutt_perror(_("Can't open PGP subprocess"));
1363 mutt_file_fclose(&fp_sig);
1364 unlink(mutt_buffer_string(sigfile));
1365 unlink(mutt_buffer_string(signedfile));
1366 goto cleanup;
1367 }
1368
1369 if (!pgp_use_gpg_agent())
1370 fputs(PgpPass, fp_pgp_in);
1371 fputc('\n', fp_pgp_in);
1372 mutt_file_fclose(&fp_pgp_in);
1373
1374 /* Read back the PGP signature. Also, change MESSAGE=>SIGNATURE as
1375 * recommended for future releases of PGP. */
1376 while (fgets(buf, sizeof(buf) - 1, fp_pgp_out))
1377 {
1378 if (mutt_str_equal("-----BEGIN PGP MESSAGE-----\n", buf))
1379 fputs("-----BEGIN PGP SIGNATURE-----\n", fp_sig);
1380 else if (mutt_str_equal("-----END PGP MESSAGE-----\n", buf))
1381 fputs("-----END PGP SIGNATURE-----\n", fp_sig);
1382 else
1383 fputs(buf, fp_sig);
1384 empty = false; /* got some output, so we're ok */
1385 }
1386
1387 /* check for errors from PGP */
1388 err = false;
1389 while (fgets(buf, sizeof(buf) - 1, fp_pgp_err))
1390 {
1391 err = true;
1392 fputs(buf, stdout);
1393 }
1394
1395 const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1396 if (filter_wait(pid) && c_pgp_check_exit)
1397 empty = true;
1398
1399 mutt_file_fclose(&fp_pgp_err);
1400 mutt_file_fclose(&fp_pgp_out);
1401 unlink(mutt_buffer_string(signedfile));
1402
1403 if (mutt_file_fclose(&fp_sig) != 0)
1404 {
1405 mutt_perror("fclose");
1406 unlink(mutt_buffer_string(sigfile));
1407 goto cleanup;
1408 }
1409
1410 if (err)
1411 mutt_any_key_to_continue(NULL);
1412 if (empty)
1413 {
1414 unlink(mutt_buffer_string(sigfile));
1415 /* most likely error is a bad passphrase, so automatically forget it */
1416 pgp_class_void_passphrase();
1417 goto cleanup; /* fatal error while signing */
1418 }
1419
1420 t = mutt_body_new();
1421 t->type = TYPE_MULTIPART;
1422 t->subtype = mutt_str_dup("signed");
1423 t->encoding = ENC_7BIT;
1424 t->use_disp = false;
1425 t->disposition = DISP_INLINE;
1426 rv = t;
1427
1428 mutt_generate_boundary(&t->parameter);
1429 mutt_param_set(&t->parameter, "protocol", "application/pgp-signature");
1430 mutt_param_set(&t->parameter, "micalg", pgp_micalg(mutt_buffer_string(sigfile)));
1431
1432 t->parts = a;
1433
1434 t->parts->next = mutt_body_new();
1435 t = t->parts->next;
1436 t->type = TYPE_APPLICATION;
1437 t->subtype = mutt_str_dup("pgp-signature");
1438 t->filename = mutt_buffer_strdup(sigfile);
1439 t->use_disp = false;
1440 t->disposition = DISP_NONE;
1441 t->encoding = ENC_7BIT;
1442 t->unlink = true; /* ok to remove this file after sending. */
1443 mutt_param_set(&t->parameter, "name", "signature.asc");
1444
1445 cleanup:
1446 mutt_buffer_pool_release(&sigfile);
1447 mutt_buffer_pool_release(&signedfile);
1448 return rv;
1449 }
1450
1451 /**
1452 * pgp_class_find_keys - Implements CryptModuleSpecs::find_keys() - @ingroup crypto_find_keys
1453 */
pgp_class_find_keys(const struct AddressList * addrlist,bool oppenc_mode)1454 char *pgp_class_find_keys(const struct AddressList *addrlist, bool oppenc_mode)
1455 {
1456 struct ListHead crypt_hook_list = STAILQ_HEAD_INITIALIZER(crypt_hook_list);
1457 struct ListNode *crypt_hook = NULL;
1458 const char *keyid = NULL;
1459 char *keylist = NULL;
1460 size_t keylist_size = 0;
1461 size_t keylist_used = 0;
1462 struct Address *p = NULL;
1463 struct PgpKeyInfo *k_info = NULL;
1464 const char *fqdn = mutt_fqdn(true, NeoMutt->sub);
1465 char buf[1024];
1466 bool key_selected;
1467 struct AddressList hookal = TAILQ_HEAD_INITIALIZER(hookal);
1468
1469 struct Address *a = NULL;
1470 TAILQ_FOREACH(a, addrlist, entries)
1471 {
1472 key_selected = false;
1473 mutt_crypt_hook(&crypt_hook_list, a);
1474 crypt_hook = STAILQ_FIRST(&crypt_hook_list);
1475 do
1476 {
1477 p = a;
1478 k_info = NULL;
1479
1480 if (crypt_hook)
1481 {
1482 keyid = crypt_hook->data;
1483 enum QuadOption ans = MUTT_YES;
1484 const bool c_crypt_confirm_hook =
1485 cs_subset_bool(NeoMutt->sub, "crypt_confirm_hook");
1486 if (!oppenc_mode && c_crypt_confirm_hook)
1487 {
1488 snprintf(buf, sizeof(buf), _("Use keyID = \"%s\" for %s?"), keyid, p->mailbox);
1489 ans = mutt_yesorno(buf, MUTT_YES);
1490 }
1491 if (ans == MUTT_YES)
1492 {
1493 if (crypt_is_numerical_keyid(keyid))
1494 {
1495 if (mutt_strn_equal(keyid, "0x", 2))
1496 keyid += 2;
1497 goto bypass_selection; /* you don't see this. */
1498 }
1499
1500 /* check for e-mail address */
1501 mutt_addrlist_clear(&hookal);
1502 if (strchr(keyid, '@') && (mutt_addrlist_parse(&hookal, keyid) != 0))
1503 {
1504 mutt_addrlist_qualify(&hookal, fqdn);
1505 p = TAILQ_FIRST(&hookal);
1506 }
1507 else if (!oppenc_mode)
1508 {
1509 k_info = pgp_getkeybystr(keyid, KEYFLAG_CANENCRYPT, PGP_PUBRING);
1510 }
1511 }
1512 else if (ans == MUTT_NO)
1513 {
1514 if (key_selected || STAILQ_NEXT(crypt_hook, entries))
1515 {
1516 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
1517 continue;
1518 }
1519 }
1520 else if (ans == MUTT_ABORT)
1521 {
1522 FREE(&keylist);
1523 mutt_addrlist_clear(&hookal);
1524 mutt_list_free(&crypt_hook_list);
1525 return NULL;
1526 }
1527 }
1528
1529 if (!k_info)
1530 {
1531 pgp_class_invoke_getkeys(p);
1532 k_info = pgp_getkeybyaddr(p, KEYFLAG_CANENCRYPT, PGP_PUBRING, oppenc_mode);
1533 }
1534
1535 if (!k_info && !oppenc_mode)
1536 {
1537 snprintf(buf, sizeof(buf), _("Enter keyID for %s: "), p->mailbox);
1538 k_info = pgp_ask_for_key(buf, p->mailbox, KEYFLAG_CANENCRYPT, PGP_PUBRING);
1539 }
1540
1541 if (!k_info)
1542 {
1543 FREE(&keylist);
1544 mutt_addrlist_clear(&hookal);
1545 mutt_list_free(&crypt_hook_list);
1546 return NULL;
1547 }
1548
1549 keyid = pgp_fpr_or_lkeyid(k_info);
1550
1551 bypass_selection:
1552 keylist_size += mutt_str_len(keyid) + 4;
1553 mutt_mem_realloc(&keylist, keylist_size);
1554 sprintf(keylist + keylist_used, "%s0x%s", keylist_used ? " " : "", keyid);
1555 keylist_used = mutt_str_len(keylist);
1556
1557 key_selected = true;
1558
1559 pgp_key_free(&k_info);
1560 mutt_addrlist_clear(&hookal);
1561
1562 if (crypt_hook)
1563 crypt_hook = STAILQ_NEXT(crypt_hook, entries);
1564
1565 } while (crypt_hook);
1566
1567 mutt_list_free(&crypt_hook_list);
1568 }
1569 return keylist;
1570 }
1571
1572 /**
1573 * pgp_class_encrypt_message - Implements CryptModuleSpecs::pgp_encrypt_message() - @ingroup crypto_pgp_encrypt_message
1574 *
1575 * @warning "a" is no longer freed in this routine, you need to free it later.
1576 * This is necessary for $fcc_attach.
1577 */
pgp_class_encrypt_message(struct Body * a,char * keylist,bool sign,const struct AddressList * from)1578 struct Body *pgp_class_encrypt_message(struct Body *a, char *keylist, bool sign,
1579 const struct AddressList *from)
1580 {
1581 char buf[1024];
1582 FILE *fp_pgp_in = NULL, *fp_tmp = NULL;
1583 struct Body *t = NULL;
1584 int err = 0;
1585 bool empty = false;
1586 pid_t pid;
1587 struct Buffer *tempfile = mutt_buffer_pool_get();
1588 struct Buffer *pgpinfile = mutt_buffer_pool_get();
1589
1590 mutt_buffer_mktemp(tempfile);
1591 FILE *fp_out = mutt_file_fopen(mutt_buffer_string(tempfile), "w+");
1592 if (!fp_out)
1593 {
1594 mutt_perror(mutt_buffer_string(tempfile));
1595 goto cleanup;
1596 }
1597
1598 FILE *fp_pgp_err = mutt_file_mkstemp();
1599 if (!fp_pgp_err)
1600 {
1601 mutt_perror(_("Can't create temporary file"));
1602 unlink(mutt_buffer_string(tempfile));
1603 mutt_file_fclose(&fp_out);
1604 goto cleanup;
1605 }
1606
1607 mutt_buffer_mktemp(pgpinfile);
1608 fp_tmp = mutt_file_fopen(mutt_buffer_string(pgpinfile), "w");
1609 if (!fp_tmp)
1610 {
1611 mutt_perror(mutt_buffer_string(pgpinfile));
1612 unlink(mutt_buffer_string(tempfile));
1613 mutt_file_fclose(&fp_out);
1614 mutt_file_fclose(&fp_pgp_err);
1615 goto cleanup;
1616 }
1617
1618 if (sign)
1619 crypt_convert_to_7bit(a);
1620
1621 mutt_write_mime_header(a, fp_tmp, NeoMutt->sub);
1622 fputc('\n', fp_tmp);
1623 mutt_write_mime_body(a, fp_tmp, NeoMutt->sub);
1624 mutt_file_fclose(&fp_tmp);
1625
1626 pid = pgp_invoke_encrypt(&fp_pgp_in, NULL, NULL, -1, fileno(fp_out), fileno(fp_pgp_err),
1627 mutt_buffer_string(pgpinfile), keylist, sign);
1628 if (pid == -1)
1629 {
1630 mutt_file_fclose(&fp_out);
1631 mutt_file_fclose(&fp_pgp_err);
1632 unlink(mutt_buffer_string(pgpinfile));
1633 goto cleanup;
1634 }
1635
1636 if (sign)
1637 {
1638 if (!pgp_use_gpg_agent())
1639 fputs(PgpPass, fp_pgp_in);
1640 fputc('\n', fp_pgp_in);
1641 }
1642 mutt_file_fclose(&fp_pgp_in);
1643
1644 const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1645 if (filter_wait(pid) && c_pgp_check_exit)
1646 empty = true;
1647
1648 unlink(mutt_buffer_string(pgpinfile));
1649
1650 fflush(fp_out);
1651 rewind(fp_out);
1652 if (!empty)
1653 empty = (fgetc(fp_out) == EOF);
1654 mutt_file_fclose(&fp_out);
1655
1656 fflush(fp_pgp_err);
1657 rewind(fp_pgp_err);
1658 while (fgets(buf, sizeof(buf) - 1, fp_pgp_err))
1659 {
1660 err = 1;
1661 fputs(buf, stdout);
1662 }
1663 mutt_file_fclose(&fp_pgp_err);
1664
1665 /* pause if there is any error output from PGP */
1666 if (err)
1667 mutt_any_key_to_continue(NULL);
1668
1669 if (empty)
1670 {
1671 /* fatal error while trying to encrypt message */
1672 if (sign)
1673 pgp_class_void_passphrase(); /* just in case */
1674 unlink(mutt_buffer_string(tempfile));
1675 goto cleanup;
1676 }
1677
1678 t = mutt_body_new();
1679 t->type = TYPE_MULTIPART;
1680 t->subtype = mutt_str_dup("encrypted");
1681 t->encoding = ENC_7BIT;
1682 t->use_disp = false;
1683 t->disposition = DISP_INLINE;
1684
1685 mutt_generate_boundary(&t->parameter);
1686 mutt_param_set(&t->parameter, "protocol", "application/pgp-encrypted");
1687
1688 t->parts = mutt_body_new();
1689 t->parts->type = TYPE_APPLICATION;
1690 t->parts->subtype = mutt_str_dup("pgp-encrypted");
1691 t->parts->encoding = ENC_7BIT;
1692
1693 t->parts->next = mutt_body_new();
1694 t->parts->next->type = TYPE_APPLICATION;
1695 t->parts->next->subtype = mutt_str_dup("octet-stream");
1696 t->parts->next->encoding = ENC_7BIT;
1697 t->parts->next->filename = mutt_buffer_strdup(tempfile);
1698 t->parts->next->use_disp = true;
1699 t->parts->next->disposition = DISP_ATTACH;
1700 t->parts->next->unlink = true; /* delete after sending the message */
1701 t->parts->next->d_filename = mutt_str_dup("msg.asc"); /* non pgp/mime can save */
1702
1703 cleanup:
1704 mutt_buffer_pool_release(&tempfile);
1705 mutt_buffer_pool_release(&pgpinfile);
1706 return t;
1707 }
1708
1709 /**
1710 * pgp_class_traditional_encryptsign - Implements CryptModuleSpecs::pgp_traditional_encryptsign() - @ingroup crypto_pgp_traditional_encryptsign
1711 */
pgp_class_traditional_encryptsign(struct Body * a,SecurityFlags flags,char * keylist)1712 struct Body *pgp_class_traditional_encryptsign(struct Body *a, SecurityFlags flags, char *keylist)
1713 {
1714 struct Body *b = NULL;
1715 char body_charset[256];
1716 const char *from_charset = NULL;
1717 const char *send_charset = NULL;
1718 bool empty = false;
1719 bool err;
1720 char buf[256];
1721 pid_t pid;
1722 struct Buffer *pgpinfile = mutt_buffer_pool_get();
1723 struct Buffer *pgpoutfile = mutt_buffer_pool_get();
1724
1725 if (a->type != TYPE_TEXT)
1726 goto cleanup;
1727 if (!mutt_istr_equal(a->subtype, "plain"))
1728 goto cleanup;
1729
1730 FILE *fp_body = fopen(a->filename, "r");
1731 if (!fp_body)
1732 {
1733 mutt_perror(a->filename);
1734 goto cleanup;
1735 }
1736
1737 mutt_buffer_mktemp(pgpinfile);
1738 FILE *fp_pgp_in = mutt_file_fopen(mutt_buffer_string(pgpinfile), "w");
1739 if (!fp_pgp_in)
1740 {
1741 mutt_perror(mutt_buffer_string(pgpinfile));
1742 mutt_file_fclose(&fp_body);
1743 goto cleanup;
1744 }
1745
1746 /* The following code is really correct: If noconv is set,
1747 * a's charset parameter contains the on-disk character set, and
1748 * we have to convert from that to utf-8. If noconv is not set,
1749 * we have to convert from $charset to utf-8. */
1750
1751 mutt_body_get_charset(a, body_charset, sizeof(body_charset));
1752 const char *const c_charset = cs_subset_string(NeoMutt->sub, "charset");
1753 if (a->noconv)
1754 from_charset = body_charset;
1755 else
1756 from_charset = c_charset;
1757
1758 if (!mutt_ch_is_us_ascii(body_charset))
1759 {
1760 int c;
1761 struct FgetConv *fc = NULL;
1762
1763 if (flags & SEC_ENCRYPT)
1764 send_charset = "us-ascii";
1765 else
1766 send_charset = "utf-8";
1767
1768 /* fromcode is assumed to be correct: we set flags to 0 */
1769 fc = mutt_ch_fgetconv_open(fp_body, from_charset, "utf-8", MUTT_ICONV_NO_FLAGS);
1770 while ((c = mutt_ch_fgetconv(fc)) != EOF)
1771 fputc(c, fp_pgp_in);
1772
1773 mutt_ch_fgetconv_close(&fc);
1774 }
1775 else
1776 {
1777 send_charset = "us-ascii";
1778 mutt_file_copy_stream(fp_body, fp_pgp_in);
1779 }
1780 mutt_file_fclose(&fp_body);
1781 mutt_file_fclose(&fp_pgp_in);
1782
1783 mutt_buffer_mktemp(pgpoutfile);
1784 FILE *fp_pgp_out = mutt_file_fopen(mutt_buffer_string(pgpoutfile), "w+");
1785 FILE *fp_pgp_err = mutt_file_mkstemp();
1786 if (!fp_pgp_out || !fp_pgp_err)
1787 {
1788 mutt_perror(fp_pgp_out ? "Can't create temporary file" : mutt_buffer_string(pgpoutfile));
1789 unlink(mutt_buffer_string(pgpinfile));
1790 if (fp_pgp_out)
1791 {
1792 mutt_file_fclose(&fp_pgp_out);
1793 unlink(mutt_buffer_string(pgpoutfile));
1794 }
1795 mutt_file_fclose(&fp_pgp_err);
1796 goto cleanup;
1797 }
1798
1799 pid = pgp_invoke_traditional(&fp_pgp_in, NULL, NULL, -1, fileno(fp_pgp_out),
1800 fileno(fp_pgp_err),
1801 mutt_buffer_string(pgpinfile), keylist, flags);
1802 if (pid == -1)
1803 {
1804 mutt_perror(_("Can't invoke PGP"));
1805 mutt_file_fclose(&fp_pgp_out);
1806 mutt_file_fclose(&fp_pgp_err);
1807 mutt_file_unlink(mutt_buffer_string(pgpinfile));
1808 unlink(mutt_buffer_string(pgpoutfile));
1809 goto cleanup;
1810 }
1811
1812 if (pgp_use_gpg_agent())
1813 *PgpPass = '\0';
1814 if (flags & SEC_SIGN)
1815 fprintf(fp_pgp_in, "%s\n", PgpPass);
1816 mutt_file_fclose(&fp_pgp_in);
1817
1818 const bool c_pgp_check_exit = cs_subset_bool(NeoMutt->sub, "pgp_check_exit");
1819 if (filter_wait(pid) && c_pgp_check_exit)
1820 empty = true;
1821
1822 mutt_file_unlink(mutt_buffer_string(pgpinfile));
1823
1824 fflush(fp_pgp_out);
1825 fflush(fp_pgp_err);
1826
1827 rewind(fp_pgp_out);
1828 rewind(fp_pgp_err);
1829
1830 if (!empty)
1831 empty = (fgetc(fp_pgp_out) == EOF);
1832 mutt_file_fclose(&fp_pgp_out);
1833
1834 err = false;
1835
1836 while (fgets(buf, sizeof(buf), fp_pgp_err))
1837 {
1838 err = true;
1839 fputs(buf, stdout);
1840 }
1841
1842 mutt_file_fclose(&fp_pgp_err);
1843
1844 if (err)
1845 mutt_any_key_to_continue(NULL);
1846
1847 if (empty)
1848 {
1849 if (flags & SEC_SIGN)
1850 pgp_class_void_passphrase(); /* just in case */
1851 unlink(mutt_buffer_string(pgpoutfile));
1852 goto cleanup;
1853 }
1854
1855 b = mutt_body_new();
1856
1857 b->encoding = ENC_7BIT;
1858
1859 b->type = TYPE_TEXT;
1860 b->subtype = mutt_str_dup("plain");
1861
1862 mutt_param_set(&b->parameter, "x-action",
1863 (flags & SEC_ENCRYPT) ? "pgp-encrypted" : "pgp-signed");
1864 mutt_param_set(&b->parameter, "charset", send_charset);
1865
1866 b->filename = mutt_buffer_strdup(pgpoutfile);
1867
1868 b->disposition = DISP_NONE;
1869 b->unlink = true;
1870
1871 b->noconv = true;
1872 b->use_disp = false;
1873
1874 if (!(flags & SEC_ENCRYPT))
1875 b->encoding = a->encoding;
1876
1877 cleanup:
1878 mutt_buffer_pool_release(&pgpinfile);
1879 mutt_buffer_pool_release(&pgpoutfile);
1880 return b;
1881 }
1882
1883 /**
1884 * pgp_class_send_menu - Implements CryptModuleSpecs::send_menu() - @ingroup crypto_send_menu
1885 */
pgp_class_send_menu(struct Email * e)1886 SecurityFlags pgp_class_send_menu(struct Email *e)
1887 {
1888 struct PgpKeyInfo *p = NULL;
1889 const char *prompt = NULL;
1890 const char *letters = NULL;
1891 const char *choices = NULL;
1892 char promptbuf[1024];
1893 int choice;
1894
1895 if (!(WithCrypto & APPLICATION_PGP))
1896 return e->security;
1897
1898 /* If autoinline and no crypto options set, then set inline. */
1899 const bool c_pgp_auto_inline =
1900 cs_subset_bool(NeoMutt->sub, "pgp_auto_inline");
1901 if (c_pgp_auto_inline &&
1902 !((e->security & APPLICATION_PGP) && (e->security & (SEC_SIGN | SEC_ENCRYPT))))
1903 {
1904 e->security |= SEC_INLINE;
1905 }
1906
1907 e->security |= APPLICATION_PGP;
1908
1909 char *mime_inline = NULL;
1910 if (e->security & SEC_INLINE)
1911 {
1912 /* L10N: The next string MUST have the same highlighted letter
1913 One of them will appear in each of the three strings marked "(inline"), below. */
1914 mime_inline = _("PGP/M(i)ME");
1915 }
1916 else
1917 {
1918 /* L10N: The previous string MUST have the same highlighted letter
1919 One of them will appear in each of the three strings marked "(inline"), below. */
1920 mime_inline = _("(i)nline");
1921 }
1922 /* Opportunistic encrypt is controlling encryption. Allow to toggle
1923 * between inline and mime, but not turn encryption on or off.
1924 * NOTE: "Signing" and "Clearing" only adjust the sign bit, so we have different
1925 * letter choices for those. */
1926 const bool c_crypt_opportunistic_encrypt =
1927 cs_subset_bool(NeoMutt->sub, "crypt_opportunistic_encrypt");
1928 if (c_crypt_opportunistic_encrypt && (e->security & SEC_OPPENCRYPT))
1929 {
1930 if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1931 {
1932 snprintf(promptbuf, sizeof(promptbuf),
1933 /* L10N: PGP options (inline) (opportunistic encryption is on) */
1934 _("PGP (s)ign, sign (a)s, %s format, (c)lear, or (o)ppenc mode "
1935 "off?"),
1936 mime_inline);
1937 prompt = promptbuf;
1938 /* L10N: PGP options (inline) (opportunistic encryption is on)
1939 The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
1940 letters = _("saico");
1941 choices = "SaiCo";
1942 }
1943 else
1944 {
1945 /* L10N: PGP options (opportunistic encryption is on) */
1946 prompt = _("PGP (s)ign, sign (a)s, (c)lear, or (o)ppenc mode off?");
1947 /* L10N: PGP options (opportunistic encryption is on) */
1948 letters = _("saco");
1949 choices = "SaCo";
1950 }
1951 }
1952 /* Opportunistic encryption option is set, but is toggled off
1953 * for this message. */
1954 else if (c_crypt_opportunistic_encrypt)
1955 {
1956 /* When the message is not selected for signing or encryption, the toggle
1957 * between PGP/MIME and Traditional doesn't make sense. */
1958 if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1959 {
1960 snprintf(promptbuf, sizeof(promptbuf),
1961 /* L10N: PGP options (inline) (opportunistic encryption is off) */
1962 _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s format, "
1963 "(c)lear, or (o)ppenc mode?"),
1964 mime_inline);
1965 prompt = promptbuf;
1966 /* L10N: PGP options (inline) (opportunistic encryption is off)
1967 The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
1968 letters = _("esabico");
1969 choices = "esabicO";
1970 }
1971 else
1972 {
1973 /* L10N: PGP options (opportunistic encryption is off) */
1974 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (c)lear, or "
1975 "(o)ppenc mode?");
1976 /* L10N: PGP options (opportunistic encryption is off) */
1977 letters = _("esabco");
1978 choices = "esabcO";
1979 }
1980 }
1981 /* Opportunistic encryption is unset */
1982 else
1983 {
1984 if (e->security & (SEC_ENCRYPT | SEC_SIGN))
1985 {
1986 snprintf(promptbuf, sizeof(promptbuf),
1987 /* L10N: PGP options (inline) */
1988 _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, %s format, or "
1989 "(c)lear?"),
1990 mime_inline);
1991 prompt = promptbuf;
1992 /* L10N: PGP options (inline)
1993 The 'i' is from the "PGP/M(i)ME" or "(i)nline", above. */
1994 letters = _("esabic");
1995 choices = "esabic";
1996 }
1997 else
1998 {
1999 /* L10N: PGP options */
2000 prompt = _("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (c)lear?");
2001 /* L10N: PGP options */
2002 letters = _("esabc");
2003 choices = "esabc";
2004 }
2005 }
2006
2007 choice = mutt_multi_choice(prompt, letters);
2008 if (choice > 0)
2009 {
2010 switch (choices[choice - 1])
2011 {
2012 case 'a': /* sign (a)s */
2013 OptPgpCheckTrust = false;
2014
2015 p = pgp_ask_for_key(_("Sign as: "), NULL, KEYFLAG_NO_FLAGS, PGP_SECRING);
2016 if (p)
2017 {
2018 char input_signas[128];
2019 snprintf(input_signas, sizeof(input_signas), "0x%s", pgp_fpr_or_lkeyid(p));
2020 cs_subset_str_string_set(NeoMutt->sub, "pgp_sign_as", input_signas, NULL);
2021 pgp_key_free(&p);
2022
2023 e->security |= SEC_SIGN;
2024
2025 crypt_pgp_void_passphrase(); /* probably need a different passphrase */
2026 }
2027 break;
2028
2029 case 'b': /* (b)oth */
2030 e->security |= (SEC_ENCRYPT | SEC_SIGN);
2031 break;
2032
2033 case 'C':
2034 e->security &= ~SEC_SIGN;
2035 break;
2036
2037 case 'c': /* (c)lear */
2038 e->security &= ~(SEC_ENCRYPT | SEC_SIGN);
2039 break;
2040
2041 case 'e': /* (e)ncrypt */
2042 e->security |= SEC_ENCRYPT;
2043 e->security &= ~SEC_SIGN;
2044 break;
2045
2046 case 'i': /* toggle (i)nline */
2047 e->security ^= SEC_INLINE;
2048 break;
2049
2050 case 'O': /* oppenc mode on */
2051 e->security |= SEC_OPPENCRYPT;
2052 crypt_opportunistic_encrypt(e);
2053 break;
2054
2055 case 'o': /* oppenc mode off */
2056 e->security &= ~SEC_OPPENCRYPT;
2057 break;
2058
2059 case 'S': /* (s)ign in oppenc mode */
2060 e->security |= SEC_SIGN;
2061 break;
2062
2063 case 's': /* (s)ign */
2064 e->security &= ~SEC_ENCRYPT;
2065 e->security |= SEC_SIGN;
2066 break;
2067 }
2068 }
2069
2070 return e->security;
2071 }
2072