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

Packit d7e8d0
/* t-tofuinfo.cpp
Packit d7e8d0
Packit d7e8d0
    This file is part of qgpgme, the Qt API binding for gpgme
Packit d7e8d0
    Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
Packit d7e8d0
    Software engineering by Intevation GmbH
Packit d7e8d0
Packit d7e8d0
    QGpgME is free software; you can redistribute it and/or
Packit d7e8d0
    modify it under the terms of the GNU General Public License as
Packit d7e8d0
    published by the Free Software Foundation; either version 2 of the
Packit d7e8d0
    License, or (at your option) any later version.
Packit d7e8d0
Packit d7e8d0
    QGpgME is distributed in the hope that it will be useful,
Packit d7e8d0
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d7e8d0
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit d7e8d0
    General Public License for more details.
Packit d7e8d0
Packit d7e8d0
    You should have received a copy of the GNU General Public License
Packit d7e8d0
    along with this program; if not, write to the Free Software
Packit d7e8d0
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit d7e8d0
Packit d7e8d0
    In addition, as a special exception, the copyright holders give
Packit d7e8d0
    permission to link the code of this program with any edition of
Packit d7e8d0
    the Qt library by Trolltech AS, Norway (or with modified versions
Packit d7e8d0
    of Qt that use the same license as Qt), and distribute linked
Packit d7e8d0
    combinations including the two.  You must obey the GNU General
Packit d7e8d0
    Public License in all respects for all of the code used other than
Packit d7e8d0
    Qt.  If you modify this file, you may extend this exception to
Packit d7e8d0
    your version of the file, but you are not obligated to do so.  If
Packit d7e8d0
    you do not wish to do so, delete this exception statement from
Packit d7e8d0
    your version.
Packit d7e8d0
*/
Packit d7e8d0
#ifdef HAVE_CONFIG_H
Packit d7e8d0
 #include "config.h"
Packit d7e8d0
#endif
Packit d7e8d0
Packit d7e8d0
#include <QDebug>
Packit d7e8d0
#include <QTest>
Packit d7e8d0
#include <QTemporaryDir>
Packit d7e8d0
#include <QSignalSpy>
Packit d7e8d0
Packit d7e8d0
#include "protocol.h"
Packit d7e8d0
#include "tofuinfo.h"
Packit d7e8d0
#include "tofupolicyjob.h"
Packit d7e8d0
#include "verifyopaquejob.h"
Packit d7e8d0
#include "verificationresult.h"
Packit d7e8d0
#include "signingresult.h"
Packit d7e8d0
#include "importjob.h"
Packit d7e8d0
#include "importresult.h"
Packit d7e8d0
#include "keylistjob.h"
Packit d7e8d0
#include "keylistresult.h"
Packit d7e8d0
#include "signjob.h"
Packit d7e8d0
#include "key.h"
Packit d7e8d0
#include "t-support.h"
Packit d7e8d0
#include "engineinfo.h"
Packit d7e8d0
#include "context.h"
Packit d7e8d0
#include <iostream>
Packit d7e8d0
Packit d7e8d0
using namespace QGpgME;
Packit d7e8d0
using namespace GpgME;
Packit d7e8d0
Packit d7e8d0
static const char testMsg1[] =
Packit d7e8d0
"-----BEGIN PGP MESSAGE-----\n"
Packit d7e8d0
"\n"
Packit d7e8d0
"owGbwMvMwCSoW1RzPCOz3IRxjXQSR0lqcYleSUWJTZOvjVdpcYmCu1+oQmaJIleH\n"
Packit d7e8d0
"GwuDIBMDGysTSIqBi1MApi+nlGGuwDeHao53HBr+FoVGP3xX+kvuu9fCMJvl6IOf\n"
Packit d7e8d0
"y1kvP4y+8D5a11ang0udywsA\n"
Packit d7e8d0
"=Crq6\n"
Packit d7e8d0
"-----END PGP MESSAGE-----\n";
Packit d7e8d0
Packit d7e8d0
static const char conflictKey1[] = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n"
Packit d7e8d0
"\n"
Packit Service 68c0f2
"mDMEWG+w/hYJKwYBBAHaRw8BAQdAiq1oStvDYg8ZfFs5DgisYJo8dJxD+C/AA21O\n"
Packit Service 68c0f2
"K/aif0O0GXRvZnVfY29uZmxpY3RAZXhhbXBsZS5jb22IlgQTFggAPhYhBHoJBLaV\n"
Packit Service 68c0f2
"DamYAgoa1L5BwMOl/x88BQJYb7D+AhsDBQkDwmcABQsJCAcCBhUICQoLAgQWAgMB\n"
Packit Service 68c0f2
"Ah4BAheAAAoJEL5BwMOl/x88GvwA/0SxkbLyAcshGm2PRrPsFQsSVAfwaSYFVmS2\n"
Packit Service 68c0f2
"cMVIw1PfAQDclRH1Z4MpufK07ju4qI33o4s0UFpVRBuSxt7A4P2ZD7g4BFhvsP4S\n"
Packit Service 68c0f2
"CisGAQQBl1UBBQEBB0AmVrgaDNJ7K2BSalsRo2EkRJjHGqnp5bBB0tapnF81CQMB\n"
Packit Service 68c0f2
"CAeIeAQYFggAIBYhBHoJBLaVDamYAgoa1L5BwMOl/x88BQJYb7D+AhsMAAoJEL5B\n"
Packit Service 68c0f2
"wMOl/x88OR0BAMq4/vmJUORRTmzjHcv/DDrQB030DSq666rlckGIKTShAPoDXM9N\n"
Packit Service 68c0f2
"0gZK+YzvrinSKZXHmn0aSwmC1/hyPybJPEljBw==\n"
Packit Service 68c0f2
"=p2Oj\n"
Packit d7e8d0
"-----END PGP PUBLIC KEY BLOCK-----\n";
Packit d7e8d0
Packit d7e8d0
static const char conflictKey2[] = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n"
Packit d7e8d0
"\n"
Packit Service 68c0f2
"mDMEWG+xShYJKwYBBAHaRw8BAQdA567gPEPJRpqKnZjlFJMRNUqruRviYMyygfF6\n"
Packit Service 68c0f2
"6Ok+ygu0GXRvZnVfY29uZmxpY3RAZXhhbXBsZS5jb22IlgQTFggAPhYhBJ5kRh7E\n"
Packit Service 68c0f2
"I98w8kgUcmkAfYFvqqHsBQJYb7FKAhsDBQkDwmcABQsJCAcCBhUICQoLAgQWAgMB\n"
Packit Service 68c0f2
"Ah4BAheAAAoJEGkAfYFvqqHsYR0BAOz8JjYB4VvGkt6noLS3F5TLfsedGwQkBCw5\n"
Packit Service 68c0f2
"znw/vGZsAQD9DSX+ekwdrN56mNO8ISt5uVS7B1ZQtouNBF+nzcwbDbg4BFhvsUoS\n"
Packit Service 68c0f2
"CisGAQQBl1UBBQEBB0BFupW8+Xc1ikab8TJqANjQhvFVh6uLsgcK4g9lZgbGXAMB\n"
Packit Service 68c0f2
"CAeIeAQYFggAIBYhBJ5kRh7EI98w8kgUcmkAfYFvqqHsBQJYb7FKAhsMAAoJEGkA\n"
Packit Service 68c0f2
"fYFvqqHs15ABALdN3uiV/07cJ3RkNb3WPcijGsto+lECDS11dKEwTMFeAQDx+V36\n"
Packit Service 68c0f2
"ocbYC/xEuwi3w45oNqGieazzcD/GBbt8OBk3BA==\n"
Packit Service 68c0f2
"=45IR\n"
Packit d7e8d0
"-----END PGP PUBLIC KEY BLOCK-----\n";
Packit d7e8d0
Packit d7e8d0
static const char conflictMsg1[] = "-----BEGIN PGP MESSAGE-----\n"
Packit d7e8d0
"\n"
Packit Service 68c0f2
"owGbwMvMwCG2z/HA4aX/5W0YT3MlMUTkb2xPSizi6ihlYRDjYJAVU2Sp4mTZNpV3\n"
Packit Service 68c0f2
"5QwmLqkrMLWsTCCFDFycAjCR1vcMf4U0Qrs6qzqfHJ9puGOFduLN2nVmhsumxjBE\n"
Packit Service 68c0f2
"mdw4lr1ehIWR4QdLuNBpe86PGx1PtNXfVAzm/hu+vfjCp5BVNjPTM9L0eAA=\n"
Packit Service 68c0f2
"=MfBD\n"
Packit d7e8d0
"-----END PGP MESSAGE-----\n";
Packit d7e8d0
Packit d7e8d0
static const char conflictMsg2[] = "-----BEGIN PGP MESSAGE-----\n"
Packit d7e8d0
"\n"
Packit Service 68c0f2
"owGbwMvMwCGWyVDbmL9q4RvG01xJDBH5GyvS8vO5OkpZGMQ4GGTFFFnmpbjJHVG+\n"
Packit Service 68c0f2
"b/DJQ6QIppaVCaSQgYtTACaySZHhr/SOPrdFJ89KrcwKY5i1XnflXYf2PK76SafK\n"
Packit Service 68c0f2
"tkxXuXzvJAvDX4kCybuqFk3HXCexz2+IrnZ+5X5EqOnuo3ens2cte+uzlhMA\n"
Packit Service 68c0f2
"=BIAi\n"
Packit d7e8d0
"-----END PGP MESSAGE-----\n";
Packit d7e8d0
Packit d7e8d0
class TofuInfoTest: public QGpgMETest
Packit d7e8d0
{
Packit d7e8d0
    Q_OBJECT
Packit d7e8d0
Q_SIGNALS:
Packit d7e8d0
    void asyncDone();
Packit d7e8d0
Packit d7e8d0
private:
Packit d7e8d0
    bool testSupported()
Packit d7e8d0
    {
Packit d7e8d0
        static bool initialized, supported;
Packit d7e8d0
        if (initialized) {
Packit d7e8d0
            return supported;
Packit d7e8d0
        }
Packit d7e8d0
        initialized = true;
Packit d7e8d0
        if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.16") {
Packit d7e8d0
            return false;
Packit d7e8d0
        }
Packit d7e8d0
        // If the keylist fails here this means that gnupg does not
Packit d7e8d0
        // support tofu at all. It can be disabled at compile time. So no
Packit d7e8d0
        // tests.
Packit d7e8d0
        auto *job = openpgp()->keyListJob(false, false, false);
Packit d7e8d0
        job->addMode(GpgME::WithTofu);
Packit d7e8d0
        std::vector<GpgME::Key> keys;
Packit d7e8d0
        job->exec(QStringList() << QStringLiteral("zulu@example.net"), true, keys);
Packit d7e8d0
        delete job;
Packit d7e8d0
        supported = !keys.empty();
Packit d7e8d0
        return supported;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
    void testTofuCopy(TofuInfo other, const TofuInfo &orig)
Packit d7e8d0
    {
Packit d7e8d0
        QVERIFY(!orig.isNull());
Packit d7e8d0
        QVERIFY(!other.isNull());
Packit d7e8d0
        QVERIFY(orig.signLast() == other.signLast());
Packit d7e8d0
        QVERIFY(orig.signCount() == other.signCount());
Packit d7e8d0
        QVERIFY(orig.validity() == other.validity());
Packit d7e8d0
        QVERIFY(orig.policy() == other.policy());
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
    void signAndVerify(const QString &what, const GpgME::Key &key, int expected)
Packit d7e8d0
    {
Packit d7e8d0
        auto job = openpgp()->signJob();
Packit d7e8d0
        auto ctx = Job::context(job);
Packit d7e8d0
        TestPassphraseProvider provider;
Packit d7e8d0
        ctx->setPassphraseProvider(&provider);
Packit d7e8d0
        ctx->setPinentryMode(Context::PinentryLoopback);
Packit d7e8d0
Packit d7e8d0
        std::vector<Key> keys;
Packit d7e8d0
        keys.push_back(key);
Packit d7e8d0
        QByteArray signedData;
Packit d7e8d0
        auto sigResult = job->exec(keys, what.toUtf8(), NormalSignatureMode, signedData);
Packit d7e8d0
        delete job;
Packit d7e8d0
Packit d7e8d0
        QVERIFY(!sigResult.error());
Packit d7e8d0
        foreach (const auto uid, keys[0].userIDs()) {
Packit d7e8d0
            auto info = uid.tofuInfo();
Packit d7e8d0
            QVERIFY(info.signCount() == expected - 1);
Packit d7e8d0
        }
Packit d7e8d0
Packit d7e8d0
        auto verifyJob = openpgp()->verifyOpaqueJob();
Packit d7e8d0
        QByteArray verified;
Packit d7e8d0
Packit d7e8d0
        auto result = verifyJob->exec(signedData, verified);
Packit d7e8d0
        delete verifyJob;
Packit d7e8d0
Packit d7e8d0
        QVERIFY(!result.error());
Packit d7e8d0
        QVERIFY(verified == what.toUtf8());
Packit d7e8d0
Packit d7e8d0
        QVERIFY(result.numSignatures() == 1);
Packit d7e8d0
        auto sig = result.signatures()[0];
Packit d7e8d0
Packit d7e8d0
        auto key2 = sig.key();
Packit d7e8d0
        QVERIFY(!key.isNull());
Packit d7e8d0
        QVERIFY(!strcmp (key2.primaryFingerprint(), key.primaryFingerprint()));
Packit d7e8d0
        QVERIFY(!strcmp (key.primaryFingerprint(), sig.fingerprint()));
Packit d7e8d0
        auto stats = key2.userID(0).tofuInfo();
Packit d7e8d0
        QVERIFY(!stats.isNull());
Packit d7e8d0
        if (stats.signCount() != expected) {
Packit d7e8d0
            std::cout << "################ Key before verify: "
Packit d7e8d0
                      << key
Packit d7e8d0
                      << "################ Key after verify: "
Packit d7e8d0
                      << key2;
Packit d7e8d0
        }
Packit d7e8d0
        QVERIFY(stats.signCount() == expected);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
private Q_SLOTS:
Packit d7e8d0
    void testTofuNull()
Packit d7e8d0
    {
Packit d7e8d0
        if (!testSupported()) {
Packit d7e8d0
            return;
Packit d7e8d0
        }
Packit d7e8d0
        TofuInfo tofu;
Packit d7e8d0
        QVERIFY(tofu.isNull());
Packit d7e8d0
        QVERIFY(!tofu.description());
Packit d7e8d0
        QVERIFY(!tofu.signCount());
Packit d7e8d0
        QVERIFY(!tofu.signLast());
Packit d7e8d0
        QVERIFY(!tofu.signFirst());
Packit d7e8d0
        QVERIFY(tofu.validity() == TofuInfo::ValidityUnknown);
Packit d7e8d0
        QVERIFY(tofu.policy() == TofuInfo::PolicyUnknown);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
    void testTofuInfo()
Packit d7e8d0
    {
Packit d7e8d0
        if (!testSupported()) {
Packit d7e8d0
            return;
Packit d7e8d0
        }
Packit d7e8d0
        auto *job = openpgp()->verifyOpaqueJob(true);
Packit d7e8d0
        const QByteArray data1(testMsg1);
Packit d7e8d0
        QByteArray plaintext;
Packit d7e8d0
Packit d7e8d0
        auto ctx = Job::context(job);
Packit d7e8d0
        QVERIFY(ctx);
Packit d7e8d0
        ctx->setSender("alfa@example.net");
Packit d7e8d0
Packit d7e8d0
        auto result = job->exec(data1, plaintext);
Packit d7e8d0
        delete job;
Packit d7e8d0
Packit d7e8d0
        QVERIFY(!result.isNull());
Packit d7e8d0
        QVERIFY(!result.error());
Packit d7e8d0
        QVERIFY(!strcmp(plaintext.constData(), "Just GNU it!\n"));
Packit d7e8d0
Packit d7e8d0
        QVERIFY(result.numSignatures() == 1);
Packit d7e8d0
        Signature sig = result.signatures()[0];
Packit d7e8d0
        /* TOFU is always marginal */
Packit d7e8d0
        QVERIFY(sig.validity() == Signature::Marginal);
Packit d7e8d0
Packit d7e8d0
        auto stats = sig.key().userID(0).tofuInfo();
Packit d7e8d0
        QVERIFY(!stats.isNull());
Packit d7e8d0
        QVERIFY(sig.key().primaryFingerprint());
Packit d7e8d0
        QVERIFY(sig.fingerprint());
Packit d7e8d0
        QVERIFY(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
Packit d7e8d0
        QVERIFY(stats.signFirst() == stats.signLast());
Packit d7e8d0
        QVERIFY(stats.signCount() == 1);
Packit d7e8d0
        QVERIFY(stats.policy() == TofuInfo::PolicyAuto);
Packit d7e8d0
        QVERIFY(stats.validity() == TofuInfo::LittleHistory);
Packit d7e8d0
Packit d7e8d0
        testTofuCopy(stats, stats);
Packit d7e8d0
Packit d7e8d0
        /* Another verify */
Packit d7e8d0
Packit d7e8d0
        job = openpgp()->verifyOpaqueJob(true);
Packit d7e8d0
        result = job->exec(data1, plaintext);
Packit d7e8d0
        delete job;
Packit d7e8d0
Packit d7e8d0
        QVERIFY(!result.isNull());
Packit d7e8d0
        QVERIFY(!result.error());
Packit d7e8d0
Packit d7e8d0
        QVERIFY(result.numSignatures() == 1);
Packit d7e8d0
        sig = result.signatures()[0];
Packit d7e8d0
        /* TOFU is always marginal */
Packit d7e8d0
        QVERIFY(sig.validity() == Signature::Marginal);
Packit d7e8d0
Packit d7e8d0
        stats = sig.key().userID(0).tofuInfo();
Packit d7e8d0
        QVERIFY(!stats.isNull());
Packit d7e8d0
        QVERIFY(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
Packit d7e8d0
        QVERIFY(stats.signFirst() == stats.signLast());
Packit d7e8d0
        QVERIFY(stats.signCount() == 1);
Packit d7e8d0
        QVERIFY(stats.policy() == TofuInfo::PolicyAuto);
Packit d7e8d0
        QVERIFY(stats.validity() == TofuInfo::LittleHistory);
Packit d7e8d0
Packit d7e8d0
        /* Verify that another call yields the same result */
Packit d7e8d0
        job = openpgp()->verifyOpaqueJob(true);
Packit d7e8d0
        result = job->exec(data1, plaintext);
Packit d7e8d0
        delete job;
Packit d7e8d0
Packit d7e8d0
        QVERIFY(!result.isNull());
Packit d7e8d0
        QVERIFY(!result.error());
Packit d7e8d0
Packit d7e8d0
        QVERIFY(result.numSignatures() == 1);
Packit d7e8d0
        sig = result.signatures()[0];
Packit d7e8d0
        /* TOFU is always marginal */
Packit d7e8d0
        QVERIFY(sig.validity() == Signature::Marginal);
Packit d7e8d0
Packit d7e8d0
        stats = sig.key().userID(0).tofuInfo();
Packit d7e8d0
        QVERIFY(!stats.isNull());
Packit d7e8d0
        QVERIFY(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
Packit d7e8d0
        QVERIFY(stats.signFirst() == stats.signLast());
Packit d7e8d0
        QVERIFY(stats.signCount() == 1);
Packit d7e8d0
        QVERIFY(stats.policy() == TofuInfo::PolicyAuto);
Packit d7e8d0
        QVERIFY(stats.validity() == TofuInfo::LittleHistory);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
    void testTofuSignCount()
Packit d7e8d0
    {
Packit d7e8d0
        if (!testSupported()) {
Packit d7e8d0
            return;
Packit d7e8d0
        }
Packit d7e8d0
        auto *job = openpgp()->keyListJob(false, false, false);
Packit d7e8d0
        job->addMode(GpgME::WithTofu);
Packit d7e8d0
        std::vector<GpgME::Key> keys;
Packit d7e8d0
        GpgME::KeyListResult result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
Packit d7e8d0
                                                true, keys);
Packit d7e8d0
        delete job;
Packit d7e8d0
        QVERIFY(!keys.empty());
Packit d7e8d0
        Key key = keys[0];
Packit d7e8d0
        QVERIFY(!key.isNull());
Packit d7e8d0
Packit d7e8d0
        /* As we sign & verify quickly here we need different
Packit d7e8d0
         * messages to avoid having them treated as the same
Packit d7e8d0
         * message if they were created within the same second.
Packit d7e8d0
         * Alternatively we could use the same message and wait
Packit d7e8d0
         * a second between each call. But this would slow down
Packit d7e8d0
         * the testsuite. */
Packit d7e8d0
        signAndVerify(QStringLiteral("Hello"), key, 1);
Packit d7e8d0
        key.update();
Packit d7e8d0
        signAndVerify(QStringLiteral("Hello2"), key, 2);
Packit d7e8d0
        key.update();
Packit d7e8d0
        signAndVerify(QStringLiteral("Hello3"), key, 3);
Packit d7e8d0
        key.update();
Packit d7e8d0
        signAndVerify(QStringLiteral("Hello4"), key, 4);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
    void testTofuKeyList()
Packit d7e8d0
    {
Packit d7e8d0
        if (!testSupported()) {
Packit d7e8d0
            return;
Packit d7e8d0
        }
Packit d7e8d0
Packit d7e8d0
        /* First check that the key has no tofu info. */
Packit d7e8d0
        auto *job = openpgp()->keyListJob(false, false, false);
Packit d7e8d0
        std::vector<GpgME::Key> keys;
Packit d7e8d0
        auto result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
Packit d7e8d0
                                                 true, keys);
Packit d7e8d0
        delete job;
Packit d7e8d0
        QVERIFY(!keys.empty());
Packit d7e8d0
        auto key = keys[0];
Packit d7e8d0
        QVERIFY(!key.isNull());
Packit d7e8d0
        QVERIFY(key.userID(0).tofuInfo().isNull());
Packit d7e8d0
        auto keyCopy = key;
Packit d7e8d0
        keyCopy.update();
Packit d7e8d0
        auto sigCnt = keyCopy.userID(0).tofuInfo().signCount();
Packit d7e8d0
        signAndVerify(QStringLiteral("Hello5"), keyCopy,
Packit d7e8d0
                      sigCnt + 1);
Packit d7e8d0
        keyCopy.update();
Packit d7e8d0
        signAndVerify(QStringLiteral("Hello6"), keyCopy,
Packit d7e8d0
                      sigCnt + 2);
Packit d7e8d0
Packit d7e8d0
        /* Now another one but with tofu */
Packit d7e8d0
        job = openpgp()->keyListJob(false, false, false);
Packit d7e8d0
        job->addMode(GpgME::WithTofu);
Packit d7e8d0
        result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
Packit d7e8d0
                           true, keys);
Packit d7e8d0
        delete job;
Packit d7e8d0
        QVERIFY(!result.error());
Packit d7e8d0
        QVERIFY(!keys.empty());
Packit d7e8d0
        auto key2 = keys[0];
Packit d7e8d0
        QVERIFY(!key2.isNull());
Packit d7e8d0
        auto info = key2.userID(0).tofuInfo();
Packit d7e8d0
        QVERIFY(!info.isNull());
Packit d7e8d0
        QVERIFY(info.signCount());
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
    void testTofuPolicy()
Packit d7e8d0
    {
Packit d7e8d0
        if (!testSupported()) {
Packit d7e8d0
            return;
Packit d7e8d0
        }
Packit d7e8d0
Packit d7e8d0
        /* First check that the key has no tofu info. */
Packit d7e8d0
        auto *job = openpgp()->keyListJob(false, false, false);
Packit d7e8d0
        std::vector<GpgME::Key> keys;
Packit d7e8d0
        job->addMode(GpgME::WithTofu);
Packit d7e8d0
        auto result = job->exec(QStringList() << QStringLiteral("bravo@example.net"),
Packit d7e8d0
                                                 false, keys);
Packit d7e8d0
Packit d7e8d0
        if (keys.empty()) {
Packit d7e8d0
            qDebug() << "bravo@example.net not found";
Packit d7e8d0
            qDebug() << "Error: " << result.error().asString();
Packit d7e8d0
            const auto homedir = QString::fromLocal8Bit(qgetenv("GNUPGHOME"));
Packit d7e8d0
            qDebug() << "Homedir is: " << homedir;
Packit d7e8d0
            QFileInfo fi(homedir + "/pubring.gpg");
Packit d7e8d0
            qDebug () << "pubring exists: " << fi.exists() << " readable? "
Packit d7e8d0
                      << fi.isReadable() << " size: " << fi.size();
Packit d7e8d0
            QFileInfo fi2(homedir + "/pubring.kbx");
Packit d7e8d0
            qDebug () << "keybox exists: " << fi2.exists() << " readable? "
Packit d7e8d0
                      << fi2.isReadable() << " size: " << fi2.size();
Packit d7e8d0
Packit d7e8d0
            result = job->exec(QStringList(), false, keys);
Packit d7e8d0
            foreach (const auto key, keys) {
Packit d7e8d0
                qDebug() << "Key: " << key.userID(0).name() << " <"
Packit d7e8d0
                         << key.userID(0).email()
Packit d7e8d0
                         << ">\n fpr: " << key.primaryFingerprint();
Packit d7e8d0
            }
Packit d7e8d0
        }
Packit d7e8d0
        QVERIFY(!result.error());
Packit d7e8d0
        QVERIFY(!keys.empty());
Packit d7e8d0
        auto key = keys[0];
Packit d7e8d0
        QVERIFY(!key.isNull());
Packit d7e8d0
        QVERIFY(key.userID(0).tofuInfo().policy() != TofuInfo::PolicyBad);
Packit d7e8d0
        auto *tofuJob = openpgp()->tofuPolicyJob();
Packit d7e8d0
        auto err = tofuJob->exec(key, TofuInfo::PolicyBad);
Packit d7e8d0
        QVERIFY(!err);
Packit d7e8d0
        result = job->exec(QStringList() << QStringLiteral("bravo@example.net"),
Packit d7e8d0
                                            false, keys);
Packit d7e8d0
        QVERIFY(!keys.empty());
Packit d7e8d0
        key = keys[0];
Packit d7e8d0
        QVERIFY(key.userID(0).tofuInfo().policy() == TofuInfo::PolicyBad);
Packit d7e8d0
        err = tofuJob->exec(key, TofuInfo::PolicyGood);
Packit d7e8d0
Packit d7e8d0
        result = job->exec(QStringList() << QStringLiteral("bravo@example.net"),
Packit d7e8d0
                                            false, keys);
Packit d7e8d0
        key = keys[0];
Packit d7e8d0
        QVERIFY(key.userID(0).tofuInfo().policy() == TofuInfo::PolicyGood);
Packit d7e8d0
        delete tofuJob;
Packit d7e8d0
        delete job;
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
    void testTofuConflict()
Packit d7e8d0
    {
Packit d7e8d0
        if (!testSupported()) {
Packit d7e8d0
            return;
Packit d7e8d0
        }
Packit d7e8d0
Packit d7e8d0
        if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.19") {
Packit d7e8d0
            return;
Packit d7e8d0
        }
Packit d7e8d0
Packit d7e8d0
        // Import key 1
Packit d7e8d0
        auto importjob = openpgp()->importJob();
Packit d7e8d0
        connect(importjob, &ImportJob::result, this,
Packit d7e8d0
                [this](ImportResult result, QString, Error)
Packit d7e8d0
        {
Packit d7e8d0
            QVERIFY(!result.error());
Packit d7e8d0
            QVERIFY(!result.imports().empty());
Packit d7e8d0
            QVERIFY(result.numImported());
Packit d7e8d0
            Q_EMIT asyncDone();
Packit d7e8d0
        });
Packit d7e8d0
        importjob->start(QByteArray(conflictKey1));
Packit d7e8d0
        QSignalSpy spy (this, SIGNAL(asyncDone()));
Packit d7e8d0
        QVERIFY(spy.wait());
Packit d7e8d0
Packit d7e8d0
        // Verify Message 1
Packit d7e8d0
        const QByteArray signedData(conflictMsg1);
Packit d7e8d0
        auto verifyJob = openpgp()->verifyOpaqueJob(true);
Packit d7e8d0
        QByteArray verified;
Packit d7e8d0
        auto result = verifyJob->exec(signedData, verified);
Packit d7e8d0
        delete verifyJob;
Packit d7e8d0
Packit d7e8d0
        QVERIFY(!result.isNull());
Packit d7e8d0
        QVERIFY(!result.error());
Packit d7e8d0
Packit d7e8d0
        QVERIFY(result.numSignatures() == 1);
Packit d7e8d0
        auto sig = result.signatures()[0];
Packit d7e8d0
        QVERIFY(sig.validity() == Signature::Marginal);
Packit d7e8d0
Packit d7e8d0
        auto stats = sig.key().userID(0).tofuInfo();
Packit d7e8d0
        QVERIFY(!stats.isNull());
Packit d7e8d0
        QVERIFY(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
Packit d7e8d0
        QVERIFY(stats.signFirst() == stats.signLast());
Packit d7e8d0
        QVERIFY(stats.signCount() == 1);
Packit d7e8d0
        QVERIFY(stats.policy() == TofuInfo::PolicyAuto);
Packit d7e8d0
        QVERIFY(stats.validity() == TofuInfo::LittleHistory);
Packit d7e8d0
Packit d7e8d0
        // Import key 2
Packit d7e8d0
        importjob = openpgp()->importJob();
Packit d7e8d0
        connect(importjob, &ImportJob::result, this,
Packit d7e8d0
                [this](ImportResult result, QString, Error)
Packit d7e8d0
        {
Packit d7e8d0
            QVERIFY(!result.error());
Packit d7e8d0
            QVERIFY(!result.imports().empty());
Packit d7e8d0
            QVERIFY(result.numImported());
Packit d7e8d0
            Q_EMIT asyncDone();
Packit d7e8d0
        });
Packit d7e8d0
        importjob->start(QByteArray(conflictKey2));
Packit d7e8d0
        QSignalSpy spy2 (this, SIGNAL(asyncDone()));
Packit d7e8d0
        QVERIFY(spy2.wait());
Packit d7e8d0
Packit d7e8d0
        // Verify Message 2
Packit d7e8d0
        const QByteArray signedData2(conflictMsg2);
Packit d7e8d0
        QByteArray verified2;
Packit d7e8d0
        verifyJob = openpgp()->verifyOpaqueJob(true);
Packit d7e8d0
        result = verifyJob->exec(signedData2, verified2);
Packit d7e8d0
        delete verifyJob;
Packit d7e8d0
Packit d7e8d0
        QVERIFY(!result.isNull());
Packit d7e8d0
        QVERIFY(!result.error());
Packit d7e8d0
Packit d7e8d0
        QVERIFY(result.numSignatures() == 1);
Packit d7e8d0
        sig = result.signatures()[0];
Packit d7e8d0
        QVERIFY(sig.validity() == Signature::Unknown);
Packit d7e8d0
        // TODO activate when implemented
Packit d7e8d0
        // QVERIFY(sig.summary() == Signature::TofuConflict);
Packit d7e8d0
Packit d7e8d0
        stats = sig.key().userID(0).tofuInfo();
Packit d7e8d0
        QVERIFY(!stats.isNull());
Packit d7e8d0
        QVERIFY(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
Packit d7e8d0
        QVERIFY(stats.signFirst() == stats.signLast());
Packit d7e8d0
        QVERIFY(stats.signCount() == 1);
Packit d7e8d0
        QVERIFY(stats.policy() == TofuInfo::PolicyAsk);
Packit d7e8d0
        QVERIFY(stats.validity() == TofuInfo::Conflict);
Packit d7e8d0
    }
Packit d7e8d0
Packit d7e8d0
Packit d7e8d0
    void initTestCase()
Packit d7e8d0
    {
Packit d7e8d0
        QGpgMETest::initTestCase();
Packit d7e8d0
        const QString gpgHome = qgetenv("GNUPGHOME");
Packit d7e8d0
        qputenv("GNUPGHOME", mDir.path().toUtf8());
Packit d7e8d0
        QVERIFY(mDir.isValid());
Packit d7e8d0
        QFile conf(mDir.path() + QStringLiteral("/gpg.conf"));
Packit d7e8d0
        QVERIFY(conf.open(QIODevice::WriteOnly));
Packit d7e8d0
        conf.write("trust-model tofu+pgp");
Packit d7e8d0
        conf.close();
Packit d7e8d0
        QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
Packit d7e8d0
        QVERIFY(agentConf.open(QIODevice::WriteOnly));
Packit d7e8d0
        agentConf.write("allow-loopback-pinentry");
Packit d7e8d0
        agentConf.close();
Packit d7e8d0
        QVERIFY(copyKeyrings(gpgHome, mDir.path()));
Packit d7e8d0
    }
Packit d7e8d0
private:
Packit d7e8d0
    QTemporaryDir mDir;
Packit d7e8d0
Packit d7e8d0
};
Packit d7e8d0
Packit d7e8d0
QTEST_MAIN(TofuInfoTest)
Packit d7e8d0
Packit d7e8d0
#include "t-tofuinfo.moc"