LCOV - code coverage report
Current view: top level - lang/qt/tests - t-encrypt.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 136 143 95.1 %
Date: 2018-11-14 16:53:58 Functions: 19 29 65.5 %

          Line data    Source code
       1             : /* t-encrypt.cpp
       2             : 
       3             :     This file is part of qgpgme, the Qt API binding for gpgme
       4             :     Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
       5             :     Software engineering by Intevation GmbH
       6             : 
       7             :     QGpgME is free software; you can redistribute it and/or
       8             :     modify it under the terms of the GNU General Public License as
       9             :     published by the Free Software Foundation; either version 2 of the
      10             :     License, or (at your option) any later version.
      11             : 
      12             :     QGpgME is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :     General Public License for more details.
      16             : 
      17             :     You should have received a copy of the GNU General Public License
      18             :     along with this program; if not, write to the Free Software
      19             :     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      20             : 
      21             :     In addition, as a special exception, the copyright holders give
      22             :     permission to link the code of this program with any edition of
      23             :     the Qt library by Trolltech AS, Norway (or with modified versions
      24             :     of Qt that use the same license as Qt), and distribute linked
      25             :     combinations including the two.  You must obey the GNU General
      26             :     Public License in all respects for all of the code used other than
      27             :     Qt.  If you modify this file, you may extend this exception to
      28             :     your version of the file, but you are not obligated to do so.  If
      29             :     you do not wish to do so, delete this exception statement from
      30             :     your version.
      31             : */
      32             : #ifdef HAVE_CONFIG_H
      33             :  #include "config.h"
      34             : #endif
      35             : 
      36             : #include <QDebug>
      37             : #include <QTest>
      38             : #include <QTemporaryDir>
      39             : #include <QSignalSpy>
      40             : #include <QBuffer>
      41             : #include "keylistjob.h"
      42             : #include "encryptjob.h"
      43             : #include "signencryptjob.h"
      44             : #include "signingresult.h"
      45             : #include "encryptjob.h"
      46             : #include "encryptionresult.h"
      47             : #include "decryptionresult.h"
      48             : #include "decryptjob.h"
      49             : #include "qgpgmebackend.h"
      50             : #include "keylistresult.h"
      51             : #include "engineinfo.h"
      52             : #include "verifyopaquejob.h"
      53             : #include "t-support.h"
      54             : 
      55             : #define PROGRESS_TEST_SIZE 1 * 1024 * 1024
      56             : 
      57             : using namespace QGpgME;
      58             : using namespace GpgME;
      59             : 
      60           4 : static bool decryptSupported()
      61             : {
      62             :     /* With GnuPG 2.0.x (at least 2.0.26 by default on jessie)
      63             :      * the passphrase_cb does not work. So the test popped up
      64             :      * a pinentry. So tests requiring decryption don't work. */
      65           4 :     static auto version = GpgME::engineInfo(GpgME::GpgEngine).engineVersion();
      66           4 :     if (version < "2.0.0") {
      67             :         /* With 1.4 it just works */
      68           0 :         return true;
      69             :     }
      70           4 :     if (version < "2.1.0") {
      71             :         /* With 2.1 it works with loopback mode */
      72           0 :         return false;
      73             :     }
      74           4 :     return true;
      75             : }
      76             : 
      77           2 : class EncryptionTest : public QGpgMETest
      78             : {
      79             :     Q_OBJECT
      80             : 
      81             : Q_SIGNALS:
      82             :     void asyncDone();
      83             : 
      84             : private Q_SLOTS:
      85             : 
      86           1 :     void testSimpleEncryptDecrypt()
      87             :     {
      88           1 :         auto listjob = openpgp()->keyListJob(false, false, false);
      89           2 :         std::vector<Key> keys;
      90           3 :         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
      91           3 :                                           false, keys);
      92           1 :         QVERIFY(!keylistresult.error());
      93           1 :         QVERIFY(keys.size() == 1);
      94           1 :         delete listjob;
      95             : 
      96           1 :         auto job = openpgp()->encryptJob(/*ASCII Armor */true, /* Textmode */ true);
      97           1 :         QVERIFY(job);
      98           2 :         QByteArray cipherText;
      99           3 :         auto result = job->exec(keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
     100           1 :         delete job;
     101           1 :         QVERIFY(!result.error());
     102           2 :         const auto cipherString = QString::fromUtf8(cipherText);
     103           1 :         QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
     104             : 
     105             :         /* Now decrypt */
     106           1 :         if (!decryptSupported()) {
     107           0 :             return;
     108             :         }
     109           1 :         auto decJob = openpgp()->decryptJob();
     110           1 :         auto ctx = Job::context(decJob);
     111           2 :         TestPassphraseProvider provider;
     112           1 :         ctx->setPassphraseProvider(&provider);
     113           1 :         ctx->setPinentryMode(Context::PinentryLoopback);
     114           2 :         QByteArray plainText;
     115           2 :         auto decResult = decJob->exec(cipherText, plainText);
     116           1 :         QVERIFY(!decResult.error());
     117           2 :         QVERIFY(QString::fromUtf8(plainText) == QStringLiteral("Hello World"));
     118           1 :         delete decJob;
     119             :     }
     120             : 
     121           1 :     void testProgress()
     122             :     {
     123           1 :         if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.15") {
     124             :             // We can only test the progress with 2.1.15 as this started to
     125             :             // have total progress for memory callbacks
     126           0 :             return;
     127             :         }
     128           1 :         auto listjob = openpgp()->keyListJob(false, false, false);
     129           2 :         std::vector<Key> keys;
     130           3 :         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
     131           3 :                                           false, keys);
     132           1 :         QVERIFY(!keylistresult.error());
     133           1 :         QVERIFY(keys.size() == 1);
     134           1 :         delete listjob;
     135             : 
     136           1 :         auto job = openpgp()->encryptJob(/*ASCII Armor */false, /* Textmode */ false);
     137           1 :         QVERIFY(job);
     138           2 :         QByteArray plainBa;
     139           1 :         plainBa.fill('X', PROGRESS_TEST_SIZE);
     140           2 :         QByteArray cipherText;
     141             : 
     142           1 :         bool initSeen = false;
     143           1 :         bool finishSeen = false;
     144           4 :         connect(job, &Job::progress, this, [this, &initSeen, &finishSeen] (const QString&, int current, int total) {
     145             :                 // We only check for progress 0 and max progress as the other progress
     146             :                 // lines depend on the system speed and are as such unreliable to test.
     147           2 :                 QVERIFY(total == PROGRESS_TEST_SIZE);
     148           2 :                 if (current == 0) {
     149           1 :                     initSeen = true;
     150             :                 }
     151           2 :                 if (current == total) {
     152           1 :                     finishSeen = true;
     153             :                 }
     154           2 :                 QVERIFY(current >= 0 && current <= total);
     155           1 :             });
     156             :         connect(job, &EncryptJob::result, this, [this, &initSeen, &finishSeen] (const GpgME::EncryptionResult &,
     157             :                                                                                 const QByteArray &,
     158             :                                                                                 const QString,
     159           3 :                                                                                 const GpgME::Error) {
     160           1 :                 QVERIFY(initSeen);
     161           1 :                 QVERIFY(finishSeen);
     162           1 :                 Q_EMIT asyncDone();
     163           1 :             });
     164             : 
     165           2 :         auto inptr  = std::shared_ptr<QIODevice>(new QBuffer(&plainBa));
     166           1 :         inptr->open(QIODevice::ReadOnly);
     167           2 :         auto outptr = std::shared_ptr<QIODevice>(new QBuffer(&cipherText));
     168           1 :         outptr->open(QIODevice::WriteOnly);
     169             : 
     170           1 :         job->start(keys, inptr, outptr, Context::AlwaysTrust);
     171           2 :         QSignalSpy spy (this, SIGNAL(asyncDone()));
     172           1 :         QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT));
     173             :     }
     174             : 
     175           1 :     void testSymmetricEncryptDecrypt()
     176             :     {
     177           1 :         if (!decryptSupported()) {
     178           0 :             return;
     179             :         }
     180           1 :         auto job = openpgp()->encryptJob();
     181           1 :         auto ctx = Job::context(job);
     182           2 :         TestPassphraseProvider provider;
     183           1 :         ctx->setPassphraseProvider(&provider);
     184           1 :         ctx->setPinentryMode(Context::PinentryLoopback);
     185           1 :         ctx->setArmor(true);
     186           1 :         ctx->setTextMode(true);
     187           2 :         QByteArray cipherText;
     188           3 :         auto result = job->exec(std::vector<Key>(), QStringLiteral("Hello symmetric World").toUtf8(), Context::AlwaysTrust, cipherText);
     189           1 :         delete job;
     190           1 :         QVERIFY(!result.error());
     191           2 :         const auto cipherString = QString::fromUtf8(cipherText);
     192           1 :         QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
     193             : 
     194           1 :         killAgent(mDir.path());
     195             : 
     196           1 :         auto decJob = openpgp()->decryptJob();
     197           1 :         auto ctx2 = Job::context(decJob);
     198           1 :         ctx2->setPassphraseProvider(&provider);
     199           1 :         ctx2->setPinentryMode(Context::PinentryLoopback);
     200           2 :         QByteArray plainText;
     201           2 :         auto decResult = decJob->exec(cipherText, plainText);
     202           1 :         QVERIFY(!result.error());
     203           2 :         QVERIFY(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
     204           1 :         delete decJob;
     205             :     }
     206             : 
     207           1 :     void testEncryptDecryptNowrap()
     208             :     {
     209             :         /* Now decrypt */
     210           1 :         if (!decryptSupported()) {
     211           0 :             return;
     212             :         }
     213           1 :         auto listjob = openpgp()->keyListJob(false, false, false);
     214           2 :         std::vector<Key> keys;
     215           3 :         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
     216           3 :                                           false, keys);
     217           1 :         QVERIFY(!keylistresult.error());
     218           1 :         QVERIFY(keys.size() == 1);
     219           1 :         delete listjob;
     220             : 
     221           1 :         auto job = openpgp()->signEncryptJob(/*ASCII Armor */true, /* Textmode */ true);
     222             : 
     223           1 :         auto encSignCtx = Job::context(job);
     224           2 :         TestPassphraseProvider provider1;
     225           1 :         encSignCtx->setPassphraseProvider(&provider1);
     226           1 :         encSignCtx->setPinentryMode(Context::PinentryLoopback);
     227             : 
     228           1 :         QVERIFY(job);
     229           2 :         QByteArray cipherText;
     230           3 :         auto result = job->exec(keys, keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
     231           1 :         delete job;
     232           1 :         QVERIFY(!result.first.error());
     233           1 :         QVERIFY(!result.second.error());
     234           2 :         const auto cipherString = QString::fromUtf8(cipherText);
     235           1 :         QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
     236             : 
     237             :         /* Now decrypt */
     238           1 :         if (!decryptSupported()) {
     239           0 :             return;
     240             :         }
     241             : 
     242           1 :         auto decJob = openpgp()->decryptJob();
     243           1 :         auto ctx = Job::context(decJob);
     244           2 :         TestPassphraseProvider provider;
     245           1 :         ctx->setPassphraseProvider(&provider);
     246           1 :         ctx->setPinentryMode(Context::PinentryLoopback);
     247           1 :         ctx->setDecryptionFlags(Context::DecryptUnwrap);
     248             : 
     249           2 :         QByteArray plainText;
     250           2 :         auto decResult = decJob->exec(cipherText, plainText);
     251             : 
     252           1 :         QVERIFY(!decResult.error());
     253             : 
     254           1 :         delete decJob;
     255             : 
     256             :         // Now verify the unwrapeped data.
     257           1 :         auto verifyJob = openpgp()->verifyOpaqueJob(true);
     258           2 :         QByteArray verified;
     259             : 
     260           2 :         auto verResult = verifyJob->exec(plainText, verified);
     261           1 :         QVERIFY(!verResult.error());
     262           1 :         delete verifyJob;
     263             : 
     264           1 :         QVERIFY(verResult.numSignatures() == 1);
     265           2 :         auto sig = verResult.signatures()[0];
     266             : 
     267           2 :         QVERIFY(verified == QStringLiteral("Hello World"));
     268             :     }
     269             : 
     270             : private:
     271             :     /* Loopback and passphrase provider don't work for mixed encryption.
     272             :      * So this test is disabled until gnupg(?) is fixed for this. */
     273             :     void testMixedEncryptDecrypt()
     274             :     {
     275             :         if (!decryptSupported()) {
     276             :             return;
     277             :         }
     278             :         auto listjob = openpgp()->keyListJob(false, false, false);
     279             :         std::vector<Key> keys;
     280             :         auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
     281             :                                           false, keys);
     282             :         QVERIFY(!keylistresult.error());
     283             :         QVERIFY(keys.size() == 1);
     284             :         delete listjob;
     285             : 
     286             :         auto job = openpgp()->encryptJob();
     287             :         auto ctx = Job::context(job);
     288             :         ctx->setPassphraseProvider(new TestPassphraseProvider);
     289             :         ctx->setPinentryMode(Context::PinentryLoopback);
     290             :         ctx->setArmor(true);
     291             :         ctx->setTextMode(true);
     292             :         QByteArray cipherText;
     293             :         printf("Before exec, flags: %x\n", Context::Symmetric | Context::AlwaysTrust);
     294             :         auto result = job->exec(keys, QStringLiteral("Hello symmetric World").toUtf8(),
     295             :                                 static_cast<Context::EncryptionFlags>(Context::Symmetric | Context::AlwaysTrust),
     296             :                                 cipherText);
     297             :         printf("After exec\n");
     298             :         delete job;
     299             :         QVERIFY(!result.error());
     300             :         printf("Cipher:\n%s\n", cipherText.constData());
     301             :         const auto cipherString = QString::fromUtf8(cipherText);
     302             :         QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
     303             : 
     304             :         killAgent(mDir.path());
     305             : 
     306             :         /* Now create a new homedir which with we test symmetric decrypt. */
     307             :         QTemporaryDir tmp;
     308             :         qputenv("GNUPGHOME", tmp.path().toUtf8());
     309             :         QFile agentConf(tmp.path() + QStringLiteral("/gpg-agent.conf"));
     310             :         QVERIFY(agentConf.open(QIODevice::WriteOnly));
     311             :         agentConf.write("allow-loopback-pinentry");
     312             :         agentConf.close();
     313             : 
     314             :         auto decJob = openpgp()->decryptJob();
     315             :         auto ctx2 = Job::context(decJob);
     316             :         ctx2->setPassphraseProvider(new TestPassphraseProvider);
     317             :         ctx2->setPinentryMode(Context::PinentryLoopback);
     318             :         ctx2->setTextMode(true);
     319             :         QByteArray plainText;
     320             :         auto decResult = decJob->exec(cipherText, plainText);
     321             :         QVERIFY(!decResult.error());
     322             :         qDebug() << "Plain: " << plainText;
     323             :         QVERIFY(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
     324             :         delete decJob;
     325             : 
     326             :         killAgent(tmp.path());
     327             :         qputenv("GNUPGHOME", mDir.path().toUtf8());
     328             :     }
     329             : 
     330             : public Q_SLOT:
     331             : 
     332             :     void initTestCase()
     333             :     {
     334             :         QGpgMETest::initTestCase();
     335             :         const QString gpgHome = qgetenv("GNUPGHOME");
     336             :         qputenv("GNUPGHOME", mDir.path().toUtf8());
     337             :         QVERIFY(mDir.isValid());
     338             :         QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
     339             :         QVERIFY(agentConf.open(QIODevice::WriteOnly));
     340             :         agentConf.write("allow-loopback-pinentry");
     341             :         agentConf.close();
     342             :         QVERIFY(copyKeyrings(gpgHome, mDir.path()));
     343             :     }
     344             : 
     345             : private:
     346             :     QTemporaryDir mDir;
     347             : };
     348             : 
     349           1 : QTEST_MAIN(EncryptionTest)
     350             : 
     351             : #include "t-encrypt.moc"

Generated by: LCOV version 1.13