Skip to content

Commit

Permalink
Read PIN tries and transactions counters
Browse files Browse the repository at this point in the history
  • Loading branch information
wosk committed Jan 29, 2024
1 parent 1074af9 commit 653af9a
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 38 deletions.
17 changes: 12 additions & 5 deletions applications/main/nfc/helpers/protocol_support/emv/emv_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
}
1 change: 1 addition & 0 deletions lib/nfc/protocols/emv/emv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
8 changes: 8 additions & 0 deletions lib/nfc/protocols/emv/emv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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];
Expand All @@ -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;
Expand Down
28 changes: 8 additions & 20 deletions lib/nfc/protocols/emv/emv_poller.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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,
};
Expand Down
4 changes: 4 additions & 0 deletions lib/nfc/protocols/emv/emv_poller.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
48 changes: 37 additions & 11 deletions lib/nfc/protocols/emv/emv_poller_i.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;

Expand Down Expand Up @@ -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;
}
2 changes: 1 addition & 1 deletion lib/nfc/protocols/emv/emv_poller_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ typedef enum {
EmvPollerStateSelectApplication,
EmvPollerStateGetProcessingOptions,
EmvPollerStateReadFiles,
EmvPollerStateReadLogs,
EmvPollerStateReadExtra,
EmvPollerStateReadFailed,
EmvPollerStateReadSuccess,

Expand Down
4 changes: 3 additions & 1 deletion targets/f7/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -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,,
Expand Down Expand Up @@ -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*
Expand Down

0 comments on commit 653af9a

Please sign in to comment.