File indexing completed on 2025-03-09 04:53:56
0001 /* 0002 SPDX-FileCopyrightText: 2020 Sandro Knauß <sknauss@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "signencrypttest.h" 0008 0009 #include "cryptofunctions.h" 0010 #include "qtest_messagecomposer.h" 0011 #include <QTest> 0012 0013 #include <KMime/Content> 0014 0015 #include <Libkleo/Enum> 0016 0017 #include <MessageComposer/Composer> 0018 #include <MessageComposer/GlobalPart> 0019 #include <MessageComposer/MainTextJob> 0020 #include <MessageComposer/SignEncryptJob> 0021 #include <MessageComposer/TextPart> 0022 #include <MessageComposer/TransparentJob> 0023 #include <MessageComposer/Util> 0024 0025 #include <QGpgME/DecryptVerifyJob> 0026 #include <QGpgME/Protocol> 0027 0028 #include <gpgme++/decryptionresult.h> 0029 #include <gpgme++/verificationresult.h> 0030 0031 #include <sstream> 0032 0033 #include "setupenv.h" 0034 0035 QTEST_MAIN(SignEncryptTest) 0036 0037 using namespace MessageComposer; 0038 0039 void SignEncryptTest::initTestCase() 0040 { 0041 Test::setupEnv(); 0042 } 0043 0044 void SignEncryptTest::testContent_data() 0045 { 0046 QTest::addColumn<int>("cryptoMessageFormat"); 0047 QTest::addColumn<QString>("error"); 0048 0049 QTest::newRow("OpenPGPMimeFormat") << (int)Kleo::OpenPGPMIMEFormat << QString(); 0050 QTest::newRow("InlineOpenPGPFormat") << (int)Kleo::InlineOpenPGPFormat << QString(); 0051 QTest::newRow("SMIMEFormat") << (int)Kleo::SMIMEFormat << QStringLiteral("Not implemented"); 0052 QTest::newRow("SMIMEOpaqueFormat") << (int)Kleo::SMIMEOpaqueFormat << QStringLiteral("Not implemented"); 0053 } 0054 0055 void SignEncryptTest::testContent() 0056 { 0057 QFETCH(int, cryptoMessageFormat); 0058 QFETCH(QString, error); 0059 0060 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0061 const QString data(QString::fromLocal8Bit("one flew over the cuckoo's nest")); 0062 0063 Composer composer; 0064 0065 const QList<QByteArray> charsets = {"us-ascii"}; 0066 composer.globalPart()->setCharsets(charsets); 0067 0068 TextPart part; 0069 part.setWordWrappingEnabled(false); 0070 part.setCleanPlainText(data); 0071 0072 auto mainTextJob = new MainTextJob(&part, &composer); 0073 auto seJob = new SignEncryptJob(&composer); 0074 0075 QVERIFY(mainTextJob); 0076 0077 VERIFYEXEC(mainTextJob); 0078 0079 const QStringList recipients = {QString::fromLocal8Bit("test@kolab.org")}; 0080 0081 seJob->setContent(mainTextJob->content()); 0082 seJob->setSigningKeys(keys); 0083 seJob->setCryptoMessageFormat((Kleo::CryptoMessageFormat)cryptoMessageFormat); 0084 seJob->setRecipients(recipients); 0085 seJob->setEncryptionKeys(keys); 0086 0087 if (!error.isEmpty()) { 0088 QVERIFY(!seJob->exec()); 0089 QCOMPARE(seJob->errorString(), error); 0090 return; 0091 } 0092 0093 VERIFYEXEC(seJob); 0094 KMime::Content *result = seJob->content(); 0095 QVERIFY(result); 0096 result->assemble(); 0097 0098 ComposerTestUtil::verifySignatureAndEncryption(result, data.toUtf8(), (Kleo::CryptoMessageFormat)cryptoMessageFormat, false, true); 0099 0100 delete result; 0101 } 0102 0103 void SignEncryptTest::testContentSubjobChained() 0104 { 0105 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0106 0107 const QByteArray data(QString::fromLocal8Bit("one flew over the cuckoo's nest").toUtf8()); 0108 KMime::Message skeletonMessage; 0109 0110 auto content = new KMime::Content; 0111 content->contentType(true)->setMimeType("text/plain"); 0112 content->setBody(data); 0113 0114 auto tJob = new TransparentJob; 0115 tJob->setContent(content); 0116 0117 const QStringList recipients = {QString::fromLocal8Bit("test@kolab.org")}; 0118 0119 Composer composer; 0120 auto seJob = new SignEncryptJob(&composer); 0121 0122 seJob->setSigningKeys(keys); 0123 seJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0124 seJob->setRecipients(recipients); 0125 seJob->setEncryptionKeys(keys); 0126 seJob->setSkeletonMessage(&skeletonMessage); 0127 QVERIFY(seJob->appendSubjob(tJob)); 0128 0129 VERIFYEXEC(seJob); 0130 KMime::Content *result = seJob->content(); 0131 QVERIFY(result); 0132 result->assemble(); 0133 0134 ComposerTestUtil::verifySignatureAndEncryption(result, data, Kleo::OpenPGPMIMEFormat, false, true); 0135 0136 delete result; 0137 } 0138 0139 void SignEncryptTest::testHeaders() 0140 { 0141 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0142 0143 Composer composer; 0144 auto seJob = new SignEncryptJob(&composer); 0145 0146 QVERIFY(seJob); 0147 0148 const QByteArray data(QString::fromLocal8Bit("one flew over the cuckoo's nest").toUtf8()); 0149 auto content = new KMime::Content; 0150 content->setBody(data); 0151 0152 const QStringList recipients = {QString::fromLocal8Bit("test@kolab.org")}; 0153 0154 seJob->setContent(content); 0155 seJob->setSigningKeys(keys); 0156 seJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0157 seJob->setRecipients(recipients); 0158 seJob->setEncryptionKeys(keys); 0159 0160 VERIFYEXEC(seJob); 0161 0162 KMime::Content *result = seJob->content(); 0163 QVERIFY(result); 0164 result->assemble(); 0165 0166 QFile f(QStringLiteral("test")); 0167 QVERIFY(f.open(QIODevice::WriteOnly | QIODevice::Truncate)); 0168 const QByteArray encodedContent(result->encodedContent()); 0169 f.write(encodedContent); 0170 if (!encodedContent.endsWith('\n')) { 0171 f.write("\n"); 0172 } 0173 f.close(); 0174 0175 QVERIFY(result->contentType(false)); 0176 QCOMPARE(result->contentType()->mimeType(), "multipart/encrypted"); 0177 QCOMPARE(result->contentType()->charset(), "ISO-8859-1"); 0178 QCOMPARE(result->contentType()->parameter(QString::fromLocal8Bit("protocol")), QString::fromLocal8Bit("application/pgp-encrypted")); 0179 QCOMPARE(result->contentTransferEncoding()->encoding(), KMime::Headers::CE7Bit); 0180 0181 delete result; 0182 } 0183 0184 void SignEncryptTest::testProtectedHeaders_data() 0185 { 0186 QTest::addColumn<bool>("protectedHeaders"); 0187 QTest::addColumn<bool>("protectedHeadersObvoscate"); 0188 QTest::addColumn<QString>("referenceFile"); 0189 0190 QTest::newRow("simple-obvoscate") << true << true << QStringLiteral("protected_headers-obvoscate.mbox"); 0191 QTest::newRow("simple-non-obvoscate") << true << false << QStringLiteral("protected_headers-non-obvoscate.mbox"); 0192 QTest::newRow("non-protected_headers") << false << false << QStringLiteral("non-protected_headers.mbox"); 0193 } 0194 0195 void SignEncryptTest::testProtectedHeaders() 0196 { 0197 QFETCH(bool, protectedHeaders); 0198 QFETCH(bool, protectedHeadersObvoscate); 0199 QFETCH(QString, referenceFile); 0200 0201 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0202 0203 Composer composer; 0204 auto seJob = new SignEncryptJob(&composer); 0205 0206 QVERIFY(seJob); 0207 0208 const QByteArray data(QStringLiteral("one flew over the cuckoo's nest").toUtf8()); 0209 const QString subject(QStringLiteral("asdfghjklö")); 0210 0211 auto content = new KMime::Content; 0212 content->contentType(true)->setMimeType("text/plain"); 0213 content->setBody(data); 0214 0215 KMime::Message skeletonMessage; 0216 skeletonMessage.contentType(true)->setMimeType("foo/bla"); 0217 skeletonMessage.to(true)->from7BitString("to@test.de, to2@test.de"); 0218 skeletonMessage.cc(true)->from7BitString("cc@test.de, cc2@test.de"); 0219 skeletonMessage.bcc(true)->from7BitString("bcc@test.de, bcc2@test.de"); 0220 skeletonMessage.subject(true)->fromUnicodeString(subject, "utf-8"); 0221 0222 const QStringList recipients = {QStringLiteral("test@kolab.org")}; 0223 0224 seJob->setContent(content); 0225 seJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0226 seJob->setRecipients(recipients); 0227 seJob->setEncryptionKeys(keys); 0228 seJob->setSkeletonMessage(&skeletonMessage); 0229 seJob->setProtectedHeaders(protectedHeaders); 0230 seJob->setProtectedHeadersObvoscate(protectedHeadersObvoscate); 0231 0232 VERIFYEXEC(seJob); 0233 0234 if (protectedHeadersObvoscate) { 0235 QCOMPARE(skeletonMessage.subject()->as7BitString(false), "..."); 0236 } else { 0237 QCOMPARE(skeletonMessage.subject()->asUnicodeString(), subject); 0238 } 0239 0240 KMime::Content *result = seJob->content(); 0241 result->assemble(); 0242 0243 KMime::Content *encPart = Util::findTypeInMessage(result, "application", "octet-stream"); 0244 KMime::Content tempNode; 0245 { 0246 QByteArray plainText; 0247 auto job = QGpgME::openpgp()->decryptVerifyJob(); 0248 auto jobResult = job->exec(encPart->encodedBody(), plainText); 0249 0250 auto signature = jobResult.second.signatures()[0]; 0251 0252 QCOMPARE(signature.fingerprint(), "1BA323932B3FAA826132C79E8D9860C58F246DE6"); 0253 QCOMPARE(signature.status().code(), 0); 0254 0255 tempNode.setContent(KMime::CRLFtoLF(plainText.constData())); 0256 tempNode.parse(); 0257 } 0258 if (protectedHeadersObvoscate) { 0259 tempNode.contentType(false)->setBoundary("123456789"); 0260 tempNode.assemble(); 0261 } 0262 0263 delete result; 0264 0265 Test::compareFile(&tempNode, QStringLiteral(MAIL_DATA_DIR "/") + referenceFile); 0266 } 0267 0268 #include "moc_signencrypttest.cpp"