From 597f9d07c02e54be4ff1d7d2d6621a97c97d189a Mon Sep 17 00:00:00 2001 From: Yves Richard Date: Mon, 9 Sep 2024 15:25:39 +0200 Subject: [PATCH] Add support to start NFC in CE and reader mode --- Makefile.standard_app | 6 ++ include/os_io_nfc.h | 66 ++++++++++++++ include/seproxyhal_protocol.h | 14 ++- lib_standard_app/io.c | 12 +++ src/os_io_nfc.c | 160 ++++++++++++++++++++++++++++++++-- src/os_io_seproxyhal.c | 20 ++++- src/os_io_task.c | 7 ++ 7 files changed, 270 insertions(+), 15 deletions(-) diff --git a/Makefile.standard_app b/Makefile.standard_app index 95c02823a..75e54db72 100644 --- a/Makefile.standard_app +++ b/Makefile.standard_app @@ -39,6 +39,12 @@ ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME), TARGET_STAX TARGET_FLEX)) endif endif +ifeq ($(ENABLE_NFC_READER), 1) +ifeq ($(TARGET_NAME),$(filter $(TARGET_NAME), TARGET_STAX TARGET_FLEX)) + DEFINES += HAVE_NFC_READER +endif +endif + ##################################################################### # SWAP # ##################################################################### diff --git a/include/os_io_nfc.h b/include/os_io_nfc.h index b8602c25f..b44453a82 100644 --- a/include/os_io_nfc.h +++ b/include/os_io_nfc.h @@ -19,8 +19,74 @@ #ifndef OS_IO_NFC_H #define OS_IO_NFC_H +#include "arch.h" + +#include "os_io_seproxyhal.h" + +/* Public API for reader application --------------------------------------- */ +#ifdef HAVE_NFC_READER + +enum card_tech { + NFC_A, + NFC_B +}; + +struct card_info { + enum card_tech tech; + uint8_t nfcid[7]; + size_t nfcid_len; +}; + +enum nfc_event { + CARD_DETECTED, + CARD_REMOVED, +}; + +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); + +/* Functions */ + +/* return false in case of error + in that case, callback will not be called */ +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); +bool io_nfc_is_reader(void); + +#endif // HAVE_NFC_READER + +/* SDK internal API --------------------------------------- */ + +#ifdef HAVE_NFC_READER + +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; +}; + +extern struct nfc_reader_context G_io_reader_ctx; +#endif // HAVE_NFC_READER + void io_nfc_init(void); void io_nfc_recv_event(void); void io_nfc_send_response(const uint8_t *packet, uint16_t packet_length); +#ifdef HAVE_NFC_READER +void io_nfc_event(void); +void io_nfc_ticker(void); +void io_nfc_process_events(void); +#endif // HAVE_NFC_READER + #endif diff --git a/include/seproxyhal_protocol.h b/include/seproxyhal_protocol.h index 3b60abc0e..4795b87be 100644 --- a/include/seproxyhal_protocol.h +++ b/include/seproxyhal_protocol.h @@ -112,7 +112,12 @@ #define SEPROXYHAL_TAG_BOOTLOADER_RAPDU_EVENT 0x19 // #define SEPROXYHAL_TAG_UX_EVENT 0x1A // #ifdef HAVE_NFC -#define SEPROXYHAL_TAG_NFC_APDU_EVENT 0x1C +#define SEPROXYHAL_TAG_NFC_APDU_EVENT 0x1C +#define SEPROXYHAL_TAG_NFC_EVENT 0x1E +#define SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED 0x01 // card_detected + type a/b + nfcid[max 7] +#define SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED_A 0x01 +#define SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED_B 0x02 +#define SEPROXYHAL_TAG_NFC_EVENT_CARD_LOST 0x02 // card lost #endif #define SEPH_PROTOCOL_EVT_POWER_BUTTON_EVENT 0x1B @@ -166,8 +171,11 @@ // #define SEPROXYHAL_TAG_SCREEN_DISPLAY 0x4A // wait for display_event after sent #ifdef HAVE_NFC -#define SEPROXYHAL_TAG_NFC_RAPDU 0x4A -#define SEPROXYHAL_TAG_NFC_POWER 0x34 +#define SEPROXYHAL_TAG_NFC_RAPDU 0x4A +#define SEPROXYHAL_TAG_NFC_POWER 0x34 +#define SEPROXYHAL_TAG_NFC_POWER_OFF 0x00 +#define SEPROXYHAL_TAG_NFC_POWER_ON_CE 0x01 +#define SEPROXYHAL_TAG_NFC_POWER_ON_READER 0x02 #endif #define SEPROXYHAL_TAG_DEVICE_OFF 0x4B diff --git a/lib_standard_app/io.c b/lib_standard_app/io.c index cf878725f..9aea6ebb8 100644 --- a/lib_standard_app/io.c +++ b/lib_standard_app/io.c @@ -25,6 +25,10 @@ #include "swap.h" #endif +#ifdef HAVE_NFC_READER +#include "os_io_nfc.h" +#endif // HAVE_NFC_READER + // TODO: Temporary workaround, at some point all status words should be defined by the SDK and // removed from the application #define SW_OK 0x9000 @@ -32,6 +36,10 @@ uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; +#ifdef HAVE_NFC_READER +struct nfc_reader_context G_io_reader_ctx; +#endif + /** * Variable containing the length of the APDU response to send back. */ @@ -83,6 +91,10 @@ WEAK uint8_t io_event(uint8_t channel) case SEPROXYHAL_TAG_TICKER_EVENT: app_ticker_event_callback(); UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer, {}); +#ifdef HAVE_NFC_READER + io_nfc_ticker(); + io_nfc_process_events(); +#endif // HAVE_NFC_READER break; default: UX_DEFAULT_EVENT(); diff --git a/src/os_io_nfc.c b/src/os_io_nfc.c index 3413a22f5..daee467aa 100644 --- a/src/os_io_nfc.c +++ b/src/os_io_nfc.c @@ -15,7 +15,11 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ -#include "bolos_target.h" + +#include "os.h" +#include "os_settings.h" +#include "os_io_seproxyhal.h" + #include "errors.h" #include "exceptions.h" #ifdef HAVE_NFC @@ -25,17 +29,11 @@ #endif // DEBUG_OS_STACK_CONSUMPTION #include "os_io.h" +#include "os_io_nfc.h" #include "os_utils.h" #include "os_io_seproxyhal.h" #include -#ifdef DEBUG -#define LOG printf -#else -#define LOG(...) -#endif - -#include "os.h" #include "ledger_protocol.h" static uint8_t rx_apdu_buffer[IO_APDU_BUFFER_SIZE]; @@ -55,6 +53,9 @@ void io_nfc_init(void) ledger_protocol_data.rx_dst_buffer = G_io_apdu_buffer; #endif LEDGER_PROTOCOL_init(&ledger_protocol_data); +#ifdef HAVE_NFC_READER + memset((void *) &G_io_reader_ctx, 0, sizeof(G_io_reader_ctx)); +#endif // HAVE_NFC_READER } void io_nfc_recv_event(void) @@ -65,6 +66,13 @@ void io_nfc_recv_event(void) // Full apdu is received, copy it to global apdu buffer if (ledger_protocol_data.rx_apdu_status == APDU_STATUS_COMPLETE) { +#ifdef HAVE_NFC_READER + if (G_io_reader_ctx.reader_mode) { + G_io_reader_ctx.response_received = true; + return; + } +#endif // HAVE_NFC_READER + memcpy(ledger_protocol_data.rx_dst_buffer, ledger_protocol_data.rx_apdu_buffer, ledger_protocol_data.rx_apdu_length); @@ -106,4 +114,140 @@ void io_nfc_send_response(const uint8_t *packet, uint16_t packet_length) } } +#ifdef HAVE_NFC_READER + +void io_nfc_event(void) +{ + size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1); + + if (size >= 1) { + switch (G_io_seproxyhal_spi_buffer[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 + = (G_io_seproxyhal_spi_buffer[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 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, + ledger_protocol_data.rx_apdu_buffer, + ledger_protocol_data.rx_apdu_length); + } + memset(ledger_protocol_data.rx_apdu_buffer, 0, ledger_protocol_data.rx_apdu_length); + } + + 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; + } + } +} + +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); + io_nfc_send_response(PIC(cmd_data), cmd_len); + + G_io_reader_ctx.response_received = false; + G_io_reader_ctx.remaining_ms = timeout_ms; + + return true; +} + +void io_nfc_reader_power(void) +{ + uint8_t buffer[4]; + buffer[0] = SEPROXYHAL_TAG_NFC_POWER; + buffer[1] = 0; + buffer[2] = 1; + buffer[3] = SEPROXYHAL_TAG_NFC_POWER_ON_READER; + io_seproxyhal_spi_send(buffer, 4); +} + +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; + io_nfc_reader_power(); + return true; +} + +void io_nfc_reader_stop() +{ + 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; + io_seproxyhal_nfc_power(false); +} + +bool io_nfc_is_reader(void) +{ + return G_io_reader_ctx.reader_mode; +} + +#endif // HAVE_NFC_READER + #endif // HAVE_NFC diff --git a/src/os_io_seproxyhal.c b/src/os_io_seproxyhal.c index 155681a03..4feefebc1 100644 --- a/src/os_io_seproxyhal.c +++ b/src/os_io_seproxyhal.c @@ -273,8 +273,19 @@ unsigned int io_seproxyhal_handle_event(void) #ifdef HAVE_NFC case SEPROXYHAL_TAG_NFC_APDU_EVENT: io_nfc_recv_event(); +#if defined(HAVE_NFC_READER) && !defined(HAVE_BOLOS) + io_nfc_process_events(); +#endif // HAVE_NFC_READER && !HAVE_BOLOS return 1; -#endif +#ifdef HAVE_NFC_READER + case SEPROXYHAL_TAG_NFC_EVENT: + io_nfc_event(); +#ifndef HAVE_BOLOS + io_nfc_process_events(); +#endif // !HAVE_BOLOS + return 1; +#endif // HAVE_NFC_READER +#endif // HAVE_NFC case SEPROXYHAL_TAG_UX_EVENT: switch (G_io_seproxyhal_spi_buffer[3]) { @@ -502,9 +513,10 @@ void io_seproxyhal_nfc_power(bool forceInit) { uint8_t buffer[4]; uint8_t power - = forceInit - ? 1 - : (os_setting_get(OS_SETTING_FEATURES, NULL, 0) & OS_SETTING_FEATURES_NFC_ENABLED); + = (forceInit + || (os_setting_get(OS_SETTING_FEATURES, NULL, 0) & OS_SETTING_FEATURES_NFC_ENABLED)) + ? SEPROXYHAL_TAG_NFC_POWER_ON_CE + : SEPROXYHAL_TAG_NFC_POWER_OFF; buffer[0] = SEPROXYHAL_TAG_NFC_POWER; buffer[1] = 0; buffer[2] = 1; diff --git a/src/os_io_task.c b/src/os_io_task.c index 674d1c25f..8cb4538b5 100644 --- a/src/os_io_task.c +++ b/src/os_io_task.c @@ -4,6 +4,7 @@ #include "os_io_seproxyhal.h" #include "os_task.h" #include "os_types.h" +#include "os_io_nfc.h" #include @@ -27,6 +28,12 @@ bolos_ux_asynch_callback_t G_io_asynch_ux_callback; // !defined(DEBUG_VARIABLE_SPI_SIZE)) #endif // !HAVE_BLE +#ifdef HAVE_NFC_READER +// For some reason the linker only works correctly +// if the struct declaration is in this file +struct nfc_reader_context G_io_reader_ctx; +#endif + // Buffer dedicated to the MCU <-> SE data transfer. unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]; io_seph_app_t G_io_app;