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.cpp283
1 files changed, 75 insertions, 208 deletions
diff --git a/framework/src/domain/mime/mimetreeparser/messagepart.cpp b/framework/src/domain/mime/mimetreeparser/messagepart.cpp
index 2fd4f496..4bed80da 100644
--- a/framework/src/domain/mime/mimetreeparser/messagepart.cpp
+++ b/framework/src/domain/mime/mimetreeparser/messagepart.cpp
@@ -27,102 +27,12 @@
27 27
28#include <KMime/Content> 28#include <KMime/Content>
29 29
30#include <QGpgME/DN> 30#include <crypto.h>
31#include <QGpgME/DataProvider>
32
33#include <gpgme++/context.h>
34#include <gpgme++/data.h>
35#include <gpgme++/verificationresult.h>
36#include <gpgme++/key.h>
37#include <gpgme++/keylistresult.h>
38#include <gpgme++/decryptionresult.h>
39#include <gpgme++/importresult.h>
40#include <gpgme.h>
41
42 31
43#include <QTextCodec> 32#include <QTextCodec>
44#include <sstream>
45 33
46using namespace MimeTreeParser; 34using namespace MimeTreeParser;
47 35using namespace Crypto;
48static GpgME::Data fromBA(const QByteArray &ba)
49{
50 return {ba.data(), static_cast<size_t>(ba.size()), false};
51}
52
53
54static GpgME::Protocol toGpgMe(CryptoProtocol p)
55{
56 switch (p) {
57 case UnknownProtocol:
58 return GpgME::UnknownProtocol;
59 case CMS:
60 return GpgME::CMS;
61 case OpenPGP:
62 return GpgME::OpenPGP;
63 }
64 return GpgME::UnknownProtocol;
65}
66
67static QSharedPointer<GpgME::Context> gpgContext(CryptoProtocol protocol)
68{
69 GpgME::initializeLibrary();
70 auto error = GpgME::checkEngine(toGpgMe(protocol));
71 if (error) {
72 qWarning() << "Engine check failed: " << error.asString();
73 }
74 auto ctx = QSharedPointer<GpgME::Context>(GpgME::Context::createForProtocol(toGpgMe(protocol)));
75 Q_ASSERT(ctx);
76 return ctx;
77}
78
79static GpgME::VerificationResult verifyDetachedSignature(CryptoProtocol protocol, const QByteArray &signature, const QByteArray &text)
80{
81 return gpgContext(protocol)->verifyDetachedSignature(fromBA(signature), fromBA(text));
82}
83
84static GpgME::VerificationResult verifyOpaqueSignature(CryptoProtocol protocol, const QByteArray &signature, QByteArray &outdata)
85{
86 QGpgME::QByteArrayDataProvider out;
87 GpgME::Data wrapper(&out);
88 const auto result = gpgContext(protocol)->verifyOpaqueSignature(fromBA(signature), wrapper);
89 outdata = out.data();
90 return result;
91}
92
93
94static std::pair<GpgME::DecryptionResult,GpgME::VerificationResult> decryptAndVerify(CryptoProtocol protocol, const QByteArray &ciphertext, QByteArray &outdata)
95{
96 QGpgME::QByteArrayDataProvider out;
97 GpgME::Data wrapper(&out);
98 const std::pair<GpgME::DecryptionResult,GpgME::VerificationResult> res = gpgContext(protocol)->decryptAndVerify(fromBA(ciphertext), wrapper);
99 outdata = out.data();
100 return res;
101}
102
103static void importKeys(CryptoProtocol protocol, const QByteArray &certData)
104{
105 gpgContext(protocol)->importKeys(fromBA(certData));
106}
107
108static GpgME::KeyListResult listKeys(CryptoProtocol protocol, const char *pattern, bool secretOnly, std::vector<GpgME::Key> &keys) {
109 auto ctx = gpgContext(protocol);
110 if (const GpgME::Error err = ctx->startKeyListing(pattern, secretOnly)) {
111 return GpgME::KeyListResult( 0, err );
112 }
113
114 GpgME::Error err;
115 do {
116 keys.push_back( ctx->nextKey(err));
117 } while ( !err );
118
119 keys.pop_back();
120
121 const GpgME::KeyListResult result = ctx->endKeyListing();
122 ctx->cancelPendingOperation();
123 return result;
124}
125
126 36
127//------MessagePart----------------------- 37//------MessagePart-----------------------
128MessagePart::MessagePart(ObjectTreeParser *otp, const QString &text, KMime::Content *node) 38MessagePart::MessagePart(ObjectTreeParser *otp, const QString &text, KMime::Content *node)
@@ -771,10 +681,7 @@ SignedMessagePart::SignedMessagePart(ObjectTreeParser *otp,
771{ 681{
772 mMetaData.isSigned = true; 682 mMetaData.isSigned = true;
773 mMetaData.isGoodSignature = false; 683 mMetaData.isGoodSignature = false;
774 //FIXME
775 // mMetaData.keyTrust = GpgME::Signature::Unknown;
776 mMetaData.status = tr("Wrong Crypto Plug-In."); 684 mMetaData.status = tr("Wrong Crypto Plug-In.");
777 mMetaData.status_code = GPGME_SIG_STAT_NONE;
778} 685}
779 686
780SignedMessagePart::~SignedMessagePart() 687SignedMessagePart::~SignedMessagePart()
@@ -792,99 +699,65 @@ bool SignedMessagePart::isSigned() const
792 return mMetaData.isSigned; 699 return mMetaData.isSigned;
793} 700}
794 701
795static int signatureToStatus(const GpgME::Signature &sig)
796{
797 switch (sig.status().code()) {
798 case GPG_ERR_NO_ERROR:
799 return GPGME_SIG_STAT_GOOD;
800 case GPG_ERR_BAD_SIGNATURE:
801 return GPGME_SIG_STAT_BAD;
802 case GPG_ERR_NO_PUBKEY:
803 return GPGME_SIG_STAT_NOKEY;
804 case GPG_ERR_NO_DATA:
805 return GPGME_SIG_STAT_NOSIG;
806 case GPG_ERR_SIG_EXPIRED:
807 return GPGME_SIG_STAT_GOOD_EXP;
808 case GPG_ERR_KEY_EXPIRED:
809 return GPGME_SIG_STAT_GOOD_EXPKEY;
810 default:
811 return GPGME_SIG_STAT_ERROR;
812 }
813}
814 702
815QString prettifyDN(const char *uid) 703static QString prettifyDN(const char *uid)
816{ 704{
817 return QGpgME::DN(uid).prettyDN(); 705 // We used to use QGpgME::DN::prettyDN here. But I'm not sure what we actually need it for.
706 return QString::fromUtf8(uid);
818} 707}
819 708
820void SignedMessagePart::sigStatusToMetaData(const GpgME::Signature &signature) 709void SignedMessagePart::sigStatusToMetaData(const Signature &signature)
821{ 710{
822 GpgME::Key key; 711 mMetaData.isGoodSignature = signature.status & GPG_ERR_NO_ERROR;
823 mMetaData.status_code = signatureToStatus(signature);
824 mMetaData.isGoodSignature = mMetaData.status_code & GPGME_SIG_STAT_GOOD;
825 // save extended signature status flags 712 // save extended signature status flags
826 auto summary = signature.summary(); 713 auto summary = signature.summary;
827 mMetaData.keyMissing = summary & GpgME::Signature::KeyMissing; 714 mMetaData.keyMissing = summary & GPGME_SIGSUM_KEY_MISSING;
828 mMetaData.keyExpired = summary & GpgME::Signature::KeyExpired; 715 mMetaData.keyExpired = summary & GPGME_SIGSUM_KEY_EXPIRED;
829 mMetaData.keyRevoked = summary & GpgME::Signature::KeyRevoked; 716 mMetaData.keyRevoked = summary & GPGME_SIGSUM_KEY_REVOKED;
830 mMetaData.sigExpired = summary & GpgME::Signature::SigExpired; 717 mMetaData.sigExpired = summary & GPGME_SIGSUM_SIG_EXPIRED;
831 mMetaData.crlMissing = summary & GpgME::Signature::CrlMissing; 718 mMetaData.crlMissing = summary & GPGME_SIGSUM_CRL_MISSING;
832 mMetaData.crlTooOld = summary & GpgME::Signature::CrlTooOld; 719 mMetaData.crlTooOld = summary & GPGME_SIGSUM_CRL_TOO_OLD;
833 720
834 if (mMetaData.isGoodSignature && !key.keyID()) { 721 Key key;
722 if (mMetaData.isGoodSignature) {
835 // Search for the key by its fingerprint so that we can check for trust etc. 723 // Search for the key by its fingerprint so that we can check for trust etc.
836 std::vector<GpgME::Key> found_keys; 724 const auto keys = findKeys({signature.fingerprint});
837 auto res = listKeys(mProtocol, signature.fingerprint(), false, found_keys); 725 if (keys.size() > 1) {
838 if (res.error()) {
839 qCDebug(MIMETREEPARSER_LOG) << "Error while searching key for Fingerprint: " << signature.fingerprint();
840 }
841 if (found_keys.size() > 1) {
842 // Should not happen 726 // Should not happen
843 qCDebug(MIMETREEPARSER_LOG) << "Oops: Found more then one Key for Fingerprint: " << signature.fingerprint(); 727 qCDebug(MIMETREEPARSER_LOG) << "Oops: Found more then one Key for Fingerprint: " << signature.fingerprint;
844 } 728 }
845 if (found_keys.empty()) { 729 if (keys.empty()) {
846 // Should not happen at this point 730 // Should not happen at this point
847 qCWarning(MIMETREEPARSER_LOG) << "Oops: Found no Key for Fingerprint: " << signature.fingerprint(); 731 qCWarning(MIMETREEPARSER_LOG) << "Oops: Found no Key for Fingerprint: " << signature.fingerprint;
848 } else { 732 } else {
849 key = found_keys[0]; 733 key = keys[0];
850 } 734 }
851 } 735 }
852 736
853 if (key.keyID()) { 737 mMetaData.keyId = key.keyId;
854 mMetaData.keyId = key.keyID();
855 }
856 if (mMetaData.keyId.isEmpty()) { 738 if (mMetaData.keyId.isEmpty()) {
857 mMetaData.keyId = signature.fingerprint(); 739 mMetaData.keyId = signature.fingerprint;
858 } 740 }
859 auto keyTrust = signature.validity(); 741 mMetaData.keyIsTrusted = signature.validity == GPGME_VALIDITY_FULL || signature.validity == GPGME_VALIDITY_ULTIMATE;
860 mMetaData.keyIsTrusted = keyTrust & GpgME::Signature::Full || keyTrust & GpgME::Signature::Ultimate; 742 if (!key.userIds.empty()) {
861 if (key.numUserIDs() > 0 && key.userID(0).id()) { 743 mMetaData.signer = prettifyDN(key.userIds[0].id);
862 mMetaData.signer = prettifyDN(key.userID(0).id()); 744 }
863 } 745 for (const auto &userId : key.userIds) {
864 for (uint iMail = 0; iMail < key.numUserIDs(); ++iMail) { 746 QString email = QString::fromUtf8(userId.email);
865 // The following if /should/ always result in TRUE but we 747 // ### work around gpgme 0.3.QString text() const Q_DECL_OVERRIDE;x / cryptplug bug where the
866 // won't trust implicitely the plugin that gave us these data. 748 // ### email addresses are specified as angle-addr, not addr-spec:
867 if (key.userID(iMail).email()) { 749 if (email.startsWith(QLatin1Char('<')) && email.endsWith(QLatin1Char('>'))) {
868 QString email = QString::fromUtf8(key.userID(iMail).email()); 750 email = email.mid(1, email.length() - 2);
869 // ### work around gpgme 0.3.QString text() const Q_DECL_OVERRIDE;x / cryptplug bug where the 751 }
870 // ### email addresses are specified as angle-addr, not addr-spec: 752 if (!email.isEmpty()) {
871 if (email.startsWith(QLatin1Char('<')) && email.endsWith(QLatin1Char('>'))) { 753 mMetaData.signerMailAddresses.append(email);
872 email = email.mid(1, email.length() - 2);
873 }
874 if (!email.isEmpty()) {
875 mMetaData.signerMailAddresses.append(email);
876 }
877 } 754 }
878 } 755 }
879 756
880 if (signature.creationTime()) { 757 mMetaData.creationTime = signature.creationTime;
881 mMetaData.creationTime.setTime_t(signature.creationTime());
882 } else {
883 mMetaData.creationTime = QDateTime();
884 }
885 if (mMetaData.signer.isEmpty()) { 758 if (mMetaData.signer.isEmpty()) {
886 if (key.numUserIDs() > 0 && key.userID(0).name()) { 759 if (!key.userIds.empty()) {
887 mMetaData.signer = prettifyDN(key.userID(0).name()); 760 mMetaData.signer = prettifyDN(key.userIds[0].name);
888 } 761 }
889 if (!mMetaData.signerMailAddresses.empty()) { 762 if (!mMetaData.signerMailAddresses.empty()) {
890 if (mMetaData.signer.isEmpty()) { 763 if (mMetaData.signer.isEmpty()) {
@@ -924,18 +797,13 @@ void SignedMessagePart::startVerificationDetached(const QByteArray &text, KMime:
924 } 797 }
925 798
926 mMetaData.isSigned = false; 799 mMetaData.isSigned = false;
927 //FIXME
928 // mMetaData.keyTrust = GpgME::Signature::Unknown;
929 mMetaData.status = tr("Wrong Crypto Plug-In."); 800 mMetaData.status = tr("Wrong Crypto Plug-In.");
930 mMetaData.status_code = GPGME_SIG_STAT_NONE;
931 801
932 if (!signature.isEmpty()) { 802 if (!signature.isEmpty()) {
933 auto result = verifyDetachedSignature(mProtocol, signature, text); 803 setVerificationResult(verifyDetachedSignature(mProtocol, signature, text), false, text);
934 setVerificationResult(result, false, text);
935 } else { 804 } else {
936 QByteArray outdata; 805 QByteArray outdata;
937 auto result = verifyOpaqueSignature(mProtocol, text, outdata); 806 setVerificationResult(verifyOpaqueSignature(mProtocol, text, outdata), false, outdata);
938 setVerificationResult(result, false, outdata);
939 } 807 }
940 808
941 if (!mMetaData.isSigned) { 809 if (!mMetaData.isSigned) {
@@ -943,11 +811,11 @@ void SignedMessagePart::startVerificationDetached(const QByteArray &text, KMime:
943 } 811 }
944} 812}
945 813
946void SignedMessagePart::setVerificationResult(const GpgME::VerificationResult &result, bool parseText, const QByteArray &plainText) 814void SignedMessagePart::setVerificationResult(const VerificationResult &result, bool parseText, const QByteArray &plainText)
947{ 815{
948 auto signatures = result.signatures(); 816 auto signatures = result.signatures;
949 // FIXME 817 // FIXME
950 // mMetaData.auditLogError = result.error(); 818 // mMetaData.auditLogError = result.error;
951 if (!signatures.empty()) { 819 if (!signatures.empty()) {
952 mMetaData.isSigned = true; 820 mMetaData.isSigned = true;
953 sigStatusToMetaData(signatures.front()); 821 sigStatusToMetaData(signatures.front());
@@ -994,10 +862,7 @@ EncryptedMessagePart::EncryptedMessagePart(ObjectTreeParser *otp,
994 mMetaData.isGoodSignature = false; 862 mMetaData.isGoodSignature = false;
995 mMetaData.isEncrypted = false; 863 mMetaData.isEncrypted = false;
996 mMetaData.isDecryptable = false; 864 mMetaData.isDecryptable = false;
997 //FIXME
998 // mMetaData.keyTrust = GpgME::Signature::Unknown;
999 mMetaData.status = tr("Wrong Crypto Plug-In."); 865 mMetaData.status = tr("Wrong Crypto Plug-In.");
1000 mMetaData.status_code = GPGME_SIG_STAT_NONE;
1001} 866}
1002 867
1003EncryptedMessagePart::~EncryptedMessagePart() 868EncryptedMessagePart::~EncryptedMessagePart()
@@ -1055,59 +920,61 @@ bool EncryptedMessagePart::okDecryptMIME(KMime::Content &data)
1055 920
1056 const QByteArray ciphertext = data.decodedContent(); 921 const QByteArray ciphertext = data.decodedContent();
1057 QByteArray plainText; 922 QByteArray plainText;
1058 const auto res = decryptAndVerify(mProtocol, ciphertext, plainText); 923 DecryptionResult decryptResult;
1059 const GpgME::DecryptionResult &decryptResult = res.first; 924 VerificationResult verifyResult;
1060 const GpgME::VerificationResult &verifyResult = res.second; 925 std::tie(decryptResult, verifyResult) = decryptAndVerify(mProtocol, ciphertext, plainText);
1061 mMetaData.isSigned = verifyResult.signatures().size() > 0; 926 mMetaData.isSigned = verifyResult.signatures.size() > 0;
1062 927
1063 if (verifyResult.signatures().size() > 0) { 928 if (verifyResult.signatures.size() > 0) {
1064 //We simply attach a signed message part to indicate that this content is also signed 929 //We simply attach a signed message part to indicate that this content is also signed
1065 auto subPart = SignedMessagePart::Ptr(new SignedMessagePart(mOtp, QString::fromUtf8(plainText), mProtocol, mFromAddress, nullptr, nullptr)); 930 auto subPart = SignedMessagePart::Ptr(new SignedMessagePart(mOtp, QString::fromUtf8(plainText), mProtocol, mFromAddress, nullptr, nullptr));
1066 subPart->setVerificationResult(verifyResult, true, plainText); 931 subPart->setVerificationResult(verifyResult, true, plainText);
1067 appendSubPart(subPart); 932 appendSubPart(subPart);
1068 } 933 }
1069 934
1070 if (decryptResult.error() && mMetaData.isSigned) { 935 if (decryptResult.error && mMetaData.isSigned) {
1071 //Only a signed part 936 //Only a signed part
1072 mMetaData.isEncrypted = false; 937 mMetaData.isEncrypted = false;
1073 mDecryptedData = plainText; 938 mDecryptedData = plainText;
1074 return true; 939 return true;
1075 } 940 }
1076 941
1077 if (mMetaData.isEncrypted && decryptResult.numRecipients() > 0) { 942 if (mMetaData.isEncrypted && decryptResult.recipients.size()) {
1078 mMetaData.keyId = decryptResult.recipient(0).keyID(); 943 mMetaData.keyId = decryptResult.recipients.at(0).keyId;
1079 } 944 }
1080 945
1081 if (!decryptResult.error()) { 946 if (!decryptResult.error) {
1082 mDecryptedData = plainText; 947 mDecryptedData = plainText;
1083 setText(QString::fromUtf8(mDecryptedData.constData())); 948 setText(QString::fromUtf8(mDecryptedData.constData()));
1084 } else { 949 } else {
1085 mMetaData.isEncrypted = decryptResult.error().code() != GPG_ERR_NO_DATA; 950 const auto errorCode = decryptResult.error.errorCode();
1086 mMetaData.errorText = QString::fromLocal8Bit(decryptResult.error().asString()); 951 mMetaData.isEncrypted = errorCode != GPG_ERR_NO_DATA;
1087 952 qWarning() << "Failed to decrypt : " << decryptResult.error;
1088 std::stringstream ss; 953
1089 ss << decryptResult << '\n' << verifyResult; 954 const bool noSecretKeyAvilable = [&] {
1090 qWarning() << "Decryption failed: " << ss.str().c_str(); 955 foreach (const auto &recipient, decryptResult.recipients) {
1091 956 if (!(recipient.status.errorCode() == GPG_ERR_NO_SECKEY)) {
1092 bool passphraseError = decryptResult.error().isCanceled() || decryptResult.error().code() == GPG_ERR_NO_SECKEY; 957 return false;
1093 958 }
1094 auto noSecKey = true; 959 }
1095 foreach (const GpgME::DecryptionResult::Recipient &recipient, decryptResult.recipients()) { 960 return true;
1096 noSecKey &= (recipient.status().code() == GPG_ERR_NO_SECKEY); 961 }();
1097 } 962 bool passphraseError = errorCode == GPG_ERR_CANCELED || errorCode == GPG_ERR_NO_SECKEY;
1098 if (!passphraseError && !noSecKey) { // GpgME do not detect passphrase error correctly 963 //We only get a decryption failed error when we enter the wrong passphrase....
964 if (!passphraseError && !noSecretKeyAvilable) {
1099 passphraseError = true; 965 passphraseError = true;
1100 } 966 }
1101 967
1102 if(noSecKey) { 968 if(noSecretKeyAvilable) {
1103 mError = NoKeyError; 969 mError = NoKeyError;
1104 mMetaData.errorText = tr("Could not decrypt the data. ") + tr("No key found for recepients."); 970 mMetaData.errorText = tr("Could not decrypt the data. ") + tr("No key found for recepients.");
1105 } else if (passphraseError) { 971 } else if (passphraseError) {
1106 mError = PassphraseError; 972 mError = PassphraseError;
973 // mMetaData.errorText = QString::fromLocal8Bit(decryptResult.error().asString());
1107 } else { 974 } else {
1108 mError = UnknownError; 975 mError = UnknownError;
1109 mMetaData.errorText = tr("Could not decrypt the data. ") 976 mMetaData.errorText = tr("Could not decrypt the data. ");
1110 + tr("Error: %1").arg(mMetaData.errorText); 977 // + tr("Error: %1").arg(QString::fromLocal8Bit(decryptResult.error().asString()));
1111 } 978 }
1112 return false; 979 return false;
1113 } 980 }