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

KDE's Doxygen guidelines are available online.