diff --git a/include/seproxyhal_protocol.h b/include/seproxyhal_protocol.h index efb52c6ff..391e00299 100644 --- a/include/seproxyhal_protocol.h +++ b/include/seproxyhal_protocol.h @@ -124,6 +124,9 @@ enum seph_protocol_evt_usb_mask { SEPROXYHAL_TAG_USB_EP_XFER_OUT = 0x04, }; +// EVT : USB IAP2 DATA +#define SEPROXYHAL_TAG_USB_IAP_EVENT (0x11) + // EVT : MCU CHUNK READ RSP #define SEPROXYHAL_TAG_UNSEC_CHUNK_EVENT (0x12) @@ -265,6 +268,9 @@ enum seph_protocol_cmd_usb_prepare_type { SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_UNSTALL = 0x80, }; +// CMD : USB SEND IAP2 DATA +#define SEPROXYHAL_TAG_USB_IAP_SEND (0x51) + // CMD : REQUEST STATUS #define SEPROXYHAL_TAG_REQUEST_STATUS (0x52) diff --git a/io/include/os_io.h b/io/include/os_io.h index b5e76d9ae..69b0bd5d8 100644 --- a/io/include/os_io.h +++ b/io/include/os_io.h @@ -46,6 +46,7 @@ typedef enum { OS_IO_PACKET_TYPE_USB_U2F_HID_CANCEL = 0x25, OS_IO_PACKET_TYPE_USB_U2F_HID_RAW = 0x26, OS_IO_PACKET_TYPE_USB_CDC_RAW = 0x29, + OS_IO_PACKET_TYPE_USB_IAP_APDU = 0x2A, OS_IO_PACKET_TYPE_BLE_MASK = 0x30, OS_IO_PACKET_TYPE_BLE_APDU = 0x30, @@ -69,6 +70,7 @@ typedef enum { APDU_TYPE_USB_U2F_CANCEL = OS_IO_PACKET_TYPE_USB_U2F_HID_CANCEL, APDU_TYPE_BLE = OS_IO_PACKET_TYPE_BLE_APDU, APDU_TYPE_NFC = OS_IO_PACKET_TYPE_NFC_APDU, + APDU_TYPE_IAP = OS_IO_PACKET_TYPE_USB_IAP_APDU, } apdu_type_t; typedef enum { diff --git a/io/src/os_io.c b/io/src/os_io.c index 4413bde8a..864998aa2 100644 --- a/io/src/os_io.c +++ b/io/src/os_io.c @@ -13,6 +13,9 @@ #ifndef HAVE_CDCUSB #include "usbd_ledger_hid_u2f.h" #endif // HAVE_CDCUSB +#ifdef HAVE_IAPUSB +#include "usb_iap.h" +#endif // HAVE_IAPUSB #endif // HAVE_IO_USB #ifdef HAVE_BLE @@ -177,6 +180,9 @@ int os_io_init(os_io_init_t *init) #ifdef HAVE_IO_USB USBD_LEDGER_init(&init->usb, force_restart); +#ifdef HAVE_IAPUSB + USB_LEDGER_IAP_init(); +#endif // HAVE_IAPUSB #endif // HAVE_IO_USB #ifdef HAVE_BLE @@ -282,6 +288,13 @@ int os_io_rx_evt(unsigned char *buffer, case SEPROXYHAL_TAG_USB_EP_XFER_EVENT: status = USBD_LEDGER_rx_seph_evt(G_io_seph_buffer, length, buffer, buffer_max_length); break; + +#ifdef HAVE_IAPUSB + case SEPROXYHAL_TAG_USB_IAP_EVENT: + status + = USB_LEDGER_iap_rx_seph_evt(G_io_seph_buffer, length, buffer, buffer_max_length); + break; +#endif // HAVE_IAPUSB #endif // HAVE_IO_USB #ifdef HAVE_BLE @@ -354,6 +367,12 @@ int os_io_tx_cmd(uint8_t type, // TODO_IO test error code USBD_LEDGER_send(USBD_LEDGER_CLASS_HID, type, buffer, length, 0); break; + +#ifdef HAVE_IAPUSB + case OS_IO_PACKET_TYPE_USB_IAP_APDU: + USB_LEDGER_IAP_send_apdu(buffer, length); + break; +#endif // HAVE_IAPUSB #ifdef HAVE_WEBUSB case OS_IO_PACKET_TYPE_USB_WEBUSB_APDU: USBD_LEDGER_send(USBD_LEDGER_CLASS_WEBUSB, type, buffer, length, 0); @@ -473,6 +492,7 @@ unsigned int os_io_handle_ux_event_reject_apdu(void) case OS_IO_PACKET_TYPE_USB_CCID_APDU: case OS_IO_PACKET_TYPE_BLE_APDU: case OS_IO_PACKET_TYPE_NFC_APDU: + case OS_IO_PACKET_TYPE_USB_IAP_APDU: os_io_tx_cmd(G_io_tx_buffer[0], err_buffer, sizeof(err_buffer), 0); break; diff --git a/io_legacy/include/os_io_legacy_types.h b/io_legacy/include/os_io_legacy_types.h index 87a339735..b1ad55c59 100644 --- a/io_legacy/include/os_io_legacy_types.h +++ b/io_legacy/include/os_io_legacy_types.h @@ -34,6 +34,7 @@ typedef enum { IO_APDU_MEDIA_RAW, IO_APDU_MEDIA_U2F, IO_APDU_MEDIA_CDC, + IO_APDU_MEDIA_IAP, } io_apdu_media_t; typedef enum { diff --git a/io_legacy/src/os_io_legacy.c b/io_legacy/src/os_io_legacy.c index 9acb45748..7069e1409 100644 --- a/io_legacy/src/os_io_legacy.c +++ b/io_legacy/src/os_io_legacy.c @@ -105,6 +105,9 @@ static io_apdu_media_t get_media_from_apdu_type(apdu_type_t apdu_type) if (apdu_type == APDU_TYPE_NFC) { return IO_APDU_MEDIA_NFC; } + if (apdu_type == APDU_TYPE_IAP) { + return IO_APDU_MEDIA_IAP; + } return IO_APDU_MEDIA_NONE; } @@ -153,6 +156,7 @@ void io_seproxyhal_io_heartbeat(void) case OS_IO_PACKET_TYPE_USB_U2F_HID_APDU: case OS_IO_PACKET_TYPE_BLE_APDU: case OS_IO_PACKET_TYPE_NFC_APDU: + case OS_IO_PACKET_TYPE_USB_IAP_APDU: os_io_tx_cmd(G_io_rx_buffer[0], err_buffer, sizeof(err_buffer), 0); break; @@ -392,6 +396,7 @@ int io_legacy_apdu_rx(uint8_t handle_ux_events) case OS_IO_PACKET_TYPE_USB_U2F_HID_RAW: case OS_IO_PACKET_TYPE_BLE_APDU: case OS_IO_PACKET_TYPE_NFC_APDU: + case OS_IO_PACKET_TYPE_USB_IAP_APDU: io_os_legacy_apdu_type = G_io_rx_buffer[0]; if (os_perso_is_pin_set() == BOLOS_TRUE && os_global_pin_is_validated() != BOLOS_TRUE) { diff --git a/lib_stusb/include/usb_iap.h b/lib_stusb/include/usb_iap.h new file mode 100644 index 000000000..278c14958 --- /dev/null +++ b/lib_stusb/include/usb_iap.h @@ -0,0 +1,46 @@ +/***************************************************************************** + * (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. + *****************************************************************************/ + +#ifndef USB_LEDGER_IAP_H +#define USB_LEDGER_IAP_H + +/* Includes ------------------------------------------------------------------*/ +#include +#include "usbd_def.h" +#include "usbd_ledger_types.h" + +/* Exported enumerations -----------------------------------------------------*/ + +/* Exported defines --------------------------------------------------------*/ + +/* Exported types, structures, unions ----------------------------------------*/ + +/* Exported macros------------------------------------------------------------*/ + +/* Exported variables --------------------------------------------------------*/ + +/* Exported functions --------------------------------------------------------*/ + +void USB_LEDGER_IAP_init(void); + +int USB_LEDGER_iap_rx_seph_evt(uint8_t *seph_buffer, + uint16_t seph_buffer_length, + uint8_t *apdu_buffer, + uint16_t apdu_buffer_max_length); + +int USB_LEDGER_IAP_send_apdu(const uint8_t *apdu_buf, uint16_t apdu_buf_length); + +#endif // USBD_LEDGER_WEBUSB_H diff --git a/lib_stusb/src/usb_iap.c b/lib_stusb/src/usb_iap.c new file mode 100644 index 000000000..7753174e0 --- /dev/null +++ b/lib_stusb/src/usb_iap.c @@ -0,0 +1,145 @@ +/***************************************************************************** + * (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. + *****************************************************************************/ + +/* Includes ------------------------------------------------------------------*/ +#include "ledger_protocol.h" +#include "usbd_ledger.h" +#include "usb_iap.h" +#include "seproxyhal_protocol.h" + +/* Private enumerations ------------------------------------------------------*/ + +/* Private defines------------------------------------------------------------*/ + +/* Private types, structures, unions -----------------------------------------*/ + +/* Private macros-------------------------------------------------------------*/ + +/* Private functions prototypes ----------------------------------------------*/ + +/* Private variables ---------------------------------------------------------*/ +static ledger_protocol_t protocol_data = {}; + +/* Exported variables --------------------------------------------------------*/ + +/* Private functions ---------------------------------------------------------*/ +static void USB_LEDGER_IAP_send_packet(uint8_t *buffer, uint16_t length) +{ + if (length) { + unsigned char hdr[3]; + hdr[0] = SEPROXYHAL_TAG_USB_IAP_SEND; + hdr[1] = length >> 8; + hdr[2] = length; + os_io_tx_cmd(OS_IO_PACKET_TYPE_SEPH, hdr, 3, NULL); + os_io_tx_cmd(OS_IO_PACKET_TYPE_SEPH, buffer, length, NULL); + } +} + +/* Exported functions --------------------------------------------------------*/ + +void USB_LEDGER_IAP_init(void) +{ + memset(&protocol_data, 0, sizeof(protocol_data)); + protocol_data.mtu = sizeof(USBD_LEDGER_protocol_chunk_buffer); + + LEDGER_PROTOCOL_init(&protocol_data, OS_IO_PACKET_TYPE_USB_IAP_APDU); +} + +int USB_LEDGER_IAP_send_apdu(const uint8_t *apdu_buf, uint16_t apdu_buf_length) +{ + uint32_t status = -1; + + ledger_protocol_result_t result = LEDGER_PROTOCOL_tx(&protocol_data, + apdu_buf, + apdu_buf_length, + USBD_LEDGER_protocol_chunk_buffer, + sizeof(USBD_LEDGER_protocol_chunk_buffer), + 0); + + if (result != LP_SUCCESS) { + goto error; + } + if (protocol_data.tx_chunk_length >= 2) { + USB_LEDGER_IAP_send_packet(USBD_LEDGER_protocol_chunk_buffer, + protocol_data.tx_chunk_length); + } + + while (protocol_data.tx_apdu_buffer) { + result = LEDGER_PROTOCOL_tx(&protocol_data, + NULL, + 0, + USBD_LEDGER_protocol_chunk_buffer, + sizeof(USBD_LEDGER_protocol_chunk_buffer), + 0); + if (result != LP_SUCCESS) { + goto error; + } + if (protocol_data.tx_chunk_length >= 2) { + USB_LEDGER_IAP_send_packet(USBD_LEDGER_protocol_chunk_buffer, + protocol_data.tx_chunk_length); + } + } + status = 0; + +error: + return status; +} + +int USB_LEDGER_iap_rx_seph_evt(uint8_t *seph_buffer, + uint16_t seph_buffer_length, + uint8_t *apdu_buffer, + uint16_t apdu_buffer_max_length) +{ + int status = -1; + + if (seph_buffer[1] != SEPROXYHAL_TAG_USB_IAP_EVENT || seph_buffer_length < 4) { + goto error; + } + + ledger_protocol_result_t result = LEDGER_PROTOCOL_rx(&protocol_data, + &seph_buffer[4], + seph_buffer_length - 4, + USBD_LEDGER_protocol_chunk_buffer, + sizeof(USBD_LEDGER_protocol_chunk_buffer), + apdu_buffer, + apdu_buffer_max_length, + 0); + if (result != LP_SUCCESS) { + goto error; + } + + if (protocol_data.tx_chunk_length > 0) { + // Tx chunck was generated while processing rx + // For example MTU request -> MTU response + USB_LEDGER_IAP_send_packet(USBD_LEDGER_protocol_chunk_buffer, + protocol_data.tx_chunk_length); + protocol_data.tx_chunk_length = 0; + } + + if (protocol_data.rx_apdu_status == APDU_STATUS_COMPLETE) { + // Should not happen as it is verified by LEDGER_PROTOCOL_rx() already + if (apdu_buffer_max_length < protocol_data.rx_apdu_length) { + status = -1; + } + else { + status = protocol_data.rx_apdu_length; + } + protocol_data.rx_apdu_status = APDU_STATUS_WAITING; + } + +error: + return status; +}