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 
18 using namespace MimeTreeParser;
19 
20 const ApplicationPkcs7MimeBodyPartFormatter *ApplicationPkcs7MimeBodyPartFormatter::self;
21 
22 const Interface::BodyPartFormatter *ApplicationPkcs7MimeBodyPartFormatter::create()
23 {
24  if (!self) {
25  self = new ApplicationPkcs7MimeBodyPartFormatter();
26  }
27  return self;
28 }
29 
30 MessagePart::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 
81  auto _mp = EncryptedMessagePart::Ptr(
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 }
virtual MimeTreeParser::ObjectTreeParser * objectTreeParser() const =0
For making it easier to refactor, add objectTreeParser.
virtual bool autoImportKeys() const =0
should keys be imported automatically
QByteArray mimeType() const
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...
QString decodedText(bool trimText=false, bool removeTrailingNewlines=false)
QString parameter(const QString &key) const
bool isEmpty() const const
virtual bool decryptMessage() const =0
Return true if an encrypted mail should be decrypted.
virtual KMime::Content * content() const =0
Returns the KMime::Content node represented here.
interface of message body parts.
Definition: bodypart.h:44
QByteArray head() const
QByteArray decodedContent()
bool isEmpty() const const
const char * constData() const const
Headers::ContentType * contentType(bool create=true)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Thu Feb 15 2024 03:55:19 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.