Add distinct error for legacy nomdc
[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 if (result.isLegacyCipherNoMDC())
206         {
207           msg += _("Data is not integrity protected. "
208                    "Decrypting it could be a security problem. (no MDC)");
209         }
210       else
211         {
212           msg += result.error().asString();
213         }
214     }
215
216   if (gpgrt_asprintf (&buf, opt.prefer_html ? decrypt_template_html :
217                       decrypt_template,
218                       protocol == OpenPGP ? "OpenPGP" : "S/MIME",
219                       _("Encrypted message (decryption not possible)"),
220                       msg.c_str()) == -1)
221     {
222       log_error ("%s:%s:Failed to Format error.",
223                  SRCNAME, __func__);
224       return "Failed to Format error.";
225     }
226   msg = buf;
227   return msg;
228 }
229
230 void
231 ParseController::setSender(const std::string &sender)
232 {
233   m_sender = sender;
234 }
235
236 static bool
237 is_valid_chksum(const GpgME::Signature &sig)
238 {
239   switch (sig.summary())
240     {
241       case GpgME::Signature::Valid:
242       case GpgME::Signature::Green:
243       case GpgME::Signature::KeyRevoked:
244       case GpgME::Signature::KeyExpired:
245       case GpgME::Signature::SigExpired:
246       case GpgME::Signature::CrlMissing:
247       case GpgME::Signature::CrlTooOld:
248       case GpgME::Signature::TofuConflict:
249         return true;
250       default:
251         return false;
252     }
253 }
254
255 void
256 ParseController::parse()
257 {
258   // Wrap the input stream in an attachment / GpgME Data
259   Protocol protocol;
260   bool decrypt, verify;
261
262   Data input (m_inputprovider);
263
264   auto inputType = input.type ();
265
266   if (inputType == Data::Type::PGPSigned)
267     {
268       verify = true;
269       decrypt = false;
270     }
271   else
272     {
273       operation_for_type (m_type, &decrypt, &verify);
274     }
275
276   if ((m_inputprovider->signature() && is_smime (*m_inputprovider->signature())) ||
277       is_smime (input))
278     {
279       protocol = Protocol::CMS;
280     }
281   else
282     {
283       protocol = Protocol::OpenPGP;
284     }
285   auto ctx = Context::createForProtocol (protocol);
286   if (!ctx)
287     {
288       log_error ("%s:%s:Failed to create context. Installation broken.",
289                  SRCNAME, __func__);
290       char *buf;
291       const char *proto = protocol == OpenPGP ? "OpenPGP" : "S/MIME";
292       if (gpgrt_asprintf (&buf, opt.prefer_html ? decrypt_template_html :
293                           decrypt_template,
294                           proto,
295                           _("Encrypted message (decryption not possible)"),
296                           _("Failed to find GnuPG please ensure that GnuPG or "
297                             "Gpg4win is properly installed.")) == -1)
298         {
299           log_error ("%s:%s:Failed format error.",
300                      SRCNAME, __func__);
301           /* Should never happen */
302           m_error = std::string("Bad installation");
303         }
304       m_error = buf;
305       xfree (buf);
306       return;
307     }
308   ctx->setArmor(true);
309
310   if (!m_sender.empty())
311     {
312       ctx->setSender(m_sender.c_str());
313     }
314
315   Data output (m_outputprovider);
316   log_debug ("%s:%s:%p decrypt: %i verify: %i with protocol: %s sender: %s type: %i",
317              SRCNAME, __func__, this,
318              decrypt, verify,
319              protocol == OpenPGP ? "OpenPGP" :
320              protocol == CMS ? "CMS" : "Unknown",
321              m_sender.empty() ? "none" : m_sender.c_str(), inputType);
322   if (decrypt)
323     {
324       input.seek (0, SEEK_SET);
325       auto combined_result = ctx->decryptAndVerify(input, output);
326       log_debug ("%s:%s:%p decrypt / verify done.",
327                  SRCNAME, __func__, this);
328       m_decrypt_result = combined_result.first;
329       m_verify_result = combined_result.second;
330
331       if ((!m_decrypt_result.error () &&
332           m_verify_result.signatures ().empty() &&
333           m_outputprovider->signature ()) ||
334           is_smime (output) ||
335           output.type() == Data::Type::PGPSigned)
336         {
337           /* There is a signature in the output. So we have
338              to verify it now as an extra step. */
339           input = Data (m_outputprovider);
340           delete m_inputprovider;
341           m_inputprovider = m_outputprovider;
342           m_outputprovider = new MimeDataProvider();
343           output = Data(m_outputprovider);
344           verify = true;
345         }
346       else
347         {
348           verify = false;
349         }
350       if (m_decrypt_result.error () || m_decrypt_result.isNull () ||
351           m_decrypt_result.error ().isCanceled ())
352         {
353           m_error = format_error (m_decrypt_result, protocol);
354         }
355     }
356   if (verify)
357     {
358       const auto sig = m_inputprovider->signature();
359       input.seek (0, SEEK_SET);
360       if (sig)
361         {
362           sig->seek (0, SEEK_SET);
363           m_verify_result = ctx->verifyDetachedSignature(*sig, input);
364           log_debug ("%s:%s:%p verify done.",
365                      SRCNAME, __func__, this);
366           /* Copy the input to output to do a mime parsing. */
367           char buf[4096];
368           input.seek (0, SEEK_SET);
369           output.seek (0, SEEK_SET);
370           size_t nread;
371           while ((nread = input.read (buf, 4096)) > 0)
372             {
373               output.write (buf, nread);
374             }
375         }
376       else
377         {
378           m_verify_result = ctx->verifyOpaqueSignature(input, output);
379
380           const auto sigs = m_verify_result.signatures();
381           bool allBad = sigs.size();
382           for (const auto s :sigs)
383             {
384               if (!(s.summary() & Signature::Red))
385                 {
386                   allBad = false;
387                   break;
388                 }
389             }
390
391           if (allBad)
392             {
393               log_debug ("%s:%s:%p inline verify error trying native to utf8.",
394                          SRCNAME, __func__, this);
395
396               // Maybe we would need to take the internetcodepage here instead
397               // of native?
398               char *utf8 = native_to_utf8 (input.toString().c_str());
399               if (utf8)
400                 {
401                   // Try again after conversion.
402                   delete ctx;
403                   ctx = Context::createForProtocol (protocol);
404                   ctx->setArmor (true);
405                   if (!m_sender.empty())
406                     {
407                       ctx->setSender(m_sender.c_str());
408                     }
409
410                   input = Data (utf8, strlen (utf8));
411                   xfree (utf8);
412
413                   // Use a fresh output
414                   auto provider = new MimeDataProvider (true);
415
416                   // Warning: The dtor of the Data object touches
417                   // the provider. So we have to delete it after
418                   // the assignment.
419                   output = Data (provider);
420                   delete m_outputprovider;
421                   m_outputprovider = provider;
422
423                   // Try again
424                   m_verify_result = ctx->verifyOpaqueSignature(input, output);
425                 }
426             }
427         }
428     }
429   delete ctx;
430   log_debug ("%s:%s:%p: decrypt err: %i verify err: %i",
431              SRCNAME, __func__, this, m_decrypt_result.error().code(),
432              m_verify_result.error().code());
433
434   TRACEPOINT;
435
436   bool has_valid_encrypted_checksum = false;
437   /* Ensure that the Keys for the signatures are available
438      and if it has a valid encrypted checksum. */
439   for (const auto sig: m_verify_result.signatures())
440     {
441       has_valid_encrypted_checksum = is_valid_chksum (sig);
442
443       sig.key(true, true);
444       if (sig.validity() == Signature::Validity::Full ||
445           sig.validity() == Signature::Validity::Ultimate)
446         {
447           /* Ensure that we have the keys with ultimate
448              trust cached for the ui. */
449           get_ultimate_keys ();
450         }
451     }
452
453   if (protocol == Protocol::CMS && decrypt && !m_decrypt_result.error() &&
454       !has_valid_encrypted_checksum)
455     {
456       log_debug ("%s:%s:%p Encrypted S/MIME without checksum. Block HTML.",
457                  SRCNAME, __func__, this);
458       m_block_html = true;
459     }
460
461   if (opt.enable_debug)
462     {
463        std::stringstream ss;
464        ss << m_decrypt_result << '\n' << m_verify_result;
465       for (const auto sig: m_verify_result.signatures())
466         {
467           ss << '\n' << sig.key();
468         }
469        log_debug ("Decrypt / Verify result: %s", ss.str().c_str());
470     }
471   TRACEPOINT;
472
473   return;
474 }
475
476 const std::string
477 ParseController::get_html_body() const
478 {
479   if (m_outputprovider)
480     {
481       return m_outputprovider->get_html_body();
482     }
483   else
484     {
485       return std::string();
486     }
487 }
488
489 const std::string
490 ParseController::get_body() const
491 {
492   if (m_outputprovider)
493     {
494       return m_outputprovider->get_body();
495     }
496   else
497     {
498       return std::string();
499     }
500 }
501
502 const std::string
503 ParseController::get_body_charset() const
504 {
505   if (m_outputprovider)
506     {
507       return m_outputprovider->get_body_charset();
508     }
509   else
510     {
511       return std::string();
512     }
513 }
514
515 const std::string
516 ParseController::get_html_charset() const
517 {
518   if (m_outputprovider)
519     {
520       return m_outputprovider->get_html_charset();
521     }
522   else
523     {
524       return std::string();
525     }
526 }
527
528 std::vector<std::shared_ptr<Attachment> >
529 ParseController::get_attachments() const
530 {
531   if (m_outputprovider)
532     {
533       return m_outputprovider->get_attachments();
534     }
535   else
536     {
537       return std::vector<std::shared_ptr<Attachment> >();
538     }
539 }
540
541 GPGRT_LOCK_DEFINE(keylist_lock);
542 /* static */
543 std::vector<Key>
544 ParseController::get_ultimate_keys()
545 {
546   static bool s_keys_listed;
547   static std::vector<Key> s_ultimate_keys;
548   gpgrt_lock_lock (&keylist_lock);
549   if (s_keys_listed)
550     {
551       gpgrt_lock_unlock (&keylist_lock);
552       return s_ultimate_keys;
553     }
554   log_debug ("%s:%s: Starting keylisting.",
555              SRCNAME, __func__);
556   auto ctx = Context::createForProtocol (OpenPGP);
557   if (!ctx)
558     {
559       /* Maybe PGP broken and not S/MIME */
560       log_error ("%s:%s: broken installation no ctx.",
561                  SRCNAME, __func__);
562       gpgrt_lock_unlock (&keylist_lock);
563       return s_ultimate_keys;
564     }
565   ctx->setKeyListMode (KeyListMode::Local);
566   Error err;
567   TRACEPOINT;
568   if ((err = ctx->startKeyListing ()))
569     {
570       log_error ("%s:%s: Failed to start keylisting err: %i: %s",
571                  SRCNAME, __func__, err.code (), err.asString());
572       delete ctx;
573       gpgrt_lock_unlock (&keylist_lock);
574       return s_ultimate_keys;
575     }
576   TRACEPOINT;
577   while (!err)
578     {
579       const auto key = ctx->nextKey(err);
580       if (err || key.isNull())
581         {
582           TRACEPOINT;
583           break;
584         }
585       if (key.isInvalid ())
586         {
587           log_debug ("%s:%s: skipping invalid key.",
588                      SRCNAME, __func__);
589           continue;
590         }
591       for (const auto uid: key.userIDs())
592         {
593           if (uid.validity() == UserID::Validity::Ultimate &&
594               uid.id())
595             {
596               s_ultimate_keys.push_back (key);
597               log_debug ("%s:%s: Adding ultimate uid.",
598                          SRCNAME, __func__);
599               log_mime_parser ("%s:%s: Added uid %s.",
600                                SRCNAME, __func__, uid.id());
601               break;
602             }
603         }
604     }
605   TRACEPOINT;
606   delete ctx;
607   log_debug ("%s:%s: keylisting done.",
608              SRCNAME, __func__);
609
610   s_keys_listed = true;
611   gpgrt_lock_unlock (&keylist_lock);
612   return s_ultimate_keys;
613 }