diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv.c b/applications/main/nfc/helpers/protocol_support/emv/emv.c index e543291cc..728aabefe 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv.c @@ -64,16 +64,6 @@ static void nfc_scene_read_success_on_enter_emv(NfcApp* instance) { furi_string_free(temp_str); } -// static void nfc_scene_emulate_on_enter_emv(NfcApp* instance) { -// const Iso14443_4aData* iso14443_4a_data = -// nfc_device_get_data(instance->nfc_device, NfcProtocolIso14443_4a); - -// instance->listener = -// nfc_listener_alloc(instance->nfc, NfcProtocolIso14443_4a, iso14443_4a_data); -// nfc_listener_start( -// instance->listener, nfc_scene_emulate_listener_callback_iso14443_4a, instance); -// } - const NfcProtocolSupportBase nfc_protocol_support_emv = { .features = NfcProtocolFeatureMoreInfo, diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index 8e3c5635b..8f26d8178 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -147,9 +147,8 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { parsed = true; } - if(app.pin_attempts_counter != 0xFF) { - furi_string_cat_printf( - parsed_data, "PIN attempts left: %d\n", app.pin_attempts_counter); + if(app.pin_try_counter != 0xFF) { + furi_string_cat_printf(parsed_data, "PIN attempts left: %d\n", app.pin_try_counter); parsed = true; } diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index c05d18b50..278828071 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -28,7 +28,7 @@ const NfcDeviceBase nfc_device_emv = { EmvData* emv_alloc() { EmvData* data = malloc(sizeof(EmvData)); data->iso14443_4a_data = iso14443_4a_alloc(); - data->emv_application.pin_attempts_counter = 0xff; + data->emv_application.pin_try_counter = 0xff; return data; } @@ -76,6 +76,9 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { EmvApplication* app = &data->emv_application; + flipper_format_read_string(ff, "Cardholder name", temp_str); + strcpy(app->cardholder_name, furi_string_get_cstr(temp_str)); + flipper_format_read_string(ff, "Application name", temp_str); strcpy(app->application_name, furi_string_get_cstr(temp_str)); @@ -107,9 +110,9 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { if(!flipper_format_read_hex(ff, "Effective month", &app->effective_month, 1)) break; if(!flipper_format_read_hex(ff, "Effective day", &app->effective_day, 1)) break; - uint32_t pin_attempts_counter; - if(!flipper_format_read_uint32(ff, "PIN attempts left", &pin_attempts_counter, 1)) break; - app->pin_attempts_counter = pin_attempts_counter; + uint32_t pin_try_counter; + if(!flipper_format_read_uint32(ff, "PIN try counter", &pin_try_counter, 1)) break; + app->pin_try_counter = pin_try_counter; parsed = true; } while(false); @@ -131,6 +134,8 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) { if(!flipper_format_write_comment_cstr(ff, "EMV specific data:\n")) break; + if(!flipper_format_write_string_cstr(ff, "Cardholder name", app.cardholder_name)) break; + if(!flipper_format_write_string_cstr(ff, "Application name", app.application_name)) break; if(!flipper_format_write_string_cstr(ff, "Application label", app.application_label)) @@ -160,8 +165,7 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) { break; if(!flipper_format_write_hex(ff, "Effective day", (uint8_t*)&app.effective_day, 1)) break; - if(!flipper_format_write_uint32( - ff, "PIN attempts left", (uint32_t*)&app.pin_attempts_counter, 1)) + if(!flipper_format_write_uint32(ff, "PIN try counter", (uint32_t*)&app.pin_try_counter, 1)) break; saved = true; diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index 2e786347c..bd195dde6 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -16,7 +16,7 @@ extern "C" { #define EMV_TAG_APPL_LABEL 0x50 #define EMV_TAG_APPL_NAME 0x9F12 #define EMV_TAG_APPL_EFFECTIVE 0x5F25 -#define EMV_TAG_PIN_ATTEMPTS_COUNTER 0x9F17 +#define EMV_TAG_PIN_TRY_COUNTER 0x9F17 #define EMV_TAG_LOG_ENTRY 0x9F4D #define EMV_TAG_LOG_FMT 0x9F4F @@ -36,6 +36,7 @@ extern "C" { #define EMV_TAG_COUNTRY_CODE 0x5F28 #define EMV_TAG_CURRENCY_CODE 0x9F42 #define EMV_TAG_CARDHOLDER_NAME 0x5F20 +#define EMV_TAG_CARDHOLDER_NAME_EXTENDED 0x9F0B #define EMV_TAG_TRACK_2_DATA 0x9F6B #define EMV_TAG_GPO_FMT1 0x80 @@ -91,7 +92,7 @@ typedef struct { uint8_t effective_year; uint16_t country_code; uint16_t currency_code; - uint8_t pin_attempts_counter; + uint8_t pin_try_counter; uint16_t transaction_counter; uint16_t last_online_atc; APDU pdol; diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 07428744f..6ca21df1c 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -108,7 +108,7 @@ static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { static NfcCommand emv_poller_handler_read_extra_data(EmvPoller* instance) { emv_poller_get_last_online_atc(instance); - emv_poller_get_pin_attempts_counter(instance); + emv_poller_get_pin_try_counter(instance); instance->state = EmvPollerStateReadSuccess; return NfcCommandContinue; diff --git a/lib/nfc/protocols/emv/emv_poller.h b/lib/nfc/protocols/emv/emv_poller.h index c24704cb5..64bd0be9d 100644 --- a/lib/nfc/protocols/emv/emv_poller.h +++ b/lib/nfc/protocols/emv/emv_poller.h @@ -50,7 +50,7 @@ EmvError emv_poller_read_afl(EmvPoller* instance); EmvError emv_poller_read_log_entry(EmvPoller* instance); -EmvError emv_poller_get_pin_attempts_counter(EmvPoller* instance); +EmvError emv_poller_get_pin_try_counter(EmvPoller* instance); EmvError emv_poller_get_last_online_atc(EmvPoller* instance); diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 8731691d9..bba0163ce 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -193,6 +193,14 @@ static bool if(strlen(app->cardholder_name) > tlen) break; memcpy(app->cardholder_name, &buff[i], tlen); app->cardholder_name[tlen] = '\0'; + + // use space char as terminator + for(size_t i = 0; i < tlen; i++) + if(app->cardholder_name[i] == 0x20) { + app->cardholder_name[i] = '\0'; + break; + } + success = true; FURI_LOG_T(TAG, "found EMV_TAG_CARDHOLDER_NAME %x: %s", tag, app->cardholder_name); break; @@ -262,11 +270,10 @@ static bool memcpy(&app->trans[app->active_tr].time, &buff[i], tlen); success = true; break; - case EMV_TAG_PIN_ATTEMPTS_COUNTER: - app->pin_attempts_counter = buff[i]; + case EMV_TAG_PIN_TRY_COUNTER: + app->pin_try_counter = buff[i]; success = true; - FURI_LOG_T( - TAG, "found EMV_TAG_PIN_ATTEMPTS_COUNTER %x: %d", tag, app->pin_attempts_counter); + FURI_LOG_T(TAG, "found EMV_TAG_PIN_TRY_COUNTER %x: %d", tag, app->pin_try_counter); break; } return success; @@ -615,6 +622,8 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { FURI_LOG_D(TAG, "Search PAN in SFI"); + bool pan_fetched = (instance->data->emv_application.pan_len); + // Iterate through all files for(size_t i = 0; i < instance->data->emv_application.afl.size; i += 4) { uint8_t sfi = afl->data[i] >> 3; @@ -633,15 +642,32 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record); } - // Some READ RECORD returns 1 byte response 0x12/0x13 (IDK WTF), - // then poller return Timeout to all subsequent requests. - // TODO: remove below lines when it was fixed - if(instance->data->emv_application.pan_len != 0) - return EmvErrorNone; // Card number fetched + if(instance->data->emv_application.pan_len) pan_fetched = true; // Card number fetched } } - return error; + // Bruteforse files 2-3 + FURI_LOG_T(TAG, "Bruteforce files 2-3"); + for(size_t sfi = 2; sfi <= 3; sfi++) { + // Iterate through records 1-5 in file + for(size_t record = 1; record <= 5; record++) { + if(strlen(instance->data->emv_application.cardholder_name)) return EmvErrorNone; + error = emv_poller_read_sfi_record(instance, sfi, record); + if(error != EmvErrorNone) break; + + if(!emv_decode_response_tlv( + bit_buffer_get_data(instance->rx_buffer), + bit_buffer_get_size_bytes(instance->rx_buffer), + &instance->data->emv_application)) { + error = EmvErrorProtocol; + FURI_LOG_T(TAG, "Failed to parse SFI 0x%X record %d", sfi, record); + } + } + } + if(pan_fetched) + return EmvErrorNone; + else + return error; } static EmvError emv_poller_req_get_data(EmvPoller* instance, uint16_t tag) { @@ -684,8 +710,8 @@ static EmvError emv_poller_req_get_data(EmvPoller* instance, uint16_t tag) { return error; } -EmvError emv_poller_get_pin_attempts_counter(EmvPoller* instance) { - return emv_poller_req_get_data(instance, EMV_TAG_PIN_ATTEMPTS_COUNTER); +EmvError emv_poller_get_pin_try_counter(EmvPoller* instance) { + return emv_poller_req_get_data(instance, EMV_TAG_PIN_TRY_COUNTER); } EmvError emv_poller_get_last_online_atc(EmvPoller* instance) { diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index d0a09d835..cb2c9cce8 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -890,7 +890,7 @@ Function,+,emv_get_uid,const uint8_t*,"const EmvData*, size_t*" Function,+,emv_is_equal,_Bool,"const EmvData*, const EmvData*" Function,+,emv_load,_Bool,"EmvData*, FlipperFormat*, uint32_t" Function,+,emv_poller_get_last_online_atc,EmvError,EmvPoller* -Function,+,emv_poller_get_pin_attempts_counter,EmvError,EmvPoller* +Function,+,emv_poller_get_pin_try_counter,EmvError,EmvPoller* Function,+,emv_poller_get_processing_options,EmvError,EmvPoller* Function,+,emv_poller_read_afl,EmvError,EmvPoller* Function,+,emv_poller_read_log_entry,EmvError,EmvPoller*