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"