From 9ceae3a3b28c7a25002434aca12e7f70e9fd5fe7 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Fri, 2 Feb 2024 00:20:31 +0000 Subject: [PATCH 01/20] [EMV] Fix crash while PDOL parsing --- lib/nfc/protocols/emv/emv_poller_i.c | 56 ++++++++++++---------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index c237125b2..bdf1ecce4 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -76,39 +76,6 @@ static void emv_trace(EmvPoller* instance, const char* message) { } } -static uint16_t emv_prepare_pdol(APDU* dest, APDU* src) { - bool tag_found; - for(uint16_t i = 0; i < src->size; i++) { - tag_found = false; - for(uint8_t j = 0; j < sizeof(pdol_values) / sizeof(PDOLValue*); j++) { - if(src->data[i] == pdol_values[j]->tag) { - // Found tag with 1 byte length - uint8_t len = src->data[++i]; - memcpy(dest->data + dest->size, pdol_values[j]->data, len); - dest->size += len; - tag_found = true; - break; - } else if(((src->data[i] << 8) | src->data[i + 1]) == pdol_values[j]->tag) { - // Found tag with 2 byte length - i += 2; - uint8_t len = src->data[i]; - memcpy(dest->data + dest->size, pdol_values[j]->data, len); - dest->size += len; - tag_found = true; - break; - } - } - if(!tag_found) { - // Unknown tag, fill zeros - i += 2; - uint8_t len = src->data[i]; - memset(dest->data + dest->size, 0, len); - dest->size += len; - } - } - return dest->size; -} - static bool emv_decode_tlv_tag(const uint8_t* buff, uint16_t tag, uint8_t tlen, EmvApplication* app) { uint8_t i = 0; @@ -406,6 +373,29 @@ static bool emv_decode_response_tlv(const uint8_t* buff, uint8_t len, EmvApplica return success; } +static void emv_prepare_pdol(APDU* dest, APDU* src) { + uint16_t tag = 0; + uint8_t tlen = 0; + uint8_t i = 0; + while(i < src->size) { + bool tag_found = emv_parse_tag(src->data, src->size, &tag, &tlen, &i); + if(tag_found) { + for(uint8_t j = 0; j < COUNT_OF(pdol_values); j++) { + if(tag == pdol_values[j]->tag) { + memcpy(dest->data + dest->size, pdol_values[j]->data, tlen); + dest->size += tlen; + break; + } + } + } else { + // Unknown tag, fill zeros + furi_check(dest->size + tlen < sizeof(dest->data)); + memset(dest->data + dest->size, 0, tlen); + dest->size += tlen; + } + } +} + EmvError emv_poller_select_ppse(EmvPoller* instance) { EmvError error = EmvErrorNone; From b1674711a15b15f26f6582f98c0f36c7bc14ec47 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Fri, 2 Feb 2024 00:44:19 +0000 Subject: [PATCH 02/20] [EMV] Add Effective date and Preferred Name --- .../helpers/protocol_support/emv/emv_render.c | 25 +++++++++++++++++-- .../main/nfc/plugins/supported_cards/emv.c | 4 +-- lib/nfc/protocols/emv/emv.c | 19 +++++++++++--- lib/nfc/protocols/emv/emv.h | 20 +++++++++++---- lib/nfc/protocols/emv/emv_poller_i.c | 20 ++++++++++++--- 5 files changed, 73 insertions(+), 15 deletions(-) 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 a01a0ba68..95b5b9662 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -88,11 +88,32 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { return; } - furi_string_cat_printf(str, "AID: "); + furi_string_cat_printf(str, "Application:\n"); + if(strlen(apl->label)) { + furi_string_cat_printf(str, " Label: %s", apl->label); + furi_string_cat_printf(str, "\n"); + } + + if(strlen(apl->name)) { + furi_string_cat_printf(str, " Name: %s", apl->name); + furi_string_cat_printf(str, "\n"); + } + + furi_string_cat_printf(str, " AID:"); for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); - furi_string_cat_printf(str, "\n"); + + if(apl->eff_month) { + furi_string_cat_printf( + str, " Effective: 20%02X/%02X/%02X", apl->eff_year, apl->eff_month, apl->eff_day); + furi_string_cat_printf(str, "\n"); + } + if(apl->exp_month) { + furi_string_cat_printf( + str, " Expire: 20%02X/%02X/%02X", apl->exp_year, apl->exp_month, apl->exp_day); + furi_string_cat_printf(str, "\n"); + } } static void nfc_render_emv_pin_try_counter(uint8_t counter, FuriString* str) { diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index a8253edff..50d63d1ed 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -73,8 +73,8 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { const EmvApplication app = data->emv_application; do { - if(app.name_found) - furi_string_cat_printf(parsed_data, "\e#%s\n", app.name); + if(strlen(app.label)) + furi_string_cat_printf(parsed_data, "\e#%s\n", app.label); else furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index 4cdacaefe..73020535b 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -76,10 +76,12 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { EmvApplication* app = &data->emv_application; - //Read name if(!flipper_format_read_string(ff, "Name", temp_str)) break; strcpy(app->name, furi_string_get_cstr(temp_str)); - if(app->name[0] != '\0') app->name_found = true; + + //Read label + if(!flipper_format_read_string(ff, "Label", temp_str)) break; + strcpy(app->label, furi_string_get_cstr(temp_str)); uint32_t pan_len; if(!flipper_format_read_uint32(ff, "PAN length", &pan_len, 1)) break; @@ -99,6 +101,11 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { if(!flipper_format_read_hex(ff, "Expiration year", &app->exp_year, 1)) break; if(!flipper_format_read_hex(ff, "Expiration month", &app->exp_month, 1)) break; + if(!flipper_format_read_hex(ff, "Expiration day", &app->exp_day, 1)) break; + + if(!flipper_format_read_hex(ff, "Effective year", &app->eff_year, 1)) break; + if(!flipper_format_read_hex(ff, "Effective month", &app->eff_month, 1)) break; + if(!flipper_format_read_hex(ff, "Effective day", &app->eff_day, 1)) break; uint32_t pin_try_counter; if(!flipper_format_read_uint32(ff, "PIN counter", &pin_try_counter, 1)) break; @@ -126,6 +133,8 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) { if(!flipper_format_write_string_cstr(ff, "Name", app.name)) break; + if(!flipper_format_write_string_cstr(ff, "Label", app.label)) break; + uint32_t pan_len = app.pan_len; if(!flipper_format_write_uint32(ff, "PAN length", &pan_len, 1)) break; @@ -141,8 +150,12 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) { if(!flipper_format_write_hex(ff, "Currency code", (uint8_t*)&app.currency_code, 2)) break; if(!flipper_format_write_hex(ff, "Expiration year", (uint8_t*)&app.exp_year, 1)) break; - if(!flipper_format_write_hex(ff, "Expiration month", (uint8_t*)&app.exp_month, 1)) break; + if(!flipper_format_write_hex(ff, "Expiration day", (uint8_t*)&app.exp_day, 1)) break; + + if(!flipper_format_write_hex(ff, "Effective year", (uint8_t*)&app.eff_year, 1)) break; + if(!flipper_format_write_hex(ff, "Effective month", (uint8_t*)&app.eff_month, 1)) break; + if(!flipper_format_write_hex(ff, "Effective day", (uint8_t*)&app.eff_day, 1)) break; if(!flipper_format_write_uint32(ff, "PIN counter", (uint32_t*)&app.pin_try_counter, 1)) break; diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index 42aa1a703..f47211662 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -10,12 +10,12 @@ extern "C" { #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_APPL_LABEL 0x50 +#define EMV_TAG_APPL_NAME 0x9F12 +#define EMV_TAG_APPL_EFFECTIVE 0x5F25 #define EMV_TAG_PIN_TRY_COUNTER 0x9F17 #define EMV_TAG_LOG_ENTRY 0x9F4D #define EMV_TAG_LOG_FMT 0x9F4F @@ -42,6 +42,12 @@ extern "C" { #define EMV_TAG_RESP_BUF_SIZE 0x6C #define EMV_TAG_RESP_BYTES_AVAILABLE 0x61 +// Not used tags +#define EMV_TAG_FORM_FACTOR 0x9F6E +#define EMV_TAG_APP_TEMPLATE 0x61 +#define EMV_TAG_FCI 0xBF0C +#define EMV_TAG_DEPOSIT_LOG_ENTRY 0xDF4D + typedef struct { uint16_t tag; uint8_t data[]; @@ -72,12 +78,16 @@ typedef struct { uint8_t priority; uint8_t aid[16]; uint8_t aid_len; - char name[32]; - bool name_found; + char name[16 + 1]; + char label[16 + 1]; uint8_t pan[10]; // card_number uint8_t pan_len; + uint8_t exp_day; uint8_t exp_month; uint8_t exp_year; + uint8_t eff_day; + uint8_t eff_month; + uint8_t eff_year; uint16_t country_code; uint16_t currency_code; uint8_t pin_try_counter; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index bdf1ecce4..bdfcf7fe2 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -114,12 +114,25 @@ static bool success = true; FURI_LOG_T(TAG, "found EMV_TAG_APP_PRIORITY %X: %d", tag, app->priority); break; - case EMV_TAG_CARD_NAME: + case EMV_TAG_APPL_LABEL: + memcpy(app->label, &buff[i], tlen); + app->label[tlen] = '\0'; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_APPL_LABEL %x: %s", tag, app->label); + break; + case EMV_TAG_APPL_NAME: + furi_check(tlen < sizeof(app->name)); memcpy(app->name, &buff[i], tlen); app->name[tlen] = '\0'; - app->name_found = true; success = true; - FURI_LOG_T(TAG, "found EMV_TAG_CARD_NAME %x : %s", tag, app->name); + FURI_LOG_T(TAG, "found EMV_TAG_APPL_NAME %x: %s", tag, app->name); + break; + case EMV_TAG_APPL_EFFECTIVE: + app->eff_year = buff[i]; + app->eff_month = buff[i + 1]; + app->eff_day = buff[i + 2]; + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_APPL_EFFECTIVE %x:", tag); break; case EMV_TAG_PDOL: memcpy(app->pdol.data, &buff[i], tlen); @@ -192,6 +205,7 @@ static bool case EMV_TAG_EXP_DATE: app->exp_year = buff[i]; app->exp_month = buff[i + 1]; + app->exp_day = buff[i + 2]; success = true; FURI_LOG_T(TAG, "found EMV_TAG_EXP_DATE %x", tag); break; From ec356626fa07cb855dae813da530909d7a242e38 Mon Sep 17 00:00:00 2001 From: Methodius Date: Fri, 2 Feb 2024 17:32:02 +0900 Subject: [PATCH 03/20] code cleanup, gui fixes --- .../helpers/protocol_support/emv/emv_render.c | 34 ------------------- .../helpers/protocol_support/emv/emv_render.h | 2 -- .../main/nfc/plugins/supported_cards/emv.c | 25 +++++++++++--- lib/nfc/protocols/emv/emv.c | 18 +++++----- lib/nfc/protocols/emv/emv.h | 12 +++---- lib/nfc/protocols/emv/emv_poller_i.c | 18 +++++----- 6 files changed, 45 insertions(+), 64 deletions(-) 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 95b5b9662..9fb6fc83f 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -63,11 +63,6 @@ void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) furi_string_cat_printf(str, "\n"); } -void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str) { - if(apl->exp_month == 0) return; - furi_string_cat_printf(str, "Exp: %02X/%02X\n", apl->exp_month, apl->exp_year); -} - void nfc_render_emv_currency(uint16_t cur_code, FuriString* str) { if(!cur_code) return; @@ -88,37 +83,9 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { return; } - furi_string_cat_printf(str, "Application:\n"); - - if(strlen(apl->label)) { - furi_string_cat_printf(str, " Label: %s", apl->label); - furi_string_cat_printf(str, "\n"); - } - - if(strlen(apl->name)) { - furi_string_cat_printf(str, " Name: %s", apl->name); - furi_string_cat_printf(str, "\n"); - } - furi_string_cat_printf(str, " AID:"); for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); furi_string_cat_printf(str, "\n"); - - if(apl->eff_month) { - furi_string_cat_printf( - str, " Effective: 20%02X/%02X/%02X", apl->eff_year, apl->eff_month, apl->eff_day); - furi_string_cat_printf(str, "\n"); - } - if(apl->exp_month) { - furi_string_cat_printf( - str, " Expire: 20%02X/%02X/%02X", apl->exp_year, apl->exp_month, apl->exp_day); - furi_string_cat_printf(str, "\n"); - } -} - -static void nfc_render_emv_pin_try_counter(uint8_t counter, FuriString* str) { - if(counter == 0xff) return; - furi_string_cat_printf(str, "PIN attempts left: %d\n", counter); } void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { @@ -207,5 +174,4 @@ 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_pin_try_counter(data->emv_application.pin_try_counter, str); } diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h index 855acdc4a..d2dabe965 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h @@ -17,8 +17,6 @@ void nfc_render_emv_application(const EmvApplication* data, FuriString* str); void nfc_render_emv_extra(const EmvData* data, FuriString* str); -void nfc_render_emv_expired(const EmvApplication* apl, FuriString* str); - void nfc_render_emv_country(uint16_t country_code, FuriString* str); void nfc_render_emv_currency(uint16_t cur_code, FuriString* str); diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index 50d63d1ed..b4037245d 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -73,8 +73,8 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { const EmvApplication app = data->emv_application; do { - if(strlen(app.label)) - furi_string_cat_printf(parsed_data, "\e#%s\n", app.label); + if(strlen(app.payment_sys)) + furi_string_cat_printf(parsed_data, "\e#%s\n", app.payment_sys); else furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); @@ -87,12 +87,29 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { // Cut padding 'F' from card number size_t end = furi_string_search_rchar(pan, 'F'); if(end) furi_string_left(pan, end); + furi_string_cat_printf(pan, "\n"); furi_string_cat(parsed_data, pan); + furi_string_free(pan); } - if(app.exp_month | app.exp_year) - furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X\n", app.exp_month, app.exp_year); + if(strlen(app.name)) furi_string_cat_printf(parsed_data, "Name: %s\n", app.name); + + if(app.issue_month) + furi_string_cat_printf( + parsed_data, + "Issue: %02X.%02X.20%02X\n", + app.issue_day, + app.issue_month, + app.issue_year); + + if(app.exp_month) + furi_string_cat_printf( + parsed_data, + "Expires: %02X.%02X.20%02X\n", + app.exp_day, + app.exp_month, + app.exp_year); FuriString* str = furi_string_alloc(); bool storage_readed = emv_get_country_name(app.country_code, str); diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index 73020535b..b3ab39d8a 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -80,8 +80,8 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { strcpy(app->name, furi_string_get_cstr(temp_str)); //Read label - if(!flipper_format_read_string(ff, "Label", temp_str)) break; - strcpy(app->label, furi_string_get_cstr(temp_str)); + if(!flipper_format_read_string(ff, "Payment system", temp_str)) break; + strcpy(app->payment_sys, furi_string_get_cstr(temp_str)); uint32_t pan_len; if(!flipper_format_read_uint32(ff, "PAN length", &pan_len, 1)) break; @@ -103,9 +103,9 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { if(!flipper_format_read_hex(ff, "Expiration month", &app->exp_month, 1)) break; if(!flipper_format_read_hex(ff, "Expiration day", &app->exp_day, 1)) break; - if(!flipper_format_read_hex(ff, "Effective year", &app->eff_year, 1)) break; - if(!flipper_format_read_hex(ff, "Effective month", &app->eff_month, 1)) break; - if(!flipper_format_read_hex(ff, "Effective day", &app->eff_day, 1)) break; + if(!flipper_format_read_hex(ff, "Issue year", &app->issue_year, 1)) break; + if(!flipper_format_read_hex(ff, "Issue month", &app->issue_month, 1)) break; + if(!flipper_format_read_hex(ff, "Issue day", &app->issue_day, 1)) break; uint32_t pin_try_counter; if(!flipper_format_read_uint32(ff, "PIN counter", &pin_try_counter, 1)) break; @@ -133,7 +133,7 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) { if(!flipper_format_write_string_cstr(ff, "Name", app.name)) break; - if(!flipper_format_write_string_cstr(ff, "Label", app.label)) break; + if(!flipper_format_write_string_cstr(ff, "Payment system", app.payment_sys)) break; uint32_t pan_len = app.pan_len; if(!flipper_format_write_uint32(ff, "PAN length", &pan_len, 1)) break; @@ -153,9 +153,9 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) { if(!flipper_format_write_hex(ff, "Expiration month", (uint8_t*)&app.exp_month, 1)) break; if(!flipper_format_write_hex(ff, "Expiration day", (uint8_t*)&app.exp_day, 1)) break; - if(!flipper_format_write_hex(ff, "Effective year", (uint8_t*)&app.eff_year, 1)) break; - if(!flipper_format_write_hex(ff, "Effective month", (uint8_t*)&app.eff_month, 1)) break; - if(!flipper_format_write_hex(ff, "Effective day", (uint8_t*)&app.eff_day, 1)) break; + if(!flipper_format_write_hex(ff, "Issue year", (uint8_t*)&app.issue_year, 1)) break; + if(!flipper_format_write_hex(ff, "Issue month", (uint8_t*)&app.issue_month, 1)) break; + if(!flipper_format_write_hex(ff, "Issue day", (uint8_t*)&app.issue_day, 1)) break; if(!flipper_format_write_uint32(ff, "PIN counter", (uint32_t*)&app.pin_try_counter, 1)) break; diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index f47211662..a1a95f48e 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -13,9 +13,9 @@ extern "C" { #define EMV_TAG_AID 0x4F #define EMV_TAG_PRIORITY 0x87 #define EMV_TAG_PDOL 0x9F38 -#define EMV_TAG_APPL_LABEL 0x50 +#define EMV_TAG_APPL_PAYMENT_SYS 0x50 #define EMV_TAG_APPL_NAME 0x9F12 -#define EMV_TAG_APPL_EFFECTIVE 0x5F25 +#define EMV_TAG_APPL_ISSUE 0x5F25 #define EMV_TAG_PIN_TRY_COUNTER 0x9F17 #define EMV_TAG_LOG_ENTRY 0x9F4D #define EMV_TAG_LOG_FMT 0x9F4F @@ -79,15 +79,15 @@ typedef struct { uint8_t aid[16]; uint8_t aid_len; char name[16 + 1]; - char label[16 + 1]; + char payment_sys[16 + 1]; uint8_t pan[10]; // card_number uint8_t pan_len; uint8_t exp_day; uint8_t exp_month; uint8_t exp_year; - uint8_t eff_day; - uint8_t eff_month; - uint8_t eff_year; + uint8_t issue_day; + uint8_t issue_month; + uint8_t issue_year; uint16_t country_code; uint16_t currency_code; uint8_t pin_try_counter; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index bdfcf7fe2..e6ae6d5a9 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -114,11 +114,11 @@ static bool success = true; FURI_LOG_T(TAG, "found EMV_TAG_APP_PRIORITY %X: %d", tag, app->priority); break; - case EMV_TAG_APPL_LABEL: - memcpy(app->label, &buff[i], tlen); - app->label[tlen] = '\0'; + case EMV_TAG_APPL_PAYMENT_SYS: + memcpy(app->payment_sys, &buff[i], tlen); + app->payment_sys[tlen] = '\0'; success = true; - FURI_LOG_T(TAG, "found EMV_TAG_APPL_LABEL %x: %s", tag, app->label); + FURI_LOG_T(TAG, "found EMV_TAG_APPL_PAYMENT_SYS %x: %s", tag, app->payment_sys); break; case EMV_TAG_APPL_NAME: furi_check(tlen < sizeof(app->name)); @@ -127,12 +127,12 @@ static bool success = true; FURI_LOG_T(TAG, "found EMV_TAG_APPL_NAME %x: %s", tag, app->name); break; - case EMV_TAG_APPL_EFFECTIVE: - app->eff_year = buff[i]; - app->eff_month = buff[i + 1]; - app->eff_day = buff[i + 2]; + case EMV_TAG_APPL_ISSUE: + app->issue_year = buff[i]; + app->issue_month = buff[i + 1]; + app->issue_day = buff[i + 2]; success = true; - FURI_LOG_T(TAG, "found EMV_TAG_APPL_EFFECTIVE %x:", tag); + FURI_LOG_T(TAG, "found EMV_TAG_APPL_ISSUE %x:", tag); break; case EMV_TAG_PDOL: memcpy(app->pdol.data, &buff[i], tlen); From d195de502e49bb4f69b93daa57e5703071201901 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Thu, 8 Feb 2024 23:30:38 +0000 Subject: [PATCH 04/20] Fix PDOL parsing --- .../helpers/protocol_support/emv/emv_render.c | 14 +--------- lib/nfc/protocols/emv/emv_poller_i.c | 28 ++++++++++++------- 2 files changed, 19 insertions(+), 23 deletions(-) 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 9fb6fc83f..091db9ebe 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -29,18 +29,6 @@ void nfc_render_emv_uid(const uint8_t* uid, const uint8_t uid_len, FuriString* s furi_string_cat_printf(str, "\n"); } -void nfc_render_emv_aid(const uint8_t* uid, const uint8_t uid_len, FuriString* str) { - if(uid_len == 0) return; - - furi_string_cat_printf(str, "UID: "); - - for(uint8_t i = 0; i < uid_len; i++) { - furi_string_cat_printf(str, "%02X ", uid[i]); - } - - furi_string_cat_printf(str, "\n"); -} - void nfc_render_emv_data(const EmvData* data, FuriString* str) { nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); nfc_render_emv_name(data->emv_application.name, str); @@ -83,7 +71,7 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { return; } - furi_string_cat_printf(str, " AID:"); + furi_string_cat_printf(str, "AID: "); for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); furi_string_cat_printf(str, "\n"); } diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index e6ae6d5a9..9ccf28a02 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -3,6 +3,7 @@ #define TAG "EMVPoller" +// "Terminal" parameters, which could be requested by card const PDOLValue pdol_term_info = {0x9F59, {0xC8, 0x80, 0x00}}; // Terminal transaction information const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type const PDOLValue pdol_merchant_type = {0x9F58, {0x01}}; // Merchant type indicator @@ -392,18 +393,25 @@ static void emv_prepare_pdol(APDU* dest, APDU* src) { uint8_t tlen = 0; uint8_t i = 0; while(i < src->size) { - bool tag_found = emv_parse_tag(src->data, src->size, &tag, &tlen, &i); - if(tag_found) { - for(uint8_t j = 0; j < COUNT_OF(pdol_values); j++) { - if(tag == pdol_values[j]->tag) { - memcpy(dest->data + dest->size, pdol_values[j]->data, tlen); - dest->size += tlen; - break; - } + bool tag_found = false; + if(!emv_parse_tag(src->data, src->size, &tag, &tlen, &i)) { + FURI_LOG_T(TAG, "Parsing PDOL failed at 0x%x", i); + dest->size = 0; + return; + } + + furi_check(dest->size + tlen < sizeof(dest->data)); + for(uint8_t j = 0; j < COUNT_OF(pdol_values); j++) { + if(tag == pdol_values[j]->tag) { + memcpy(dest->data + dest->size, pdol_values[j]->data, tlen); + dest->size += tlen; + tag_found = true; + break; } - } else { + } + + if(!tag_found) { // Unknown tag, fill zeros - furi_check(dest->size + tlen < sizeof(dest->data)); memset(dest->data + dest->size, 0, tlen); dest->size += tlen; } From e6935f2a9dc4d4eed2594d0691923b58a9cf7bbc Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Sat, 10 Feb 2024 01:37:49 +0000 Subject: [PATCH 05/20] Reset transactions widget before enter again --- applications/main/nfc/scenes/nfc_scene_emv_more_info.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/main/nfc/scenes/nfc_scene_emv_more_info.c b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c index 0cddce20a..08f373496 100644 --- a/applications/main/nfc/scenes/nfc_scene_emv_more_info.c +++ b/applications/main/nfc/scenes/nfc_scene_emv_more_info.c @@ -37,6 +37,8 @@ bool nfc_scene_emv_more_info_on_event(void* context, SceneManagerEvent event) { const EmvData* data = nfc_device_get_data(nfc->nfc_device, NfcProtocolEmv); if(event.type == SceneManagerEventTypeCustom) { + widget_reset(nfc->widget); + if(event.event == SubmenuIndexTransactions) { FuriString* temp_str = furi_string_alloc(); nfc_render_emv_transactions(&data->emv_application, temp_str); From ab609bc2949c3695373d9d133a34d80d2d7f5f01 Mon Sep 17 00:00:00 2001 From: Nikita Vostokov <1042932+wosk@users.noreply.github.com> Date: Sat, 10 Feb 2024 01:04:06 +0000 Subject: [PATCH 06/20] WIP: Test for some visa cards * Could break communication with another cards --- lib/nfc/protocols/emv/emv_poller_i.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 9ccf28a02..e027846ee 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -9,20 +9,20 @@ const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type const PDOLValue pdol_merchant_type = {0x9F58, {0x01}}; // Merchant type indicator const PDOLValue pdol_term_trans_qualifies = { 0x9F66, - {0x79, 0x00, 0x40, 0x80}}; // Terminal transaction qualifiers + {0xF6, 0x20, 0xC0, 0x00}}; // Terminal transaction qualifiers const PDOLValue pdol_addtnl_term_qualifies = { 0x9F40, {0x79, 0x00, 0x40, 0x80}}; // Terminal transaction qualifiers const PDOLValue pdol_amount_authorise = { 0x9F02, - {0x00, 0x00, 0x00, 0x10, 0x00, 0x00}}; // Amount, authorised + {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}; // Amount, authorised const PDOLValue pdol_amount = {0x9F03, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Amount -const PDOLValue pdol_country_code = {0x9F1A, {0x01, 0x24}}; // Terminal country code -const PDOLValue pdol_currency_code = {0x5F2A, {0x01, 0x24}}; // Transaction currency code +const PDOLValue pdol_country_code = {0x9F1A, {0x06, 0x43}}; // Terminal country code +const PDOLValue pdol_currency_code = {0x5F2A, {0x06, 0x43}}; // Transaction currency code const PDOLValue pdol_term_verification = { 0x95, {0x00, 0x00, 0x00, 0x00, 0x00}}; // Terminal verification results -const PDOLValue pdol_transaction_date = {0x9A, {0x19, 0x01, 0x01}}; // Transaction date +const PDOLValue pdol_transaction_date = {0x9A, {0x24, 0x02, 0x09}}; // Transaction date const PDOLValue pdol_transaction_type = {0x9C, {0x00}}; // Transaction type const PDOLValue pdol_transaction_cert = {0x98, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; // Transaction cert From 56875ed9a74185bbbd7b6c1705c784778f976287 Mon Sep 17 00:00:00 2001 From: Methodius Date: Sun, 11 Feb 2024 01:18:27 +0900 Subject: [PATCH 07/20] Revert "WIP: Test for some visa cards" This reverts commit ab609bc2949c3695373d9d133a34d80d2d7f5f01. --- lib/nfc/protocols/emv/emv_poller_i.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index e027846ee..9ccf28a02 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -9,20 +9,20 @@ const PDOLValue pdol_term_type = {0x9F5A, {0x00}}; // Terminal transaction type const PDOLValue pdol_merchant_type = {0x9F58, {0x01}}; // Merchant type indicator const PDOLValue pdol_term_trans_qualifies = { 0x9F66, - {0xF6, 0x20, 0xC0, 0x00}}; // Terminal transaction qualifiers + {0x79, 0x00, 0x40, 0x80}}; // Terminal transaction qualifiers const PDOLValue pdol_addtnl_term_qualifies = { 0x9F40, {0x79, 0x00, 0x40, 0x80}}; // Terminal transaction qualifiers const PDOLValue pdol_amount_authorise = { 0x9F02, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x01}}; // Amount, authorised + {0x00, 0x00, 0x00, 0x10, 0x00, 0x00}}; // Amount, authorised const PDOLValue pdol_amount = {0x9F03, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; // Amount -const PDOLValue pdol_country_code = {0x9F1A, {0x06, 0x43}}; // Terminal country code -const PDOLValue pdol_currency_code = {0x5F2A, {0x06, 0x43}}; // Transaction currency code +const PDOLValue pdol_country_code = {0x9F1A, {0x01, 0x24}}; // Terminal country code +const PDOLValue pdol_currency_code = {0x5F2A, {0x01, 0x24}}; // Transaction currency code const PDOLValue pdol_term_verification = { 0x95, {0x00, 0x00, 0x00, 0x00, 0x00}}; // Terminal verification results -const PDOLValue pdol_transaction_date = {0x9A, {0x24, 0x02, 0x09}}; // Transaction date +const PDOLValue pdol_transaction_date = {0x9A, {0x19, 0x01, 0x01}}; // Transaction date const PDOLValue pdol_transaction_type = {0x9C, {0x00}}; // Transaction type const PDOLValue pdol_transaction_cert = {0x98, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; // Transaction cert From 702e4f39abe4794b0a5883585cffd11e32e419ac Mon Sep 17 00:00:00 2001 From: Methodius Date: Sun, 11 Feb 2024 01:32:17 +0900 Subject: [PATCH 08/20] 0x5F25 tag renamed (issue date->effective date) --- .../main/nfc/plugins/supported_cards/emv.c | 10 ++--- lib/nfc/protocols/emv/emv.c | 14 +++--- lib/nfc/protocols/emv/emv.h | 10 ++--- lib/nfc/protocols/emv/emv_poller.c | 2 +- lib/nfc/protocols/emv/emv_poller.h | 2 +- lib/nfc/protocols/emv/emv_poller_i.c | 16 +++---- targets/f18/api_symbols.csv | 45 ++++++++++++++++++- targets/f7/api_symbols.csv | 2 +- 8 files changed, 72 insertions(+), 29 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index b4037245d..7dd401ba6 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -95,13 +95,13 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { if(strlen(app.name)) furi_string_cat_printf(parsed_data, "Name: %s\n", app.name); - if(app.issue_month) + if(app.effective_month) furi_string_cat_printf( parsed_data, - "Issue: %02X.%02X.20%02X\n", - app.issue_day, - app.issue_month, - app.issue_year); + "Effective: %02X.%02X.20%02X\n", + app.effective_day, + app.effective_month, + app.effective_year); if(app.exp_month) furi_string_cat_printf( diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index b3ab39d8a..95a153012 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -103,9 +103,9 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { if(!flipper_format_read_hex(ff, "Expiration month", &app->exp_month, 1)) break; if(!flipper_format_read_hex(ff, "Expiration day", &app->exp_day, 1)) break; - if(!flipper_format_read_hex(ff, "Issue year", &app->issue_year, 1)) break; - if(!flipper_format_read_hex(ff, "Issue month", &app->issue_month, 1)) break; - if(!flipper_format_read_hex(ff, "Issue day", &app->issue_day, 1)) break; + if(!flipper_format_read_hex(ff, "Effective year", &app->effective_year, 1)) break; + 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_try_counter; if(!flipper_format_read_uint32(ff, "PIN counter", &pin_try_counter, 1)) break; @@ -153,9 +153,11 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) { if(!flipper_format_write_hex(ff, "Expiration month", (uint8_t*)&app.exp_month, 1)) break; if(!flipper_format_write_hex(ff, "Expiration day", (uint8_t*)&app.exp_day, 1)) break; - if(!flipper_format_write_hex(ff, "Issue year", (uint8_t*)&app.issue_year, 1)) break; - if(!flipper_format_write_hex(ff, "Issue month", (uint8_t*)&app.issue_month, 1)) break; - if(!flipper_format_write_hex(ff, "Issue day", (uint8_t*)&app.issue_day, 1)) break; + if(!flipper_format_write_hex(ff, "Effective year", (uint8_t*)&app.effective_year, 1)) + break; + if(!flipper_format_write_hex(ff, "Effective month", (uint8_t*)&app.effective_month, 1)) + break; + if(!flipper_format_write_hex(ff, "Effective day", (uint8_t*)&app.effective_day, 1)) break; if(!flipper_format_write_uint32(ff, "PIN counter", (uint32_t*)&app.pin_try_counter, 1)) break; diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index a1a95f48e..a46622751 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -15,8 +15,8 @@ extern "C" { #define EMV_TAG_PDOL 0x9F38 #define EMV_TAG_APPL_PAYMENT_SYS 0x50 #define EMV_TAG_APPL_NAME 0x9F12 -#define EMV_TAG_APPL_ISSUE 0x5F25 -#define EMV_TAG_PIN_TRY_COUNTER 0x9F17 +#define EMV_TAG_APPL_EFFECTIVE 0x5F25 +#define EMV_TAG_PIN_ATTEMPTS_COUNTER 0x9F17 #define EMV_TAG_LOG_ENTRY 0x9F4D #define EMV_TAG_LOG_FMT 0x9F4F @@ -85,9 +85,9 @@ typedef struct { uint8_t exp_day; uint8_t exp_month; uint8_t exp_year; - uint8_t issue_day; - uint8_t issue_month; - uint8_t issue_year; + uint8_t effective_day; + uint8_t effective_month; + uint8_t effective_year; uint16_t country_code; uint16_t currency_code; uint8_t pin_try_counter; diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 6ca21df1c..07428744f 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_try_counter(instance); + emv_poller_get_pin_attempts_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 64bd0be9d..c24704cb5 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_try_counter(EmvPoller* instance); +EmvError emv_poller_get_pin_attempts_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 9ccf28a02..16b32f225 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -128,10 +128,10 @@ static bool success = true; FURI_LOG_T(TAG, "found EMV_TAG_APPL_NAME %x: %s", tag, app->name); break; - case EMV_TAG_APPL_ISSUE: - app->issue_year = buff[i]; - app->issue_month = buff[i + 1]; - app->issue_day = buff[i + 2]; + case EMV_TAG_APPL_EFFECTIVE: + app->effective_year = buff[i]; + app->effective_month = buff[i + 1]; + app->effective_day = buff[i + 2]; success = true; FURI_LOG_T(TAG, "found EMV_TAG_APPL_ISSUE %x:", tag); break; @@ -262,10 +262,10 @@ static bool memcpy(&app->trans[app->active_tr].time, &buff[i], tlen); success = true; break; - case EMV_TAG_PIN_TRY_COUNTER: + case EMV_TAG_PIN_ATTEMPTS_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); + FURI_LOG_T(TAG, "found EMV_TAG_PIN_ATTEMPTS_COUNTER %x: %d", tag, app->pin_try_counter); break; } return success; @@ -683,8 +683,8 @@ static EmvError emv_poller_req_get_data(EmvPoller* instance, uint16_t tag) { 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_pin_attempts_counter(EmvPoller* instance) { + return emv_poller_req_get_data(instance, EMV_TAG_PIN_ATTEMPTS_COUNTER); } EmvError emv_poller_get_last_online_atc(EmvPoller* instance) { diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 1971f5c41..5c1c3bbab 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,54.1,, +Version,v,54.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -582,11 +582,20 @@ Function,+,ble_glue_start,_Bool, Function,+,ble_glue_thread_stop,void, Function,+,ble_glue_wait_for_c2_start,_Bool,int32_t Function,-,bsearch,void*,"const void*, const void*, size_t, size_t, __compar_fn_t" +Function,?,bt_disable_peer_key_update,void,Bt* Function,+,bt_disconnect,void,Bt* +Function,?,bt_enable_peer_key_update,void,Bt* Function,+,bt_forget_bonded_devices,void,Bt* +Function,?,bt_get_profile_adv_name,const char*,Bt* +Function,?,bt_get_profile_mac_address,const uint8_t*,Bt* +Function,?,bt_get_profile_pairing_method,GapPairing,Bt* Function,+,bt_keys_storage_set_default_path,void,Bt* Function,+,bt_keys_storage_set_storage_path,void,"Bt*, const char*" +Function,?,bt_remote_rssi,_Bool,"Bt*, uint8_t*" Function,+,bt_set_profile,_Bool,"Bt*, BtProfile" +Function,?,bt_set_profile_adv_name,void,"Bt*, const char*, ..." +Function,?,bt_set_profile_mac_address,void,"Bt*, const uint8_t[6]" +Function,?,bt_set_profile_pairing_method,void,"Bt*, GapPairing" Function,+,bt_set_status_changed_callback,void,"Bt*, BtStatusChangedCallback, void*" Function,+,buffered_file_stream_alloc,Stream*,Storage* Function,+,buffered_file_stream_close,_Bool,Stream* @@ -608,6 +617,7 @@ Function,+,button_panel_free,void,ButtonPanel* Function,+,button_panel_get_view,View*,ButtonPanel* Function,+,button_panel_reserve,void,"ButtonPanel*, size_t, size_t" Function,+,button_panel_reset,void,ButtonPanel* +Function,?,button_panel_reset_selection,void,ButtonPanel* Function,+,byte_input_alloc,ByteInput*, Function,+,byte_input_free,void,ByteInput* Function,+,byte_input_get_view,View*,ByteInput* @@ -618,6 +628,7 @@ Function,+,calloc,void*,"size_t, size_t" Function,+,canvas_clear,void,Canvas* Function,+,canvas_commit,void,Canvas* Function,+,canvas_current_font_height,uint8_t,const Canvas* +Function,?,canvas_current_font_width,uint8_t,const Canvas* Function,+,canvas_draw_bitmap,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, const uint8_t*" Function,+,canvas_draw_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,canvas_draw_circle,void,"Canvas*, uint8_t, uint8_t, uint8_t" @@ -627,6 +638,7 @@ Function,+,canvas_draw_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,canvas_draw_glyph,void,"Canvas*, uint8_t, uint8_t, uint16_t" Function,+,canvas_draw_icon,void,"Canvas*, uint8_t, uint8_t, const Icon*" Function,+,canvas_draw_icon_animation,void,"Canvas*, uint8_t, uint8_t, IconAnimation*" +Function,?,canvas_draw_icon_bitmap,void,"Canvas*, uint8_t, uint8_t, int16_t, int16_t, const Icon*" Function,+,canvas_draw_icon_ex,void,"Canvas*, uint8_t, uint8_t, const Icon*, IconRotation" Function,+,canvas_draw_line,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" Function,+,canvas_draw_rbox,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t" @@ -764,6 +776,7 @@ Function,+,elements_multiline_text_framed,void,"Canvas*, uint8_t, uint8_t, const Function,+,elements_progress_bar,void,"Canvas*, uint8_t, uint8_t, uint8_t, float" Function,+,elements_progress_bar_with_text,void,"Canvas*, uint8_t, uint8_t, uint8_t, float, const char*" Function,+,elements_scrollable_text_line,void,"Canvas*, uint8_t, uint8_t, uint8_t, FuriString*, size_t, _Bool" +Function,?,elements_scrollable_text_line_str,void,"Canvas*, uint8_t, uint8_t, uint8_t, const char*, size_t, _Bool, _Bool" Function,+,elements_scrollbar,void,"Canvas*, uint16_t, uint16_t" Function,+,elements_scrollbar_pos,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint16_t, uint16_t" Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t" @@ -987,16 +1000,24 @@ Function,+,furi_event_flag_wait,uint32_t,"FuriEventFlag*, uint32_t, uint32_t, ui Function,+,furi_get_tick,uint32_t, Function,+,furi_hal_bt_change_app,_Bool,"FuriHalBtProfile, GapEventCallback, void*" Function,+,furi_hal_bt_clear_white_list,_Bool, +Function,?,furi_hal_bt_custom_adv_set,_Bool,"const uint8_t*, size_t" +Function,?,furi_hal_bt_custom_adv_start,_Bool,"uint16_t, uint16_t, uint8_t, const uint8_t[( 6 )], uint8_t" +Function,?,furi_hal_bt_custom_adv_stop,_Bool, Function,+,furi_hal_bt_dump_state,void,FuriString* Function,+,furi_hal_bt_ensure_c2_mode,_Bool,BleGlueC2Mode +Function,?,furi_hal_bt_get_conn_rssi,uint32_t,uint8_t* Function,-,furi_hal_bt_get_hardfault_info,const FuriHalBtHardfaultInfo*, Function,+,furi_hal_bt_get_key_storage_buff,void,"uint8_t**, uint16_t*" +Function,?,furi_hal_bt_get_profile_adv_name,const char*,FuriHalBtProfile +Function,?,furi_hal_bt_get_profile_mac_addr,const uint8_t*,FuriHalBtProfile +Function,?,furi_hal_bt_get_profile_pairing_method,GapPairing,FuriHalBtProfile Function,+,furi_hal_bt_get_radio_stack,FuriHalBtStack, Function,+,furi_hal_bt_get_rssi,float, Function,+,furi_hal_bt_get_transmitted_packets,uint32_t, Function,+,furi_hal_bt_hid_consumer_key_press,_Bool,uint16_t Function,+,furi_hal_bt_hid_consumer_key_release,_Bool,uint16_t Function,+,furi_hal_bt_hid_consumer_key_release_all,_Bool, +Function,?,furi_hal_bt_hid_get_led_state,uint8_t, Function,+,furi_hal_bt_hid_kb_press,_Bool,uint16_t Function,+,furi_hal_bt_hid_kb_release,_Bool,uint16_t Function,+,furi_hal_bt_hid_kb_release_all,_Bool, @@ -1011,11 +1032,13 @@ Function,-,furi_hal_bt_init,void, Function,+,furi_hal_bt_is_active,_Bool, Function,+,furi_hal_bt_is_alive,_Bool, Function,+,furi_hal_bt_is_ble_gatt_gap_supported,_Bool, +Function,?,furi_hal_bt_is_connected,_Bool, Function,+,furi_hal_bt_is_testing_supported,_Bool, Function,+,furi_hal_bt_lock_core2,void, Function,+,furi_hal_bt_nvm_sram_sem_acquire,void, Function,+,furi_hal_bt_nvm_sram_sem_release,void, Function,+,furi_hal_bt_reinit,void, +Function,?,furi_hal_bt_reverse_mac_addr,void,uint8_t[( 6 )] Function,+,furi_hal_bt_serial_notify_buffer_is_empty,void, Function,+,furi_hal_bt_serial_set_event_callback,void,"uint16_t, FuriHalBtSerialCallback, void*" Function,+,furi_hal_bt_serial_set_rpc_status,void,FuriHalBtSerialRpcStatus @@ -1023,6 +1046,9 @@ Function,+,furi_hal_bt_serial_start,void, Function,+,furi_hal_bt_serial_stop,void, Function,+,furi_hal_bt_serial_tx,_Bool,"uint8_t*, uint16_t" Function,+,furi_hal_bt_set_key_storage_change_callback,void,"BleGlueKeyStorageChangedCallback, void*" +Function,?,furi_hal_bt_set_profile_adv_name,void,"FuriHalBtProfile, const char[( ( 1 + 8 + ( 8 + 1 ) ) + 1 )]" +Function,?,furi_hal_bt_set_profile_mac_addr,void,"FuriHalBtProfile, const uint8_t[( 6 )]" +Function,?,furi_hal_bt_set_profile_pairing_method,void,"FuriHalBtProfile, GapPairing" Function,+,furi_hal_bt_start_advertising,void, Function,+,furi_hal_bt_start_app,_Bool,"FuriHalBtProfile, GapEventCallback, void*" Function,+,furi_hal_bt_start_packet_rx,void,"uint8_t, uint8_t" @@ -1217,7 +1243,6 @@ Function,+,furi_hal_random_init,void, Function,+,furi_hal_region_get,const FuriHalRegion*, Function,+,furi_hal_region_get_band,const FuriHalRegionBand*,uint32_t Function,+,furi_hal_region_get_name,const char*, -Function,-,furi_hal_region_init,void, Function,+,furi_hal_region_is_frequency_allowed,_Bool,uint32_t Function,+,furi_hal_region_is_provisioned,_Bool, Function,+,furi_hal_region_set,void,FuriHalRegion* @@ -1344,6 +1369,8 @@ Function,+,furi_hal_version_get_hw_connect,uint8_t, Function,+,furi_hal_version_get_hw_display,FuriHalVersionDisplay, Function,+,furi_hal_version_get_hw_region,FuriHalVersionRegion, Function,+,furi_hal_version_get_hw_region_name,const char*, +Function,?,furi_hal_version_get_hw_region_name_otp,const char*, +Function,?,furi_hal_version_get_hw_region_otp,FuriHalVersionRegion, Function,+,furi_hal_version_get_hw_target,uint8_t, Function,+,furi_hal_version_get_hw_timestamp,uint32_t, Function,+,furi_hal_version_get_hw_version,uint8_t, @@ -1356,7 +1383,9 @@ Function,+,furi_hal_version_get_ncc_id,const char*, Function,+,furi_hal_version_get_otp_version,FuriHalVersionOtpVersion, Function,+,furi_hal_version_get_srrc_id,const char*, Function,-,furi_hal_version_init,void, +Function,?,furi_hal_version_set_name,void,const char* Function,+,furi_hal_version_uid,const uint8_t*, +Function,?,furi_hal_version_uid_default,const uint8_t*, Function,+,furi_hal_version_uid_size,size_t, Function,-,furi_hal_vibro_init,void, Function,+,furi_hal_vibro_on,void,_Bool @@ -1529,6 +1558,7 @@ Function,-,gamma,double,double Function,-,gamma_r,double,"double, int*" Function,-,gammaf,float,float Function,-,gammaf_r,float,"float, int*" +Function,?,gap_get_remote_conn_rssi,uint32_t,int8_t* Function,-,gap_get_state,GapState, Function,-,gap_init,_Bool,"GapConfig*, GapEventCallback, void*" Function,-,gap_start_advertising,void, @@ -1921,8 +1951,11 @@ Function,-,music_worker_set_volume,void,"MusicWorker*, float" Function,-,music_worker_start,void,MusicWorker* Function,-,music_worker_stop,void,MusicWorker* Function,+,name_generator_make_auto,void,"char*, size_t, const char*" +Function,?,name_generator_make_auto_datetime,void,"char*, size_t, const char*, FuriHalRtcDateTime*" Function,+,name_generator_make_detailed,void,"char*, size_t, const char*" +Function,?,name_generator_make_detailed_datetime,void,"char*, size_t, const char*, FuriHalRtcDateTime*" Function,+,name_generator_make_random,void,"char*, size_t" +Function,?,name_generator_make_random_prefixed,void,"char*, size_t, const char*" Function,-,nan,double,const char* Function,-,nanf,float,const char* Function,-,nanl,long double,const char* @@ -2038,6 +2071,7 @@ Function,+,power_get_pubsub,FuriPubSub*,Power* Function,+,power_is_battery_healthy,_Bool,Power* Function,+,power_off,void,Power* Function,+,power_reboot,void,PowerBootMode +Function,?,power_trigger_ui_update,void,Power* Function,+,powf,float,"float, float" Function,-,powl,long double,"long double, long double" Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t" @@ -2372,11 +2406,13 @@ Function,-,strverscmp,int,"const char*, const char*" Function,-,strxfrm,size_t,"char*, const char*, size_t" Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t" Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*" +Function,?,submenu_add_lockable_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*, _Bool, const char*" Function,+,submenu_alloc,Submenu*, Function,+,submenu_free,void,Submenu* Function,+,submenu_get_view,View*,Submenu* Function,+,submenu_reset,void,Submenu* Function,+,submenu_set_header,void,"Submenu*, const char*" +Function,?,submenu_set_orientation,void,"Submenu*, ViewOrientation" Function,+,submenu_set_selected_item,void,"Submenu*, uint32_t" Function,-,system,int,const char* Function,-,tan,double,double @@ -2415,6 +2451,7 @@ Function,+,text_input_get_validator_callback_context,void*,TextInput* Function,+,text_input_get_view,View*,TextInput* Function,+,text_input_reset,void,TextInput* Function,+,text_input_set_header_text,void,"TextInput*, const char*" +Function,?,text_input_set_minimum_length,void,"TextInput*, size_t" Function,+,text_input_set_result_callback,void,"TextInput*, TextInputCallback, void*, char*, size_t, _Bool" Function,+,text_input_set_validator,void,"TextInput*, TextInputValidatorCallback, void*" Function,-,tgamma,double,double @@ -2450,6 +2487,7 @@ Function,+,variable_item_get_current_value_index,uint8_t,VariableItem* Function,+,variable_item_list_add,VariableItem*,"VariableItemList*, const char*, uint8_t, VariableItemChangeCallback, void*" Function,+,variable_item_list_alloc,VariableItemList*, Function,+,variable_item_list_free,void,VariableItemList* +Function,?,variable_item_list_get,VariableItem*,"VariableItemList*, uint8_t" Function,+,variable_item_list_get_selected_item_index,uint8_t,VariableItemList* Function,+,variable_item_list_get_view,View*,VariableItemList* Function,+,variable_item_list_reset,void,VariableItemList* @@ -2457,6 +2495,7 @@ Function,+,variable_item_list_set_enter_callback,void,"VariableItemList*, Variab Function,+,variable_item_list_set_selected_item,void,"VariableItemList*, uint8_t" Function,+,variable_item_set_current_value_index,void,"VariableItem*, uint8_t" Function,+,variable_item_set_current_value_text,void,"VariableItem*, const char*" +Function,?,variable_item_set_locked,void,"VariableItem*, _Bool, const char*" Function,+,variable_item_set_values_count,void,"VariableItem*, uint8_t" Function,-,vasiprintf,int,"char**, const char*, __gnuc_va_list" Function,-,vasniprintf,char*,"char*, size_t*, const char*, __gnuc_va_list" @@ -2466,6 +2505,7 @@ Function,-,vdiprintf,int,"int, const char*, __gnuc_va_list" Function,-,vdprintf,int,"int, const char*, __gnuc_va_list" Function,+,version_get,const Version*, Function,+,version_get_builddate,const char*,const Version* +Function,?,version_get_custom_name,const char*,const Version* Function,+,version_get_dirty_flag,_Bool,const Version* Function,+,version_get_firmware_origin,const char*,const Version* Function,+,version_get_git_origin,const char*,const Version* @@ -2474,6 +2514,7 @@ Function,+,version_get_gitbranchnum,const char*,const Version* Function,+,version_get_githash,const char*,const Version* Function,+,version_get_target,uint8_t,const Version* Function,+,version_get_version,const char*,const Version* +Function,?,version_set_custom_name,void,"Version*, const char*" Function,-,vfiprintf,int,"FILE*, const char*, __gnuc_va_list" Function,-,vfiscanf,int,"FILE*, const char*, __gnuc_va_list" Function,-,vfprintf,int,"FILE*, const char*, __gnuc_va_list" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index cb2c9cce8..d0a09d835 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_try_counter,EmvError,EmvPoller* +Function,+,emv_poller_get_pin_attempts_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* From c35f258ab8390d1a50a56e5aac12e31aee780860 Mon Sep 17 00:00:00 2001 From: Methodius Date: Sun, 11 Feb 2024 01:47:33 +0900 Subject: [PATCH 09/20] parser 0day fix --- .../main/nfc/plugins/supported_cards/emv.c | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index 7dd401ba6..dd97cb3cf 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -95,21 +95,33 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { if(strlen(app.name)) furi_string_cat_printf(parsed_data, "Name: %s\n", app.name); - if(app.effective_month) + if(app.effective_month) { + char day[] = "??"; + if(app.effective_day) itoa(app.effective_day, day, 16); + if(day[1] == '\0') { + day[1] = day[0]; + day[0] = '0'; + } + furi_string_cat_printf( parsed_data, - "Effective: %02X.%02X.20%02X\n", - app.effective_day, + "Effective: %s.%02X.20%02X\n", + day, app.effective_month, app.effective_year); + } + + if(app.exp_month) { + char day[] = "??"; + if(app.exp_day) itoa(app.exp_day, day, 16); + if(day[1] == '\0') { + day[1] = day[0]; + day[0] = '0'; + } - if(app.exp_month) furi_string_cat_printf( - parsed_data, - "Expires: %02X.%02X.20%02X\n", - app.exp_day, - app.exp_month, - app.exp_year); + parsed_data, "Expires: %s.%02X.20%02X\n", day, app.exp_month, app.exp_year); + } FuriString* str = furi_string_alloc(); bool storage_readed = emv_get_country_name(app.country_code, str); From c24625fae835cced6eeb40b39c88bf2bb4b3b6bb Mon Sep 17 00:00:00 2001 From: Methodius Date: Sun, 11 Feb 2024 04:45:07 +0900 Subject: [PATCH 10/20] 14_4a poller: send block max attempts increased --- lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c index 2065b81a2..45f427dc6 100644 --- a/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c +++ b/lib/nfc/protocols/iso14443_4a/iso14443_4a_poller_i.c @@ -7,6 +7,7 @@ #define TAG "Iso14443_4aPoller" #define ISO14443_4A_FSDI_256 (0x8U) +#define ISO14443_4A_SEND_BLOCK_MAX_ATTEMPTS (20) Iso14443_4aError iso14443_4a_poller_halt(Iso14443_4aPoller* instance) { furi_assert(instance); @@ -88,7 +89,7 @@ Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext( BitBuffer* rx_buffer) { furi_assert(instance); - uint8_t retry = 5; + uint8_t attempts_left = ISO14443_4A_SEND_BLOCK_MAX_ATTEMPTS; bit_buffer_reset(instance->tx_buffer); iso14443_4_layer_encode_block(instance->iso14443_4_layer, tx_buffer, instance->tx_buffer); @@ -103,6 +104,8 @@ Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext( iso14443_4a_get_fwt_fc_max(instance->data)); if(iso14443_3a_error != Iso14443_3aErrorNone) { + FURI_LOG_T( + TAG, "Attempt: %u", ISO14443_4A_SEND_BLOCK_MAX_ATTEMPTS + 1 - attempts_left); FURI_LOG_RAW_T("RAW RX(%d):", bit_buffer_get_size_bytes(instance->rx_buffer)); for(size_t x = 0; x < bit_buffer_get_size_bytes(instance->rx_buffer); x++) { FURI_LOG_RAW_T("%02X ", bit_buffer_get_byte(instance->rx_buffer, x)); @@ -116,7 +119,7 @@ Iso14443_4aError iso14443_4a_poller_send_block_pwt_ext( error = iso14443_4_layer_decode_block_pwt_ext( instance->iso14443_4_layer, rx_buffer, instance->rx_buffer); if(error == Iso14443_4aErrorSendExtra) { - if(--retry == 0) break; + if(--attempts_left == 0) break; // Send response for Control message if(bit_buffer_get_size_bytes(rx_buffer)) bit_buffer_copy(instance->tx_buffer, rx_buffer); From 4a382bc1de3db585517d9f0ae8c03f5e0079f6b5 Mon Sep 17 00:00:00 2001 From: Methodius Date: Sun, 11 Feb 2024 04:54:04 +0900 Subject: [PATCH 11/20] typos fixed --- applications/main/nfc/plugins/supported_cards/emv.c | 5 +++-- lib/nfc/protocols/emv/emv.c | 11 ++++++----- lib/nfc/protocols/emv/emv.h | 2 +- lib/nfc/protocols/emv/emv_poller_i.c | 5 +++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index dd97cb3cf..30296e098 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -133,8 +133,9 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { if(storage_readed) furi_string_cat_printf(parsed_data, "Currency: %s\n", furi_string_get_cstr(str)); - if(app.pin_try_counter != 0xFF) - furi_string_cat_printf(parsed_data, "PIN attempts left: %d\n", app.pin_try_counter); + if(app.pin_attempts_counter != 0xFF) + furi_string_cat_printf( + parsed_data, "PIN attempts left: %d\n", app.pin_attempts_counter); parsed = true; } while(false); diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index 95a153012..0dabd3690 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_try_counter = 0xff; + data->emv_application.pin_attempts_counter = 0xff; return data; } @@ -107,9 +107,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_try_counter; - if(!flipper_format_read_uint32(ff, "PIN counter", &pin_try_counter, 1)) break; - app->pin_try_counter = pin_try_counter; + 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; parsed = true; } while(false); @@ -159,7 +159,8 @@ 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 counter", (uint32_t*)&app.pin_try_counter, 1)) + if(!flipper_format_write_uint32( + ff, "PIN attempts left", (uint32_t*)&app.pin_attempts_counter, 1)) break; saved = true; diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index a46622751..88ea4a9d8 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -90,7 +90,7 @@ typedef struct { uint8_t effective_year; uint16_t country_code; uint16_t currency_code; - uint8_t pin_try_counter; + uint8_t pin_attempts_counter; uint16_t transaction_counter; uint16_t last_online_atc; APDU pdol; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 16b32f225..81b91c553 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -263,9 +263,10 @@ static bool success = true; break; case EMV_TAG_PIN_ATTEMPTS_COUNTER: - app->pin_try_counter = buff[i]; + app->pin_attempts_counter = buff[i]; success = true; - FURI_LOG_T(TAG, "found EMV_TAG_PIN_ATTEMPTS_COUNTER %x: %d", tag, app->pin_try_counter); + FURI_LOG_T( + TAG, "found EMV_TAG_PIN_ATTEMPTS_COUNTER %x: %d", tag, app->pin_attempts_counter); break; } return success; From 08f096df24b65a374b5f444662c369f65af1ea49 Mon Sep 17 00:00:00 2001 From: Methodius Date: Mon, 12 Feb 2024 00:28:01 +0900 Subject: [PATCH 12/20] EMV dump save/load fix --- applications/main/nfc/plugins/supported_cards/emv.c | 8 ++++---- lib/nfc/protocols/emv/emv.c | 10 +++++----- lib/nfc/protocols/emv/emv.h | 4 ++-- lib/nfc/protocols/emv/emv_poller_i.c | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index 30296e098..63bc534c9 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -73,8 +73,10 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { const EmvApplication app = data->emv_application; do { - if(strlen(app.payment_sys)) - furi_string_cat_printf(parsed_data, "\e#%s\n", app.payment_sys); + if(strlen(app.label)) + furi_string_cat_printf(parsed_data, "\e#%s\n", app.label); + else if(strlen(app.name)) + furi_string_cat_printf(parsed_data, "\e#%s\n", app.name); else furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); @@ -93,8 +95,6 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_free(pan); } - if(strlen(app.name)) furi_string_cat_printf(parsed_data, "Name: %s\n", app.name); - if(app.effective_month) { char day[] = "??"; if(app.effective_day) itoa(app.effective_day, day, 16); diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index 0dabd3690..89d490c90 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -76,12 +76,12 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { EmvApplication* app = &data->emv_application; - if(!flipper_format_read_string(ff, "Name", temp_str)) break; + flipper_format_read_string(ff, "Application name", temp_str); strcpy(app->name, furi_string_get_cstr(temp_str)); //Read label - if(!flipper_format_read_string(ff, "Payment system", temp_str)) break; - strcpy(app->payment_sys, furi_string_get_cstr(temp_str)); + flipper_format_read_string(ff, "Application label", temp_str); + strcpy(app->label, furi_string_get_cstr(temp_str)); uint32_t pan_len; if(!flipper_format_read_uint32(ff, "PAN length", &pan_len, 1)) break; @@ -131,9 +131,9 @@ 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, "Name", app.name)) break; + if(!flipper_format_write_string_cstr(ff, "Application name", app.name)) break; - if(!flipper_format_write_string_cstr(ff, "Payment system", app.payment_sys)) break; + if(!flipper_format_write_string_cstr(ff, "Application label", app.label)) break; uint32_t pan_len = app.pan_len; if(!flipper_format_write_uint32(ff, "PAN length", &pan_len, 1)) break; diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index 88ea4a9d8..f61fe1610 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -13,7 +13,7 @@ extern "C" { #define EMV_TAG_AID 0x4F #define EMV_TAG_PRIORITY 0x87 #define EMV_TAG_PDOL 0x9F38 -#define EMV_TAG_APPL_PAYMENT_SYS 0x50 +#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 @@ -79,7 +79,7 @@ typedef struct { uint8_t aid[16]; uint8_t aid_len; char name[16 + 1]; - char payment_sys[16 + 1]; + char label[16 + 1]; uint8_t pan[10]; // card_number uint8_t pan_len; uint8_t exp_day; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 81b91c553..a03681a7c 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -115,11 +115,11 @@ static bool success = true; FURI_LOG_T(TAG, "found EMV_TAG_APP_PRIORITY %X: %d", tag, app->priority); break; - case EMV_TAG_APPL_PAYMENT_SYS: - memcpy(app->payment_sys, &buff[i], tlen); - app->payment_sys[tlen] = '\0'; + case EMV_TAG_APPL_LABEL: + memcpy(app->label, &buff[i], tlen); + app->label[tlen] = '\0'; success = true; - FURI_LOG_T(TAG, "found EMV_TAG_APPL_PAYMENT_SYS %x: %s", tag, app->payment_sys); + FURI_LOG_T(TAG, "found EMV_TAG_APPL_LABEL %x: %s", tag, app->label); break; case EMV_TAG_APPL_NAME: furi_check(tlen < sizeof(app->name)); From a9de06d6f20cc64aaa56e14915a95d11c7dd753b Mon Sep 17 00:00:00 2001 From: Methodius Date: Mon, 12 Feb 2024 02:59:24 +0900 Subject: [PATCH 13/20] cardholder name parsing prepared --- .../helpers/protocol_support/emv/emv_render.c | 2 +- .../main/nfc/plugins/supported_cards/emv.c | 11 ++++++---- lib/nfc/protocols/emv/emv.c | 9 ++++---- lib/nfc/protocols/emv/emv.h | 5 +++-- lib/nfc/protocols/emv/emv_poller_i.c | 22 +++++++++---------- 5 files changed, 27 insertions(+), 22 deletions(-) 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 091db9ebe..71395acf5 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -31,7 +31,7 @@ void nfc_render_emv_uid(const uint8_t* uid, const uint8_t uid_len, FuriString* s void nfc_render_emv_data(const EmvData* data, FuriString* str) { nfc_render_emv_pan(data->emv_application.pan, data->emv_application.pan_len, str); - nfc_render_emv_name(data->emv_application.name, str); + nfc_render_emv_name(data->emv_application.application_name, str); } void nfc_render_emv_pan(const uint8_t* data, const uint8_t len, FuriString* str) { diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index 63bc534c9..9e961acc6 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -73,10 +73,10 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { const EmvApplication app = data->emv_application; do { - if(strlen(app.label)) - furi_string_cat_printf(parsed_data, "\e#%s\n", app.label); - else if(strlen(app.name)) - furi_string_cat_printf(parsed_data, "\e#%s\n", app.name); + if(strlen(app.application_label)) + furi_string_cat_printf(parsed_data, "\e#%s\n", app.application_label); + else if(strlen(app.application_name)) + furi_string_cat_printf(parsed_data, "\e#%s\n", app.application_name); else furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); @@ -95,6 +95,9 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_free(pan); } + if(strlen(app.cardholder_name)) + furi_string_cat_printf(parsed_data, "Cardholder name: %s\n", app.cardholder_name); + if(app.effective_month) { char day[] = "??"; if(app.effective_day) itoa(app.effective_day, day, 16); diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index 89d490c90..c05d18b50 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -77,11 +77,11 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { EmvApplication* app = &data->emv_application; flipper_format_read_string(ff, "Application name", temp_str); - strcpy(app->name, furi_string_get_cstr(temp_str)); + strcpy(app->application_name, furi_string_get_cstr(temp_str)); //Read label flipper_format_read_string(ff, "Application label", temp_str); - strcpy(app->label, furi_string_get_cstr(temp_str)); + strcpy(app->application_label, furi_string_get_cstr(temp_str)); uint32_t pan_len; if(!flipper_format_read_uint32(ff, "PAN length", &pan_len, 1)) break; @@ -131,9 +131,10 @@ 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, "Application name", app.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.label)) break; + if(!flipper_format_write_string_cstr(ff, "Application label", app.application_label)) + break; uint32_t pan_len = app.pan_len; if(!flipper_format_write_uint32(ff, "PAN length", &pan_len, 1)) break; diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index f61fe1610..2e786347c 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -78,8 +78,9 @@ typedef struct { uint8_t priority; uint8_t aid[16]; uint8_t aid_len; - char name[16 + 1]; - char label[16 + 1]; + char application_name[16 + 1]; + char application_label[16 + 1]; + char cardholder_name[24 + 1]; uint8_t pan[10]; // card_number uint8_t pan_len; uint8_t exp_day; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index a03681a7c..8731691d9 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -116,17 +116,17 @@ static bool FURI_LOG_T(TAG, "found EMV_TAG_APP_PRIORITY %X: %d", tag, app->priority); break; case EMV_TAG_APPL_LABEL: - memcpy(app->label, &buff[i], tlen); - app->label[tlen] = '\0'; + memcpy(app->application_label, &buff[i], tlen); + app->application_label[tlen] = '\0'; success = true; - FURI_LOG_T(TAG, "found EMV_TAG_APPL_LABEL %x: %s", tag, app->label); + FURI_LOG_T(TAG, "found EMV_TAG_APPL_LABEL %x: %s", tag, app->application_label); break; case EMV_TAG_APPL_NAME: - furi_check(tlen < sizeof(app->name)); - memcpy(app->name, &buff[i], tlen); - app->name[tlen] = '\0'; + furi_check(tlen < sizeof(app->application_name)); + memcpy(app->application_name, &buff[i], tlen); + app->application_name[tlen] = '\0'; success = true; - FURI_LOG_T(TAG, "found EMV_TAG_APPL_NAME %x: %s", tag, app->name); + FURI_LOG_T(TAG, "found EMV_TAG_APPL_NAME %x: %s", tag, app->application_name); break; case EMV_TAG_APPL_EFFECTIVE: app->effective_year = buff[i]; @@ -190,11 +190,11 @@ static bool break; } case EMV_TAG_CARDHOLDER_NAME: { - char name[27]; - memcpy(name, &buff[i], tlen); - name[tlen] = '\0'; + if(strlen(app->cardholder_name) > tlen) break; + memcpy(app->cardholder_name, &buff[i], tlen); + app->cardholder_name[tlen] = '\0'; success = true; - FURI_LOG_T(TAG, "found EMV_TAG_CARDHOLDER_NAME %x: %s", tag, name); + FURI_LOG_T(TAG, "found EMV_TAG_CARDHOLDER_NAME %x: %s", tag, app->cardholder_name); break; } case EMV_TAG_PAN: From 809e1b3aff115de00f7906a588e8544cc341288c Mon Sep 17 00:00:00 2001 From: Methodius Date: Mon, 12 Feb 2024 03:18:36 +0900 Subject: [PATCH 14/20] explicit nodata message when no data parsed from card --- .../main/nfc/plugins/supported_cards/emv.c | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index 9e961acc6..8e3c5635b 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -73,11 +73,11 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { const EmvApplication app = data->emv_application; do { - if(strlen(app.application_label)) + if(strlen(app.application_label)) { furi_string_cat_printf(parsed_data, "\e#%s\n", app.application_label); - else if(strlen(app.application_name)) + } else if(strlen(app.application_name)) { furi_string_cat_printf(parsed_data, "\e#%s\n", app.application_name); - else + } else furi_string_cat_printf(parsed_data, "\e#%s\n", "EMV"); if(app.pan_len) { @@ -93,10 +93,13 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_cat(parsed_data, pan); furi_string_free(pan); + parsed = true; } - if(strlen(app.cardholder_name)) + if(strlen(app.cardholder_name)) { furi_string_cat_printf(parsed_data, "Cardholder name: %s\n", app.cardholder_name); + parsed = true; + } if(app.effective_month) { char day[] = "??"; @@ -112,6 +115,8 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { day, app.effective_month, app.effective_year); + + parsed = true; } if(app.exp_month) { @@ -124,21 +129,31 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { furi_string_cat_printf( parsed_data, "Expires: %s.%02X.20%02X\n", day, app.exp_month, app.exp_year); + + parsed = true; } FuriString* str = furi_string_alloc(); bool storage_readed = emv_get_country_name(app.country_code, str); - if(storage_readed) + if(storage_readed) { furi_string_cat_printf(parsed_data, "Country: %s\n", furi_string_get_cstr(str)); + parsed = true; + } storage_readed = emv_get_currency_name(app.currency_code, str); - if(storage_readed) + if(storage_readed) { furi_string_cat_printf(parsed_data, "Currency: %s\n", furi_string_get_cstr(str)); + parsed = true; + } - if(app.pin_attempts_counter != 0xFF) + if(app.pin_attempts_counter != 0xFF) { furi_string_cat_printf( parsed_data, "PIN attempts left: %d\n", app.pin_attempts_counter); + parsed = true; + } + + if(!parsed) furi_string_cat_printf(parsed_data, "No data was parsed\n"); parsed = true; } while(false); From 11cfbd1ec894c47573e02d38fa3463157a11cf29 Mon Sep 17 00:00:00 2001 From: Methodius Date: Mon, 12 Feb 2024 14:34:11 +0900 Subject: [PATCH 15/20] bruteforce sfi 2-3 records 1-5 --- .../nfc/helpers/protocol_support/emv/emv.c | 10 ---- .../main/nfc/plugins/supported_cards/emv.c | 5 +- lib/nfc/protocols/emv/emv.c | 16 +++--- lib/nfc/protocols/emv/emv.h | 5 +- lib/nfc/protocols/emv/emv_poller.c | 2 +- lib/nfc/protocols/emv/emv_poller.h | 2 +- lib/nfc/protocols/emv/emv_poller_i.c | 50 ++++++++++++++----- targets/f7/api_symbols.csv | 2 +- 8 files changed, 56 insertions(+), 36 deletions(-) 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* From 14d3510d8e56eb17b2ae2e0f8b063576f7cf7383 Mon Sep 17 00:00:00 2001 From: Methodius Date: Mon, 12 Feb 2024 14:46:31 +0900 Subject: [PATCH 16/20] little speed up --- lib/nfc/protocols/emv/emv_poller_i.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index bba0163ce..61efc6799 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -622,6 +622,9 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { FURI_LOG_D(TAG, "Search PAN in SFI"); + uint8_t sfi_2_mask = 0; + uint8_t sfi_3_mask = 0; + bool pan_fetched = (instance->data->emv_application.pan_len); // Iterate through all files @@ -631,6 +634,9 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { uint8_t record_end = afl->data[i + 2]; // Iterate through all records in file for(uint8_t record = record_start; record <= record_end; ++record) { + if((sfi == 2) && (record < 8)) FURI_BIT_SET(sfi_2_mask, record); + if((sfi == 3) && (record < 8)) FURI_BIT_SET(sfi_3_mask, record); + error = emv_poller_read_sfi_record(instance, sfi, record); if(error != EmvErrorNone) break; @@ -645,13 +651,22 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { if(instance->data->emv_application.pan_len) pan_fetched = true; // Card number fetched } } - + bool cardholder_name_fetched = strlen(instance->data->emv_application.cardholder_name); // 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; + // Skip previously readed sfi + if(sfi == 2) { + if((sfi_2_mask >> record) & (0b1)) continue; + } + if(sfi == 3) { + if((sfi_3_mask >> record) & (0b1)) continue; + } + + if(strlen(instance->data->emv_application.cardholder_name)) + cardholder_name_fetched = true; error = emv_poller_read_sfi_record(instance, sfi, record); if(error != EmvErrorNone) break; @@ -664,7 +679,7 @@ EmvError emv_poller_read_afl(EmvPoller* instance) { } } } - if(pan_fetched) + if(pan_fetched || cardholder_name_fetched) return EmvErrorNone; else return error; From b904555ebf4e0e258536be6af8ab267d950f24c2 Mon Sep 17 00:00:00 2001 From: Methodius Date: Mon, 12 Feb 2024 16:35:56 +0900 Subject: [PATCH 17/20] application interchange profile parse added --- .../helpers/protocol_support/emv/emv_render.c | 16 ++++++++++++++++ .../helpers/protocol_support/emv/emv_render.h | 2 ++ .../main/nfc/plugins/supported_cards/emv.c | 5 +++++ lib/nfc/protocols/emv/emv.c | 9 ++++++++- lib/nfc/protocols/emv/emv.h | 2 ++ lib/nfc/protocols/emv/emv_poller_i.c | 10 ++++++++++ 6 files changed, 43 insertions(+), 1 deletion(-) 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 71395acf5..d625ed22c 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -76,6 +76,21 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { furi_string_cat_printf(str, "\n"); } +void nfc_render_emv_application_interchange_profile(const EmvApplication* apl, FuriString* str) { + //TODO: CLEANUP AFERT BITLIB MERGE + uint16_t data = (apl->application_interchange_profile[0] << 8) | + (apl->application_interchange_profile[1]); + if(!data) { + furi_string_cat_printf(str, "No Interchange profile found\n"); + return; + } + + furi_string_cat_printf(str, "Interchange profile: "); + for(uint8_t i = 0; i < 2; i++) + furi_string_cat_printf(str, "%02X", apl->application_interchange_profile[i]); + furi_string_cat_printf(str, "\n"); +} + void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { if(apl->transaction_counter) furi_string_cat_printf(str, "Transactions count: %d\n", apl->transaction_counter); @@ -159,6 +174,7 @@ void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { void nfc_render_emv_extra(const EmvData* data, FuriString* str) { nfc_render_emv_application(&data->emv_application, str); + nfc_render_emv_application_interchange_profile(&data->emv_application, str); nfc_render_emv_currency(data->emv_application.currency_code, str); nfc_render_emv_country(data->emv_application.country_code, str); diff --git a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h index d2dabe965..4f1e9bb09 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.h +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.h @@ -15,6 +15,8 @@ void nfc_render_emv_name(const char* data, FuriString* str); void nfc_render_emv_application(const EmvApplication* data, FuriString* str); +void nfc_render_emv_application_interchange_profile(const EmvApplication* apl, FuriString* str); + void nfc_render_emv_extra(const EmvData* data, FuriString* str); void nfc_render_emv_country(uint16_t country_code, FuriString* str); diff --git a/applications/main/nfc/plugins/supported_cards/emv.c b/applications/main/nfc/plugins/supported_cards/emv.c index 8f26d8178..fd2c3fcb3 100644 --- a/applications/main/nfc/plugins/supported_cards/emv.c +++ b/applications/main/nfc/plugins/supported_cards/emv.c @@ -152,6 +152,11 @@ static bool emv_parse(const NfcDevice* device, FuriString* parsed_data) { parsed = true; } + if((app.application_interchange_profile[1] >> 6) & 0b1) { + furi_string_cat_printf(parsed_data, "Mobile: yes\n"); + parsed = true; + } + if(!parsed) furi_string_cat_printf(parsed_data, "No data was parsed\n"); parsed = true; diff --git a/lib/nfc/protocols/emv/emv.c b/lib/nfc/protocols/emv/emv.c index 278828071..af208ea10 100644 --- a/lib/nfc/protocols/emv/emv.c +++ b/lib/nfc/protocols/emv/emv.c @@ -82,7 +82,6 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { flipper_format_read_string(ff, "Application name", temp_str); strcpy(app->application_name, furi_string_get_cstr(temp_str)); - //Read label flipper_format_read_string(ff, "Application label", temp_str); strcpy(app->application_label, furi_string_get_cstr(temp_str)); @@ -98,6 +97,10 @@ bool emv_load(EmvData* data, FlipperFormat* ff, uint32_t version) { if(!flipper_format_read_hex(ff, "AID", app->aid, aid_len)) break; + if(!flipper_format_read_hex( + ff, "Application interchange profile", app->application_interchange_profile, 2)) + break; + if(!flipper_format_read_hex(ff, "Country code", (uint8_t*)&app->country_code, 2)) break; if(!flipper_format_read_hex(ff, "Currency code", (uint8_t*)&app->currency_code, 2)) break; @@ -151,6 +154,10 @@ bool emv_save(const EmvData* data, FlipperFormat* ff) { if(!flipper_format_write_hex(ff, "AID", app.aid, aid_len)) break; + if(!flipper_format_write_hex( + ff, "Application interchange profile", app.application_interchange_profile, 2)) + break; + if(!flipper_format_write_hex(ff, "Country code", (uint8_t*)&app.country_code, 2)) break; if(!flipper_format_write_hex(ff, "Currency code", (uint8_t*)&app.currency_code, 2)) break; diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index bd195dde6..d7708e049 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -12,6 +12,7 @@ extern "C" { #define EMV_TAG_AID 0x4F #define EMV_TAG_PRIORITY 0x87 +#define EMV_TAG_APPL_INTERCHANGE_PROFILE 0x82 #define EMV_TAG_PDOL 0x9F38 #define EMV_TAG_APPL_LABEL 0x50 #define EMV_TAG_APPL_NAME 0x9F12 @@ -79,6 +80,7 @@ typedef struct { uint8_t priority; uint8_t aid[16]; uint8_t aid_len; + uint8_t application_interchange_profile[2]; char application_name[16 + 1]; char application_label[16 + 1]; char cardholder_name[24 + 1]; diff --git a/lib/nfc/protocols/emv/emv_poller_i.c b/lib/nfc/protocols/emv/emv_poller_i.c index 61efc6799..e72432287 100644 --- a/lib/nfc/protocols/emv/emv_poller_i.c +++ b/lib/nfc/protocols/emv/emv_poller_i.c @@ -115,6 +115,16 @@ static bool success = true; FURI_LOG_T(TAG, "found EMV_TAG_APP_PRIORITY %X: %d", tag, app->priority); break; + case EMV_TAG_APPL_INTERCHANGE_PROFILE: + furi_check(tlen == 2); + memcpy(app->application_interchange_profile, &buff[i], tlen); + success = true; + FURI_LOG_T(TAG, "found EMV_TAG_APPL_INTERCHANGE_PROFILE %x: ", tag); + for(size_t x = 0; x < tlen; x++) { + FURI_LOG_RAW_T("%02X ", app->application_interchange_profile[x]); + } + FURI_LOG_RAW_T("\r\n"); + break; case EMV_TAG_APPL_LABEL: memcpy(app->application_label, &buff[i], tlen); app->application_label[tlen] = '\0'; From 3f292953806043166a84223e8be94d74cb350b23 Mon Sep 17 00:00:00 2001 From: Methodius Date: Wed, 14 Feb 2024 12:44:03 +0900 Subject: [PATCH 18/20] transactions render fix Co-authored-by: Nikita Vostokov <1042932+wosk@users.noreply.github.com> --- .../nfc/helpers/protocol_support/emv/emv_render.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) 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 d625ed22c..6b571e7b8 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -125,13 +125,12 @@ void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { furi_string_cat_printf(str, ".%02X", a[x]); break; } - if(a[x]) { - if(top) { - furi_string_cat_printf(str, "%X", a[x]); - top = false; - } else { - furi_string_cat_printf(str, "%02X", a[x]); - } + if(top && a[x]) { + // print without leading zeros if exist + furi_string_cat_printf(str, "%X", a[x]); + top = false; + } else { + furi_string_cat_printf(str, "%02X", a[x]); } } } From 0397dd0a40895d58bce4381f897fc926cb01c4da Mon Sep 17 00:00:00 2001 From: Methodius Date: Wed, 14 Feb 2024 17:41:45 +0900 Subject: [PATCH 19/20] fix false-positive emv protocol detect --- .../main/nfc/helpers/protocol_support/emv/emv_render.c | 5 ----- lib/nfc/protocols/emv/emv.h | 2 ++ lib/nfc/protocols/emv/emv_poller.c | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) 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 6b571e7b8..d5c1e5105 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -66,11 +66,6 @@ void nfc_render_emv_country(uint16_t country_code, FuriString* str) { void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { const uint8_t len = apl->aid_len; - if(!len) { - furi_string_cat_printf(str, "No Pay Application found\n"); - return; - } - furi_string_cat_printf(str, "AID: "); for(uint8_t i = 0; i < len; i++) furi_string_cat_printf(str, "%02X", apl->aid[i]); furi_string_cat_printf(str, "\n"); diff --git a/lib/nfc/protocols/emv/emv.h b/lib/nfc/protocols/emv/emv.h index d7708e049..e09eacaa4 100644 --- a/lib/nfc/protocols/emv/emv.h +++ b/lib/nfc/protocols/emv/emv.h @@ -10,6 +10,8 @@ extern "C" { #define EMV_REQ_GET_DATA 0x80CA +#define UNKNOWN_TAG 0x0B + #define EMV_TAG_AID 0x4F #define EMV_TAG_PRIORITY 0x87 #define EMV_TAG_APPL_INTERCHANGE_PROFILE 0x82 diff --git a/lib/nfc/protocols/emv/emv_poller.c b/lib/nfc/protocols/emv/emv_poller.c index 6ca21df1c..9acb854d6 100644 --- a/lib/nfc/protocols/emv/emv_poller.c +++ b/lib/nfc/protocols/emv/emv_poller.c @@ -186,7 +186,7 @@ static bool emv_poller_detect(NfcGenericEvent event, void* context) { if(iso14443_4a_event->type == Iso14443_4aPollerEventTypeReady) { const EmvError error = emv_poller_select_ppse(instance); - protocol_detected = (error == EmvErrorNone); + protocol_detected = (error == EmvErrorNone) && (instance->data->emv_application.aid_len); } return protocol_detected; From c061fb1681e77d95d505c363bba1c3b90fc7b8f5 Mon Sep 17 00:00:00 2001 From: Methodius Date: Thu, 15 Feb 2024 01:45:48 +0900 Subject: [PATCH 20/20] transactions render fix part 2 --- .../helpers/protocol_support/emv/emv_render.c | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) 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 d5c1e5105..9e315ff47 100644 --- a/applications/main/nfc/helpers/protocol_support/emv/emv_render.c +++ b/applications/main/nfc/helpers/protocol_support/emv/emv_render.c @@ -1,6 +1,7 @@ #include "emv_render.h" #include "../iso14443_4a/iso14443_4a_render.h" +#include #include "nfc/nfc_app_i.h" void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) { @@ -72,9 +73,8 @@ void nfc_render_emv_application(const EmvApplication* apl, FuriString* str) { } void nfc_render_emv_application_interchange_profile(const EmvApplication* apl, FuriString* str) { - //TODO: CLEANUP AFERT BITLIB MERGE - uint16_t data = (apl->application_interchange_profile[0] << 8) | - (apl->application_interchange_profile[1]); + uint16_t data = bit_lib_bytes_to_num_be(apl->application_interchange_profile, 2); + if(!data) { furi_string_cat_printf(str, "No Interchange profile found\n"); return; @@ -112,22 +112,14 @@ void nfc_render_emv_transactions(const EmvApplication* apl, FuriString* str) { if(!apl->trans[i].amount) { furi_string_cat_printf(str, "???"); } else { - uint8_t* a = (uint8_t*)&apl->trans[i].amount; - bool top = true; - for(int x = 0; x < 6; x++) { - // cents - if(x == 5) { - furi_string_cat_printf(str, ".%02X", a[x]); - break; - } - if(top && a[x]) { - // print without leading zeros if exist - furi_string_cat_printf(str, "%X", a[x]); - top = false; - } else { - furi_string_cat_printf(str, "%02X", a[x]); - } - } + uint8_t amount_bytes[6]; + bit_lib_num_to_bytes_le(apl->trans[i].amount, 6, amount_bytes); + + bool junk = false; + uint64_t amount = bit_lib_bytes_to_num_bcd(amount_bytes, 6, &junk); + uint8_t amount_cents = amount % 100; + + furi_string_cat_printf(str, "%llu.%02u", amount / 100, amount_cents); } if(apl->trans[i].currency) {