diff options
Diffstat (limited to 'framework/src/domain/mimetreeparser/otp/applicationpkcs7mime.cpp')
-rw-r--r-- | framework/src/domain/mimetreeparser/otp/applicationpkcs7mime.cpp | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/framework/src/domain/mimetreeparser/otp/applicationpkcs7mime.cpp b/framework/src/domain/mimetreeparser/otp/applicationpkcs7mime.cpp new file mode 100644 index 00000000..bcfc0616 --- /dev/null +++ b/framework/src/domain/mimetreeparser/otp/applicationpkcs7mime.cpp | |||
@@ -0,0 +1,178 @@ | |||
1 | /* | ||
2 | Copyright (c) 2016 Sandro Knauß <sknauss@kde.org> | ||
3 | |||
4 | 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 | the Free Software Foundation; either version 2 of the License, or (at your | ||
7 | option) any later version. | ||
8 | |||
9 | This library is distributed in the hope that it will be useful, but WITHOUT | ||
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | ||
12 | License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Library General Public License | ||
15 | along with this library; see the file COPYING.LIB. If not, write to the | ||
16 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | 02110-1301, USA. | ||
18 | */ | ||
19 | |||
20 | #include "applicationpkcs7mime.h" | ||
21 | |||
22 | #include "utils.h" | ||
23 | |||
24 | #include "attachmentstrategy.h" | ||
25 | #include "objecttreeparser.h" | ||
26 | #include "messagepart.h" | ||
27 | |||
28 | #include <QGpgME/Protocol> | ||
29 | |||
30 | #include <KMime/Content> | ||
31 | |||
32 | #include <QTextCodec> | ||
33 | |||
34 | #include "mimetreeparser_debug.h" | ||
35 | |||
36 | using namespace MimeTreeParser; | ||
37 | |||
38 | const ApplicationPkcs7MimeBodyPartFormatter *ApplicationPkcs7MimeBodyPartFormatter::self; | ||
39 | |||
40 | const Interface::BodyPartFormatter *ApplicationPkcs7MimeBodyPartFormatter::create() | ||
41 | { | ||
42 | if (!self) { | ||
43 | self = new ApplicationPkcs7MimeBodyPartFormatter(); | ||
44 | } | ||
45 | return self; | ||
46 | } | ||
47 | Interface::BodyPartFormatter::Result ApplicationPkcs7MimeBodyPartFormatter::format(Interface::BodyPart *part, HtmlWriter *writer) const | ||
48 | { | ||
49 | Q_UNUSED(writer) | ||
50 | const auto p = process(*part); | ||
51 | const auto mp = static_cast<MessagePart *>(p.data()); | ||
52 | if (mp) { | ||
53 | mp->html(false); | ||
54 | return Ok; | ||
55 | } | ||
56 | return Failed; | ||
57 | } | ||
58 | |||
59 | Interface::MessagePart::Ptr ApplicationPkcs7MimeBodyPartFormatter::process(Interface::BodyPart &part) const | ||
60 | { | ||
61 | KMime::Content *node = part.content(); | ||
62 | |||
63 | if (node->head().isEmpty()) { | ||
64 | return MessagePart::Ptr(); | ||
65 | } | ||
66 | |||
67 | const auto smimeCrypto = QGpgME::smime(); | ||
68 | if (!smimeCrypto) { | ||
69 | return MessagePart::Ptr(); | ||
70 | } | ||
71 | |||
72 | const QString smimeType = node->contentType()->parameter(QStringLiteral("smime-type")).toLower(); | ||
73 | |||
74 | if (smimeType == QLatin1String("certs-only")) { | ||
75 | part.processResult()->setNeverDisplayInline(true); | ||
76 | |||
77 | CertMessagePart::Ptr mp(new CertMessagePart(part.objectTreeParser(), node, smimeCrypto, part.source()->autoImportKeys())); | ||
78 | return mp; | ||
79 | } | ||
80 | |||
81 | bool isSigned = (smimeType == QLatin1String("signed-data")); | ||
82 | bool isEncrypted = (smimeType == QLatin1String("enveloped-data")); | ||
83 | |||
84 | // Analyze "signTestNode" node to find/verify a signature. | ||
85 | // If zero part.objectTreeParser() verification was successfully done after | ||
86 | // decrypting via recursion by insertAndParseNewChildNode(). | ||
87 | KMime::Content *signTestNode = isEncrypted ? nullptr : node; | ||
88 | |||
89 | // We try decrypting the content | ||
90 | // if we either *know* that it is an encrypted message part | ||
91 | // or there is neither signed nor encrypted parameter. | ||
92 | MessagePart::Ptr mp; | ||
93 | if (!isSigned) { | ||
94 | if (isEncrypted) { | ||
95 | qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime == S/MIME TYPE: enveloped (encrypted) data"; | ||
96 | } else { | ||
97 | qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - type unknown - enveloped (encrypted) data ?"; | ||
98 | } | ||
99 | |||
100 | auto _mp = EncryptedMessagePart::Ptr(new EncryptedMessagePart(part.objectTreeParser(), | ||
101 | node->decodedText(), smimeCrypto, | ||
102 | part.nodeHelper()->fromAsString(node), node)); | ||
103 | mp = _mp; | ||
104 | _mp->setIsEncrypted(true); | ||
105 | _mp->setDecryptMessage(part.source()->decryptMessage()); | ||
106 | PartMetaData *messagePart(_mp->partMetaData()); | ||
107 | if (!part.source()->decryptMessage()) { | ||
108 | isEncrypted = true; | ||
109 | signTestNode = nullptr; // PENDING(marc) to be abs. sure, we'd need to have to look at the content | ||
110 | } else { | ||
111 | _mp->startDecryption(); | ||
112 | if (messagePart->isDecryptable) { | ||
113 | qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - encryption found - enveloped (encrypted) data !"; | ||
114 | isEncrypted = true; | ||
115 | part.nodeHelper()->setEncryptionState(node, KMMsgFullyEncrypted); | ||
116 | signTestNode = nullptr; | ||
117 | |||
118 | } else { | ||
119 | // decryption failed, which could be because the part was encrypted but | ||
120 | // decryption failed, or because we didn't know if it was encrypted, tried, | ||
121 | // and failed. If the message was not actually encrypted, we continue | ||
122 | // assuming it's signed | ||
123 | if (_mp->passphraseError() || (smimeType.isEmpty() && messagePart->isEncrypted)) { | ||
124 | isEncrypted = true; | ||
125 | signTestNode = nullptr; | ||
126 | } | ||
127 | |||
128 | if (isEncrypted) { | ||
129 | qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - ERROR: COULD NOT DECRYPT enveloped data !"; | ||
130 | } else { | ||
131 | qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - NO encryption found"; | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | if (isEncrypted) { | ||
137 | part.nodeHelper()->setEncryptionState(node, KMMsgFullyEncrypted); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | // We now try signature verification if necessarry. | ||
142 | if (signTestNode) { | ||
143 | if (isSigned) { | ||
144 | qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime == S/MIME TYPE: opaque signed data"; | ||
145 | } else { | ||
146 | qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - type unknown - opaque signed data ?"; | ||
147 | } | ||
148 | |||
149 | const QTextCodec *aCodec(part.objectTreeParser()->codecFor(signTestNode)); | ||
150 | const QByteArray signaturetext = signTestNode->decodedContent(); | ||
151 | auto _mp = SignedMessagePart::Ptr(new SignedMessagePart(part.objectTreeParser(), | ||
152 | aCodec->toUnicode(signaturetext), smimeCrypto, | ||
153 | part.nodeHelper()->fromAsString(node), signTestNode)); | ||
154 | mp = _mp; | ||
155 | //mp->setDecryptMessage(part.source()->decryptMessage()); | ||
156 | PartMetaData *messagePart(mp->partMetaData()); | ||
157 | if (smimeCrypto) { | ||
158 | _mp->startVerificationDetached(signaturetext, nullptr, QByteArray()); | ||
159 | } else { | ||
160 | messagePart->auditLogError = GpgME::Error(GPG_ERR_NOT_IMPLEMENTED); | ||
161 | } | ||
162 | |||
163 | if (_mp->isSigned()) { | ||
164 | if (!isSigned) { | ||
165 | qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - signature found - opaque signed data !"; | ||
166 | isSigned = true; | ||
167 | } | ||
168 | |||
169 | if (signTestNode != node) { | ||
170 | part.nodeHelper()->setSignatureState(node, KMMsgFullySigned); | ||
171 | } | ||
172 | } else { | ||
173 | qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - NO signature found :-("; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | return mp; | ||
178 | } | ||