LCOV - code coverage report
Current view: top level - lang/qt/tests - t-tofuinfo.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 208 228 91.2 %
Date: 2016-11-29 15:07:43 Functions: 26 41 63.4 %

          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             : #ifdef HAVE_CONFIG_H
      32             :  #include "config.h"
      33             : #endif
      34             : 
      35             : #include <QDebug>
      36             : #include <QTest>
      37             : #include <QTemporaryDir>
      38             : #include "protocol.h"
      39             : #include "tofuinfo.h"
      40             : #include "tofupolicyjob.h"
      41             : #include "verifyopaquejob.h"
      42             : #include "verificationresult.h"
      43             : #include "signingresult.h"
      44             : #include "keylistjob.h"
      45             : #include "keylistresult.h"
      46             : #include "qgpgmesignjob.h"
      47             : #include "key.h"
      48             : #include "t-support.h"
      49             : #include "engineinfo.h"
      50             : #include <iostream>
      51             : 
      52             : using namespace QGpgME;
      53             : using namespace GpgME;
      54             : 
      55             : static const char testMsg1[] =
      56             : "-----BEGIN PGP MESSAGE-----\n"
      57             : "\n"
      58             : "owGbwMvMwCSoW1RzPCOz3IRxjXQSR0lqcYleSUWJTZOvjVdpcYmCu1+oQmaJIleH\n"
      59             : "GwuDIBMDGysTSIqBi1MApi+nlGGuwDeHao53HBr+FoVGP3xX+kvuu9fCMJvl6IOf\n"
      60             : "y1kvP4y+8D5a11ang0udywsA\n"
      61             : "=Crq6\n"
      62             : "-----END PGP MESSAGE-----\n";
      63             : 
      64           2 : class TofuInfoTest: public QGpgMETest
      65             : {
      66             :     Q_OBJECT
      67             : 
      68           5 :     bool testSupported()
      69             :     {
      70           5 :         return !(GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.1.16");
      71             :     }
      72             : 
      73           1 :     void testTofuCopy(TofuInfo other, const TofuInfo &orig)
      74             :     {
      75           1 :         Q_ASSERT(!orig.isNull());
      76           1 :         Q_ASSERT(!other.isNull());
      77           1 :         Q_ASSERT(orig.signLast() == other.signLast());
      78           1 :         Q_ASSERT(orig.signCount() == other.signCount());
      79           1 :         Q_ASSERT(orig.validity() == other.validity());
      80           1 :         Q_ASSERT(orig.policy() == other.policy());
      81           1 :     }
      82             : 
      83           6 :     void signAndVerify(const QString &what, const GpgME::Key &key, int expected)
      84             :     {
      85           6 :         Context *ctx = Context::createForProtocol(OpenPGP);
      86           6 :         TestPassphraseProvider provider;
      87           6 :         ctx->setPassphraseProvider(&provider);
      88           6 :         ctx->setPinentryMode(Context::PinentryLoopback);
      89           6 :         auto *job = new QGpgMESignJob(ctx);
      90             : 
      91          12 :         std::vector<Key> keys;
      92           6 :         keys.push_back(key);
      93          12 :         QByteArray signedData;
      94          12 :         auto sigResult = job->exec(keys, what.toUtf8(), NormalSignatureMode, signedData);
      95           6 :         delete job;
      96             : 
      97           6 :         Q_ASSERT(!sigResult.error());
      98          18 :         foreach (const auto uid, keys[0].userIDs()) {
      99           6 :             auto info = uid.tofuInfo();
     100           6 :             Q_ASSERT(info.signCount() == expected - 1);
     101          18 :         }
     102             : 
     103           6 :         auto verifyJob = openpgp()->verifyOpaqueJob();
     104          12 :         QByteArray verified;
     105             : 
     106          12 :         auto result = verifyJob->exec(signedData, verified);
     107           6 :         delete verifyJob;
     108             : 
     109           6 :         Q_ASSERT(!result.error());
     110           6 :         Q_ASSERT(verified == what.toUtf8());
     111             : 
     112           6 :         Q_ASSERT(result.numSignatures() == 1);
     113          12 :         auto sig = result.signatures()[0];
     114             : 
     115          12 :         auto key2 = sig.key();
     116           6 :         Q_ASSERT(!key.isNull());
     117           6 :         Q_ASSERT(!strcmp (key2.primaryFingerprint(), key.primaryFingerprint()));
     118           6 :         Q_ASSERT(!strcmp (key.primaryFingerprint(), sig.fingerprint()));
     119          12 :         auto stats = key2.userID(0).tofuInfo();
     120           6 :         Q_ASSERT(!stats.isNull());
     121           6 :         if (stats.signCount() != expected) {
     122           0 :             std::cout << "################ Key before verify: "
     123           0 :                       << key
     124           0 :                       << "################ Key after verify: "
     125           0 :                       << key2;
     126             :         }
     127          12 :         Q_ASSERT(stats.signCount() == expected);
     128           6 :     }
     129             : 
     130             : private Q_SLOTS:
     131           1 :     void testTofuNull()
     132             :     {
     133           1 :         if (!testSupported()) {
     134           1 :             return;
     135             :         }
     136           1 :         TofuInfo tofu;
     137           1 :         Q_ASSERT(tofu.isNull());
     138           1 :         Q_ASSERT(!tofu.description());
     139           1 :         Q_ASSERT(!tofu.signCount());
     140           1 :         Q_ASSERT(!tofu.signLast());
     141           1 :         Q_ASSERT(!tofu.signFirst());
     142           1 :         Q_ASSERT(tofu.validity() == TofuInfo::ValidityUnknown);
     143           1 :         Q_ASSERT(tofu.policy() == TofuInfo::PolicyUnknown);
     144             :     }
     145             : 
     146           1 :     void testTofuInfo()
     147             :     {
     148           1 :         if (!testSupported()) {
     149           1 :             return;
     150             :         }
     151           1 :         auto *job = openpgp()->verifyOpaqueJob(true);
     152           1 :         const QByteArray data1(testMsg1);
     153           2 :         QByteArray plaintext;
     154             : 
     155           1 :         auto ctx = Job::context(job);
     156           1 :         Q_ASSERT(ctx);
     157           1 :         ctx->setSender("alfa@example.net");
     158             : 
     159           2 :         auto result = job->exec(data1, plaintext);
     160           1 :         delete job;
     161             : 
     162           1 :         Q_ASSERT(!result.isNull());
     163           1 :         Q_ASSERT(!result.error());
     164           1 :         Q_ASSERT(!strcmp(plaintext.constData(), "Just GNU it!\n"));
     165             : 
     166           1 :         Q_ASSERT(result.numSignatures() == 1);
     167           2 :         Signature sig = result.signatures()[0];
     168             :         /* TOFU is always marginal */
     169           1 :         Q_ASSERT(sig.validity() == Signature::Marginal);
     170             : 
     171           2 :         auto stats = sig.key().userID(0).tofuInfo();
     172           1 :         Q_ASSERT(!stats.isNull());
     173           1 :         Q_ASSERT(sig.key().primaryFingerprint());
     174           1 :         Q_ASSERT(sig.fingerprint());
     175           1 :         Q_ASSERT(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
     176           1 :         Q_ASSERT(stats.signFirst() == stats.signLast());
     177           1 :         Q_ASSERT(stats.signCount() == 1);
     178           1 :         Q_ASSERT(stats.policy() == TofuInfo::PolicyAuto);
     179           1 :         Q_ASSERT(stats.validity() == TofuInfo::LittleHistory);
     180             : 
     181           1 :         testTofuCopy(stats, stats);
     182             : 
     183             :         /* Another verify */
     184             : 
     185           1 :         job = openpgp()->verifyOpaqueJob(true);
     186           1 :         result = job->exec(data1, plaintext);
     187           1 :         delete job;
     188             : 
     189           1 :         Q_ASSERT(!result.isNull());
     190           1 :         Q_ASSERT(!result.error());
     191             : 
     192           1 :         Q_ASSERT(result.numSignatures() == 1);
     193           1 :         sig = result.signatures()[0];
     194             :         /* TOFU is always marginal */
     195           1 :         Q_ASSERT(sig.validity() == Signature::Marginal);
     196             : 
     197           1 :         stats = sig.key().userID(0).tofuInfo();
     198           1 :         Q_ASSERT(!stats.isNull());
     199           1 :         Q_ASSERT(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
     200           1 :         Q_ASSERT(stats.signFirst() == stats.signLast());
     201           1 :         Q_ASSERT(stats.signCount() == 1);
     202           1 :         Q_ASSERT(stats.policy() == TofuInfo::PolicyAuto);
     203           1 :         Q_ASSERT(stats.validity() == TofuInfo::LittleHistory);
     204             : 
     205             :         /* Verify that another call yields the same result */
     206           1 :         job = openpgp()->verifyOpaqueJob(true);
     207           1 :         result = job->exec(data1, plaintext);
     208           1 :         delete job;
     209             : 
     210           1 :         Q_ASSERT(!result.isNull());
     211           1 :         Q_ASSERT(!result.error());
     212             : 
     213           1 :         Q_ASSERT(result.numSignatures() == 1);
     214           1 :         sig = result.signatures()[0];
     215             :         /* TOFU is always marginal */
     216           1 :         Q_ASSERT(sig.validity() == Signature::Marginal);
     217             : 
     218           1 :         stats = sig.key().userID(0).tofuInfo();
     219           1 :         Q_ASSERT(!stats.isNull());
     220           1 :         Q_ASSERT(!strcmp(sig.key().primaryFingerprint(), sig.fingerprint()));
     221           1 :         Q_ASSERT(stats.signFirst() == stats.signLast());
     222           1 :         Q_ASSERT(stats.signCount() == 1);
     223           1 :         Q_ASSERT(stats.policy() == TofuInfo::PolicyAuto);
     224           2 :         Q_ASSERT(stats.validity() == TofuInfo::LittleHistory);
     225             :     }
     226             : 
     227           1 :     void testTofuSignCount()
     228             :     {
     229           1 :         if (!testSupported()) {
     230           1 :             return;
     231             :         }
     232           1 :         auto *job = openpgp()->keyListJob(false, false, false);
     233           1 :         job->addMode(GpgME::WithTofu);
     234           1 :         std::vector<GpgME::Key> keys;
     235           3 :         GpgME::KeyListResult result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
     236           3 :                                                 true, keys);
     237           1 :         delete job;
     238           1 :         Q_ASSERT(!keys.empty());
     239           2 :         Key key = keys[0];
     240           1 :         Q_ASSERT(!key.isNull());
     241             : 
     242             :         /* As we sign & verify quickly here we need different
     243             :          * messages to avoid having them treated as the same
     244             :          * message if they were created within the same second.
     245             :          * Alternatively we could use the same message and wait
     246             :          * a second between each call. But this would slow down
     247             :          * the testsuite. */
     248           2 :         signAndVerify(QStringLiteral("Hello"), key, 1);
     249           1 :         key.update();
     250           2 :         signAndVerify(QStringLiteral("Hello2"), key, 2);
     251           1 :         key.update();
     252           2 :         signAndVerify(QStringLiteral("Hello3"), key, 3);
     253           1 :         key.update();
     254           3 :         signAndVerify(QStringLiteral("Hello4"), key, 4);
     255             :     }
     256             : 
     257           1 :     void testTofuKeyList()
     258             :     {
     259           1 :         if (!testSupported()) {
     260           1 :             return;
     261             :         }
     262             : 
     263             :         /* First check that the key has no tofu info. */
     264           1 :         auto *job = openpgp()->keyListJob(false, false, false);
     265           1 :         std::vector<GpgME::Key> keys;
     266           3 :         auto result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
     267           3 :                                                  true, keys);
     268           1 :         delete job;
     269           1 :         Q_ASSERT(!keys.empty());
     270           2 :         auto key = keys[0];
     271           1 :         Q_ASSERT(!key.isNull());
     272           1 :         Q_ASSERT(key.userID(0).tofuInfo().isNull());
     273           2 :         auto keyCopy = key;
     274           1 :         keyCopy.update();
     275           1 :         auto sigCnt = keyCopy.userID(0).tofuInfo().signCount();
     276           1 :         signAndVerify(QStringLiteral("Hello5"), keyCopy,
     277           1 :                       sigCnt + 1);
     278           1 :         keyCopy.update();
     279           1 :         signAndVerify(QStringLiteral("Hello6"), keyCopy,
     280           1 :                       sigCnt + 2);
     281             : 
     282             :         /* Now another one but with tofu */
     283           1 :         job = openpgp()->keyListJob(false, false, false);
     284           1 :         job->addMode(GpgME::WithTofu);
     285           3 :         result = job->exec(QStringList() << QStringLiteral("zulu@example.net"),
     286           2 :                            true, keys);
     287           1 :         delete job;
     288           1 :         Q_ASSERT(!result.error());
     289           1 :         Q_ASSERT(!keys.empty());
     290           2 :         auto key2 = keys[0];
     291           1 :         Q_ASSERT(!key2.isNull());
     292           2 :         auto info = key2.userID(0).tofuInfo();
     293           1 :         Q_ASSERT(!info.isNull());
     294           2 :         Q_ASSERT(info.signCount());
     295             :     }
     296             : 
     297           1 :     void testTofuPolicy()
     298             :     {
     299           1 :         if (!testSupported()) {
     300           1 :             return;
     301             :         }
     302             : 
     303             :         /* First check that the key has no tofu info. */
     304           1 :         auto *job = openpgp()->keyListJob(false, false, false);
     305           1 :         std::vector<GpgME::Key> keys;
     306           1 :         job->addMode(GpgME::WithTofu);
     307           3 :         auto result = job->exec(QStringList() << QStringLiteral("bravo@example.net"),
     308           3 :                                                  false, keys);
     309             : 
     310           1 :         if (keys.empty()) {
     311           0 :             qDebug() << "bravo@example.net not found";
     312           0 :             qDebug() << "Error: " << result.error().asString();
     313           0 :             const auto homedir = QString::fromLocal8Bit(qgetenv("GNUPGHOME"));
     314           0 :             qDebug() << "Homedir is: " << homedir;
     315           0 :             QFileInfo fi(homedir + "/pubring.gpg");
     316           0 :             qDebug () << "pubring exists: " << fi.exists() << " readable? "
     317           0 :                       << fi.isReadable() << " size: " << fi.size();
     318           0 :             QFileInfo fi2(homedir + "/pubring.kbx");
     319           0 :             qDebug () << "keybox exists: " << fi2.exists() << " readable? "
     320           0 :                       << fi2.isReadable() << " size: " << fi2.size();
     321             : 
     322           0 :             result = job->exec(QStringList(), false, keys);
     323           0 :             foreach (const auto key, keys) {
     324           0 :                 qDebug() << "Key: " << key.userID(0).name() << " <"
     325           0 :                          << key.userID(0).email()
     326           0 :                          << ">\n fpr: " << key.primaryFingerprint();
     327           0 :             }
     328             :         }
     329           1 :         Q_ASSERT(!result.error());
     330           1 :         Q_ASSERT(!keys.empty());
     331           2 :         auto key = keys[0];
     332           1 :         Q_ASSERT(!key.isNull());
     333           1 :         Q_ASSERT(key.userID(0).tofuInfo().policy() != TofuInfo::PolicyBad);
     334           1 :         auto *tofuJob = openpgp()->tofuPolicyJob();
     335           2 :         auto err = tofuJob->exec(key, TofuInfo::PolicyBad);
     336           1 :         Q_ASSERT(!err);
     337           3 :         result = job->exec(QStringList() << QStringLiteral("bravo@example.net"),
     338           2 :                                             false, keys);
     339           1 :         Q_ASSERT(!keys.empty());
     340           1 :         key = keys[0];
     341           1 :         Q_ASSERT(key.userID(0).tofuInfo().policy() == TofuInfo::PolicyBad);
     342           1 :         err = tofuJob->exec(key, TofuInfo::PolicyGood);
     343             : 
     344           3 :         result = job->exec(QStringList() << QStringLiteral("bravo@example.net"),
     345           2 :                                             false, keys);
     346           1 :         key = keys[0];
     347           1 :         Q_ASSERT(key.userID(0).tofuInfo().policy() == TofuInfo::PolicyGood);
     348           1 :         delete tofuJob;
     349           2 :         delete job;
     350             :     }
     351             : 
     352           1 :     void initTestCase()
     353             :     {
     354           1 :         QGpgMETest::initTestCase();
     355           1 :         const QString gpgHome = qgetenv("GNUPGHOME");
     356           1 :         qputenv("GNUPGHOME", mDir.path().toUtf8());
     357           1 :         Q_ASSERT(mDir.isValid());
     358           3 :         QFile conf(mDir.path() + QStringLiteral("/gpg.conf"));
     359           1 :         Q_ASSERT(conf.open(QIODevice::WriteOnly));
     360           1 :         conf.write("trust-model tofu+pgp");
     361           1 :         conf.close();
     362           3 :         QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf"));
     363           1 :         Q_ASSERT(agentConf.open(QIODevice::WriteOnly));
     364           1 :         agentConf.write("allow-loopback-pinentry");
     365           1 :         agentConf.close();
     366           2 :         Q_ASSERT(copyKeyrings(gpgHome, mDir.path()));
     367           1 :     }
     368             : private:
     369             :     QTemporaryDir mDir;
     370             : 
     371             : };
     372             : 
     373           1 : QTEST_MAIN(TofuInfoTest)
     374             : 
     375             : #include "t-tofuinfo.moc"

Generated by: LCOV version 1.11