diff --git a/applications/main/nfc/nfc_cli.c b/applications/main/nfc/nfc_cli.c index a6475ca68..c21e491e6 100644 --- a/applications/main/nfc/nfc_cli.c +++ b/applications/main/nfc/nfc_cli.c @@ -67,7 +67,7 @@ static void nfc_cli_emulate(Cli* cli, FuriString* args) { }; while(!cli_cmd_interrupt_received(cli)) { - if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 100)) { + if (furi_hal_nfc_listen(¶ms, false, 100)) { printf("Reader detected\r\n"); furi_hal_nfc_sleep(); } diff --git a/applications/main/u2f/scenes/u2f_scene_main.c b/applications/main/u2f/scenes/u2f_scene_main.c index af7f1159b..abf78c841 100644 --- a/applications/main/u2f/scenes/u2f_scene_main.c +++ b/applications/main/u2f/scenes/u2f_scene_main.c @@ -101,6 +101,7 @@ void u2f_scene_main_on_enter(void* context) { if(app->u2f_ready == true) { u2f_set_event_callback(app->u2f_instance, u2f_scene_main_event_callback, app); app->u2f_hid = u2f_hid_start(app->u2f_instance); + app->u2f_nfc = u2f_nfc_start(app->u2f_instance); u2f_view_set_ok_callback(app->u2f_view, u2f_scene_main_ok_callback, app); } else { u2f_free(app->u2f_instance); @@ -117,6 +118,7 @@ void u2f_scene_main_on_exit(void* context) { furi_timer_free(app->timer); if(app->u2f_ready == true) { u2f_hid_stop(app->u2f_hid); + u2f_nfc_stop(app->u2f_nfc); u2f_free(app->u2f_instance); } } diff --git a/applications/main/u2f/u2f.c b/applications/main/u2f/u2f.c index 767733ce6..f4197dd74 100644 --- a/applications/main/u2f/u2f.c +++ b/applications/main/u2f/u2f.c @@ -16,6 +16,7 @@ #define U2F_CMD_REGISTER 0x01 #define U2F_CMD_AUTHENTICATE 0x02 #define U2F_CMD_VERSION 0x03 +#define U2F_CMD_APPLET_SELECTION 0xA4 typedef enum { U2fCheckOnly = 0x07, // "check-only" - only check key handle, don't send auth response @@ -37,11 +38,6 @@ typedef struct { } __attribute__((packed)) U2fKeyHandle; typedef struct { - uint8_t cla; - uint8_t ins; - uint8_t p1; - uint8_t p2; - uint8_t len[3]; uint8_t challenge[32]; uint8_t app_id[32]; } __attribute__((packed)) U2fRegisterReq; @@ -54,11 +50,6 @@ typedef struct { } __attribute__((packed)) U2fRegisterResp; typedef struct { - uint8_t cla; - uint8_t ins; - uint8_t p1; - uint8_t p2; - uint8_t len[3]; uint8_t challenge[32]; uint8_t app_id[32]; U2fKeyHandle key_handle; @@ -72,10 +63,14 @@ typedef struct { static const uint8_t ver_str[] = {"U2F_V2"}; +// NFC applet selection fields +static const uint8_t rid_ac_ax[] = { 0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01 }; + static const uint8_t state_no_error[] = {0x90, 0x00}; static const uint8_t state_not_supported[] = {0x6D, 0x00}; static const uint8_t state_user_missing[] = {0x69, 0x85}; static const uint8_t state_wrong_data[] = {0x6A, 0x80}; +static const uint8_t state_app_not_found[] = { 0x6A, 0x82 }; struct U2fData { uint8_t device_key[32]; @@ -88,6 +83,17 @@ struct U2fData { void* context; }; +static void* apdu_command_data(U2fApduCommand* cmd) { + // Short encoding is a single byte. + // Extended length encoding is 0 byte followed by MSB and LSB bytes. + if (cmd->len[0] == 0) { + return cmd->len + 3; + } + else { + return cmd->len + 1; + } +} + static int u2f_uecc_random(uint8_t* dest, unsigned size) { furi_hal_random_fill_buf(dest, size); return 1; @@ -178,9 +184,10 @@ static uint8_t u2f_der_encode_signature(uint8_t* der, uint8_t* sig) { return len; } -static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { - U2fRegisterReq* req = (U2fRegisterReq*)buf; - U2fRegisterResp* resp = (U2fRegisterResp*)buf; +static uint16_t u2f_register(U2fData* U2F, const uint8_t* in_buf, uint8_t* out_buf) { + U2fApduCommand* cmd = (U2fApduCommand*)in_buf; + U2fRegisterReq* req = apdu_command_data(cmd); + U2fRegisterResp* resp = (U2fRegisterResp*)out_buf; U2fKeyHandle handle; uint8_t private[32]; U2fPubKey pub_key; @@ -190,13 +197,13 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { if(u2f_data_check(false) == false) { U2F->ready = false; if(U2F->callback != NULL) U2F->callback(U2fNotifyError, U2F->context); - memcpy(&buf[0], state_not_supported, 2); + memcpy(&out_buf[0], state_not_supported, 2); return 2; } if(U2F->callback != NULL) U2F->callback(U2fNotifyRegister, U2F->context); if(U2F->user_present == false) { - memcpy(&buf[0], state_user_missing, 2); + memcpy(&out_buf[0], state_user_missing, 2); return 2; } U2F->user_present = false; @@ -247,9 +254,10 @@ static uint16_t u2f_register(U2fData* U2F, uint8_t* buf) { return (sizeof(U2fRegisterResp) + cert_len + signature_len + 2); } -static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { - U2fAuthReq* req = (U2fAuthReq*)buf; - U2fAuthResp* resp = (U2fAuthResp*)buf; +static uint16_t u2f_authenticate(U2fData* U2F, const uint8_t* in_buf, uint8_t* out_buf) { + U2fApduCommand* cmd = (U2fApduCommand*)in_buf; + U2fAuthReq* req = apdu_command_data(cmd); + U2fAuthResp* resp = (U2fAuthResp*)out_buf; uint8_t priv_key[32]; uint8_t mac_control[32]; hmac_sha256_context hmac_ctx; @@ -262,7 +270,7 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { if(u2f_data_check(false) == false) { U2F->ready = false; if(U2F->callback != NULL) U2F->callback(U2fNotifyError, U2F->context); - memcpy(&buf[0], state_not_supported, 2); + memcpy(&out_buf[0], state_not_supported, 2); return 2; } @@ -270,8 +278,8 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { if(U2F->user_present == true) { flags |= 1; } else { - if(req->p1 == U2fEnforce) { - memcpy(&buf[0], state_user_missing, 2); + if (cmd->p1 == U2fEnforce) { + memcpy(&out_buf[0], state_user_missing, 2); return 2; } } @@ -302,12 +310,12 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { if(memcmp(req->key_handle.hash, mac_control, 32) != 0) { FURI_LOG_W(TAG, "Wrong handle!"); - memcpy(&buf[0], state_wrong_data, 2); + memcpy(&out_buf[0], state_wrong_data, 2); return 2; } - if(req->p1 == U2fCheckOnly) { // Check-only: don't need to send full response - memcpy(&buf[0], state_user_missing, 2); + if (cmd->p1 == U2fCheckOnly) { // Check-only: don't need to send full response + memcpy(&out_buf[0], state_user_missing, 2); return 2; } @@ -327,36 +335,69 @@ static uint16_t u2f_authenticate(U2fData* U2F, uint8_t* buf) { return (sizeof(U2fAuthResp) + signature_len + 2); } -uint16_t u2f_msg_parse(U2fData* U2F, uint8_t* buf, uint16_t len) { +uint16_t u2f_applet_selection(const uint8_t* in_buf, uint8_t* out_buf) { + U2fApduCommand* cmd = (U2fApduCommand*)in_buf; + uint8_t* data = apdu_command_data(cmd); + + FURI_LOG_D( + TAG, + "len=%d %02x%02x%02x%02x%02x%02x%02x%02x", + cmd->len[0], + data[0], + data[1], + data[2], + data[3], + data[4], + data[5], + data[6], + data[7]); + + if (cmd->len[0] != 8 || memcmp(rid_ac_ax, data, 8) != 0) { + memcpy(&out_buf[0], state_app_not_found, 2); + return 2; + } + + memcpy(&out_buf[0], ver_str, 6); + memcpy(&out_buf[6], state_no_error, 2); + return 8; +} + +uint16_t u2f_msg_parse(U2fData* U2F, const uint8_t* in_buf, uint16_t in_len, uint8_t* out_buf) { furi_assert(U2F); - if(!U2F->ready) return 0; - if((buf[0] != 0x00) && (len < 5)) return 0; - if(buf[1] == U2F_CMD_REGISTER) { // Register request - return u2f_register(U2F, buf); - - } else if(buf[1] == U2F_CMD_AUTHENTICATE) { // Authenticate request - return u2f_authenticate(U2F, buf); - - } else if(buf[1] == U2F_CMD_VERSION) { // Get U2F version string - memcpy(&buf[0], ver_str, 6); - memcpy(&buf[6], state_no_error, 2); + if (!U2F->ready) return 0; + if ((in_buf[0] != 0x00) && (in_len < 5)) return 0; + FURI_LOG_D(TAG, "ins=0x%02x", in_buf[1]); + if (in_buf[1] == U2F_CMD_REGISTER) { // Register request + return u2f_register(U2F, in_buf, out_buf); + } + else if (in_buf[1] == U2F_CMD_AUTHENTICATE) { // Authenticate request + return u2f_authenticate(U2F, in_buf, out_buf); + } + else if (in_buf[1] == U2F_CMD_VERSION) { // Get U2F version string + memcpy(&out_buf[0], ver_str, 6); + memcpy(&out_buf[6], state_no_error, 2); return 8; - } else { - memcpy(&buf[0], state_not_supported, 2); + } + else if (in_buf[1] == U2F_CMD_APPLET_SELECTION) { + return u2f_applet_selection(in_buf, out_buf); + } + else { + memcpy(&out_buf[0], state_not_supported, 2); return 2; } return 0; } void u2f_wink(U2fData* U2F) { - if(U2F->callback != NULL) U2F->callback(U2fNotifyWink, U2F->context); + if (U2F->callback != NULL) U2F->callback(U2fNotifyWink, U2F->context); } void u2f_set_state(U2fData* U2F, uint8_t state) { - if(state == 0) { - if(U2F->callback != NULL) U2F->callback(U2fNotifyDisconnect, U2F->context); - } else { - if(U2F->callback != NULL) U2F->callback(U2fNotifyConnect, U2F->context); + if (state == 0) { + if (U2F->callback != NULL) U2F->callback(U2fNotifyDisconnect, U2F->context); + } + else { + if (U2F->callback != NULL) U2F->callback(U2fNotifyConnect, U2F->context); } U2F->user_present = false; } diff --git a/applications/main/u2f/u2f.h b/applications/main/u2f/u2f.h index dcd7c3ff2..e7508dfa5 100644 --- a/applications/main/u2f/u2f.h +++ b/applications/main/u2f/u2f.h @@ -6,6 +6,14 @@ extern "C" { #include +typedef struct { + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t len[]; +} __attribute__((packed)) U2fApduCommand; + typedef enum { U2fNotifyRegister, U2fNotifyAuth, @@ -30,7 +38,7 @@ void u2f_set_event_callback(U2fData* instance, U2fEvtCallback callback, void* co void u2f_confirm_user_present(U2fData* instance); -uint16_t u2f_msg_parse(U2fData* instance, uint8_t* buf, uint16_t len); +uint16_t u2f_msg_parse(U2fData* instance, const uint8_t* in_buf, uint16_t len, uint8_t* out_buf); void u2f_wink(U2fData* instance); diff --git a/applications/main/u2f/u2f_app_i.h b/applications/main/u2f/u2f_app_i.h index 2896684c3..cfaf3a929 100644 --- a/applications/main/u2f/u2f_app_i.h +++ b/applications/main/u2f/u2f_app_i.h @@ -13,6 +13,7 @@ #include #include #include "views/u2f_view.h" +#include "u2f_nfc.h" #include "u2f_hid.h" #include "u2f.h" @@ -54,6 +55,7 @@ struct U2fApp { Widget* widget; FuriTimer* timer; U2fHid* u2f_hid; + U2fNfc* u2f_nfc; U2fView* u2f_view; U2fData* u2f_instance; GpioCustomEvent event_cur; diff --git a/applications/main/u2f/u2f_hid.c b/applications/main/u2f/u2f_hid.c index 9b625c1f3..4ca49a3bb 100644 --- a/applications/main/u2f/u2f_hid.c +++ b/applications/main/u2f/u2f_hid.c @@ -140,8 +140,11 @@ static bool u2f_hid_parse_request(U2fHid* u2f_hid) { } else if(u2f_hid->packet.cmd == U2F_HID_MSG) { // MSG - U2F message if((u2f_hid->lock == true) && (u2f_hid->packet.cid != u2f_hid->lock_cid)) return false; - uint16_t resp_len = - u2f_msg_parse(u2f_hid->u2f_instance, u2f_hid->packet.payload, u2f_hid->packet.len); + uint16_t resp_len = u2f_msg_parse( + u2f_hid->u2f_instance, + u2f_hid->packet.payload, + u2f_hid->packet.len, + u2f_hid->packet.payload); if(resp_len > 0) { u2f_hid->packet.len = resp_len; u2f_hid_send_response(u2f_hid); diff --git a/applications/main/u2f/u2f_nfc.c b/applications/main/u2f/u2f_nfc.c new file mode 100644 index 000000000..9ee97ad2a --- /dev/null +++ b/applications/main/u2f/u2f_nfc.c @@ -0,0 +1,187 @@ +#include "u2f_nfc.h" +#include "furi_hal.h" +#include "u2f.h" + +#define TAG "U2F_NFC" + +typedef enum { + WorkerEvtReserved = (1 << 0), + WorkerEvtStop = (1 << 1), +} WorkerEvtFlags; + +struct U2fNfc { + FuriThread* thread; + U2fData* u2f_instance; + uint8_t payload[65535]; + uint16_t payload_len; + uint16_t payload_cursor; +}; + +static uint16_t +u2f_callback(U2fNfc* u2f_nfc, const uint8_t* buff_rx, uint16_t buff_rx_len, uint8_t* buff_tx) { + U2fApduCommand* cmd = (U2fApduCommand*)buff_rx; + if (cmd->ins == 0xC0) { + if (u2f_nfc->payload_len == 0) { + FURI_LOG_E(TAG, "requested block but not chaining"); + buff_tx[0] = 0x69; + buff_tx[1] = 0x00; + return 2; + } + + FURI_LOG_T(TAG, "continued chaining %d/%d", u2f_nfc->payload_cursor, u2f_nfc->payload_len); + + uint16_t max_resp_len = cmd->len[0]; + if (max_resp_len == 0) { + max_resp_len = 256; + } + + uint16_t remaining_len = (u2f_nfc->payload_len - 2) - u2f_nfc->payload_cursor; + if (remaining_len > max_resp_len) { + memcpy(buff_tx, &u2f_nfc->payload[u2f_nfc->payload_cursor], max_resp_len); + remaining_len -= max_resp_len; + buff_tx[max_resp_len] = 0x61; + if (remaining_len >= 256) { + buff_tx[max_resp_len + 1] = 0x00; + } + else { + buff_tx[max_resp_len + 1] = remaining_len; + } + u2f_nfc->payload_cursor += max_resp_len; + return max_resp_len + 2; + } + else { + memcpy( + buff_tx, + &u2f_nfc->payload[u2f_nfc->payload_cursor], + u2f_nfc->payload_len - u2f_nfc->payload_cursor); + u2f_nfc->payload_len = 0; + return remaining_len; + } + } + + // Presence is implied by touching the NFC devices. + u2f_confirm_user_present(u2f_nfc->u2f_instance); + + u2f_nfc->payload_len = + u2f_msg_parse(u2f_nfc->u2f_instance, buff_rx, buff_rx_len, u2f_nfc->payload); + + // If this is extended format, send entire response at once + if (cmd->len[0] == 0) { + FURI_LOG_T(TAG, "single extended response"); + memcpy(&buff_tx, u2f_nfc->payload, u2f_nfc->payload_len); + uint16_t len = u2f_nfc->payload_len; + u2f_nfc->payload_len = 0; + return len; + } + + // Otherwise, we need to do chaining. + uint16_t max_resp_len = 256; + + // If this message happens to be less than the chaining size, send it all at once. + if ((u2f_nfc->payload_len - 2) <= max_resp_len) { + FURI_LOG_T(TAG, "single short response"); + memcpy(buff_tx, u2f_nfc->payload, u2f_nfc->payload_len); + uint16_t len = u2f_nfc->payload_len; + u2f_nfc->payload_len = 0; + return len; + } + else { + memcpy(buff_tx, u2f_nfc->payload, max_resp_len); + buff_tx[max_resp_len] = 0x61; + uint16_t remaining_len = (u2f_nfc->payload_len - 2) - max_resp_len; + if (remaining_len >= max_resp_len) { + buff_tx[max_resp_len + 1] = 0x00; + } + else { + buff_tx[max_resp_len + 1] = remaining_len; + } + u2f_nfc->payload_cursor = max_resp_len; + FURI_LOG_T( + TAG, "started u2f chaining %d/%d", u2f_nfc->payload_cursor, u2f_nfc->payload_len); + return max_resp_len + 2; + } +} + +static int32_t u2f_nfc_worker(void* context) { + U2fNfc* u2f_nfc = context; + FURI_LOG_D(TAG, "Init"); + while (furi_hal_nfc_is_busy()) { + furi_delay_ms(10); + } + FuriHalNfcDevData params = { + // TODO: Randomize this or something? + .uid = {0xCF, 0x72, 0xd4, 0x40}, + .uid_len = 4, + .atqa = {0x00, 0x04}, + .sak = 0x20, + .type = FuriHalNfcTypeA, + .interface = FuriHalNfcInterfaceIsoDep, + }; + + furi_hal_nfc_exit_sleep(); + + FURI_LOG_D(TAG, "Start"); + + while (1) { + uint32_t flags = furi_thread_flags_wait(WorkerEvtStop, FuriFlagWaitAny, 10); + if (flags != FuriFlagErrorTimeout) { + furi_check((flags & FuriFlagError) == 0); + if (flags & WorkerEvtStop) break; + } + if (!furi_hal_nfc_listen(¶ms, false, 200)) { + FURI_LOG_T(TAG, "wtf"); + continue; + } + FuriHalNfcTxRxContext tx_rx = {}; + tx_rx.tx_bits = 0; + tx_rx.tx_rx_type = FuriHalNfcTxRxTypeDefault; + if (!furi_hal_nfc_tx_rx(&tx_rx, 300)) continue; + if (tx_rx.rx_bits == 0) continue; + u2f_nfc->payload_len = 0; + u2f_nfc->payload_cursor = 0; + while (true) { + uint16_t payload_len = + u2f_callback(u2f_nfc, tx_rx.rx_data, tx_rx.rx_bits / 8, tx_rx.tx_data); + tx_rx.rx_bits = 0; + FURI_LOG_T(TAG, "payload_len=%d", payload_len); + if (payload_len == 0) { + break; + } + else { + tx_rx.tx_bits = payload_len * 8; + tx_rx.tx_rx_type = FuriHalNfcTxRxTypeDefault; + if (!furi_hal_nfc_tx_rx(&tx_rx, 300)) break; + if (tx_rx.rx_bits == 0) break; + } + } + } + + FURI_LOG_D(TAG, "Cleanup"); + furi_hal_nfc_sleep(); + FURI_LOG_D(TAG, "End"); + return 0; +} + +U2fNfc* u2f_nfc_start(U2fData* u2f_inst) { + U2fNfc* u2f_nfc = malloc(sizeof(U2fNfc)); + u2f_nfc->u2f_instance = u2f_inst; + u2f_nfc->payload_len = 0; + u2f_nfc->payload_cursor = 0; + + u2f_nfc->thread = furi_thread_alloc(); + furi_thread_set_name(u2f_nfc->thread, "U2fNFCWorker"); + furi_thread_set_stack_size(u2f_nfc->thread, 4096); + furi_thread_set_context(u2f_nfc->thread, u2f_nfc); + furi_thread_set_callback(u2f_nfc->thread, u2f_nfc_worker); + furi_thread_start(u2f_nfc->thread); + + return u2f_nfc; +} + +void u2f_nfc_stop(U2fNfc* u2f_nfc) { + furi_assert(u2f_nfc); + furi_thread_flags_set(furi_thread_get_id(u2f_nfc->thread), WorkerEvtStop); + furi_thread_join(u2f_nfc->thread); + furi_thread_free(u2f_nfc->thread); + free(u2f_nfc); +} diff --git a/applications/main/u2f/u2f_nfc.h b/applications/main/u2f/u2f_nfc.h new file mode 100644 index 000000000..c3018f601 --- /dev/null +++ b/applications/main/u2f/u2f_nfc.h @@ -0,0 +1,17 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "u2f.h" + + typedef struct U2fNfc U2fNfc; + + U2fNfc* u2f_nfc_start(U2fData* u2f_inst); + + void u2f_nfc_stop(U2fNfc* u2f_hid); + +#ifdef __cplusplus +} +#endif diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index 9e38f6970..1874b664b 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,12.0,, +Version,+,13.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1198,7 +1198,7 @@ Function,+,furi_hal_nfc_field_on,void, Function,-,furi_hal_nfc_init,void, Function,+,furi_hal_nfc_is_busy,_Bool, Function,+,furi_hal_nfc_is_init,_Bool, -Function,+,furi_hal_nfc_listen,_Bool,"uint8_t*, uint8_t, uint8_t*, uint8_t, _Bool, uint32_t" +Function,+,furi_hal_nfc_listen,_Bool,"FuriHalNfcDevData*, _Bool, uint32_t" Function,+,furi_hal_nfc_listen_rx,_Bool,"FuriHalNfcTxRxContext*, uint32_t" Function,+,furi_hal_nfc_listen_sleep,void, Function,+,furi_hal_nfc_listen_start,void,FuriHalNfcDevData* diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index 6381d1a91..0923378db 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -206,10 +206,7 @@ bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid) { } bool furi_hal_nfc_listen( - uint8_t* uid, - uint8_t uid_len, - uint8_t* atqa, - uint8_t sak, + FuriHalNfcDevData* nfc_data, bool activate_after_sak, uint32_t timeout) { rfalNfcState state = rfalNfcGetState(); @@ -232,16 +229,19 @@ bool furi_hal_nfc_listen( .notifyCb = NULL, .activate_after_sak = activate_after_sak, }; - if(FURI_BIT(sak, 5)) { + if (nfc_data->interface == FuriHalNfcInterfaceIsoDep) { + params.compMode = RFAL_COMPLIANCE_MODE_ISO; + } + else if (FURI_BIT(nfc_data->sak, 5)) { params.compMode = RFAL_COMPLIANCE_MODE_EMV; } else { params.compMode = RFAL_COMPLIANCE_MODE_NFC; } - params.lmConfigPA.nfcidLen = uid_len; - memcpy(params.lmConfigPA.nfcid, uid, uid_len); - params.lmConfigPA.SENS_RES[0] = atqa[0]; - params.lmConfigPA.SENS_RES[1] = atqa[1]; - params.lmConfigPA.SEL_RES = sak; + params.lmConfigPA.nfcidLen = nfc_data->uid_len; + memcpy(params.lmConfigPA.nfcid, nfc_data->uid, nfc_data->uid_len); + params.lmConfigPA.SENS_RES[0] = nfc_data->atqa[0]; + params.lmConfigPA.SENS_RES[1] = nfc_data->atqa[1]; + params.lmConfigPA.SEL_RES = nfc_data->sak; rfalNfcDiscover(¶ms); // Disable EMD suppression. diff --git a/firmware/targets/furi_hal_include/furi_hal_nfc.h b/firmware/targets/furi_hal_include/furi_hal_nfc.h index d3f6de602..79207ea71 100644 --- a/firmware/targets/furi_hal_include/furi_hal_nfc.h +++ b/firmware/targets/furi_hal_include/furi_hal_nfc.h @@ -154,6 +154,7 @@ bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid); /** NFC listen * * @param uid pointer to uid buffer + * @param nfc_data pointer to FuriHalNfcDevData * @param uid_len uid length * @param atqa pointer to atqa * @param sak sak @@ -163,10 +164,7 @@ bool furi_hal_nfc_activate_nfca(uint32_t timeout, uint32_t* cuid); * @return true on success */ bool furi_hal_nfc_listen( - uint8_t* uid, - uint8_t uid_len, - uint8_t* atqa, - uint8_t sak, + FuriHalNfcDevData* nfc_data, bool activate_after_sak, uint32_t timeout); diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 4138bf033..de7e99cf2 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -776,7 +776,7 @@ void nfc_worker_emulate_uid(NfcWorker* nfc_worker) { // Need to save ATS to support ISO-14443A-4 emulation while(nfc_worker->state == NfcWorkerStateUidEmulate) { - if(furi_hal_nfc_listen(data->uid, data->uid_len, data->atqa, data->sak, false, 100)) { + if (furi_hal_nfc_listen(data, false, 100)) { if(furi_hal_nfc_tx_rx(&tx_rx, 100)) { reader_data->size = tx_rx.rx_bits / 8; if(reader_data->size > 0) { @@ -834,7 +834,7 @@ void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) { } while(nfc_worker->state == NfcWorkerStateEmulateApdu) { //-V1044 - if(furi_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, false, 300)) { + if (furi_hal_nfc_listen(¶ms, false, 300)) { FURI_LOG_D(TAG, "POS terminal detected"); if(emv_card_emulation(&tx_rx)) { FURI_LOG_D(TAG, "EMV card emulated"); diff --git a/scripts/flipper/assets/icon.py b/scripts/flipper/assets/icon.py index ed85b024e..c31eab0b7 100644 --- a/scripts/flipper/assets/icon.py +++ b/scripts/flipper/assets/icon.py @@ -60,7 +60,10 @@ class ImageTools: with Image.open(file) as im: with io.BytesIO() as output: bw = im.convert("1") - bw = ImageOps.invert(bw) + try: + bw = ImageOps.invert(bw) + except OSError: + bw = bw.point(lambda x: 255 - x) bw.save(output, format="XBM") return output.getvalue()