summaryrefslogtreecommitdiffstats
path: root/framework/src/domain/mime/mimetreeparser/messagepart.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/domain/mime/mimetreeparser/messagepart.cpp')
-rw-r--r--framework/src/domain/mime/mimetreeparser/messagepart.cpp207
1 files changed, 92 insertions, 115 deletions
diff --git a/framework/src/domain/mime/mimetreeparser/messagepart.cpp b/framework/src/domain/mime/mimetreeparser/messagepart.cpp
index fb61e015..3ba19567 100644
--- a/framework/src/domain/mime/mimetreeparser/messagepart.cpp
+++ b/framework/src/domain/mime/mimetreeparser/messagepart.cpp
@@ -1,5 +1,6 @@
1/* 1/*
2 Copyright (c) 2015 Sandro Knauß <sknauss@kde.org> 2 Copyright (c) 2015 Sandro Knauß <sknauss@kde.org>
3 Copyright (c) 2017 Christian Mollekopf <mollekopf@kolabsys.com>
3 4
4 This library is free software; you can redistribute it and/or modify it 5 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by 6 under the terms of the GNU Library General Public License as published by
@@ -21,24 +22,17 @@
21#include "mimetreeparser_debug.h" 22#include "mimetreeparser_debug.h"
22#include "cryptohelper.h" 23#include "cryptohelper.h"
23#include "objecttreeparser.h" 24#include "objecttreeparser.h"
24#include "qgpgmejobexecutor.h"
25
26#include "cryptobodypartmemento.h"
27#include "decryptverifybodypartmemento.h"
28#include "verifydetachedbodypartmemento.h"
29#include "verifyopaquebodypartmemento.h"
30 25
31#include "utils.h" 26#include "utils.h"
32 27
33#include <KMime/Content> 28#include <KMime/Content>
34 29
35#include <QGpgME/DN> 30#include <QGpgME/DN>
36#include <QGpgME/Protocol> 31#include <QGpgME/DataProvider>
37#include <QGpgME/ImportJob>
38#include <QGpgME/KeyListJob>
39#include <QGpgME/VerifyDetachedJob>
40#include <QGpgME/VerifyOpaqueJob>
41 32
33#include <gpgme++/context.h>
34#include <gpgme++/data.h>
35#include <gpgme++/verificationresult.h>
42#include <gpgme++/key.h> 36#include <gpgme++/key.h>
43#include <gpgme++/keylistresult.h> 37#include <gpgme++/keylistresult.h>
44#include <gpgme.h> 38#include <gpgme.h>
@@ -48,6 +42,24 @@
48 42
49using namespace MimeTreeParser; 43using namespace MimeTreeParser;
50 44
45static GpgME::Data fromBA(const QByteArray &ba)
46{
47 return {ba.data(), static_cast<size_t>(ba.size()), false};
48}
49
50static QSharedPointer<GpgME::Context> gpgContext(GpgME::Protocol protocol)
51{
52 GpgME::initializeLibrary();
53 auto error = GpgME::checkEngine(protocol);
54 if (error) {
55 qWarning() << "Engine check failed: " << error.asString();
56 }
57 auto ctx = QSharedPointer<GpgME::Context>(GpgME::Context::createForProtocol(protocol));
58 Q_ASSERT(ctx);
59 return ctx;
60}
61
62
51//------MessagePart----------------------- 63//------MessagePart-----------------------
52MessagePart::MessagePart(ObjectTreeParser *otp, const QString &text, KMime::Content *node) 64MessagePart::MessagePart(ObjectTreeParser *otp, const QString &text, KMime::Content *node)
53 : mText(text) 65 : mText(text)
@@ -382,7 +394,7 @@ void TextMessagePart::parseContent()
382 mEncryptionState = KMMsgNotEncrypted; 394 mEncryptionState = KMMsgNotEncrypted;
383 const auto blocks = prepareMessageForDecryption(mNode->decodedContent()); 395 const auto blocks = prepareMessageForDecryption(mNode->decodedContent());
384 396
385 const auto cryptProto = QGpgME::openpgp(); 397 const auto cryptProto = GpgME::OpenPGP;
386 398
387 if (!blocks.isEmpty()) { 399 if (!blocks.isEmpty()) {
388 400
@@ -639,7 +651,7 @@ QString AlternativeMessagePart::htmlContent() const
639 651
640//-----CertMessageBlock---------------------- 652//-----CertMessageBlock----------------------
641 653
642CertMessagePart::CertMessagePart(ObjectTreeParser *otp, KMime::Content *node, const QGpgME::Protocol *cryptoProto) 654CertMessagePart::CertMessagePart(ObjectTreeParser *otp, KMime::Content *node, const GpgME::Protocol cryptoProto)
643 : MessagePart(otp, QString(), node) 655 : MessagePart(otp, QString(), node)
644 , mCryptoProto(cryptoProto) 656 , mCryptoProto(cryptoProto)
645{ 657{
@@ -657,9 +669,8 @@ CertMessagePart::~CertMessagePart()
657void CertMessagePart::import() 669void CertMessagePart::import()
658{ 670{
659 const QByteArray certData = mNode->decodedContent(); 671 const QByteArray certData = mNode->decodedContent();
660 QGpgME::ImportJob *import = mCryptoProto->importJob(); 672 auto ctx = gpgContext(mCryptoProto);
661 QGpgMEJobExecutor executor; 673 const auto result = ctx->importKeys(fromBA(certData));
662 auto result = executor.exec(import, certData);
663} 674}
664 675
665QString CertMessagePart::text() const 676QString CertMessagePart::text() const
@@ -670,11 +681,11 @@ QString CertMessagePart::text() const
670//-----SignedMessageBlock--------------------- 681//-----SignedMessageBlock---------------------
671SignedMessagePart::SignedMessagePart(ObjectTreeParser *otp, 682SignedMessagePart::SignedMessagePart(ObjectTreeParser *otp,
672 const QString &text, 683 const QString &text,
673 const QGpgME::Protocol *cryptoProto, 684 const GpgME::Protocol cryptoProto,
674 const QString &fromAddress, 685 const QString &fromAddress,
675 KMime::Content *node, KMime::Content *signedData) 686 KMime::Content *node, KMime::Content *signedData)
676 : MessagePart(otp, text, node) 687 : MessagePart(otp, text, node)
677 , mCryptoProto(cryptoProto) 688 , mProtocol(cryptoProto)
678 , mFromAddress(fromAddress) 689 , mFromAddress(fromAddress)
679 , mSignedData(signedData) 690 , mSignedData(signedData)
680{ 691{
@@ -700,20 +711,6 @@ bool SignedMessagePart::isSigned() const
700 return mMetaData.isSigned; 711 return mMetaData.isSigned;
701} 712}
702 713
703CryptoBodyPartMemento *SignedMessagePart::verifySignature(const QByteArray &data, const QByteArray &signature)
704{
705 if (!signature.isEmpty()) {
706 if (QGpgME::VerifyDetachedJob *job = mCryptoProto->verifyDetachedJob()) {
707 return new VerifyDetachedBodyPartMemento(job, mCryptoProto->keyListJob(), signature, data);
708 }
709 } else {
710 if (QGpgME::VerifyOpaqueJob *job = mCryptoProto->verifyOpaqueJob()) {
711 return new VerifyOpaqueBodyPartMemento(job, mCryptoProto->keyListJob(), data);
712 }
713 }
714 return nullptr;
715}
716
717static int signatureToStatus(const GpgME::Signature &sig) 714static int signatureToStatus(const GpgME::Signature &sig)
718{ 715{
719 switch (sig.status().code()) { 716 switch (sig.status().code()) {
@@ -739,6 +736,23 @@ QString prettifyDN(const char *uid)
739 return QGpgME::DN(uid).prettyDN(); 736 return QGpgME::DN(uid).prettyDN();
740} 737}
741 738
739static GpgME::KeyListResult listKeys(GpgME::Context * ctx, const char *pattern, bool secretOnly, std::vector<GpgME::Key> &keys) {
740 if (const GpgME::Error err = ctx->startKeyListing(pattern, secretOnly)) {
741 return GpgME::KeyListResult( 0, err );
742 }
743
744 GpgME::Error err;
745 do {
746 keys.push_back( ctx->nextKey(err));
747 } while ( !err );
748
749 keys.pop_back();
750
751 const GpgME::KeyListResult result = ctx->endKeyListing();
752 ctx->cancelPendingOperation();
753 return result;
754}
755
742void SignedMessagePart::sigStatusToMetaData() 756void SignedMessagePart::sigStatusToMetaData()
743{ 757{
744 GpgME::Key key; 758 GpgME::Key key;
@@ -749,29 +763,22 @@ void SignedMessagePart::sigStatusToMetaData()
749 mMetaData.sigSummary = signature.summary(); 763 mMetaData.sigSummary = signature.summary();
750 764
751 if (mMetaData.isGoodSignature && !key.keyID()) { 765 if (mMetaData.isGoodSignature && !key.keyID()) {
752 // Search for the key by its fingerprint so that we can check for 766 auto ctx = gpgContext(mProtocol);
753 // trust etc. 767 // Search for the key by its fingerprint so that we can check for trust etc.
754 QGpgME::KeyListJob *job = mCryptoProto->keyListJob(false); // local, no sigs 768 std::vector<GpgME::Key> found_keys;
755 if (!job) { 769 auto res = listKeys(ctx.data(), signature.fingerprint(), false, found_keys);
756 qCDebug(MIMETREEPARSER_LOG) << "The Crypto backend does not support listing keys. "; 770 if (res.error()) {
771 qCDebug(MIMETREEPARSER_LOG) << "Error while searching key for Fingerprint: " << signature.fingerprint();
772 }
773 if (found_keys.size() > 1) {
774 // Should not happen
775 qCDebug(MIMETREEPARSER_LOG) << "Oops: Found more then one Key for Fingerprint: " << signature.fingerprint();
776 }
777 if (found_keys.empty()) {
778 // Should not happen at this point
779 qCWarning(MIMETREEPARSER_LOG) << "Oops: Found no Key for Fingerprint: " << signature.fingerprint();
757 } else { 780 } else {
758 std::vector<GpgME::Key> found_keys; 781 key = found_keys[0];
759 // As we are local it is ok to make this synchronous
760 GpgME::KeyListResult res = job->exec(QStringList(QLatin1String(signature.fingerprint())), false, found_keys);
761 if (res.error()) {
762 qCDebug(MIMETREEPARSER_LOG) << "Error while searching key for Fingerprint: " << signature.fingerprint();
763 }
764 if (found_keys.size() > 1) {
765 // Should not happen
766 qCDebug(MIMETREEPARSER_LOG) << "Oops: Found more then one Key for Fingerprint: " << signature.fingerprint();
767 }
768 if (found_keys.empty()) {
769 // Should not happen at this point
770 qCWarning(MIMETREEPARSER_LOG) << "Oops: Found no Key for Fingerprint: " << signature.fingerprint();
771 } else {
772 key = found_keys[0];
773 }
774 delete job;
775 } 782 }
776 } 783 }
777 784
@@ -857,25 +864,18 @@ void SignedMessagePart::startVerificationDetached(const QByteArray &text, KMime:
857 mMetaData.status = tr("Wrong Crypto Plug-In."); 864 mMetaData.status = tr("Wrong Crypto Plug-In.");
858 mMetaData.status_code = GPGME_SIG_STAT_NONE; 865 mMetaData.status_code = GPGME_SIG_STAT_NONE;
859 866
860 if (auto *m = verifySignature(text, signature)) { 867 auto ctx = gpgContext(mProtocol);
861 m->exec(); 868
862 if (!signature.isEmpty()) { 869 if (!signature.isEmpty()) {
863 mVerifiedText = text; 870 qWarning() << "We have a signature";
864 } 871 auto result = ctx->verifyDetachedSignature(fromBA(signature), fromBA(text));
865 setVerificationResult(m, textNode); 872 setVerificationResult(result, textNode, text);
866 delete m;
867 } else { 873 } else {
868 QString errorMsg; 874 qWarning() << "We have no signature";
869 if (!mCryptoProto) { 875 QGpgME::QByteArrayDataProvider out;
870 errorMsg = tr("No appropriate crypto plug-in was found."); 876 GpgME::Data outdata(&out);
871 } else { 877 auto result = ctx->verifyOpaqueSignature(fromBA(text), outdata);
872 errorMsg = tr("Crypto plug-in \"%1\" cannot verify signatures.").arg( 878 setVerificationResult(result, textNode, out.data());
873 mCryptoProto->name());
874 }
875 mMetaData.errorText = tr("The message is signed, but the "
876 "validity of the signature cannot be "
877 "verified.<br />"
878 "Reason: %1").arg(errorMsg);
879 } 879 }
880 880
881 if (!mMetaData.isSigned) { 881 if (!mMetaData.isSigned) {
@@ -883,24 +883,13 @@ void SignedMessagePart::startVerificationDetached(const QByteArray &text, KMime:
883 } 883 }
884} 884}
885 885
886void SignedMessagePart::setVerificationResult(const CryptoBodyPartMemento *m, KMime::Content *textNode) 886void SignedMessagePart::setVerificationResult(const GpgME::VerificationResult &result, KMime::Content *textNode, const QByteArray &plainText)
887{ 887{
888 if (const auto vm = dynamic_cast<const VerifyDetachedBodyPartMemento *>(m)) { 888 mSignatures = result.signatures();
889 mSignatures = vm->verifyResult().signatures(); 889 mVerifiedText = plainText;
890 } 890 mMetaData.auditLogError = result.error();
891 if (const auto vm = dynamic_cast<const VerifyOpaqueBodyPartMemento *>(m)) { 891 if (!mSignatures.empty()) {
892 mVerifiedText = vm->plainText(); 892 mMetaData.isSigned = true;
893 mSignatures = vm->verifyResult().signatures();
894 }
895 if (const auto vm = dynamic_cast<const DecryptVerifyBodyPartMemento *>(m)) {
896 mVerifiedText = vm->plainText();
897 mSignatures = vm->verifyResult().signatures();
898 }
899 mMetaData.auditLogError = m->auditLogError();
900 mMetaData.auditLog = m->auditLogAsHtml();
901 mMetaData.isSigned = !mSignatures.empty();
902
903 if (mMetaData.isSigned) {
904 sigStatusToMetaData(); 893 sigStatusToMetaData();
905 if (mNode && !textNode) { 894 if (mNode && !textNode) {
906 mOtp->mNodeHelper->setPartMetaData(mNode, mMetaData); 895 mOtp->mNodeHelper->setPartMetaData(mNode, mMetaData);
@@ -941,11 +930,11 @@ QString SignedMessagePart::htmlContent() const
941//-----CryptMessageBlock--------------------- 930//-----CryptMessageBlock---------------------
942EncryptedMessagePart::EncryptedMessagePart(ObjectTreeParser *otp, 931EncryptedMessagePart::EncryptedMessagePart(ObjectTreeParser *otp,
943 const QString &text, 932 const QString &text,
944 const QGpgME::Protocol *cryptoProto, 933 const GpgME::Protocol cryptoProto,
945 const QString &fromAddress, 934 const QString &fromAddress,
946 KMime::Content *node, KMime::Content *encryptedNode) 935 KMime::Content *node, KMime::Content *encryptedNode)
947 : MessagePart(otp, text, node) 936 : MessagePart(otp, text, node)
948 , mCryptoProto(cryptoProto) 937 , mProtocol(cryptoProto)
949 , mFromAddress(fromAddress) 938 , mFromAddress(fromAddress)
950 , mEncryptedNode(encryptedNode) 939 , mEncryptedNode(encryptedNode)
951{ 940{
@@ -1012,32 +1001,21 @@ bool EncryptedMessagePart::okDecryptMIME(KMime::Content &data)
1012 mMetaData.auditLogError = GpgME::Error(); 1001 mMetaData.auditLogError = GpgME::Error();
1013 mMetaData.auditLog.clear(); 1002 mMetaData.auditLog.clear();
1014 1003
1015 if (!mCryptoProto) {
1016 mError = UnknownError;
1017 mMetaData.errorText = tr("No appropriate crypto plug-in was found.");
1018 return false;
1019 }
1020
1021 QGpgME::DecryptVerifyJob *job = mCryptoProto->decryptVerifyJob();
1022 if (!job) {
1023 mError = UnknownError;
1024 mMetaData.errorText = tr("Crypto plug-in \"%1\" cannot decrypt messages.").arg(mCryptoProto->name());
1025 return false;
1026 }
1027
1028 const QByteArray ciphertext = data.decodedContent(); 1004 const QByteArray ciphertext = data.decodedContent();
1029 auto m = QSharedPointer<DecryptVerifyBodyPartMemento>::create(job, ciphertext); 1005 qWarning() << "Protocol: " << mProtocol;
1030 m->exec(); 1006 auto ctx = gpgContext(mProtocol);
1031 1007 QGpgME::QByteArrayDataProvider out;
1032 const QByteArray &plainText = m->plainText(); 1008 GpgME::Data outdata(&out);
1033 const GpgME::DecryptionResult &decryptResult = m->decryptResult(); 1009 const std::pair<GpgME::DecryptionResult,GpgME::VerificationResult> res = ctx->decryptAndVerify(fromBA(ciphertext), outdata);
1034 const GpgME::VerificationResult &verifyResult = m->verifyResult(); 1010 const QByteArray &plainText = out.data();
1011 const GpgME::DecryptionResult &decryptResult = res.first;
1012 const GpgME::VerificationResult &verifyResult = res.second;
1035 mMetaData.isSigned = verifyResult.signatures().size() > 0; 1013 mMetaData.isSigned = verifyResult.signatures().size() > 0;
1036 1014
1037 if (verifyResult.signatures().size() > 0) { 1015 if (verifyResult.signatures().size() > 0) {
1038 //We simply attach a signed message part to indicate that this content is also signed 1016 //We simply attach a signed message part to indicate that this content is also signed
1039 auto subPart = SignedMessagePart::Ptr(new SignedMessagePart(mOtp, QString::fromUtf8(plainText), mCryptoProto, mFromAddress, nullptr, nullptr)); 1017 auto subPart = SignedMessagePart::Ptr(new SignedMessagePart(mOtp, QString::fromUtf8(plainText), mProtocol, mFromAddress, nullptr, nullptr));
1040 subPart->setVerificationResult(m.data(), nullptr); 1018 subPart->setVerificationResult(verifyResult, nullptr, plainText);
1041 appendSubPart(subPart); 1019 appendSubPart(subPart);
1042 } 1020 }
1043 1021
@@ -1075,13 +1053,12 @@ bool EncryptedMessagePart::okDecryptMIME(KMime::Content &data)
1075 1053
1076 if(noSecKey) { 1054 if(noSecKey) {
1077 mError = NoKeyError; 1055 mError = NoKeyError;
1078 mMetaData.errorText = tr("Crypto plug-in \"%1\" could not decrypt the data. ").arg(mCryptoProto->name()) 1056 mMetaData.errorText = tr("Could not decrypt the data. ") + tr("No key found for recepients.");
1079 + tr("No key found for recepients.");
1080 } else if (passphraseError) { 1057 } else if (passphraseError) {
1081 mError = PassphraseError; 1058 mError = PassphraseError;
1082 } else { 1059 } else {
1083 mError = UnknownError; 1060 mError = UnknownError;
1084 mMetaData.errorText = tr("Crypto plug-in \"%1\" could not decrypt the data. ").arg(mCryptoProto->name()) 1061 mMetaData.errorText = tr("Could not decrypt the data. ")
1085 + tr("Error: %1").arg(mMetaData.errorText); 1062 + tr("Error: %1").arg(mMetaData.errorText);
1086 } 1063 }
1087 return false; 1064 return false;