Merge pull request #2226 from nvx/bugfix/14a_apdu_ats_timeout

hf 14a apdu now uses the FWI and SGFI values from the ATS to determine an appropriate timeout.
This commit is contained in:
Iceman 2024-01-01 12:19:08 +01:00 committed by GitHub
commit 2e7be4faba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 9 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
- Changed `hf 14a apdu` - It now uses the FWI and SGFI values from the ATS to determine an appropriate timeout (@nvx)
- Added a thread to check when device comes online again. It will connect and update prompt (@iceman1001)
- Changed CLI offline prompt - replaces the old prompt when offline is detected (@iceman100)
- Changed `hf mf info` - it now uses found keys to try identify Gen2 cards (@iceman1001)

View file

@ -1006,6 +1006,11 @@ int SelectCard14443A_4_WithParameters(bool disconnect, bool verbose, iso14a_card
return PM3_ECARDEXCHANGE;
}
iso14a_card_select_t *vcard = (iso14a_card_select_t *) resp.data.asBytes;
if (card) {
memcpy(card, vcard, sizeof(iso14a_card_select_t));
}
if (resp.oldarg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
// get ATS
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
@ -1029,19 +1034,19 @@ int SelectCard14443A_4_WithParameters(bool disconnect, bool verbose, iso14a_card
gs_frame_len = atsFSC[fsci];
}
}
if (card) {
card->ats_len = resp.oldarg[0];
memcpy(card->ats, resp.data.asBytes, card->ats_len);
}
} else {
// get frame length from ATS in card data structure
iso14a_card_select_t *vcard = (iso14a_card_select_t *) resp.data.asBytes;
if (vcard->ats_len > 1) {
uint8_t fsci = vcard->ats[1] & 0x0f;
if (fsci < ARRAYLEN(atsFSC)) {
gs_frame_len = atsFSC[fsci];
}
}
if (card) {
memcpy(card, vcard, sizeof(iso14a_card_select_t));
}
}
SetISODEPState(ISODEP_NFCA);
@ -1060,11 +1065,44 @@ int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card
static int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) {
*chainingout = false;
size_t timeout = 1500;
if (activateField) {
// select with no disconnect and set gs_frame_len
int selres = SelectCard14443A_4(false, true, NULL);
if (selres != PM3_SUCCESS)
iso14a_card_select_t card;
int selres = SelectCard14443A_4(false, true, &card);
if (selres != PM3_SUCCESS) {
return selres;
}
// Extract FWI and SFGI from ATS and increase timeout by the indicated values
// for most cards these values are trivially small so will make no practical
// difference but some "cards" like hf_cardhopper overwrite these to their
// maximum values resulting in ~5 seconds each which can cause timeouts if we
// just ignore it
if (((card.ats[1] & 0x20) == 0x20) && card.ats_len > 2) {
// TB is present in ATS
uint8_t tb;
if ((card.ats[1] & 0x10) == 0x10 && card.ats_len > 3) {
// TA is also present, so TB at ats[3]
tb = card.ats[3];
} else {
// TA is not present, so TB is at ats[2]
tb = card.ats[2];
}
uint8_t fwi = (tb & 0xF0) >> 4;
if (fwi != 0x0F) {
uint32_t fwt = 256 * 16 * (1 << fwi);
timeout += fwt;
}
uint8_t sfgi = tb & 0x0F;
if (sfgi != 0x0F) {
uint32_t sgft = 256 * 16 * (1 << sfgi);
timeout += sgft;
}
}
}
uint16_t cmdc = 0;
@ -1082,7 +1120,7 @@ static int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
if (WaitForResponseTimeout(CMD_ACK, &resp, timeout)) {
uint8_t *recv = resp.data.asBytes;
int iLen = resp.oldarg[0];
uint8_t res = resp.oldarg[1];
@ -2410,7 +2448,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
int isMagic = 0;
if (isMifareClassic) {
isMagic = detect_mf_magic(true, MF_KEY_A, 0);
isMagic = detect_mf_magic(true, MF_KEY_B, 0xFFFFFFFFFFFF);
}
if (isMifareUltralight) {
isMagic = (detect_mf_magic(false, MF_KEY_A, 0) == MAGIC_NTAG21X);