- extend PaymentRequestPlus::getMerchant to return status of payment request errors related to certificates/PKIs etc.
- do a real check for errors, which was missing until now, in PaymentServer::processPaymentRequest and also extend our tests in paymentservertests.cpp to not only rely on the content of "merchant" passed to getMerchant
- this explicitly treats insecure payment requests not as errors, as they are allowed as per BIP70
[Qt] log cert errors for payment requests and harden test-cases #5466
pull Diapolo wants to merge 1 commits into bitcoin:master from Diapolo:pr_harden_certchecks changing 5 files +39 −27-
Diapolo commented at 9:07 AM on December 12, 2014: none
-
Diapolo commented at 9:08 AM on December 12, 2014: none
Waiting for Travis to pass, but needs some review then. @gavinandresen @laanwj Mind looking at this?
-
Diapolo commented at 9:41 AM on December 12, 2014: none
This was the problem:
<pre> ********* Start testing of PaymentServerTests ********* Config: Using QTest library 4.6.4, Qt 4.6.4 PASS : PaymentServerTests::initTestCase() QDEBUG : PaymentServerTests::paymentServerTests() PaymentServer::initNetManager : No active proxy server found. QDEBUG : PaymentServerTests::paymentServerTests() PaymentServer::processPaymentRequest : Secure payment request from "testmerchant.org" QWARN : PaymentServerTests::paymentServerTests() PaymentRequestPlus::getMerchant : Payment request: certificate expired or not yet active: QSslCertificate( "3" , "3" , "LxHILx+N3qwVoAcCmQ5cyw==" , "" , "Expired Test Merchant" , QMap() , QDateTime("Sat Feb 23 21:26:43 2013") , QDateTime("Sun Feb 24 21:26:43 2013") ) FAIL! : PaymentServerTests::paymentServerTests() Compared values are not the same Loc: [qt/test/paymentservertests.cpp(87)] PASS : PaymentServerTests::cleanupTestCase() Totals: 2 passed, 1 failed, 0 skipped ********* Finished testing of PaymentServerTests ********* </pre>
Tried to fix by using QVERIFY instead of QCOMPARE, as the return value of getMerchant is a bit field.
Edit: WoW, we are still using Qt 4.6.4 for verifying and building in Travis!?
-
laanwj commented at 12:01 PM on December 12, 2014: member
Isn't this the same discussion we had before? Certificate problems should be logged, but not lead to rejection of the payment request or scary messages shown to the user. It just means that the payment request is unvalidated.
-
in src/qt/paymentrequestplus.h:None in 36e5ada1a1 outdated
12 | @@ -13,6 +13,17 @@ 13 | #include <QList> 14 | #include <QString> 15 | 16 | +// Used in getMerchant() to return state 17 | +enum GetMerchantStatus { 18 | + PR_NOTINITIALIZED = 0,
laanwj commented at 12:04 PM on December 12, 2014:Would be clearer as a plain enumeration instead of a bit field?
jonasschnelli commented at 7:36 PM on July 14, 2015:A bitfield would only make sense if flags can be combined. But IMO things like
PR_UNAUTHENTICATEDtogether withPR_AUTHENTICATEDdoes not make sense. Agree with @laanwj to use plain enumeration in this case.
Diapolo commented at 9:26 AM on July 16, 2015:@jonasschnelli Just to be sure, plain enum means I just don't init the values?
jonasschnelli commented at 6:50 PM on July 23, 2015:The
GetMerchantStatusis a bit mask where you can combine things. It's only a nit. But IMO combining a returned status in a bit mask is a bit wired.
Diapolo commented at 6:06 AM on July 24, 2015:Let me ask again, how do I make this so it's accepted. Is it just removing the init values in the enum? Hand me some code example ;).
Diapolo commented at 12:31 PM on December 12, 2014: none@laanwj You are not serious with your above comment? Current master currently doesn't even explicitly care whats going on if we have cert failures... I'm not sure but perhaps this could potentially be dangerous even. I'm doing my best to improve our code and it feel like this isn't wanted anymore...
laanwj commented at 12:34 PM on December 12, 2014: member@Diapolo It is dangerous if it is possible to make an invalid signature pass as authenticated merchant. Does that happen? If not it makes no sense. An attacker can just as well replace the payment request with an unsigned one as mess up the signature, so from a security perspective there is no reason to treat signature errors differently from unsigned payment requests.
in src/qt/paymentrequestplus.h:None in 36e5ada1a1 outdated
17 | +enum GetMerchantStatus { 18 | + PR_NOTINITIALIZED = 0, 19 | + PR_PKIERROR = (1U << 0), 20 | + PR_CERTERROR = (1U << 1), 21 | + PR_INSECURE = (1U << 2), 22 | + PR_SECURE = (1U << 3),
laanwj commented at 12:39 PM on December 12, 2014:Please use authenticated/unauthenticated instead of secure/insecure. If we treat certificate errors as 'unauthenticated' those two statuses are enough.
Diapolo commented at 2:24 PM on December 12, 2014:Will do, thanks.
Diapolo commented at 12:39 PM on December 12, 2014: noneIMHO the current behaviour can make invalid secure payment (invalid because of cert errors and authenticatedMerchant not set) requests to be treated like valid insecure payment requests, which is bad as they should be rejected directly!
Diapolo commented at 12:42 PM on December 12, 2014: noneFrom BIP70:
The recipient must verify the certificate chain according to [RFC5280] and reject the PaymentRequest if any validation failure occurs.https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#Certificates
laanwj commented at 12:46 PM on December 12, 2014: memberAs I said: Unauthenticated is unauthenticated, it doesn't matter from a security viewpoint if that's caused by an invalid signature ("cert errors") or not having a signature in the first place ("unsecure"). Both attacks, so stripping or corrupting the signature, require the same effort to pull off.
If getMerchant returns false in the case of errors, that's enough to signal that authentication was not successful and thus not show the payment request in green.
Also ping @mikehearn .
Diapolo commented at 12:48 PM on December 12, 2014: noneOur own protection here currently is a yellow background in the GUI and a tooltip, which sais this is an unverified payment request. Don't you think that could trick our users into a bad situation?
mikehearn commented at 12:50 PM on December 12, 2014: contributorYeah, we should be ignoring cert errors and treating the payment request as unsigned. Sounds like BIP70 doesn't say that explicitly, but IMHO it should. I should spend some time refreshing it and working on pp related stuff.
The rationale is pretty simple - if we want to introduce a new set of root CAs in future (e.g. that have different requirements from browser root store programs), then we don't want payment requests signed with the new CAs to trigger errors. It's better if they are just not shown as authenticated. In this way, we can do backwards compatible upgrades.
laanwj commented at 12:52 PM on December 12, 2014: member@diapolo As I'm now trying to communicate for the third time: those two cases are equivalent. No, it cannot trick the user into anything. An attacker can just as well present an unverified payment request as one with an invalid signature. Showing them differently does not add any extra security. It's security theater. A yellow payment request (which will not have an authenticated merchant) already means "be very careful, you're probably being tricked".
Diapolo commented at 12:58 PM on December 12, 2014: noneInvalid secure == valid insecure seems not right and is against current spec. If an attacker would be able to manipulate a payment request from a merchant to pay him instead of the merchant and the only precaution is that we treat that invalid secure payment request as a valid insecure one is good? If this is consensus I'm out and out of motivation also... sadly.
laanwj commented at 1:00 PM on December 12, 2014: memberAn attacker can manipulate the signed payment request into a valid insecure one that pays him just as easily. It would make more sense, even, as a user wouldn't expect that, especially if certificate failures were flagged differently.
Diapolo commented at 1:06 PM on December 12, 2014: noneThis needs at least a clarification in the BIP, also in terms of valid unverified payment requests, which have just set pki_type == "none", which is not the case for ones that should have been valid verified ones (but are treated like unverified ones).
mikehearn commented at 1:53 PM on December 12, 2014: contributorIf an attacker would be able to manipulate a payment request from a merchant to pay him instead of the merchant and the only precaution is that we treat that invalid secure payment request as a valid insecure one is good?
Yes, ultimately the only way we have to ensure users are secure against MITM attacks is to train users to expect signed requests. That's it. It's like SSL in that respect - if you can be a MITM then you can do SSL stripping attacks and unless the client knows to expect authentication, or the user checks for the padlock, you still win. The joys of backwards compatibility, huh!
Perhaps one day signed payment requests will be so common that we can actually show unsigned requests in some kind of warning, or red/yellow colour. But that would be very hard to accomplish. The PKI isn't suitable for everyone today. In future additional PKIs might make it so, but that's years off.
Diapolo commented at 1:59 PM on December 12, 2014: noneIf we show a warning and the users explicitly chooses to accept that, he can continue by using the invalid verified request as valid unverified request, what about that idea? That would at least be like with browsers and invalid SSL certs or SSL connection problems.
gavinandresen commented at 1:59 PM on December 12, 2014: contributorError-handling policy does NOT belong in that BIP; e.g. certificate errors will be handled differently in GUI apps than machine-to-machine scenarios.
On Dec 12, 2014, at 8:06 AM, P. Kaufmann notifications@github.com wrote:
This needs at least a clarification in the BIP, also in terms of valid unverified payment requests, which have just set pki_type == "none", which is not the case for ones that should have been valid verified ones (but are treated like unverified ones).
— Reply to this email directly or view it on GitHub.
mikehearn commented at 2:07 PM on December 12, 2014: contributorBIP should not specify a policy but I think UI recommendations are OK, as otherwise we'll keep having these discussions with every wallet dev. @Diapolo the way browsers do it is a source of significant discontent in parts of the security community, and generally they try and stop users clicking through or forbid it entirely anyway. The problem with what browsers do is it does make revoking CAs hard, and it makes self signed certs even harder. We all used to believe self signed certs were useless because any MITM could break it, but now we know there are adversaries (like governments) that do passive attacks way more frequently than active attacks. So browser UI is looking less appropriate as time goes on. It would not surprise me if it changed in future.
Unfortunately there can be no equivalent of HSTS in the Bitcoin world because the user doesn't generally tell their wallet who they want to pay. So we can't know if a request is expected to be signed or not.
Diapolo commented at 2:21 PM on December 12, 2014: noneFine, so to not make my work obsolete alltogether, what about keeping the code and the added tests but just don't require or add new UX or user interactions needs!? That way it's possible to extend in the future, have more in-depth test cases and speaking return values.
Diapolo commented at 2:46 PM on December 12, 2014: noneAdded a commit to achieve some consensus with this :).
Diapolo renamed this:[Qt] ensure cert errors lead to rejecting payment requests
[Qt] log cert errors for payment requests and harden test-cases
on Dec 16, 2014Diapolo commented at 1:32 PM on December 20, 2014: noneRebased to be a single commit and updated commit-msg.
in src/qt/test/paymentservertests.cpp:None in bfb9cf9954 outdated
94 | 95 | // Long certificate chain, with an expired certificate in the middle: 96 | data = DecodeBase64(paymentrequest4_BASE64); 97 | r = handleRequest(server, data); 98 | - r.paymentRequest.getMerchant(caStore, merchant); 99 | + QVERIFY(r.paymentRequest.getMerchant(caStore, merchant) | PR_ERROR);
laanwj commented at 12:13 PM on January 8, 2015:Shouldn't this be
&instead of|? This will always pass.
Diapolo commented at 2:39 PM on January 8, 2015:I had the impression because of
PR_ERROR = (PR_NOTINITIALIZED | PR_PKIERROR | PR_CERTERROR)this is correct, no?
laanwj commented at 2:45 PM on January 8, 2015:QVERIFY(x) where x is not zero will pass. x = result | PR_PERROR is always non-zero. An OR operation with a non-zero value always results in a non-zero value.
Diapolo commented at 2:04 PM on January 9, 2015:Changed to be a
&.laanwj added the label GUI on Jan 8, 2015laanwj added the label Tests on Jan 8, 20151d93a26647[Qt] log cert errors for payment requests and harden test-cases
- extend PaymentRequestPlus::getMerchant to return status of payment request errors related to certificates/PKIs etc. - do a real check for errors, which was missing until now, in PaymentServer::processPaymentRequest and also extend our tests in paymentservertests.cpp to not only rely on the content of "merchant" passed to getMerchant - this explicitly treats insecure payment requests not as errors, as they are allowed as per BIP70
jgarzik commented at 4:16 PM on September 15, 2015: contributorut ACK - all feedback appears to have been addressed
Diapolo closed this on Oct 31, 2015Diapolo deleted the branch on Oct 31, 2015DrahtBot locked this on Sep 8, 2021
This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-21 18:15 UTC
More mirrored repositories can be found on mirror.b10c.me