From af170501788bfc0ea6ffb84c03d46ba67425e7d6 Mon Sep 17 00:00:00 2001 From: Tiernan Messmer Date: Wed, 20 Aug 2025 18:21:16 +1000 Subject: [PATCH] reconstruct the full ATS rather than just sending the historical bytes rejig card type detection in seader_worker_card_detect --- sam_api.c | 30 +++++++++--------------------- seader_worker.c | 43 +++++++++++++++++++++++++++++++++---------- seader_worker_i.h | 5 +++++ 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/sam_api.c b/sam_api.c index b3cda6e..8f3e770 100644 --- a/sam_api.c +++ b/sam_api.c @@ -1101,6 +1101,7 @@ NfcCommand seader_worker_card_detect( uint8_t uid_len, uint8_t* ats, uint8_t ats_len) { + UNUSED(atqa); SeaderCredential* credential = seader->credential; CardDetails_t* cardDetails = 0; @@ -1109,37 +1110,21 @@ NfcCommand seader_worker_card_detect( OCTET_STRING_fromBuf(&cardDetails->csn, (const char*)uid, uid_len); OCTET_STRING_t sak_string = {.buf = &sak, .size = 1}; - OCTET_STRING_t ats_string = {0}; - if(ats != NULL) { - ats_string.buf = ats; - ats_string.size = ats_len; - } else { - // technically I think this field is only ever meant to be ATS not ATQA - // for 14443a-4 cards but in practice, Seos cards seem to fail to read the - // ATS but the ATS doesn't matter for Seos as long as it's there otherwise - // the SAM thinks it's a part3 card, and filling it with the ATQA is what - // we did previously and seemed to work so eh - ats_string.buf = atqa; - ats_string.size = 2; - } + OCTET_STRING_t ats_string = {.buf = ats, .size = ats_len}; uint8_t protocol_bytes[] = {0x00, 0x00}; - if(sak != 0 && atqa != NULL) { // type 4 + if(ats != NULL) { // type 4 protocol_bytes[1] = FrameProtocol_nfc; OCTET_STRING_fromBuf( &cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes)); cardDetails->sak = &sak_string; + // TODO: Update asn1 to change atqa to ats cardDetails->atqa = &ats_string; credential->isDesfire = seader_mf_df_check_card_type(atqa[0], atqa[1], sak); if(credential->isDesfire) { memcpy(credential->diversifier, uid, uid_len); credential->diversifier_len = uid_len; } - } else if(sak != 0 && atqa == NULL) { // MFC - protocol_bytes[1] = FrameProtocol_nfc; - OCTET_STRING_fromBuf( - &cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes)); - cardDetails->sak = &sak_string; } else if(uid_len == 8) { // picopass protocol_bytes[1] = FrameProtocol_iclass; OCTET_STRING_fromBuf( @@ -1147,8 +1132,11 @@ NfcCommand seader_worker_card_detect( memcpy(credential->diversifier, uid, uid_len); credential->diversifier_len = uid_len; credential->isDesfire = false; - } else { - FURI_LOG_D(TAG, "Unknown card type"); + } else { // MFC + protocol_bytes[1] = FrameProtocol_nfc; + OCTET_STRING_fromBuf( + &cardDetails->protocol, (const char*)protocol_bytes, sizeof(protocol_bytes)); + cardDetails->sak = &sak_string; } seader_send_card_detected(seader, cardDetails); diff --git a/seader_worker.c b/seader_worker.c index 071e99e..c13928e 100644 --- a/seader_worker.c +++ b/seader_worker.c @@ -284,24 +284,47 @@ NfcCommand seader_worker_poller_callback_iso14443_4a(NfcGenericEvent event, void const Iso14443_4aData* iso14443_4a_data = nfc_device_get_data(seader->nfc_device, NfcProtocolIso14443_4a); const Iso14443_3aData* iso14443_3a_data = iso14443_4a_get_base_data(iso14443_4a_data); - uint32_t ats_len = 0; - uint8_t* ats = NULL; + + uint32_t t1_tk_size = 0; if(iso14443_4a_data->ats_data.t1_tk != NULL) { - // for some reason Seos cards fail to read the ATS - SimpleArray* ats_array = iso14443_4a_data->ats_data.t1_tk; - ats_len = simple_array_get_count(ats_array); - if(ats_len > 0xFF) { - ats_len = 0; - } - if(ats_len > 0) { - ats = simple_array_get_data(ats_array); + t1_tk_size = simple_array_get_count(iso14443_4a_data->ats_data.t1_tk); + if(t1_tk_size > 0xFF) { + t1_tk_size = 0; } } + + uint8_t ats_len = 0; + uint8_t* ats = malloc(4 + t1_tk_size); + furi_assert(ats); + + if(iso14443_4a_data->ats_data.tl > 1) { + ats[ats_len++] = iso14443_4a_data->ats_data.t0; + if(iso14443_4a_data->ats_data.t0 & ISO14443_4A_ATS_T0_TA1) { + ats[ats_len++] = iso14443_4a_data->ats_data.ta_1; + } + if(iso14443_4a_data->ats_data.t0 & ISO14443_4A_ATS_T0_TB1) { + ats[ats_len++] = iso14443_4a_data->ats_data.tb_1; + } + if(iso14443_4a_data->ats_data.t0 & ISO14443_4A_ATS_T0_TC1) { + ats[ats_len++] = iso14443_4a_data->ats_data.tc_1; + } + + if(t1_tk_size != 0) { + memcpy( + ats + ats_len, + simple_array_cget_data(iso14443_4a_data->ats_data.t1_tk), + t1_tk_size); + ats_len += t1_tk_size; + } + } + uint8_t sak = iso14443_3a_get_sak(iso14443_3a_data); seader_worker_card_detect( seader, sak, (uint8_t*)iso14443_3a_data->atqa, uid, uid_len, ats, ats_len); + free(ats); + // nfc_set_fdt_poll_fc(event.instance, SEADER_POLLER_MAX_FWT); furi_thread_set_current_priority(FuriThreadPriorityLowest); seader_worker->stage = SeaderPollerEventTypeConversation; diff --git a/seader_worker_i.h b/seader_worker_i.h index 4b9e350..b27b5ac 100644 --- a/seader_worker_i.h +++ b/seader_worker_i.h @@ -17,6 +17,11 @@ #define SEADER_POLLER_MAX_FWT (200000U) #define SEADER_POLLER_MAX_BUFFER_SIZE (255U) +// ATS bit definitions +#define ISO14443_4A_ATS_T0_TA1 (1U << 4) +#define ISO14443_4A_ATS_T0_TB1 (1U << 5) +#define ISO14443_4A_ATS_T0_TC1 (1U << 6) + struct SeaderWorker { FuriThread* thread; Storage* storage;