LCOV - code coverage report
Current view: top level - lang/qt/tests - t-tofuinfo.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 176 180 97.8 %
Date: 2016-09-12 13:07:23 Functions: 22 34 64.7 %

          Line data    Source code
       1             : /* t-tofuinfo.cpp
       2             : 
       3             :     This file is part of qgpgme, the Qt API binding for gpgme
       4             :     Copyright (c) 2016 Intevation GmbH
       5             : 
       6             :     QGpgME is free software; you can redistribute it and/or
       7             :     modify it under the terms of the GNU General Public License as
       8             :     published by the Free Software Foundation; either version 2 of the
       9             :     License, or (at your option) any later version.
      10             : 
      11             :     QGpgME is distributed in the hope that it will be useful,
      12             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :     General Public License for more details.
      15             : 
      16             :     You should have received a copy of the GNU General Public License
      17             :     along with this program; if not, write to the Free Software
      18             :     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      19             : 
      20             :     In addition, as a special exception, the copyright holders give
      21             :     permission to link the code of this program with any edition of
      22             :     the Qt library by Trolltech AS, Norway (or with modified versions
      23             :     of Qt that use the same license as Qt), and distribute linked
      24             :     combinations including the two.  You must obey the GNU General
      25             :     Public License in all respects for all of the code used other than
      26             :     Qt.  If you modify this file, you may extend this exception to
      27             :     your version of the file, but you are not obligated to do so.  If
      28             :     you do not wish to do so, delete this exception statement from
      29             :     your version.
      30             : */
      31             : #include <QDebug>
      32             : #include <QTest>
      33             : #include <QTemporaryDir>
      34             : #include "protocol.h"
      35             : #include "tofuinfo.h"
      36             : #include "verifyopaquejob.h"
      37             : #include "verificationresult.h"
      38             : #include "signingresult.h"
      39             : #include "keylistjob.h"
      40             : #include "keylistresult.h"
      41             : #include "qgpgmesignjob.h"
      42             : #include "key.h"
      43             : #include "t-support.h"
      44             : #include "engineinfo.h"
      45             : #include <iostream>
      46             : 
      47             : using namespace QGpgME;
      48             : using namespace GpgME;
      49             : 
      50             : static const char testMsg1[] =
      51             : "-----BEGIN PGP MESSAGE-----\n"
      52             : "\n"
      53             : "owGbwMvMwCSoW1RzPCOz3IRxjXQSR0lqcYleSUWJTZOvjVdpcYmCu1+oQmaJIleH\n"
      54             : "GwuDIBMDGysTSIqBi1MApi+nlGGuwDeHao53HBr+FoVGP3xX+kvuu9fCMJvl6IOf\n"
      55             : "y1kvP4y+8D5a11ang0udywsA\n"
      56             : "=Crq6\n"
      57             : "-----END PGP MESSAGE-----\n";
      58             : 
      59           2 : class TofuInfoTest: public QGpgMETest
      60             : {
      61             :     Q_OBJECT
      62             : 
      63           4 :     bool testSupported()
      64             :     {
      65           4 :         return !(GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.16");
      66             :     }
      67             : 
      68           1 :     void testTofuCopy(TofuInfo other, const TofuInfo &orig)
      69             :     {
      70           1 :         Q_ASSERT(!orig.isNull());
      71           1 :         Q_ASSERT(!other.isNull());
      72           1 :         Q_ASSERT(orig.signLast() == other.signLast());
      73           1 :         Q_ASSERT(orig.signCount() == other.signCount());
      74           1 :         Q_ASSERT(orig.validity() == other.validity());
      75           1 :         Q_ASSERT(orig.policy() == other.policy());
      76           1 :     }
      77             : 
      78           6 :     void signAndVerify(const QString &what, const GpgME::Key &key, int expected)
      79             :     {
      80           6 :         Context *ctx = Context::createForProtocol(OpenPGP);
      81           6 :         TestPassphraseProvider provider;
      82           6 :         ctx->setPassphraseProvider(&provider);
      83           6 :         ctx->setPinentryMode(Context::PinentryLoopback);
      84           6 :         auto *job = new QGpgMESignJob(ctx);
      85             : 
      86          12 :         std::vector<Key> keys;
      87           6 :         keys.push_back(key);
      88          12 :         QByteArray signedData;
      89          12 :         auto sigResult = job->exec(keys, what.toUtf8(), NormalSignatureMode, signedData);
      90           6 :         delete job;
      91             : 
      92           6 :         Q_ASSERT(!sigResult.error());
      93          18 :         foreach (const auto uid, keys[0].userIDs()) {
      94           6 :             auto info = uid.tofuInfo();
      95           6 :             Q_ASSERT(info.signCount() == expected - 1);
      96          18 :         }
      97             : 
      98           6 :         auto verifyJob = openpgp()->verifyOpaqueJob();
      99          12 :         QByteArray verified;
     100             : 
     101          12 :         auto result = verifyJob->exec(signedData, verified);
     102           6 :         delete verifyJob;
     103             : 
     104           6 :         Q_ASSERT(!result.error());
     105           6 :         Q_ASSERT(verified == what.toUtf8());
     106             : 
     107           6 :         Q_ASSERT(result.numSignatures() == 1);
     108          12 :         auto sig = result.signatures()[0];
     109             : 
     110          12 :         auto key2 = sig.key();
     111           6 :         Q_ASSERT(!key.isNull());
     112           6 :         Q_ASSERT(!strcmp (key2.primaryFingerprint(), key.primaryFingerprint()));
     113           6 :         Q_ASSERT(!strcmp (key.primaryFingerprint(), sig.fingerprint()));
     114          12 :         auto stats = key2.userID(0).tofuInfo();
     115           6 :         Q_ASSERT(!stats.isNull());
     116           6 :         if (stats.signCount() != expected) {
     117           0 :             std::cout << "################ Key before verify: "
     118           0 :                       << key
     119           0 :                       << "################ Key after verify: "
     120           0 :                       << key2;
     121             :         }
     122          12 :         Q_ASSERT(stats.signCount() == expected);
     123           6 :     }
     124             : 
     125             : private Q_SLOTS:
     126           1 :     void testTofuNull()
     127             :     {
     128           1 :         if (!testSupported()) {
     129           1 :             return;
     130             :         }
     131           1 :         TofuInfo tofu;
     132           1 :         Q_ASSERT(tofu.isNull());
     133           1 :         Q_ASSERT(!tofu.description());
     134           1 :         Q_ASSERT(!tofu.signCount());
     135           1 :         Q_ASSERT(!tofu.signLast());
     136           1 :         Q_ASSERT(!tofu.signFirst());
     137           1 :         Q_ASSERT(tofu.validity() == TofuInfo::ValidityUnknown);
     138           1 :         Q_ASSERT(tofu.policy() == TofuInfo::PolicyUnknown);
     139             :     }
     140             : 
     141           1 :     void testTofuInfo()
     142             :     {
     143           1 :         if (!testSupported()) {
     144           1 :             return;
     145             :         }
     146           1 :         auto *job = openpgp()->verifyOpaqueJob(true);
     147           1 :         const QByteArray data1(testMsg1);
     148           2 :         QByteArray plaintext;
     149             : 
     150           2 :         auto result = job->exec(data1, plaintext);
     151           1 :         delete job;
     152             : 
     153           1 :         Q_ASSERT(!result.isNull());
     154           1 :         Q_ASSERT(!result.error());
     155           1 :         Q_ASSERT(!strcmp(plaintext.constData(), "Just GNU it!\n"));
     156             : 
     157           1 :         Q_ASSERT(result.numSignatures() == 1);
     158           2 :         Signature sig = result.signatures()[0];
     159             :         /* TOFU is always marginal */
     160           1 :         Q_ASSERT(sig.validity() == Signature::Marginal);
     161             : 
     162           2 :         auto stats = sig.key().userID(0).tofuInfo();
     163           1 :         Q_ASSERT(!stats.isNull());
     164           1 :         Q_ASSERT(sig.key().primaryFingerprint());
     165           1 :         Q_ASSERT(sig.fingerprint());
     166           1 :         Q_ASSERT(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
     167           1 :         Q_ASSERT(stats.signFirst() == stats.signLast());
     168           1 :         Q_ASSERT(stats.signCount() == 1);
     169           1 :         Q_ASSERT(stats.policy() == TofuInfo::PolicyAuto);
     170           1 :         Q_ASSERT(stats.validity() == TofuInfo::LittleHistory);
     171             : 
     172           1 :         testTofuCopy(stats, stats);
     173             : 
     174             :         /* Another verify */
     175             : 
     176           1 :         job = openpgp()->verifyOpaqueJob(true);
     177           1 :         result = job->exec(data1, plaintext);
     178           1 :         delete job;
     179             : 
     180           1 :         Q_ASSERT(!result.isNull());
     181           1 :         Q_ASSERT(!result.error());
     182             : 
     183           1 :         Q_ASSERT(result.numSignatures() == 1);
     184           1 :         sig = result.signatures()[0];
     185             :         /* TOFU is always marginal */
     186           1 :         Q_ASSERT(sig.validity() == Signature::Marginal);
     187             : 
     188           1 :         stats = sig.key().userID(0).tofuInfo();
     189           1 :         Q_ASSERT(!stats.isNull());
     190           1 :         Q_ASSERT(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
     191           1 :         Q_ASSERT(stats.signFirst() == stats.signLast());
     192           1 :         Q_ASSERT(stats.signCount() == 1);
     193           1 :         Q_ASSERT(stats.policy() == TofuInfo::PolicyAuto);
     194           1 :         Q_ASSERT(stats.validity() == TofuInfo::LittleHistory);
     195             : 
     196             :         /* Verify that another call yields the same result */
     197           1 :         job = openpgp()->verifyOpaqueJob(true);
     198           1 :         result = job->exec(data1, plaintext);
     199           1 :         delete job;
     200             : 
     201           1 :         Q_ASSERT(!result.isNull());
     202           1 :         Q_ASSERT(!result.error());
     203             : 
     204           1 :         Q_ASSERT(result.numSignatures() == 1);
     205           1 :         sig = result.signatures()[0];
     206             :         /* TOFU is always marginal */
     207           1 :         Q_ASSERT(sig.validity() == Signature::Marginal);
     208             : 
     209           1 :         stats = sig.key().userID(0).tofuInfo();
     210           1 :         Q_ASSERT(!stats.isNull());
     211           1 :         Q_ASSERT(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
     212           1 :         Q_ASSERT(stats.signFirst() == stats.signLast());
     213           1 :         Q_ASSERT(stats.signCount() == 1);
     214           1 :         Q_ASSERT(stats.policy() == TofuInfo::PolicyAuto);
     215           2 :         Q_ASSERT(stats.validity() == TofuInfo::LittleHistory);
     216             :     }
     217             : 
     218           1 :     void testTofuSignCount()
     219             :     {
     220           1 :         if (!testSupported()) {
     221           1 :             return;
     222             :         }
     223           1 :         auto *job = openpgp()->keyListJob(false, false, false);
     224           1 :         job->addMode(GpgME::WithTofu);
     225           1 :         std::vector<GpgME::Key> keys;
     226           3 :         GpgME::KeyListResult result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
     227           3 :                                                 true, keys);
     228           1 :         delete job;
     229           1 :         Q_ASSERT(!keys.empty());
     230           2 :         Key key = keys[0];
     231           1 :         Q_ASSERT(!key.isNull());
     232             : 
     233             :         /* As we sign & verify quickly here we need different
     234             :          * messages to avoid having them treated as the same
     235             :          * message if they were created within the same second.
     236             :          * Alternatively we could use the same message and wait
     237             :          * a second between each call. But this would slow down
     238             :          * the testsuite. */
     239           2 :         signAndVerify(QStringLiteral("Hello"), key, 1);
     240           1 :         key.update();
     241           2 :         signAndVerify(QStringLiteral("Hello2"), key, 2);
     242           1 :         key.update();
     243           2 :         signAndVerify(QStringLiteral("Hello3"), key, 3);
     244           1 :         key.update();
     245           3 :         signAndVerify(QStringLiteral("Hello4"), key, 4);
     246             :     }
     247             : 
     248           1 :     void testTofuKeyList()
     249             :     {
     250           1 :         if (!testSupported()) {
     251           1 :             return;
     252             :         }
     253             : 
     254             :         /* First check that the key has no tofu info. */
     255           1 :         auto *job = openpgp()->keyListJob(false, false, false);
     256           1 :         std::vector<GpgME::Key> keys;
     257           3 :         auto result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
     258           3 :                                                  true, keys);
     259           1 :         delete job;
     260           1 :         Q_ASSERT(!keys.empty());
     261           2 :         auto key = keys[0];
     262           1 :         Q_ASSERT(!key.isNull());
     263           1 :         Q_ASSERT(key.userID(0).tofuInfo().isNull());
     264           2 :         auto keyCopy = key;
     265           1 :         keyCopy.update();
     266           1 :         auto sigCnt = keyCopy.userID(0).tofuInfo().signCount();
     267           1 :         signAndVerify(QStringLiteral("Hello5"), keyCopy,
     268           1 :                       sigCnt + 1);
     269           1 :         keyCopy.update();
     270           1 :         signAndVerify(QStringLiteral("Hello6"), keyCopy,
     271           1 :                       sigCnt + 2);
     272             : 
     273             :         /* Now another one but with tofu */
     274           1 :         job = openpgp()->keyListJob(false, false, false);
     275           1 :         job->addMode(GpgME::WithTofu);
     276           3 :         result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
     277           2 :                            true, keys);
     278           1 :         delete job;
     279           1 :         Q_ASSERT(!result.error());
     280           1 :         Q_ASSERT(!keys.empty());
     281           2 :         auto key2 = keys[0];
     282           1 :         Q_ASSERT(!key2.isNull());
     283           2 :         auto info = key2.userID(0).tofuInfo();
     284           1 :         Q_ASSERT(!info.isNull());
     285           2 :         Q_ASSERT(info.signCount());
     286             :     }
     287             : 
     288           1 :     void initTestCase()
     289             :     {
     290           1 :         QGpgMETest::initTestCase();
     291           1 :         const QString gpgHome = qgetenv("GNUPGHOME");
     292           1 :         qputenv("GNUPGHOME", mDir.path().toUtf8());
     293           1 :         Q_ASSERT(mDir.isValid());
     294           3 :         QFile conf(mDir.path() + QStringLiteral("/gpg.conf"));
     295           1 :         Q_ASSERT(conf.open(QIODevice::WriteOnly));
     296           1 :         conf.write("trust-model tofu+pgp");
     297           1 :         conf.close();
     298           3 :         QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
     299           1 :         Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
     300           1 :         agentConf.write("allow-loopback-pinentry");
     301           1 :         agentConf.close();
     302           2 :         Q_ASSERT(copyKeyrings(gpgHome, mDir.path()));
     303           1 :     }
     304             : private:
     305             :     QTemporaryDir mDir;
     306             : 
     307             : };
     308             : 
     309           1 : QTEST_MAIN(TofuInfoTest)
     310             : 
     311             : #include "t-tofuinfo.moc"

Generated by: LCOV version 1.11