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