File indexing completed on 2024-06-02 05:29:15
0001 /* 0002 SPDX-FileCopyrightText: 2009 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.net 0003 SPDX-FileCopyrightText: 2009 Leo Franchi <lfranchi@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "signjobtest.h" 0009 0010 #include "cryptofunctions.h" 0011 #include "qtest_messagecomposer.h" 0012 #include <QTest> 0013 0014 #include <KMime/Content> 0015 0016 #include <Libkleo/Enum> 0017 0018 #include <MessageComposer/Composer> 0019 #include <MessageComposer/SignJob> 0020 #include <MessageComposer/TransparentJob> 0021 0022 #include "setupenv.h" 0023 #include <MessageCore/NodeHelper> 0024 0025 #include <cstdlib> 0026 0027 QTEST_MAIN(SignJobTest) 0028 0029 using namespace MessageComposer; 0030 0031 void SignJobTest::initTestCase() 0032 { 0033 Test::setupEnv(); 0034 } 0035 0036 void SignJobTest::testContentDirect() 0037 { 0038 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0039 0040 Composer composer; 0041 auto sJob = new SignJob(&composer); 0042 0043 QVERIFY(sJob); 0044 0045 const QByteArray data(QString::fromLocal8Bit("one flew over the cuckoo's nest").toUtf8()); 0046 auto content = new KMime::Content; 0047 content->setBody(data); 0048 0049 sJob->setContent(content); 0050 sJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0051 sJob->setSigningKeys(keys); 0052 0053 checkSignJob(sJob); 0054 } 0055 0056 void SignJobTest::testContentChained() 0057 { 0058 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0059 0060 const QByteArray data(QString::fromLocal8Bit("one flew over the cuckoo's nest").toUtf8()); 0061 auto content = new KMime::Content; 0062 content->setBody(data); 0063 0064 auto tJob = new TransparentJob; 0065 tJob->setContent(content); 0066 0067 Composer composer; 0068 auto sJob = new SignJob(&composer); 0069 0070 sJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0071 sJob->setSigningKeys(keys); 0072 0073 sJob->appendSubjob(tJob); 0074 0075 checkSignJob(sJob); 0076 } 0077 0078 void SignJobTest::testHeaders() 0079 { 0080 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0081 0082 Composer composer; 0083 auto sJob = new SignJob(&composer); 0084 0085 QVERIFY(sJob); 0086 0087 const QByteArray data(QString::fromLocal8Bit("one flew over the cuckoo's nest").toUtf8()); 0088 auto content = new KMime::Content; 0089 content->setBody(data); 0090 0091 sJob->setContent(content); 0092 sJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0093 sJob->setSigningKeys(keys); 0094 0095 VERIFYEXEC(sJob); 0096 0097 KMime::Content *result = sJob->content(); 0098 result->assemble(); 0099 0100 QVERIFY(result->contentType(false)); 0101 QCOMPARE(result->contentType()->mimeType(), "multipart/signed"); 0102 QCOMPARE(result->contentType()->charset(), "ISO-8859-1"); 0103 QVERIFY(result->contentType() 0104 ->parameter(QString::fromLocal8Bit("micalg")) 0105 .startsWith(QLatin1StringView("pgp-sha"))); // sha1 or sha256, depending on GnuPG version 0106 QCOMPARE(result->contentType()->parameter(QString::fromLocal8Bit("protocol")), QString::fromLocal8Bit("application/pgp-signature")); 0107 QCOMPARE(result->contentTransferEncoding()->encoding(), KMime::Headers::CE7Bit); 0108 0109 delete result; 0110 } 0111 0112 void SignJobTest::testRecommentationRFC3156() 0113 { 0114 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0115 0116 const QString data = QStringLiteral("=2D Magic foo\nFrom test\n\n-- quaak\nOhno"); 0117 KMime::Headers::contentEncoding cte = KMime::Headers::CEquPr; 0118 0119 Composer composer; 0120 auto sJob = new SignJob(&composer); 0121 0122 QVERIFY(sJob); 0123 0124 auto content = new KMime::Content; 0125 content->setBody(data.toUtf8()); 0126 0127 sJob->setContent(content); 0128 sJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0129 sJob->setSigningKeys(keys); 0130 0131 VERIFYEXEC(sJob); 0132 0133 KMime::Content *result = sJob->content(); 0134 result->assemble(); 0135 0136 const QByteArray body = MessageCore::NodeHelper::firstChild(result)->body(); 0137 QCOMPARE(QString::fromUtf8(body), QStringLiteral("=3D2D Magic foo\n=46rom test\n\n=2D- quaak\nOhno")); 0138 0139 ComposerTestUtil::verify(true, false, result, data.toUtf8(), Kleo::OpenPGPMIMEFormat, cte); 0140 delete result; 0141 } 0142 0143 void SignJobTest::testMixedContent() 0144 { 0145 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0146 0147 const QString data = QStringLiteral("=2D Magic foo\nFrom test\n\n-- quaak\nOhno"); 0148 0149 Composer composer; 0150 auto sJob = new SignJob(&composer); 0151 0152 QVERIFY(sJob); 0153 0154 auto content = new KMime::Content; 0155 content->contentType()->setMimeType(QByteArrayLiteral("multipart/mixed")); 0156 content->contentType()->setBoundary(KMime::multiPartBoundary()); 0157 auto subcontent = new KMime::Content; 0158 subcontent->contentType()->setMimeType(QByteArrayLiteral("text/plain")); 0159 subcontent->setBody(data.toUtf8()); 0160 auto attachment = new KMime::Content; 0161 attachment->contentType()->setMimeType(QByteArrayLiteral("text/plain")); 0162 const QByteArray attachmentData("an attachment"); 0163 attachment->setBody(attachmentData); 0164 0165 content->appendContent(subcontent); 0166 content->appendContent(attachment); 0167 content->assemble(); 0168 0169 sJob->setContent(content); 0170 sJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0171 sJob->setSigningKeys(keys); 0172 0173 VERIFYEXEC(sJob); 0174 0175 KMime::Content *result = sJob->content(); 0176 result->assemble(); 0177 0178 KMime::Content *firstChild = MessageCore::NodeHelper::firstChild(result); 0179 QCOMPARE(result->contents().count(), 2); 0180 QCOMPARE(firstChild->contents().count(), 2); 0181 QCOMPARE(firstChild->body(), QByteArray()); 0182 QCOMPARE(firstChild->contentType()->mimeType(), QByteArrayLiteral("multipart/mixed")); 0183 QCOMPARE(firstChild->contents()[0]->body(), data.toUtf8()); 0184 QCOMPARE(firstChild->contents()[1]->body(), attachmentData); 0185 0186 ComposerTestUtil::verify(true, false, result, data.toUtf8(), Kleo::OpenPGPMIMEFormat, KMime::Headers::CE7Bit); 0187 delete result; 0188 } 0189 0190 void SignJobTest::checkSignJob(SignJob *sJob) 0191 { 0192 VERIFYEXEC(sJob); 0193 0194 KMime::Content *result = sJob->content(); 0195 Q_ASSERT(result); 0196 result->assemble(); 0197 0198 ComposerTestUtil::verifySignature(result, 0199 QString::fromLocal8Bit("one flew over the cuckoo's nest").toUtf8(), 0200 Kleo::OpenPGPMIMEFormat, 0201 KMime::Headers::CE7Bit); 0202 0203 delete result; 0204 } 0205 0206 void SignJobTest::testProtectedHeaders_data() 0207 { 0208 QTest::addColumn<bool>("protectedHeaders"); 0209 QTest::addColumn<QString>("referenceFile"); 0210 0211 QTest::newRow("simple-non-obvoscate") << true << QStringLiteral("protected_headers-non-obvoscate.mbox"); 0212 QTest::newRow("non-protected_headers") << false << QStringLiteral("non-protected_headers.mbox"); 0213 } 0214 0215 void SignJobTest::testProtectedHeaders() 0216 { 0217 QFETCH(bool, protectedHeaders); 0218 QFETCH(QString, referenceFile); 0219 0220 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0221 0222 Composer composer; 0223 auto sJob = new SignJob(&composer); 0224 0225 QVERIFY(sJob); 0226 0227 const QByteArray data(QString::fromLocal8Bit("one flew over the cuckoo's nest").toUtf8()); 0228 const QString subject(QStringLiteral("asdfghjklö")); 0229 0230 auto content = new KMime::Content; 0231 content->contentType(true)->setMimeType("text/plain"); 0232 content->setBody(data); 0233 0234 KMime::Message skeletonMessage; 0235 skeletonMessage.contentType(true)->setMimeType("foo/bla"); 0236 skeletonMessage.to(true)->from7BitString("to@test.de, to2@test.de"); 0237 skeletonMessage.cc(true)->from7BitString("cc@test.de, cc2@test.de"); 0238 skeletonMessage.bcc(true)->from7BitString("bcc@test.de, bcc2@test.de"); 0239 skeletonMessage.subject(true)->fromUnicodeString(subject, "utf-8"); 0240 0241 sJob->setContent(content); 0242 sJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0243 sJob->setSigningKeys(keys); 0244 sJob->setSkeletonMessage(&skeletonMessage); 0245 sJob->setProtectedHeaders(protectedHeaders); 0246 0247 VERIFYEXEC(sJob); 0248 0249 QCOMPARE(skeletonMessage.subject()->asUnicodeString(), subject); 0250 0251 KMime::Content *result = sJob->content(); 0252 result->assemble(); 0253 0254 Test::compareFile(result->contents().at(0), QStringLiteral(MAIL_DATA_DIR "/") + referenceFile); 0255 } 0256 0257 void SignJobTest::testProtectedHeadersOverwrite() 0258 { 0259 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0260 const auto referenceFile = QStringLiteral("protected_headers-non-obvoscate.mbox"); 0261 0262 Composer composer; 0263 auto sJob = new SignJob(&composer); 0264 0265 QVERIFY(sJob); 0266 0267 const QByteArray data(QString::fromLocal8Bit("one flew over the cuckoo's nest").toUtf8()); 0268 const QString subject(QStringLiteral("asdfghjklö")); 0269 0270 auto content = new KMime::Content; 0271 content->contentType(true)->setMimeType("text/plain"); 0272 content->setBody(data); 0273 0274 KMime::Message skeletonMessage; 0275 skeletonMessage.contentType(true)->setMimeType("foo/bla"); 0276 skeletonMessage.to(true)->from7BitString("to@test.de, to2@test.de"); 0277 skeletonMessage.cc(true)->from7BitString("cc@test.de, cc2@test.de"); 0278 skeletonMessage.bcc(true)->from7BitString("bcc@test.de, bcc2@test.de"); 0279 skeletonMessage.subject(true)->fromUnicodeString(subject, "utf-8"); 0280 0281 sJob->setContent(content); 0282 sJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0283 sJob->setSigningKeys(keys); 0284 sJob->setSkeletonMessage(&skeletonMessage); 0285 sJob->setProtectedHeaders(true); 0286 0287 VERIFYEXEC(sJob); 0288 0289 QCOMPARE(skeletonMessage.subject()->asUnicodeString(), subject); 0290 skeletonMessage.to()->from7BitString("overwrite@example.org"); 0291 skeletonMessage.cc()->from7BitString("cc_overwrite@example.org"); 0292 skeletonMessage.bcc()->from7BitString("bcc_overwrite@example.org"); 0293 skeletonMessage.subject()->fromUnicodeString(subject + QStringLiteral("_owerwrite"), "utf-8"); 0294 0295 KMime::Content *result = sJob->content(); 0296 result->assemble(); 0297 0298 Test::compareFile(result->contents().at(0), QStringLiteral(MAIL_DATA_DIR "/") + referenceFile); 0299 } 0300 0301 void SignJobTest::testProtectedHeadersSkipLong() 0302 { 0303 const std::vector<GpgME::Key> &keys = Test::getKeys(); 0304 const auto referenceFile = QStringLiteral("protected_headers-non-obvoscate.mbox"); 0305 0306 Composer composer; 0307 auto sJob = new SignJob(&composer); 0308 0309 QVERIFY(sJob); 0310 0311 const QByteArray data(QString::fromLocal8Bit("one flew over the cuckoo's nest").toUtf8()); 0312 const QString subject(QStringLiteral("asdfghjklö")); 0313 0314 auto content = new KMime::Content; 0315 content->contentType(true)->setMimeType("text/plain"); 0316 content->setBody(data); 0317 0318 KMime::Message skeletonMessage; 0319 auto face = new KMime::Headers::Generic("Face"); 0320 face->from7BitString( 0321 "iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAElBMVEX9/ftIS5IsNImXjKgc\n" 0322 " I3Dh29sdnA7JAAAB60lEQVR4nI2US5ajMAxFXeF4HtlhXlZ7AdCCBWCcORTx/rfSkgyEyqg14uii\n" 0323 " pw8SpnzaRmrm/8yWD0dZqn80G5WlUOVEnsCPNKp6D2w98JsWHcJuiOiCPnXGNPDIU/U7BuKPGe7G\n" 0324 " fAW/rNPhl+A4bqkC6IZDiwOwXb0CnKBtpjMJhgZoB96bXl5Gtftfr+AHJ4LlhRm8VOvmJlCvwM3U\n" 0325 " d41f9maX1dOADG4cQe1lDD3RAzVH+DXMhhUTfjOIkWexvAHRkCSiyZmuYBWlGpGfV0CihDyrW8yh\n" 0326 " bOYDaFU5d+8AU8YXqtQNEz5P92KskWFq54h/ONWs4OtpbDoiGCzmNatc05rmBE6AtQpKsdsOfoLD\n" 0327 " UBgci6JAqgqI8bI2F+AwjleAew6OwFYSWA8CVgFdrQqfCnIW8MKAdexscwWTbOML8Q0myV4y8218\n" 0328 " 7FIKomwvf5bO0ph+gZFbZCD7q2DZAc7nyQxv4FSLTcHjkLo5KS/Ox41lPHIExyEZRb4lP5zgR7c8\n" 0329 " BV822d6UTiAjiQnGVfyyIZfpYmZg+gpiTvHsg4EzHOIVsMC9lsvP0He2B+qHmHOO6fsAAehpqSc+\n" 0330 " yBNIF1wUgOXzCJDVBIB0Icfd2vKAN2jAubRfOvt3INsO+3XvdgGBgAH/OepfoIJ/RyuNKjhmbCAA\n" 0331 " AAAASUVORK5CYII="); 0332 skeletonMessage.contentType(true)->setMimeType("foo/bla"); 0333 skeletonMessage.to(true)->from7BitString("to@test.de, to2@test.de"); 0334 skeletonMessage.cc(true)->from7BitString("cc@test.de, cc2@test.de"); 0335 skeletonMessage.bcc(true)->from7BitString("bcc@test.de, bcc2@test.de"); 0336 skeletonMessage.appendHeader(face); 0337 skeletonMessage.subject(true)->fromUnicodeString(subject, "utf-8"); 0338 0339 sJob->setContent(content); 0340 sJob->setCryptoMessageFormat(Kleo::OpenPGPMIMEFormat); 0341 sJob->setSigningKeys(keys); 0342 sJob->setSkeletonMessage(&skeletonMessage); 0343 sJob->setProtectedHeaders(true); 0344 0345 VERIFYEXEC(sJob); 0346 0347 KMime::Content *result = sJob->content(); 0348 result->assemble(); 0349 0350 Test::compareFile(result->contents().at(0), QStringLiteral(MAIL_DATA_DIR "/") + referenceFile); 0351 } 0352 0353 #include "moc_signjobtest.cpp"