Skip to content

Commit 85973bc

Browse files
committed
When BIP70 is disabled, get PaymentRequest merchant using string search
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.
1 parent 1985c4e commit 85973bc

File tree

1 file changed

+48
-10
lines changed

1 file changed

+48
-10
lines changed

src/qt/transactiondesc.cpp

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,36 @@ QString TransactionDesc::FormatTxStatus(const interfaces::WalletTx& wtx, const i
4949
}
5050
}
5151

52+
#ifndef ENABLE_BIP70
53+
// Takes an encoded PaymentRequest as a string and tries to find the Common Name of the X.509 certificate
54+
// used to sign the PaymentRequest.
55+
bool GetPaymentRequestMerchant(const std::string& pr, QString& merchant)
56+
{
57+
// Search for the supported pki type strings
58+
if (pr.find(std::string({0x12, 0x0b}) + "x509+sha256") != std::string::npos || pr.find(std::string({0x12, 0x09}) + "x509+sha1") != std::string::npos) {
59+
// We want the common name of the Subject of the cert. This should be the second occurrence
60+
// of the bytes 0x0603550403. The first occurrence of those is the common name of the issuer.
61+
// After those bytes will be either 0x13 or 0x0C, then length, then either the ascii or utf8
62+
// string with the common name which is the merchant name
63+
size_t cn_pos = pr.find({0x06, 0x03, 0x55, 0x04, 0x03});
64+
if (cn_pos != std::string::npos) {
65+
cn_pos = pr.find({0x06, 0x03, 0x55, 0x04, 0x03}, cn_pos + 5);
66+
if (cn_pos != std::string::npos) {
67+
cn_pos += 5;
68+
if (pr[cn_pos] == 0x13 || pr[cn_pos] == 0x0c) {
69+
cn_pos++; // Consume the type
70+
int str_len = pr[cn_pos];
71+
cn_pos++; // Consume the string length
72+
merchant = QString::fromUtf8(pr.data() + cn_pos, str_len);
73+
return true;
74+
}
75+
}
76+
}
77+
}
78+
return false;
79+
}
80+
#endif
81+
5282
QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wallet, TransactionRecord *rec, int unit)
5383
{
5484
int numBlocks;
@@ -255,26 +285,34 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
255285
strHTML += "<b>" + tr("Output index") + ":</b> " + QString::number(rec->getOutputIndex()) + "<br>";
256286

257287
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
258-
for (const std::pair<std::string, std::string>& r : orderForm)
288+
for (const std::pair<std::string, std::string>& r : orderForm) {
259289
if (r.first == "Message")
260290
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
261291

262-
#ifdef ENABLE_BIP70
263-
//
264-
// PaymentRequest info:
265-
//
266-
for (const std::pair<std::string, std::string>& r : orderForm)
267-
{
292+
//
293+
// PaymentRequest info:
294+
//
268295
if (r.first == "PaymentRequest")
269296
{
297+
QString merchant;
298+
#ifdef ENABLE_BIP70
270299
PaymentRequestPlus req;
271300
req.parse(QByteArray::fromRawData(r.second.data(), r.second.size()));
272-
QString merchant;
273-
if (req.getMerchant(PaymentServer::getCertStore(), merchant))
301+
if (!req.getMerchant(PaymentServer::getCertStore(), merchant)) {
302+
merchant.clear();
303+
}
304+
#else
305+
if (!GetPaymentRequestMerchant(r.second, merchant)) {
306+
merchant.clear();
307+
} else {
308+
merchant += tr(" (Certificate was not verified)");
309+
}
310+
#endif
311+
if (!merchant.isNull()) {
274312
strHTML += "<b>" + tr("Merchant") + ":</b> " + GUIUtil::HtmlEscape(merchant) + "<br>";
313+
}
275314
}
276315
}
277-
#endif
278316

279317
if (wtx.is_coinbase)
280318
{

0 commit comments

Comments
 (0)