diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-05-05 10:39:32 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-05-06 17:21:01 +0200 |
commit | 01594e68275a09c67b5ee258e2af86598118a6a0 (patch) | |
tree | 4f859815f6455906bb656f9cc27ba5d6e4111599 /framework/src/domain/mime/mimetreeparser | |
parent | 481cb9f600caf3f45596bf78b5ba2bd07007969c (diff) | |
download | kube-01594e68275a09c67b5ee258e2af86598118a6a0.tar.gz kube-01594e68275a09c67b5ee258e2af86598118a6a0.zip |
Port to gpgme only.
QGpgme and Gpgmepp are not readily available, the cmake files buggy, the
buildsystem horrendous and generally just difficult to build on windows.
Given that all they are is a wrapper around gpgme, we're better of
without all the indirections.
What we loose is:
* QGpgme moved the work to separate threads (but we then blocked
anyways), something that we can just do in our own code should we want to.
* QGpgme has a function to prettify dn's that was used to show the
signer. Also something we could bring back should we need to (don't know
where it is useful atm.)
Ported messagepart to gpgme
Almost there
Moved the crypto bits to a separate file
All gpg code is in one place.
All tests passing
Use error codes
Cleanup
Diffstat (limited to 'framework/src/domain/mime/mimetreeparser')
6 files changed, 90 insertions, 233 deletions
diff --git a/framework/src/domain/mime/mimetreeparser/CMakeLists.txt b/framework/src/domain/mime/mimetreeparser/CMakeLists.txt index b35bd958..c3f317ee 100644 --- a/framework/src/domain/mime/mimetreeparser/CMakeLists.txt +++ b/framework/src/domain/mime/mimetreeparser/CMakeLists.txt | |||
@@ -2,9 +2,8 @@ set(CMAKE_CXX_VISIBILITY_PRESET default) | |||
2 | 2 | ||
3 | find_package(Qt5 COMPONENTS REQUIRED Core Gui) | 3 | find_package(Qt5 COMPONENTS REQUIRED Core Gui) |
4 | find_package(KF5Mime 4.87.0 CONFIG REQUIRED) | 4 | find_package(KF5Mime 4.87.0 CONFIG REQUIRED) |
5 | find_package(QGpgme CONFIG REQUIRED) | ||
6 | find_package(Gpgmepp CONFIG REQUIRED) | ||
7 | find_package(KF5Codecs CONFIG REQUIRED) | 5 | find_package(KF5Codecs CONFIG REQUIRED) |
6 | find_package(Gpgme REQUIRED) | ||
8 | 7 | ||
9 | # target_include_directories does not handle empty include paths | 8 | # target_include_directories does not handle empty include paths |
10 | include_directories(${GPGME_INCLUDES}) | 9 | include_directories(${GPGME_INCLUDES}) |
@@ -49,8 +48,8 @@ target_link_libraries(kube_otp | |||
49 | 48 | ||
50 | target_link_libraries(kube_otp | 49 | target_link_libraries(kube_otp |
51 | PRIVATE | 50 | PRIVATE |
52 | QGpgme | 51 | gpgme |
53 | Gpgmepp | 52 | mailcrypto |
54 | KF5::Codecs | 53 | KF5::Codecs |
55 | Qt5::Gui | 54 | Qt5::Gui |
56 | ) | 55 | ) |
diff --git a/framework/src/domain/mime/mimetreeparser/autotests/CMakeLists.txt b/framework/src/domain/mime/mimetreeparser/autotests/CMakeLists.txt index f0b1f5f5..e67884e0 100644 --- a/framework/src/domain/mime/mimetreeparser/autotests/CMakeLists.txt +++ b/framework/src/domain/mime/mimetreeparser/autotests/CMakeLists.txt | |||
@@ -15,7 +15,7 @@ macro(add_mimetreeparser_unittest _source) | |||
15 | ecm_add_test(${_source} util.cpp setupenv.cpp | 15 | ecm_add_test(${_source} util.cpp setupenv.cpp |
16 | TEST_NAME ${_name} | 16 | TEST_NAME ${_name} |
17 | NAME_PREFIX "mimetreeparser-" | 17 | NAME_PREFIX "mimetreeparser-" |
18 | LINK_LIBRARIES kube_otp Qt5::Test KF5::Mime Gpgmepp | 18 | LINK_LIBRARIES kube_otp Qt5::Test KF5::Mime gpgme |
19 | ) | 19 | ) |
20 | endmacro () | 20 | endmacro () |
21 | 21 | ||
@@ -24,7 +24,7 @@ macro(add_mimetreeparser_class_unittest _source _additionalSource) | |||
24 | ecm_add_test(${_source} ${_additionalSource} | 24 | ecm_add_test(${_source} ${_additionalSource} |
25 | TEST_NAME ${_name} | 25 | TEST_NAME ${_name} |
26 | NAME_PREFIX "mimetreeparser-" | 26 | NAME_PREFIX "mimetreeparser-" |
27 | LINK_LIBRARIES kube_otp Qt5::Test KF5::Mime Gpgmepp | 27 | LINK_LIBRARIES kube_otp Qt5::Test KF5::Mime gpgme |
28 | ) | 28 | ) |
29 | endmacro () | 29 | endmacro () |
30 | 30 | ||
@@ -37,7 +37,7 @@ macro(add_mimetreeparser_crypto_unittest _source) | |||
37 | kube_otp | 37 | kube_otp |
38 | Qt5::Test | 38 | Qt5::Test |
39 | KF5::Mime | 39 | KF5::Mime |
40 | Gpgmepp | 40 | gpgme |
41 | ) | 41 | ) |
42 | add_gpg_crypto_test(${_name} mimetreeparser-${_name}) | 42 | add_gpg_crypto_test(${_name} mimetreeparser-${_name}) |
43 | endmacro () | 43 | endmacro () |
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 | ||
46 | using namespace MimeTreeParser; | 34 | using namespace MimeTreeParser; |
47 | 35 | using namespace Crypto; | |
48 | static GpgME::Data fromBA(const QByteArray &ba) | ||
49 | { | ||
50 | return {ba.data(), static_cast<size_t>(ba.size()), false}; | ||
51 | } | ||
52 | |||
53 | |||
54 | static 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 | |||
67 | static 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 | |||
79 | static GpgME::VerificationResult verifyDetachedSignature(CryptoProtocol protocol, const QByteArray &signature, const QByteArray &text) | ||
80 | { | ||
81 | return gpgContext(protocol)->verifyDetachedSignature(fromBA(signature), fromBA(text)); | ||
82 | } | ||
83 | |||
84 | static 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 | |||
94 | static 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 | |||
103 | static void importKeys(CryptoProtocol protocol, const QByteArray &certData) | ||
104 | { | ||
105 | gpgContext(protocol)->importKeys(fromBA(certData)); | ||
106 | } | ||
107 | |||
108 | static 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----------------------- |
128 | MessagePart::MessagePart(ObjectTreeParser *otp, const QString &text, KMime::Content *node) | 38 | MessagePart::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 | ||
780 | SignedMessagePart::~SignedMessagePart() | 687 | SignedMessagePart::~SignedMessagePart() |
@@ -792,99 +699,65 @@ bool SignedMessagePart::isSigned() const | |||
792 | return mMetaData.isSigned; | 699 | return mMetaData.isSigned; |
793 | } | 700 | } |
794 | 701 | ||
795 | static 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 | ||
815 | QString prettifyDN(const char *uid) | 703 | static 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 | ||
820 | void SignedMessagePart::sigStatusToMetaData(const GpgME::Signature &signature) | 709 | void 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 | ||
946 | void SignedMessagePart::setVerificationResult(const GpgME::VerificationResult &result, bool parseText, const QByteArray &plainText) | 814 | void 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 | ||
1003 | EncryptedMessagePart::~EncryptedMessagePart() | 868 | EncryptedMessagePart::~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 | } |
diff --git a/framework/src/domain/mime/mimetreeparser/messagepart.h b/framework/src/domain/mime/mimetreeparser/messagepart.h index 3c07ca88..c576699e 100644 --- a/framework/src/domain/mime/mimetreeparser/messagepart.h +++ b/framework/src/domain/mime/mimetreeparser/messagepart.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "util.h" | 23 | #include "util.h" |
24 | #include "enums.h" | 24 | #include "enums.h" |
25 | #include "partmetadata.h" | 25 | #include "partmetadata.h" |
26 | #include <crypto.h> | ||
26 | 27 | ||
27 | #include <KMime/Message> | 28 | #include <KMime/Message> |
28 | 29 | ||
@@ -32,13 +33,6 @@ | |||
32 | class QTextCodec; | 33 | class QTextCodec; |
33 | class PartPrivate; | 34 | class PartPrivate; |
34 | 35 | ||
35 | namespace GpgME | ||
36 | { | ||
37 | class ImportResult; | ||
38 | class VerificationResult; | ||
39 | class Signature; | ||
40 | } | ||
41 | |||
42 | namespace KMime | 36 | namespace KMime |
43 | { | 37 | { |
44 | class Content; | 38 | class Content; |
@@ -55,11 +49,10 @@ class MultiPartAlternativeBodyPartFormatter; | |||
55 | class SignedMessagePart; | 49 | class SignedMessagePart; |
56 | class EncryptedMessagePart; | 50 | class EncryptedMessagePart; |
57 | 51 | ||
58 | enum CryptoProtocol { | 52 | using Crypto::CryptoProtocol; |
59 | UnknownProtocol, | 53 | using Crypto::CryptoProtocol::CMS; |
60 | OpenPGP, | 54 | using Crypto::CryptoProtocol::OpenPGP; |
61 | CMS | 55 | using Crypto::CryptoProtocol::UnknownProtocol; |
62 | }; | ||
63 | 56 | ||
64 | class MessagePart : public QObject | 57 | class MessagePart : public QObject |
65 | { | 58 | { |
@@ -366,8 +359,8 @@ public: | |||
366 | QString htmlContent() const Q_DECL_OVERRIDE; | 359 | QString htmlContent() const Q_DECL_OVERRIDE; |
367 | 360 | ||
368 | private: | 361 | private: |
369 | void sigStatusToMetaData(const GpgME::Signature &signature); | 362 | void sigStatusToMetaData(const Crypto::Signature &signature); |
370 | void setVerificationResult(const GpgME::VerificationResult &result, bool parseText, const QByteArray &plainText); | 363 | void setVerificationResult(const Crypto::VerificationResult &result, bool parseText, const QByteArray &plainText); |
371 | 364 | ||
372 | protected: | 365 | protected: |
373 | CryptoProtocol mProtocol; | 366 | CryptoProtocol mProtocol; |
diff --git a/framework/src/domain/mime/mimetreeparser/partmetadata.h b/framework/src/domain/mime/mimetreeparser/partmetadata.h index 44a9cf7e..583eb454 100644 --- a/framework/src/domain/mime/mimetreeparser/partmetadata.h +++ b/framework/src/domain/mime/mimetreeparser/partmetadata.h | |||
@@ -37,7 +37,6 @@ public: | |||
37 | QByteArray keyId; | 37 | QByteArray keyId; |
38 | bool keyIsTrusted = false; | 38 | bool keyIsTrusted = false; |
39 | QString status; // to be used for unknown plug-ins | 39 | QString status; // to be used for unknown plug-ins |
40 | int status_code; // to be used for i18n of OpenPGP and S/MIME CryptPlugs | ||
41 | QString errorText; | 40 | QString errorText; |
42 | QDateTime creationTime; | 41 | QDateTime creationTime; |
43 | QString decryptionError; | 42 | QString decryptionError; |
diff --git a/framework/src/domain/mime/mimetreeparser/tests/CMakeLists.txt b/framework/src/domain/mime/mimetreeparser/tests/CMakeLists.txt index 9937ab06..fcb1988a 100644 --- a/framework/src/domain/mime/mimetreeparser/tests/CMakeLists.txt +++ b/framework/src/domain/mime/mimetreeparser/tests/CMakeLists.txt | |||
@@ -15,12 +15,11 @@ target_link_libraries(mimetreeparsertest | |||
15 | Qt5::Core | 15 | Qt5::Core |
16 | Qt5::Test | 16 | Qt5::Test |
17 | KF5::Mime | 17 | KF5::Mime |
18 | Gpgmepp | 18 | gpgme |
19 | QGpgme | ||
20 | ) | 19 | ) |
21 | 20 | ||
22 | ecm_add_test(gpgerrortest.cpp | 21 | ecm_add_test(gpgerrortest.cpp |
23 | TEST_NAME "gpgerrortest" | 22 | TEST_NAME "gpgerrortest" |
24 | NAME_PREFIX "mimetreeparser-" | 23 | NAME_PREFIX "mimetreeparser-" |
25 | LINK_LIBRARIES Qt5::Core Qt5::Test kube_otp Gpgmepp QGpgme | 24 | LINK_LIBRARIES Qt5::Core Qt5::Test kube_otp gpgme |
26 | ) | 25 | ) |