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)
This commit is contained in:
Wladimir J. van der Laan 2015-01-14 14:16:29 +01:00
commit 30a5b5fa7a
No known key found for this signature in database
GPG key ID: 74810B012346C9A6
4 changed files with 125 additions and 25 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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==\
";

View file

@ -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));