mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-26 14:30:25 +00:00
Read PIN tries and transactions counters
This commit is contained in:
parent
1074af905c
commit
653af9a5cd
8 changed files with 74 additions and 38 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ typedef enum {
|
|||
EmvPollerStateSelectApplication,
|
||||
EmvPollerStateGetProcessingOptions,
|
||||
EmvPollerStateReadFiles,
|
||||
EmvPollerStateReadLogs,
|
||||
EmvPollerStateReadExtra,
|
||||
EmvPollerStateReadFailed,
|
||||
EmvPollerStateReadSuccess,
|
||||
|
||||
|
|
|
@ -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*
|
||||
|
|
|
Loading…
Reference in a new issue