hf 14a apdu now uses the FWI and SGFI values from the ATS to determine an appropriate timeout.

This fixes issues when using the command against cards that indicate really slow times, such as card emulation by hf_cardhopper.
This commit is contained in:
nvx 2024-01-01 21:14:32 +10:00
parent e9972bd060
commit d156e48a83
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);