From 82baf1e9232ad72b565cfe33e6b5177a32daa4fe Mon Sep 17 00:00:00 2001 From: gornekich Date: Tue, 5 Dec 2023 17:40:06 +0400 Subject: [PATCH] [FL-3701] NFC fixes (#3264) * nfc app: fix unlock with manual password crash * nfc app: preserve card detected state * nfc app: fix mf keys scene switch * nfc app: fix multiple protocol tag detect notification * nfc plugin: fix retrun in function body in aime parser * iso14443-3b poller: rework ATTRIB response check * nfc app: fix navigation after file load failur * iso14443-3b poller: fix PVS warning * mfc listener: add crutch in mfc emulation --- applications/main/nfc/nfc_app.c | 17 +++++++++-------- .../main/nfc/plugins/supported_cards/aime.c | 7 ++++++- applications/main/nfc/scenes/nfc_scene_detect.c | 1 + .../main/nfc/scenes/nfc_scene_extra_actions.c | 6 +----- .../nfc_scene_mf_ultralight_unlock_warn.c | 3 ++- .../main/nfc/scenes/nfc_scene_select_protocol.c | 1 - applications/main/nfc/views/dict_attack.c | 1 - .../iso14443_3b/iso14443_3b_poller_i.c | 15 ++++++++++++--- .../protocols/mf_classic/mf_classic_listener.c | 7 +++++++ 9 files changed, 38 insertions(+), 20 deletions(-) diff --git a/applications/main/nfc/nfc_app.c b/applications/main/nfc/nfc_app.c index 141a67e5c..5ae0ca5f5 100644 --- a/applications/main/nfc/nfc_app.c +++ b/applications/main/nfc/nfc_app.c @@ -400,15 +400,16 @@ bool nfc_load_from_file_select(NfcApp* instance) { browser_options.base_path = NFC_APP_FOLDER; browser_options.hide_dot_files = true; - // Input events and views are managed by file_browser - bool result = dialog_file_browser_show( - instance->dialogs, instance->file_path, instance->file_path, &browser_options); + bool success = false; + do { + // Input events and views are managed by file_browser + if(!dialog_file_browser_show( + instance->dialogs, instance->file_path, instance->file_path, &browser_options)) + break; + success = nfc_load_file(instance, instance->file_path, true); + } while(!success); - if(result) { - result = nfc_load_file(instance, instance->file_path, true); - } - - return result; + return success; } void nfc_show_loading_popup(void* context, bool show) { diff --git a/applications/main/nfc/plugins/supported_cards/aime.c b/applications/main/nfc/plugins/supported_cards/aime.c index 1db89ffd6..df1e7e077 100644 --- a/applications/main/nfc/plugins/supported_cards/aime.c +++ b/applications/main/nfc/plugins/supported_cards/aime.c @@ -120,10 +120,15 @@ static bool aime_parse(const NfcDevice* device, FuriString* parsed_data) { aime_accesscode[9]); // validate decimal hex representation + bool code_is_hex = true; for(int i = 0; i < 24; i++) { if(aime_accesscode_str[i] == ' ') continue; - if(aime_accesscode_str[i] < '0' || aime_accesscode_str[i] > '9') return false; + if(aime_accesscode_str[i] < '0' || aime_accesscode_str[i] > '9') { + code_is_hex = false; + break; + } } + if(!code_is_hex) break; // Note: Aime access code has some other self-check algorithms that are not public. // This parser does not try to verify the number. diff --git a/applications/main/nfc/scenes/nfc_scene_detect.c b/applications/main/nfc/scenes/nfc_scene_detect.c index 326b1458c..593c67aab 100644 --- a/applications/main/nfc/scenes/nfc_scene_detect.c +++ b/applications/main/nfc/scenes/nfc_scene_detect.c @@ -37,6 +37,7 @@ bool nfc_scene_detect_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == NfcCustomEventWorkerExit) { if(instance->protocols_detected_num > 1) { + notification_message(instance->notifications, &sequence_single_vibro); scene_manager_next_scene(instance->scene_manager, NfcSceneSelectProtocol); } else { scene_manager_next_scene(instance->scene_manager, NfcSceneRead); diff --git a/applications/main/nfc/scenes/nfc_scene_extra_actions.c b/applications/main/nfc/scenes/nfc_scene_extra_actions.c index 7f51b7174..721919d2b 100644 --- a/applications/main/nfc/scenes/nfc_scene_extra_actions.c +++ b/applications/main/nfc/scenes/nfc_scene_extra_actions.c @@ -45,11 +45,7 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SubmenuIndexMfClassicKeys) { - if(nfc_dict_check_presence(NFC_APP_MF_CLASSIC_DICT_USER_PATH)) { - scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys); - } else { - scene_manager_previous_scene(instance->scene_manager); - } + scene_manager_next_scene(instance->scene_manager, NfcSceneMfClassicKeys); consumed = true; } else if(event.event == SubmenuIndexMfUltralightUnlock) { mf_ultralight_auth_reset(instance->mf_ul_auth); diff --git a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c index 6be051ced..e3bbfba59 100644 --- a/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c +++ b/applications/main/nfc/scenes/nfc_scene_mf_ultralight_unlock_warn.c @@ -52,11 +52,12 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve bool consumed = false; - nfc->protocols_detected[0] = nfc_device_get_protocol(nfc->nfc_device); MfUltralightAuthType type = nfc->mf_ul_auth->type; if((type == MfUltralightAuthTypeReader) || (type == MfUltralightAuthTypeManual)) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == DialogExResultRight) { + const NfcProtocol mfu_protocol[] = {NfcProtocolMfUltralight}; + nfc_app_set_detected_protocols(nfc, mfu_protocol, COUNT_OF(mfu_protocol)); scene_manager_next_scene(nfc->scene_manager, NfcSceneRead); dolphin_deed(DolphinDeedNfcRead); consumed = true; diff --git a/applications/main/nfc/scenes/nfc_scene_select_protocol.c b/applications/main/nfc/scenes/nfc_scene_select_protocol.c index 86b9982fc..7a5d12521 100644 --- a/applications/main/nfc/scenes/nfc_scene_select_protocol.c +++ b/applications/main/nfc/scenes/nfc_scene_select_protocol.c @@ -21,7 +21,6 @@ void nfc_scene_select_protocol_on_enter(void* context) { } else { prefix = "Read as"; submenu_set_header(submenu, "Multi-protocol card"); - notification_message(instance->notifications, &sequence_single_vibro); } for(uint32_t i = 0; i < instance->protocols_detected_num; i++) { diff --git a/applications/main/nfc/views/dict_attack.c b/applications/main/nfc/views/dict_attack.c index b656c2dc5..ce8679088 100644 --- a/applications/main/nfc/views/dict_attack.c +++ b/applications/main/nfc/views/dict_attack.c @@ -125,7 +125,6 @@ void dict_attack_reset(DictAttack* instance) { instance->view, DictAttackViewModel * model, { - model->card_detected = false; model->sectors_total = 0; model->sectors_read = 0; model->current_sector = 0; diff --git a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c index 1ee5237c6..15fc609db 100644 --- a/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c +++ b/lib/nfc/protocols/iso14443_3b/iso14443_3b_poller_i.c @@ -131,9 +131,18 @@ Iso14443_3bError iso14443_3b_poller_activate(Iso14443_3bPoller* instance, Iso144 break; } - if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1 || - bit_buffer_get_byte(instance->rx_buffer, 0) != 0) { - FURI_LOG_D(TAG, "Unexpected ATTRIB response"); + if(bit_buffer_get_size_bytes(instance->rx_buffer) != 1) { + FURI_LOG_W( + TAG, + "Unexpected ATTRIB response length: %zu", + bit_buffer_get_size_bytes(instance->rx_buffer)); + } + + if(bit_buffer_get_byte(instance->rx_buffer, 0) != 0) { + FURI_LOG_D( + TAG, + "Incorrect CID in ATTRIB response: %02X", + bit_buffer_get_byte(instance->rx_buffer, 0)); instance->state = Iso14443_3bPollerStateActivationFailed; ret = Iso14443_3bErrorCommunication; break; diff --git a/lib/nfc/protocols/mf_classic/mf_classic_listener.c b/lib/nfc/protocols/mf_classic/mf_classic_listener.c index fb12ba8a9..3423e89e4 100644 --- a/lib/nfc/protocols/mf_classic/mf_classic_listener.c +++ b/lib/nfc/protocols/mf_classic/mf_classic_listener.c @@ -481,6 +481,13 @@ static const MfClassicListenerCmd mf_classic_listener_cmd_handlers[] = { .command_num = COUNT_OF(mf_classic_listener_halt_handlers), .handler = mf_classic_listener_halt_handlers, }, + { + // This crutch is necessary since some devices (like Pixel) send 15-bit "HALT" command ... + .cmd_start_byte = MF_CLASSIC_CMD_HALT_MSB, + .cmd_len_bits = 15, + .command_num = COUNT_OF(mf_classic_listener_halt_handlers), + .handler = mf_classic_listener_halt_handlers, + }, { .cmd_start_byte = MF_CLASSIC_CMD_AUTH_KEY_A, .cmd_len_bits = 2 * 8,