diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c index 463f7355e..cc8a46efe 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -91,10 +91,20 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { furi_record_close(RECORD_STORAGE); } +static void nfc_render_emv_pin_try_counter(uint8_t counter, FuriString* str) { + if(counter == 0xff) return; + furi_string_cat_printf(str, "PIN try left: %d\n", counter); +} + void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { + if(apl->transaction_counter) + furi_string_cat_printf(str, "Transactions: %d\n", apl->transaction_counter); + if(apl->last_online_atc) + furi_string_cat_printf(str, "Last Online ATC: %d\n", apl->last_online_atc); + const uint8_t len = apl->active_tr; if(!len) { - furi_string_cat_printf(str, "No transaction info\n"); + furi_string_cat_printf(str, "No transactions info\n"); return; } @@ -163,8 +173,5 @@ void nfc_render_emv_extra(const EmvData* data, FuriString* str) { nfc_render_emv_currency(data->emv_application.currency_code, str); nfc_render_emv_country(data->emv_application.country_code, str); nfc_render_emv_application(&data->emv_application, str); - // PIN try - // transactions counter - - //nfc_render_emv_transactions(&data->emv_application, str); + nfc_render_emv_pin_try_counter(data->emv_application.pin_try_counter, str); } diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index 2a6c83101..bbeacffb8 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -27,6 +27,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_try_counter = 0xff; return data; } diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index b565ee334..42aa1a703 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -8,15 +8,19 @@ extern "C" { #define MAX_APDU_LEN 255 +#define EMV_REQ_GET_DATA 0x80CA + #define EMV_TAG_APP_TEMPLATE 0x61 #define EMV_TAG_AID 0x4F #define EMV_TAG_PRIORITY 0x87 #define EMV_TAG_PDOL 0x9F38 #define EMV_TAG_CARD_NAME 0x50 #define EMV_TAG_FCI 0xBF0C +#define EMV_TAG_PIN_TRY_COUNTER 0x9F17 #define EMV_TAG_LOG_ENTRY 0x9F4D #define EMV_TAG_LOG_FMT 0x9F4F +#define EMV_TAG_LAST_ONLINE_ATC 0x9F13 #define EMV_TAG_ATC 0x9F36 #define EMV_TAG_LOG_AMOUNT 0x9F02 #define EMV_TAG_LOG_COUNTRY 0x9F1A @@ -63,6 +67,7 @@ typedef struct { uint8_t log_fmt[50]; uint8_t log_fmt_len; uint8_t active_tr; + bool saving_trans_list; Transaction trans[16]; uint8_t priority; uint8_t aid[16]; @@ -75,6 +80,9 @@ typedef struct { uint8_t exp_year; uint16_t country_code; uint16_t currency_code; + uint8_t pin_try_counter; + uint16_t transaction_counter; + uint16_t last_online_atc; APDU pdol; APDU afl; } EmvApplication; diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 70051afcd..7907908fd 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -96,17 +96,12 @@ static NfcCommand emv_poller_handler_get_processing_options(EmvPoller* instance) if(instance->error == EmvErrorNone) { FURI_LOG_D(TAG, "Get processing options success"); - if(instance->data->emv_application.pan_len > 0) { - instance->state = EmvPollerStateReadSuccess; - } else { - FURI_LOG_D(TAG, "No PAN still. Read SFI files"); - instance->state = EmvPollerStateReadFiles; - } } else { FURI_LOG_E(TAG, "Failed to get processing options"); - instance->state = EmvPollerStateReadFiles; } + // Read another informations + instance->state = EmvPollerStateReadFiles; return NfcCommandContinue; } @@ -115,10 +110,7 @@ static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { if(instance->error == EmvErrorNone) { FURI_LOG_D(TAG, "Read files success"); - if(instance->data->emv_application.log_sfi) - instance->state = EmvPollerStateReadLogs; - else - instance->state = EmvPollerStateReadSuccess; + instance->state = EmvPollerStateReadExtra; } else { FURI_LOG_E(TAG, "Failed to read files"); instance->state = EmvPollerStateReadFailed; @@ -127,14 +119,10 @@ static NfcCommand emv_poller_handler_read_files(EmvPoller* instance) { return NfcCommandContinue; } -static NfcCommand emv_poller_handler_read_logs(EmvPoller* instance) { - instance->error = emv_poller_read_log_entry(instance); - - if(instance->error == EmvErrorNone) { - FURI_LOG_D(TAG, "Log entries had been read"); - } else { - FURI_LOG_D(TAG, "No log entry"); - } +static NfcCommand emv_poller_handler_read_extra_data(EmvPoller* instance) { + emv_poller_read_log_entry(instance); + emv_poller_get_last_online_atc(instance); + emv_poller_get_pin_try_counter(instance); instance->state = EmvPollerStateReadSuccess; return NfcCommandContinue; @@ -163,7 +151,7 @@ static const EmvPollerReadHandler emv_poller_read_handler[EmvPollerStateNum] = { [EmvPollerStateSelectApplication] = emv_poller_handler_select_application, [EmvPollerStateGetProcessingOptions] = emv_poller_handler_get_processing_options, [EmvPollerStateReadFiles] = emv_poller_handler_read_files, - [EmvPollerStateReadLogs] = emv_poller_handler_read_logs, + [EmvPollerStateReadExtra] = emv_poller_handler_read_extra_data, [EmvPollerStateReadFailed] = emv_poller_handler_read_fail, [EmvPollerStateReadSuccess] = emv_poller_handler_read_success, }; diff --git a/lib/nfc/protocols/emv/emv_poller.h b/lib/nfc/protocols/emv/emv_poller.h index c2335bfa4..64bd0be9d 100644 --- a/lib/nfc/protocols/emv/emv_poller.h +++ b/lib/nfc/protocols/emv/emv_poller.h @@ -50,6 +50,10 @@ EmvError emv_poller_read_afl(EmvPoller* instance); EmvError emv_poller_read_log_entry(EmvPoller* instance); +EmvError emv_poller_get_pin_try_counter(EmvPoller* instance); + +EmvError emv_poller_get_last_online_atc(EmvPoller* instance); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 99e7c9759..7288c473c 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -249,8 +249,15 @@ static bool app->log_sfi, app->log_records); break; + case EMV_TAG_LAST_ONLINE_ATC: + app->last_online_atc = (buff[i] << 8 | buff[i + 1]); + success = true; + break; case EMV_TAG_ATC: - app->trans[app->active_tr].atc = (buff[i] << 8 | buff[i + 1]); + if(app->saving_trans_list) + app->trans[app->active_tr].atc = (buff[i] << 8 | buff[i + 1]); + else + app->transaction_counter = (buff[i] << 8 | buff[i + 1]); success = true; break; case EMV_TAG_LOG_AMOUNT: @@ -273,6 +280,11 @@ static bool memcpy(&app->trans[app->active_tr].time, &buff[i], tlen); success = true; break; + case EMV_TAG_PIN_TRY_COUNTER: + app->pin_try_counter = buff[i]; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_PIN_TRY_COUNTER %x: %d", tag, app->pin_try_counter); + break; } return success; } @@ -616,29 +628,28 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { return error; } -static EmvError emv_poller_get_log_format(EmvPoller* instance) { +static EmvError emv_poller_req_get_data(EmvPoller* instance, uint16_t tag) { EmvError error = EmvErrorNone; - const uint8_t cla_ins[] = {0x80, 0xCA}; - bit_buffer_reset(instance->tx_buffer); bit_buffer_reset(instance->rx_buffer); - bit_buffer_copy_bytes(instance->tx_buffer, cla_ins, sizeof(cla_ins)); - bit_buffer_append_byte(instance->tx_buffer, EMV_TAG_LOG_FMT >> 8); - bit_buffer_append_byte(instance->tx_buffer, EMV_TAG_LOG_FMT & 0xFF); + bit_buffer_append_byte(instance->tx_buffer, EMV_REQ_GET_DATA >> 8); + bit_buffer_append_byte(instance->tx_buffer, EMV_REQ_GET_DATA & 0xFF); + bit_buffer_append_byte(instance->tx_buffer, tag >> 8); + bit_buffer_append_byte(instance->tx_buffer, tag & 0xFF); bit_buffer_append_byte(instance->tx_buffer, 0x00); //Length do { - FURI_LOG_D(TAG, "Get log format"); + FURI_LOG_D(TAG, "Get data for tag 0x%x", tag); Iso14443_4aError iso14443_4a_error = iso14443_4a_poller_send_block_pwt_ext( instance->iso14443_4a_poller, instance->tx_buffer, instance->rx_buffer); - emv_trace(instance, "Get log format answer:"); + emv_trace(instance, "Get log data answer:"); if(iso14443_4a_error != Iso14443_4aErrorNone) { - FURI_LOG_E(TAG, "Failed to get log format, error %u", iso14443_4a_error); + FURI_LOG_E(TAG, "Failed to get data, error %u", iso14443_4a_error); error = emv_process_error(iso14443_4a_error); break; } @@ -650,21 +661,35 @@ static EmvError emv_poller_get_log_format(EmvPoller* instance) { bit_buffer_get_size_bytes(instance->rx_buffer), &instance->data->emv_application)) { error = EmvErrorProtocol; - FURI_LOG_E(TAG, "Failed to parse log format"); + FURI_LOG_E(TAG, "Failed to parse get data"); } } while(false); return error; } +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) { + return emv_poller_req_get_data(instance, EMV_TAG_LAST_ONLINE_ATC); +} + +static EmvError emv_poller_get_log_format(EmvPoller* instance) { + return emv_poller_req_get_data(instance, EMV_TAG_LOG_FMT); +} + EmvError emv_poller_read_log_entry(EmvPoller* instance) { EmvError error = EmvErrorProtocol; + if(!instance->data->emv_application.log_sfi) return error; uint8_t records = instance->data->emv_application.log_records; if(records == 0) { return error; } + instance->data->emv_application.saving_trans_list = true; error = emv_poller_get_log_format(instance); if(error != EmvErrorNone) return error; @@ -694,5 +719,6 @@ EmvError emv_poller_read_log_entry(EmvPoller* instance) { COUNT_OF(instance->data->emv_application.trans)); } + instance->data->emv_application.saving_trans_list = false; return error; } diff --git a/lib/nfc/protocols/emv/emv_poller_i.h b/lib/nfc/protocols/emv/emv_poller_i.h index 554560a25..620d2f359 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.h +++ b/lib/nfc/protocols/emv/emv_poller_i.h @@ -14,7 +14,7 @@ typedef enum { EmvPollerStateSelectApplication, EmvPollerStateGetProcessingOptions, EmvPollerStateReadFiles, - EmvPollerStateReadLogs, + EmvPollerStateReadExtra, EmvPollerStateReadFailed, EmvPollerStateReadSuccess, diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index f53c4d0ca..948f957b5 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,52.1,, +Version,+,52.3,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -887,6 +887,8 @@ Function,+,emv_get_device_name,const char*,"const EmvData*, NfcDeviceNameType" 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_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*