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 → %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