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... 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] ## [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) - 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 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) - 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; 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 if (resp.oldarg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
// get ATS // get ATS
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 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]; gs_frame_len = atsFSC[fsci];
} }
} }
if (card) {
card->ats_len = resp.oldarg[0];
memcpy(card->ats, resp.data.asBytes, card->ats_len);
}
} else { } else {
// get frame length from ATS in card data structure // 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) { if (vcard->ats_len > 1) {
uint8_t fsci = vcard->ats[1] & 0x0f; uint8_t fsci = vcard->ats[1] & 0x0f;
if (fsci < ARRAYLEN(atsFSC)) { if (fsci < ARRAYLEN(atsFSC)) {
gs_frame_len = atsFSC[fsci]; gs_frame_len = atsFSC[fsci];
} }
} }
if (card) {
memcpy(card, vcard, sizeof(iso14a_card_select_t));
}
} }
SetISODEPState(ISODEP_NFCA); SetISODEPState(ISODEP_NFCA);
@ -1060,13 +1065,46 @@ 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) { static int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) {
*chainingout = false; *chainingout = false;
size_t timeout = 1500;
if (activateField) { if (activateField) {
// select with no disconnect and set gs_frame_len // select with no disconnect and set gs_frame_len
int selres = SelectCard14443A_4(false, true, NULL); iso14a_card_select_t card;
if (selres != PM3_SUCCESS) int selres = SelectCard14443A_4(false, true, &card);
if (selres != PM3_SUCCESS) {
return selres; 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; uint16_t cmdc = 0;
if (chainingin) if (chainingin)
cmdc = ISO14A_SEND_CHAINING; cmdc = ISO14A_SEND_CHAINING;
@ -1082,7 +1120,7 @@ static int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (WaitForResponseTimeout(CMD_ACK, &resp, timeout)) {
uint8_t *recv = resp.data.asBytes; uint8_t *recv = resp.data.asBytes;
int iLen = resp.oldarg[0]; int iLen = resp.oldarg[0];
uint8_t res = resp.oldarg[1]; 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; int isMagic = 0;
if (isMifareClassic) { if (isMifareClassic) {
isMagic = detect_mf_magic(true, MF_KEY_A, 0); isMagic = detect_mf_magic(true, MF_KEY_B, 0xFFFFFFFFFFFF);
} }
if (isMifareUltralight) { if (isMifareUltralight) {
isMagic = (detect_mf_magic(false, MF_KEY_A, 0) == MAGIC_NTAG21X); isMagic = (detect_mf_magic(false, MF_KEY_A, 0) == MAGIC_NTAG21X);