Blame lang/qt/tests/t-encrypt.cpp

Packit Service 672cf4
/* t-encrypt.cpp
Packit Service 672cf4
Packit Service 672cf4
    This file is part of qgpgme, the Qt API binding for gpgme
Packit Service 672cf4
    Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
Packit Service 672cf4
    Software engineering by Intevation GmbH
Packit Service 672cf4
Packit Service 672cf4
    QGpgME is free software; you can redistribute it and/or
Packit Service 672cf4
    modify it under the terms of the GNU General Public License as
Packit Service 672cf4
    published by the Free Software Foundation; either version 2 of the
Packit Service 672cf4
    License, or (at your option) any later version.
Packit Service 672cf4
Packit Service 672cf4
    QGpgME is distributed in the hope that it will be useful,
Packit Service 672cf4
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 672cf4
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 672cf4
    General Public License for more details.
Packit Service 672cf4
Packit Service 672cf4
    You should have received a copy of the GNU General Public License
Packit Service 672cf4
    along with this program; if not, write to the Free Software
Packit Service 672cf4
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit Service 672cf4
Packit Service 672cf4
    In addition, as a special exception, the copyright holders give
Packit Service 672cf4
    permission to link the code of this program with any edition of
Packit Service 672cf4
    the Qt library by Trolltech AS, Norway (or with modified versions
Packit Service 672cf4
    of Qt that use the same license as Qt), and distribute linked
Packit Service 672cf4
    combinations including the two.  You must obey the GNU General
Packit Service 672cf4
    Public License in all respects for all of the code used other than
Packit Service 672cf4
    Qt.  If you modify this file, you may extend this exception to
Packit Service 672cf4
    your version of the file, but you are not obligated to do so.  If
Packit Service 672cf4
    you do not wish to do so, delete this exception statement from
Packit Service 672cf4
    your version.
Packit Service 672cf4
*/
Packit Service 672cf4
#ifdef HAVE_CONFIG_H
Packit Service 672cf4
 #include "config.h"
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include <QDebug>
Packit Service 672cf4
#include <QTest>
Packit Service 672cf4
#include <QTemporaryDir>
Packit Service 672cf4
#include <QSignalSpy>
Packit Service 672cf4
#include <QBuffer>
Packit Service 672cf4
#include "keylistjob.h"
Packit Service 672cf4
#include "encryptjob.h"
Packit Service 672cf4
#include "signencryptjob.h"
Packit Service 672cf4
#include "signingresult.h"
Packit Service 672cf4
#include "encryptjob.h"
Packit Service 672cf4
#include "encryptionresult.h"
Packit Service 672cf4
#include "decryptionresult.h"
Packit Service 672cf4
#include "decryptjob.h"
Packit Service 672cf4
#include "qgpgmebackend.h"
Packit Service 672cf4
#include "keylistresult.h"
Packit Service 672cf4
#include "engineinfo.h"
Packit Service 672cf4
#include "verifyopaquejob.h"
Packit Service 672cf4
#include "t-support.h"
Packit Service 672cf4
Packit Service 672cf4
#define PROGRESS_TEST_SIZE 1 * 1024 * 1024
Packit Service 672cf4
Packit Service 672cf4
using namespace QGpgME;
Packit Service 672cf4
using namespace GpgME;
Packit Service 672cf4
Packit Service 672cf4
static bool decryptSupported()
Packit Service 672cf4
{
Packit Service 672cf4
    /* With GnuPG 2.0.x (at least 2.0.26 by default on jessie)
Packit Service 672cf4
     * the passphrase_cb does not work. So the test popped up
Packit Service 672cf4
     * a pinentry. So tests requiring decryption don't work. */
Packit Service 672cf4
    static auto version = GpgME::engineInfo(GpgME::GpgEngine).engineVersion();
Packit Service 672cf4
    if (version < "2.0.0") {
Packit Service 672cf4
        /* With 1.4 it just works */
Packit Service 672cf4
        return true;
Packit Service 672cf4
    }
Packit Service 672cf4
    if (version < "2.1.0") {
Packit Service 672cf4
        /* With 2.1 it works with loopback mode */
Packit Service 672cf4
        return false;
Packit Service 672cf4
    }
Packit Service 672cf4
    return true;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
class EncryptionTest : public QGpgMETest
Packit Service 672cf4
{
Packit Service 672cf4
    Q_OBJECT
Packit Service 672cf4
Packit Service 672cf4
Q_SIGNALS:
Packit Service 672cf4
    void asyncDone();
Packit Service 672cf4
Packit Service 672cf4
private Q_SLOTS:
Packit Service 672cf4
Packit Service 672cf4
    void testSimpleEncryptDecrypt()
Packit Service 672cf4
    {
Packit Service 672cf4
        auto listjob = openpgp()->keyListJob(false, false, false);
Packit Service 672cf4
        std::vector<Key> keys;
Packit Service 672cf4
        auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
Packit Service 672cf4
                                          false, keys);
Packit Service 672cf4
        QVERIFY(!keylistresult.error());
Packit Service 672cf4
        QVERIFY(keys.size() == 1);
Packit Service 672cf4
        delete listjob;
Packit Service 672cf4
Packit Service 672cf4
        auto job = openpgp()->encryptJob(/*ASCII Armor */true, /* Textmode */ true);
Packit Service 672cf4
        QVERIFY(job);
Packit Service 672cf4
        QByteArray cipherText;
Packit Service 672cf4
        auto result = job->exec(keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
Packit Service 672cf4
        delete job;
Packit Service 672cf4
        QVERIFY(!result.error());
Packit Service 672cf4
        const auto cipherString = QString::fromUtf8(cipherText);
Packit Service 672cf4
        QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
Packit Service 672cf4
Packit Service 672cf4
        /* Now decrypt */
Packit Service 672cf4
        if (!decryptSupported()) {
Packit Service 672cf4
            return;
Packit Service 672cf4
        }
Packit Service 672cf4
        auto decJob = openpgp()->decryptJob();
Packit Service 672cf4
        auto ctx = Job::context(decJob);
Packit Service 672cf4
        TestPassphraseProvider provider;
Packit Service 672cf4
        ctx->setPassphraseProvider(&provider);
Packit Service 672cf4
        ctx->setPinentryMode(Context::PinentryLoopback);
Packit Service 672cf4
        QByteArray plainText;
Packit Service 672cf4
        auto decResult = decJob->exec(cipherText, plainText);
Packit Service 672cf4
        QVERIFY(!decResult.error());
Packit Service 672cf4
        QVERIFY(QString::fromUtf8(plainText) == QStringLiteral("Hello World"));
Packit Service 672cf4
        delete decJob;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    void testProgress()
Packit Service 672cf4
    {
Packit Service 672cf4
        if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.15") {
Packit Service 672cf4
            // We can only test the progress with 2.1.15 as this started to
Packit Service 672cf4
            // have total progress for memory callbacks
Packit Service 672cf4
            return;
Packit Service 672cf4
        }
Packit Service 672cf4
        auto listjob = openpgp()->keyListJob(false, false, false);
Packit Service 672cf4
        std::vector<Key> keys;
Packit Service 672cf4
        auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
Packit Service 672cf4
                                          false, keys);
Packit Service 672cf4
        QVERIFY(!keylistresult.error());
Packit Service 672cf4
        QVERIFY(keys.size() == 1);
Packit Service 672cf4
        delete listjob;
Packit Service 672cf4
Packit Service 672cf4
        auto job = openpgp()->encryptJob(/*ASCII Armor */false, /* Textmode */ false);
Packit Service 672cf4
        QVERIFY(job);
Packit Service 672cf4
        QByteArray plainBa;
Packit Service 672cf4
        plainBa.fill('X', PROGRESS_TEST_SIZE);
Packit Service 672cf4
        QByteArray cipherText;
Packit Service 672cf4
Packit Service 672cf4
        bool initSeen = false;
Packit Service 672cf4
        bool finishSeen = false;
Packit Service 672cf4
        connect(job, &Job::progress, this, [this, &initSeen, &finishSeen] (const QString&, int current, int total) {
Packit Service 672cf4
                // We only check for progress 0 and max progress as the other progress
Packit Service 672cf4
                // lines depend on the system speed and are as such unreliable to test.
Packit Service 672cf4
                QVERIFY(total == PROGRESS_TEST_SIZE);
Packit Service 672cf4
                if (current == 0) {
Packit Service 672cf4
                    initSeen = true;
Packit Service 672cf4
                }
Packit Service 672cf4
                if (current == total) {
Packit Service 672cf4
                    finishSeen = true;
Packit Service 672cf4
                }
Packit Service 672cf4
                QVERIFY(current >= 0 && current <= total);
Packit Service 672cf4
            });
Packit Service 672cf4
        connect(job, &EncryptJob::result, this, [this, &initSeen, &finishSeen] (const GpgME::EncryptionResult &,
Packit Service 672cf4
                                                                                const QByteArray &,
Packit Service 672cf4
                                                                                const QString,
Packit Service 672cf4
                                                                                const GpgME::Error) {
Packit Service 672cf4
                QVERIFY(initSeen);
Packit Service 672cf4
                QVERIFY(finishSeen);
Packit Service 672cf4
                Q_EMIT asyncDone();
Packit Service 672cf4
            });
Packit Service 672cf4
Packit Service 672cf4
        auto inptr  = std::shared_ptr<QIODevice>(new QBuffer(&plainBa));
Packit Service 672cf4
        inptr->open(QIODevice::ReadOnly);
Packit Service 672cf4
        auto outptr = std::shared_ptr<QIODevice>(new QBuffer(&cipherText));
Packit Service 672cf4
        outptr->open(QIODevice::WriteOnly);
Packit Service 672cf4
Packit Service 672cf4
        job->start(keys, inptr, outptr, Context::AlwaysTrust);
Packit Service 672cf4
        QSignalSpy spy (this, SIGNAL(asyncDone()));
Packit Service 672cf4
        QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    void testSymmetricEncryptDecrypt()
Packit Service 672cf4
    {
Packit Service 672cf4
        if (!decryptSupported()) {
Packit Service 672cf4
            return;
Packit Service 672cf4
        }
Packit Service 672cf4
        auto job = openpgp()->encryptJob();
Packit Service 672cf4
        auto ctx = Job::context(job);
Packit Service 672cf4
        TestPassphraseProvider provider;
Packit Service 672cf4
        ctx->setPassphraseProvider(&provider);
Packit Service 672cf4
        ctx->setPinentryMode(Context::PinentryLoopback);
Packit Service 672cf4
        ctx->setArmor(true);
Packit Service 672cf4
        ctx->setTextMode(true);
Packit Service 672cf4
        QByteArray cipherText;
Packit Service 672cf4
        auto result = job->exec(std::vector<Key>(), QStringLiteral("Hello symmetric World").toUtf8(), Context::AlwaysTrust, cipherText);
Packit Service 672cf4
        delete job;
Packit Service 672cf4
        QVERIFY(!result.error());
Packit Service 672cf4
        const auto cipherString = QString::fromUtf8(cipherText);
Packit Service 672cf4
        QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
Packit Service 672cf4
Packit Service 672cf4
        killAgent(mDir.path());
Packit Service 672cf4
Packit Service 672cf4
        auto decJob = openpgp()->decryptJob();
Packit Service 672cf4
        auto ctx2 = Job::context(decJob);
Packit Service 672cf4
        ctx2->setPassphraseProvider(&provider);
Packit Service 672cf4
        ctx2->setPinentryMode(Context::PinentryLoopback);
Packit Service 672cf4
        QByteArray plainText;
Packit Service 672cf4
        auto decResult = decJob->exec(cipherText, plainText);
Packit Service 672cf4
        QVERIFY(!result.error());
Packit Service 672cf4
        QVERIFY(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
Packit Service 672cf4
        delete decJob;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    void testEncryptDecryptNowrap()
Packit Service 672cf4
    {
Packit Service 672cf4
        /* Now decrypt */
Packit Service 672cf4
        if (!decryptSupported()) {
Packit Service 672cf4
            return;
Packit Service 672cf4
        }
Packit Service 672cf4
        auto listjob = openpgp()->keyListJob(false, false, false);
Packit Service 672cf4
        std::vector<Key> keys;
Packit Service 672cf4
        auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
Packit Service 672cf4
                                          false, keys);
Packit Service 672cf4
        QVERIFY(!keylistresult.error());
Packit Service 672cf4
        QVERIFY(keys.size() == 1);
Packit Service 672cf4
        delete listjob;
Packit Service 672cf4
Packit Service 672cf4
        auto job = openpgp()->signEncryptJob(/*ASCII Armor */true, /* Textmode */ true);
Packit Service 672cf4
Packit Service 672cf4
        auto encSignCtx = Job::context(job);
Packit Service 672cf4
        TestPassphraseProvider provider1;
Packit Service 672cf4
        encSignCtx->setPassphraseProvider(&provider1);
Packit Service 672cf4
        encSignCtx->setPinentryMode(Context::PinentryLoopback);
Packit Service 672cf4
Packit Service 672cf4
        QVERIFY(job);
Packit Service 672cf4
        QByteArray cipherText;
Packit Service 672cf4
        auto result = job->exec(keys, keys, QStringLiteral("Hello World").toUtf8(), Context::AlwaysTrust, cipherText);
Packit Service 672cf4
        delete job;
Packit Service 672cf4
        QVERIFY(!result.first.error());
Packit Service 672cf4
        QVERIFY(!result.second.error());
Packit Service 672cf4
        const auto cipherString = QString::fromUtf8(cipherText);
Packit Service 672cf4
        QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
Packit Service 672cf4
Packit Service 672cf4
        /* Now decrypt */
Packit Service 672cf4
        if (!decryptSupported()) {
Packit Service 672cf4
            return;
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
        auto decJob = openpgp()->decryptJob();
Packit Service 672cf4
        auto ctx = Job::context(decJob);
Packit Service 672cf4
        TestPassphraseProvider provider;
Packit Service 672cf4
        ctx->setPassphraseProvider(&provider);
Packit Service 672cf4
        ctx->setPinentryMode(Context::PinentryLoopback);
Packit Service 672cf4
        ctx->setDecryptionFlags(Context::DecryptUnwrap);
Packit Service 672cf4
Packit Service 672cf4
        QByteArray plainText;
Packit Service 672cf4
        auto decResult = decJob->exec(cipherText, plainText);
Packit Service 672cf4
Packit Service 672cf4
        QVERIFY(!decResult.error());
Packit Service 672cf4
Packit Service 672cf4
        delete decJob;
Packit Service 672cf4
Packit Service 672cf4
        // Now verify the unwrapeped data.
Packit Service 672cf4
        auto verifyJob = openpgp()->verifyOpaqueJob(true);
Packit Service 672cf4
        QByteArray verified;
Packit Service 672cf4
Packit Service 672cf4
        auto verResult = verifyJob->exec(plainText, verified);
Packit Service 672cf4
        QVERIFY(!verResult.error());
Packit Service 672cf4
        delete verifyJob;
Packit Service 672cf4
Packit Service 672cf4
        QVERIFY(verResult.numSignatures() == 1);
Packit Service 672cf4
        auto sig = verResult.signatures()[0];
Packit Service 672cf4
Packit Service 672cf4
        QVERIFY(verified == QStringLiteral("Hello World"));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
private:
Packit Service 672cf4
    /* Loopback and passphrase provider don't work for mixed encryption.
Packit Service 672cf4
     * So this test is disabled until gnupg(?) is fixed for this. */
Packit Service 672cf4
    void testMixedEncryptDecrypt()
Packit Service 672cf4
    {
Packit Service 672cf4
        if (!decryptSupported()) {
Packit Service 672cf4
            return;
Packit Service 672cf4
        }
Packit Service 672cf4
        auto listjob = openpgp()->keyListJob(false, false, false);
Packit Service 672cf4
        std::vector<Key> keys;
Packit Service 672cf4
        auto keylistresult = listjob->exec(QStringList() << QStringLiteral("alfa@example.net"),
Packit Service 672cf4
                                          false, keys);
Packit Service 672cf4
        QVERIFY(!keylistresult.error());
Packit Service 672cf4
        QVERIFY(keys.size() == 1);
Packit Service 672cf4
        delete listjob;
Packit Service 672cf4
Packit Service 672cf4
        auto job = openpgp()->encryptJob();
Packit Service 672cf4
        auto ctx = Job::context(job);
Packit Service 672cf4
        ctx->setPassphraseProvider(new TestPassphraseProvider);
Packit Service 672cf4
        ctx->setPinentryMode(Context::PinentryLoopback);
Packit Service 672cf4
        ctx->setArmor(true);
Packit Service 672cf4
        ctx->setTextMode(true);
Packit Service 672cf4
        QByteArray cipherText;
Packit Service 672cf4
        printf("Before exec, flags: %x\n", Context::Symmetric | Context::AlwaysTrust);
Packit Service 672cf4
        auto result = job->exec(keys, QStringLiteral("Hello symmetric World").toUtf8(),
Packit Service 672cf4
                                static_cast<Context::EncryptionFlags>(Context::Symmetric | Context::AlwaysTrust),
Packit Service 672cf4
                                cipherText);
Packit Service 672cf4
        printf("After exec\n");
Packit Service 672cf4
        delete job;
Packit Service 672cf4
        QVERIFY(!result.error());
Packit Service 672cf4
        printf("Cipher:\n%s\n", cipherText.constData());
Packit Service 672cf4
        const auto cipherString = QString::fromUtf8(cipherText);
Packit Service 672cf4
        QVERIFY(cipherString.startsWith("-----BEGIN PGP MESSAGE-----"));
Packit Service 672cf4
Packit Service 672cf4
        killAgent(mDir.path());
Packit Service 672cf4
Packit Service 6c01f9
        /* Now create a new homedir which with we test symetric decrypt. */
Packit Service 672cf4
        QTemporaryDir tmp;
Packit Service 672cf4
        qputenv("GNUPGHOME", tmp.path().toUtf8());
Packit Service 672cf4
        QFile agentConf(tmp.path() + QStringLiteral("/gpg-agent.conf"));
Packit Service 672cf4
        QVERIFY(agentConf.open(QIODevice::WriteOnly));
Packit Service 672cf4
        agentConf.write("allow-loopback-pinentry");
Packit Service 672cf4
        agentConf.close();
Packit Service 672cf4
Packit Service 672cf4
        auto decJob = openpgp()->decryptJob();
Packit Service 672cf4
        auto ctx2 = Job::context(decJob);
Packit Service 672cf4
        ctx2->setPassphraseProvider(new TestPassphraseProvider);
Packit Service 672cf4
        ctx2->setPinentryMode(Context::PinentryLoopback);
Packit Service 672cf4
        ctx2->setTextMode(true);
Packit Service 672cf4
        QByteArray plainText;
Packit Service 672cf4
        auto decResult = decJob->exec(cipherText, plainText);
Packit Service 672cf4
        QVERIFY(!decResult.error());
Packit Service 672cf4
        qDebug() << "Plain: " << plainText;
Packit Service 672cf4
        QVERIFY(QString::fromUtf8(plainText) == QStringLiteral("Hello symmetric World"));
Packit Service 672cf4
        delete decJob;
Packit Service 672cf4
Packit Service 672cf4
        killAgent(tmp.path());
Packit Service 672cf4
        qputenv("GNUPGHOME", mDir.path().toUtf8());
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
public Q_SLOT:
Packit Service 672cf4
Packit Service 672cf4
    void initTestCase()
Packit Service 672cf4
    {
Packit Service 672cf4
        QGpgMETest::initTestCase();
Packit Service 672cf4
        const QString gpgHome = qgetenv("GNUPGHOME");
Packit Service 672cf4
        qputenv("GNUPGHOME", mDir.path().toUtf8());
Packit Service 672cf4
        QVERIFY(mDir.isValid());
Packit Service 672cf4
        QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
Packit Service 672cf4
        QVERIFY(agentConf.open(QIODevice::WriteOnly));
Packit Service 672cf4
        agentConf.write("allow-loopback-pinentry");
Packit Service 672cf4
        agentConf.close();
Packit Service 672cf4
        QVERIFY(copyKeyrings(gpgHome, mDir.path()));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
private:
Packit Service 672cf4
    QTemporaryDir mDir;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
QTEST_MAIN(EncryptionTest)
Packit Service 672cf4
Packit Service 672cf4
#include "t-encrypt.moc"