diff --git a/io/include/os_io_nfc.h b/io/include/os_io_nfc.h new file mode 100644 index 000000000..bab27d0b2 --- /dev/null +++ b/io/include/os_io_nfc.h @@ -0,0 +1,48 @@ +/***************************************************************************** + * (c) 2025 Ledger SAS. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *****************************************************************************/ + +#pragma once + +#ifdef HAVE_NFC_READER + +enum card_tech { + NFC_A, + NFC_B +}; + +enum nfc_event { + CARD_DETECTED, + CARD_REMOVED, +}; + +struct card_info { + enum card_tech tech; + uint8_t nfcid[7]; + size_t nfcid_len; +}; + +typedef void (*nfc_evt_callback_t)(enum nfc_event event, struct card_info *info); +typedef void (*nfc_resp_callback_t)(bool error, bool timeout, uint8_t *resp_data, size_t resp_len); + +bool os_io_nfc_reader_send(const uint8_t *cmd_data, + size_t cmd_len, + nfc_resp_callback_t callback, + int timeout_ms); + +/* Return false if nfc reader can not be started in current conditions */ +bool os_io_nfc_reader_start(nfc_evt_callback_t callback); +void os_io_nfc_reader_stop(void); +#endif // HAVE_NFC_READER diff --git a/io/src/os_io_nfc.c b/io/src/os_io_nfc.c new file mode 100644 index 000000000..8b46f4913 --- /dev/null +++ b/io/src/os_io_nfc.c @@ -0,0 +1,167 @@ +#ifdef HAVE_NFC_READER + +/* Includes ------------------------------------------------------------------*/ +#include +#include "os_io.h" +#include "os_io_seph_cmd.h" +#include "checks.h" +#include "errors.h" +#include "os_io_nfc.h" +#include "os_pic.h" +#include "decorators.h" + +#ifdef HAVE_PRINTF +#define LOG_IO PRINTF +// #define LOG_IO(...) +#else // !HAVE_PRINTF +#define LOG_IO(...) +#endif // !HAVE_PRINTF + +/* Private enumerations ------------------------------------------------------*/ + +/* Private types, structures, unions -----------------------------------------*/ + +struct nfc_reader_context { + nfc_resp_callback_t resp_callback; + nfc_evt_callback_t evt_callback; + bool reader_mode; + unsigned int remaining_ms; + struct card_info card; +}; + +/* Private defines------------------------------------------------------------*/ + +/* Private macros-------------------------------------------------------------*/ + +/* Private functions prototypes ----------------------------------------------*/ +static void nfc_event(uint8_t *buffer_in, size_t buffer_in_length); +static void nfc_ticker(void); + +/* Private variables ---------------------------------------------------------*/ + +static struct nfc_reader_context G_io_reader_ctx = {}; + +/* Private functions ---------------------------------------------------------*/ + +static void nfc_event(uint8_t *buffer_in, size_t buffer_in_length) +{ + if (buffer_in_length < 3) { + return; + } + size_t size = U2BE(buffer_in, 1); + if (buffer_in_length < 3 + size) { + return; + } + + if (size >= 1) { + switch (buffer_in[3]) { + case SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED: { + G_io_reader_ctx.card.tech + = (buffer_in[4] == SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED_A) ? NFC_A : NFC_B; + G_io_reader_ctx.card.nfcid_len = MIN(size - 2, sizeof(G_io_reader_ctx.card.nfcid)); + memcpy((void *) G_io_reader_ctx.card.nfcid, + buffer_in + 5, + G_io_reader_ctx.card.nfcid_len); + + if (G_io_reader_ctx.evt_callback != NULL) { + G_io_reader_ctx.evt_callback(CARD_DETECTED, + (struct card_info *) &G_io_reader_ctx.card); + } + } break; + + case SEPROXYHAL_TAG_NFC_EVENT_CARD_LOST: + // If card is removed during an APDU processing, call the resp_callback with an + // error + if (G_io_reader_ctx.resp_callback != NULL) { + nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback; + G_io_reader_ctx.resp_callback = NULL; + resp_cb(true, false, NULL, 0); + } + + if (G_io_reader_ctx.evt_callback != NULL) { + G_io_reader_ctx.evt_callback(CARD_REMOVED, + (struct card_info *) &G_io_reader_ctx.card); + } + memset((void *) &G_io_reader_ctx.card, 0, sizeof(G_io_reader_ctx.card)); + break; + } + } +} + +static void nfc_ticker(void) +{ + if (G_io_reader_ctx.resp_callback != NULL) { + if (G_io_reader_ctx.remaining_ms <= 100) { + G_io_reader_ctx.remaining_ms = 0; + nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback; + G_io_reader_ctx.resp_callback = NULL; + resp_cb(false, true, NULL, 0); + } + else { + G_io_reader_ctx.remaining_ms -= 100; + } + } +} + +/* Exported functions --------------------------------------------------------*/ + +void os_io_nfc_reader_rx(uint8_t *in_buffer, size_t in_buffer_len) +{ + if (G_io_reader_ctx.resp_callback != NULL) { + nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback; + G_io_reader_ctx.resp_callback = NULL; + resp_cb(false, false, in_buffer, in_buffer_len); + } +} + +void os_io_nfc_evt(uint8_t *buffer_in, size_t buffer_in_length) +{ + switch (buffer_in[0]) { + case SEPROXYHAL_TAG_NFC_EVENT: + nfc_event(buffer_in, buffer_in_length); + break; + + case SEPROXYHAL_TAG_TICKER_EVENT: + nfc_ticker(); + break; + + default: + break; + } +} + +bool os_io_nfc_reader_send(const uint8_t *cmd_data, + size_t cmd_len, + nfc_resp_callback_t callback, + int timeout_ms) +{ + G_io_reader_ctx.resp_callback = PIC(callback); + os_io_tx_cmd(APDU_TYPE_NFC, PIC(cmd_data), cmd_len, 0); + + G_io_reader_ctx.remaining_ms = timeout_ms; + + return true; +} + +bool os_io_nfc_reader_start(nfc_evt_callback_t callback) +{ + G_io_reader_ctx.evt_callback = PIC(callback); + G_io_reader_ctx.reader_mode = true; + G_io_reader_ctx.resp_callback = NULL; + os_io_nfc_cmd_start_reader(); + return true; +} + +void os_io_nfc_reader_stop(void) +{ + G_io_reader_ctx.evt_callback = NULL; + G_io_reader_ctx.reader_mode = false; + G_io_reader_ctx.resp_callback = NULL; + os_io_nfc_cmd_stop(); +} + +bool os_io_nfc_is_reader(void) +{ + return G_io_reader_ctx.reader_mode; +} +#endif // HAVE_NFC_READER diff --git a/io_legacy/include/os_io_legacy.h b/io_legacy/include/os_io_legacy.h index 70e892632..17a9784ea 100644 --- a/io_legacy/include/os_io_legacy.h +++ b/io_legacy/include/os_io_legacy.h @@ -56,9 +56,6 @@ extern unsigned char G_io_asynch_ux_callback; /* Exported variables --------------------------------------------------------*/ extern unsigned char G_io_seproxyhal_spi_buffer[OS_IO_SEPH_BUFFER_SIZE]; -#ifdef HAVE_NFC_READER -extern struct nfc_reader_context G_io_reader_ctx; -#endif // HAVE_NFC_READER /* Exported functions prototypes--------------------------------------------- */ SYSCALL void io_seph_send(const unsigned char *buffer PLENGTH(length), unsigned short length); @@ -98,14 +95,3 @@ unsigned char io_event(unsigned char channel); int io_legacy_apdu_rx(uint8_t handle_ux_events); int io_legacy_apdu_tx(const unsigned char *buffer, unsigned short length); - -#ifdef HAVE_NFC_READER -bool io_nfc_reader_send(const uint8_t *cmd_data, - size_t cmd_len, - nfc_resp_callback_t callback, - int timeout_ms); - -/* Return false if nfc reader can not be started in current conditions */ -bool io_nfc_reader_start(nfc_evt_callback_t callback); -void io_nfc_reader_stop(void); -#endif // HAVE_NFC_READER diff --git a/io_legacy/include/os_io_legacy_types.h b/io_legacy/include/os_io_legacy_types.h index 87a339735..00ed043b8 100644 --- a/io_legacy/include/os_io_legacy_types.h +++ b/io_legacy/include/os_io_legacy_types.h @@ -54,18 +54,6 @@ typedef enum { APDU_USB_WEBUSB, } io_apdu_state_e; -#ifdef HAVE_NFC_READER -enum card_tech { - NFC_A, - NFC_B -}; - -enum nfc_event { - CARD_DETECTED, - CARD_REMOVED, -}; -#endif // HAVE_NFC_READER - /* Exported types, structures, unions ----------------------------------------*/ typedef struct { io_apdu_state_e apdu_state; // by default @@ -77,31 +65,6 @@ typedef struct { #endif // HAVE_BLE } io_seph_app_t; -#ifdef HAVE_NFC_READER -struct card_info { - enum card_tech tech; - uint8_t nfcid[7]; - size_t nfcid_len; -}; - -typedef void (*nfc_evt_callback_t)(enum nfc_event event, struct card_info *info); -typedef void (*nfc_resp_callback_t)(bool error, bool timeout, uint8_t *resp_data, size_t resp_len); - -struct nfc_reader_context { - nfc_resp_callback_t resp_callback; - nfc_evt_callback_t evt_callback; - bool reader_mode; - bool event_happened; - bool response_received; - unsigned int remaining_ms; - enum nfc_event last_event; - struct card_info card; - uint8_t *apdu_rx; - size_t apdu_rx_len; // Used length - size_t apdu_rx_max_size; // Max size of buffer -}; -#endif // HAVE_NFC_READER - /* Exported defines --------------------------------------------------------*/ #ifdef IO_SEPROXYHAL_BUFFER_SIZE_B #undef IO_SEPROXYHAL_BUFFER_SIZE_B diff --git a/io_legacy/src/os_io_legacy.c b/io_legacy/src/os_io_legacy.c index 279b28b29..4245a2c26 100644 --- a/io_legacy/src/os_io_legacy.c +++ b/io_legacy/src/os_io_legacy.c @@ -67,10 +67,6 @@ unsigned char G_io_asynch_ux_callback; extern u2f_service_t G_io_u2f; #endif // HAVE_IO_U2F -#ifdef HAVE_NFC_READER -struct nfc_reader_context G_io_reader_ctx; -#endif // HAVE_NFC_READER - #ifdef HAVE_BOLOS_APP_STACK_CANARY extern unsigned int app_stack_canary; #endif // HAVE_BOLOS_APP_STACK_CANARY @@ -309,12 +305,6 @@ void io_seproxyhal_init(void) init_io.ble.profile_mask = BLE_LEDGER_PROFILE_APDU; #endif // !HAVE_BLE -#ifdef HAVE_NFC_READER - memset((void *) &G_io_reader_ctx, 0, sizeof(G_io_reader_ctx)); - G_io_reader_ctx.apdu_rx = G_io_seproxyhal_spi_buffer; - G_io_reader_ctx.apdu_rx_max_size = sizeof(G_io_seproxyhal_spi_buffer); -#endif // HAVE_NFC_READER - #ifdef HAVE_BOLOS_APP_STACK_CANARY app_stack_canary = APP_STACK_CANARY_MAGIC; #endif // HAVE_BOLOS_APP_STACK_CANARY @@ -476,156 +466,3 @@ int io_legacy_apdu_tx(const unsigned char *buffer, unsigned short length) return status; } - -#ifdef HAVE_NFC_READER - -void io_nfc_event(uint8_t *buffer_in, size_t buffer_in_length) -{ - if (buffer_in_length < 3) { - return; - } - size_t size = U2BE(buffer_in, 1); - if (buffer_in_length < 3 + size) { - return; - } - - if (size >= 1) { - switch (buffer_in[3]) { - case SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED: { - G_io_reader_ctx.event_happened = true; - G_io_reader_ctx.last_event = CARD_DETECTED; - G_io_reader_ctx.card.tech - = (buffer_in[4] == SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED_A) ? NFC_A : NFC_B; - G_io_reader_ctx.card.nfcid_len = MIN(size - 2, sizeof(G_io_reader_ctx.card.nfcid)); - memcpy((void *) G_io_reader_ctx.card.nfcid, - G_io_seproxyhal_spi_buffer + 5, - G_io_reader_ctx.card.nfcid_len); - } break; - - case SEPROXYHAL_TAG_NFC_EVENT_CARD_LOST: - if (G_io_reader_ctx.evt_callback != NULL) { - G_io_reader_ctx.event_happened = true; - G_io_reader_ctx.last_event = CARD_REMOVED; - } - break; - } - } -} - -void os_io_nfc_reader_rx(uint8_t *in_buffer, size_t in_buffer_len) -{ - if (in_buffer_len <= G_io_reader_ctx.apdu_rx_max_size) { - memcpy(G_io_reader_ctx.apdu_rx, in_buffer, in_buffer_len); - G_io_reader_ctx.response_received = true; - G_io_reader_ctx.apdu_rx_len = in_buffer_len; - io_nfc_process_events(); - } -} - -void io_nfc_process_events(void) -{ - if (G_io_reader_ctx.response_received) { - G_io_reader_ctx.response_received = false; - if (G_io_reader_ctx.resp_callback != NULL) { - nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback; - G_io_reader_ctx.resp_callback = NULL; - resp_cb(false, false, G_io_reader_ctx.apdu_rx, G_io_reader_ctx.apdu_rx_len); - } - } - - if (G_io_reader_ctx.resp_callback != NULL && G_io_reader_ctx.remaining_ms == 0) { - nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback; - G_io_reader_ctx.resp_callback = NULL; - resp_cb(false, true, NULL, 0); - } - - if (G_io_reader_ctx.event_happened) { - G_io_reader_ctx.event_happened = 0; - - // If card is removed during an APDU processing, call the resp_callback with an error - if (G_io_reader_ctx.resp_callback != NULL && G_io_reader_ctx.last_event == CARD_REMOVED) { - nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback; - G_io_reader_ctx.resp_callback = NULL; - resp_cb(true, false, NULL, 0); - } - - if (G_io_reader_ctx.evt_callback != NULL) { - G_io_reader_ctx.evt_callback(G_io_reader_ctx.last_event, - (struct card_info *) &G_io_reader_ctx.card); - } - if (G_io_reader_ctx.last_event == CARD_REMOVED) { - memset((void *) &G_io_reader_ctx.card, 0, sizeof(G_io_reader_ctx.card)); - } - } -} - -void io_nfc_ticker(void) -{ - if (G_io_reader_ctx.resp_callback != NULL) { - if (G_io_reader_ctx.remaining_ms <= 100) { - G_io_reader_ctx.remaining_ms = 0; - } - else { - G_io_reader_ctx.remaining_ms -= 100; - } - } -} - -void os_io_nfc_evt(uint8_t *buffer_in, size_t buffer_in_length) -{ - switch (buffer_in[0]) { - case SEPROXYHAL_TAG_NFC_EVENT: - io_nfc_event(buffer_in, buffer_in_length); - io_nfc_process_events(); - break; - - case SEPROXYHAL_TAG_TICKER_EVENT: - io_nfc_ticker(); - io_nfc_process_events(); - break; - - default: - break; - } -} - -bool io_nfc_reader_send(const uint8_t *cmd_data, - size_t cmd_len, - nfc_resp_callback_t callback, - int timeout_ms) -{ - G_io_reader_ctx.resp_callback = PIC(callback); - os_io_tx_cmd(APDU_TYPE_NFC, PIC(cmd_data), cmd_len, 0); - - G_io_reader_ctx.response_received = false; - G_io_reader_ctx.remaining_ms = timeout_ms; - - return true; -} - -bool io_nfc_reader_start(nfc_evt_callback_t callback) -{ - G_io_reader_ctx.evt_callback = PIC(callback); - G_io_reader_ctx.reader_mode = true; - G_io_reader_ctx.event_happened = false; - G_io_reader_ctx.resp_callback = NULL; - G_io_reader_ctx.response_received = false; - os_io_nfc_cmd_start_reader(); - return true; -} - -void io_nfc_reader_stop(void) -{ - G_io_reader_ctx.evt_callback = NULL; - G_io_reader_ctx.reader_mode = false; - G_io_reader_ctx.event_happened = false; - G_io_reader_ctx.resp_callback = NULL; - G_io_reader_ctx.response_received = false; - os_io_nfc_cmd_stop(); -} - -bool io_nfc_is_reader(void) -{ - return G_io_reader_ctx.reader_mode; -} -#endif // HAVE_NFC_READER