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);