Browse Source

Merge pull request #5642

17005bc [Qt] add payment request unit test for non matching networks (Philip Kaufmann)
080da96 [Qt] prepare paymentservertests for new unit tests (Philip Kaufmann)
0.13
Wladimir J. van der Laan 10 years ago
parent
commit
30a5b5fa7a
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 15
      src/qt/paymentserver.cpp
  2. 3
      src/qt/paymentserver.h
  3. 76
      src/qt/test/paymentrequestdata.h
  4. 56
      src/qt/test/paymentservertests.cpp

15
src/qt/paymentserver.cpp

@ -521,8 +521,7 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins
const payments::PaymentDetails& details = request.getDetails(); const payments::PaymentDetails& details = request.getDetails();
// Payment request network matches client network? // Payment request network matches client network?
if (details.network() != Params().NetworkIDString()) if (!verifyNetwork(request.getDetails())) {
{
emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."), emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
CClientUIInterface::MSG_ERROR); CClientUIInterface::MSG_ERROR);
@ -745,3 +744,15 @@ void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
// currently we don't futher process or store the paymentACK message // currently we don't futher process or store the paymentACK message
emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL); emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
} }
bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails)
{
bool fVerified = requestDetails.network() == Params().NetworkIDString();
if (!fVerified) {
qWarning() << QString("PaymentServer::%1: Payment request network \"%2\" doesn't match client network \"%3\".")
.arg(__func__)
.arg(QString::fromStdString(requestDetails.network()))
.arg(QString::fromStdString(Params().NetworkIDString()));
}
return fVerified;
}

3
src/qt/paymentserver.h

@ -91,6 +91,9 @@ public:
// This is now public, because we use it in paymentservertests.cpp // This is now public, because we use it in paymentservertests.cpp
static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request); static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request);
// Verify that the payment request network matches the client network
static bool verifyNetwork(const payments::PaymentDetails& requestDetails);
signals: signals:
// Fired when a valid payment request is received // Fired when a valid payment request is received
void receivedPaymentRequest(SendCoinsRecipient); void receivedPaymentRequest(SendCoinsRecipient);

76
src/qt/test/paymentrequestdata.h

@ -6,16 +6,16 @@
// Data for paymentservertests.cpp // Data for paymentservertests.cpp
// //
// Base64/DER-encoded fake certificate authority certificate. // Base64/DER-encoded fake certificate authority certificates.
// Convert pem to base64/der with: // Convert pem to base64/der with:
// cat file.pem | openssl x509 -inform PEM -outform DER | openssl enc -base64 // openssl x509 -in cert.pem -inform PEM -outform DER | openssl enc -base64
//
// Serial Number: 10302349811211485352 (0x8ef94c91b112c0a8) // Serial Number: 10302349811211485352 (0x8ef94c91b112c0a8)
// Issuer: CN=PaymentRequest Test CA // Issuer: CN=PaymentRequest Test CA
// Subject: CN=PaymentRequest Test CA // Subject: CN=PaymentRequest Test CA
// Not Valid After : Dec 8 16:37:24 2022 GMT // Not Valid After : Dec 8 16:37:24 2022 GMT
// //
const char* caCert_BASE64 = const char* caCert1_BASE64 =
"\ "\
MIIB0DCCATmgAwIBAgIJAI75TJGxEsCoMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\ MIIB0DCCATmgAwIBAgIJAI75TJGxEsCoMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\
BAMTFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTIxMjEwMTYzNzI0WhcNMjIx\ BAMTFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTIxMjEwMTYzNzI0WhcNMjIx\
@ -29,11 +29,36 @@ RtQcf0AJ9olzUMY4syehxbzUJP6aeXhZEYiMvdvcv9D55clq6+WLLlNT3jBgAaVn\
p3waRjPD4bUX3nv+ojz5s4puw7Qq5QUZlhGsMzPvwDGCmZkL\ p3waRjPD4bUX3nv+ojz5s4puw7Qq5QUZlhGsMzPvwDGCmZkL\
"; ";
// Serial Number: f0:da:97:e4:38:d7:64:16
// Issuer: CN=PaymentRequest Test CA
// Subject: CN=PaymentRequest Test CA
// Not Valid After : Jan 8 18:21:06 2025 GMT
//
const char* caCert2_BASE64 =
"\
MIIC1TCCAb2gAwIBAgIJAPDal+Q412QWMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNV\
BAMMFlBheW1lbnRSZXF1ZXN0IFRlc3QgQ0EwHhcNMTUwMTExMTgyMTA2WhcNMjUw\
MTA4MTgyMTA2WjAhMR8wHQYDVQQDDBZQYXltZW50UmVxdWVzdCBUZXN0IENBMIIB\
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1S9wVLfTplJuT/1OaaBgl/Mb\
I392v8S9kHbzYz7B4OTMslaO7piz0v3SO3TKMh0dswjiRdHrIgpO7XdIUQiU/ugg\
xDw0kuNehfz1ycaGedlFFtFHTNXqLyIUF3dlwHhQwaomM6RXoJmxLny5BhYHEcmk\
yWwr3Cdjd9gAZpblugVJB9C1e40uyL8ao4PHdLzOqO27iSe6riP8SwwisJZEbMaz\
AZpgNEEMbIXPJEFvm5HTRXSMtQCOTSZYMFF0M2yrtmlECnz7hWP19b9bcoDzZQB4\
ylIsFG/7q2jV7MC/e2STZv+niJiHL08RUdoFpAgzaxMgqj63C7B55HgNDNHJYQID\
AQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBGejPxLxj9\
+crv6gUeEBMZPiUx7pUgcI22Wm5yymP96B4fwI3Y0DBehq20d76vbWGPN17Z6pH3\
ge7PVY1SYqXtS6hXTo4olCm/BZADli+2Bs2xCiaa+Ltve4ufVej+bKJXN/YnrhvO\
Kq+klQkuuHywU+GJV/NQeBqToIrSOBgi477NgLFCCCmmx2QWsxHoCFGfuRCBVseT\
z2k/tMuALCDXGeZBRPTsGHu1y4cj84swAeoDK5QSQcI+Ub7GKc+zkoj02sdDLiMo\
3wokYPcIy47oclhmb4xubHc+y7nF610yZBoC/zgbhbawnZ65hDDWkdQ/SVAnWZD7\
9PFfmNnYPTQH\
";
// //
// This payment request validates directly against the // This payment request validates directly against the
// above certificate authority. // caCert1 certificate authority.
// //
const char* paymentrequest1_BASE64 = const char* paymentrequest1_cert1_BASE64 =
"\ "\
Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\ Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\
BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMjEyMTAx\ BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMjEyMTAx\
@ -55,7 +80,7 @@ SiWVbw0tX/68iSQEGGfh9n6ee/8Myb3ICdw=\
// //
// Signed, but expired, merchant cert in the request // Signed, but expired, merchant cert in the request
// //
const char* paymentrequest2_BASE64 = const char* paymentrequest2_cert1_BASE64 =
"\ "\
Egt4NTA5K3NoYTI1NhrsAwrpAzCCAeUwggFOoAMCAQICAQMwDQYJKoZIhvcNAQEL\ Egt4NTA5K3NoYTI1NhrsAwrpAzCCAeUwggFOoAMCAQICAQMwDQYJKoZIhvcNAQEL\
BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzAyMjMy\ BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzAyMjMy\
@ -75,9 +100,9 @@ tejrSPOBNSJ3Mi/q5u2Yl4gJZY2b\
"; ";
// //
// 10-long chain, all intermediates valid // 10-long certificate chain, all intermediates valid
// //
const char* paymentrequest3_BASE64 = const char* paymentrequest3_cert1_BASE64 =
"\ "\
Egt4NTA5K3NoYTI1Nhq8JAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\ Egt4NTA5K3NoYTI1Nhq8JAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\
BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\ BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\
@ -184,9 +209,9 @@ chhR/aHOuEMTxmc12K4rNlgYtHCsxLP9zd+6u0cva3TucZ6EzS8PKEib/+r12/52\
"; ";
// //
// Long chain, with an invalid (expired) cert in the middle // Long certificate chain, with an expired certificate in the middle
// //
const char* paymentrequest4_BASE64 = const char* paymentrequest4_cert1_BASE64 =
"\ "\
Egt4NTA5K3NoYTI1NhqeJAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\ Egt4NTA5K3NoYTI1NhqeJAr/AzCCAfswggFkoAMCAQICAQEwDQYJKoZIhvcNAQEL\
BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\ BQAwPzEUMBIGA1UEAwwLdGVzdGNhOC5vcmcxJzAlBgNVBAoMHlBheW1lbnQgUmVx\
@ -291,7 +316,10 @@ HXQjsfdR58qZQS9CS5DAtRUf0R8+43/wijO/hb49VNaNXmY+/cPHMkahP2aV3tZi\
FAyZblLik9A7ZvF+UsjeFQiHB5wzWQvbqk5wQ4yabHIXoYv/E0q+eQ==\ FAyZblLik9A7ZvF+UsjeFQiHB5wzWQvbqk5wQ4yabHIXoYv/E0q+eQ==\
"; ";
const char* paymentrequest5_BASE64 = //
// Validly signed, but by a CA not in our root CA list
//
const char* paymentrequest5_cert1_BASE64 =
"\ "\
Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\ Egt4NTA5K3NoYTI1NhrxAwruAzCCAeowggFToAMCAQICAQEwDQYJKoZIhvcNAQEL\
BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzA0MTkx\ BQAwITEfMB0GA1UEAxMWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xMzA0MTkx\
@ -309,3 +337,27 @@ ssymvca1S/1KeM3n8Ydi2fi1JUzAAr59xPvNJRUeqCLP9upHn5z7br3P12Oz9A20\
5/4wL4ClPRPVnOHgij0bEg+y0tGESqmF1rfOfXDszlo2U92wCxS07kq79YAZJ1Zo\ 5/4wL4ClPRPVnOHgij0bEg+y0tGESqmF1rfOfXDszlo2U92wCxS07kq79YAZJ1Zo\
XYh860/Q4wvc7lfiTe+dXBzPKAKhMy91yETY\ XYh860/Q4wvc7lfiTe+dXBzPKAKhMy91yETY\
"; ";
//
// Contains a testnet paytoaddress, so payment request network doesn't match client network
//
const char* paymentrequest1_cert2_BASE64 =
"\
Egt4NTA5K3NoYTI1NhrQBArNBDCCAkkwggExoAMCAQICAQEwDQYJKoZIhvcNAQEL\
BQAwITEfMB0GA1UEAwwWUGF5bWVudFJlcXVlc3QgVGVzdCBDQTAeFw0xNTAxMTEx\
ODIxMDhaFw0yNTAxMDgxODIxMDhaMCExHzAdBgNVBAMMFlBheW1lbnRSZXF1ZXN0\
IFRlc3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMsZqzkzeBGo+i2N\
mUak3Ciodr1V7S062VOy7N0OQYNDQHYkgDFAUET7cEb5VJaHPv5m3ppTBpU9xBcf\
wbHHUt4VjA+mhRmYrl1khjvZM+X8kEqvWn20BtcM9R6r0yIYec8UERDDHBleL/P8\
RkxEnVLjYTV9zigCXfMsgYb3EQShAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJ\
KoZIhvcNAQELBQADggEBABUJpl3QCqsoDSxAsQdV6zKT4VGV76AzoGj7etQsQY+r\
+S26VfWh/fMobEzuxFChr0USgLJ6FoK78hAtoZvt1lrye9yqFv/ig3WLWsJKWHHb\
3RT6oR03CIwZXFSUasi08QDVLxafwsU5OMcPLucF3a1lRL1ccYrNgVCCx1+X7Bos\
tIgDGRQQ4AyoHTcfVd2hEGeUv7k14mOxFsAp6851yosHq9Q2kwmdH+rHEJbjof87\
yyKLagc4owyXBZYkQmkeHWCNqnuRmO5vUsfVb0UUrkD64o7Th/NjwooA7SCiUXl6\
dfygT1b7ggpx7GC+sP2DsIM47IAZ55drjqX5u2f+Ba0iPQoEdGVzdBIhCIDWwowE\
Ehl2qRQErGqUUwSsaMpDvWIaGnJGNQqi8oisGNeMy6UFKgxKdXN0IFRlc3Rpbmcq\
gAFwThsozZxkZxzCn4R8WxNiLFV6m0ye9fEtSbolfaW+EjBMpO03lr/dwNnrclhg\
ew+A05xfZztrAt16XKEY7qKJ/eY2nLd0fVAIu/nIt+7/VYVXT83zLrWc150aRS7W\
AdJbL3JOJLs6Eyp5zrPbfI8faRttFAdONKDrJgIpuW1E3g==\
";

56
src/qt/test/paymentservertests.cpp

@ -65,38 +65,44 @@ void PaymentServerTests::paymentServerTests()
OptionsModel optionsModel; OptionsModel optionsModel;
PaymentServer* server = new PaymentServer(NULL, false); PaymentServer* server = new PaymentServer(NULL, false);
X509_STORE* caStore = X509_STORE_new(); X509_STORE* caStore = X509_STORE_new();
X509_STORE_add_cert(caStore, parse_b64der_cert(caCert_BASE64)); X509_STORE_add_cert(caStore, parse_b64der_cert(caCert1_BASE64));
PaymentServer::LoadRootCAs(caStore); PaymentServer::LoadRootCAs(caStore);
server->setOptionsModel(&optionsModel); server->setOptionsModel(&optionsModel);
server->uiReady(); server->uiReady();
// Now feed PaymentRequests to server, and observe signals it produces: std::vector<unsigned char> data;
std::vector<unsigned char> data = DecodeBase64(paymentrequest1_BASE64); SendCoinsRecipient r;
SendCoinsRecipient r = handleRequest(server, data);
QString merchant; QString merchant;
// Now feed PaymentRequests to server, and observe signals it produces
// This payment request validates directly against the
// caCert1 certificate authority:
data = DecodeBase64(paymentrequest1_cert1_BASE64);
r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant); r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString("testmerchant.org")); QCOMPARE(merchant, QString("testmerchant.org"));
// Version of the above, with an expired certificate: // Signed, but expired, merchant cert in the request:
data = DecodeBase64(paymentrequest2_BASE64); data = DecodeBase64(paymentrequest2_cert1_BASE64);
r = handleRequest(server, data); r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant); r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString("")); QCOMPARE(merchant, QString(""));
// Long certificate chain: // 10-long certificate chain, all intermediates valid:
data = DecodeBase64(paymentrequest3_BASE64); data = DecodeBase64(paymentrequest3_cert1_BASE64);
r = handleRequest(server, data); r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant); r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString("testmerchant8.org")); QCOMPARE(merchant, QString("testmerchant8.org"));
// Long certificate chain, with an expired certificate in the middle: // Long certificate chain, with an expired certificate in the middle:
data = DecodeBase64(paymentrequest4_BASE64); data = DecodeBase64(paymentrequest4_cert1_BASE64);
r = handleRequest(server, data); r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant); r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString("")); QCOMPARE(merchant, QString(""));
// Validly signed, but by a CA not in our root CA list: // Validly signed, but by a CA not in our root CA list:
data = DecodeBase64(paymentrequest5_BASE64); data = DecodeBase64(paymentrequest5_cert1_BASE64);
r = handleRequest(server, data); r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant); r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString("")); QCOMPARE(merchant, QString(""));
@ -104,11 +110,39 @@ void PaymentServerTests::paymentServerTests()
// Try again with no root CA's, verifiedMerchant should be empty: // Try again with no root CA's, verifiedMerchant should be empty:
caStore = X509_STORE_new(); caStore = X509_STORE_new();
PaymentServer::LoadRootCAs(caStore); PaymentServer::LoadRootCAs(caStore);
data = DecodeBase64(paymentrequest1_BASE64); data = DecodeBase64(paymentrequest1_cert1_BASE64);
r = handleRequest(server, data); r = handleRequest(server, data);
r.paymentRequest.getMerchant(caStore, merchant); r.paymentRequest.getMerchant(caStore, merchant);
QCOMPARE(merchant, QString("")); QCOMPARE(merchant, QString(""));
// Load second root certificate
caStore = X509_STORE_new();
X509_STORE_add_cert(caStore, parse_b64der_cert(caCert2_BASE64));
PaymentServer::LoadRootCAs(caStore);
QByteArray byteArray;
// For the tests below we just need the payment request data from
// paymentrequestdata.h parsed + stored in r.paymentRequest.
//
// These tests require us to bypass the following normal client execution flow
// shown below to be able to explicitly just trigger a certain condition!
//
// handleRequest()
// -> PaymentServer::eventFilter()
// -> PaymentServer::handleURIOrFile()
// -> PaymentServer::readPaymentRequestFromFile()
// -> PaymentServer::processPaymentRequest()
// Contains a testnet paytoaddress, so payment request network doesn't match client network:
data = DecodeBase64(paymentrequest1_cert2_BASE64);
byteArray = QByteArray((const char*)&data[0], data.size());
r.paymentRequest.parse(byteArray);
// Ensure the request is initialized, because network "main" is default, even for
// uninizialized payment requests and that will fail our test here.
QVERIFY(r.paymentRequest.IsInitialized());
QCOMPARE(PaymentServer::verifyNetwork(r.paymentRequest.getDetails()), false);
// Just get some random data big enough to trigger BIP70 DoS protection // Just get some random data big enough to trigger BIP70 DoS protection
unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1]; unsigned char randData[BIP70_MAX_PAYMENTREQUEST_SIZE + 1];
GetRandBytes(randData, sizeof(randData)); GetRandBytes(randData, sizeof(randData));

Loading…
Cancel
Save