1 /* -*- mode: c++; c-basic-offset:4 -*-
2     decryptverifytask.cpp
3 
4     This file is part of Kleopatra, the KDE keymanager
5     SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
6 
7     SPDX-License-Identifier: GPL-2.0-or-later
8 */
9 
10 #include <config-kleopatra.h>
11 
12 #include "decryptverifytask.h"
13 
14 #include <QGpgME/Protocol>
15 #include <QGpgME/VerifyOpaqueJob>
16 #include <QGpgME/VerifyDetachedJob>
17 #include <QGpgME/DecryptJob>
18 #include <QGpgME/DecryptVerifyJob>
19 
20 #include <Libkleo/Dn>
21 #include <Libkleo/KleoException>
22 #include <Libkleo/Stl_Util>
23 #include <Libkleo/KeyCache>
24 #include <Libkleo/Predicates>
25 #include <Libkleo/Formatting>
26 #include <Libkleo/Classify>
27 
28 #include <utils/detail_p.h>
29 #include <utils/input.h>
30 #include <utils/output.h>
31 #include <utils/kleo_assert.h>
32 #include <utils/auditlog.h>
33 #include <Libkleo/GnuPG>
34 
35 #include <KMime/HeaderParsing>
36 
37 #include <gpgme++/error.h>
38 #include <gpgme++/key.h>
39 #include <gpgme++/verificationresult.h>
40 #include <gpgme++/decryptionresult.h>
41 #include <gpgme++/context.h>
42 
43 #include <gpg-error.h>
44 
45 #include "kleopatra_debug.h"
46 #include <KLocalizedString>
47 #include <QLocale>
48 
49 #include <QByteArray>
50 #include <QDateTime>
51 #include <QStringList>
52 #include <QTextDocument> // Qt::escape
53 
54 #include <algorithm>
55 #include <sstream>
56 
57 using namespace Kleo::Crypto;
58 using namespace Kleo;
59 using namespace GpgME;
60 using namespace KMime::Types;
61 
62 namespace
63 {
64 
auditLogFromSender(QObject * sender)65 static AuditLog auditLogFromSender(QObject *sender)
66 {
67     return AuditLog::fromJob(qobject_cast<const QGpgME::Job *>(sender));
68 }
69 
addrspec_equal(const AddrSpec & lhs,const AddrSpec & rhs,Qt::CaseSensitivity cs)70 static bool addrspec_equal(const AddrSpec &lhs, const AddrSpec &rhs, Qt::CaseSensitivity cs)
71 {
72     return lhs.localPart.compare(rhs.localPart, cs) == 0 && lhs.domain.compare(rhs.domain, Qt::CaseInsensitive) == 0;
73 }
74 
mailbox_equal(const Mailbox & lhs,const Mailbox & rhs,Qt::CaseSensitivity cs)75 static bool mailbox_equal(const Mailbox &lhs, const Mailbox &rhs, Qt::CaseSensitivity cs)
76 {
77     return addrspec_equal(lhs.addrSpec(), rhs.addrSpec(), cs);
78 }
79 
stripAngleBrackets(const std::string & str)80 static std::string stripAngleBrackets(const std::string &str)
81 {
82     if (str.empty()) {
83         return str;
84     }
85     if (str[0] == '<' && str[str.size() - 1] == '>') {
86         return str.substr(1, str.size() - 2);
87     }
88     return str;
89 }
90 
email(const UserID & uid)91 static std::string email(const UserID &uid)
92 {
93 
94     if (uid.parent().protocol() == OpenPGP) {
95         if (const char *const email = uid.email()) {
96             return stripAngleBrackets(email);
97         } else {
98             return std::string();
99         }
100     }
101 
102     Q_ASSERT(uid.parent().protocol() == CMS);
103 
104     if (const char *const id = uid.id())
105         if (*id == '<') {
106             return stripAngleBrackets(id);
107         } else {
108             return DN(id)[QStringLiteral("EMAIL")].trimmed().toUtf8().constData();
109         }
110     else {
111         return std::string();
112     }
113 }
114 
mailbox(const UserID & uid)115 static Mailbox mailbox(const UserID &uid)
116 {
117     const std::string e = email(uid);
118     Mailbox mbox;
119     if (!e.empty()) {
120         mbox.setAddress(e.c_str());
121     }
122     return mbox;
123 }
124 
extractMailboxes(const Key & key)125 static std::vector<Mailbox> extractMailboxes(const Key &key)
126 {
127     std::vector<Mailbox> res;
128     const auto userIDs{key.userIDs()};
129     for (const UserID &id : userIDs) {
130         const Mailbox mbox = mailbox(id);
131         if (!mbox.addrSpec().isEmpty()) {
132             res.push_back(mbox);
133         }
134     }
135     return res;
136 }
137 
extractMailboxes(const std::vector<Key> & signers)138 static std::vector<Mailbox> extractMailboxes(const std::vector<Key> &signers)
139 {
140     std::vector<Mailbox> res;
141     for (const Key &i : signers) {
142         const std::vector<Mailbox> bxs = extractMailboxes(i);
143         res.insert(res.end(), bxs.begin(), bxs.end());
144     }
145     return res;
146 }
147 
keyContainsMailbox(const Key & key,const Mailbox & mbox)148 static bool keyContainsMailbox(const Key &key, const Mailbox &mbox)
149 {
150     const std::vector<Mailbox> mbxs = extractMailboxes(key);
151     return std::find_if(mbxs.cbegin(), mbxs.cend(),
152                         [mbox](const Mailbox &m) {
153                             return mailbox_equal(mbox, m, Qt::CaseInsensitive);
154                         }) != mbxs.cend();
155 }
156 
keysContainMailbox(const std::vector<Key> & keys,const Mailbox & mbox)157 static bool keysContainMailbox(const std::vector<Key> &keys, const Mailbox &mbox)
158 {
159     return std::find_if(keys.cbegin(), keys.cend(),
160                         [mbox](const Key &key) {
161                             return keyContainsMailbox(key, mbox);
162                         }) != keys.cend();
163 }
164 
relevantInDecryptVerifyContext(const VerificationResult & r)165 static bool relevantInDecryptVerifyContext(const VerificationResult &r)
166 {
167     // for D/V operations, we ignore verification results which are not errors and contain
168     // no signatures (which means that the data was just not signed)
169 
170     return (r.error() && r.error().code() != GPG_ERR_DECRYPT_FAILED) || r.numSignatures() > 0;
171 }
172 
signatureSummaryToString(int summary)173 static QString signatureSummaryToString(int summary)
174 {
175     if (summary & Signature::None) {
176         return i18n("Error: Signature not verified");
177     } else if (summary & Signature::Valid || summary & Signature::Green) {
178         return i18n("Good signature");
179     } else if (summary & Signature::KeyRevoked) {
180         return i18n("Signing certificate was revoked");
181     } else if (summary & Signature::KeyExpired) {
182         return i18n("Signing certificate is expired");
183     } else if (summary & Signature::KeyMissing) {
184         return i18n("Certificate is not available");
185     } else if (summary & Signature::SigExpired) {
186         return i18n("Signature expired");
187     } else if (summary & Signature::CrlMissing) {
188         return i18n("CRL missing");
189     } else if (summary & Signature::CrlTooOld) {
190         return i18n("CRL too old");
191     } else if (summary & Signature::BadPolicy) {
192         return i18n("Bad policy");
193     } else if (summary & Signature::SysError) {
194         return i18n("System error");    //### retrieve system error details?
195     } else if (summary & Signature::Red) {
196         return i18n("Bad signature");
197     }return QString();
198 }
199 
formatValidSignatureWithTrustLevel(const UserID & id)200 static QString formatValidSignatureWithTrustLevel(const UserID &id)
201 {
202     if (id.isNull()) {
203         return QString();
204     }
205     switch (id.validity()) {
206     case UserID::Marginal:
207         return i18n("The signature is valid but the trust in the certificate's validity is only marginal.");
208     case UserID::Full:
209         return i18n("The signature is valid and the certificate's validity is fully trusted.");
210     case UserID::Ultimate:
211         return i18n("The signature is valid and the certificate's validity is ultimately trusted.");
212     case UserID::Never:
213         return i18n("The signature is valid but the certificate's validity is <em>not trusted</em>.");
214     case UserID::Unknown:
215         return i18n("The signature is valid but the certificate's validity is unknown.");
216     case UserID::Undefined:
217     default:
218         return i18n("The signature is valid but the certificate's validity is undefined.");
219     }
220 }
221 
renderKeyLink(const QString & fpr,const QString & text)222 static QString renderKeyLink(const QString &fpr, const QString &text)
223 {
224     return QStringLiteral("<a href=\"key:%1\">%2</a>").arg(fpr, text);
225 }
226 
renderKey(const Key & key)227 static QString renderKey(const Key &key)
228 {
229     if (key.isNull()) {
230         return i18n("Unknown certificate");
231     }
232 
233     if (key.primaryFingerprint() && strlen(key.primaryFingerprint()) > 16 && key.numUserIDs()) {
234         const QString text = QStringLiteral("%1 (%2)").arg(Formatting::prettyNameAndEMail(key).toHtmlEscaped()).arg(
235             Formatting::prettyID(QString::fromLocal8Bit(key.primaryFingerprint()).right(16).toLatin1().constData()));
236         return renderKeyLink(QLatin1String(key.primaryFingerprint()), text);
237     }
238 
239     return renderKeyLink(QLatin1String(key.primaryFingerprint()), Formatting::prettyID(key.primaryFingerprint()));
240 }
241 
renderKeyEMailOnlyNameAsFallback(const Key & key)242 static QString renderKeyEMailOnlyNameAsFallback(const Key &key)
243 {
244     if (key.isNull()) {
245         return i18n("Unknown certificate");
246     }
247     const QString email = Formatting::prettyEMail(key);
248     const QString user = !email.isEmpty() ? email : Formatting::prettyName(key);
249     return renderKeyLink(QLatin1String(key.primaryFingerprint()), user);
250 }
251 
formatDate(const QDateTime & dt)252 static QString formatDate(const QDateTime &dt)
253 {
254     return QLocale().toString(dt);
255 }
formatSigningInformation(const Signature & sig)256 static QString formatSigningInformation(const Signature &sig)
257 {
258     if (sig.isNull()) {
259         return QString();
260     }
261     const QDateTime dt = sig.creationTime() != 0 ? QDateTime::fromSecsSinceEpoch(sig.creationTime()) : QDateTime();
262     QString text;
263     Key key = sig.key();
264     if (dt.isValid()) {
265         text = i18nc("1 is a date", "Signature created on %1", formatDate(dt)) + QStringLiteral("<br>");
266     }
267     if (key.isNull()) {
268         return text += i18n("With unavailable certificate:") + QStringLiteral("<br>ID: 0x%1").arg(QString::fromLatin1(sig.fingerprint()).toUpper());
269     }
270     text += i18n("With certificate:") + QStringLiteral("<br>") + renderKey(key);
271 
272     if (Kleo::gnupgIsDeVsCompliant()) {
273         text +=
274             (QStringLiteral("<br/>")
275              + (IS_DE_VS(sig)
276                 ? i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
277                         "The signature is %1", Formatting::deVsString())
278                 : i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
279                         "The signature <b>is not</b> %1.", Formatting::deVsString())));
280     }
281 
282     return text;
283 }
284 
strikeOut(const QString & str,bool strike)285 static QString strikeOut(const QString &str, bool strike)
286 {
287     return QString(strike ? QStringLiteral("<s>%1</s>") : QStringLiteral("%1")).arg(str.toHtmlEscaped());
288 }
289 
formatInputOutputLabel(const QString & input,const QString & output,bool inputDeleted,bool outputDeleted)290 static QString formatInputOutputLabel(const QString &input, const QString &output, bool inputDeleted, bool outputDeleted)
291 {
292     if (output.isEmpty()) {
293         return strikeOut(input, inputDeleted);
294     }
295     return i18nc("Input file --> Output file (rarr is arrow", "%1 &rarr; %2",
296                  strikeOut(input, inputDeleted),
297                  strikeOut(output, outputDeleted));
298 }
299 
IsErrorOrCanceled(const GpgME::Error & err)300 static bool IsErrorOrCanceled(const GpgME::Error &err)
301 {
302     return err || err.isCanceled();
303 }
304 
IsErrorOrCanceled(const Result & res)305 static bool IsErrorOrCanceled(const Result &res)
306 {
307     return IsErrorOrCanceled(res.error());
308 }
309 
IsBad(const Signature & sig)310 static bool IsBad(const Signature &sig)
311 {
312     return sig.summary() & Signature::Red;
313 }
314 
IsGoodOrValid(const Signature & sig)315 static bool IsGoodOrValid(const Signature &sig)
316 {
317     return (sig.summary() & Signature::Valid) || (sig.summary() & Signature::Green);
318 }
319 
findUserIDByMailbox(const Key & key,const Mailbox & mbox)320 static UserID findUserIDByMailbox(const Key &key, const Mailbox &mbox)
321 {
322     const auto userIDs{key.userIDs()};
323     for (const UserID &id : userIDs)
324         if (mailbox_equal(mailbox(id), mbox, Qt::CaseInsensitive)) {
325             return id;
326         }
327     return UserID();
328 }
329 
updateKeys(const VerificationResult & result)330 static void updateKeys(const VerificationResult &result) {
331     // This little hack works around the problem that GnuPG / GpgME does not
332     // provide Key information in a verification result. The Key object is
333     // a dummy just holding the KeyID. This hack ensures that all available
334     // keys are fetched from the backend and are populated
335     for (const auto &sig: result.signatures()) {
336         // Update key information
337         sig.key(true, true);
338     }
339 }
340 
341 }
342 
343 class DecryptVerifyResult::SenderInfo
344 {
345 public:
SenderInfo(const Mailbox & infSender,const std::vector<Key> & signers_)346     explicit SenderInfo(const Mailbox &infSender, const std::vector<Key> &signers_) : informativeSender(infSender), signers(signers_) {}
347     const Mailbox informativeSender;
348     const std::vector<Key> signers;
hasInformativeSender() const349     bool hasInformativeSender() const
350     {
351         return !informativeSender.addrSpec().isEmpty();
352     }
conflicts() const353     bool conflicts() const
354     {
355         return hasInformativeSender() && hasKeys() && !keysContainMailbox(signers, informativeSender);
356     }
hasKeys() const357     bool hasKeys() const
358     {
359         return std::any_of(signers.cbegin(), signers.cend(), [](const Key &key) { return !key.isNull(); });
360     }
signerMailboxes() const361     std::vector<Mailbox> signerMailboxes() const
362     {
363         return extractMailboxes(signers);
364     }
365 };
366 
367 namespace
368 {
369 
codeForVerificationResult(const VerificationResult & res)370 static Task::Result::VisualCode codeForVerificationResult(const VerificationResult &res)
371 {
372     if (res.isNull()) {
373         return Task::Result::NeutralSuccess;
374     }
375 
376     const std::vector<Signature> sigs = res.signatures();
377     if (sigs.empty()) {
378         return Task::Result::Warning;
379     }
380 
381     if (std::find_if(sigs.begin(), sigs.end(), IsBad) != sigs.end()) {
382         return Task::Result::Danger;
383     }
384 
385     if ((size_t)std::count_if(sigs.begin(), sigs.end(), IsGoodOrValid) == sigs.size()) {
386         return Task::Result::AllGood;
387     }
388 
389     return Task::Result::Warning;
390 }
391 
formatVerificationResultOverview(const VerificationResult & res,const DecryptVerifyResult::SenderInfo & info)392 static QString formatVerificationResultOverview(const VerificationResult &res, const DecryptVerifyResult::SenderInfo &info)
393 {
394     if (res.isNull()) {
395         return QString();
396     }
397 
398     const Error err = res.error();
399 
400     if (err.isCanceled()) {
401         return i18n("<b>Verification canceled.</b>");
402     } else if (err) {
403         return i18n("<b>Verification failed: %1.</b>", QString::fromLocal8Bit(err.asString()).toHtmlEscaped());
404     }
405 
406     const std::vector<Signature> sigs = res.signatures();
407 
408     if (sigs.empty()) {
409         return i18n("<b>No signatures found.</b>");
410     }
411 
412     const uint bad = std::count_if(sigs.cbegin(), sigs.cend(), IsBad);
413     if (bad > 0) {
414         return i18np("<b>Invalid signature.</b>", "<b>%1 invalid signatures.</b>", bad);
415     }
416     const uint warn = std::count_if(sigs.cbegin(), sigs.cend(), [](const Signature &sig) { return !IsGoodOrValid(sig); });
417     if (warn == sigs.size()) {
418         return i18np("<b>The data could not be verified.</b>", "<b>%1 signatures could not be verified.</b>", warn);
419     }
420 
421     //Good signature:
422     QString text;
423     if (sigs.size() == 1) {
424         text = i18n("<b>Valid signature by %1</b>", renderKeyEMailOnlyNameAsFallback(sigs[0].key()));
425         if (info.conflicts())
426             text += i18n("<br/><b>Warning:</b> The sender's mail address is not stored in the %1 used for signing.",
427                          renderKeyLink(QLatin1String(sigs[0].key().primaryFingerprint()), i18n("certificate")));
428     } else {
429         text = i18np("<b>Valid signature.</b>", "<b>%1 valid signatures.</b>", sigs.size());
430         if (info.conflicts()) {
431             text += i18n("<br/><b>Warning:</b> The sender's mail address is not stored in the certificates used for signing.");
432         }
433     }
434 
435     return text;
436 }
437 
formatDecryptionResultOverview(const DecryptionResult & result,const QString & errorString=QString ())438 static QString formatDecryptionResultOverview(const DecryptionResult &result, const QString &errorString = QString())
439 {
440     const Error err = result.error();
441 
442     if (err.isCanceled()) {
443         return i18n("<b>Decryption canceled.</b>");
444     }
445     else if (result.isLegacyCipherNoMDC()) {
446         return i18n("<b>Decryption failed: %1.</b>", i18n("No integrity protection (MDC)."));
447     }
448     else if (!errorString.isEmpty()) {
449         return i18n("<b>Decryption failed: %1.</b>", errorString.toHtmlEscaped());
450     } else if (err) {
451         return i18n("<b>Decryption failed: %1.</b>", QString::fromLocal8Bit(err.asString()).toHtmlEscaped());
452     }
453     return i18n("<b>Decryption succeeded.</b>");
454 }
455 
formatSignature(const Signature & sig,const DecryptVerifyResult::SenderInfo & info)456 static QString formatSignature(const Signature &sig, const DecryptVerifyResult::SenderInfo &info)
457 {
458     if (sig.isNull()) {
459         return QString();
460     }
461 
462     const QString text = formatSigningInformation(sig) + QLatin1String("<br/>");
463     const Key key = sig.key();
464 
465     // Green
466     if (sig.summary() & Signature::Valid) {
467         const UserID id = findUserIDByMailbox(key, info.informativeSender);
468         return text + formatValidSignatureWithTrustLevel(!id.isNull() ? id : key.userID(0));
469     }
470 
471     // Red
472     if ((sig.summary() & Signature::Red)) {
473         const QString ret = text + i18n("The signature is invalid: %1", signatureSummaryToString(sig.summary()));
474         if (sig.summary() & Signature::SysError) {
475             return ret + QStringLiteral(" (%1)").arg(QString::fromLocal8Bit(sig.status().asString()));
476         }
477         return ret;
478     }
479 
480     // Key missing
481     if ((sig.summary() & Signature::KeyMissing)) {
482         return text + i18n("You can search the certificate on a keyserver or import it from a file.");
483     }
484 
485     // Yellow
486     if ((sig.validity() & Signature::Validity::Undefined) ||
487         (sig.validity() & Signature::Validity::Unknown) ||
488         (sig.summary() == Signature::Summary::None)) {
489         return text + (key.protocol() == OpenPGP ? i18n("The used key is not certified by you or any trusted person.") :
490                i18n("The used certificate is not certified by a trustworthy Certificate Authority or the Certificate Authority is unknown."));
491     }
492 
493     // Catch all fall through
494     const QString ret = text + i18n("The signature is invalid: %1", signatureSummaryToString(sig.summary()));
495     if (sig.summary() & Signature::SysError) {
496         return ret + QStringLiteral(" (%1)").arg(QString::fromLocal8Bit(sig.status().asString()));
497     }
498     return ret;
499 }
500 
format(const std::vector<Mailbox> & mbxs)501 static QStringList format(const std::vector<Mailbox> &mbxs)
502 {
503     QStringList res;
504     std::transform(mbxs.cbegin(), mbxs.cend(), std::back_inserter(res),
505                    [](const Mailbox &mbox) {
506                        return mbox.prettyAddress();
507                    });
508     return res;
509 }
510 
formatVerificationResultDetails(const VerificationResult & res,const DecryptVerifyResult::SenderInfo & info,const QString & errorString)511 static QString formatVerificationResultDetails(const VerificationResult &res, const DecryptVerifyResult::SenderInfo &info, const QString &errorString)
512 {
513     if ((res.error().code() == GPG_ERR_EIO || res.error().code() == GPG_ERR_NO_DATA) && !errorString.isEmpty()) {
514         return i18n("Input error: %1", errorString);
515     }
516 
517     const std::vector<Signature> sigs = res.signatures();
518     QString details;
519     for (const Signature &sig : sigs) {
520         details += formatSignature(sig, info) + QLatin1Char('\n');
521     }
522     details = details.trimmed();
523     details.replace(QLatin1Char('\n'), QStringLiteral("<br/><br/>"));
524     if (info.conflicts()) {
525         details += i18n("<p>The sender's address %1 is not stored in the certificate. Stored: %2</p>", info.informativeSender.prettyAddress(), format(info.signerMailboxes()).join(i18nc("separator for a list of e-mail addresses", ", ")));
526     }
527     return details;
528 }
529 
formatRecipientsDetails(const std::vector<Key> & knownRecipients,unsigned int numRecipients)530 static QString formatRecipientsDetails(const std::vector<Key> &knownRecipients, unsigned int numRecipients)
531 {
532     if (numRecipients == 0) {
533         return {};
534     }
535 
536     if (knownRecipients.empty()) {
537         return QLatin1String("<i>") +
538                i18np("One unknown recipient.", "%1 unknown recipients.", numRecipients) +
539                QLatin1String("</i>");
540     }
541 
542     QString details = i18np("Recipient:", "Recipients:", numRecipients);
543 
544     if (numRecipients == 1) {
545         details += QLatin1Char(' ') + renderKey(knownRecipients.front());
546     } else {
547         details += QLatin1String("<ul>");
548         for (const Key &key : knownRecipients) {
549             details += QLatin1String("<li>") + renderKey(key) + QLatin1String("</li>");
550         }
551         if (knownRecipients.size() < numRecipients) {
552             details += QLatin1String("<li><i>") +
553                        i18np("One unknown recipient", "%1 unknown recipients",
554                              numRecipients - knownRecipients.size()) +
555                        QLatin1String("</i></li>");
556         }
557         details += QLatin1String("</ul>");
558     }
559 
560     return details;
561 }
562 
formatDecryptionResultDetails(const DecryptionResult & res,const std::vector<Key> & recipients,const QString & errorString,bool isSigned,const QPointer<Task> & task)563 static QString formatDecryptionResultDetails(const DecryptionResult &res, const std::vector<Key> &recipients,
564                                              const QString &errorString, bool isSigned, const QPointer<Task> &task)
565 {
566     if ((res.error().code() == GPG_ERR_EIO || res.error().code() == GPG_ERR_NO_DATA) && !errorString.isEmpty()) {
567         return i18n("Input error: %1", errorString);
568     }
569 
570     if (res.isNull() || res.error() || res.error().isCanceled()) {
571         return formatRecipientsDetails(recipients, res.numRecipients());
572     }
573 
574     QString details;
575 
576     if (Kleo::gnupgIsDeVsCompliant()) {
577         details += ((IS_DE_VS(res)
578                      ? i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
579                              "The decryption is %1.", Formatting::deVsString())
580                      : i18nc("%1 is a placeholder for the name of a compliance mode. E.g. NATO RESTRICTED compliant or VS-NfD compliant",
581                              "The decryption <b>is not</b> %1."), Formatting::deVsString())
582                     + QStringLiteral("<br/>"));
583     }
584 
585     if (res.fileName()) {
586         const auto decVerifyTask = qobject_cast<AbstractDecryptVerifyTask*> (task.data());
587         if (decVerifyTask) {
588             const auto embedFileName = QString::fromUtf8(res.fileName()).toHtmlEscaped();
589 
590             if (embedFileName != decVerifyTask->outputLabel()) {
591                 details += i18n("Embedded file name: '%1'", embedFileName);
592                 details += QStringLiteral("<br/>");
593             }
594         }
595     }
596 
597     if (!isSigned) {
598         details += i18n("<b>Note:</b> You cannot be sure who encrypted this message as it is not signed.")
599                    + QLatin1String("<br/>");
600     }
601 
602     if (res.isLegacyCipherNoMDC()) {
603         details += i18nc("Integrity protection was missing because an old cipher was used.",
604                          "<b>Hint:</b> If this file was encrypted before the year 2003 it is "
605                          "likely that the file is legitimate.  This is because back "
606                          "then integrity protection was not widely used.") + QStringLiteral("<br/><br/>") +
607                    i18nc("The user is offered to force decrypt a non integrity protected message. With the strong advice to re-encrypt it.",
608                          "If you are confident that the file was not manipulated you should re-encrypt it after you have forced the decryption.") +
609                    QStringLiteral("<br/><br/>");
610     }
611 
612     details += formatRecipientsDetails(recipients, res.numRecipients());
613 
614     return details;
615 }
616 
formatDecryptVerifyResultOverview(const DecryptionResult & dr,const VerificationResult & vr,const DecryptVerifyResult::SenderInfo & info)617 static QString formatDecryptVerifyResultOverview(const DecryptionResult &dr, const VerificationResult &vr, const  DecryptVerifyResult::SenderInfo &info)
618 {
619     if (IsErrorOrCanceled(dr) || !relevantInDecryptVerifyContext(vr)) {
620         return formatDecryptionResultOverview(dr);
621     }
622     return formatVerificationResultOverview(vr, info);
623 }
624 
formatDecryptVerifyResultDetails(const DecryptionResult & dr,const VerificationResult & vr,const std::vector<Key> & recipients,const DecryptVerifyResult::SenderInfo & info,const QString & errorString,const QPointer<Task> & task)625 static QString formatDecryptVerifyResultDetails(const DecryptionResult &dr,
626         const VerificationResult &vr,
627         const std::vector<Key> &recipients,
628         const DecryptVerifyResult::SenderInfo &info,
629         const QString &errorString,
630         const QPointer<Task> &task)
631 {
632     const QString drDetails = formatDecryptionResultDetails(dr, recipients, errorString, relevantInDecryptVerifyContext(vr), task);
633     if (IsErrorOrCanceled(dr) || !relevantInDecryptVerifyContext(vr)) {
634         return drDetails;
635     }
636     return drDetails + (drDetails.isEmpty() ? QString() : QStringLiteral("<br/>")) + formatVerificationResultDetails(vr, info, errorString);
637 }
638 
639 } // anon namespace
640 
641 class DecryptVerifyResult::Private
642 {
643     DecryptVerifyResult *const q;
644 public:
Private(DecryptVerifyOperation type,const VerificationResult & vr,const DecryptionResult & dr,const QByteArray & stuff,int errCode,const QString & errString,const QString & input,const QString & output,const AuditLog & auditLog,Task * parentTask,const Mailbox & informativeSender,DecryptVerifyResult * qq)645     Private(DecryptVerifyOperation type,
646             const VerificationResult &vr,
647             const DecryptionResult &dr,
648             const QByteArray &stuff,
649             int errCode,
650             const QString &errString,
651             const QString &input,
652             const QString &output,
653             const AuditLog &auditLog,
654             Task *parentTask,
655             const Mailbox &informativeSender,
656             DecryptVerifyResult *qq) :
657         q(qq),
658         m_type(type),
659         m_verificationResult(vr),
660         m_decryptionResult(dr),
661         m_stuff(stuff),
662         m_error(errCode),
663         m_errorString(errString),
664         m_inputLabel(input),
665         m_outputLabel(output),
666         m_auditLog(auditLog),
667         m_parentTask(QPointer<Task>(parentTask)),
668         m_informativeSender(informativeSender)
669     {
670     }
671 
label() const672     QString label() const
673     {
674         return formatInputOutputLabel(m_inputLabel, m_outputLabel, false, q->hasError());
675     }
676 
677     DecryptVerifyResult::SenderInfo makeSenderInfo() const;
678 
isDecryptOnly() const679     bool isDecryptOnly() const
680     {
681         return m_type == Decrypt;
682     }
isVerifyOnly() const683     bool isVerifyOnly() const
684     {
685         return m_type == Verify;
686     }
isDecryptVerify() const687     bool isDecryptVerify() const
688     {
689         return m_type == DecryptVerify;
690     }
691     DecryptVerifyOperation m_type;
692     VerificationResult m_verificationResult;
693     DecryptionResult m_decryptionResult;
694     QByteArray m_stuff;
695     int m_error;
696     QString m_errorString;
697     QString m_inputLabel;
698     QString m_outputLabel;
699     const AuditLog m_auditLog;
700     QPointer <Task> m_parentTask;
701     const Mailbox m_informativeSender;
702 };
703 
makeSenderInfo() const704 DecryptVerifyResult::SenderInfo DecryptVerifyResult::Private::makeSenderInfo() const
705 {
706     return SenderInfo(m_informativeSender, KeyCache::instance()->findSigners(m_verificationResult));
707 }
708 
fromDecryptResult(const DecryptionResult & dr,const QByteArray & plaintext,const AuditLog & auditLog)709 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptResult(const DecryptionResult &dr, const QByteArray &plaintext, const AuditLog &auditLog)
710 {
711     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(
712             Decrypt,
713             VerificationResult(),
714             dr,
715             plaintext,
716             0,
717             QString(),
718             inputLabel(),
719             outputLabel(),
720             auditLog,
721             this,
722             informativeSender()));
723 }
724 
fromDecryptResult(const GpgME::Error & err,const QString & what,const AuditLog & auditLog)725 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptResult(const GpgME::Error &err, const QString &what, const AuditLog &auditLog)
726 {
727     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(
728             Decrypt,
729             VerificationResult(),
730             DecryptionResult(err),
731             QByteArray(),
732             err.code(),
733             what,
734             inputLabel(),
735             outputLabel(),
736             auditLog,
737             this,
738             informativeSender()));
739 }
740 
fromDecryptVerifyResult(const DecryptionResult & dr,const VerificationResult & vr,const QByteArray & plaintext,const AuditLog & auditLog)741 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptVerifyResult(const DecryptionResult &dr, const VerificationResult &vr, const QByteArray &plaintext, const AuditLog &auditLog)
742 {
743     int err = dr.error() ? dr.error().code() : vr.error().code();
744     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(
745             DecryptVerify,
746             vr,
747             dr,
748             plaintext,
749             err,
750             QString(),
751             inputLabel(),
752             outputLabel(),
753             auditLog,
754             this,
755             informativeSender()));
756 }
757 
fromDecryptVerifyResult(const GpgME::Error & err,const QString & details,const AuditLog & auditLog)758 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromDecryptVerifyResult(const GpgME::Error &err, const QString &details, const AuditLog &auditLog)
759 {
760     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(
761             DecryptVerify,
762             VerificationResult(),
763             DecryptionResult(err),
764             QByteArray(),
765             err.code(),
766             details,
767             inputLabel(),
768             outputLabel(),
769             auditLog,
770             this,
771             informativeSender()));
772 }
773 
fromVerifyOpaqueResult(const VerificationResult & vr,const QByteArray & plaintext,const AuditLog & auditLog)774 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromVerifyOpaqueResult(const VerificationResult &vr, const QByteArray &plaintext, const AuditLog &auditLog)
775 {
776     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(
777             Verify,
778             vr,
779             DecryptionResult(),
780             plaintext,
781             0,
782             QString(),
783             inputLabel(),
784             outputLabel(),
785             auditLog,
786             this,
787             informativeSender()));
788 }
fromVerifyOpaqueResult(const GpgME::Error & err,const QString & details,const AuditLog & auditLog)789 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromVerifyOpaqueResult(const GpgME::Error &err, const QString &details, const AuditLog &auditLog)
790 {
791     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(
792             Verify,
793             VerificationResult(err),
794             DecryptionResult(),
795             QByteArray(),
796             err.code(),
797             details,
798             inputLabel(),
799             outputLabel(),
800             auditLog,
801             this,
802             informativeSender()));
803 }
804 
fromVerifyDetachedResult(const VerificationResult & vr,const AuditLog & auditLog)805 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromVerifyDetachedResult(const VerificationResult &vr, const AuditLog &auditLog)
806 {
807     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(
808             Verify,
809             vr,
810             DecryptionResult(),
811             QByteArray(),
812             0,
813             QString(),
814             inputLabel(),
815             outputLabel(),
816             auditLog,
817             this,
818             informativeSender()));
819 }
fromVerifyDetachedResult(const GpgME::Error & err,const QString & details,const AuditLog & auditLog)820 std::shared_ptr<DecryptVerifyResult> AbstractDecryptVerifyTask::fromVerifyDetachedResult(const GpgME::Error &err, const QString &details, const AuditLog &auditLog)
821 {
822     return std::shared_ptr<DecryptVerifyResult>(new DecryptVerifyResult(
823             Verify,
824             VerificationResult(err),
825             DecryptionResult(),
826             QByteArray(),
827             err.code(),
828             details,
829             inputLabel(),
830             outputLabel(),
831             auditLog,
832             this,
833             informativeSender()));
834 }
835 
DecryptVerifyResult(DecryptVerifyOperation type,const VerificationResult & vr,const DecryptionResult & dr,const QByteArray & stuff,int errCode,const QString & errString,const QString & inputLabel,const QString & outputLabel,const AuditLog & auditLog,Task * parentTask,const Mailbox & informativeSender)836 DecryptVerifyResult::DecryptVerifyResult(DecryptVerifyOperation type,
837         const VerificationResult &vr,
838         const DecryptionResult &dr,
839         const QByteArray &stuff,
840         int errCode,
841         const QString &errString,
842         const QString &inputLabel,
843         const QString &outputLabel,
844         const AuditLog &auditLog,
845         Task *parentTask,
846         const Mailbox &informativeSender)
847     : Task::Result(), d(new Private(type, vr, dr, stuff, errCode, errString, inputLabel, outputLabel, auditLog, parentTask, informativeSender, this))
848 {
849 }
850 
overview() const851 QString DecryptVerifyResult::overview() const
852 {
853     QString ov;
854     if (d->isDecryptOnly()) {
855         ov += formatDecryptionResultOverview(d->m_decryptionResult);
856     } else if (d->isVerifyOnly()) {
857         ov += formatVerificationResultOverview(d->m_verificationResult, d->makeSenderInfo());
858     } else {
859         ov += formatDecryptVerifyResultOverview(d->m_decryptionResult, d->m_verificationResult, d->makeSenderInfo());
860     }
861     if (ov.size() + d->label().size() > 120) {
862         // Avoid ugly breaks
863         ov = QStringLiteral("<br>") + ov;
864     }
865     return i18nc("label: result example: foo.sig: Verification failed. ", "%1: %2", d->label(), ov);
866 }
867 
details() const868 QString DecryptVerifyResult::details() const
869 {
870     if (d->isDecryptOnly()) {
871         return formatDecryptionResultDetails(d->m_decryptionResult,
872                 KeyCache::instance()->findRecipients(d->m_decryptionResult),
873                 errorString(), false, d->m_parentTask);
874     }
875     if (d->isVerifyOnly()) {
876         return formatVerificationResultDetails(d->m_verificationResult, d->makeSenderInfo(), errorString());
877     }
878     return formatDecryptVerifyResultDetails(d->m_decryptionResult,
879                                             d->m_verificationResult, KeyCache::instance()->findRecipients(
880                                                     d->m_decryptionResult), d->makeSenderInfo(), errorString(),
881                                             d->m_parentTask);
882 }
883 
hasError() const884 bool DecryptVerifyResult::hasError() const
885 {
886     return d->m_error != 0;
887 }
888 
errorCode() const889 int DecryptVerifyResult::errorCode() const
890 {
891     return d->m_error;
892 }
893 
errorString() const894 QString DecryptVerifyResult::errorString() const
895 {
896     return d->m_errorString;
897 }
898 
auditLog() const899 AuditLog DecryptVerifyResult::auditLog() const
900 {
901     return d->m_auditLog;
902 }
903 
parentTask() const904 QPointer<Task> DecryptVerifyResult::parentTask() const
905 {
906     return d->m_parentTask;
907 }
908 
code() const909 Task::Result::VisualCode DecryptVerifyResult::code() const
910 {
911     if ((d->m_type == DecryptVerify || d->m_type == Verify) && relevantInDecryptVerifyContext(verificationResult())) {
912         return codeForVerificationResult(verificationResult());
913     }
914     return hasError() ? NeutralError : NeutralSuccess;
915 }
916 
verificationResult() const917 GpgME::VerificationResult DecryptVerifyResult::verificationResult() const
918 {
919     return d->m_verificationResult;
920 }
921 
decryptionResult() const922 GpgME::DecryptionResult DecryptVerifyResult::decryptionResult() const
923 {
924     return d->m_decryptionResult;
925 }
926 
927 class AbstractDecryptVerifyTask::Private
928 {
929 public:
930     Mailbox informativeSender;
931 };
932 
AbstractDecryptVerifyTask(QObject * parent)933 AbstractDecryptVerifyTask::AbstractDecryptVerifyTask(QObject *parent) : Task(parent), d(new Private) {}
934 
~AbstractDecryptVerifyTask()935 AbstractDecryptVerifyTask::~AbstractDecryptVerifyTask() {}
936 
informativeSender() const937 Mailbox AbstractDecryptVerifyTask::informativeSender() const
938 {
939     return d->informativeSender;
940 }
941 
setInformativeSender(const Mailbox & sender)942 void AbstractDecryptVerifyTask::setInformativeSender(const Mailbox &sender)
943 {
944     d->informativeSender = sender;
945 }
946 
947 class DecryptVerifyTask::Private
948 {
949     DecryptVerifyTask *const q;
950 public:
Private(DecryptVerifyTask * qq)951     explicit Private(DecryptVerifyTask *qq) : q(qq), m_backend(nullptr), m_protocol(UnknownProtocol), m_ignoreMDCError(false)  {}
952 
953     void slotResult(const DecryptionResult &, const VerificationResult &, const QByteArray &);
954 
registerJob(QGpgME::DecryptVerifyJob * job)955     void registerJob(QGpgME::DecryptVerifyJob *job)
956     {
957         q->connect(job, SIGNAL(result(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray)),
958                    q, SLOT(slotResult(GpgME::DecryptionResult,GpgME::VerificationResult,QByteArray)));
959         q->connect(job, SIGNAL(progress(QString,int,int)),
960                    q, SLOT(setProgress(QString,int,int)));
961     }
962 
963     void emitResult(const std::shared_ptr<DecryptVerifyResult> &result);
964 
965     std::shared_ptr<Input> m_input;
966     std::shared_ptr<Output> m_output;
967     const QGpgME::Protocol *m_backend;
968     Protocol m_protocol;
969     bool m_ignoreMDCError;
970 };
971 
emitResult(const std::shared_ptr<DecryptVerifyResult> & result)972 void DecryptVerifyTask::Private::emitResult(const std::shared_ptr<DecryptVerifyResult> &result)
973 {
974     q->emitResult(result);
975     Q_EMIT q->decryptVerifyResult(result);
976 }
977 
slotResult(const DecryptionResult & dr,const VerificationResult & vr,const QByteArray & plainText)978 void DecryptVerifyTask::Private::slotResult(const DecryptionResult &dr, const VerificationResult &vr, const QByteArray &plainText)
979 {
980     updateKeys(vr);
981     {
982         std::stringstream ss;
983         ss << dr << '\n' << vr;
984         qCDebug(KLEOPATRA_LOG) << ss.str().c_str();
985     }
986     const AuditLog auditLog = auditLogFromSender(q->sender());
987     if (dr.error().code() || vr.error().code()) {
988         m_output->cancel();
989     } else {
990         try {
991             kleo_assert(!dr.isNull() || !vr.isNull());
992             m_output->finalize();
993         } catch (const GpgME::Exception &e) {
994             emitResult(q->fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
995             return;
996         } catch (const std::exception &e) {
997             emitResult(q->fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog));
998             return;
999         } catch (...) {
1000             emitResult(q->fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog));
1001             return;
1002         }
1003     }
1004     const int drErr = dr.error().code();
1005     const QString errorString = m_output->errorString();
1006     if (((drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty()) ||
1007           m_output->failed()) {
1008         emitResult(q->fromDecryptResult(drErr ? dr.error() : Error::fromCode(GPG_ERR_EIO),
1009                     errorString, auditLog));
1010         return;
1011     }
1012 
1013     emitResult(q->fromDecryptVerifyResult(dr, vr, plainText, auditLog));
1014 }
1015 
DecryptVerifyTask(QObject * parent)1016 DecryptVerifyTask::DecryptVerifyTask(QObject *parent) : AbstractDecryptVerifyTask(parent), d(new Private(this))
1017 {
1018 }
1019 
~DecryptVerifyTask()1020 DecryptVerifyTask::~DecryptVerifyTask()
1021 {
1022 }
1023 
setInput(const std::shared_ptr<Input> & input)1024 void DecryptVerifyTask::setInput(const std::shared_ptr<Input> &input)
1025 {
1026     d->m_input = input;
1027     kleo_assert(d->m_input && d->m_input->ioDevice());
1028 }
1029 
setOutput(const std::shared_ptr<Output> & output)1030 void DecryptVerifyTask::setOutput(const std::shared_ptr<Output> &output)
1031 {
1032     d->m_output = output;
1033     kleo_assert(d->m_output && d->m_output->ioDevice());
1034 }
1035 
setProtocol(Protocol prot)1036 void DecryptVerifyTask::setProtocol(Protocol prot)
1037 {
1038     kleo_assert(prot != UnknownProtocol);
1039     d->m_protocol = prot;
1040     d->m_backend = prot == GpgME::OpenPGP ? QGpgME::openpgp() : QGpgME::smime();
1041     kleo_assert(d->m_backend);
1042 }
1043 
autodetectProtocolFromInput()1044 void DecryptVerifyTask::autodetectProtocolFromInput()
1045 {
1046     if (!d->m_input) {
1047         return;
1048     }
1049     const Protocol p = findProtocol(d->m_input->classification());
1050     if (p == UnknownProtocol) {
1051         throw Exception(gpg_error(GPG_ERR_NOTHING_FOUND), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature/ciphertext - maybe it is neither ciphertext nor a signature?"), Exception::MessageOnly);
1052     }
1053     setProtocol(p);
1054 }
1055 
label() const1056 QString DecryptVerifyTask::label() const
1057 {
1058     return i18n("Decrypting: %1...", d->m_input->label());
1059 }
1060 
inputSize() const1061 unsigned long long DecryptVerifyTask::inputSize() const
1062 {
1063     return d->m_input ? d->m_input->size() : 0;
1064 }
1065 
inputLabel() const1066 QString DecryptVerifyTask::inputLabel() const
1067 {
1068     return d->m_input ? d->m_input->label() : QString();
1069 }
1070 
outputLabel() const1071 QString DecryptVerifyTask::outputLabel() const
1072 {
1073     return d->m_output ? d->m_output->label() : QString();
1074 }
1075 
protocol() const1076 Protocol DecryptVerifyTask::protocol() const
1077 {
1078     return d->m_protocol;
1079 }
1080 
cancel()1081 void DecryptVerifyTask::cancel()
1082 {
1083 
1084 }
1085 
ensureIOOpen(QIODevice * input,QIODevice * output)1086 static void ensureIOOpen(QIODevice *input, QIODevice *output)
1087 {
1088     if (input && !input->isOpen()) {
1089         input->open(QIODevice::ReadOnly);
1090     }
1091     if (output && !output->isOpen()) {
1092         output->open(QIODevice::WriteOnly);
1093     }
1094 }
1095 
setIgnoreMDCError(bool value)1096 void DecryptVerifyTask::setIgnoreMDCError(bool value)
1097 {
1098     d->m_ignoreMDCError = value;
1099 }
1100 
doStart()1101 void DecryptVerifyTask::doStart()
1102 {
1103     kleo_assert(d->m_backend);
1104     try {
1105         QGpgME::DecryptVerifyJob *const job = d->m_backend->decryptVerifyJob();
1106 
1107         if (d->m_ignoreMDCError) {
1108             qCDebug(KLEOPATRA_LOG) << "Modifying job to ignore MDC errors.";
1109             auto ctx = QGpgME::Job::context(job);
1110             if (!ctx) {
1111                 qCWarning(KLEOPATRA_LOG) << "Failed to get context for job";
1112             } else {
1113                 const auto err = ctx->setFlag("ignore-mdc-error", "1");
1114                 if (err) {
1115                     qCWarning(KLEOPATRA_LOG) << "Failed to set ignore mdc errors" << err.asString();
1116                 }
1117             }
1118         }
1119         kleo_assert(job);
1120         d->registerJob(job);
1121         ensureIOOpen(d->m_input->ioDevice().get(), d->m_output->ioDevice().get());
1122         job->start(d->m_input->ioDevice(), d->m_output->ioDevice());
1123     } catch (const GpgME::Exception &e) {
1124         d->emitResult(fromDecryptVerifyResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLog()));
1125     } catch (const std::exception &e) {
1126         d->emitResult(fromDecryptVerifyResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog()));
1127     } catch (...) {
1128         d->emitResult(fromDecryptVerifyResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLog()));
1129     }
1130 
1131 }
1132 
1133 class DecryptTask::Private
1134 {
1135     DecryptTask *const q;
1136 public:
Private(DecryptTask * qq)1137     explicit Private(DecryptTask *qq) : q(qq), m_backend(nullptr), m_protocol(UnknownProtocol)  {}
1138 
1139     void slotResult(const DecryptionResult &, const QByteArray &);
1140 
registerJob(QGpgME::DecryptJob * job)1141     void registerJob(QGpgME::DecryptJob *job)
1142     {
1143         q->connect(job, SIGNAL(result(GpgME::DecryptionResult,QByteArray)),
1144                    q, SLOT(slotResult(GpgME::DecryptionResult,QByteArray)));
1145         q->connect(job, SIGNAL(progress(QString,int,int)),
1146                    q, SLOT(setProgress(QString,int,int)));
1147     }
1148 
1149     void emitResult(const std::shared_ptr<DecryptVerifyResult> &result);
1150 
1151     std::shared_ptr<Input> m_input;
1152     std::shared_ptr<Output> m_output;
1153     const QGpgME::Protocol *m_backend;
1154     Protocol m_protocol;
1155 };
1156 
emitResult(const std::shared_ptr<DecryptVerifyResult> & result)1157 void DecryptTask::Private::emitResult(const std::shared_ptr<DecryptVerifyResult> &result)
1158 {
1159     q->emitResult(result);
1160     Q_EMIT q->decryptVerifyResult(result);
1161 }
1162 
slotResult(const DecryptionResult & result,const QByteArray & plainText)1163 void DecryptTask::Private::slotResult(const DecryptionResult &result, const QByteArray &plainText)
1164 {
1165     {
1166         std::stringstream ss;
1167         ss << result;
1168         qCDebug(KLEOPATRA_LOG) << ss.str().c_str();
1169     }
1170     const AuditLog auditLog = auditLogFromSender(q->sender());
1171     if (result.error().code()) {
1172         m_output->cancel();
1173     } else {
1174         try {
1175             kleo_assert(!result.isNull());
1176             m_output->finalize();
1177         } catch (const GpgME::Exception &e) {
1178             emitResult(q->fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
1179             return;
1180         } catch (const std::exception &e) {
1181             emitResult(q->fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog));
1182             return;
1183         } catch (...) {
1184             emitResult(q->fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog));
1185             return;
1186         }
1187     }
1188 
1189     const int drErr = result.error().code();
1190     const QString errorString = m_output->errorString();
1191     if (((drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty()) ||
1192           m_output->failed()) {
1193         emitResult(q->fromDecryptResult(result.error() ? result.error() : Error::fromCode(GPG_ERR_EIO),
1194                     errorString, auditLog));
1195         return;
1196     }
1197 
1198     emitResult(q->fromDecryptResult(result, plainText, auditLog));
1199 }
1200 
DecryptTask(QObject * parent)1201 DecryptTask::DecryptTask(QObject *parent) : AbstractDecryptVerifyTask(parent), d(new Private(this))
1202 {
1203 }
1204 
~DecryptTask()1205 DecryptTask::~DecryptTask()
1206 {
1207 }
1208 
setInput(const std::shared_ptr<Input> & input)1209 void DecryptTask::setInput(const std::shared_ptr<Input> &input)
1210 {
1211     d->m_input = input;
1212     kleo_assert(d->m_input && d->m_input->ioDevice());
1213 }
1214 
setOutput(const std::shared_ptr<Output> & output)1215 void DecryptTask::setOutput(const std::shared_ptr<Output> &output)
1216 {
1217     d->m_output = output;
1218     kleo_assert(d->m_output && d->m_output->ioDevice());
1219 }
1220 
setProtocol(Protocol prot)1221 void DecryptTask::setProtocol(Protocol prot)
1222 {
1223     kleo_assert(prot != UnknownProtocol);
1224     d->m_protocol = prot;
1225     d->m_backend = (prot == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime();
1226     kleo_assert(d->m_backend);
1227 }
1228 
autodetectProtocolFromInput()1229 void DecryptTask::autodetectProtocolFromInput()
1230 {
1231     if (!d->m_input) {
1232         return;
1233     }
1234     const Protocol p = findProtocol(d->m_input->classification());
1235     if (p == UnknownProtocol) {
1236         throw Exception(gpg_error(GPG_ERR_NOTHING_FOUND), i18n("Could not determine whether this was S/MIME- or OpenPGP-encrypted - maybe it is not ciphertext at all?"), Exception::MessageOnly);
1237     }
1238     setProtocol(p);
1239 }
1240 
label() const1241 QString DecryptTask::label() const
1242 {
1243     return i18n("Decrypting: %1...", d->m_input->label());
1244 }
1245 
inputSize() const1246 unsigned long long DecryptTask::inputSize() const
1247 {
1248     return d->m_input ? d->m_input->size() : 0;
1249 }
1250 
inputLabel() const1251 QString DecryptTask::inputLabel() const
1252 {
1253     return d->m_input ? d->m_input->label() : QString();
1254 }
1255 
outputLabel() const1256 QString DecryptTask::outputLabel() const
1257 {
1258     return d->m_output ? d->m_output->label() : QString();
1259 }
1260 
protocol() const1261 Protocol DecryptTask::protocol() const
1262 {
1263     return d->m_protocol;
1264 }
1265 
cancel()1266 void DecryptTask::cancel()
1267 {
1268 
1269 }
1270 
doStart()1271 void DecryptTask::doStart()
1272 {
1273     kleo_assert(d->m_backend);
1274 
1275     try {
1276         QGpgME::DecryptJob *const job = d->m_backend->decryptJob();
1277         kleo_assert(job);
1278         d->registerJob(job);
1279         ensureIOOpen(d->m_input->ioDevice().get(), d->m_output->ioDevice().get());
1280         job->start(d->m_input->ioDevice(), d->m_output->ioDevice());
1281     } catch (const GpgME::Exception &e) {
1282         d->emitResult(fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLog()));
1283     } catch (const std::exception &e) {
1284         d->emitResult(fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog()));
1285     } catch (...) {
1286         d->emitResult(fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLog()));
1287     }
1288 }
1289 
1290 class VerifyOpaqueTask::Private
1291 {
1292     VerifyOpaqueTask *const q;
1293 public:
Private(VerifyOpaqueTask * qq)1294     explicit Private(VerifyOpaqueTask *qq) : q(qq), m_backend(nullptr), m_protocol(UnknownProtocol)  {}
1295 
1296     void slotResult(const VerificationResult &, const QByteArray &);
1297 
registerJob(QGpgME::VerifyOpaqueJob * job)1298     void registerJob(QGpgME::VerifyOpaqueJob *job)
1299     {
1300         q->connect(job, SIGNAL(result(GpgME::VerificationResult,QByteArray)),
1301                    q, SLOT(slotResult(GpgME::VerificationResult,QByteArray)));
1302         q->connect(job, SIGNAL(progress(QString,int,int)),
1303                    q, SLOT(setProgress(QString,int,int)));
1304     }
1305 
1306     void emitResult(const std::shared_ptr<DecryptVerifyResult> &result);
1307 
1308     std::shared_ptr<Input> m_input;
1309     std::shared_ptr<Output> m_output;
1310     const QGpgME::Protocol *m_backend;
1311     Protocol m_protocol;
1312 };
1313 
emitResult(const std::shared_ptr<DecryptVerifyResult> & result)1314 void VerifyOpaqueTask::Private::emitResult(const std::shared_ptr<DecryptVerifyResult> &result)
1315 {
1316     q->emitResult(result);
1317     Q_EMIT q->decryptVerifyResult(result);
1318 }
1319 
slotResult(const VerificationResult & result,const QByteArray & plainText)1320 void VerifyOpaqueTask::Private::slotResult(const VerificationResult &result, const QByteArray &plainText)
1321 {
1322     updateKeys(result);
1323     {
1324         std::stringstream ss;
1325         ss << result;
1326         qCDebug(KLEOPATRA_LOG) << ss.str().c_str();
1327     }
1328     const AuditLog auditLog = auditLogFromSender(q->sender());
1329     if (result.error().code()) {
1330         m_output->cancel();
1331     } else {
1332         try {
1333             kleo_assert(!result.isNull());
1334             m_output->finalize();
1335         } catch (const GpgME::Exception &e) {
1336             emitResult(q->fromDecryptResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
1337             return;
1338         } catch (const std::exception &e) {
1339             emitResult(q->fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog));
1340             return;
1341         } catch (...) {
1342             emitResult(q->fromDecryptResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog));
1343             return;
1344         }
1345     }
1346 
1347     const int drErr = result.error().code();
1348     const QString errorString = m_output->errorString();
1349     if (((drErr == GPG_ERR_EIO || drErr == GPG_ERR_NO_DATA) && !errorString.isEmpty()) ||
1350           m_output->failed()) {
1351         emitResult(q->fromDecryptResult(result.error() ? result.error() : Error::fromCode(GPG_ERR_EIO),
1352                     errorString, auditLog));
1353         return;
1354     }
1355 
1356     emitResult(q->fromVerifyOpaqueResult(result, plainText, auditLog));
1357 }
1358 
VerifyOpaqueTask(QObject * parent)1359 VerifyOpaqueTask::VerifyOpaqueTask(QObject *parent) : AbstractDecryptVerifyTask(parent), d(new Private(this))
1360 {
1361 }
1362 
~VerifyOpaqueTask()1363 VerifyOpaqueTask::~VerifyOpaqueTask()
1364 {
1365 }
1366 
setInput(const std::shared_ptr<Input> & input)1367 void VerifyOpaqueTask::setInput(const std::shared_ptr<Input> &input)
1368 {
1369     d->m_input = input;
1370     kleo_assert(d->m_input && d->m_input->ioDevice());
1371 }
1372 
setOutput(const std::shared_ptr<Output> & output)1373 void VerifyOpaqueTask::setOutput(const std::shared_ptr<Output> &output)
1374 {
1375     d->m_output = output;
1376     kleo_assert(d->m_output && d->m_output->ioDevice());
1377 }
1378 
setProtocol(Protocol prot)1379 void VerifyOpaqueTask::setProtocol(Protocol prot)
1380 {
1381     kleo_assert(prot != UnknownProtocol);
1382     d->m_protocol = prot;
1383     d->m_backend = (prot == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime();
1384     kleo_assert(d->m_backend);
1385 }
1386 
autodetectProtocolFromInput()1387 void VerifyOpaqueTask::autodetectProtocolFromInput()
1388 {
1389     if (!d->m_input) {
1390         return;
1391     }
1392     const Protocol p = findProtocol(d->m_input->classification());
1393     if (p == UnknownProtocol) {
1394         throw Exception(gpg_error(GPG_ERR_NOTHING_FOUND), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature - maybe it is not a signature at all?"), Exception::MessageOnly);
1395     }
1396     setProtocol(p);
1397 }
1398 
label() const1399 QString VerifyOpaqueTask::label() const
1400 {
1401     return i18n("Verifying: %1...", d->m_input->label());
1402 }
1403 
inputSize() const1404 unsigned long long VerifyOpaqueTask::inputSize() const
1405 {
1406     return d->m_input ? d->m_input->size() : 0;
1407 }
1408 
inputLabel() const1409 QString VerifyOpaqueTask::inputLabel() const
1410 {
1411     return d->m_input ? d->m_input->label() : QString();
1412 }
1413 
outputLabel() const1414 QString VerifyOpaqueTask::outputLabel() const
1415 {
1416     return d->m_output ? d->m_output->label() : QString();
1417 }
1418 
protocol() const1419 Protocol VerifyOpaqueTask::protocol() const
1420 {
1421     return d->m_protocol;
1422 }
1423 
cancel()1424 void VerifyOpaqueTask::cancel()
1425 {
1426 
1427 }
1428 
doStart()1429 void VerifyOpaqueTask::doStart()
1430 {
1431     kleo_assert(d->m_backend);
1432 
1433     try {
1434         QGpgME::VerifyOpaqueJob *const job = d->m_backend->verifyOpaqueJob();
1435         kleo_assert(job);
1436         d->registerJob(job);
1437         ensureIOOpen(d->m_input->ioDevice().get(), d->m_output ? d->m_output->ioDevice().get() : nullptr);
1438         job->start(d->m_input->ioDevice(), d->m_output ? d->m_output->ioDevice() : std::shared_ptr<QIODevice>());
1439     } catch (const GpgME::Exception &e) {
1440         d->emitResult(fromVerifyOpaqueResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLog()));
1441     } catch (const std::exception &e) {
1442         d->emitResult(fromVerifyOpaqueResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog()));
1443     } catch (...) {
1444         d->emitResult(fromVerifyOpaqueResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLog()));
1445     }
1446 }
1447 
1448 class VerifyDetachedTask::Private
1449 {
1450     VerifyDetachedTask *const q;
1451 public:
Private(VerifyDetachedTask * qq)1452     explicit Private(VerifyDetachedTask *qq) : q(qq), m_backend(nullptr), m_protocol(UnknownProtocol) {}
1453 
1454     void slotResult(const VerificationResult &);
1455 
registerJob(QGpgME::VerifyDetachedJob * job)1456     void registerJob(QGpgME::VerifyDetachedJob *job)
1457     {
1458         q->connect(job, SIGNAL(result(GpgME::VerificationResult)),
1459                    q, SLOT(slotResult(GpgME::VerificationResult)));
1460         q->connect(job, SIGNAL(progress(QString,int,int)),
1461                    q, SLOT(setProgress(QString,int,int)));
1462     }
1463 
1464     void emitResult(const std::shared_ptr<DecryptVerifyResult> &result);
1465 
1466     std::shared_ptr<Input> m_input, m_signedData;
1467     const QGpgME::Protocol *m_backend;
1468     Protocol m_protocol;
1469 };
1470 
emitResult(const std::shared_ptr<DecryptVerifyResult> & result)1471 void VerifyDetachedTask::Private::emitResult(const std::shared_ptr<DecryptVerifyResult> &result)
1472 {
1473     q->emitResult(result);
1474     Q_EMIT q->decryptVerifyResult(result);
1475 }
1476 
slotResult(const VerificationResult & result)1477 void VerifyDetachedTask::Private::slotResult(const VerificationResult &result)
1478 {
1479     updateKeys(result);
1480     {
1481         std::stringstream ss;
1482         ss << result;
1483         qCDebug(KLEOPATRA_LOG) << ss.str().c_str();
1484     }
1485     const AuditLog auditLog = auditLogFromSender(q->sender());
1486     try {
1487         kleo_assert(!result.isNull());
1488         emitResult(q->fromVerifyDetachedResult(result, auditLog));
1489     } catch (const GpgME::Exception &e) {
1490         emitResult(q->fromVerifyDetachedResult(e.error(), QString::fromLocal8Bit(e.what()), auditLog));
1491     } catch (const std::exception &e) {
1492         emitResult(q->fromVerifyDetachedResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), auditLog));
1493     } catch (...) {
1494         emitResult(q->fromVerifyDetachedResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), auditLog));
1495     }
1496 }
1497 
VerifyDetachedTask(QObject * parent)1498 VerifyDetachedTask::VerifyDetachedTask(QObject *parent) : AbstractDecryptVerifyTask(parent), d(new Private(this))
1499 {
1500 }
1501 
~VerifyDetachedTask()1502 VerifyDetachedTask::~VerifyDetachedTask()
1503 {
1504 }
1505 
setInput(const std::shared_ptr<Input> & input)1506 void VerifyDetachedTask::setInput(const std::shared_ptr<Input> &input)
1507 {
1508     d->m_input = input;
1509     kleo_assert(d->m_input && d->m_input->ioDevice());
1510 }
1511 
setSignedData(const std::shared_ptr<Input> & signedData)1512 void VerifyDetachedTask::setSignedData(const std::shared_ptr<Input> &signedData)
1513 {
1514     d->m_signedData = signedData;
1515     kleo_assert(d->m_signedData && d->m_signedData->ioDevice());
1516 }
1517 
setProtocol(Protocol prot)1518 void VerifyDetachedTask::setProtocol(Protocol prot)
1519 {
1520     kleo_assert(prot != UnknownProtocol);
1521     d->m_protocol = prot;
1522     d->m_backend = (prot == GpgME::OpenPGP) ? QGpgME::openpgp() : QGpgME::smime();
1523     kleo_assert(d->m_backend);
1524 }
1525 
autodetectProtocolFromInput()1526 void VerifyDetachedTask::autodetectProtocolFromInput()
1527 {
1528     if (!d->m_input) {
1529         return;
1530     }
1531     const Protocol p = findProtocol(d->m_input->classification());
1532     if (p == UnknownProtocol) {
1533         throw Exception(gpg_error(GPG_ERR_NOTHING_FOUND), i18n("Could not determine whether this is an S/MIME or an OpenPGP signature - maybe it is not a signature at all?"), Exception::MessageOnly);
1534     }
1535     setProtocol(p);
1536 }
1537 
inputSize() const1538 unsigned long long VerifyDetachedTask::inputSize() const
1539 {
1540     return d->m_signedData ? d->m_signedData->size() : 0;
1541 }
1542 
label() const1543 QString VerifyDetachedTask::label() const
1544 {
1545     if (d->m_signedData) {
1546         return xi18nc("Verification of a detached signature in progress. The first file contains the data."
1547                       "The second file is the signature file.",
1548                       "Verifying: <filename>%1</filename> with <filename>%2</filename>...",
1549                       d->m_signedData->label(),
1550                       d->m_input->label());
1551 
1552     }
1553     return i18n("Verifying signature: %1...", d->m_input->label());
1554 }
1555 
inputLabel() const1556 QString VerifyDetachedTask::inputLabel() const
1557 {
1558     if (d->m_signedData && d->m_input) {
1559         return xi18nc("Verification of a detached signature summary. The first file contains the data."
1560                       "The second file is signature.",
1561                       "Verified <filename>%1</filename> with <filename>%2</filename>",
1562                       d->m_signedData->label(),
1563                       d->m_input->label());
1564 
1565     }
1566     return d->m_input ? d->m_input->label() : QString();
1567 }
1568 
outputLabel() const1569 QString VerifyDetachedTask::outputLabel() const
1570 {
1571     return QString();
1572 }
1573 
protocol() const1574 Protocol VerifyDetachedTask::protocol() const
1575 {
1576     return d->m_protocol;
1577 }
1578 
cancel()1579 void VerifyDetachedTask::cancel()
1580 {
1581 
1582 }
1583 
doStart()1584 void VerifyDetachedTask::doStart()
1585 {
1586     kleo_assert(d->m_backend);
1587     try {
1588         QGpgME::VerifyDetachedJob *const job = d->m_backend->verifyDetachedJob();
1589         kleo_assert(job);
1590         d->registerJob(job);
1591         ensureIOOpen(d->m_input->ioDevice().get(), nullptr);
1592         ensureIOOpen(d->m_signedData->ioDevice().get(), nullptr);
1593         job->start(d->m_input->ioDevice(), d->m_signedData->ioDevice());
1594     } catch (const GpgME::Exception &e) {
1595         d->emitResult(fromVerifyDetachedResult(e.error(), QString::fromLocal8Bit(e.what()), AuditLog()));
1596     } catch (const std::exception &e) {
1597         d->emitResult(fromVerifyDetachedResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught exception: %1", QString::fromLocal8Bit(e.what())), AuditLog()));
1598     } catch (...) {
1599         d->emitResult(fromVerifyDetachedResult(Error::fromCode(GPG_ERR_INTERNAL), i18n("Caught unknown exception"), AuditLog()));
1600     }
1601 }
1602 
1603 #include "moc_decryptverifytask.cpp"
1604