LCOV - code coverage report
Current view: top level - src/qt/test - paymentservertests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 98 98 100.0 %
Date: 2015-10-12 22:39:14 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2009-2014 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include "paymentservertests.h"
       6             : 
       7             : #include "optionsmodel.h"
       8             : #include "paymentrequestdata.h"
       9             : 
      10             : #include "amount.h"
      11             : #include "random.h"
      12             : #include "script/script.h"
      13             : #include "script/standard.h"
      14             : #include "util.h"
      15             : #include "utilstrencodings.h"
      16             : 
      17             : #include <openssl/x509.h>
      18             : #include <openssl/x509_vfy.h>
      19             : 
      20             : #include <QFileOpenEvent>
      21             : #include <QTemporaryFile>
      22             : 
      23           2 : X509 *parse_b64der_cert(const char* cert_data)
      24             : {
      25           2 :     std::vector<unsigned char> data = DecodeBase64(cert_data);
      26           4 :     assert(data.size() > 0);
      27           2 :     const unsigned char* dptr = &data[0];
      28           4 :     X509 *cert = d2i_X509(NULL, &dptr, data.size());
      29           2 :     assert(cert);
      30           4 :     return cert;
      31             : }
      32             : 
      33             : //
      34             : // Test payment request handling
      35             : //
      36             : 
      37           6 : static SendCoinsRecipient handleRequest(PaymentServer* server, std::vector<unsigned char>& data)
      38             : {
      39           6 :     RecipientCatcher sigCatcher;
      40             :     QObject::connect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
      41           6 :         &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));
      42             : 
      43             :     // Write data to a temp file:
      44          12 :     QTemporaryFile f;
      45             :     f.open();
      46          12 :     f.write((const char*)&data[0], data.size());
      47           6 :     f.close();
      48             : 
      49             :     // Create a QObject, install event filter from PaymentServer
      50             :     // and send a file open event to the object
      51          12 :     QObject object;
      52           6 :     object.installEventFilter(server);
      53          12 :     QFileOpenEvent event(f.fileName());
      54             :     // If sending the event fails, this will cause sigCatcher to be empty,
      55             :     // which will lead to a test failure anyway.
      56           6 :     QCoreApplication::sendEvent(&object, &event);
      57             : 
      58             :     QObject::disconnect(server, SIGNAL(receivedPaymentRequest(SendCoinsRecipient)),
      59           6 :         &sigCatcher, SLOT(getRecipient(SendCoinsRecipient)));
      60             : 
      61             :     // Return results from sigCatcher
      62          12 :     return sigCatcher.recipient;
      63             : }
      64             : 
      65           1 : void PaymentServerTests::paymentServerTests()
      66             : {
      67           1 :     SelectParams(CBaseChainParams::MAIN);
      68           1 :     OptionsModel optionsModel;
      69           1 :     PaymentServer* server = new PaymentServer(NULL, false);
      70           1 :     X509_STORE* caStore = X509_STORE_new();
      71           1 :     X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
      72           1 :     PaymentServer::LoadRootCAs(caStore);
      73           1 :     server->setOptionsModel(&optionsModel);
      74           1 :     server->uiReady();
      75             : 
      76             :     std::vector<unsigned char> data;
      77           2 :     SendCoinsRecipient r;
      78           1 :     QString merchant;
      79             : 
      80             :     // Now feed PaymentRequests to server, and observe signals it produces
      81             : 
      82             :     // This payment request validates directly against the
      83             :     // caCert1 certificate authority:
      84           2 :     data = DecodeBase64(paymentrequest1_cert1_BASE64);
      85           1 :     r = handleRequest(server, data);
      86           1 :     r.paymentRequest.getMerchant(caStore, merchant);
      87           1 :     QCOMPARE(merchant, QString("testmerchant.org"));
      88             : 
      89             :     // Signed, but expired, merchant cert in the request:
      90           2 :     data = DecodeBase64(paymentrequest2_cert1_BASE64);
      91           1 :     r = handleRequest(server, data);
      92           1 :     r.paymentRequest.getMerchant(caStore, merchant);
      93           1 :     QCOMPARE(merchant, QString(""));
      94             : 
      95             :     // 10-long certificate chain, all intermediates valid:
      96           2 :     data = DecodeBase64(paymentrequest3_cert1_BASE64);
      97           1 :     r = handleRequest(server, data);
      98           1 :     r.paymentRequest.getMerchant(caStore, merchant);
      99           1 :     QCOMPARE(merchant, QString("testmerchant8.org"));
     100             : 
     101             :     // Long certificate chain, with an expired certificate in the middle:
     102           2 :     data = DecodeBase64(paymentrequest4_cert1_BASE64);
     103           1 :     r = handleRequest(server, data);
     104           1 :     r.paymentRequest.getMerchant(caStore, merchant);
     105           1 :     QCOMPARE(merchant, QString(""));
     106             : 
     107             :     // Validly signed, but by a CA not in our root CA list:
     108           2 :     data = DecodeBase64(paymentrequest5_cert1_BASE64);
     109           1 :     r = handleRequest(server, data);
     110           1 :     r.paymentRequest.getMerchant(caStore, merchant);
     111           1 :     QCOMPARE(merchant, QString(""));
     112             : 
     113             :     // Try again with no root CA's, verifiedMerchant should be empty:
     114           1 :     caStore = X509_STORE_new();
     115           1 :     PaymentServer::LoadRootCAs(caStore);
     116           2 :     data = DecodeBase64(paymentrequest1_cert1_BASE64);
     117           1 :     r = handleRequest(server, data);
     118           1 :     r.paymentRequest.getMerchant(caStore, merchant);
     119           1 :     QCOMPARE(merchant, QString(""));
     120             : 
     121             :     // Load second root certificate
     122           1 :     caStore = X509_STORE_new();
     123           1 :     X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64));
     124           1 :     PaymentServer::LoadRootCAs(caStore);
     125             : 
     126           1 :     QByteArray byteArray;
     127             : 
     128             :     // For the tests below we just need the payment request data from
     129             :     // paymentrequestdata.h parsed + stored in r.paymentRequest.
     130             :     //
     131             :     // These tests require us to bypass the following normal client execution flow
     132             :     // shown below to be able to explicitly just trigger a certain condition!
     133             :     //
     134             :     // handleRequest()
     135             :     // -> PaymentServer::eventFilter()
     136             :     //   -> PaymentServer::handleURIOrFile()
     137             :     //     -> PaymentServer::readPaymentRequestFromFile()
     138             :     //       -> PaymentServer::processPaymentRequest()
     139             : 
     140             :     // Contains a testnet paytoaddress, so payment request network doesn't match client network:
     141           2 :     data = DecodeBase64(paymentrequest1_cert2_BASE64);
     142           2 :     byteArray = QByteArray((const char*)&data[0], data.size());
     143           1 :     r.paymentRequest.parse(byteArray);
     144             :     // Ensure the request is initialized, because network "main" is default, even for
     145             :     // uninizialized payment requests and that will fail our test here.
     146           1 :     QVERIFY(r.paymentRequest.IsInitialized());
     147           1 :     QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false);
     148             : 
     149             :     // Expired payment request (expires is set to 1 = 1970-01-01 00:00:01):
     150           2 :     data = DecodeBase64(paymentrequest2_cert2_BASE64);
     151           2 :     byteArray = QByteArray((const char*)&data[0], data.size());
     152           1 :     r.paymentRequest.parse(byteArray);
     153             :     // Ensure the request is initialized
     154           1 :     QVERIFY(r.paymentRequest.IsInitialized());
     155             :     // compares 1 < GetTime() == false (treated as expired payment request)
     156           1 :     QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);
     157             : 
     158             :     // Unexpired payment request (expires is set to 0x7FFFFFFFFFFFFFFF = max. int64_t):
     159             :     // 9223372036854775807 (uint64), 9223372036854775807 (int64_t) and -1 (int32_t)
     160             :     // -1 is 1969-12-31 23:59:59 (for a 32 bit time values)
     161           2 :     data = DecodeBase64(paymentrequest3_cert2_BASE64);
     162           2 :     byteArray = QByteArray((const char*)&data[0], data.size());
     163           1 :     r.paymentRequest.parse(byteArray);
     164             :     // Ensure the request is initialized
     165           1 :     QVERIFY(r.paymentRequest.IsInitialized());
     166             :     // compares 9223372036854775807 < GetTime() == false (treated as unexpired payment request)
     167           1 :     QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), false);
     168             : 
     169             :     // Unexpired payment request (expires is set to 0x8000000000000000 > max. int64_t, allowed uint64):
     170             :     // 9223372036854775808 (uint64), -9223372036854775808 (int64_t) and 0 (int32_t)
     171             :     // 0 is 1970-01-01 00:00:00 (for a 32 bit time values)
     172           2 :     data = DecodeBase64(paymentrequest4_cert2_BASE64);
     173           2 :     byteArray = QByteArray((const char*)&data[0], data.size());
     174           1 :     r.paymentRequest.parse(byteArray);
     175             :     // Ensure the request is initialized
     176           1 :     QVERIFY(r.paymentRequest.IsInitialized());
     177             :     // compares -9223372036854775808 < GetTime() == true (treated as expired payment request)
     178           1 :     QCOMPARE(PaymentServer::verifyExpired(r.paymentRequest.getDetails()), true);
     179             : 
     180             :     // Test BIP70 DoS protection:
     181           1 :     unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1];
     182           1 :     GetRandBytes(randData, sizeof(randData));
     183             :     // Write data to a temp file:
     184           2 :     QTemporaryFile tempFile;
     185             :     tempFile.open();
     186           1 :     tempFile.write((const char*)randData, sizeof(randData));
     187           1 :     tempFile.close();
     188             :     // compares 50001 <= BIP70_MAX_PAYMENTREQUEST_SIZE == false
     189           1 :     QCOMPARE(PaymentServer::verifySize(tempFile.size()), false);
     190             : 
     191             :     // Payment request with amount overflow (amount is set to 21000001 BTC):
     192           2 :     data = DecodeBase64(paymentrequest5_cert2_BASE64);
     193           2 :     byteArray = QByteArray((const char*)&data[0], data.size());
     194           1 :     r.paymentRequest.parse(byteArray);
     195             :     // Ensure the request is initialized
     196           1 :     QVERIFY(r.paymentRequest.IsInitialized());
     197             :     // Extract address and amount from the request
     198           2 :     QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo();
     199           7 :     Q_FOREACH (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
     200             :         CTxDestination dest;
     201           1 :         if (ExtractDestination(sendingTo.first, dest))
     202           1 :             QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false);
     203             :     }
     204             : 
     205           2 :     delete server;
     206             : }
     207             : 
     208           6 : void RecipientCatcher::getRecipient(SendCoinsRecipient r)
     209             : {
     210           6 :     recipient = r;
     211           9 : }

Generated by: LCOV version 1.11