88263a6fd07fa4ac711a5c9438277441390f54e2
[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 <gpgme++/context.h>
29 #include <gpgme++/decryptionresult.h>
30 #include <gpgme++/key.h>
31
32 #include <sstream>
33
34 #ifdef HAVE_W32_SYSTEM
35 #include "common.h"
36 /* We use UTF-8 internally. */
37 #undef _
38 # define _(a) utf8_gettext (a)
39 #else
40 # define _(a) a
41 #endif
42
43
44
45 const char decrypt_template_html[] = {
46 "<html><head></head><body>"
47 "<table border=\"0\" width=\"100%%\" cellspacing=\"1\" cellpadding=\"1\" bgcolor=\"#0069cc\">"
48 "<tr>"
49 "<td bgcolor=\"#0080ff\">"
50 "<p><span style=\"font-weight:600; background-color:#0080ff;\"><center>%s %s</center><span></p></td></tr>"
51 "<tr>"
52 "<td bgcolor=\"#e0f0ff\">"
53 "<center>"
54 "<br/>%s"
55 "</td></tr>"
56 "</table></body></html>"};
57
58 const char decrypt_template[] = {"%s %s\n\n%s"};
59
60 using namespace GpgME;
61
62 static bool
63 expect_no_headers (msgtype_t type)
64 {
65   return type != MSGTYPE_GPGOL_MULTIPART_SIGNED;
66 }
67
68 static bool
69 expect_no_mime (msgtype_t type)
70 {
71   return type == MSGTYPE_GPGOL_PGP_MESSAGE ||
72          type == MSGTYPE_GPGOL_CLEAR_SIGNED;
73 }
74
75 #ifdef HAVE_W32_SYSTEM
76 ParseController::ParseController(LPSTREAM instream, msgtype_t type):
77     m_inputprovider  (new MimeDataProvider(instream,
78                           expect_no_headers(type))),
79     m_outputprovider (new MimeDataProvider(expect_no_mime(type))),
80     m_type (type),
81     m_block_html (false)
82 {
83   log_mime_parser ("%s:%s: Creating parser for stream: %p of type %i"
84                    " expect no headers: %i expect no mime: %i",
85                    SRCNAME, __func__, instream, type,
86                    expect_no_headers (type), expect_no_mime (type));
87 }
88 #endif
89
90 ParseController::ParseController(FILE *instream, msgtype_t type):
91     m_inputprovider  (new MimeDataProvider(instream,
92                           expect_no_headers(type))),
93     m_outputprovider (new MimeDataProvider(expect_no_mime(type))),
94     m_type (type),
95     m_block_html (false)
96 {
97   log_mime_parser ("%s:%s: Creating parser for stream: %p of type %i",
98                    SRCNAME, __func__, instream, type);
99 }
100
101 ParseController::~ParseController()
102 {
103   log_debug ("%s:%s", SRCNAME, __func__);
104   delete m_inputprovider;
105   delete m_outputprovider;
106 }
107
108 static void
109 operation_for_type(msgtype_t type, bool *decrypt,
110                    bool *verify)
111 {
112   *decrypt = false;
113   *verify = false;
114   switch (type)
115     {
116       case MSGTYPE_GPGOL_MULTIPART_ENCRYPTED:
117       case MSGTYPE_GPGOL_PGP_MESSAGE:
118         *decrypt = true;
119         break;
120       case MSGTYPE_GPGOL_MULTIPART_SIGNED:
121       case MSGTYPE_GPGOL_CLEAR_SIGNED:
122         *verify = true;
123         break;
124       case MSGTYPE_GPGOL_OPAQUE_SIGNED:
125         *verify = true;
126         break;
127       case MSGTYPE_GPGOL_OPAQUE_ENCRYPTED:
128         *decrypt = true;
129         break;
130       default:
131         log_error ("%s:%s: Unknown data type: %i",
132                    SRCNAME, __func__, type);
133     }
134 }
135
136 static bool
137 is_smime (Data &data)
138 {
139   data.seek (0, SEEK_SET);
140   auto id = data.type();
141   data.seek (0, SEEK_SET);
142   return id == Data::CMSSigned || id == Data::CMSEncrypted;
143 }
144
145 static std::string
146 format_recipients(GpgME::DecryptionResult result, Protocol protocol)
147 {
148   std::string msg;
149   for (const auto recipient: result.recipients())
150     {
151       auto ctx = Context::createForProtocol(protocol);
152       Error e;
153       if (!ctx) {
154           /* Can't happen */
155           TRACEPOINT;
156           continue;
157       }
158       const auto key = ctx->key(recipient.keyID(), e, false);
159       delete ctx;
160       if (!key.isNull() && key.numUserIDs() && !e) {
161         msg += std::string("<br/>") + key.userIDs()[0].id() + " (0x" + recipient.keyID() + ")";
162         continue;
163       }
164       msg += std::string("<br/>") + _("Unknown Key:") + " 0x" + recipient.keyID();
165     }
166   return msg;
167 }
168
169 static std::string
170 format_error(GpgME::DecryptionResult result, Protocol protocol)
171 {
172   char *buf;
173   bool no_sec = false;
174   std::string msg;
175
176   if (result.error ().isCanceled () ||
177       result.error ().code () == GPG_ERR_NO_SECKEY)
178     {
179        msg = _("Decryption canceled or timed out.");
180     }
181
182   if (result.error ().code () == GPG_ERR_DECRYPT_FAILED ||
183       result.error ().code () == GPG_ERR_NO_SECKEY)
184     {
185       no_sec = true;
186       for (const auto &recipient: result.recipients ()) {
187         no_sec &= (recipient.status ().code () == GPG_ERR_NO_SECKEY);
188       }
189     }
190
191   if (no_sec)
192     {
193       msg = _("No secret key found to decrypt the message. "
194               "It is encrypted to the following keys:");
195       msg += format_recipients (result, protocol);
196     }
197   else
198     {
199       msg = _("Could not decrypt the data: ");
200
201       if (result.isNull ())
202         {
203           msg += _("Failed to parse the mail.");
204         }
205       else
206         {
207           msg += result.error().asString();
208         }
209     }
210
211   if (gpgrt_asprintf (&buf, opt.prefer_html ? decrypt_template_html :
212                       decrypt_template,
213                       protocol == OpenPGP ? "OpenPGP" : "S/MIME",
214                       _("Encrypted message (decryption not possible)"),
215                       msg.c_str()) == -1)
216     {
217       log_error ("%s:%s:Failed to Format error.",
218                  SRCNAME, __func__);
219       return "Failed to Format error.";
220     }
221   msg = buf;
222   return msg;
223 }
224
225 void
226 ParseController::setSender(const std::string &sender)
227 {
228   m_sender = sender;
229 }
230
231 static bool
232 is_valid_chksum(const GpgME::Signature &sig)
233 {
234   switch (sig.summary())
235     {
236       case GpgME::Signature::Valid:
237       case GpgME::Signature::Green:
238       case GpgME::Signature::KeyRevoked:
239       case GpgME::Signature::KeyExpired:
240       case GpgME::Signature::SigExpired:
241       case GpgME::Signature::CrlMissing:
242       case GpgME::Signature::CrlTooOld:
243       case GpgME::Signature::TofuConflict:
244         return true;
245       default:
246         return false;
247     }
248 }
249
250 void
251 ParseController::parse()
252 {
253   // Wrap the input stream in an attachment / GpgME Data
254   Protocol protocol;
255   bool decrypt, verify;
256
257   Data input (m_inputprovider);
258
259   auto inputType = input.type ();
260
261   if (inputType == Data::Type::PGPSigned)
262     {
263       verify = true;
264       decrypt = false;
265     }
266   else
267     {
268       operation_for_type (m_type, &decrypt, &verify);
269     }
270
271   if ((m_inputprovider->signature() && is_smime (*m_inputprovider->signature())) ||
272       is_smime (input))
273     {
274       protocol = Protocol::CMS;
275     }
276   else
277     {
278       protocol = Protocol::OpenPGP;
279     }
280   auto ctx = Context::createForProtocol (protocol);
281   if (!ctx)
282     {
283       log_error ("%s:%s:Failed to create context. Installation broken.",
284                  SRCNAME, __func__);
285       char *buf;
286       const char *proto = protocol == OpenPGP ? "OpenPGP" : "S/MIME";
287       if (gpgrt_asprintf (&buf, opt.prefer_html ? decrypt_template_html :
288                           decrypt_template,
289                           proto,
290                           _("Encrypted message (decryption not possible)"),
291                           _("Failed to find GnuPG please ensure that GnuPG or "
292                             "Gpg4win is properly installed.")) == -1)
293         {
294           log_error ("%s:%s:Failed format error.",
295                      SRCNAME, __func__);
296           /* Should never happen */
297           m_error = std::string("Bad installation");
298         }
299       m_error = buf;
300       xfree (buf);
301       return;
302     }
303   ctx->setArmor(true);
304
305   if (!m_sender.empty())
306     {
307       ctx->setSender(m_sender.c_str());
308     }
309
310   Data output (m_outputprovider);
311   log_debug ("%s:%s:%p decrypt: %i verify: %i with protocol: %s sender: %s type: %i",
312              SRCNAME, __func__, this,
313              decrypt, verify,
314              protocol == OpenPGP ? "OpenPGP" :
315              protocol == CMS ? "CMS" : "Unknown",
316              m_sender.empty() ? "none" : m_sender.c_str(), inputType);
317   if (decrypt)
318     {
319       input.seek (0, SEEK_SET);
320       auto combined_result = ctx->decryptAndVerify(input, output);
321       log_debug ("%s:%s:%p decrypt / verify done.",
322                  SRCNAME, __func__, this);
323       m_decrypt_result = combined_result.first;
324       m_verify_result = combined_result.second;
325
326       if ((!m_decrypt_result.error () &&
327           m_verify_result.signatures ().empty() &&
328           m_outputprovider->signature ()) ||
329           is_smime (output) ||
330           output.type() == Data::Type::PGPSigned)
331         {
332           /* There is a signature in the output. So we have
333              to verify it now as an extra step. */
334           input = Data (m_outputprovider);
335           delete m_inputprovider;
336           m_inputprovider = m_outputprovider;
337           m_outputprovider = new MimeDataProvider();
338           output = Data(m_outputprovider);
339           verify = true;
340         }
341       else
342         {
343           verify = false;
344         }
345       if (m_decrypt_result.error () || m_decrypt_result.isNull () ||
346           m_decrypt_result.error ().isCanceled ())
347         {
348           m_error = format_error (m_decrypt_result, protocol);
349         }
350     }
351   if (verify)
352     {
353       const auto sig = m_inputprovider->signature();
354       input.seek (0, SEEK_SET);
355       if (sig)
356         {
357           sig->seek (0, SEEK_SET);
358           m_verify_result = ctx->verifyDetachedSignature(*sig, input);
359           log_debug ("%s:%s:%p verify done.",
360                      SRCNAME, __func__, this);
361           /* Copy the input to output to do a mime parsing. */
362           char buf[4096];
363           input.seek (0, SEEK_SET);
364           output.seek (0, SEEK_SET);
365           size_t nread;
366           while ((nread = input.read (buf, 4096)) > 0)
367             {
368               output.write (buf, nread);
369             }
370         }
371       else
372         {
373           m_verify_result = ctx->verifyOpaqueSignature(input, output);
374
375           const auto sigs = m_verify_result.signatures();
376           bool allBad = sigs.size();
377           for (const auto s :sigs)
378             {
379               if (!(s.summary() & Signature::Red))
380                 {
381                   allBad = false;
382                   break;
383                 }
384             }
385
386           if (allBad)
387             {
388               log_debug ("%s:%s:%p inline verify error trying native to utf8.",
389                          SRCNAME, __func__, this);
390
391               // Maybe we would need to take the internetcodepage here instead
392               // of native?
393               char *utf8 = native_to_utf8 (input.toString().c_str());
394               if (utf8)
395                 {
396                   // Try again after conversion.
397                   delete ctx;
398                   ctx = Context::createForProtocol (protocol);
399                   ctx->setArmor (true);
400                   if (!m_sender.empty())
401                     {
402                       ctx->setSender(m_sender.c_str());
403                     }
404
405                   input = Data (utf8, strlen (utf8));
406                   xfree (utf8);
407
408                   // Use a fresh output
409                   auto provider = new MimeDataProvider (true);
410
411                   // Warning: The dtor of the Data object touches
412                   // the provider. So we have to delete it after
413                   // the assignment.
414                   output = Data (provider);
415                   delete m_outputprovider;
416                   m_outputprovider = provider;
417
418                   // Try again
419                   m_verify_result = ctx->verifyOpaqueSignature(input, output);
420                 }
421             }
422         }
423     }
424   delete ctx;
425   log_debug ("%s:%s:%p: decrypt err: %i verify err: %i",
426              SRCNAME, __func__, this, m_decrypt_result.error().code(),
427              m_verify_result.error().code());
428
429   TRACEPOINT;
430
431   bool has_valid_encrypted_checksum = false;
432   /* Ensure that the Keys for the signatures are available
433      and if it has a valid encrypted checksum. */
434   for (const auto sig: m_verify_result.signatures())
435     {
436       has_valid_encrypted_checksum = is_valid_chksum (sig);
437
438       sig.key(true, true);
439       if (sig.validity() == Signature::Validity::Full ||
440           sig.validity() == Signature::Validity::Ultimate)
441         {
442           /* Ensure that we have the keys with ultimate
443              trust cached for the ui. */
444           get_ultimate_keys ();
445         }
446     }
447
448   if (protocol == Protocol::CMS && decrypt && !m_decrypt_result.error() &&
449       !has_valid_encrypted_checksum)
450     {
451       log_debug ("%s:%s:%p Encrypted S/MIME without checksum. Block HTML.",
452                  SRCNAME, __func__, this);
453       m_block_html = true;
454     }
455
456   if (opt.enable_debug)
457     {
458        std::stringstream ss;
459        ss << m_decrypt_result << '\n' << m_verify_result;
460       for (const auto sig: m_verify_result.signatures())
461         {
462           ss << '\n' << sig.key();
463         }
464        log_debug ("Decrypt / Verify result: %s", ss.str().c_str());
465     }
466   TRACEPOINT;
467
468   return;
469 }
470
471 const std::string
472 ParseController::get_html_body() const
473 {
474   if (m_outputprovider)
475     {
476       return m_outputprovider->get_html_body();
477     }
478   else
479     {
480       return std::string();
481     }
482 }
483
484 const std::string
485 ParseController::get_body() const
486 {
487   if (m_outputprovider)
488     {
489       return m_outputprovider->get_body();
490     }
491   else
492     {
493       return std::string();
494     }
495 }
496
497 const std::string
498 ParseController::get_body_charset() const
499 {
500   if (m_outputprovider)
501     {
502       return m_outputprovider->get_body_charset();
503     }
504   else
505     {
506       return std::string();
507     }
508 }
509
510 const std::string
511 ParseController::get_html_charset() const
512 {
513   if (m_outputprovider)
514     {
515       return m_outputprovider->get_html_charset();
516     }
517   else
518     {
519       return std::string();
520     }
521 }
522
523 std::vector<std::shared_ptr<Attachment> >
524 ParseController::get_attachments() const
525 {
526   if (m_outputprovider)
527     {
528       return m_outputprovider->get_attachments();
529     }
530   else
531     {
532       return std::vector<std::shared_ptr<Attachment> >();
533     }
534 }
535
536 GPGRT_LOCK_DEFINE(keylist_lock);
537 /* static */
538 std::vector<Key>
539 ParseController::get_ultimate_keys()
540 {
541   static bool s_keys_listed;
542   static std::vector<Key> s_ultimate_keys;
543   gpgrt_lock_lock (&keylist_lock);
544   if (s_keys_listed)
545     {
546       gpgrt_lock_unlock (&keylist_lock);
547       return s_ultimate_keys;
548     }
549   log_debug ("%s:%s: Starting keylisting.",
550              SRCNAME, __func__);
551   auto ctx = Context::createForProtocol (OpenPGP);
552   if (!ctx)
553     {
554       /* Maybe PGP broken and not S/MIME */
555       log_error ("%s:%s: broken installation no ctx.",
556                  SRCNAME, __func__);
557       gpgrt_lock_unlock (&keylist_lock);
558       return s_ultimate_keys;
559     }
560   ctx->setKeyListMode (KeyListMode::Local);
561   Error err;
562   TRACEPOINT;
563   if ((err = ctx->startKeyListing ()))
564     {
565       log_error ("%s:%s: Failed to start keylisting err: %i: %s",
566                  SRCNAME, __func__, err.code (), err.asString());
567       delete ctx;
568       gpgrt_lock_unlock (&keylist_lock);
569       return s_ultimate_keys;
570     }
571   TRACEPOINT;
572   while (!err)
573     {
574       const auto key = ctx->nextKey(err);
575       if (err || key.isNull())
576         {
577           TRACEPOINT;
578           break;
579         }
580       if (key.isInvalid ())
581         {
582           log_debug ("%s:%s: skipping invalid key.",
583                      SRCNAME, __func__);
584           continue;
585         }
586       for (const auto uid: key.userIDs())
587         {
588           if (uid.validity() == UserID::Validity::Ultimate &&
589               uid.id())
590             {
591               s_ultimate_keys.push_back (key);
592               log_debug ("%s:%s: Adding ultimate uid.",
593                          SRCNAME, __func__);
594               log_mime_parser ("%s:%s: Added uid %s.",
595                                SRCNAME, __func__, uid.id());
596               break;
597             }
598         }
599     }
600   TRACEPOINT;
601   delete ctx;
602   log_debug ("%s:%s: keylisting done.",
603              SRCNAME, __func__);
604
605   s_keys_listed = true;
606   gpgrt_lock_unlock (&keylist_lock);
607   return s_ultimate_keys;
608 }