Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emv fixes #702

Merged
merged 29 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9ceae3a
[EMV] Fix crash while PDOL parsing
wosk Feb 2, 2024
b167471
[EMV] Add Effective date and Preferred Name
wosk Feb 2, 2024
ec35662
code cleanup, gui fixes
Leptopt1los Feb 2, 2024
d195de5
Fix PDOL parsing
wosk Feb 8, 2024
e6935f2
Reset transactions widget before enter again
wosk Feb 10, 2024
ab609bc
WIP: Test for some visa cards
wosk Feb 10, 2024
1e09034
Merge remote-tracking branch 'upstream/dev' into emv-fixes
Leptopt1los Feb 10, 2024
56875ed
Revert "WIP: Test for some visa cards"
Leptopt1los Feb 10, 2024
702e4f3
0x5F25 tag renamed (issue date->effective date)
Leptopt1los Feb 10, 2024
c35f258
parser 0day fix
Leptopt1los Feb 10, 2024
c24625f
14_4a poller: send block max attempts increased
Leptopt1los Feb 10, 2024
6f71f11
Merge remote-tracking branch 'upstream/dev' into emv-fixes
Leptopt1los Feb 10, 2024
4a382bc
typos fixed
Leptopt1los Feb 10, 2024
08f096d
EMV dump save/load fix
Leptopt1los Feb 11, 2024
a9de06d
cardholder name parsing prepared
Leptopt1los Feb 11, 2024
809e1b3
explicit nodata message when no data parsed from card
Leptopt1los Feb 11, 2024
11cfbd1
bruteforce sfi 2-3 records 1-5
Leptopt1los Feb 12, 2024
14d3510
little speed up
Leptopt1los Feb 12, 2024
b904555
application interchange profile parse added
Leptopt1los Feb 12, 2024
5c88e68
Merge remote-tracking branch 'upstream/dev' into emv-fixes
Leptopt1los Feb 13, 2024
3f29295
transactions render fix
Leptopt1los Feb 14, 2024
0397dd0
fix false-positive emv protocol detect
Leptopt1los Feb 14, 2024
8dd59a5
Merge remote-tracking branch 'upstream/dev' into emv-fixes
Leptopt1los Feb 14, 2024
c061fb1
transactions render fix part 2
Leptopt1los Feb 14, 2024
7b01a33
read transactions fail on some cards fixed
Leptopt1los Feb 15, 2024
4d73794
emv parser day ??->dd
Leptopt1los Feb 15, 2024
f7742c6
Merge remote-tracking branch 'upstream/dev' into emv-fixes
Leptopt1los Feb 15, 2024
698d0b4
emv parser day dd->--
Leptopt1los Feb 15, 2024
4adb492
nevermind. target 18
Leptopt1los Feb 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions applications/main/nfc/helpers/protocol_support/emv/emv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down
70 changes: 24 additions & 46 deletions applications/main/nfc/helpers/protocol_support/emv/emv_render.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "emv_render.h"

#include "../iso14443_4a/iso14443_4a_render.h"
#include <bit_lib.h>
#include "nfc/nfc_app_i.h"

void nfc_render_emv_info(const EmvData* data, NfcProtocolFormatType format_type, FuriString* str) {
Expand Down Expand Up @@ -29,21 +30,9 @@ 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);
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) {
Expand All @@ -63,11 +52,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;

Expand All @@ -83,21 +67,23 @@ 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");
}

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_application_interchange_profile(const EmvApplication* apl, FuriString* str) {
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;
}

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) {
Expand Down Expand Up @@ -126,23 +112,15 @@ 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(a[x]) {
if(top) {
furi_string_cat_printf(str, "%X", a[x]);
top = false;
} else {
furi_string_cat_printf(str, "%02X", a[x]);
}
}
}
FURI_LOG_D("EMV Render", "Amount: %llX\n", apl->trans[i].amount);
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) {
Expand Down Expand Up @@ -183,8 +161,8 @@ 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);
nfc_render_emv_pin_try_counter(data->emv_application.pin_try_counter, str);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ void nfc_render_emv_name(const char* data, FuriString* str);

void nfc_render_emv_application(const EmvApplication* data, FuriString* str);

void nfc_render_emv_extra(const EmvData* data, FuriString* str);
void nfc_render_emv_application_interchange_profile(const EmvApplication* apl, FuriString* str);

void nfc_render_emv_expired(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);

Expand Down
68 changes: 60 additions & 8 deletions applications/main/nfc/plugins/supported_cards/emv.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ 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);
else
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");

if(app.pan_len) {
Expand All @@ -82,25 +84,75 @@ 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);
parsed = true;
}

if(strlen(app.cardholder_name)) {
furi_string_cat_printf(parsed_data, "Cardholder name: %s\n", app.cardholder_name);
parsed = true;
}

if(app.exp_month | app.exp_year)
furi_string_cat_printf(parsed_data, "\nExp: %02X/%02X\n", app.exp_month, app.exp_year);
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: %s.%02X.20%02X\n",
day,
app.effective_month,
app.effective_year);

parsed = true;
}

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

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_try_counter != 0xFF)
if(app.pin_try_counter != 0xFF) {
furi_string_cat_printf(parsed_data, "PIN attempts left: %d\n", app.pin_try_counter);
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;
} while(false);
Expand Down
2 changes: 2 additions & 0 deletions applications/main/nfc/scenes/nfc_scene_emv_more_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
44 changes: 36 additions & 8 deletions lib/nfc/protocols/emv/emv.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,14 @@ 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;
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));

flipper_format_read_string(ff, "Application label", 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;
Expand All @@ -93,15 +97,24 @@ 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;

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->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;
if(!flipper_format_read_uint32(ff, "PIN try counter", &pin_try_counter, 1)) break;
app->pin_try_counter = pin_try_counter;

parsed = true;
Expand All @@ -124,7 +137,12 @@ 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, "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))
break;

uint32_t pan_len = app.pan_len;
if(!flipper_format_write_uint32(ff, "PAN length", &pan_len, 1)) break;
Expand All @@ -136,15 +154,25 @@ 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;

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.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))
if(!flipper_format_write_uint32(ff, "PIN try counter", (uint32_t*)&app.pin_try_counter, 1))
break;

saved = true;
Expand Down
Loading