Read PIN tries and transactions counters

This commit is contained in:
Nikita Vostokov 2024-01-29 00:07:17 +00:00
parent 1074af905c
commit 653af9a5cd
8 changed files with 74 additions and 38 deletions

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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,
};

View file

@ -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

View file

@ -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;
}

View file

@ -14,7 +14,7 @@ typedef enum {
EmvPollerStateSelectApplication,
EmvPollerStateGetProcessingOptions,
EmvPollerStateReadFiles,
EmvPollerStateReadLogs,
EmvPollerStateReadExtra,
EmvPollerStateReadFailed,
EmvPollerStateReadSuccess,

View file

@ -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*

1 entry status name type params
2 Version + 52.1 52.3
3 Header + applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h
4 Header + applications/services/bt/bt_service/bt.h
5 Header + applications/services/cli/cli.h
887 Function + emv_get_uid const uint8_t* const EmvData*, size_t*
888 Function + emv_is_equal _Bool const EmvData*, const EmvData*
889 Function + emv_load _Bool EmvData*, FlipperFormat*, uint32_t
890 Function + emv_poller_get_last_online_atc EmvError EmvPoller*
891 Function + emv_poller_get_pin_try_counter EmvError EmvPoller*
892 Function + emv_poller_get_processing_options EmvError EmvPoller*
893 Function + emv_poller_read_afl EmvError EmvPoller*
894 Function + emv_poller_read_log_entry EmvError EmvPoller*