Skip to content

Commit

Permalink
Use ledger protocol to split NFC APDUs
Browse files Browse the repository at this point in the history
  • Loading branch information
yrichard-ledger committed May 17, 2024
1 parent 90da458 commit 91665ee
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 38 deletions.
26 changes: 26 additions & 0 deletions include/os_io_nfc.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion include/os_io_seproxyhal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 4 additions & 2 deletions lib_blewbxx_impl/src/ledger_ble.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 7 additions & 11 deletions src/ledger_protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ 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);
ctx->rx_apdu_length = 0;
ctx->rx_apdu_status = APDU_STATUS_WAITING;
return;
}
ctx->rx_apdu_offset = 0;
buffer = &buffer[4];
buffer = &buffer[4];
length -= 4;
}
else {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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],
Expand Down
110 changes: 110 additions & 0 deletions src/os_io_nfc.c
Original file line number Diff line number Diff line change
@@ -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 <string.h>

#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
34 changes: 10 additions & 24 deletions src/os_io_seproxyhal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 91665ee

Please sign in to comment.