Add specific option for auto-key-retrieve
[gpgol.git] / src / parsecontroller.cpp
1 /* @file parsecontroller.cpp
2  * @brief Parse a mail and decrypt / verify accordingly
3  *
4  * Copyright (C) 2016 by Bundesamt für Sicherheit in der Informationstechnik
5  * Software engineering by Intevation GmbH
6  *
7  * This file is part of GpgOL.
8  *
9  * GpgOL is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * GpgOL is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22 #include "config.h"
23
24 #include "parsecontroller.h"
25 #include "attachment.h"
26 #include "mimedataprovider.h"
27
28 #include "keycache.h"
29
30 #include <gpgme++/context.h>
31 #include <gpgme++/decryptionresult.h>
32 #include <gpgme++/key.h>
33
34 #include <sstream>
35
36 #ifdef HAVE_W32_SYSTEM
37 #include "common.h"
38 /* We use UTF-8 internally. */
39 #undef _
40 # define _(a) utf8_gettext (a)
41 #else
42 # define _(a) a
43 #endif
44
45
46
47 const char decrypt_template_html[] = {
48 "<html><head></head><body>"
49 "<table border=\"0\" width=\"100%%\" cellspacing=\"1\" cellpadding=\"1\" bgcolor=\"#0069cc\">"
50 "<tr>"
51 "<td bgcolor=\"#0080ff\">"
52 "<p><span style=\"font-weight:600; background-color:#0080ff;\"><center>%s %s</center><span></p></td></tr>"
53 "<tr>"
54 "<td bgcolor=\"#e0f0ff\">"
55 "<center>"
56 "<br/>%s"
57 "</td></tr>"
58 "</table></body></html>"};
59
60 const char decrypt_template[] = {"%s %s\n\n%s"};
61
62 using namespace GpgME;
63
64 static bool
65 expect_no_headers (msgtype_t type)
66 {
67   TSTART;
68   TRETURN type != MSGTYPE_GPGOL_MULTIPART_SIGNED;
69 }
70
71 static bool
72 expect_no_mime (msgtype_t type)
73 {
74   TSTART;
75   TRETURN type == MSGTYPE_GPGOL_PGP_MESSAGE ||
76          type == MSGTYPE_GPGOL_CLEAR_SIGNED;
77 }
78
79 #ifdef HAVE_W32_SYSTEM
80 ParseController::ParseController(LPSTREAM instream, msgtype_t type):
81     m_inputprovider  (new MimeDataProvider(instream,
82                           expect_no_headers(type))),
83     m_outputprovider (new MimeDataProvider(expect_no_mime(type))),
84     m_type (type),
85     m_block_html (false)
86 {
87   TSTART;
88   memdbg_ctor ("ParseController");
89   log_data ("%s:%s: Creating parser for stream: %p of type %i"
90                    " expect no headers: %i expect no mime: %i",
91                    SRCNAME, __func__, instream, type,
92                    expect_no_headers (type), expect_no_mime (type));
93   TRETURN;
94 }
95 #endif
96
97 ParseController::ParseController(FILE *instream, msgtype_t type):
98     m_inputprovider  (new MimeDataProvider(instream,
99                           expect_no_headers(type))),
100     m_outputprovider (new MimeDataProvider(expect_no_mime(type))),
101     m_type (type),
102     m_block_html (false)
103 {
104   TSTART;
105   memdbg_ctor ("ParseController");
106   log_data ("%s:%s: Creating parser for stream: %p of type %i",
107                    SRCNAME, __func__, instream, type);
108   TRETURN;
109 }
110
111 ParseController::~ParseController()
112 {
113   TSTART;
114   log_debug ("%s:%s", SRCNAME, __func__);
115   memdbg_dtor ("ParseController");
116   delete m_inputprovider;
117   delete m_outputprovider;
118   TRETURN;
119 }
120
121 static void
122 operation_for_type(msgtype_t type, bool *decrypt,
123                    bool *verify)
124 {
125   *decrypt = false;
126   *verify = false;
127   switch (type)
128     {
129       case MSGTYPE_GPGOL_MULTIPART_ENCRYPTED:
130       case MSGTYPE_GPGOL_PGP_MESSAGE:
131         *decrypt = true;
132         break;
133       case MSGTYPE_GPGOL_MULTIPART_SIGNED:
134       case MSGTYPE_GPGOL_CLEAR_SIGNED:
135         *verify = true;
136         break;
137       case MSGTYPE_GPGOL_OPAQUE_SIGNED:
138         *verify = true;
139         break;
140       case MSGTYPE_GPGOL_OPAQUE_ENCRYPTED:
141         *decrypt = true;
142         break;
143       default:
144         log_error ("%s:%s: Unknown data type: %i",
145                    SRCNAME, __func__, type);
146     }
147 }
148
149 static bool
150 is_smime (Data &data)
151 {
152   TSTART;
153   data.seek (0, SEEK_SET);
154   auto id = data.type();
155   data.seek (0, SEEK_SET);
156   TRETURN id == Data::CMSSigned || id == Data::CMSEncrypted;
157 }
158
159 static std::string
160 format_recipients(GpgME::DecryptionResult result, Protocol protocol)
161 {
162   TSTART;
163   std::string msg;
164   for (const auto recipient: result.recipients())
165     {
166       auto ctx = Context::createForProtocol(protocol);
167       Error e;
168       if (!ctx) {
169           /* Can't happen */
170           TRACEPOINT;
171           continue;
172       }
173       const auto key = ctx->key(recipient.keyID(), e, false);
174       delete ctx;
175       if (!key.isNull() && key.numUserIDs() && !e) {
176         msg += std::string("<br/>") + key.userIDs()[0].id() + " (0x" + recipient.keyID() + ")";
177         continue;
178       }
179       msg += std::string("<br/>") + _("Unknown Key:") + " 0x" + recipient.keyID();
180     }
181   TRETURN msg;
182 }
183
184 static std::string
185 format_error(GpgME::DecryptionResult result, Protocol protocol)
186 {
187   TSTART;
188   char *buf;
189   bool no_sec = false;
190   std::string msg;
191
192   if (result.error ().isCanceled () ||
193       result.error ().code () == GPG_ERR_NO_SECKEY)
194     {
195        msg = _("Decryption canceled or timed out.");
196     }
197
198   if (result.error ().code () == GPG_ERR_DECRYPT_FAILED ||
199       result.error ().code () == GPG_ERR_NO_SECKEY)
200     {
201       no_sec = true;
202       for (const auto &recipient: result.recipients ()) {
203         no_sec &= (recipient.status ().code () == GPG_ERR_NO_SECKEY);
204       }
205     }
206
207   if (no_sec)
208     {
209       msg = _("No secret key found to decrypt the message. "
210               "It is encrypted to the following keys:");
211       msg += format_recipients (result, protocol);
212     }
213   else
214     {
215       msg = _("Could not decrypt the data: ");
216
217       if (result.isNull ())
218         {
219           msg += _("Failed to parse the mail.");
220         }
221       else if (result.isLegacyCipherNoMDC())
222         {
223           msg += _("Data is not integrity protected. "
224                    "Decrypting it could be a security problem. (no MDC)");
225         }
226       else
227         {
228           msg += result.error().asString();
229         }
230     }
231
232   if (gpgrt_asprintf (&buf, opt.prefer_html ? decrypt_template_html :
233                       decrypt_template,
234                       protocol == OpenPGP ? "OpenPGP" : "S/MIME",
235                       _("Encrypted message (decryption not possible)"),
236                       msg.c_str()) == -1)
237     {
238       log_error ("%s:%s:Failed to Format error.",
239                  SRCNAME, __func__);
240       TRETURN "Failed to Format error.";
241     }
242   msg = buf;
243   memdbg_alloc (buf);
244   xfree (buf);
245   TRETURN msg;
246 }
247
248 void
249 ParseController::setSender(const std::string &sender)
250 {
251   TSTART;
252   m_sender = sender;
253   TRETURN;
254 }
255
256 static bool
257 is_valid_chksum(const GpgME::Signature &sig)
258 {
259   TSTART;
260   const auto sum = sig.summary();
261   static unsigned int valid_mask = (unsigned int) (
262       GpgME::Signature::Valid |
263       GpgME::Signature::Green |
264       GpgME::Signature::KeyRevoked |
265       GpgME::Signature::KeyExpired |
266       GpgME::Signature::SigExpired |
267       GpgME::Signature::CrlMissing |
268       GpgME::Signature::CrlTooOld |
269       GpgME::Signature::TofuConflict );
270
271   TRETURN sum & valid_mask;
272 }
273
274
275 /* Note on stability:
276
277    Experiments have shown that we can have a crash if parse
278    Returns at time that is not good for the state of Outlook.
279
280    This happend in my test instance after a delay of > 1s < 3s
281    with a < 1% chance :-/
282
283    So if you have really really bad luck this might still crash
284    although it usually should be either much quicker or much slower
285    (slower e.g. when pinentry is requrired).
286 */
287 void
288 ParseController::parse()
289 {
290   TSTART;
291   // Wrap the input stream in an attachment / GpgME Data
292   Protocol protocol;
293   bool decrypt, verify;
294
295   Data input (m_inputprovider);
296
297   auto inputType = input.type ();
298
299   if (inputType == Data::Type::PGPSigned)
300     {
301       verify = true;
302       decrypt = false;
303     }
304   else
305     {
306       operation_for_type (m_type, &decrypt, &verify);
307     }
308
309   if ((m_inputprovider->signature() && is_smime (*m_inputprovider->signature())) ||
310       is_smime (input))
311     {
312       protocol = Protocol::CMS;
313     }
314   else
315     {
316       protocol = Protocol::OpenPGP;
317     }
318   auto ctx = std::unique_ptr<Context> (Context::createForProtocol (protocol));
319   if (!ctx)
320     {
321       log_error ("%s:%s:Failed to create context. Installation broken.",
322                  SRCNAME, __func__);
323       char *buf;
324       const char *proto = protocol == OpenPGP ? "OpenPGP" : "S/MIME";
325       if (gpgrt_asprintf (&buf, opt.prefer_html ? decrypt_template_html :
326                           decrypt_template,
327                           proto,
328                           _("Encrypted message (decryption not possible)"),
329                           _("Failed to find GnuPG please ensure that GnuPG or "
330                             "Gpg4win is properly installed.")) == -1)
331         {
332           log_error ("%s:%s:Failed format error.",
333                      SRCNAME, __func__);
334           /* Should never happen */
335           m_error = std::string("Bad installation");
336         }
337       memdbg_alloc (buf);
338       m_error = buf;
339       xfree (buf);
340       TRETURN;
341     }
342
343   /* Maybe a different option for this ? */
344   if (opt.autoretrieve)
345     {
346       ctx->setFlag("auto-key-retrieve", "1");
347     }
348
349   ctx->setArmor(true);
350
351   if (!m_sender.empty())
352     {
353       ctx->setSender(m_sender.c_str());
354     }
355
356   Data output (m_outputprovider);
357   log_debug ("%s:%s:%p decrypt: %i verify: %i with protocol: %s sender: %s type: %i",
358              SRCNAME, __func__, this,
359              decrypt, verify,
360              protocol == OpenPGP ? "OpenPGP" :
361              protocol == CMS ? "CMS" : "Unknown",
362              m_sender.empty() ? "none" : anonstr (m_sender.c_str()), inputType);
363   if (decrypt)
364     {
365       input.seek (0, SEEK_SET);
366       auto combined_result = ctx->decryptAndVerify(input, output);
367       log_debug ("%s:%s:%p decrypt / verify done.",
368                  SRCNAME, __func__, this);
369       m_decrypt_result = combined_result.first;
370       m_verify_result = combined_result.second;
371
372       if ((!m_decrypt_result.error () &&
373           m_verify_result.signatures ().empty() &&
374           m_outputprovider->signature ()) ||
375           is_smime (output) ||
376           output.type() == Data::Type::PGPSigned)
377         {
378           /* There is a signature in the output. So we have
379              to verify it now as an extra step. */
380           input = Data (m_outputprovider);
381           delete m_inputprovider;
382           m_inputprovider = m_outputprovider;
383           m_outputprovider = new MimeDataProvider();
384           output = Data(m_outputprovider);
385           verify = true;
386         }
387       else
388         {
389           verify = false;
390         }
391       if (m_decrypt_result.error () || m_decrypt_result.isNull () ||
392           m_decrypt_result.error ().isCanceled ())
393         {
394           m_error = format_error (m_decrypt_result, protocol);
395         }
396     }
397   if (verify)
398     {
399       const auto sig = m_inputprovider->signature();
400       input.seek (0, SEEK_SET);
401       if (sig)
402         {
403           sig->seek (0, SEEK_SET);
404           m_verify_result = ctx->verifyDetachedSignature(*sig, input);
405           log_debug ("%s:%s:%p verify done.",
406                      SRCNAME, __func__, this);
407           /* Copy the input to output to do a mime parsing. */
408           char buf[4096];
409           input.seek (0, SEEK_SET);
410           output.seek (0, SEEK_SET);
411           size_t nread;
412           while ((nread = input.read (buf, 4096)) > 0)
413             {
414               output.write (buf, nread);
415             }
416         }
417       else
418         {
419           m_verify_result = ctx->verifyOpaqueSignature(input, output);
420
421           const auto sigs = m_verify_result.signatures();
422           bool allBad = sigs.size();
423           for (const auto s :sigs)
424             {
425               if (!(s.summary() & Signature::Red))
426                 {
427                   allBad = false;
428                   break;
429                 }
430             }
431 #ifdef HAVE_W32_SYSTEM
432           if (allBad)
433             {
434               log_debug ("%s:%s:%p inline verify error trying native to utf8.",
435                          SRCNAME, __func__, this);
436
437
438               /* The proper solution would be to take the encoding from
439                  the mail / headers. Then convert the wchar body to that
440                  encoding. Verify, and convert it after verifcation to
441                  UTF-8 which the rest of the code expects.
442
443                  Or native_body from native ACP to InternetCodepage, then
444                  verify and convert the output back to utf8 as the rest
445                  expects.
446
447                  But as this is clearsigned and we don't really want that.
448                  Meh.
449                  */
450               char *utf8 = native_to_utf8 (input.toString().c_str());
451               if (utf8)
452                 {
453                   // Try again after conversion.
454                   ctx = std::unique_ptr<Context> (Context::createForProtocol (protocol));
455                   ctx->setArmor (true);
456                   if (!m_sender.empty())
457                     {
458                       ctx->setSender(m_sender.c_str());
459                     }
460
461                   input = Data (utf8, strlen (utf8));
462                   xfree (utf8);
463
464                   // Use a fresh output
465                   auto provider = new MimeDataProvider (true);
466
467                   // Warning: The dtor of the Data object touches
468                   // the provider. So we have to delete it after
469                   // the assignment.
470                   output = Data (provider);
471                   delete m_outputprovider;
472                   m_outputprovider = provider;
473
474                   // Try again
475                   m_verify_result = ctx->verifyOpaqueSignature(input, output);
476                 }
477             }
478 #endif
479         }
480     }
481   log_debug ("%s:%s:%p: decrypt err: %i verify err: %i",
482              SRCNAME, __func__, this, m_decrypt_result.error().code(),
483              m_verify_result.error().code());
484
485   bool has_valid_encrypted_checksum = false;
486   /* Ensure that the Keys for the signatures are available
487      and if it has a valid encrypted checksum. */
488   bool ultimate_keys_queried = false;
489   for (const auto sig: m_verify_result.signatures())
490     {
491       has_valid_encrypted_checksum = is_valid_chksum (sig);
492
493       KeyCache::instance ()->update (sig.fingerprint (), protocol);
494
495       if (!ultimate_keys_queried &&
496           (sig.validity() == Signature::Validity::Full ||
497           sig.validity() == Signature::Validity::Ultimate))
498         {
499           /* Ensure that we have the keys with ultimate
500              trust cached for the ui. */
501
502           // TODO this is something for the keycache
503           get_ultimate_keys ();
504           ultimate_keys_queried = true;
505         }
506     }
507
508   if (protocol == Protocol::CMS && decrypt && !m_decrypt_result.error() &&
509       !has_valid_encrypted_checksum)
510     {
511       log_debug ("%s:%s:%p Encrypted S/MIME without checksum. Block HTML.",
512                  SRCNAME, __func__, this);
513       m_block_html = true;
514     }
515
516   if (opt.enable_debug & DBG_DATA)
517     {
518       std::stringstream ss;
519       ss << m_decrypt_result << '\n' << m_verify_result;
520       for (const auto sig: m_verify_result.signatures())
521         {
522           const auto key = sig.key();
523           if (key.isNull())
524             {
525               ss << '\n' << "Cached key:\n" << KeyCache::instance()->getByFpr(
526                   sig.fingerprint(), false);
527             }
528           else
529             {
530               ss << '\n' << key;
531             }
532         }
533        log_debug ("Decrypt / Verify result: %s", ss.str().c_str());
534     }
535   else
536     {
537       log_debug ("%s:%s:%p Decrypt / verify done errs: %i / %i numsigs: %i.",
538                  SRCNAME, __func__, this, m_decrypt_result.error().code(),
539                  m_verify_result.error().code(), m_verify_result.numSignatures());
540     }
541   TRACEPOINT;
542
543   if (m_outputprovider)
544     {
545       m_outputprovider->finalize ();
546     }
547
548   TRETURN;
549 }
550
551 const std::string
552 ParseController::get_html_body () const
553 {
554   TSTART;
555   if (m_outputprovider)
556     {
557       TRETURN m_outputprovider->get_html_body ();
558     }
559   else
560     {
561       TRETURN std::string();
562     }
563 }
564
565 const std::string
566 ParseController::get_body () const
567 {
568   TSTART;
569   if (m_outputprovider)
570     {
571       TRETURN m_outputprovider->get_body ();
572     }
573   else
574     {
575       TRETURN std::string();
576     }
577 }
578
579 const std::string
580 ParseController::get_body_charset() const
581 {
582   TSTART;
583   if (m_outputprovider)
584     {
585       TRETURN m_outputprovider->get_body_charset();
586     }
587   else
588     {
589       TRETURN std::string();
590     }
591 }
592
593 const std::string
594 ParseController::get_html_charset() const
595 {
596   TSTART;
597   if (m_outputprovider)
598     {
599       TRETURN m_outputprovider->get_html_charset();
600     }
601   else
602     {
603       TRETURN std::string();
604     }
605 }
606
607 std::vector<std::shared_ptr<Attachment> >
608 ParseController::get_attachments() const
609 {
610   TSTART;
611   if (m_outputprovider)
612     {
613       TRETURN m_outputprovider->get_attachments();
614     }
615   else
616     {
617       TRETURN std::vector<std::shared_ptr<Attachment> >();
618     }
619 }
620
621 GPGRT_LOCK_DEFINE(keylist_lock);
622 /* static */
623 std::vector<Key>
624 ParseController::get_ultimate_keys()
625 {
626   TSTART;
627   static bool s_keys_listed;
628   static std::vector<Key> s_ultimate_keys;
629   gpgrt_lock_lock (&keylist_lock);
630   if (s_keys_listed)
631     {
632       gpgrt_lock_unlock (&keylist_lock);
633       TRETURN s_ultimate_keys;
634     }
635   log_debug ("%s:%s: Starting keylisting.",
636              SRCNAME, __func__);
637   auto ctx = std::unique_ptr<Context> (Context::createForProtocol (OpenPGP));
638   if (!ctx)
639     {
640       /* Maybe PGP broken and not S/MIME */
641       log_error ("%s:%s: broken installation no ctx.",
642                  SRCNAME, __func__);
643       gpgrt_lock_unlock (&keylist_lock);
644       TRETURN s_ultimate_keys;
645     }
646   ctx->setKeyListMode (KeyListMode::Local);
647   Error err;
648   TRACEPOINT;
649   if ((err = ctx->startKeyListing ()))
650     {
651       log_error ("%s:%s: Failed to start keylisting err: %i: %s",
652                  SRCNAME, __func__, err.code (), err.asString());
653       gpgrt_lock_unlock (&keylist_lock);
654       TRETURN s_ultimate_keys;
655     }
656   TRACEPOINT;
657   while (!err)
658     {
659       const auto key = ctx->nextKey(err);
660       if (err || key.isNull())
661         {
662           TRACEPOINT;
663           break;
664         }
665       if (key.isInvalid ())
666         {
667           log_debug ("%s:%s: skipping invalid key.",
668                      SRCNAME, __func__);
669           continue;
670         }
671       for (const auto uid: key.userIDs())
672         {
673           if (uid.validity() == UserID::Validity::Ultimate &&
674               uid.id())
675             {
676               s_ultimate_keys.push_back (key);
677               log_debug ("%s:%s: Adding ultimate uid.",
678                          SRCNAME, __func__);
679               log_data ("%s:%s: Added uid %s.",
680                         SRCNAME, __func__, uid.id());
681               break;
682             }
683         }
684     }
685   TRACEPOINT;
686   log_debug ("%s:%s: keylisting done.",
687              SRCNAME, __func__);
688
689   s_keys_listed = true;
690   gpgrt_lock_unlock (&keylist_lock);
691   TRETURN s_ultimate_keys;
692 }