From 121ce315c153411f1d3f64d04fe36fefb0047521 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 18 Mar 2025 06:28:04 +0000 Subject: [PATCH] NFC: Detect Type 4 Tag platform (eg DESFire) --- .../protocols/mf_desfire/mf_desfire_poller.c | 3 +- lib/nfc/protocols/type_4_tag/type_4_tag.c | 29 +++++++++-- lib/nfc/protocols/type_4_tag/type_4_tag.h | 10 ++++ .../protocols/type_4_tag/type_4_tag_poller.c | 16 +++++- .../type_4_tag/type_4_tag_poller_i.c | 49 +++++++++++++++++++ .../type_4_tag/type_4_tag_poller_i.h | 3 ++ 6 files changed, 104 insertions(+), 6 deletions(-) diff --git a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c index 45e5a27f9..e9c5e3b6d 100644 --- a/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c +++ b/lib/nfc/protocols/mf_desfire/mf_desfire_poller.c @@ -251,8 +251,7 @@ static bool mf_desfire_poller_detect(NfcGenericEvent event, void* context) { MfDesfireError error = mf_desfire_poller_read_key_version(instance, 0, &key_version); if(error != MfDesfireErrorNone) break; - MfDesfireVersion version = {}; - error = mf_desfire_poller_read_version(instance, &version); + error = mf_desfire_poller_read_version(instance, &instance->data->version); if(error != MfDesfireErrorNone) break; protocol_detected = true; diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag.c b/lib/nfc/protocols/type_4_tag/type_4_tag.c index 3bcb0ee41..09d3f5be6 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag.c +++ b/lib/nfc/protocols/type_4_tag/type_4_tag.c @@ -1,6 +1,7 @@ #include "type_4_tag_i.h" #define TYPE_4_TAG_PROTOCOL_NAME "Type 4 Tag" +#define TYPE_4_TAG_SHORT_NAME "T4T" const NfcDeviceBase nfc_device_type_4_tag = { .protocol_name = TYPE_4_TAG_PROTOCOL_NAME, @@ -21,6 +22,9 @@ const NfcDeviceBase nfc_device_type_4_tag = { Type4TagData* type_4_tag_alloc(void) { Type4TagData* data = malloc(sizeof(Type4TagData)); data->iso14443_4a_data = iso14443_4a_alloc(); + data->device_name = furi_string_alloc(); + data->platform_name_full = furi_string_alloc(); + data->platform_name_short = furi_string_alloc(); data->ndef_data = simple_array_alloc(&simple_array_config_uint8_t); return data; } @@ -30,6 +34,9 @@ void type_4_tag_free(Type4TagData* data) { type_4_tag_reset(data); simple_array_free(data->ndef_data); + furi_string_free(data->platform_name_short); + furi_string_free(data->platform_name_full); + furi_string_free(data->device_name); iso14443_4a_free(data->iso14443_4a_data); free(data); } @@ -40,6 +47,9 @@ void type_4_tag_reset(Type4TagData* data) { iso14443_4a_reset(data->iso14443_4a_data); data->is_tag_specific = false; + furi_string_reset(data->device_name); + furi_string_reset(data->platform_name_full); + furi_string_reset(data->platform_name_short); data->t4t_version.value = 0; data->chunk_max_read = 0; data->chunk_max_write = 0; @@ -60,6 +70,9 @@ void type_4_tag_copy(Type4TagData* data, const Type4TagData* other) { iso14443_4a_copy(data->iso14443_4a_data, other->iso14443_4a_data); data->is_tag_specific = other->is_tag_specific; + furi_string_set(data->device_name, other->device_name); + furi_string_set(data->platform_name_full, other->platform_name_full); + furi_string_set(data->platform_name_short, other->platform_name_short); data->t4t_version.value = other->t4t_version.value; data->chunk_max_read = other->chunk_max_read; data->chunk_max_write = other->chunk_max_write; @@ -137,9 +150,19 @@ bool type_4_tag_is_equal(const Type4TagData* data, const Type4TagData* other) { } const char* type_4_tag_get_device_name(const Type4TagData* data, NfcDeviceNameType name_type) { - UNUSED(data); - UNUSED(name_type); - return TYPE_4_TAG_PROTOCOL_NAME; + FuriString* platform_name = name_type == NfcDeviceNameTypeFull ? data->platform_name_full : + data->platform_name_short; + if(furi_string_empty(platform_name)) { + return TYPE_4_TAG_PROTOCOL_NAME; + } + furi_string_printf( + data->device_name, + "%s%c(%s)", + name_type == NfcDeviceNameTypeFull ? TYPE_4_TAG_PROTOCOL_NAME : TYPE_4_TAG_SHORT_NAME, + name_type == NfcDeviceNameTypeFull ? '\n' : ' ', + furi_string_get_cstr(platform_name)); + furi_string_replace_str(data->device_name, "Mifare", "MIFARE"); + return furi_string_get_cstr(data->device_name); } const uint8_t* type_4_tag_get_uid(const Type4TagData* data, size_t* uid_len) { diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag.h b/lib/nfc/protocols/type_4_tag/type_4_tag.h index 653785cba..9c19fd92e 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag.h +++ b/lib/nfc/protocols/type_4_tag/type_4_tag.h @@ -19,10 +19,20 @@ typedef enum { Type4TagErrorCustomCommand, } Type4TagError; +typedef enum { + Type4TagPlatformUnknown, + Type4TagPlatformNtag4xx, + Type4TagPlatformMfDesfire, +} Type4TagPlatform; + typedef struct { Iso14443_4aData* iso14443_4a_data; + FuriString* device_name; // Tag specific data bool is_tag_specific; + Type4TagPlatform platform; + FuriString* platform_name_full; + FuriString* platform_name_short; union { struct { uint8_t minor : 4; diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c index 76a42459b..4a8e984fc 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_poller.c @@ -62,10 +62,23 @@ static NfcCommand type_4_tag_poller_handler_request_mode(Type4TagPoller* instanc type_4_tag_copy(instance->data, instance->type_4_tag_event.data->poller_mode.data); } - instance->state = Type4TagPollerStateSelectApplication; + instance->state = Type4TagPollerStateDetectPlatform; return command; } +static NfcCommand type_4_tag_poller_handler_detect_platform(Type4TagPoller* instance) { + instance->error = type_4_tag_poller_detect_platform(instance); + iso14443_4a_poller_halt(instance->iso14443_4a_poller); + if(instance->error == Type4TagErrorNone) { + FURI_LOG_D(TAG, "Detect platform success"); + } else { + FURI_LOG_W(TAG, "Failed to detect platform"); + } + instance->state = Type4TagPollerStateSelectApplication; + + return NfcCommandContinue; +} + static NfcCommand type_4_tag_poller_handler_select_app(Type4TagPoller* instance) { instance->error = type_4_tag_poller_select_app(instance); if(instance->error == Type4TagErrorNone) { @@ -199,6 +212,7 @@ static NfcCommand type_4_tag_poller_handler_success(Type4TagPoller* instance) { static const Type4TagPollerReadHandler type_4_tag_poller_read_handler[Type4TagPollerStateNum] = { [Type4TagPollerStateIdle] = type_4_tag_poller_handler_idle, [Type4TagPollerStateRequestMode] = type_4_tag_poller_handler_request_mode, + [Type4TagPollerStateDetectPlatform] = type_4_tag_poller_handler_detect_platform, [Type4TagPollerStateSelectApplication] = type_4_tag_poller_handler_select_app, [Type4TagPollerStateReadCapabilityContainer] = type_4_tag_poller_handler_read_cc, [Type4TagPollerStateReadNdefMessage] = type_4_tag_poller_handler_read_ndef, diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.c b/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.c index b2895fc95..078fbf990 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.c +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.c @@ -3,6 +3,9 @@ #include +#include +#include + #define TAG "Type4TagPoller" Type4TagError type_4_tag_apdu_trx(Type4TagPoller* instance, BitBuffer* tx_buf, BitBuffer* rx_buf) { @@ -178,6 +181,52 @@ static Type4TagError type_5_tag_poller_iso_write( return Type4TagErrorNone; } +Type4TagError type_4_tag_poller_detect_platform(Type4TagPoller* instance) { + furi_check(instance); + + Iso14443_4aPollerEvent iso14443_4a_event = { + .type = Iso14443_4aPollerEventTypeReady, + .data = NULL, + }; + NfcGenericEvent event = { + .protocol = NfcProtocolIso14443_4a, + .instance = instance->iso14443_4a_poller, + .event_data = &iso14443_4a_event, + }; + + Type4TagPlatform platform = Type4TagPlatformUnknown; + NfcDevice* device = nfc_device_alloc(); + + do { + FURI_LOG_D(TAG, "Detect DESFire"); + NfcGenericInstance* mf_des = mf_desfire_poller.alloc(instance->iso14443_4a_poller); + if(mf_desfire_poller.detect(event, mf_des)) { + platform = Type4TagPlatformMfDesfire; + nfc_device_set_data(device, NfcProtocolMfDesfire, mf_desfire_poller.get_data(mf_des)); + } + mf_desfire_poller.free(mf_des); + if(platform != Type4TagPlatformUnknown) break; + + // FIXME: detect NTAG4xx + } while(false); + + if(platform != Type4TagPlatformUnknown) { + furi_string_set( + instance->data->platform_name_full, + nfc_device_get_name(device, NfcDeviceNameTypeFull)); + furi_string_set( + instance->data->platform_name_short, + nfc_device_get_name(device, NfcDeviceNameTypeShort)); + } else { + furi_string_reset(instance->data->platform_name_full); + furi_string_reset(instance->data->platform_name_short); + } + instance->data->platform = platform; + nfc_device_free(device); + + return platform != Type4TagPlatformUnknown ? Type4TagErrorNone : Type4TagErrorNotSupported; +} + Type4TagError type_4_tag_poller_select_app(Type4TagPoller* instance) { furi_check(instance); diff --git a/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.h b/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.h index 3fbead2f8..0989bca60 100644 --- a/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.h +++ b/lib/nfc/protocols/type_4_tag/type_4_tag_poller_i.h @@ -11,6 +11,7 @@ extern "C" { typedef enum { Type4TagPollerStateIdle, Type4TagPollerStateRequestMode, + Type4TagPollerStateDetectPlatform, Type4TagPollerStateSelectApplication, Type4TagPollerStateReadCapabilityContainer, Type4TagPollerStateReadNdefMessage, @@ -41,6 +42,8 @@ struct Type4TagPoller { const Type4TagData* type_4_tag_poller_get_data(Type4TagPoller* instance); +Type4TagError type_4_tag_poller_detect_platform(Type4TagPoller* instance); + Type4TagError type_4_tag_poller_select_app(Type4TagPoller* instance); Type4TagError type_4_tag_poller_read_cc(Type4TagPoller* instance);