From 91665ee152007e34a773dee8f02e8476aa89e4e1 Mon Sep 17 00:00:00 2001 From: Yves Richard Date: Wed, 15 May 2024 23:02:43 +0200 Subject: [PATCH] Use ledger protocol to split NFC APDUs --- include/os_io_nfc.h | 26 +++++++ include/os_io_seproxyhal.h | 2 +- lib_blewbxx_impl/src/ledger_ble.c | 6 +- src/ledger_protocol.c | 18 ++--- src/os_io_nfc.c | 110 ++++++++++++++++++++++++++++++ src/os_io_seproxyhal.c | 34 +++------ 6 files changed, 158 insertions(+), 38 deletions(-) create mode 100644 include/os_io_nfc.h create mode 100644 src/os_io_nfc.c diff --git a/include/os_io_nfc.h b/include/os_io_nfc.h new file mode 100644 index 000000000..b8602c25f --- /dev/null +++ b/include/os_io_nfc.h @@ -0,0 +1,26 @@ + +/******************************************************************************* + * Ledger Nano S - Secure firmware + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ + +#ifndef OS_IO_NFC_H +#define OS_IO_NFC_H + +void io_nfc_init(void); +void io_nfc_recv_event(void); +void io_nfc_send_response(const uint8_t *packet, uint16_t packet_length); + +#endif diff --git a/include/os_io_seproxyhal.h b/include/os_io_seproxyhal.h index 23c86f39c..e39528d54 100644 --- a/include/os_io_seproxyhal.h +++ b/include/os_io_seproxyhal.h @@ -136,7 +136,7 @@ void io_set_timeout(unsigned int timeout); #ifdef HAVE_NFC // Needs to be aligned with RFAL_FEATURE_ISO_DEP_IBLOCK_MAX_LEN defined on mcu side in platform.h -#define NFC_APDU_MAX_SIZE 256 +#define NFC_APDU_MAX_SIZE 1024 void io_seproxyhal_nfc_power(bool forceInit); #endif diff --git a/lib_blewbxx_impl/src/ledger_ble.c b/lib_blewbxx_impl/src/ledger_ble.c index 16411b03e..ec3f8719f 100644 --- a/lib_blewbxx_impl/src/ledger_ble.c +++ b/lib_blewbxx_impl/src/ledger_ble.c @@ -882,7 +882,8 @@ static void attribute_modified(const uint8_t *buffer, uint16_t length) copy_apdu_to_app(true); } else if (ledger_ble_data.resp_length) { - LEDGER_PROTOCOL_tx(&ledger_protocol_data, ledger_ble_data.resp, ledger_ble_data.resp_length); + LEDGER_PROTOCOL_tx( + &ledger_protocol_data, ledger_ble_data.resp, ledger_ble_data.resp_length); ledger_ble_data.resp_length = 0; notify_chunk(); } @@ -1058,7 +1059,8 @@ void LEDGER_BLE_send(const uint8_t *packet, uint16_t packet_length) } else { if ((ledger_ble_data.resp_length != 0) && (U2BE(ledger_ble_data.resp, 0) != SWO_SUCCESS)) { - LEDGER_PROTOCOL_tx(&ledger_protocol_data, ledger_ble_data.resp, ledger_ble_data.resp_length); + LEDGER_PROTOCOL_tx( + &ledger_protocol_data, ledger_ble_data.resp, ledger_ble_data.resp_length); } else { LEDGER_PROTOCOL_tx(&ledger_protocol_data, packet, packet_length); diff --git a/src/ledger_protocol.c b/src/ledger_protocol.c index 2af57a375..62c00fe3b 100644 --- a/src/ledger_protocol.c +++ b/src/ledger_protocol.c @@ -72,6 +72,7 @@ static void process_apdu_chunk(ledger_protocol_t *ctx, const uint8_t *buffer, ui // First chunk ctx->rx_apdu_status = APDU_STATUS_NEED_MORE_DATA; ctx->rx_apdu_length = (uint16_t) U2BE(buffer, 2); + ctx->rx_apdu_offset = 0; // Check if we have enough space to store the apdu if (ctx->rx_apdu_length > ctx->rx_apdu_buffer_max_length) { LOG_BLE_PROTOCOL("APDU WAITING - %d\n", ctx->rx_apdu_length); @@ -79,8 +80,7 @@ static void process_apdu_chunk(ledger_protocol_t *ctx, const uint8_t *buffer, ui ctx->rx_apdu_status = APDU_STATUS_WAITING; return; } - ctx->rx_apdu_offset = 0; - buffer = &buffer[4]; + buffer = &buffer[4]; length -= 4; } else { @@ -131,11 +131,9 @@ void LEDGER_PROTOCOL_rx(ledger_protocol_t *ctx, const uint8_t *buffer, uint16_t switch (buffer[2]) { case TAG_GET_PROTOCOL_VERSION: LOG_BLE_PROTOCOL("TAG_GET_PROTOCOL_VERSION\n"); - ctx->tx_chunk[2] = TAG_GET_PROTOCOL_VERSION; - ctx->tx_chunk_length - = MIN(sizeof(protocol_version), (sizeof(ctx->tx_chunk) - 3)); - memcpy( - &ctx->tx_chunk[3], protocol_version, ctx->tx_chunk_length); + ctx->tx_chunk[2] = TAG_GET_PROTOCOL_VERSION; + ctx->tx_chunk_length = MIN(sizeof(protocol_version), (sizeof(ctx->tx_chunk) - 3)); + memcpy(&ctx->tx_chunk[3], protocol_version, ctx->tx_chunk_length); ctx->tx_chunk_length += 3; break; @@ -194,16 +192,14 @@ void LEDGER_PROTOCOL_tx(ledger_protocol_t *ctx, const uint8_t *buffer, uint16_t ctx->tx_chunk[tx_chunk_offset++] = TAG_APDU; - U2BE_ENCODE( - ctx->tx_chunk, tx_chunk_offset, ctx->tx_apdu_sequence_number); + U2BE_ENCODE(ctx->tx_chunk, tx_chunk_offset, ctx->tx_apdu_sequence_number); tx_chunk_offset += 2; if (ctx->tx_apdu_sequence_number == 0) { U2BE_ENCODE(ctx->tx_chunk, tx_chunk_offset, ctx->tx_apdu_length); tx_chunk_offset += 2; } - if ((ctx->tx_apdu_length + tx_chunk_offset) - >= (ctx->mtu + ctx->tx_apdu_offset)) { + if ((ctx->tx_apdu_length + tx_chunk_offset) >= (ctx->mtu + ctx->tx_apdu_offset)) { // Remaining buffer length doesn't fit the chunk memcpy(&ctx->tx_chunk[tx_chunk_offset], &ctx->tx_apdu_buffer[ctx->tx_apdu_offset], diff --git a/src/os_io_nfc.c b/src/os_io_nfc.c new file mode 100644 index 000000000..5d9afda9c --- /dev/null +++ b/src/os_io_nfc.c @@ -0,0 +1,110 @@ + +/******************************************************************************* + * Ledger Nano S - Secure firmware + * (c) 2022 Ledger + * + * 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. + ********************************************************************************/ +#include "bolos_target.h" +#include "errors.h" +#include "exceptions.h" +#ifdef HAVE_NFC + +#if defined(DEBUG_OS_STACK_CONSUMPTION) +#include "os_debug.h" +#endif // DEBUG_OS_STACK_CONSUMPTION + +#include "os_io.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]; +static ledger_protocol_t ledger_protocol_data; + +void io_nfc_init(void) +{ + memset(&rx_apdu_buffer, 0, sizeof(rx_apdu_buffer)); + memset(&ledger_protocol_data, 0, sizeof(ledger_protocol_data)); + ledger_protocol_data.rx_apdu_buffer = rx_apdu_buffer; + ledger_protocol_data.rx_apdu_buffer_max_length = sizeof(rx_apdu_buffer); + ledger_protocol_data.mtu + = MIN(sizeof(ledger_protocol_data.tx_chunk), sizeof(G_io_seproxyhal_spi_buffer) - 3); +#ifdef HAVE_LOCAL_APDU_BUFFER + ledger_protocol_data.rx_dst_buffer = NULL; +#else + ledger_protocol_data.rx_dst_buffer = G_io_apdu_buffer; +#endif + LEDGER_PROTOCOL_init(&ledger_protocol_data); +} + +void io_nfc_recv_event(void) +{ + size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1); + + LEDGER_PROTOCOL_rx(&ledger_protocol_data, G_io_seproxyhal_spi_buffer + 3, size); + + // Full apdu is received, copy it to global apdu buffer + if (ledger_protocol_data.rx_apdu_status == APDU_STATUS_COMPLETE) { + memcpy(ledger_protocol_data.rx_dst_buffer, + ledger_protocol_data.rx_apdu_buffer, + ledger_protocol_data.rx_apdu_length); + G_io_app.apdu_length = ledger_protocol_data.rx_apdu_length; + G_io_app.apdu_state = APDU_NFC; + G_io_app.apdu_media = IO_APDU_MEDIA_NFC; + ledger_protocol_data.rx_apdu_length = 0; + ledger_protocol_data.rx_apdu_status = APDU_STATUS_WAITING; + } +} + +void io_nfc_send_response(const uint8_t *packet, uint16_t packet_length) +{ + LEDGER_PROTOCOL_tx(&ledger_protocol_data, packet, packet_length); + if (ledger_protocol_data.tx_chunk_length >= 2) { + // reply the NFC APDU over SEPROXYHAL protocol + G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_NFC_RAPDU; + G_io_seproxyhal_spi_buffer[1] = (ledger_protocol_data.tx_chunk_length) >> 8; + G_io_seproxyhal_spi_buffer[2] = (ledger_protocol_data.tx_chunk_length); + memcpy(G_io_seproxyhal_spi_buffer + 3, + ledger_protocol_data.tx_chunk, + ledger_protocol_data.tx_chunk_length); + io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, + 3 + ledger_protocol_data.tx_chunk_length); + } + + while (ledger_protocol_data.tx_apdu_buffer) { + LEDGER_PROTOCOL_tx(&ledger_protocol_data, NULL, 0); + if (ledger_protocol_data.tx_chunk_length >= 2) { + // reply the NFC APDU over SEPROXYHAL protocol + G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_NFC_RAPDU; + G_io_seproxyhal_spi_buffer[1] = (ledger_protocol_data.tx_chunk_length) >> 8; + G_io_seproxyhal_spi_buffer[2] = (ledger_protocol_data.tx_chunk_length); + memcpy(G_io_seproxyhal_spi_buffer + 3, + ledger_protocol_data.tx_chunk, + ledger_protocol_data.tx_chunk_length); + io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, + 3 + ledger_protocol_data.tx_chunk_length); + } + } +} + +#endif // HAVE_NFC diff --git a/src/os_io_seproxyhal.c b/src/os_io_seproxyhal.c index 34286cca3..44dca27d0 100644 --- a/src/os_io_seproxyhal.c +++ b/src/os_io_seproxyhal.c @@ -87,6 +87,10 @@ extern USBD_HandleTypeDef USBD_Device; #endif #include "os.h" +#ifdef HAVE_NFC +#include "os_io_nfc.h" +#endif + #ifdef HAVE_SERIALIZED_NBGL #include "nbgl_serialize.h" #endif @@ -243,21 +247,6 @@ void io_seproxyhal_handle_capdu_event(void) } } -#ifdef HAVE_NFC -void io_seproxyhal_handle_nfc_recv_event(void) -{ - if (G_io_app.apdu_state == APDU_IDLE) { - size_t max = MIN(sizeof(G_io_apdu_buffer), sizeof(G_io_seproxyhal_spi_buffer) - 3); - size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1); - - G_io_app.apdu_media = IO_APDU_MEDIA_NFC; - G_io_app.apdu_state = APDU_NFC; - G_io_app.apdu_length = MIN(size, max); - - memcpy(G_io_apdu_buffer, &G_io_seproxyhal_spi_buffer[3], G_io_app.apdu_length); - } -} -#endif unsigned int io_seproxyhal_handle_event(void) { #ifdef HAVE_IO_USB @@ -290,7 +279,7 @@ unsigned int io_seproxyhal_handle_event(void) #ifdef HAVE_NFC case SEPROXYHAL_TAG_NFC_APDU_EVENT: - io_seproxyhal_handle_nfc_recv_event(); + io_nfc_recv_event(); return 1; #endif @@ -462,6 +451,10 @@ void io_seproxyhal_init(void) io_usb_hid_init(); #endif // HAVE_USB_APDU +#ifdef HAVE_NFC + io_nfc_init(); +#endif // HAVE_NFC + #ifdef HAVE_BAGL io_seproxyhal_init_ux(); @@ -1358,14 +1351,7 @@ unsigned short io_exchange(unsigned char channel, unsigned short tx_len) || (tx_len > NFC_APDU_MAX_SIZE)) { THROW(INVALID_PARAMETER); } - // reply the NFC APDU over SEPROXYHAL protocol - G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_NFC_RAPDU; - G_io_seproxyhal_spi_buffer[1] = (tx_len) >> 8; - G_io_seproxyhal_spi_buffer[2] = (tx_len); - io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 3); - io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len); - - // isngle packet reply, mark immediate idle + io_nfc_send_response(G_io_apdu_buffer, tx_len); G_io_app.apdu_state = APDU_IDLE; G_io_app.apdu_media = IO_APDU_MEDIA_NONE; goto break_send;