Messagelib

applicationpkcs7mime.cpp
1/*
2 SPDX-FileCopyrightText: 2016 Sandro Knauß <sknauss@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "applicationpkcs7mime.h"
8
9#include "messagepart.h"
10#include "objecttreeparser.h"
11
12#include <QGpgME/Protocol>
13
14#include <KMime/Content>
15
16#include "mimetreeparser_debug.h"
17
18using namespace MimeTreeParser;
19
20const ApplicationPkcs7MimeBodyPartFormatter *ApplicationPkcs7MimeBodyPartFormatter::self;
21
22const Interface::BodyPartFormatter *ApplicationPkcs7MimeBodyPartFormatter::create()
23{
24 if (!self) {
25 self = new ApplicationPkcs7MimeBodyPartFormatter();
26 }
27 return self;
28}
29
30MessagePart::Ptr ApplicationPkcs7MimeBodyPartFormatter::process(Interface::BodyPart &part) const
31{
32 KMime::Content *node = part.content();
33
34 if (node->head().isEmpty()) {
35 return {};
36 }
37
38 const auto smimeCrypto = QGpgME::smime();
39 if (!smimeCrypto) {
40 return {};
41 }
42
43 // we are also registered for octet-stream, in that case stop here if that's not a part for us
44 const auto ct = node->contentType(); // Create
45 const auto mt = ct->mimeType();
46 const auto isCorrectMimeType = mt == QByteArrayLiteral("application/pkcs7-mime") || mt == QByteArrayLiteral("application/x-pkcs7-mime");
47 const auto hasCorrectName = mt == QByteArrayLiteral("application/octet-stream")
48 && (ct->name().endsWith(QLatin1StringView("p7m")) || ct->name().endsWith(QLatin1StringView("p7s")) || ct->name().endsWith(QLatin1StringView("p7c")));
49 if (!isCorrectMimeType && !hasCorrectName) {
50 return {};
51 }
52
53 const QString smimeType = node->contentType(false)->parameter(QStringLiteral("smime-type")).toLower();
54
55 if (smimeType == QLatin1StringView("certs-only")) {
56 part.processResult()->setNeverDisplayInline(true);
57
58 CertMessagePart::Ptr mp(new CertMessagePart(part.objectTreeParser(), node, smimeCrypto, part.source()->autoImportKeys()));
59 return mp;
60 }
61
62 bool isSigned = (smimeType == QLatin1StringView("signed-data"));
63 bool isEncrypted = (smimeType == QLatin1StringView("enveloped-data"));
64
65 // Analyze "signTestNode" node to find/verify a signature.
66 // If zero part.objectTreeParser() verification was successfully done after
67 // decrypting via recursion by insertAndParseNewChildNode().
68 KMime::Content *signTestNode = isEncrypted ? nullptr : node;
69
70 // We try decrypting the content
71 // if we either *know* that it is an encrypted message part
72 // or there is neither signed nor encrypted parameter.
74 if (!isSigned) {
75 if (isEncrypted) {
76 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime == S/MIME TYPE: enveloped (encrypted) data";
77 } else {
78 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - type unknown - enveloped (encrypted) data ?";
79 }
80
82 new EncryptedMessagePart(part.objectTreeParser(), node->decodedText(), smimeCrypto, part.nodeHelper()->fromAsString(node), node));
83 mp = _mp;
84 _mp->setIsEncrypted(true);
85 _mp->setDecryptMessage(part.source()->decryptMessage());
86 PartMetaData *messagePart(_mp->partMetaData());
87 if (!part.source()->decryptMessage()) {
88 isEncrypted = true;
89 signTestNode = nullptr; // PENDING(marc) to be abs. sure, we'd need to have to look at the content
90 } else {
91 _mp->startDecryption();
92 if (messagePart->isDecryptable) {
93 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - encryption found - enveloped (encrypted) data !";
94 isEncrypted = true;
95 part.nodeHelper()->setEncryptionState(node, KMMsgFullyEncrypted);
96 signTestNode = nullptr;
97 } else {
98 // decryption failed, which could be because the part was encrypted but
99 // decryption failed, or because we didn't know if it was encrypted, tried,
100 // and failed. If the message was not actually encrypted, we continue
101 // assuming it's signed
102 if (_mp->passphraseError() || (smimeType.isEmpty() && messagePart->isEncrypted)) {
103 isEncrypted = true;
104 signTestNode = nullptr;
105 }
106
107 if (isEncrypted) {
108 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - ERROR: COULD NOT DECRYPT enveloped data !";
109 } else {
110 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - NO encryption found";
111 }
112 }
113 }
114
115 if (isEncrypted) {
116 part.nodeHelper()->setEncryptionState(node, KMMsgFullyEncrypted);
117 }
118 }
119
120 // We now try signature verification if necessary.
121 if (signTestNode) {
122 if (isSigned) {
123 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime == S/MIME TYPE: opaque signed data";
124 } else {
125 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - type unknown - opaque signed data ?";
126 }
127
128 QStringDecoder aCodec(part.objectTreeParser()->codecNameFor(signTestNode).constData());
129 const QByteArray signaturetext = signTestNode->decodedContent();
130 auto _mp = SignedMessagePart::Ptr(
131 new SignedMessagePart(part.objectTreeParser(), aCodec.decode(signaturetext), smimeCrypto, part.nodeHelper()->fromAsString(node), signTestNode));
132 mp = _mp;
133 _mp->startVerificationDetached(signaturetext, nullptr, QByteArray());
134
135 if (_mp->isSigned()) {
136 if (!isSigned) {
137 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - signature found - opaque signed data !";
138 }
139
140 if (signTestNode != node) {
141 part.nodeHelper()->setSignatureState(node, KMMsgFullySigned);
142 }
143 } else {
144 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - NO signature found :-(";
145 }
146 }
147
148 return mp;
149}
Headers::ContentType * contentType(bool create=true)
QString decodedText(bool trimText=false, bool removeTrailingNewlines=false)
QByteArray head() const
QByteArray decodedContent()
QByteArray mimeType() const
QString parameter(const QString &key) const
interface of message body parts.
Definition bodypart.h:45
virtual MimeTreeParser::ObjectTreeParser * objectTreeParser() const =0
For making it easier to refactor, add objectTreeParser.
virtual MimeTreeParser::NodeHelper * nodeHelper() const =0
Ok, this is ugly, exposing the node helper here, but there is too much useful stuff in there for real...
virtual KMime::Content * content() const =0
Returns the KMime::Content node represented here.
virtual bool autoImportKeys() const =0
should keys be imported automatically
virtual bool decryptMessage() const =0
Return true if an encrypted mail should be decrypted.
const char * constData() const const
bool isEmpty() const const
bool isEmpty() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:12:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.