From 063cf2bec338729e98dec301b109d54803995587 Mon Sep 17 00:00:00 2001 From: Stephane Portron Date: Mon, 23 Jun 2025 09:26:16 +0200 Subject: [PATCH 01/20] IO revamp adaptation --- ledger_device_sdk/src/ble.rs | 14 - ledger_device_sdk/src/io.rs | 365 ++++++++++++------------ ledger_device_sdk/src/nbgl.rs | 34 --- ledger_device_sdk/src/seph.rs | 218 ++++---------- ledger_device_sdk/src/ui/gadgets.rs | 16 +- ledger_device_sdk/src/ui/screen_util.rs | 2 +- ledger_device_sdk/src/uxapp.rs | 24 +- ledger_secure_sdk_sys/build.rs | 89 +++--- ledger_secure_sdk_sys/csdk_flex.h | 8 +- ledger_secure_sdk_sys/csdk_nanos2.h | 9 +- ledger_secure_sdk_sys/csdk_nanox.h | 9 +- ledger_secure_sdk_sys/csdk_stax.h | 8 +- ledger_secure_sdk_sys/src/c/src.c | 88 +++--- ledger_secure_sdk_sys/src/seph.rs | 63 +--- 14 files changed, 369 insertions(+), 578 deletions(-) diff --git a/ledger_device_sdk/src/ble.rs b/ledger_device_sdk/src/ble.rs index 9a83a373..e69de29b 100644 --- a/ledger_device_sdk/src/ble.rs +++ b/ledger_device_sdk/src/ble.rs @@ -1,14 +0,0 @@ -use ledger_secure_sdk_sys::{LEDGER_BLE_receive, LEDGER_BLE_send, LEDGER_BLE_set_recv_buffer}; - -pub fn receive(apdu_buffer: &mut [u8], spi_buffer: &[u8]) { - unsafe { - LEDGER_BLE_set_recv_buffer(apdu_buffer.as_mut_ptr(), apdu_buffer.len() as u16); - LEDGER_BLE_receive(spi_buffer.as_ptr()); - } -} - -pub fn send(buffer: &[u8]) { - unsafe { - LEDGER_BLE_send(buffer.as_ptr(), buffer.len() as u16); - } -} diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index 8e28524c..426227f3 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -1,14 +1,23 @@ -#[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] -use crate::ble; + #[cfg(not(any(target_os = "stax", target_os = "flex")))] use ledger_secure_sdk_sys::buttons::{get_button_event, ButtonEvent, ButtonsState}; use ledger_secure_sdk_sys::seph as sys_seph; use ledger_secure_sdk_sys::*; use crate::seph; + +#[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] +use crate::seph::ItcUxEvent; + use core::convert::{Infallible, TryFrom}; use core::ops::{Index, IndexMut}; +#[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] +unsafe extern "C" { + pub unsafe static mut G_ux_params: bolos_ux_params_t; +} + + #[derive(Copy, Clone)] #[repr(u16)] pub enum StatusWords { @@ -94,15 +103,12 @@ pub enum Event { #[cfg(any(target_os = "stax", target_os = "flex"))] TouchEvent, /// Ticker - Ticker, + Ticker } /// Manages the communication of the device: receives events such as button presses, incoming /// APDU requests, and provides methods to build and transmit APDU responses. pub struct Comm { - pub apdu_buffer: [u8; 260], - pub rx: usize, - pub tx: usize, pub event_pending: bool, #[cfg(not(any(target_os = "stax", target_os = "flex")))] buttons: ButtonsState, @@ -111,6 +117,14 @@ pub struct Comm { /// with wrong CLA byte is received. If set to [`None`], all CLA are accepted. /// Can be set using [`Comm::set_expected_cla`] method. pub expected_cla: Option, + + pub apdu_type: u8, + pub io_buffer: [u8; 273], + pub rx_length: usize, + pub tx_length: usize, + + // Legacy + pub rx: usize, } impl Default for Comm { @@ -136,13 +150,15 @@ impl Comm { /// Creates a new [`Comm`] instance, which accepts any CLA APDU by default. pub const fn new() -> Self { Self { - apdu_buffer: [0u8; 260], - rx: 0, - tx: 0, event_pending: false, #[cfg(not(any(target_os = "stax", target_os = "flex")))] buttons: ButtonsState::new(), expected_cla: None, + apdu_type: seph::PacketTypes::PacketTypeNone as u8, + io_buffer: [0u8; 273], + rx_length: 0, + tx_length: 0, + rx: 0, } } @@ -168,49 +184,10 @@ impl Comm { /// Send the currently held APDU // This is private. Users should call reply to set the satus word and // transmit the response. - fn apdu_send(&mut self, is_swap: bool) { - if !sys_seph::is_status_sent() { - sys_seph::send_general_status() - } - let mut spi_buffer = [0u8; 256]; - while sys_seph::is_status_sent() { - sys_seph::seph_recv(&mut spi_buffer, 0); - seph::handle_event(&mut self.apdu_buffer, &spi_buffer); - } - - match unsafe { G_io_app.apdu_state } { - APDU_USB_HID => unsafe { - ledger_secure_sdk_sys::io_usb_hid_send( - Some(io_usb_send_apdu_data), - self.tx as u16, - self.apdu_buffer.as_mut_ptr(), - ); - }, - APDU_RAW => { - let len = (self.tx as u16).to_be_bytes(); - sys_seph::seph_send(&[sys_seph::SephTags::RawAPDU as u8, len[0], len[1]]); - sys_seph::seph_send(&self.apdu_buffer[..self.tx]); - } - #[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] - APDU_BLE => { - ble::send(&self.apdu_buffer[..self.tx]); - } - _ => (), - } - if is_swap { - if !sys_seph::is_status_sent() { - sys_seph::send_general_status() - } - sys_seph::seph_recv(&mut spi_buffer, 0); - seph::handle_event(&mut self.apdu_buffer, &spi_buffer); - } - self.tx = 0; - self.rx = 0; - unsafe { - G_io_app.apdu_state = APDU_IDLE; - G_io_app.apdu_media = IO_APDU_MEDIA_NONE; - G_io_app.apdu_length = 0; - } + fn apdu_send(&mut self, _is_swap: bool) { + sys_seph::io_tx(self.apdu_type, &self.io_buffer, self.tx_length); + self.tx_length = 0; + self.rx_length = 0; } /// Wait and return next button press event or APDU command. @@ -254,26 +231,14 @@ impl Comm { T: TryFrom, Reply: From<>::Error>, { - let mut spi_buffer = [0u8; 256]; - - unsafe { - G_io_app.apdu_state = APDU_IDLE; - G_io_app.apdu_media = IO_APDU_MEDIA_NONE; - G_io_app.apdu_length = 0; - } - + self.rx_length = 0; loop { - // Signal end of command stream from SE to MCU - // And prepare reception - if !sys_seph::is_status_sent() { - sys_seph::send_general_status(); - } + let status = sys_seph::io_rx(&mut self.io_buffer, true); - // Fetch the next message from the MCU - let _rx = sys_seph::seph_recv(&mut spi_buffer, 0); - - if let Some(value) = self.decode_event(&mut spi_buffer) { - return value; + if status > 0 { + if let Some(value) = self.decode_event(status) { + return value; + } } } } @@ -283,16 +248,12 @@ impl Comm { T: TryFrom, Reply: From<>::Error>, { - let mut spi_buffer = [0u8; 256]; + let status = sys_seph::io_rx(&mut self.io_buffer, true); - // Signal end of command stream from SE to MCU - // And prepare reception - if !sys_seph::is_status_sent() { - sys_seph::send_general_status(); + if status > 0 { + return self.detect_apdu::(status); } - // Fetch the next message from the MCU - let _rx = sys_seph::seph_recv(&mut spi_buffer, 0); - return self.detect_apdu::(&mut spi_buffer); + return false } pub fn check_event(&mut self) -> Option> @@ -301,9 +262,12 @@ impl Comm { Reply: From<>::Error>, { if self.event_pending { + //let mut apdu_buffer = [0u8; 272]; + //apdu_buffer[0..272].copy_from_slice(&self.io_buffer[1..273]); self.event_pending = false; + // Reject incomplete APDUs - if self.rx < 4 { + if self.rx_length < 6 { self.reply(StatusWords::BadLen); return None; } @@ -315,17 +279,17 @@ impl Comm { } // Manage BOLOS specific APDUs B0xx0000 - if self.apdu_buffer[0] == 0xB0 - && self.apdu_buffer[2] == 0x00 - && self.apdu_buffer[3] == 0x00 + if self.io_buffer[1] == 0xB0 + && self.io_buffer[3] == 0x00 + && self.io_buffer[4] == 0x00 { - handle_bolos_apdu(self, self.apdu_buffer[1]); + handle_bolos_apdu(self, self.io_buffer[2]); return None; } // If CLA filtering is enabled, automatically reject APDUs with wrong CLA if let Some(cla) = self.expected_cla { - if self.apdu_buffer[0] != cla { + if self.io_buffer[1] != cla { self.reply(StatusWords::BadCla); return None; } @@ -347,69 +311,94 @@ impl Comm { None } - pub fn process_event(&mut self, spi_buffer: &mut [u8; 256]) -> Option> + pub fn process_event(&mut self, mut seph_buffer: [u8; 272], length: i32) -> Option> where T: TryFrom, Reply: From<>::Error>, { - // message = [ tag, len_hi, len_lo, ... ] - let tag = spi_buffer[0]; - let len = u16::from_be_bytes([spi_buffer[1], spi_buffer[2]]); - - // XXX: check whether this is necessary - // if rx < 3 && rx != len+3 { - // unsafe { - // G_io_app.apdu_state = APDU_IDLE; - // G_io_app.apdu_length = 0; - // } - // return None - // } - - // Treat all possible events. - // If this is a button push, return with the associated event - // If this is an APDU, return with the "received command" event - // Any other event (usb, xfer, ticker) is silently handled + let tag = seph_buffer[0]; + let _len: usize = u16::from_be_bytes([seph_buffer[1], seph_buffer[2]]) as usize; + + if (length as usize) < _len+3 { + self.reply(StatusWords::BadLen); + return None + } + match seph::Events::from(tag) { + + // BUTTON PUSH EVENT #[cfg(not(any(target_os = "stax", target_os = "flex")))] - seph::Events::ButtonPush => { + seph::Events::ButtonPushEvent => { #[cfg(feature = "nano_nbgl")] unsafe { - ux_process_button_event(spi_buffer.as_mut_ptr()); + ux_process_button_event(seph_buffer.as_mut_ptr()); } - let button_info = spi_buffer[3] >> 1; + let button_info = seph_buffer[3] >> 1; if let Some(btn_evt) = get_button_event(&mut self.buttons, button_info) { return Some(Event::Button(btn_evt)); } } - seph::Events::USBEvent => { - if len == 1 { - seph::handle_usb_event(spi_buffer[3]); - } - } - seph::Events::USBXFEREvent => { - if len >= 3 { - seph::handle_usb_ep_xfer_event(&mut self.apdu_buffer, spi_buffer); - } - } - seph::Events::CAPDUEvent => seph::handle_capdu_event(&mut self.apdu_buffer, spi_buffer), - #[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] - seph::Events::BleReceive => ble::receive(&mut self.apdu_buffer, spi_buffer), + // SCREEN TOUCH EVENT + #[cfg(any(target_os = "stax", target_os = "flex"))] + seph::Events::ScreenTouchEvent => unsafe { + ux_process_finger_event(seph_buffer.as_mut_ptr()); + return Some(Event::TouchEvent); + } + // TICKER EVENT seph::Events::TickerEvent => { #[cfg(any(target_os = "stax", target_os = "flex", feature = "nano_nbgl"))] unsafe { - ux_process_ticker_event(); + ux_process_ticker_event(); } return Some(Event::Ticker); } - #[cfg(any(target_os = "stax", target_os = "flex"))] - seph::Events::ScreenTouch => unsafe { - ux_process_finger_event(spi_buffer.as_mut_ptr()); - return Some(Event::TouchEvent); - }, + // ITC EVENT + seph::Events::ItcEvent => { + #[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] + match ItcUxEvent::from(seph_buffer[3]) { + + seph::ItcUxEvent::AskBlePairing => { + unsafe { + G_ux_params.ux_id = BOLOS_UX_ASYNCHMODAL_PAIRING_REQUEST; + G_ux_params.len = 20; + G_ux_params.u.pairing_request.type_ = seph_buffer[4]; + G_ux_params.u.pairing_request.pairing_info_len = (_len-2) as u32; + for i in 0..G_ux_params.u.pairing_request.pairing_info_len as usize { + G_ux_params.u.pairing_request.pairing_info[i as usize] = seph_buffer[5+i] as i8; + } + G_ux_params.u.pairing_request.pairing_info[G_ux_params.u.pairing_request.pairing_info_len as usize] = 0; + os_ux(&raw mut G_ux_params as *mut bolos_ux_params_t); + } + } + + seph::ItcUxEvent::BlePairingStatus => { + unsafe { + G_ux_params.ux_id = BOLOS_UX_ASYNCHMODAL_PAIRING_STATUS; + G_ux_params.len = 0; + G_ux_params.u.pairing_status.pairing_ok = seph_buffer[4]; + os_ux(&raw mut G_ux_params as *mut bolos_ux_params_t); + } + } + + seph::ItcUxEvent::Redisplay => { + unsafe { + nbgl_objAllowDrawing(true); + nbgl_screenRedraw(); + nbgl_refresh(); + } + } + + _ => { + return None + } + } + return None + } + // DEFAULT EVENT _ => { #[cfg(any(target_os = "stax", target_os = "flex", feature = "nano_nbgl"))] unsafe { @@ -424,39 +413,56 @@ impl Comm { None } - pub fn decode_event(&mut self, spi_buffer: &mut [u8; 256]) -> Option> + pub fn decode_event(&mut self, length:i32) -> Option> where T: TryFrom, Reply: From<>::Error>, { - if let Some(event) = self.process_event(spi_buffer) { - return Some(event); - } + let packet_type = self.io_buffer[0]; + + match seph::PacketTypes::from(packet_type) { + seph::PacketTypes::PacketTypeSeph | seph::PacketTypes::PacketTypeSeEvent => { + // SE or SEPH event + let mut seph_buffer = [0u8; 272]; + seph_buffer[0..272].copy_from_slice(&self.io_buffer[1..273]); + if let Some(event) = self.process_event(seph_buffer, length-1) { + return Some(event); + } + } - if unsafe { G_io_app.apdu_state } != APDU_IDLE && unsafe { G_io_app.apdu_length } > 0 { - unsafe { - if os_perso_is_pin_set() == BOLOS_TRUE.try_into().unwrap() - && os_global_pin_is_validated() != BOLOS_TRUE.try_into().unwrap() - { - self.reply(StatusWords::DeviceLocked); - return None; + seph::PacketTypes::PacketTypeRawApdu | + seph::PacketTypes::PacketTypeUsbHidApdu | + seph::PacketTypes::PacketTypeUsbWebusbApdu | + seph::PacketTypes::PacketTypeBleApdu=> { + unsafe { + if os_perso_is_pin_set() == BOLOS_TRUE.try_into().unwrap() + && os_global_pin_is_validated() != BOLOS_TRUE.try_into().unwrap() { + self.reply(StatusWords::DeviceLocked); + return None; + } } + self.apdu_type = packet_type; + self.rx_length = length as usize; + self.rx = self.rx_length; + self.event_pending = true; + return self.check_event(); + } + + _ => { } - self.rx = unsafe { G_io_app.apdu_length as usize }; - self.event_pending = true; - return self.check_event(); } None } - fn detect_apdu(&mut self, spi_buffer: &mut [u8; 256]) -> bool + fn detect_apdu(&mut self, length:i32) -> bool where T: TryFrom, Reply: From<>::Error>, { - match self.decode_event::(spi_buffer) { + match self.decode_event::(length) { Some(Event::Command(_)) => { - self.rx = unsafe { G_io_app.apdu_length as usize }; + self.rx_length = length as usize; + self.rx = self.rx_length; self.event_pending = true; return true; } @@ -519,9 +525,9 @@ impl Comm { pub fn reply>(&mut self, reply: T) { let sw = reply.into().0; // Append status word - self.apdu_buffer[self.tx] = (sw >> 8) as u8; - self.apdu_buffer[self.tx + 1] = sw as u8; - self.tx += 2; + self.io_buffer[self.tx_length] = (sw >> 8) as u8; + self.io_buffer[self.tx_length + 1] = sw as u8; + self.tx_length += 2; // Transmit the response self.apdu_send(false); } @@ -529,9 +535,9 @@ impl Comm { pub fn swap_reply>(&mut self, reply: T) { let sw = reply.into().0; // Append status word - self.apdu_buffer[self.tx] = (sw >> 8) as u8; - self.apdu_buffer[self.tx + 1] = sw as u8; - self.tx += 2; + self.io_buffer[self.tx_length] = (sw >> 8) as u8; + self.io_buffer[self.tx_length + 1] = sw as u8; + self.tx_length += 2; // Transmit the response self.apdu_send(true); } @@ -548,43 +554,43 @@ impl Comm { /// Return APDU Metadata pub fn get_apdu_metadata(&self) -> &ApduHeader { - assert!(self.apdu_buffer.len() >= 4); - let ptr = &self.apdu_buffer[0] as &u8 as *const u8 as *const ApduHeader; + assert!(self.io_buffer.len() >= 5); + let ptr = &self.io_buffer[1] as &u8 as *const u8 as *const ApduHeader; unsafe { &*ptr } } pub fn get_data(&self) -> Result<&[u8], StatusWords> { - if self.rx == 4 { + if self.rx_length == 6 { Ok(&[]) // Conforming zero-data APDU } else { - let first_len_byte = self.apdu_buffer[4] as usize; + let first_len_byte = self.io_buffer[5] as usize; let get_data_from_buffer = |len, offset| { - if len == 0 || len + offset > self.rx { + if len == 0 || len + offset > self.rx_length { Err(StatusWords::BadLen) } else { - Ok(&self.apdu_buffer[offset..offset + len]) + Ok(&self.io_buffer[offset..offset + len]) } }; - match (first_len_byte, self.rx) { - (0, 5) => Ok(&[]), // Non-conforming zero-data APDU - (0, 6) => Err(StatusWords::BadLen), + match (first_len_byte, self.rx_length) { + (0, 6) => Ok(&[]), // Non-conforming zero-data APDU + (0, 7) => Err(StatusWords::BadLen), (0, _) => { let len = - u16::from_le_bytes([self.apdu_buffer[5], self.apdu_buffer[6]]) as usize; - get_data_from_buffer(len, 7) + u16::from_le_bytes([self.io_buffer[6], self.io_buffer[7]]) as usize; + get_data_from_buffer(len, 8) } - (len, _) => get_data_from_buffer(len, 5), + (len, _) => get_data_from_buffer(len, 6), } } } pub fn get(&self, start: usize, end: usize) -> &[u8] { - &self.apdu_buffer[start..end] + &self.io_buffer[start..end] } pub fn append(&mut self, m: &[u8]) { - self.apdu_buffer[self.tx..self.tx + m.len()].copy_from_slice(m); - self.tx += m.len(); + self.io_buffer[self.tx_length..self.tx_length + m.len()].copy_from_slice(m); + self.tx_length += m.len(); } } @@ -594,30 +600,31 @@ fn handle_bolos_apdu(com: &mut Comm, ins: u8) { // Get Information INS: retrieve App name and version 0x01 => { unsafe { - com.apdu_buffer[0] = 0x01; - com.tx += 1; + com.tx_length = 0; + com.io_buffer[com.tx_length] = 0x01; + com.tx_length += 1; let len = os_registry_get_current_app_tag( BOLOS_TAG_APPNAME, - &mut com.apdu_buffer[com.tx + 1] as *mut u8, - (260 - com.tx - 1) as u32, + &mut com.io_buffer[com.tx_length + 1] as *mut u8, + (273 - com.tx_length - 2) as u32, ); - com.apdu_buffer[com.tx] = len as u8; - com.tx += 1 + (len as usize); + com.io_buffer[com.tx_length] = len as u8; + com.tx_length += 1 + (len as usize); let len = os_registry_get_current_app_tag( BOLOS_TAG_APPVERSION, - &mut com.apdu_buffer[com.tx + 1] as *mut u8, - (260 - com.tx - 1) as u32, + &mut com.io_buffer[com.tx_length + 1] as *mut u8, + (273 - com.tx_length - 2) as u32, ); - com.apdu_buffer[com.tx] = len as u8; - com.tx += 1 + (len as usize); + com.io_buffer[com.tx_length] = len as u8; + com.tx_length += 1 + (len as usize); // to be fixed within io tasks // return OS flags to notify of platform's global state (pin lock etc) - com.apdu_buffer[com.tx] = 1; // flags length - com.tx += 1; - com.apdu_buffer[com.tx] = os_flags() as u8; - com.tx += 1; + com.io_buffer[com.tx_length] = 1; // flags length + com.tx_length += 1; + com.io_buffer[com.tx_length] = os_flags() as u8; + com.tx_length += 1; } com.reply_ok(); } @@ -635,14 +642,14 @@ fn handle_bolos_apdu(com: &mut Comm, ins: u8) { impl Index for Comm { type Output = u8; fn index(&self, idx: usize) -> &Self::Output { - &self.apdu_buffer[idx] + &self.io_buffer[idx] } } impl IndexMut for Comm { fn index_mut(&mut self, idx: usize) -> &mut Self::Output { - self.tx = idx.max(self.tx); - &mut self.apdu_buffer[idx] + self.tx_length = idx.max(self.tx_length); + &mut self.io_buffer[idx] } } diff --git a/ledger_device_sdk/src/nbgl.rs b/ledger_device_sdk/src/nbgl.rs index dcb86907..35a46345 100644 --- a/ledger_device_sdk/src/nbgl.rs +++ b/ledger_device_sdk/src/nbgl.rs @@ -273,37 +273,3 @@ pub enum TuneIndex { TapCasual, TapNext, } - -// Direct translation of the C original. This was done to -// avoid compiling `os_io_seproxyhal.c` which includes many other things -#[no_mangle] -#[cfg(any(target_os = "stax", target_os = "flex"))] -extern "C" fn io_seproxyhal_play_tune(tune_index: u8) { - let mut buffer = [0u8; 4]; - let mut spi_buffer = [0u8; 128]; - - if tune_index >= NB_TUNES { - return; - } - - let sound_setting = - unsafe { os_setting_get(OS_SETTING_PIEZO_SOUND.into(), core::ptr::null_mut(), 0) }; - - if ((sound_setting & 2) == 2) && (tune_index < TUNE_TAP_CASUAL) { - return; - } - - if ((sound_setting & 1) == 1) && (tune_index >= TUNE_TAP_CASUAL) { - return; - } - - if seph::is_status_sent() { - seph::seph_recv(&mut spi_buffer, 0); - } - - buffer[0] = SEPROXYHAL_TAG_PLAY_TUNE as u8; - buffer[1] = 0; - buffer[2] = 1; - buffer[3] = tune_index; - seph::seph_send(&buffer); -} diff --git a/ledger_device_sdk/src/seph.rs b/ledger_device_sdk/src/seph.rs index 5165b079..d2021fce 100644 --- a/ledger_device_sdk/src/seph.rs +++ b/ledger_device_sdk/src/seph.rs @@ -2,70 +2,78 @@ use ledger_secure_sdk_sys::*; -#[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] -use crate::ble; +//#[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] +//use crate::ble; + +#[repr(u8)] +pub enum PacketTypes { + PacketTypeNone = OS_IO_PACKET_TYPE_NONE as u8, + PacketTypeSeph = OS_IO_PACKET_TYPE_SEPH as u8, + PacketTypeSeEvent = OS_IO_PACKET_TYPE_SE_EVT as u8, + + PacketTypeRawApdu = OS_IO_PACKET_TYPE_RAW_APDU as u8, + PacketTypeUsbHidApdu = OS_IO_PACKET_TYPE_USB_HID_APDU as u8, + PacketTypeUsbWebusbApdu = OS_IO_PACKET_TYPE_USB_WEBUSB_APDU as u8, + + PacketTypeBleApdu = OS_IO_PACKET_TYPE_BLE_APDU as u8, +} + +impl From for PacketTypes { + fn from(v: u8) -> PacketTypes { + match v as u8 { + OS_IO_PACKET_TYPE_NONE => PacketTypes::PacketTypeNone, + OS_IO_PACKET_TYPE_SEPH => PacketTypes::PacketTypeSeph, + OS_IO_PACKET_TYPE_SE_EVT => PacketTypes::PacketTypeSeEvent, + OS_IO_PACKET_TYPE_RAW_APDU => PacketTypes::PacketTypeRawApdu, + OS_IO_PACKET_TYPE_USB_HID_APDU => PacketTypes::PacketTypeUsbHidApdu, + OS_IO_PACKET_TYPE_USB_WEBUSB_APDU => PacketTypes::PacketTypeUsbWebusbApdu, + OS_IO_PACKET_TYPE_BLE_APDU => PacketTypes::PacketTypeBleApdu, + _ => PacketTypes::PacketTypeNone, + } + } +} #[repr(u8)] pub enum Events { - USBXFEREvent = SEPROXYHAL_TAG_USB_EP_XFER_EVENT as u8, - USBEvent = SEPROXYHAL_TAG_USB_EVENT as u8, - USBEventReset = SEPROXYHAL_TAG_USB_EVENT_RESET as u8, - USBEventSOF = SEPROXYHAL_TAG_USB_EVENT_SOF as u8, - USBEventSuspend = SEPROXYHAL_TAG_USB_EVENT_SUSPENDED as u8, - USBEventResume = SEPROXYHAL_TAG_USB_EVENT_RESUMED as u8, - CAPDUEvent = SEPROXYHAL_TAG_CAPDU_EVENT as u8, TickerEvent = SEPROXYHAL_TAG_TICKER_EVENT as u8, - StatusEvent = SEPROXYHAL_TAG_STATUS_EVENT as u8, - ButtonPush = SEPROXYHAL_TAG_BUTTON_PUSH_EVENT as u8, - DisplayProcessed = SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT as u8, - BleReceive = SEPROXYHAL_TAG_BLE_RECV_EVENT as u8, - ScreenTouch = SEPROXYHAL_TAG_FINGER_EVENT as u8, + ButtonPushEvent = SEPROXYHAL_TAG_BUTTON_PUSH_EVENT as u8, + ScreenTouchEvent = SEPROXYHAL_TAG_FINGER_EVENT as u8, + ItcEvent = SEPROXYHAL_TAG_ITC_EVENT as u8, Unknown = 0xff, } -#[repr(u8)] -pub enum UsbEp { - USBEpXFERSetup = SEPROXYHAL_TAG_USB_EP_XFER_SETUP as u8, - USBEpXFERIn = SEPROXYHAL_TAG_USB_EP_XFER_IN as u8, - USBEpXFEROut = SEPROXYHAL_TAG_USB_EP_XFER_OUT as u8, - USBEpPrepare = SEPROXYHAL_TAG_USB_EP_PREPARE as u8, - USBEpPrepareDirIn = SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN as u8, - Unknown, -} impl From for Events { fn from(v: u8) -> Events { match v as u32 { - SEPROXYHAL_TAG_USB_EP_XFER_EVENT => Events::USBXFEREvent, - SEPROXYHAL_TAG_USB_EVENT => Events::USBEvent, - SEPROXYHAL_TAG_USB_EVENT_RESET => Events::USBEventReset, - SEPROXYHAL_TAG_USB_EVENT_SOF => Events::USBEventSOF, - SEPROXYHAL_TAG_USB_EVENT_SUSPENDED => Events::USBEventSuspend, - SEPROXYHAL_TAG_USB_EVENT_RESUMED => Events::USBEventResume, - SEPROXYHAL_TAG_CAPDU_EVENT => Events::CAPDUEvent, SEPROXYHAL_TAG_TICKER_EVENT => Events::TickerEvent, - SEPROXYHAL_TAG_STATUS_EVENT => Events::StatusEvent, - SEPROXYHAL_TAG_BUTTON_PUSH_EVENT => Events::ButtonPush, - SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT => Events::DisplayProcessed, - SEPROXYHAL_TAG_BLE_RECV_EVENT => Events::BleReceive, - SEPROXYHAL_TAG_FINGER_EVENT => Events::ScreenTouch, + SEPROXYHAL_TAG_BUTTON_PUSH_EVENT => Events::ButtonPushEvent, + SEPROXYHAL_TAG_FINGER_EVENT => Events::ScreenTouchEvent, + SEPROXYHAL_TAG_ITC_EVENT => Events::ItcEvent, _ => Events::Unknown, } } } -impl From for UsbEp { - fn from(v: u8) -> UsbEp { - match v as u32 { - SEPROXYHAL_TAG_USB_EP_XFER_SETUP => UsbEp::USBEpXFERSetup, - SEPROXYHAL_TAG_USB_EP_XFER_IN => UsbEp::USBEpXFERIn, - SEPROXYHAL_TAG_USB_EP_XFER_OUT => UsbEp::USBEpXFEROut, - SEPROXYHAL_TAG_USB_EP_PREPARE => UsbEp::USBEpPrepare, - SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN => UsbEp::USBEpPrepareDirIn, - _ => UsbEp::Unknown, +#[repr(u8)] +pub enum ItcUxEvent { + AskBlePairing = ITC_UX_ASK_BLE_PAIRING as u8, + BlePairingStatus = ITC_UX_BLE_PAIRING_STATUS as u8, + Redisplay = ITC_UX_REDISPLAY as u8, + Unknown = 0xff, +} + +impl From for ItcUxEvent { + fn from(v: u8) -> ItcUxEvent { + match v as u8 { + ITC_UX_ASK_BLE_PAIRING => ItcUxEvent::AskBlePairing, + ITC_UX_BLE_PAIRING_STATUS => ItcUxEvent::BlePairingStatus, + ITC_UX_REDISPLAY => ItcUxEvent::Redisplay, + _ => ItcUxEvent::Unknown, } } } + /// FFI bindings to USBD functions inlined here for clarity /// and also because some of the generated ones are incorrectly /// assuming mutable pointers when they are not @@ -81,128 +89,10 @@ impl Default for apdu_buffer_s { } } pub type ApduBufferT = apdu_buffer_s; -extern "C" { - pub static mut USBD_Device: USBD_HandleTypeDef; - pub fn USBD_LL_SetupStage( - pdev: *mut USBD_HandleTypeDef, - psetup: *const u8, - ) -> USBD_StatusTypeDef; - pub fn USBD_LL_DataOutStage( - pdev: *mut USBD_HandleTypeDef, - epnum: u8, - pdata: *const u8, - arg1: *mut ApduBufferT, - ) -> USBD_StatusTypeDef; - pub fn USBD_LL_DataInStage( - pdev: *mut USBD_HandleTypeDef, - epnum: u8, - pdata: *const u8, - ) -> USBD_StatusTypeDef; - pub fn USBD_LL_Reset(pdev: *mut USBD_HandleTypeDef) -> USBD_StatusTypeDef; - pub fn USBD_LL_SetSpeed( - pdev: *mut USBD_HandleTypeDef, - speed: USBD_SpeedTypeDef, - ) -> USBD_StatusTypeDef; - pub fn USBD_LL_Suspend(pdev: *mut USBD_HandleTypeDef) -> USBD_StatusTypeDef; - pub fn USBD_LL_Resume(pdev: *mut USBD_HandleTypeDef) -> USBD_StatusTypeDef; - pub fn USBD_LL_SOF(pdev: *mut USBD_HandleTypeDef) -> USBD_StatusTypeDef; -} -/// Below is a straightforward translation of the corresponding functions -/// in the C SDK, they could be improved -pub fn handle_usb_event(event: u8) { - match Events::from(event) { - Events::USBEventReset => { - unsafe { - USBD_LL_SetSpeed(&raw mut USBD_Device, 1 /*USBD_SPEED_FULL*/); - USBD_LL_Reset(&raw mut USBD_Device); - - if G_io_app.apdu_media != IO_APDU_MEDIA_NONE { - return; - } - - G_io_app.usb_ep_xfer_len = core::mem::zeroed(); - G_io_app.usb_ep_timeouts = core::mem::zeroed(); - } - } - Events::USBEventSOF => unsafe { - USBD_LL_SOF(&raw mut USBD_Device); - }, - Events::USBEventSuspend => unsafe { - USBD_LL_Suspend(&raw mut USBD_Device); - }, - Events::USBEventResume => unsafe { - USBD_LL_Resume(&raw mut USBD_Device); - }, - _ => (), - } -} - -pub fn handle_usb_ep_xfer_event(apdu_buffer: &mut [u8], buffer: &[u8]) { - let endpoint = buffer[3] & 0x7f; - match UsbEp::from(buffer[4]) { - UsbEp::USBEpXFERSetup => unsafe { - USBD_LL_SetupStage(&raw mut USBD_Device, &buffer[6]); - }, - UsbEp::USBEpXFERIn => { - if (endpoint as u32) < IO_USB_MAX_ENDPOINTS { - unsafe { - G_io_app.usb_ep_timeouts[endpoint as usize].timeout = 0; - USBD_LL_DataInStage(&raw mut USBD_Device, endpoint, &buffer[6]); - } - } - } - UsbEp::USBEpXFEROut => { - if (endpoint as u32) < IO_USB_MAX_ENDPOINTS { - unsafe { - G_io_app.usb_ep_xfer_len[endpoint as usize] = buffer[5]; - let mut apdu_buf = ApduBufferT { - buf: apdu_buffer.as_mut_ptr(), - len: 260, - }; - USBD_LL_DataOutStage(&raw mut USBD_Device, endpoint, &buffer[6], &mut apdu_buf); - } - } - } - _ => (), - } -} - -pub fn handle_capdu_event(apdu_buffer: &mut [u8], buffer: &[u8]) { - let io_app = &raw mut G_io_app; - unsafe { - if (*io_app).apdu_state == APDU_IDLE { - let max = (apdu_buffer.len() - 3).min(buffer.len() - 3); - let size = u16::from_be_bytes([buffer[1], buffer[2]]) as usize; - - (*io_app).apdu_media = IO_APDU_MEDIA_RAW; - (*io_app).apdu_state = APDU_RAW; - - let len = size.min(max); - - (*io_app).apdu_length = len as u16; - - apdu_buffer[..len].copy_from_slice(&buffer[3..len + 3]); - } - } -} - -pub fn handle_event(apdu_buffer: &mut [u8], spi_buffer: &[u8]) { - let len = u16::from_be_bytes([spi_buffer[1], spi_buffer[2]]); +pub fn handle_event(_apdu_buffer: &mut [u8], spi_buffer: &[u8]) { + let _len = u16::from_be_bytes([spi_buffer[1], spi_buffer[2]]); match Events::from(spi_buffer[0]) { - Events::USBEvent => { - if len == 1 { - handle_usb_event(spi_buffer[3]); - } - } - Events::USBXFEREvent => { - if len >= 3 { - handle_usb_ep_xfer_event(apdu_buffer, spi_buffer); - } - } - #[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] - Events::BleReceive => ble::receive(apdu_buffer, spi_buffer), - Events::CAPDUEvent => handle_capdu_event(apdu_buffer, spi_buffer), Events::TickerEvent => { #[cfg(any(target_os = "stax", target_os = "flex", feature = "nano_nbgl"))] unsafe { diff --git a/ledger_device_sdk/src/ui/gadgets.rs b/ledger_device_sdk/src/ui/gadgets.rs index 5a1e8066..afb186e2 100644 --- a/ledger_device_sdk/src/ui/gadgets.rs +++ b/ledger_device_sdk/src/ui/gadgets.rs @@ -4,8 +4,9 @@ use crate::{ uxapp::{UxEvent, BOLOS_UX_OK}, }; use ledger_secure_sdk_sys::{ - buttons::{get_button_event, ButtonEvent, ButtonsState}, - seph, + //buttons::{get_button_event, ButtonEvent, ButtonsState}, + buttons::{ButtonEvent, ButtonsState}, + //seph, }; use crate::ui::bitmaps::{Glyph, WARNING}; @@ -22,8 +23,9 @@ const MAX_CHAR_PER_LINE: usize = 17; /// Handles communication to filter /// out actual events, and converts key /// events into presses/releases -pub fn get_event(buttons: &mut ButtonsState) -> Option { - if !seph::is_status_sent() { +/// TODO_IO +pub fn get_event(_buttons: &mut ButtonsState) -> Option { + /*if !seph::is_status_sent() { seph::send_general_status(); } @@ -37,7 +39,7 @@ pub fn get_event(buttons: &mut ButtonsState) -> Option { let button_info = buttons.cmd_buffer[3] >> 1; return get_button_event(buttons, button_info); } - } + }*/ None } @@ -539,7 +541,7 @@ impl<'a> MultiPageMenu<'a> { loop { match self.comm.next_event() { io::Event::Button(button) => { - if UxEvent::Event.request() == BOLOS_UX_OK { + if UxEvent::Event.request(self.comm) == BOLOS_UX_OK { match button { BothButtonsRelease => return EventOrPageIndex::Index(index), b => { @@ -571,7 +573,7 @@ impl<'a> MultiPageMenu<'a> { } io::Event::Command(ins) => return EventOrPageIndex::Event(io::Event::Command(ins)), io::Event::Ticker => { - if UxEvent::Event.request() != BOLOS_UX_OK { + if UxEvent::Event.request(self.comm) != BOLOS_UX_OK { // pin lock management UxEvent::block_and_get_event::(self.comm); // notify Ticker event only when redisplay is required diff --git a/ledger_device_sdk/src/ui/screen_util.rs b/ledger_device_sdk/src/ui/screen_util.rs index 2fbcd148..66922ee9 100644 --- a/ledger_device_sdk/src/ui/screen_util.rs +++ b/ledger_device_sdk/src/ui/screen_util.rs @@ -32,5 +32,5 @@ pub fn screen_update() { #[cfg(not(feature = "speculos"))] pub fn seph_setup_ticker(interval_ms: u16) { let ms = interval_ms.to_be_bytes(); - ledger_secure_sdk_sys::seph::seph_send(&[0x4e, 0, 2, ms[0], ms[1]]); + ledger_secure_sdk_sys::seph::io_tx(0x01, &[0x4e, 0, 2, ms[0], ms[1]], 5); } diff --git a/ledger_device_sdk/src/uxapp.rs b/ledger_device_sdk/src/uxapp.rs index 27e57a00..dbe0f359 100644 --- a/ledger_device_sdk/src/uxapp.rs +++ b/ledger_device_sdk/src/uxapp.rs @@ -27,7 +27,7 @@ pub enum UxEvent { impl UxEvent { #[allow(unused)] - pub fn request(&self) -> u32 { + pub fn request(&self, comm: &mut Comm) -> u32 { unsafe { //let mut params = bolos_ux_params_t::default(); G_ux_params.ux_id = match self { @@ -42,7 +42,7 @@ impl UxEvent { Self::ValidatePIN as u8 } Self::DelayLock => { - #[cfg(any(target_os = "stax", target_os = "flex", feature = "nano_nbgl"))] + #[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] { G_ux_params.u.lock_delay.delay_ms = 10000; } @@ -55,22 +55,20 @@ impl UxEvent { os_ux(&raw mut G_ux_params as *mut bolos_ux_params_t); match self { - Self::ValidatePIN => Self::block(), + Self::ValidatePIN => Self::block(comm), _ => os_sched_last_status(TASK_BOLOS_UX as u32) as u32, } } } - pub fn block() -> u32 { + pub fn block(comm: &mut Comm) -> u32 { let mut ret = unsafe { os_sched_last_status(TASK_BOLOS_UX as u32) } as u32; while ret == BOLOS_UX_IGNORE || ret == BOLOS_UX_CONTINUE { if unsafe { os_sched_is_running(TASK_SUBTASKS_START as u32) } != BOLOS_TRUE.try_into().unwrap() { - let mut spi_buffer = [0u8; 256]; - sys_seph::send_general_status(); - sys_seph::seph_recv(&mut spi_buffer, 0); - UxEvent::Event.request(); + sys_seph::io_rx(&mut comm.io_buffer, true); + UxEvent::Event.request(comm); } else { unsafe { os_sched_yield(BOLOS_UX_OK as u8) }; } @@ -90,12 +88,12 @@ impl UxEvent { if unsafe { os_sched_is_running(TASK_SUBTASKS_START as u32) } != BOLOS_TRUE.try_into().unwrap() { - let mut spi_buffer = [0u8; 256]; - seph::send_general_status(); - seph::seph_recv(&mut spi_buffer, 0); - event = comm.decode_event(&mut spi_buffer); + let status = sys_seph::io_rx(&mut comm.io_buffer, true); + if status > 0 { + event = comm.decode_event(status) + } - UxEvent::Event.request(); + UxEvent::Event.request(comm); if let Option::Some(Event::Command(_)) = event { return (ret, event); diff --git a/ledger_secure_sdk_sys/build.rs b/ledger_secure_sdk_sys/build.rs index 1588273d..caf0edbf 100644 --- a/ledger_secure_sdk_sys/build.rs +++ b/ledger_secure_sdk_sys/build.rs @@ -8,8 +8,7 @@ use std::{env, fs::File, io::BufRead, io::BufReader, io::Read}; const AUX_C_FILES: [&str; 2] = ["./src/c/src.c", "./src/c/sjlj.s"]; -const SDK_C_FILES: [&str; 9] = [ - "src/os_io_usb.c", +const SDK_C_FILES: [&str; 13] = [ "src/pic.c", "src/checks.c", "src/cx_stubs.S", @@ -18,15 +17,11 @@ const SDK_C_FILES: [&str; 9] = [ "src/svc_cx_call.s", "src/syscalls.c", "src/os_printf.c", -]; - -const SDK_USB_FILES: [&str; 6] = [ - "lib_stusb/usbd_conf.c", - "lib_stusb/STM32_USB_Device_Library/Core/Src/usbd_core.c", - "lib_stusb/STM32_USB_Device_Library/Core/Src/usbd_ctlreq.c", - "lib_stusb/STM32_USB_Device_Library/Core/Src/usbd_ioreq.c", - "lib_stusb_impl/usbd_impl.c", - "lib_stusb/STM32_USB_Device_Library/Class/HID/Src/usbd_hid.c", + "protocol/src/ledger_protocol.c", + "io/src/os_io.c", + "io/src/os_io_default_apdu.c", + "io/src/os_io_seph_cmd.c", + "io/src/os_io_seph_ux.c" ]; const CFLAGS_NANOSPLUS: [&str; 22] = [ @@ -378,25 +373,25 @@ impl SDKBuilder<'_> { command .files(&AUX_C_FILES) - .files(str2path(&self.device.c_sdk, &SDK_C_FILES)) - .files(str2path(&self.device.c_sdk, &SDK_USB_FILES)); + .files(str2path(&self.device.c_sdk, &SDK_C_FILES)); + + //command + // .file(c_sdk.join("lib_standard_app/main.c")) + + let glyphs_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("glyphs"); command = command .include(self.gcc_toolchain.join("include")) .include(self.device.c_sdk.join("include")) + .include(self.device.c_sdk.join("lib_u2f/include")) + .include(self.device.c_sdk.join("io/include")) + .include(self.device.c_sdk.join("io_legacy/include")) + .include(self.device.c_sdk.join("protocol/include")) .include(self.device.c_sdk.join("lib_cxng/include")) - .include(self.device.c_sdk.join("lib_stusb")) - .include(self.device.c_sdk.join("lib_stusb_impl")) - .include( - self.device - .c_sdk - .join("lib_stusb/STM32_USB_Device_Library/Core/Inc"), - ) - .include( - self.device - .c_sdk - .join("lib_stusb/STM32_USB_Device_Library/Class/HID/Inc"), - ) + .include(self.device.c_sdk.join("lib_ux/include")) + .include(self.device.c_sdk.join("lib_bagl/include")) + .include(self.device.c_sdk.join("lib_nbgl/include")) + .include(&glyphs_path) .debug(true) .define("main", "_start") .clone(); @@ -419,6 +414,9 @@ impl SDKBuilder<'_> { // Configure BLE and NBGL for s in self.device.defines.iter() { + if s.0 == "HAVE_IO_USB" { + configure_lib_usb(&mut command, &self.device.c_sdk); + } if s.0 == "HAVE_BLE" { configure_lib_ble(&mut command, &self.device.c_sdk); } @@ -452,9 +450,10 @@ impl SDKBuilder<'_> { "-fshort-enums".to_string(), format!("-I{gcc_tc}/include"), format!("-I{bsdk}/include"), + format!("-I{bsdk}/io/include/"), + format!("-I{bsdk}/io_legacy/include/"), + format!("-I{bsdk}/lib_u2f/include/"), format!("-I{bsdk}/lib_cxng/include/"), - format!("-I{bsdk}/lib_stusb/STM32_USB_Device_Library/Core/Inc/"), - format!("-I{bsdk}/lib_stusb/"), ]; let headers = str2path( &self.device.c_sdk, @@ -463,11 +462,8 @@ impl SDKBuilder<'_> { "include/os.h", /* syscalls */ "include/os_screen.h", "include/syscalls.h", - "include/os_io_seproxyhal.h", "include/os_ux.h", "include/ox.h", /* crypto-related syscalls */ - "lib_stusb/STM32_USB_Device_Library/Core/Inc/usbd_def.h", - "include/os_io_usb.h", "lib_standard_app/swap_lib_calls.h", ], ); @@ -615,20 +611,31 @@ fn main() { // Helper functions // -------------------------------------------------- +fn configure_lib_usb(command: &mut cc::Build, c_sdk: &Path) { + command + .file(c_sdk.join("lib_stusb/src/usbd_conf.c")) + .file(c_sdk.join("lib_stusb/src/usbd_core.c")) + .file(c_sdk.join("lib_stusb/src/usbd_ctlreq.c")) + .file(c_sdk.join("lib_stusb/src/usbd_desc.c")) + .file(c_sdk.join("lib_stusb/src/usbd_ioreq.c")) + .file(c_sdk.join("lib_stusb/src/usbd_ledger_ccid.c")) + .file(c_sdk.join("lib_stusb/src/usbd_ledger_cdc.c")) + .file(c_sdk.join("lib_stusb/src/usbd_ledger_hid_kbd.c")) + .file(c_sdk.join("lib_stusb/src/usbd_ledger_hid_u2f.c")) + .file(c_sdk.join("lib_stusb/src/usbd_ledger_hid.c")) + .file(c_sdk.join("lib_stusb/src/usbd_ledger_webusb.c")) + .file(c_sdk.join("lib_stusb/src/usbd_ledger.c")) + .include(c_sdk.join("lib_stusb/include")) + .include(c_sdk.join("lib_stusb_impl/include")); +} + fn configure_lib_ble(command: &mut cc::Build, c_sdk: &Path) { command - .file(c_sdk.join("src/ledger_protocol.c")) - .file(c_sdk.join("lib_blewbxx/core/auto/ble_gap_aci.c")) - .file(c_sdk.join("lib_blewbxx/core/auto/ble_gatt_aci.c")) - .file(c_sdk.join("lib_blewbxx/core/auto/ble_hal_aci.c")) - .file(c_sdk.join("lib_blewbxx/core/auto/ble_hci_le.c")) - .file(c_sdk.join("lib_blewbxx/core/auto/ble_l2cap_aci.c")) - .file(c_sdk.join("lib_blewbxx/core/template/osal.c")) - .file(c_sdk.join("lib_blewbxx_impl/src/ledger_ble.c")) + .file(c_sdk.join("lib_blewbxx/src/ble_cmd.c")) + .file(c_sdk.join("lib_blewbxx/src/ble_ledger_profile_apdu.c")) + .file(c_sdk.join("lib_blewbxx/src/ble_ledger_profile_u2f.c")) + .file(c_sdk.join("lib_blewbxx/src/ble_ledger.c")) .include(c_sdk.join("lib_blewbxx/include")) - .include(c_sdk.join("lib_blewbxx/core")) - .include(c_sdk.join("lib_blewbxx/core/auto")) - .include(c_sdk.join("lib_blewbxx/core/template")) .include(c_sdk.join("lib_blewbxx_impl/include")); } diff --git a/ledger_secure_sdk_sys/csdk_flex.h b/ledger_secure_sdk_sys/csdk_flex.h index b878a6ab..a8643398 100644 --- a/ledger_secure_sdk_sys/csdk_flex.h +++ b/ledger_secure_sdk_sys/csdk_flex.h @@ -12,7 +12,7 @@ // APP STORAGE (feature dependent) //#define HAVE_APP_STORAGE // IO SEPROXY BUFFER SIZE -#define IO_SEPROXYHAL_BUFFER_SIZE_B 300 +#define OS_IO_SEPH_BUFFER_SIZE 272 // NBGL QRCODE (feature dependent) #define NBGL_QRCODE // NBGL KEYBOARD (feature dependent) @@ -28,10 +28,10 @@ #define IO_USB_MAX_ENDPOINTS 4 #define HAVE_USB_APDU #define USB_SEGMENT_SIZE 64 -//#define HAVE_WEBUSB +#define HAVE_WEBUSB //#define WEBUSB_URL_SIZE_B //#define WEBUSB_URL -#define OS_IO_SEPROXYHAL +#define HAVE_IO_U2F //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Makefile.defines //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -57,7 +57,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Misc //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define HAVE_LOCAL_APDU_BUFFER +//#define HAVE_LOCAL_APDU_BUFFER //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DEBUG C SDK diff --git a/ledger_secure_sdk_sys/csdk_nanos2.h b/ledger_secure_sdk_sys/csdk_nanos2.h index 126ba21f..a2187004 100644 --- a/ledger_secure_sdk_sys/csdk_nanos2.h +++ b/ledger_secure_sdk_sys/csdk_nanos2.h @@ -4,7 +4,7 @@ // APP STORAGE (feature dependent) //#define HAVE_APP_STORAGE // IO SEPROXY BUFFER SIZE -#define IO_SEPROXYHAL_BUFFER_SIZE_B 300 +#define OS_IO_SEPH_BUFFER_SIZE 272 // NBGL KEYBOARD (feature dependent) //#define NBGL_KEYBOARD // NBGL KEYPAD (feature dependent) @@ -18,10 +18,10 @@ #define IO_USB_MAX_ENDPOINTS 4 #define HAVE_USB_APDU #define USB_SEGMENT_SIZE 64 -//#define HAVE_WEBUSB +#define HAVE_WEBUSB //#define WEBUSB_URL_SIZE_B //#define WEBUSB_URL -#define OS_IO_SEPROXYHAL +#define HAVE_IO_U2F //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Makefile.defines //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -35,6 +35,7 @@ #define HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX #define HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX #define SCREEN_SIZE_NANO +#define HAVE_UX_FLOW #define HAVE_SE_BUTTON #define HAVE_SE_SCREEN @@ -47,7 +48,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Misc //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define HAVE_LOCAL_APDU_BUFFER +//#define HAVE_LOCAL_APDU_BUFFER //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DEBUG C SDK diff --git a/ledger_secure_sdk_sys/csdk_nanox.h b/ledger_secure_sdk_sys/csdk_nanox.h index c6f69c1d..50d403f3 100644 --- a/ledger_secure_sdk_sys/csdk_nanox.h +++ b/ledger_secure_sdk_sys/csdk_nanox.h @@ -9,7 +9,7 @@ // APP STORAGE (feature dependent) //#define HAVE_APP_STORAGE // IO SEPROXY BUFFER SIZE -#define IO_SEPROXYHAL_BUFFER_SIZE_B 300 +#define OS_IO_SEPH_BUFFER_SIZE 272 // NBGL KEYBOARD (feature dependent) //#define NBGL_KEYBOARD // NBGL KEYPAD (feature dependent) @@ -23,10 +23,10 @@ #define IO_USB_MAX_ENDPOINTS 4 #define HAVE_USB_APDU #define USB_SEGMENT_SIZE 64 -//#define HAVE_WEBUSB +#define HAVE_WEBUSB //#define WEBUSB_URL_SIZE_B //#define WEBUSB_URL -#define OS_IO_SEPROXYHAL +#define HAVE_IO_U2F //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Makefile.defines //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -40,6 +40,7 @@ #define HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX #define HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX #define SCREEN_SIZE_NANO +#define HAVE_UX_FLOW #define HAVE_SE_BUTTON #define HAVE_SE_SCREEN @@ -52,7 +53,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Misc //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define HAVE_LOCAL_APDU_BUFFER +//#define HAVE_LOCAL_APDU_BUFFER #define HAVE_SEPROXYHAL_MCU #define HAVE_MCU_PROTECT diff --git a/ledger_secure_sdk_sys/csdk_stax.h b/ledger_secure_sdk_sys/csdk_stax.h index bfb3d7fa..08ba196d 100644 --- a/ledger_secure_sdk_sys/csdk_stax.h +++ b/ledger_secure_sdk_sys/csdk_stax.h @@ -12,7 +12,7 @@ // APP STORAGE (feature dependent) //#define HAVE_APP_STORAGE // IO SEPROXY BUFFER SIZE -#define IO_SEPROXYHAL_BUFFER_SIZE_B 300 +#define OS_IO_SEPH_BUFFER_SIZE 272 // NBGL QRCODE (feature dependent) #define NBGL_QRCODE // NBGL KEYBOARD (feature dependent) @@ -28,10 +28,10 @@ #define IO_USB_MAX_ENDPOINTS 4 #define HAVE_USB_APDU #define USB_SEGMENT_SIZE 64 -//#define HAVE_WEBUSB +#define HAVE_WEBUSB //#define WEBUSB_URL_SIZE_B //#define WEBUSB_URL -#define OS_IO_SEPROXYHAL +#define HAVE_IO_U2F //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Makefile.defines //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -55,7 +55,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Misc //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define HAVE_LOCAL_APDU_BUFFER +//#define HAVE_LOCAL_APDU_BUFFER //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DEBUG C SDK diff --git a/ledger_secure_sdk_sys/src/c/src.c b/ledger_secure_sdk_sys/src/c/src.c index 5b7c94d0..a95b8f0e 100644 --- a/ledger_secure_sdk_sys/src/c/src.c +++ b/ledger_secure_sdk_sys/src/c/src.c @@ -3,16 +3,20 @@ #include "exceptions.h" #include "os_apilevel.h" #include "string.h" -#include "seproxyhal_protocol.h" +#include "os_io.h" #include "os_id.h" -#include "os_io_usb.h" #include "os_nvm.h" #include "os_pic.h" #include "checks.h" + +#ifdef HAVE_IO_USB +#include "usbd_ledger.h" +#endif // HAVE_IO_USB + #ifdef HAVE_BLE - #include "ledger_ble.h" - bolos_ux_asynch_callback_t G_io_asynch_ux_callback; -#endif +#include "ble_ledger.h" +#include "ble_ledger_profile_apdu.h" +#endif // HAVE_BLE extern void sample_main(int arg0); extern void heap_init(); @@ -20,8 +24,6 @@ extern void heap_init(); struct SectionSrc; struct SectionDst; -io_seph_app_t G_io_app; - extern Elf32_Rel _relocs; extern Elf32_Rel _erelocs; @@ -254,15 +256,6 @@ void c_reset_bss() { bolos_ux_params_t G_ux_params = {0}; void c_boot_std() { - // below is a 'manual' implementation of `io_seproxyhal_init` -#ifdef HAVE_MCU_PROTECT - unsigned char c[4]; - c[0] = SEPROXYHAL_TAG_MCU; - c[1] = 0; - c[2] = 1; - c[3] = SEPROXYHAL_TAG_MCU_TYPE_PROTECT; - io_seproxyhal_spi_send(c, 4); -#endif // Warn UX layer of io reset to avoid unwanted pin lock memset(&G_ux_params, 0, sizeof(G_ux_params)); @@ -277,33 +270,36 @@ void c_boot_std() { } } + os_io_init_t init_io; + + init_io.usb.pid = 0; + init_io.usb.vid = 0; + init_io.usb.class_mask = 0; + memset(init_io.usb.name, 0, sizeof(init_io.usb.name)); +#ifdef HAVE_IO_USB + init_io.usb.class_mask = USBD_LEDGER_CLASS_HID; +#ifdef HAVE_WEBUSB + init_io.usb.class_mask |= USBD_LEDGER_CLASS_WEBUSB; +#endif // HAVE_WEBUSB +#ifdef HAVE_IO_U2F + init_io.usb.class_mask |= USBD_LEDGER_CLASS_HID_U2F; + + init_io.usb.hid_u2f_settings.protocol_version = 2; + init_io.usb.hid_u2f_settings.major_device_version_number = 0; + init_io.usb.hid_u2f_settings.minor_device_version_number = 1; + init_io.usb.hid_u2f_settings.build_device_version_number = 0; + init_io.usb.hid_u2f_settings.capabilities_flag = 0; +#endif // HAVE_IO_U2F +#endif // !HAVE_IO_USB + + init_io.ble.profile_mask = 0; #ifdef HAVE_BLE - unsigned int plane = G_io_app.plane_mode; -#endif - - memset(&G_io_app, 0, sizeof(G_io_app)); - -#ifdef HAVE_BLE - G_io_app.plane_mode = plane; -#endif - G_io_app.apdu_state = APDU_IDLE; - G_io_app.apdu_length = 0; - G_io_app.apdu_media = IO_APDU_MEDIA_NONE; + init_io.ble.profile_mask = BLE_LEDGER_PROFILE_APDU; +#endif // !HAVE_BLE - G_io_app.ms = 0; - io_usb_hid_init(); - - USB_power(0); - USB_power(1); - -#ifdef HAVE_BLE - memset(&G_io_asynch_ux_callback, 0, sizeof(G_io_asynch_ux_callback)); - BLE_power(1, NULL); -#endif + os_io_init(&init_io); + os_io_start(); -#if !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN) - check_audited_app(); -#endif // !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN) heap_init(); } @@ -358,15 +354,3 @@ int c_main(int arg0) { } return 0; } - -#ifdef HAVE_PRINTF -void mcu_usb_prints(const char *str, unsigned int charcount) -{ - unsigned char buf[4]; - buf[0] = SEPROXYHAL_TAG_PRINTF; - buf[1] = charcount >> 8; - buf[2] = charcount; - io_seproxyhal_spi_send(buf, 3); - io_seproxyhal_spi_send((const uint8_t *) str, charcount); -} -#endif \ No newline at end of file diff --git a/ledger_secure_sdk_sys/src/seph.rs b/ledger_secure_sdk_sys/src/seph.rs index 0a83fcb1..c303e4d2 100644 --- a/ledger_secure_sdk_sys/src/seph.rs +++ b/ledger_secure_sdk_sys/src/seph.rs @@ -1,64 +1,13 @@ use crate::{ - io_seph_is_status_sent, io_seph_recv, io_seph_send, SEPROXYHAL_TAG_GENERAL_STATUS, - SEPROXYHAL_TAG_RAPDU, SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS, + os_io_rx_evt, + os_io_tx_cmd, }; -/// Directly send buffer over the SPI channel to the MCU -pub fn seph_send(buffer: &[u8]) { - unsafe { io_seph_send(buffer.as_ptr(), buffer.len() as u16) }; -} - /// Receive the next APDU into 'buffer' -pub fn seph_recv(buffer: &mut [u8], flags: u32) -> u16 { - unsafe { io_seph_recv(buffer.as_mut_ptr(), buffer.len() as u16, flags) } -} - -/// Wrapper for 'io_seph_is_status_sent' -pub fn is_status_sent() -> bool { - let status = unsafe { io_seph_is_status_sent() }; - status == 1 -} - -/// Inform the MCU that the previous event was processed -pub fn send_general_status() { - // XXX: Not sure we need this line to 'avoid troubles' like - // in the original SDK - // if io_seproxyhal_spi_is_status_sent() { - // return; - // } - if !is_status_sent() { - // The two last bytes are supposed to be - // SEPROXYHAL_TAG_GENERAL_STATUS_LAST_COMMAND, which is 0u16 - let status = [SEPROXYHAL_TAG_GENERAL_STATUS as u8, 0, 2, 0, 0]; - seph_send(&status); - } -} - -/// Function to ensure a I/O channel is not timeouting waiting -/// for operations after a long time without SEPH packet exchanges -pub fn heartbeat() { - send_general_status(); - let mut spi_buffer = [0u8; 128]; - seph_recv(&mut spi_buffer, 0); - while is_status_sent() { - seph_recv(&mut spi_buffer, 0); - } -} - -#[repr(u8)] -pub enum SephTags { - ScreenDisplayStatus = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS as u8, - GeneralStatus = SEPROXYHAL_TAG_GENERAL_STATUS as u8, - RawAPDU = SEPROXYHAL_TAG_RAPDU as u8, - Unknown, +pub fn io_rx(buffer: &mut [u8], check_se_event: bool) -> i32 { + unsafe { os_io_rx_evt(buffer.as_ptr() as _, buffer.len() as u16, core::ptr::null_mut(), check_se_event) } } -impl From for SephTags { - fn from(v: u8) -> SephTags { - match v as u32 { - SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS => SephTags::ScreenDisplayStatus, - SEPROXYHAL_TAG_GENERAL_STATUS => SephTags::GeneralStatus, - _ => SephTags::Unknown, - } - } +pub fn io_tx(apdu_type: u8, buffer: &[u8], length:usize) -> i32 { + unsafe { os_io_tx_cmd(apdu_type, buffer.as_ptr() as _, length as u16, core::ptr::null_mut()) } } From e46f8304dc67880d4c27c0913f700edc9f2995d3 Mon Sep 17 00:00:00 2001 From: Stephane Portron Date: Thu, 26 Jun 2025 15:51:28 +0200 Subject: [PATCH 02/20] [io] fix some issues --- ledger_device_sdk/src/io.rs | 8 ++++---- ledger_device_sdk/src/uxapp.rs | 13 +++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index 426227f3..3790e1f5 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -267,7 +267,7 @@ impl Comm { self.event_pending = false; // Reject incomplete APDUs - if self.rx_length < 6 { + if self.rx_length < 5 { self.reply(StatusWords::BadLen); return None; } @@ -443,7 +443,7 @@ impl Comm { } self.apdu_type = packet_type; self.rx_length = length as usize; - self.rx = self.rx_length; + self.rx = self.rx_length-1; self.event_pending = true; return self.check_event(); } @@ -462,7 +462,7 @@ impl Comm { match self.decode_event::(length) { Some(Event::Command(_)) => { self.rx_length = length as usize; - self.rx = self.rx_length; + self.rx = self.rx_length-1; self.event_pending = true; return true; } @@ -560,7 +560,7 @@ impl Comm { } pub fn get_data(&self) -> Result<&[u8], StatusWords> { - if self.rx_length == 6 { + if self.rx_length == 5 { Ok(&[]) // Conforming zero-data APDU } else { let first_len_byte = self.io_buffer[5] as usize; diff --git a/ledger_device_sdk/src/uxapp.rs b/ledger_device_sdk/src/uxapp.rs index dbe0f359..58d4ca87 100644 --- a/ledger_device_sdk/src/uxapp.rs +++ b/ledger_device_sdk/src/uxapp.rs @@ -27,7 +27,7 @@ pub enum UxEvent { impl UxEvent { #[allow(unused)] - pub fn request(&self, comm: &mut Comm) -> u32 { + pub fn request(&self) -> u32 { unsafe { //let mut params = bolos_ux_params_t::default(); G_ux_params.ux_id = match self { @@ -55,20 +55,21 @@ impl UxEvent { os_ux(&raw mut G_ux_params as *mut bolos_ux_params_t); match self { - Self::ValidatePIN => Self::block(comm), + Self::ValidatePIN => Self::block(), _ => os_sched_last_status(TASK_BOLOS_UX as u32) as u32, } } } - pub fn block(comm: &mut Comm) -> u32 { + pub fn block() -> u32 { let mut ret = unsafe { os_sched_last_status(TASK_BOLOS_UX as u32) } as u32; while ret == BOLOS_UX_IGNORE || ret == BOLOS_UX_CONTINUE { if unsafe { os_sched_is_running(TASK_SUBTASKS_START as u32) } != BOLOS_TRUE.try_into().unwrap() { - sys_seph::io_rx(&mut comm.io_buffer, true); - UxEvent::Event.request(comm); + let mut spi_buffer = [0u8; 256]; + sys_seph::io_rx(&mut spi_buffer, true); + UxEvent::Event.request(); } else { unsafe { os_sched_yield(BOLOS_UX_OK as u8) }; } @@ -93,7 +94,7 @@ impl UxEvent { event = comm.decode_event(status) } - UxEvent::Event.request(comm); + UxEvent::Event.request(); if let Option::Some(Event::Command(_)) = event { return (ret, event); From 1eea6d3e4372be5e2dd24825bdc7b9b15c652c23 Mon Sep 17 00:00:00 2001 From: Stephane Portron Date: Mon, 30 Jun 2025 09:59:09 +0200 Subject: [PATCH 03/20] [io] fix some issues --- ledger_device_sdk/src/ui/gadgets.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ledger_device_sdk/src/ui/gadgets.rs b/ledger_device_sdk/src/ui/gadgets.rs index afb186e2..bf23c9ae 100644 --- a/ledger_device_sdk/src/ui/gadgets.rs +++ b/ledger_device_sdk/src/ui/gadgets.rs @@ -541,7 +541,7 @@ impl<'a> MultiPageMenu<'a> { loop { match self.comm.next_event() { io::Event::Button(button) => { - if UxEvent::Event.request(self.comm) == BOLOS_UX_OK { + if UxEvent::Event.request() == BOLOS_UX_OK { match button { BothButtonsRelease => return EventOrPageIndex::Index(index), b => { @@ -573,7 +573,7 @@ impl<'a> MultiPageMenu<'a> { } io::Event::Command(ins) => return EventOrPageIndex::Event(io::Event::Command(ins)), io::Event::Ticker => { - if UxEvent::Event.request(self.comm) != BOLOS_UX_OK { + if UxEvent::Event.request() != BOLOS_UX_OK { // pin lock management UxEvent::block_and_get_event::(self.comm); // notify Ticker event only when redisplay is required From afee3c919b0bb2dac7281d7a22de25401b1315ea Mon Sep 17 00:00:00 2001 From: Stephane Portron Date: Mon, 30 Jun 2025 10:56:20 +0200 Subject: [PATCH 04/20] [io] fix some issues --- .github/workflows/ci.yml | 1 + ledger_device_sdk/src/io.rs | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b2cdaff..eb14c7c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,3 +80,4 @@ jobs: uses: ./.github/workflows/reusable_build_all_apps.yml with: rust_sdk_branch: ${{ github.ref }} + c_sdk_branch: API_LEVEL_24 diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index 3790e1f5..7ac89455 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -109,6 +109,9 @@ pub enum Event { /// Manages the communication of the device: receives events such as button presses, incoming /// APDU requests, and provides methods to build and transmit APDU responses. pub struct Comm { + pub apdu_buffer: [u8; 272], + pub rx: usize, + pub tx: usize, pub event_pending: bool, #[cfg(not(any(target_os = "stax", target_os = "flex")))] buttons: ButtonsState, @@ -122,9 +125,6 @@ pub struct Comm { pub io_buffer: [u8; 273], pub rx_length: usize, pub tx_length: usize, - - // Legacy - pub rx: usize, } impl Default for Comm { @@ -150,6 +150,9 @@ impl Comm { /// Creates a new [`Comm`] instance, which accepts any CLA APDU by default. pub const fn new() -> Self { Self { + apdu_buffer: [0u8; 272], + rx: 0, + tx: 0, event_pending: false, #[cfg(not(any(target_os = "stax", target_os = "flex")))] buttons: ButtonsState::new(), @@ -158,7 +161,6 @@ impl Comm { io_buffer: [0u8; 273], rx_length: 0, tx_length: 0, - rx: 0, } } @@ -185,7 +187,13 @@ impl Comm { // This is private. Users should call reply to set the satus word and // transmit the response. fn apdu_send(&mut self, _is_swap: bool) { - sys_seph::io_tx(self.apdu_type, &self.io_buffer, self.tx_length); + if self.tx != 0 { + sys_seph::io_tx(self.apdu_type, &self.apdu_buffer, self.tx); + self.tx = 0; + } + else { + sys_seph::io_tx(self.apdu_type, &self.io_buffer, self.tx_length); + } self.tx_length = 0; self.rx_length = 0; } @@ -350,7 +358,7 @@ impl Comm { seph::Events::TickerEvent => { #[cfg(any(target_os = "stax", target_os = "flex", feature = "nano_nbgl"))] unsafe { - ux_process_ticker_event(); + ux_process_ticker_event(); } return Some(Event::Ticker); } @@ -384,6 +392,7 @@ impl Comm { } seph::ItcUxEvent::Redisplay => { + #[cfg(any(target_os = "stax", target_os = "flex", feature = "nano_nbgl"))] unsafe { nbgl_objAllowDrawing(true); nbgl_screenRedraw(); @@ -441,6 +450,7 @@ impl Comm { return None; } } + self.apdu_buffer[0..272].copy_from_slice(&self.io_buffer[1..273]); self.apdu_type = packet_type; self.rx_length = length as usize; self.rx = self.rx_length-1; From 2aa2b487c5a8353118a4edba491aa8e0b3728ba4 Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 2 Jul 2025 15:29:43 +0200 Subject: [PATCH 05/20] Build SDK and run tests with C SDK API_LEVEL_24 --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eb14c7c3..10449c89 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,13 @@ jobs: - name: Cargo build working-directory: ledger_device_sdk run: | + git clone https://github.com/LedgerHQ/ledger-secure-sdk.git --branch API_LEVEL_24 --single-branch c_sdk + echo "setting LEDGER_SDK_PATH to $(realpath c_sdk)" + export LEDGER_SDK_PATH=$(realpath c_sdk) cargo build --target ${{ matrix.target }} + if ($${ matrix.target } == "nanosplus" | $${ matrix.target } == "nanox"); then + cargo build --target ${{ matrix.target }} --features nano_nbgl; + fi test: name: Run unit and integration tests @@ -73,7 +79,7 @@ jobs: - name: Unit tests working-directory: ledger_device_sdk run: | - cargo test --target ${{ matrix.target }} --features speculos --tests + cargo test --target ${{ matrix.target }} --features speculos,debug --tests build-apps: name: Build all Rust apps From 34c6f0330728adfdef143ed5c9ed4b02f2b9ea2f Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 2 Jul 2025 15:42:29 +0200 Subject: [PATCH 06/20] Clone C SDK API_LEVEl_24 for clippy --- .github/workflows/ci.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10449c89..54d5e109 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,11 @@ jobs: - name: Cargo clippy working-directory: ${{ matrix.package }} run: | + # to be suppressed when C SDK API_LEVEL_24 is available in dev-tools + git clone https://github.com/LedgerHQ/ledger-secure-sdk.git --branch API_LEVEL_24 --single-branch c_sdk + echo "setting LEDGER_SDK_PATH to $(realpath c_sdk)" + export LEDGER_SDK_PATH=$(realpath c_sdk) + # ####################################### # cargo clippy --target ${{ matrix.target }} format: @@ -57,11 +62,13 @@ jobs: - name: Cargo build working-directory: ledger_device_sdk run: | + # to be suppressed when C SDK API_LEVEL_24 is available in dev-tools git clone https://github.com/LedgerHQ/ledger-secure-sdk.git --branch API_LEVEL_24 --single-branch c_sdk echo "setting LEDGER_SDK_PATH to $(realpath c_sdk)" export LEDGER_SDK_PATH=$(realpath c_sdk) + # ####################################### # cargo build --target ${{ matrix.target }} - if ($${ matrix.target } == "nanosplus" | $${ matrix.target } == "nanox"); then + if [[ "${{ matrix.target }}" == "nanosplus" || "${{ matrix.target }}" == "nanox" ]]; then cargo build --target ${{ matrix.target }} --features nano_nbgl; fi From 9af9e99f4a9905eaf92993600c9cbe027e98f35a Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 2 Jul 2025 15:47:48 +0200 Subject: [PATCH 07/20] Clone C SDK API_LEVEL_24 for tests --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54d5e109..74bf409f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,6 +86,11 @@ jobs: - name: Unit tests working-directory: ledger_device_sdk run: | + # to be suppressed when C SDK API_LEVEL_24 is available in dev-tools + git clone https://github.com/LedgerHQ/ledger-secure-sdk.git --branch API_LEVEL_24 --single-branch c_sdk + echo "setting LEDGER_SDK_PATH to $(realpath c_sdk)" + export LEDGER_SDK_PATH=$(realpath c_sdk) + # ####################################### # cargo test --target ${{ matrix.target }} --features speculos,debug --tests build-apps: From 22fa888eac0eea48b16304d696b01d17efd61c05 Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 2 Jul 2025 15:48:15 +0200 Subject: [PATCH 08/20] Run cargo fmt --- ledger_device_sdk/src/ble.rs | 1 + ledger_device_sdk/src/io.rs | 95 +++++++++++++------------------ ledger_device_sdk/src/seph.rs | 1 - ledger_secure_sdk_sys/build.rs | 2 +- ledger_secure_sdk_sys/src/seph.rs | 25 +++++--- 5 files changed, 61 insertions(+), 63 deletions(-) diff --git a/ledger_device_sdk/src/ble.rs b/ledger_device_sdk/src/ble.rs index e69de29b..8b137891 100644 --- a/ledger_device_sdk/src/ble.rs +++ b/ledger_device_sdk/src/ble.rs @@ -0,0 +1 @@ + diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index 7ac89455..dd945677 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -1,4 +1,3 @@ - #[cfg(not(any(target_os = "stax", target_os = "flex")))] use ledger_secure_sdk_sys::buttons::{get_button_event, ButtonEvent, ButtonsState}; use ledger_secure_sdk_sys::seph as sys_seph; @@ -17,7 +16,6 @@ unsafe extern "C" { pub unsafe static mut G_ux_params: bolos_ux_params_t; } - #[derive(Copy, Clone)] #[repr(u16)] pub enum StatusWords { @@ -103,7 +101,7 @@ pub enum Event { #[cfg(any(target_os = "stax", target_os = "flex"))] TouchEvent, /// Ticker - Ticker + Ticker, } /// Manages the communication of the device: receives events such as button presses, incoming @@ -190,8 +188,7 @@ impl Comm { if self.tx != 0 { sys_seph::io_tx(self.apdu_type, &self.apdu_buffer, self.tx); self.tx = 0; - } - else { + } else { sys_seph::io_tx(self.apdu_type, &self.io_buffer, self.tx_length); } self.tx_length = 0; @@ -261,7 +258,7 @@ impl Comm { if status > 0 { return self.detect_apdu::(status); } - return false + return false; } pub fn check_event(&mut self) -> Option> @@ -287,10 +284,7 @@ impl Comm { } // Manage BOLOS specific APDUs B0xx0000 - if self.io_buffer[1] == 0xB0 - && self.io_buffer[3] == 0x00 - && self.io_buffer[4] == 0x00 - { + if self.io_buffer[1] == 0xB0 && self.io_buffer[3] == 0x00 && self.io_buffer[4] == 0x00 { handle_bolos_apdu(self, self.io_buffer[2]); return None; } @@ -327,13 +321,12 @@ impl Comm { let tag = seph_buffer[0]; let _len: usize = u16::from_be_bytes([seph_buffer[1], seph_buffer[2]]) as usize; - if (length as usize) < _len+3 { + if (length as usize) < _len + 3 { self.reply(StatusWords::BadLen); - return None + return None; } match seph::Events::from(tag) { - // BUTTON PUSH EVENT #[cfg(not(any(target_os = "stax", target_os = "flex")))] seph::Events::ButtonPushEvent => { @@ -352,7 +345,7 @@ impl Comm { seph::Events::ScreenTouchEvent => unsafe { ux_process_finger_event(seph_buffer.as_mut_ptr()); return Some(Event::TouchEvent); - } + }, // TICKER EVENT seph::Events::TickerEvent => { @@ -367,29 +360,26 @@ impl Comm { seph::Events::ItcEvent => { #[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] match ItcUxEvent::from(seph_buffer[3]) { - - seph::ItcUxEvent::AskBlePairing => { - unsafe { - G_ux_params.ux_id = BOLOS_UX_ASYNCHMODAL_PAIRING_REQUEST; - G_ux_params.len = 20; - G_ux_params.u.pairing_request.type_ = seph_buffer[4]; - G_ux_params.u.pairing_request.pairing_info_len = (_len-2) as u32; - for i in 0..G_ux_params.u.pairing_request.pairing_info_len as usize { - G_ux_params.u.pairing_request.pairing_info[i as usize] = seph_buffer[5+i] as i8; - } - G_ux_params.u.pairing_request.pairing_info[G_ux_params.u.pairing_request.pairing_info_len as usize] = 0; - os_ux(&raw mut G_ux_params as *mut bolos_ux_params_t); + seph::ItcUxEvent::AskBlePairing => unsafe { + G_ux_params.ux_id = BOLOS_UX_ASYNCHMODAL_PAIRING_REQUEST; + G_ux_params.len = 20; + G_ux_params.u.pairing_request.type_ = seph_buffer[4]; + G_ux_params.u.pairing_request.pairing_info_len = (_len - 2) as u32; + for i in 0..G_ux_params.u.pairing_request.pairing_info_len as usize { + G_ux_params.u.pairing_request.pairing_info[i as usize] = + seph_buffer[5 + i] as i8; } - } - - seph::ItcUxEvent::BlePairingStatus => { - unsafe { - G_ux_params.ux_id = BOLOS_UX_ASYNCHMODAL_PAIRING_STATUS; - G_ux_params.len = 0; - G_ux_params.u.pairing_status.pairing_ok = seph_buffer[4]; - os_ux(&raw mut G_ux_params as *mut bolos_ux_params_t); - } - } + G_ux_params.u.pairing_request.pairing_info + [G_ux_params.u.pairing_request.pairing_info_len as usize] = 0; + os_ux(&raw mut G_ux_params as *mut bolos_ux_params_t); + }, + + seph::ItcUxEvent::BlePairingStatus => unsafe { + G_ux_params.ux_id = BOLOS_UX_ASYNCHMODAL_PAIRING_STATUS; + G_ux_params.len = 0; + G_ux_params.u.pairing_status.pairing_ok = seph_buffer[4]; + os_ux(&raw mut G_ux_params as *mut bolos_ux_params_t); + }, seph::ItcUxEvent::Redisplay => { #[cfg(any(target_os = "stax", target_os = "flex", feature = "nano_nbgl"))] @@ -400,11 +390,9 @@ impl Comm { } } - _ => { - return None - } + _ => return None, } - return None + return None; } // DEFAULT EVENT @@ -422,7 +410,7 @@ impl Comm { None } - pub fn decode_event(&mut self, length:i32) -> Option> + pub fn decode_event(&mut self, length: i32) -> Option> where T: TryFrom, Reply: From<>::Error>, @@ -434,18 +422,19 @@ impl Comm { // SE or SEPH event let mut seph_buffer = [0u8; 272]; seph_buffer[0..272].copy_from_slice(&self.io_buffer[1..273]); - if let Some(event) = self.process_event(seph_buffer, length-1) { + if let Some(event) = self.process_event(seph_buffer, length - 1) { return Some(event); } } - seph::PacketTypes::PacketTypeRawApdu | - seph::PacketTypes::PacketTypeUsbHidApdu | - seph::PacketTypes::PacketTypeUsbWebusbApdu | - seph::PacketTypes::PacketTypeBleApdu=> { + seph::PacketTypes::PacketTypeRawApdu + | seph::PacketTypes::PacketTypeUsbHidApdu + | seph::PacketTypes::PacketTypeUsbWebusbApdu + | seph::PacketTypes::PacketTypeBleApdu => { unsafe { if os_perso_is_pin_set() == BOLOS_TRUE.try_into().unwrap() - && os_global_pin_is_validated() != BOLOS_TRUE.try_into().unwrap() { + && os_global_pin_is_validated() != BOLOS_TRUE.try_into().unwrap() + { self.reply(StatusWords::DeviceLocked); return None; } @@ -453,18 +442,17 @@ impl Comm { self.apdu_buffer[0..272].copy_from_slice(&self.io_buffer[1..273]); self.apdu_type = packet_type; self.rx_length = length as usize; - self.rx = self.rx_length-1; + self.rx = self.rx_length - 1; self.event_pending = true; return self.check_event(); } - _ => { - } + _ => {} } None } - fn detect_apdu(&mut self, length:i32) -> bool + fn detect_apdu(&mut self, length: i32) -> bool where T: TryFrom, Reply: From<>::Error>, @@ -472,7 +460,7 @@ impl Comm { match self.decode_event::(length) { Some(Event::Command(_)) => { self.rx_length = length as usize; - self.rx = self.rx_length-1; + self.rx = self.rx_length - 1; self.event_pending = true; return true; } @@ -585,8 +573,7 @@ impl Comm { (0, 6) => Ok(&[]), // Non-conforming zero-data APDU (0, 7) => Err(StatusWords::BadLen), (0, _) => { - let len = - u16::from_le_bytes([self.io_buffer[6], self.io_buffer[7]]) as usize; + let len = u16::from_le_bytes([self.io_buffer[6], self.io_buffer[7]]) as usize; get_data_from_buffer(len, 8) } (len, _) => get_data_from_buffer(len, 6), diff --git a/ledger_device_sdk/src/seph.rs b/ledger_device_sdk/src/seph.rs index d2021fce..107c97c5 100644 --- a/ledger_device_sdk/src/seph.rs +++ b/ledger_device_sdk/src/seph.rs @@ -73,7 +73,6 @@ impl From for ItcUxEvent { } } - /// FFI bindings to USBD functions inlined here for clarity /// and also because some of the generated ones are incorrectly /// assuming mutable pointers when they are not diff --git a/ledger_secure_sdk_sys/build.rs b/ledger_secure_sdk_sys/build.rs index caf0edbf..06c60c5f 100644 --- a/ledger_secure_sdk_sys/build.rs +++ b/ledger_secure_sdk_sys/build.rs @@ -21,7 +21,7 @@ const SDK_C_FILES: [&str; 13] = [ "io/src/os_io.c", "io/src/os_io_default_apdu.c", "io/src/os_io_seph_cmd.c", - "io/src/os_io_seph_ux.c" + "io/src/os_io_seph_ux.c", ]; const CFLAGS_NANOSPLUS: [&str; 22] = [ diff --git a/ledger_secure_sdk_sys/src/seph.rs b/ledger_secure_sdk_sys/src/seph.rs index c303e4d2..dfc5e749 100644 --- a/ledger_secure_sdk_sys/src/seph.rs +++ b/ledger_secure_sdk_sys/src/seph.rs @@ -1,13 +1,24 @@ -use crate::{ - os_io_rx_evt, - os_io_tx_cmd, -}; +use crate::{os_io_rx_evt, os_io_tx_cmd}; /// Receive the next APDU into 'buffer' pub fn io_rx(buffer: &mut [u8], check_se_event: bool) -> i32 { - unsafe { os_io_rx_evt(buffer.as_ptr() as _, buffer.len() as u16, core::ptr::null_mut(), check_se_event) } + unsafe { + os_io_rx_evt( + buffer.as_ptr() as _, + buffer.len() as u16, + core::ptr::null_mut(), + check_se_event, + ) + } } -pub fn io_tx(apdu_type: u8, buffer: &[u8], length:usize) -> i32 { - unsafe { os_io_tx_cmd(apdu_type, buffer.as_ptr() as _, length as u16, core::ptr::null_mut()) } +pub fn io_tx(apdu_type: u8, buffer: &[u8], length: usize) -> i32 { + unsafe { + os_io_tx_cmd( + apdu_type, + buffer.as_ptr() as _, + length as u16, + core::ptr::null_mut(), + ) + } } From 6c8144e5704f0e0e3919ddf4d1cde829d35e5bbb Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 2 Jul 2025 15:56:36 +0200 Subject: [PATCH 09/20] Install last speculos 0.23.0 to run tests --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 74bf409f..2c109add 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,6 +90,7 @@ jobs: git clone https://github.com/LedgerHQ/ledger-secure-sdk.git --branch API_LEVEL_24 --single-branch c_sdk echo "setting LEDGER_SDK_PATH to $(realpath c_sdk)" export LEDGER_SDK_PATH=$(realpath c_sdk) + pip install speculos --break-system-packages # ####################################### # cargo test --target ${{ matrix.target }} --features speculos,debug --tests From 8fe89da9e19a017834f303f7f53642807f5c57f5 Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 2 Jul 2025 16:07:07 +0200 Subject: [PATCH 10/20] Upgrade speculos --- .github/workflows/ci.yml | 2 +- ledger_device_sdk/src/ble.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 ledger_device_sdk/src/ble.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c109add..972da316 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,7 +90,7 @@ jobs: git clone https://github.com/LedgerHQ/ledger-secure-sdk.git --branch API_LEVEL_24 --single-branch c_sdk echo "setting LEDGER_SDK_PATH to $(realpath c_sdk)" export LEDGER_SDK_PATH=$(realpath c_sdk) - pip install speculos --break-system-packages + pip install -U speculos --break-system-packages # ####################################### # cargo test --target ${{ matrix.target }} --features speculos,debug --tests diff --git a/ledger_device_sdk/src/ble.rs b/ledger_device_sdk/src/ble.rs deleted file mode 100644 index 8b137891..00000000 --- a/ledger_device_sdk/src/ble.rs +++ /dev/null @@ -1 +0,0 @@ - From 5d227b65f843e4369822e335480566a966f4f68d Mon Sep 17 00:00:00 2001 From: GroM Date: Wed, 2 Jul 2025 16:10:55 +0200 Subject: [PATCH 11/20] Delete useless ble module --- ledger_device_sdk/src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/ledger_device_sdk/src/lib.rs b/ledger_device_sdk/src/lib.rs index 63ba76f9..b325066a 100644 --- a/ledger_device_sdk/src/lib.rs +++ b/ledger_device_sdk/src/lib.rs @@ -7,9 +7,6 @@ #![feature(generic_const_exprs)] #![feature(cfg_version)] -#[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] -pub mod ble; - pub mod ecc; pub mod hash; pub mod hmac; From 9bb89d92f78f2574179ea41ce5364c1550c43291 Mon Sep 17 00:00:00 2001 From: Stephane Portron Date: Wed, 2 Jul 2025 17:36:03 +0200 Subject: [PATCH 12/20] [io]: Handle get_event with revamp --- ledger_device_sdk/src/io.rs | 2 +- ledger_device_sdk/src/ui/gadgets.rs | 37 ++++++++++++++--------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index dd945677..a981047f 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -313,7 +313,7 @@ impl Comm { None } - pub fn process_event(&mut self, mut seph_buffer: [u8; 272], length: i32) -> Option> + pub fn process_event(&mut self, seph_buffer: [u8; 272], length: i32) -> Option> where T: TryFrom, Reply: From<>::Error>, diff --git a/ledger_device_sdk/src/ui/gadgets.rs b/ledger_device_sdk/src/ui/gadgets.rs index bf23c9ae..8a0ce16a 100644 --- a/ledger_device_sdk/src/ui/gadgets.rs +++ b/ledger_device_sdk/src/ui/gadgets.rs @@ -4,9 +4,8 @@ use crate::{ uxapp::{UxEvent, BOLOS_UX_OK}, }; use ledger_secure_sdk_sys::{ - //buttons::{get_button_event, ButtonEvent, ButtonsState}, - buttons::{ButtonEvent, ButtonsState}, - //seph, + buttons::{get_button_event, ButtonEvent, ButtonsState}, + seph, }; use crate::ui::bitmaps::{Glyph, WARNING}; @@ -23,23 +22,23 @@ const MAX_CHAR_PER_LINE: usize = 17; /// Handles communication to filter /// out actual events, and converts key /// events into presses/releases -/// TODO_IO -pub fn get_event(_buttons: &mut ButtonsState) -> Option { - /*if !seph::is_status_sent() { - seph::send_general_status(); - } - - // TODO: Receiving an APDU while in UX will lead to .. exit ? - while seph::is_status_sent() { - seph::seph_recv(&mut buttons.cmd_buffer, 0); - let tag = buttons.cmd_buffer[0]; - - // button push event - if tag == 0x05 { - let button_info = buttons.cmd_buffer[3] >> 1; - return get_button_event(buttons, button_info); +pub fn get_event(buttons: &mut ButtonsState) -> Option { + let mut io_buffer = [0u8; 273]; + let status = seph::io_rx(&mut io_buffer, true); + if status > 0 { + let packet_type = io_buffer[0]; + match packet_type { + 0x01 | 0x02 => { + // SE or SEPH event + if io_buffer[1] == 0x05 { + let button_info = io_buffer[4] >> 1; + return get_button_event(buttons, button_info); + } + } + _ => { + } } - }*/ + } None } From e5c0b9c26867c5d54003c1a630836fe4df9b62c0 Mon Sep 17 00:00:00 2001 From: GroM Date: Thu, 3 Jul 2025 10:08:18 +0200 Subject: [PATCH 13/20] [io] seph_buffer shall be mutable for NBGL --- ledger_device_sdk/src/io.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index a981047f..dd945677 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -313,7 +313,7 @@ impl Comm { None } - pub fn process_event(&mut self, seph_buffer: [u8; 272], length: i32) -> Option> + pub fn process_event(&mut self, mut seph_buffer: [u8; 272], length: i32) -> Option> where T: TryFrom, Reply: From<>::Error>, From 6054c0a635f82c1d8ff8a2ede8f8ea3b092a42b1 Mon Sep 17 00:00:00 2001 From: GroM Date: Thu, 3 Jul 2025 10:13:39 +0200 Subject: [PATCH 14/20] run cargo fmt --- ledger_device_sdk/src/ui/gadgets.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ledger_device_sdk/src/ui/gadgets.rs b/ledger_device_sdk/src/ui/gadgets.rs index 8a0ce16a..faccf122 100644 --- a/ledger_device_sdk/src/ui/gadgets.rs +++ b/ledger_device_sdk/src/ui/gadgets.rs @@ -35,8 +35,7 @@ pub fn get_event(buttons: &mut ButtonsState) -> Option { return get_button_event(buttons, button_info); } } - _ => { - } + _ => {} } } None From 4994bf41a3a2e1a24f7048916a22b79164eef61a Mon Sep 17 00:00:00 2001 From: Stephane Portron Date: Thu, 3 Jul 2025 18:48:12 +0200 Subject: [PATCH 15/20] [io] : fix get_data function --- ledger_device_sdk/src/io.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index dd945677..ec868cbd 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -558,25 +558,26 @@ impl Comm { } pub fn get_data(&self) -> Result<&[u8], StatusWords> { - if self.rx_length == 5 { + if self.rx == 4 { Ok(&[]) // Conforming zero-data APDU } else { - let first_len_byte = self.io_buffer[5] as usize; + let first_len_byte = self.apdu_buffer[4] as usize; let get_data_from_buffer = |len, offset| { - if len == 0 || len + offset > self.rx_length { + if len == 0 || len + offset > self.rx { Err(StatusWords::BadLen) } else { - Ok(&self.io_buffer[offset..offset + len]) + Ok(&self.apdu_buffer[offset..offset + len]) } }; - match (first_len_byte, self.rx_length) { - (0, 6) => Ok(&[]), // Non-conforming zero-data APDU - (0, 7) => Err(StatusWords::BadLen), + match (first_len_byte, self.rx) { + (0, 5) => Ok(&[]), // Non-conforming zero-data APDU + (0, 6) => Err(StatusWords::BadLen), (0, _) => { - let len = u16::from_le_bytes([self.io_buffer[6], self.io_buffer[7]]) as usize; - get_data_from_buffer(len, 8) + let len = + u16::from_le_bytes([self.apdu_buffer[5], self.apdu_buffer[6]]) as usize; + get_data_from_buffer(len, 7) } - (len, _) => get_data_from_buffer(len, 6), + (len, _) => get_data_from_buffer(len, 5), } } } From a61da40a0ee41f6b7336d10fd2b6a01dc5055c44 Mon Sep 17 00:00:00 2001 From: GroM Date: Mon, 7 Jul 2025 17:30:59 +0200 Subject: [PATCH 16/20] [io] swap_reply() shall be the same as reply() --- ledger_device_sdk/src/io.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index ec868cbd..1234fee1 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -184,7 +184,7 @@ impl Comm { /// Send the currently held APDU // This is private. Users should call reply to set the satus word and // transmit the response. - fn apdu_send(&mut self, _is_swap: bool) { + fn apdu_send(&mut self) { if self.tx != 0 { sys_seph::io_tx(self.apdu_type, &self.apdu_buffer, self.tx); self.tx = 0; @@ -527,17 +527,11 @@ impl Comm { self.io_buffer[self.tx_length + 1] = sw as u8; self.tx_length += 2; // Transmit the response - self.apdu_send(false); + self.apdu_send(); } pub fn swap_reply>(&mut self, reply: T) { - let sw = reply.into().0; - // Append status word - self.io_buffer[self.tx_length] = (sw >> 8) as u8; - self.io_buffer[self.tx_length + 1] = sw as u8; - self.tx_length += 2; - // Transmit the response - self.apdu_send(true); + self.reply(reply); } /// Set the Status Word of the response to `StatusWords::OK` (which is equal @@ -547,7 +541,7 @@ impl Comm { } pub fn swap_reply_ok(&mut self) { - self.swap_reply(StatusWords::Ok); + self.reply_ok(); } /// Return APDU Metadata From dbf46b06cdd20c05018a300e157d4683f2c99800 Mon Sep 17 00:00:00 2001 From: GroM Date: Thu, 10 Jul 2025 09:37:05 +0200 Subject: [PATCH 17/20] [io] Get Ticker events befeore sending APDU (cherry picked from commit f48979a3ba4d20e2c98e9dec5872fc66f3ac0fa3) --- ledger_device_sdk/src/io.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index 1234fee1..3cbca440 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -185,6 +185,23 @@ impl Comm { // This is private. Users should call reply to set the satus word and // transmit the response. fn apdu_send(&mut self) { + #[cfg(any(target_os = "stax", target_os = "flex", feature = "nano_nbgl"))] + { + let mut buffer: [u8; 273] = [0; 273]; + let status = sys_seph::io_rx(&mut buffer, false); + if status > 0 { + let packet_type = seph::PacketTypes::from(buffer[0]); + let event = seph::Events::from(buffer[1]); + match (packet_type, event) { + (seph::PacketTypes::PacketTypeSeph, seph::Events::TickerEvent) => { + unsafe { + ux_process_ticker_event(); + } + } + (_, _) => {} + } + } + } if self.tx != 0 { sys_seph::io_tx(self.apdu_type, &self.apdu_buffer, self.tx); self.tx = 0; From 7c3a0078b36df714382e37f6f7bdbd7139e19163 Mon Sep 17 00:00:00 2001 From: GroM Date: Thu, 10 Jul 2025 16:57:41 +0200 Subject: [PATCH 18/20] Run cargo fmt --- ledger_device_sdk/src/io.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index 3cbca440..5017a38e 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -193,11 +193,9 @@ impl Comm { let packet_type = seph::PacketTypes::from(buffer[0]); let event = seph::Events::from(buffer[1]); match (packet_type, event) { - (seph::PacketTypes::PacketTypeSeph, seph::Events::TickerEvent) => { - unsafe { - ux_process_ticker_event(); - } - } + (seph::PacketTypes::PacketTypeSeph, seph::Events::TickerEvent) => unsafe { + ux_process_ticker_event(); + }, (_, _) => {} } } From 8c03b5270350464b484709d2398ee9b68f13bd1b Mon Sep 17 00:00:00 2001 From: GroM Date: Fri, 11 Jul 2025 11:30:27 +0200 Subject: [PATCH 19/20] [uxapp] Keep DelayLock for NBGL usecase --- ledger_device_sdk/src/uxapp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ledger_device_sdk/src/uxapp.rs b/ledger_device_sdk/src/uxapp.rs index 58d4ca87..4ba807cf 100644 --- a/ledger_device_sdk/src/uxapp.rs +++ b/ledger_device_sdk/src/uxapp.rs @@ -42,7 +42,7 @@ impl UxEvent { Self::ValidatePIN as u8 } Self::DelayLock => { - #[cfg(any(target_os = "nanox", target_os = "stax", target_os = "flex"))] + #[cfg(any(target_os = "stax", target_os = "flex", feature = "nano_nbgl"))] { G_ux_params.u.lock_delay.delay_ms = 10000; } From d927290079d7cb5dd38d34f2b55abce76a84549c Mon Sep 17 00:00:00 2001 From: GroM Date: Tue, 22 Jul 2025 13:37:53 +0200 Subject: [PATCH 20/20] Bump versions --- Cargo.lock | 4 ++-- ledger_device_sdk/Cargo.toml | 4 ++-- ledger_secure_sdk_sys/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e10d601a..b717cdef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,7 +327,7 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" [[package]] name = "ledger_device_sdk" -version = "1.22.14" +version = "1.23.0" dependencies = [ "const-zero", "include_gif", @@ -342,7 +342,7 @@ dependencies = [ [[package]] name = "ledger_secure_sdk_sys" -version = "1.8.3" +version = "1.9.0" dependencies = [ "bindgen", "cc", diff --git a/ledger_device_sdk/Cargo.toml b/ledger_device_sdk/Cargo.toml index cf3c8d7d..33e900b1 100644 --- a/ledger_device_sdk/Cargo.toml +++ b/ledger_device_sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ledger_device_sdk" -version = "1.22.14" +version = "1.23.0" authors = ["yhql", "yogh333", "agrojean-ledger", "kingofpayne"] edition = "2021" license.workspace = true @@ -21,7 +21,7 @@ rand_core = { version = "0.6.3", default-features = false } zeroize = { version = "1.6.0", default-features = false } numtoa = "0.2.4" const-zero = "0.1.1" -ledger_secure_sdk_sys = { path = "../ledger_secure_sdk_sys", version = "1.8.3" } +ledger_secure_sdk_sys = { path = "../ledger_secure_sdk_sys", version = "1.9.0" } [features] debug = [] diff --git a/ledger_secure_sdk_sys/Cargo.toml b/ledger_secure_sdk_sys/Cargo.toml index 5878e3cf..16bba9e9 100644 --- a/ledger_secure_sdk_sys/Cargo.toml +++ b/ledger_secure_sdk_sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ledger_secure_sdk_sys" -version = "1.8.3" +version = "1.9.0" authors = ["yhql", "agrojean-ledger", "yogh333"] edition = "2021" license.workspace = true