Messagelib

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

KDE's Doxygen guidelines are available online.