reconstruct the full ATS rather than just sending the historical bytes

rejig card type detection in seader_worker_card_detect
This commit is contained in:
Tiernan Messmer
2025-08-20 18:21:16 +10:00
parent 4eb43d1a24
commit af17050178
3 changed files with 47 additions and 31 deletions
+9 -21
View File
@@ -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);
+33 -10
View File
@@ -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;
+5
View File
@@ -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;