Merge #16852: gui: When BIP70 is disabled, get PaymentRequest merchant using string search

85973bcc44 When BIP70 is disabled, get PaymentRequest merchant using string search (Andrew Chow)

Pull request description:

  The merchant name is stored in the X.509 certificate embedded in a PaymentRequest. Use some string searching to locate it so that it can be shown to the user in the transaction details when BIP70 support was not configured.

  An additional notice is added to the merchant string that indicates the certificate was not verified. When BIP70 is enabled, the certificate would be verified and the merchant name not shown if the certificate was invalid.

ACKs for top commit:
  laanwj:
    ACK 85973bcc44

Tree-SHA512: 50fdb60d418e2f9eb65a4b52477be16189f00bfc30493adb27d9fb62100fd5bca33b98b8db6caa8485db424838d3b7a1da802c14ff4917943464401f47391616
This commit is contained in:
Wladimir J. van der Laan 2019-10-01 11:53:31 +02:00
commit cd6e9b33a6
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D

View file

@ -49,6 +49,36 @@ QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const i
}
}
#ifndef ENABLE_BIP70
// Takes an encoded PaymentRequest as a string and tries to find the Common Name of the X.509 certificate
// used to sign the PaymentRequest.
bool GetPaymentRequestMerchant(const std::string& pr, QString& merchant)
{
// Search for the supported pki type strings
if (pr.find(std::string({0x12, 0x0b}) + "x509+sha256") != std::string::npos || pr.find(std::string({0x12, 0x09}) + "x509+sha1") != std::string::npos) {
// We want the common name of the Subject of the cert. This should be the second occurrence
// of the bytes 0x0603550403. The first occurrence of those is the common name of the issuer.
// After those bytes will be either 0x13 or 0x0C, then length, then either the ascii or utf8
// string with the common name which is the merchant name
size_t cn_pos = pr.find({0x06, 0x03, 0x55, 0x04, 0x03});
if (cn_pos != std::string::npos) {
cn_pos = pr.find({0x06, 0x03, 0x55, 0x04, 0x03}, cn_pos + 5);
if (cn_pos != std::string::npos) {
cn_pos += 5;
if (pr[cn_pos] == 0x13 || pr[cn_pos] == 0x0c) {
cn_pos++; // Consume the type
int str_len = pr[cn_pos];
cn_pos++; // Consume the string length
merchant = QString::fromUtf8(pr.data() + cn_pos, str_len);
return true;
}
}
}
}
return false;
}
#endif
QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit)
{
int numBlocks;
@ -255,26 +285,34 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
for (const std::pair<std::string, std::string>& r : orderForm)
for (const std::pair<std::string, std::string>& r : orderForm) {
if (r.first == "Message")
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
#ifdef ENABLE_BIP70
//
// PaymentRequest info:
//
for (const std::pair<std::string, std::string>& r : orderForm)
{
//
// PaymentRequest info:
//
if (r.first == "PaymentRequest")
{
QString merchant;
#ifdef ENABLE_BIP70
PaymentRequestPlus req;
req.parse(QByteArray::fromRawData(r.second.data(), r.second.size()));
QString merchant;
if (req.getMerchant(PaymentServer::getCertStore(), merchant))
if (!req.getMerchant(PaymentServer::getCertStore(), merchant)) {
merchant.clear();
}
#else
if (!GetPaymentRequestMerchant(r.second, merchant)) {
merchant.clear();
} else {
merchant += tr(" (Certificate was not verified)");
}
#endif
if (!merchant.isNull()) {
strHTML += "<b>" + tr("Merchant") + ":</b> " + GUIUtil::HtmlEscape(merchant) + "<br>";
}
}
}
#endif
if (wtx.is_coinbase)
{