File indexing completed on 2024-06-23 05:19:20
0001 /* 0002 SPDX-FileCopyrightText: 2016 Sandro Knauß <sknauss@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "applicationpkcs7mime.h" 0008 0009 #include "messagepart.h" 0010 #include "objecttreeparser.h" 0011 0012 #include <QGpgME/Protocol> 0013 0014 #include <KMime/Content> 0015 0016 #include "mimetreeparser_debug.h" 0017 0018 using namespace MimeTreeParser; 0019 0020 const ApplicationPkcs7MimeBodyPartFormatter *ApplicationPkcs7MimeBodyPartFormatter::self; 0021 0022 const Interface::BodyPartFormatter *ApplicationPkcs7MimeBodyPartFormatter::create() 0023 { 0024 if (!self) { 0025 self = new ApplicationPkcs7MimeBodyPartFormatter(); 0026 } 0027 return self; 0028 } 0029 0030 MessagePart::Ptr ApplicationPkcs7MimeBodyPartFormatter::process(Interface::BodyPart &part) const 0031 { 0032 KMime::Content *node = part.content(); 0033 0034 if (node->head().isEmpty()) { 0035 return {}; 0036 } 0037 0038 const auto smimeCrypto = QGpgME::smime(); 0039 if (!smimeCrypto) { 0040 return {}; 0041 } 0042 0043 // we are also registered for octet-stream, in that case stop here if that's not a part for us 0044 const auto ct = node->contentType(); // Create 0045 const auto mt = ct->mimeType(); 0046 const auto isCorrectMimeType = mt == QByteArrayLiteral("application/pkcs7-mime") || mt == QByteArrayLiteral("application/x-pkcs7-mime"); 0047 const auto hasCorrectName = mt == QByteArrayLiteral("application/octet-stream") 0048 && (ct->name().endsWith(QLatin1StringView("p7m")) || ct->name().endsWith(QLatin1StringView("p7s")) || ct->name().endsWith(QLatin1StringView("p7c"))); 0049 if (!isCorrectMimeType && !hasCorrectName) { 0050 return {}; 0051 } 0052 0053 const QString smimeType = node->contentType(false)->parameter(QStringLiteral("smime-type")).toLower(); 0054 0055 if (smimeType == QLatin1StringView("certs-only")) { 0056 part.processResult()->setNeverDisplayInline(true); 0057 0058 CertMessagePart::Ptr mp(new CertMessagePart(part.objectTreeParser(), node, smimeCrypto, part.source()->autoImportKeys())); 0059 return mp; 0060 } 0061 0062 bool isSigned = (smimeType == QLatin1StringView("signed-data")); 0063 bool isEncrypted = (smimeType == QLatin1StringView("enveloped-data")); 0064 0065 // Analyze "signTestNode" node to find/verify a signature. 0066 // If zero part.objectTreeParser() verification was successfully done after 0067 // decrypting via recursion by insertAndParseNewChildNode(). 0068 KMime::Content *signTestNode = isEncrypted ? nullptr : node; 0069 0070 // We try decrypting the content 0071 // if we either *know* that it is an encrypted message part 0072 // or there is neither signed nor encrypted parameter. 0073 MessagePart::Ptr mp; 0074 if (!isSigned) { 0075 if (isEncrypted) { 0076 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime == S/MIME TYPE: enveloped (encrypted) data"; 0077 } else { 0078 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - type unknown - enveloped (encrypted) data ?"; 0079 } 0080 0081 auto _mp = EncryptedMessagePart::Ptr( 0082 new EncryptedMessagePart(part.objectTreeParser(), node->decodedText(), smimeCrypto, part.nodeHelper()->fromAsString(node), node)); 0083 mp = _mp; 0084 _mp->setIsEncrypted(true); 0085 _mp->setDecryptMessage(part.source()->decryptMessage()); 0086 PartMetaData *messagePart(_mp->partMetaData()); 0087 if (!part.source()->decryptMessage()) { 0088 isEncrypted = true; 0089 signTestNode = nullptr; // PENDING(marc) to be abs. sure, we'd need to have to look at the content 0090 } else { 0091 _mp->startDecryption(); 0092 if (messagePart->isDecryptable) { 0093 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - encryption found - enveloped (encrypted) data !"; 0094 isEncrypted = true; 0095 part.nodeHelper()->setEncryptionState(node, KMMsgFullyEncrypted); 0096 signTestNode = nullptr; 0097 } else { 0098 // decryption failed, which could be because the part was encrypted but 0099 // decryption failed, or because we didn't know if it was encrypted, tried, 0100 // and failed. If the message was not actually encrypted, we continue 0101 // assuming it's signed 0102 if (_mp->passphraseError() || (smimeType.isEmpty() && messagePart->isEncrypted)) { 0103 isEncrypted = true; 0104 signTestNode = nullptr; 0105 } 0106 0107 if (isEncrypted) { 0108 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - ERROR: COULD NOT DECRYPT enveloped data !"; 0109 } else { 0110 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - NO encryption found"; 0111 } 0112 } 0113 } 0114 0115 if (isEncrypted) { 0116 part.nodeHelper()->setEncryptionState(node, KMMsgFullyEncrypted); 0117 } 0118 } 0119 0120 // We now try signature verification if necessary. 0121 if (signTestNode) { 0122 if (isSigned) { 0123 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime == S/MIME TYPE: opaque signed data"; 0124 } else { 0125 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - type unknown - opaque signed data ?"; 0126 } 0127 0128 QStringDecoder aCodec(part.objectTreeParser()->codecNameFor(signTestNode).constData()); 0129 const QByteArray signaturetext = signTestNode->decodedContent(); 0130 auto _mp = SignedMessagePart::Ptr( 0131 new SignedMessagePart(part.objectTreeParser(), aCodec.decode(signaturetext), smimeCrypto, part.nodeHelper()->fromAsString(node), signTestNode)); 0132 mp = _mp; 0133 _mp->startVerificationDetached(signaturetext, nullptr, QByteArray()); 0134 0135 if (_mp->isSigned()) { 0136 if (!isSigned) { 0137 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - signature found - opaque signed data !"; 0138 } 0139 0140 if (signTestNode != node) { 0141 part.nodeHelper()->setSignatureState(node, KMMsgFullySigned); 0142 } 0143 } else { 0144 qCDebug(MIMETREEPARSER_LOG) << "pkcs7 mime - NO signature found :-("; 0145 } 0146 } 0147 0148 return mp; 0149 }