From d156e48a83c7a8ab051d781d60b1eedb1f49e68f Mon Sep 17 00:00:00 2001 From: nvx Date: Mon, 1 Jan 2024 21:14:32 +1000 Subject: [PATCH] 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. --- CHANGELOG.md | 1 + client/src/cmdhf14a.c | 56 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e646c72a3..e3759eeaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 8d63a98da..361e4deae 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -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);