mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2026-10-21 22:02:37 +00:00
Security tokens: bound response chaining and EMV directory reads
ApduProcessData sent GET RESPONSE for as long as the card answered 0x61XX, allowing an endless loop and unbounded response growth. Limit each chain to 256 follow-up commands and erase the partial response if the limit is exceeded. PSE directory enumeration had a separate unbounded loop with an eight-bit record counter. Read only records 1 through 254, stop on an empty or unsuccessful response, and limit the accumulated directory data to 254 short records before parsing. Malformed TLV responses consume this budget too, so they cannot bypass either limit.
This commit is contained in:
+16
-4
@@ -252,13 +252,21 @@ namespace VeraCrypt
|
||||
{
|
||||
sfi = sfiNode->Value->at(0);
|
||||
|
||||
uint8 rec = 1;
|
||||
do
|
||||
// Record numbers 0 and 255 are reserved. Use a wider counter
|
||||
// so a full directory cannot wrap back to the first record.
|
||||
const unsigned int maxDirectoryRecords = 254;
|
||||
// Also bound the total data retained across all short records.
|
||||
size_t remainingDirectoryBytes = maxDirectoryRecords * SCardReader::shortAPDUMaxTransSize;
|
||||
for (unsigned int rec = 1; rec <= maxDirectoryRecords; ++rec)
|
||||
{
|
||||
command = CommandAPDU(CLA_ISO7816, INS_READ_RECORD, rec++, (sfi << 3) | 4, SCardReader::shortAPDUMaxTransSize);
|
||||
command = CommandAPDU(CLA_ISO7816, INS_READ_RECORD, rec, (sfi << 3) | 4, SCardReader::shortAPDUMaxTransSize);
|
||||
m_reader->ApduProcessData(command, response);
|
||||
if (response.getSW() == SW_NO_ERROR && response.getData().size() > 0)
|
||||
{
|
||||
if (response.getData().size() > remainingDirectoryBytes)
|
||||
throw PCSCException(SCARD_E_UNEXPECTED);
|
||||
remainingDirectoryBytes -= response.getData().size();
|
||||
|
||||
try
|
||||
{
|
||||
templateNode = TLVParser::TLV_Parse(response.getData().data(), response.getData().size());
|
||||
@@ -278,7 +286,11 @@ namespace VeraCrypt
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} while (response.getData().size() > 0);
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,8 +590,18 @@ namespace VeraCrypt
|
||||
|
||||
// Send get response to get the rest as long as we receive SW == 0x61XX
|
||||
// In case of PACE, this is never the case
|
||||
// A GET RESPONSE returns at most 256 bytes and no response exceeds 65536 bytes,
|
||||
// so stop a card that keeps answering 0x61XX instead of looping without end
|
||||
uint32 getResponseCount = 0;
|
||||
while ((lRet == SCARD_S_SUCCESS) && ((BYTE)(SW >> 8) == (BYTE)(SW_BYTES_REMAINING_00 >> 8))) // 0x61
|
||||
{
|
||||
if (++getResponseCount > extendedAPDUMaxTransSize / shortAPDUMaxTransSize)
|
||||
{
|
||||
responseAPDU.clear();
|
||||
lRet = SCARD_E_UNEXPECTED;
|
||||
break;
|
||||
}
|
||||
|
||||
// GET RESPONSE APDU
|
||||
pbSendBuffer[0] = commandAPDU.getCLA();
|
||||
pbSendBuffer[1] = INS_GET_RESPONSE;
|
||||
|
||||
Reference in New Issue
Block a user