Repository navigation
Sort EMV applications by the priority indicator, not the AID - #1874
arpitjain099 wants to merge 1 commit into
Conversation
GetCardTokenAID reads both the AID (tag 0x4F) and the Application Priority Indicator (tag 0x87), validates that the priority node exists and is exactly one byte, and then pushes the first byte of the AID as the sort key. So aidPriorityNode is fetched and length-checked and never dereferenced; grep finds it on only three lines, all of them above the push. The key actually used is the AID's first byte, which on essentially every EMV card is 0xA0, the registered application provider prefix, so every key collapses to the same value and the card's stated priorities never enter the sort. EMV Book 1 section 12.4 makes the priority indicator the thing that orders candidate applications. On a multi-application card the keyfile is currently derived from a different application than the card designates. Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
idrassi
left a comment
There was a problem hiding this comment.
Thanks for catching this. Indeed, the code reads from the wrong node. But I'm hesitant to merge the change as it stands because application selection affects the keyfile itself.
Selecting another application can change the certificates used to build the keyfile. Someone could then upgrade VeraCrypt and find that their existing volume won't open with the same card and password. The token path doesn't record the AID, so we don't currently have a way to preserve the previous choice.
There's a point in the description I'd like to clarify too. The existing sort is deterministic: it compares pairs, so the full AID breaks ties when the first byte is identical. It ignores the card's priority, but it doesn't produce an arbitrary selection.
The replacement also needs to account for how the priority byte is encoded. Zero means no priority is assigned, yet this change would sort it ahead of priority one. For contact cards, bit 8 carries a separate requirement for cardholder confirmation.
The Visa and Mastercard example misses the initial selection step. If the standard Mastercard AID is selectable, both versions choose it before reaching this block. I'd like to see a test through GetCardAID() that actually exercises the directory fallback.
I'm glad you brought this up, but we need to work out how to correct the priority handling while keeping existing keyfiles usable before changing the selection behavior.
EMVCard::GetCardTokenAIDreads both the AID (tag0x4F) and the Application Priority Indicator (tag0x87), validates that the priority node exists and is exactly one byte, and then sorts on the wrong one:The length check on
aidPriorityNodeonly makes sense if byte 0 is about to be read, and it never is:grep -rn "aidPriorityNode" src/returns exactly the three lines above, so the value is discarded everywhere in the tree. The key that gets pushed is the AID's first byte, which on essentially every EMV card is0xA0, the registered application provider prefix. Every key collapses to the same value and the ordering degenerates.Verification drives the unmodified
src/Common/TLVParser.cpp, compiled standalone against a small shim forPlatform/PlatformBase.handTcdefs.h, with the selection loop transcribed fromEMVCard.cpplines 280-305. Source identity confirmed by sha256 before building. The input is one PSE READ RECORD response holding two application templates, Visa at priority0x02and Mastercard at priority0x01, so the card ranks Mastercard first:The
sort keys used: 0xA0 0xA0line is the whole finding. EMV Book 1 section 12.4 makes the priority indicator the field that orders candidate applications.On severity, so it is not overread: this is a correctness and spec-conformance bug, not a security issue. A hostile card already supplies every certificate byte that becomes the keyfile, so controlling the ordering gains it nothing, and the wrong selection reaches only the user who inserted the card. What it costs is keyfile determinism on a multi-application card, which is the contract of the feature.