Skip to content

Sort EMV applications by the priority indicator, not the AID - #1874

Open
arpitjain099 wants to merge 1 commit into
veracrypt:masterfrom
arpitjain099:fix/emv-application-priority
Open

Sort EMV applications by the priority indicator, not the AID#1874
arpitjain099 wants to merge 1 commit into
veracrypt:masterfrom
arpitjain099:fix/emv-application-priority

Conversation

@arpitjain099

Copy link
Copy Markdown

EMVCard::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 sorts on the wrong one:

aidNode         = TLVParser::TLV_Find(pseDirectoryNodes[i], EMV_AID_TAG);
aidPriorityNode = TLVParser::TLV_Find(pseDirectoryNodes[i], EMV_PRIORITY_TAG);
if (aidNode && aidNode->Value->size() > 0 && aidPriorityNode && aidPriorityNode->Value->size() == 1)
{
    supportedAIDs.push_back(*aidNode->Value.get());
    supportedAIDsPriorities.push_back(aidNode->Value->at(0));   // <- AID, not priority
}

The length check on aidPriorityNode only 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 is 0xA0, 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 for Platform/PlatformBase.h and Tcdefs.h, with the selection loop transcribed from EMVCard.cpp lines 280-305. Source identity confirmed by sha256 before building. The input is one PSE READ RECORD response holding two application templates, Visa at priority 0x02 and Mastercard at priority 0x01, so the card ranks Mastercard first:

application templates found: 2
  [shipped code: aidNode->Value->at(0)]
    sort keys used: 0xA0 0xA0
    SELECTED AID: A0000000031010
  [fixed: aidPriorityNode->Value->at(0)]
    sort keys used: 0x02 0x01
    SELECTED AID: A0000000041010
card's stated priority-1 application: A0000000041010

The sort keys used: 0xA0 0xA0 line 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.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant