1 /* t-wkspublish.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 <QSignalSpy> 39 #include <QTemporaryDir> 40 #include "wkspublishjob.h" 41 #include "keygenerationjob.h" 42 #include "keygenerationresult.h" 43 #include "importjob.h" 44 #include "importresult.h" 45 #include "protocol.h" 46 #include "engineinfo.h" 47 48 #include "t-support.h" 49 50 using namespace QGpgME; 51 using namespace GpgME; 52 53 //#define DO_ONLINE_TESTS 54 55 #define TEST_ADDRESS "testuser2@test.gnupg.org" 56 57 static const char *testSecKey = 58 "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" 59 "\n" 60 "lHgEV77hVhMJKyQDAwIIAQEHAgMEN3qKqBr9EecnfUnpw8RS8DHAjJqhwm2HAoEE\n" 61 "3yfQQ9w8uB/bKm5dqW4HML3JWRH8YoJaKSVrJY2D1FZUY+vHlgABAKDwEAB0HND8\n" 62 "5kbxiJmqKIuuNqCJ2jHgs9G0xk4GdKvZEdq0JlRlc3QgVXNlciAyIDx0ZXN0dXNl\n" 63 "cjJAdGVzdC5nbnVwZy5vcmc+iHkEExMIACEFAle+4VYCGwMFCwkIBwIGFQgJCgsC\n" 64 "BBYCAwECHgECF4AACgkQRVRoUEJO+6zgFQD7BF3pnS3w3A7J9y+Y3kyGfmscXFWJ\n" 65 "Kme1PAsAlVSm1y4A+weReMvWFYHJH257v94yhStmV8egGoybsNDttNAW53cbnHwE\n" 66 "V77hVhIJKyQDAwIIAQEHAgMEX+6cF0HEn4g3ztFvwHyr7uwXMVYUGL3lE3mjhnV3\n" 67 "SbY6Dmy3OeFVnEVkawHqSv+HobpQTeEqNoQHAoIiXFCRlgMBCAcAAP9FykiyDspm\n" 68 "T33XWRPD+LAOmaIU7CIhfv9+lVkeExlU1w+qiGEEGBMIAAkFAle+4VYCGwwACgkQ\n" 69 "RVRoUEJO+6xjhgD/ZJ/MwYZJPk/xPYhTP8+wF+tErVNA8w3pP9D69dgUPdcA/izZ\n" 70 "Pji6YetVhgsyaHc4PrKynsk5G6nM3KkAOehUQsX8\n" 71 "=S/Wa\n" 72 "-----END PGP PRIVATE KEY BLOCK-----\n"; 73 74 static const char *testResponse = 75 "From key-submission@test.gnupg.org Thu Aug 25 12:15:54 2016\n" 76 "Return-Path: <webkey@g10code.com>\n" 77 "From: key-submission@test.gnupg.org\n" 78 "To: testuser2@test.gnupg.org\n" 79 "Subject: Confirm your key publication\n" 80 "X-Wks-Loop: webkey.g10code.com\n" 81 "MIME-Version: 1.0\n" 82 "Content-Type: multipart/encrypted; protocol=\"application/pgp-encrypted\";\n" 83 " boundary=\"=-=01-wbu5fr9nu6fix5tcojjo=-=\"\n" 84 "Date: Thu, 25 Aug 2016 12:15:54 +0000\n" 85 "Message-Id: <E1bctZa-0004LE-Fr@kerckhoffs.g10code.com>\n" 86 "Sender: <webkey@g10code.com>\n" 87 "X-Kolab-Scheduling-Message: FALSE\n" 88 "\n" 89 " \n" 90 "\n" 91 "--=-=01-wbu5fr9nu6fix5tcojjo=-=\n" 92 "Content-Type: application/pgp-encrypted\n" 93 "\n" 94 "Version: 1\n" 95 "\n" 96 "--=-=01-wbu5fr9nu6fix5tcojjo=-=\n" 97 "Content-Type: application/octet-stream\n" 98 "\n" 99 "-----BEGIN PGP MESSAGE-----\n" 100 "Version: GnuPG v2\n" 101 "\n" 102 "hH4D8pSp7hUsFUASAgMEg0w39E6d0TkFYxLbT6n3YcoKTT+Ur/c7Sn1ECyL7Rnuk\n" 103 "cmPO0adt3JxueK7Oz5COlk32SECFODdF3cQuDhkGxzC6Sfc4SfisdILmNhaT/MeW\n" 104 "8a+yE4skSK70absif4kw5XkvxXNxHeIHfAteP50jPJLSwEsBTEceb9cRMoP7s8w0\n" 105 "lYyi+RWQ7UKlKKywtcRCL4ow2H7spjx+a+3FzNOAoy7K0/thhLVRk8z+iuPi0/4n\n" 106 "Z2Ql60USLLUlfV2ZIpXdCd+5GjTJsnGhDos1pas5TZcOOAxO12Cg5TcqHISOaqa8\n" 107 "6BqxcKCU3NypIynOKHj375KArSs0WsEH8HWHyBBHB+NYtNpnTAuHNKxM+JtNxf+U\n" 108 "NfD2zptS6kyiHLw+4zjL5pEV7RHS2PBwWBDS6vhnyybNwckleya96U04iYiGRYGE\n" 109 "lUUR6Fl8H6x04dItFH1/jJA6Ppcu4FoYou04HADWCqJXPTgztjiW1/9QoCeXl5lm\n" 110 "CcOCcuw7lXp+qTejuns=\n" 111 "=SsWX\n" 112 "-----END PGP MESSAGE-----\n" 113 "\n" 114 "--=-=01-wbu5fr9nu6fix5tcojjo=-=--\n"; 115 116 117 class WKSPublishTest : public QGpgMETest 118 { 119 Q_OBJECT 120 121 Q_SIGNALS: 122 void asyncDone(); 123 124 private Q_SLOTS: testUnsupported()125 void testUnsupported() 126 { 127 // First check if it is supported 128 auto job = openpgp()->wksPublishJob(); 129 connect(job, &WKSPublishJob::result, this, 130 [this] (Error err, QByteArray, QByteArray, QString, Error) { 131 QVERIFY(err); 132 Q_EMIT asyncDone(); 133 }); 134 job->startCheck ("testuser1@localhost"); 135 QSignalSpy spy (this, SIGNAL(asyncDone())); 136 QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT)); 137 } 138 #ifdef DO_ONLINE_TESTS 139 private Q_SLOTS: 140 #else 141 private: 142 #endif testWSKPublishSupport()143 void testWSKPublishSupport() 144 { 145 // First check if it is supported 146 auto job = openpgp()->wksPublishJob(); 147 connect(job, &WKSPublishJob::result, this, 148 [this] (Error err, QByteArray, QByteArray, QString, Error) { 149 if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.0.16") { 150 std::cout << err; 151 QVERIFY(err); 152 } else { 153 QVERIFY(!err); 154 } 155 Q_EMIT asyncDone(); 156 }); 157 job->startCheck ("testuser1@test.gnupg.org"); 158 QSignalSpy spy (this, SIGNAL(asyncDone())); 159 QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT)); 160 } 161 testWKSPublishErrors()162 void testWKSPublishErrors() { 163 if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.0.16") { 164 /* Not supported */ 165 return; 166 } 167 auto job = openpgp()->wksPublishJob(); 168 connect(job, &WKSPublishJob::result, this, 169 [this] (Error err, QByteArray, QByteArray, QString, Error) { 170 QVERIFY(err); 171 Q_EMIT asyncDone(); 172 }); 173 job->startCreate("AB874F24E98EBB8487EE7B170F8E3D97FE7011B7", 174 QStringLiteral("Foo@bar.baz")); 175 QSignalSpy spy (this, SIGNAL(asyncDone())); 176 QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT)); 177 } 178 testWKSPublishCreate()179 void testWKSPublishCreate() { 180 if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.0.16") { 181 /* Not supported */ 182 return; 183 } 184 /* First generate a test key */ 185 const QString args = QStringLiteral("<GnupgKeyParms format=\"internal\">\n" 186 "%no-protection\n" 187 "%transient-key\n" 188 "key-type: ECDSA\n" 189 "key-curve: brainpoolP256r1\n" 190 "key-usage: sign\n" 191 "subkey-type: ECDH\n" 192 "subkey-curve: brainpoolP256r1\n" 193 "subkey-usage: encrypt\n" 194 "name-email: %1\n" 195 "name-real: Test User\n" 196 "</GnupgKeyParms>").arg(TEST_ADDRESS); 197 198 auto keygenjob = openpgp()->keyGenerationJob(); 199 QByteArray fpr; 200 connect(keygenjob, &KeyGenerationJob::result, this, 201 [this, &fpr](KeyGenerationResult result, QByteArray, QString, Error) 202 { 203 QVERIFY(!result.error()); 204 fpr = QByteArray(result.fingerprint()); 205 QVERIFY(!fpr.isEmpty()); 206 Q_EMIT asyncDone(); 207 }); 208 keygenjob->start(args); 209 QSignalSpy spy (this, SIGNAL(asyncDone())); 210 QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT)); 211 212 /* Then try to create a request. */ 213 auto job = openpgp()->wksPublishJob(); 214 connect(job, &WKSPublishJob::result, this, 215 [this] (Error err, QByteArray out, QByteArray, QString, Error) { 216 QVERIFY(!err); 217 Q_EMIT asyncDone(); 218 const QString outstr = QString(out); 219 QVERIFY(outstr.contains( 220 QStringLiteral("-----BEGIN PGP PUBLIC KEY BLOCK-----"))); 221 QVERIFY(outstr.contains( 222 QStringLiteral("Content-Type: application/pgp-keys"))); 223 QVERIFY(outstr.contains( 224 QStringLiteral("From: " TEST_ADDRESS))); 225 }); 226 job->startCreate(fpr.constData(), QLatin1String(TEST_ADDRESS)); 227 QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT)); 228 } 229 testWKSPublishReceive()230 void testWKSPublishReceive() { 231 if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < "2.0.16") { 232 /* Not supported */ 233 return; 234 } 235 auto importjob = openpgp()->importJob(); 236 connect(importjob, &ImportJob::result, this, 237 [this](ImportResult result, QString, Error) 238 { 239 QVERIFY(!result.error()); 240 QVERIFY(!result.imports().empty()); 241 QVERIFY(result.numSecretKeysImported()); 242 Q_EMIT asyncDone(); 243 }); 244 importjob->start(QByteArray(testSecKey)); 245 QSignalSpy spy (this, SIGNAL(asyncDone())); 246 QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT)); 247 248 /* Get a response. */ 249 auto job = openpgp()->wksPublishJob(); 250 connect(job, &WKSPublishJob::result, this, 251 [this] (Error err, QByteArray out, QByteArray, QString, Error) { 252 QVERIFY(!err); 253 Q_EMIT asyncDone(); 254 const QString outstr = QString(out); 255 QVERIFY(outstr.contains( 256 QStringLiteral("-----BEGIN PGP MESSAGE-----"))); 257 QVERIFY(outstr.contains( 258 QStringLiteral("Content-Type: multipart/encrypted;"))); 259 QVERIFY(outstr.contains( 260 QStringLiteral("From: " TEST_ADDRESS))); 261 }); 262 job->startReceive(QByteArray(testResponse)); 263 QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT)); 264 } 265 initTestCase()266 void initTestCase() 267 { 268 QGpgMETest::initTestCase(); 269 const QString gpgHome = qgetenv("GNUPGHOME"); 270 qputenv("GNUPGHOME", mDir.path().toUtf8()); 271 QVERIFY(mDir.isValid()); 272 QFile agentConf(mDir.path() + QStringLiteral("/gpg-agent.conf")); 273 QVERIFY(agentConf.open(QIODevice::WriteOnly)); 274 agentConf.write("allow-loopback-pinentry"); 275 agentConf.close(); 276 } 277 private: 278 QTemporaryDir mDir; 279 }; 280 281 QTEST_MAIN(WKSPublishTest) 282 283 #include "t-wkspublish.moc" 284