diff --git a/components/dispatch-fido/Cargo.toml b/components/dispatch-fido/Cargo.toml deleted file mode 100644 index 43df34cb..00000000 --- a/components/dispatch-fido/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "dispatch-fido" -version = "0.1.0" -authors = ["Conor Patrick "] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -delog = "0.1.0" -heapless = "0.6" -heapless-bytes = "0.3" -interchange = "0.2.0" -serde = { version = "1", default-features = false } - -apdu-dispatch = { git = "https://github.com/solokeys/apdu-dispatch" } -ctaphid-dispatch = { git = "https://github.com/solokeys/ctaphid-dispatch" } -ctap-types = { git = "https://github.com/solokeys/ctap-types" } -fido-authenticator = { git = "https://github.com/Nitrokey/fido-authenticator" } -iso7816 = { git = "https://github.com/ycrypto/iso7816" } -trussed = { git = "https://github.com/trussed-dev/trussed" } - -[features] -default = [] - -log-all = [] -log-none = [] -log-info = [] -log-debug = [] -log-warn = [] -log-error = [] diff --git a/components/dispatch-fido/src/cbor.rs b/components/dispatch-fido/src/cbor.rs deleted file mode 100644 index dc403b83..00000000 --- a/components/dispatch-fido/src/cbor.rs +++ /dev/null @@ -1,155 +0,0 @@ -use core::convert::From; -use core::convert::TryFrom; -use ctap_types::{ - authenticator::{Request, Error as AuthenticatorError}, - operation::Operation, - serde::{cbor_deserialize, error::Error as SerdeError}, -}; - -pub enum CtapMappingError { - InvalidCommand(u8), - ParsingError(SerdeError), -} - -impl From for AuthenticatorError { - fn from(mapping_error: CtapMappingError) -> AuthenticatorError { - match mapping_error { - CtapMappingError::InvalidCommand(_cmd) => { - AuthenticatorError::InvalidCommand - } - CtapMappingError::ParsingError(cbor_error) => { - match cbor_error { - SerdeError::SerdeMissingField => AuthenticatorError::MissingParameter, - _ => AuthenticatorError::InvalidCbor - } - } - } - - } -} - -pub fn parse_cbor(data: &[u8]) -> core::result::Result { - - if data.len() < 1 { - return Err(CtapMappingError::ParsingError(SerdeError::DeserializeUnexpectedEnd)); - } - - let operation_u8: u8 = data[0]; - - let operation = match Operation::try_from(operation_u8) { - Ok(operation) => { - operation - }, - _ => { - return Err(CtapMappingError::InvalidCommand(operation_u8)); - } - }; - - // use ctap_types::ctap2::*; - use ctap_types::authenticator::*; - - match operation { - Operation::MakeCredential => { - info!("authenticatorMakeCredential"); - match cbor_deserialize(&data[1..]) { - Ok(params) => { - Ok(Request::Ctap2(ctap2::Request::MakeCredential(params))) - }, - Err(error) => { - Err(CtapMappingError::ParsingError(error)) - } - } - // TODO: ensure earlier that RPC send queue is empty - } - - Operation::GetAssertion => { - info!("authenticatorGetAssertion"); - - match cbor_deserialize(&data[1..]) { - Ok(params) => { - Ok(Request::Ctap2(ctap2::Request::GetAssertion(params))) - }, - Err(error) => { - Err(CtapMappingError::ParsingError(error)) - } - } - // TODO: ensure earlier that RPC send queue is empty - } - - Operation::GetNextAssertion => { - info!("authenticatorGetNextAssertion"); - - // TODO: ensure earlier that RPC send queue is empty - Ok(Request::Ctap2(ctap2::Request::GetNextAssertion)) - } - - Operation::CredentialManagement => { - info!("authenticatorCredentialManagement"); - - match cbor_deserialize(&data[1..]) { - Ok(params) => { - Ok(Request::Ctap2(ctap2::Request::CredentialManagement(params))) - }, - Err(error) => { - Err(CtapMappingError::ParsingError(error)) - } - } - // TODO: ensure earlier that RPC send queue is empty - } - - Operation::Reset => { - info!("authenticatorReset"); - - // TODO: ensure earlier that RPC send queue is empty - Ok(Request::Ctap2(ctap2::Request::Reset)) - } - - Operation::GetInfo => { - info!("authenticatorGetInfo"); - // TODO: ensure earlier that RPC send queue is empty - Ok(Request::Ctap2(ctap2::Request::GetInfo)) - } - - Operation::ClientPin => { - info!("authenticatorClientPin"); - match cbor_deserialize(&data[1..]) - { - Ok(params) => { - - Ok(Request::Ctap2(ctap2::Request::ClientPin(params))) - }, - Err(error) => { - - Err(CtapMappingError::ParsingError(error)) - } - } - // TODO: ensure earlier that RPC send queue is empty - } - - Operation::Vendor(vendor_operation) => { - info!("authenticatorVendor({:?})", &vendor_operation); - - let vo_u8: u8 = vendor_operation.into(); - if vo_u8 == 0x41 { - // copy-pasta for now - match cbor_deserialize(&data[1..]) - { - Ok(params) => { - Ok(Request::Ctap2(ctap2::Request::CredentialManagement(params))) - }, - Err(error) => { - Err(CtapMappingError::ParsingError(error)) - } - } - // TODO: ensure earlier that RPC send queue is empty - - } else { - // TODO: ensure earlier that RPC send queue is empty - Ok(Request::Ctap2(ctap2::Request::Vendor(vendor_operation))) - } - } - _ => { - Err(CtapMappingError::InvalidCommand(operation_u8)) - } - } -} diff --git a/components/dispatch-fido/src/fido.rs b/components/dispatch-fido/src/fido.rs deleted file mode 100644 index dd4b9b83..00000000 --- a/components/dispatch-fido/src/fido.rs +++ /dev/null @@ -1,296 +0,0 @@ -use core::convert::TryFrom; -use iso7816::{Instruction, Status}; -use apdu_dispatch::{Command, response, app}; -use ctaphid_dispatch::command::Command as FidoCommand; -use ctap_types::{ - authenticator::Error as AuthenticatorError, - authenticator::Request as AuthenticatorRequest, - serde::{cbor_serialize}, - ctap1::{Command as U2fCommand}, -}; - -use crate::cbor::{parse_cbor}; - -use trussed::client; -use fido_authenticator::{Authenticator, UserPresence}; -use ctaphid_dispatch::app as hid; - -pub struct Fido -where UP: UserPresence, -{ - authenticator: Authenticator, -} - -impl Fido -where UP: UserPresence, - Trussed: client::Client - + client::P256 - + client::Chacha8Poly1305 - + client::Aes256Cbc - + client::Sha256 - + client::HmacSha256 - + client::Ed255 - + client::Totp -{ - pub fn new(authenticator: Authenticator) -> Fido { - Self { authenticator } - } - - fn response_from_object(&mut self, object: Option, reply: &mut response::Data) -> app::Result { - reply.resize_default(reply.capacity()).ok(); - if let Some(object) = object { - match cbor_serialize(&object, &mut reply[1..]) { - Ok(ser) => { - let l = ser.len(); - reply[0] = 0; - reply.resize_default(l + 1).unwrap(); - } - Err(_) => { - reply[0] = AuthenticatorError::Other as u8; - reply.resize_default(1).unwrap(); - } - } - } else { - reply[0] = 0; - reply.resize_default(1).unwrap(); - } - Ok(()) - } - - fn call_authenticator(&mut self, request: &AuthenticatorRequest, reply: &mut response::Data) -> app::Result { - - let result = self.authenticator.call(request); - match &result { - Err(error) => { - info!("error {}", *error as u8); - reply.push(*error as u8).ok(); - Ok(()) - } - - Ok(response) => { - use ctap_types::authenticator::Response; - match response { - Response::Ctap1(_response) => { - todo!("CTAP1 responses"); - } - - Response::Ctap2(response) => { - use ctap_types::authenticator::ctap2::Response; - match response { - Response::GetInfo(response) => { - self.response_from_object(Some(response), reply) - }, - - Response::MakeCredential(response) => { - self.response_from_object(Some(response), reply) - }, - - Response::ClientPin(response) => { - self.response_from_object(Some(response), reply) - }, - - Response::GetAssertion(response) => { - self.response_from_object(Some(response), reply) - }, - - Response::GetNextAssertion(response) => { - self.response_from_object(Some(response), reply) - }, - - Response::CredentialManagement(response) => { - self.response_from_object(Some(response), reply) - }, - - Response::Reset => { - self.response_from_object::<()>(None, reply) - }, - - Response::Vendor => { - self.response_from_object::<()>(None, reply) - }, - } - } - } - } - } - } - - #[inline(never)] - fn call_authenticator_u2f_with_bytes(&mut self, request: &response::Data, reply: &mut response::Data) -> app::Result { - match &Command::try_from(request) { - Ok(command) => { - self.call_authenticator_u2f(command, reply) - }, - _ => { - Err(Status::IncorrectDataParameter) - } - } - } - - #[inline(never)] - fn call_authenticator_u2f(&mut self, apdu: &Command, reply: &mut response::Data) -> app::Result { - let u2f_command = U2fCommand::try_from(apdu)?; - let result = self.authenticator.call_u2f(&u2f_command); - match result { - Ok(u2f_response) => { - u2f_response.serialize(reply).unwrap(); - Ok(()) - } - Err(err)=> Err(err) - } - } - - - -} - -impl iso7816::App for Fido -where UP: UserPresence, -{ - fn aid(&self) -> iso7816::Aid { - iso7816::Aid::new(&[ 0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01]) - } -} - -impl app::App< - {apdu_dispatch::command::SIZE}, - {apdu_dispatch::response::SIZE}, -> for Fido -where UP: UserPresence, - T: client::Client - + client::P256 - + client::Chacha8Poly1305 - + client::Aes256Cbc - + client::Sha256 - + client::HmacSha256 - + client::Ed255 - + client::Totp -{ - - - fn select(&mut self, _apdu: &Command, reply: &mut response::Data) -> app::Result { - // U2F_V2 - reply.extend_from_slice(& [0x55, 0x32, 0x46, 0x5f, 0x56, 0x32,]).unwrap(); - Ok(()) - } - - fn deselect(&mut self) {} - - fn call(&mut self, _type: app::Interface, apdu: &Command, reply: &mut response::Data) -> app::Result { - let instruction = apdu.instruction(); - - match instruction { - Instruction::Unknown(ins) => { - // TODO need to tidy up these ins codes somewhere - match ins { - // U2F ins codes - 0x00 | 0x01 | 0x02 => { - self.call_authenticator_u2f(apdu, reply) - } - _ => { - match FidoCommand::try_from(ins) { - Ok(FidoCommand::Cbor) => { - match parse_cbor(apdu.data()) { - Ok(request) => { - info!("parsed cbor"); - self.call_authenticator(&request, reply) - } - Err(mapping_error) => { - let authenticator_error: AuthenticatorError = mapping_error.into(); - info!("cbor mapping error: {}", authenticator_error as u8); - reply.push(authenticator_error as u8).ok(); - Ok(()) - } - } - } - Ok(FidoCommand::Msg) => { - self.call_authenticator_u2f(apdu, reply) - } - Ok(FidoCommand::Deselect) => { - self.deselect(); - Ok(()) - } - _ => { - info!("Unsupported ins for fido app {:02x}", ins); - Err(Status::InstructionNotSupportedOrInvalid) - } - } - } - } - - } - _ => { - info!("Unsupported ins for fido app"); - Err(Status::InstructionNotSupportedOrInvalid) - } - } - } - -} - -impl hid::App for Fido -where UP: UserPresence, - T: client::Client - + client::P256 - + client::Chacha8Poly1305 - + client::Aes256Cbc - + client::Sha256 - + client::HmacSha256 - + client::Ed255 - + client::Totp -{ - - fn commands(&self,) -> &'static [hid::Command] { - &[ hid::Command::Cbor, hid::Command::Msg ] - } - - #[inline(never)] - fn call(&mut self, command: hid::Command, request: &hid::Message, response: &mut hid::Message) -> hid::AppResult { - - if request.len() < 1 { - return Err(hid::Error::InvalidLength); - } - // info_now!("request: "); - // blocking::dump_hex(request, request.len()); - match command { - hid::Command::Cbor => { - match parse_cbor(request) { - Ok(request) => { - self.call_authenticator(&request, response).ok(); - Ok(()) - } - Err(mapping_error) => { - let authenticator_error: AuthenticatorError = mapping_error.into(); - info!("authenticator_error: {}", authenticator_error as u8); - response.extend_from_slice(&[ - authenticator_error as u8 - ]).ok(); - Ok(()) - } - } - }, - // hid::Command::Msg is only other registered command. - _ => { - let result = self.call_authenticator_u2f_with_bytes(request, response); - match result { - Ok(()) => { - info!("U2F response {} bytes", response.len()); - // Need to add x9000 success code (normally the apdu-dispatch does this, but - // since u2f uses apdus over hid, we must do it here.) - response.extend_from_slice(&[0x90, 0x00]).ok(); - }, - Err(status) => { - let code: [u8; 2] = status.into(); - info!("U2F error. {}", hex_str!(&code)); - response.extend_from_slice(&code).ok(); - }, - } - Ok(()) - - }, - } - - } - - -} diff --git a/components/dispatch-fido/src/lib.rs b/components/dispatch-fido/src/lib.rs deleted file mode 100644 index 9591f899..00000000 --- a/components/dispatch-fido/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! # dispatch-fido -//! -//! This library implements the `apdu-dispatch` and `ctaphid-dispatch` App traits -//! for the `fido-authenticator`, allowing it to be called over both interfaces -//! in the Solo 2 security key. -#![no_std] - -#[macro_use] -extern crate delog; -generate_macros!(); - -pub mod fido; -pub use fido::*; - -pub mod cbor; diff --git a/components/ndef-app/Cargo.toml b/components/ndef-app/Cargo.toml index b47a7ad9..4ae69cf6 100644 --- a/components/ndef-app/Cargo.toml +++ b/components/ndef-app/Cargo.toml @@ -9,5 +9,5 @@ edition = "2018" [dependencies] heapless = "0.7" -apdu-dispatch = { git = "https://github.com/solokeys/apdu-dispatch" } -iso7816 = { git = "https://github.com/ycrypto/iso7816" } +apdu-dispatch = "0.1" +iso7816 = "0.1" diff --git a/components/nfc-device/Cargo.toml b/components/nfc-device/Cargo.toml index 3de57a43..e663d6f4 100644 --- a/components/nfc-device/Cargo.toml +++ b/components/nfc-device/Cargo.toml @@ -10,8 +10,8 @@ embedded-time = "0.12" heapless = "0.7" nb = "1" -apdu-dispatch = { git = "https://github.com/solokeys/apdu-dispatch" } -iso7816 = { git = "https://github.com/ycrypto/iso7816" } +apdu-dispatch = "0.1" +iso7816 = "0.1" interchange = "0.2.1" [features] diff --git a/components/provisioner-app/Cargo.toml b/components/provisioner-app/Cargo.toml index 59b23b5c..4bf93bc8 100644 --- a/components/provisioner-app/Cargo.toml +++ b/components/provisioner-app/Cargo.toml @@ -7,14 +7,14 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -apdu-dispatch = { git = "https://github.com/solokeys/apdu-dispatch" } -delog = "0.1.1" +apdu-dispatch = "0.1" +delog = "0.1" heapless = "0.7" heapless-bytes = "0.3" lpc55-hal = { version = "0.3", features = ["littlefs", "rtic-peripherals"] } littlefs2 = "0.3.1" salty = { version = "0.2", features = ["cose"] } -trussed = { git = "https://github.com/trussed-dev/trussed" } +trussed = "0.1" [dependencies.nisty] version = "0.1.0-alpha.5" diff --git a/components/usbd-ccid/Cargo.toml b/components/usbd-ccid/Cargo.toml index 20be1dc4..cc2d7ffd 100644 --- a/components/usbd-ccid/Cargo.toml +++ b/components/usbd-ccid/Cargo.toml @@ -11,8 +11,8 @@ delog = "0.1.0" embedded-time = "0.12" heapless = "0.7" # heapless-bytes = "0.3" -interchange = "0.2.0" -iso7816 = { git = "https://github.com/ycrypto/iso7816" } +interchange = "0.2" +iso7816 = "0.1" usb-device = { version = "0.2.3", features = ["control-buffer-256"] } [features] diff --git a/components/usbd-ccid/src/class.rs b/components/usbd-ccid/src/class.rs index 4f3f482f..0d597132 100644 --- a/components/usbd-ccid/src/class.rs +++ b/components/usbd-ccid/src/class.rs @@ -114,6 +114,7 @@ where .then(|| FUNCTIONAL_INTERFACE_STRING) } + #[inline(never)] fn poll(&mut self) { // info_now!("poll of ccid"); self.pipe.poll_app(); diff --git a/components/usbd-ccid/src/pipe.rs b/components/usbd-ccid/src/pipe.rs index 52a853d2..c0f52685 100644 --- a/components/usbd-ccid/src/pipe.rs +++ b/components/usbd-ccid/src/pipe.rs @@ -351,6 +351,7 @@ where self.state = State::Processing; } + #[inline(never)] pub fn poll_app(&mut self) { if let State::Processing = self.state { // info!("processing, checking for response, interchange state {:?}", @@ -476,6 +477,7 @@ where self.maybe_send_packet(); } + #[inline(never)] pub fn maybe_send_packet(&mut self) { if let Some(packet) = self.outbox.as_ref() { let needs_zlp = packet.len() == PACKET_SIZE; diff --git a/components/usbd-ctaphid/Cargo.toml b/components/usbd-ctaphid/Cargo.toml index a60bcca3..488ed22e 100644 --- a/components/usbd-ctaphid/Cargo.toml +++ b/components/usbd-ctaphid/Cargo.toml @@ -6,6 +6,8 @@ license = "Apache-2.0 OR MIT" edition = "2018" [dependencies] +ctap-types = "0.1.0" +ctaphid-dispatch = "0.1.0" embedded-time = "0.12" delog = "0.1.0" heapless = "0.7" @@ -14,8 +16,6 @@ interchange = "0.2.0" serde = { version = "1.0", default-features = false } usb-device = "0.2.3" -ctaphid-dispatch = { git = "https://github.com/solokeys/ctaphid-dispatch" } -ctap-types = { git = "https://github.com/solokeys/ctap-types" } [features] default = [] diff --git a/components/usbd-ctaphid/src/class.rs b/components/usbd-ctaphid/src/class.rs index b4e5364e..a45b1044 100644 --- a/components/usbd-ctaphid/src/class.rs +++ b/components/usbd-ctaphid/src/class.rs @@ -48,7 +48,12 @@ where pipe, } } - + + /// Set versions returned in CTAPHID_INIT + pub fn set_version(&mut self, version: crate::Version) { + self.pipe.set_version(version); + } + /// Indicate in INIT response that Wink command is implemented. pub fn implements_wink(mut self) -> Self { self.pipe.implements |= 0x01; @@ -188,11 +193,9 @@ where Bus: UsbBus Ok(()) } + #[inline(never)] fn poll(&mut self) { - // if self.pipe.interchange.recv.ready() { - // // hprintln!("recv pipe ready").ok(); - // } - // // hprintln!("state = {:?}", self.pipe.state).ok(); + // debug!("state = {:?}", self.pipe().state); self.pipe.handle_response(); self.pipe.maybe_write_packet(); } diff --git a/components/usbd-ctaphid/src/constants.rs b/components/usbd-ctaphid/src/constants.rs index 9a4026c2..ab1610b6 100644 --- a/components/usbd-ctaphid/src/constants.rs +++ b/components/usbd-ctaphid/src/constants.rs @@ -3,5 +3,6 @@ pub const INTERRUPT_POLL_MILLISECONDS: u8 = 5; pub const PACKET_SIZE: usize = 64; -// 7609 bytes -pub const MESSAGE_SIZE: usize = PACKET_SIZE - 7 + 128 * (PACKET_SIZE - 5); +// 1200 +// pub const MESSAGE_SIZE: usize = ctap_types::sizes::REALISTIC_MAX_MESSAGE_SIZE; +pub const MESSAGE_SIZE: usize = 3072; diff --git a/components/usbd-ctaphid/src/lib.rs b/components/usbd-ctaphid/src/lib.rs index d669c025..ec6e394a 100644 --- a/components/usbd-ctaphid/src/lib.rs +++ b/components/usbd-ctaphid/src/lib.rs @@ -22,3 +22,11 @@ pub use class::CtapHid; pub mod pipe; pub mod types; +/// major/minor/build version bytes returned in CTAPHID_INIT +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +pub struct Version { + pub major: u8, + pub minor: u8, + pub build: u8, +} + diff --git a/components/usbd-ctaphid/src/pipe.rs b/components/usbd-ctaphid/src/pipe.rs index 988a70ef..6b17d348 100644 --- a/components/usbd-ctaphid/src/pipe.rs +++ b/components/usbd-ctaphid/src/pipe.rs @@ -20,11 +20,7 @@ use core::convert::TryFrom; use ctaphid_dispatch::types::HidInterchange; use ctaphid_dispatch::command::Command; -use ctap_types::{ - authenticator::Error as AuthenticatorError, -}; - - +use ctap_types::Error as AuthenticatorError; use interchange::Requester; @@ -38,7 +34,7 @@ use usb_device::{ use crate::{ constants::{ - // 7609 + // 3072 MESSAGE_SIZE, // 64 PACKET_SIZE, @@ -152,6 +148,8 @@ pub struct Pipe<'alloc, Bus: UsbBus> { started_processing: bool, needs_keepalive: bool, + + pub(crate) version: crate::Version, } impl<'alloc, Bus: UsbBus> Pipe<'alloc, Bus> { @@ -179,9 +177,14 @@ impl<'alloc, Bus: UsbBus> Pipe<'alloc, Bus> { last_milliseconds: initial_milliseconds, started_processing: false, needs_keepalive: false, + version: Default::default(), } } + pub(crate) fn set_version(&mut self, version: crate::Version) { + self.version = version; + } + pub fn read_address(&self) -> EndpointAddress { self.read_endpoint.address() } @@ -449,11 +452,11 @@ impl<'alloc, Bus: UsbBus> Pipe<'alloc, Bus> { // CTAPHID protocol version self.buffer[12] = 2; // major device version number - self.buffer[13] = 0; + self.buffer[13] = self.version.major; // minor device version number - self.buffer[14] = 0; + self.buffer[14] = self.version.minor; // build device version number - self.buffer[15] = 0; + self.buffer[15] = self.version.build; // capabilities flags // 0x1: implements WINK // 0x4: implements CBOR @@ -540,6 +543,7 @@ impl<'alloc, Bus: UsbBus> Pipe<'alloc, Bus> { } } + #[inline(never)] pub fn handle_response(&mut self) { if let State::WaitingOnAuthenticator(request) = self.state { @@ -598,6 +602,7 @@ impl<'alloc, Bus: UsbBus> Pipe<'alloc, Bus> { } // called from poll, and when a packet has been sent + #[inline(never)] pub(crate) fn maybe_write_packet(&mut self) { match self.state { diff --git a/runners/lpc55/.cargo/config b/runners/lpc55/.cargo/config.toml similarity index 92% rename from runners/lpc55/.cargo/config rename to runners/lpc55/.cargo/config.toml index d086b8cd..bc5e0202 100644 --- a/runners/lpc55/.cargo/config +++ b/runners/lpc55/.cargo/config.toml @@ -3,7 +3,6 @@ runner = "arm-none-eabi-gdb -q -x jlink.gdb" rustflags = [ "-C", "linker=flip-link", "-C", "link-arg=-Tlink.x", - # "-Dwarnings", ] [build] diff --git a/runners/lpc55/Cargo.lock b/runners/lpc55/Cargo.lock index a4b1241f..33e94bd6 100644 --- a/runners/lpc55/Cargo.lock +++ b/runners/lpc55/Cargo.lock @@ -5,12 +5,14 @@ version = 3 [[package]] name = "admin-app" version = "0.1.0" -source = "git+https://github.com/solokeys/admin-app#99951ba7bc2c577dac1c7a1bb74999eb29e01a34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67d9f4831720ac3f95d708922b71cbec0d085548affb935f4af35395af28366c" dependencies = [ - "apdu-dispatch", + "apdu-dispatch 0.1.0", "ctaphid-dispatch", - "iso7816", - "trussed", + "delog", + "iso7816 0.1.0", + "trussed 0.1.0 (git+https://github.com/nitrokey/trussed?branch=no-ui-status-reset)", ] [[package]] @@ -52,7 +54,19 @@ dependencies = [ "delog", "heapless 0.7.9", "interchange", - "iso7816", + "iso7816 0.1.0-alpha.1", +] + +[[package]] +name = "apdu-dispatch" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4984da9e0c0fa55506888d6fa48bab859b20d788654267bebedfac64f54dff17" +dependencies = [ + "delog", + "heapless 0.7.9", + "interchange", + "iso7816 0.1.0", ] [[package]] @@ -181,13 +195,15 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] name = "board" -version = "0.0.0-unreleased" +version = "0.1.0-unreleased" dependencies = [ + "admin-app", "delog", "fm11nc08", "lpc55-hal", + "lpc55-rtic", "nb 1.0.0", - "trussed", + "trussed 0.1.0 (git+https://github.com/nitrokey/trussed?branch=no-ui-status-reset)", ] [[package]] @@ -393,8 +409,9 @@ dependencies = [ [[package]] name = "ctap-types" -version = "0.1.0" -source = "git+https://github.com/solokeys/ctap-types#98534ed1167a87dfb6f0a93ceab9c98980a8164d" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4fa005ff525537460e1fd70a1ff4f417ae4a6ed14887f3e4720221e20f7562" dependencies = [ "bitflags", "cbor-smol", @@ -403,7 +420,7 @@ dependencies = [ "heapless 0.7.9", "heapless-bytes 0.3.0", "interchange", - "iso7816", + "iso7816 0.1.0", "serde", "serde-indexed", "serde_repr", @@ -411,8 +428,9 @@ dependencies = [ [[package]] name = "ctaphid-dispatch" -version = "0.0.1" -source = "git+https://github.com/solokeys/ctaphid-dispatch#6dcbc0d1b79e597eb643b2d35ac5d6e548e30172" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f378100ce2ecda0bc9c882254583168b63afd788f277f45d494c33b4493d5a" dependencies = [ "delog", "heapless 0.7.9", @@ -428,9 +446,9 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "delog" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1abe705f4932cb84b67569a7e05cda7ffc9b8847980b2e1cf290f41045eea73b" +checksum = "cb73cae03ad02cd38353f93fe84b288daffcb6371212226e09b9a4c7fc93b03f" dependencies = [ "log", ] @@ -499,23 +517,6 @@ dependencies = [ "generic-array 0.14.5", ] -[[package]] -name = "dispatch-fido" -version = "0.1.0" -dependencies = [ - "apdu-dispatch", - "ctap-types", - "ctaphid-dispatch", - "delog", - "fido-authenticator", - "heapless 0.6.1", - "heapless-bytes 0.3.0", - "interchange", - "iso7816", - "serde", - "trussed", -] - [[package]] name = "ecdsa" version = "0.12.4" @@ -583,18 +584,22 @@ dependencies = [ [[package]] name = "fido-authenticator" -version = "0.0.0-unreleased" -source = "git+https://github.com/Nitrokey/fido-authenticator#5862c89b02b1cc8629e3a7fea8c2cbdab8211d39" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c809364e63e0bfc7153a6101235cd407a11d34e97b27984eb1f49e8e6a25122" dependencies = [ + "apdu-dispatch 0.1.0", "ctap-types", + "ctaphid-dispatch", "delog", "heapless 0.7.9", "interchange", + "iso7816 0.1.0", "littlefs2", "serde", "serde-indexed", "serde_cbor", - "trussed", + "trussed 0.1.0 (git+https://github.com/nitrokey/trussed?branch=no-ui-status-reset)", ] [[package]] @@ -795,6 +800,16 @@ dependencies = [ "heapless 0.7.9", ] +[[package]] +name = "iso7816" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a921942ff6163b5dc8be6996deed8193064db1f57ae3c327ac29a7c3cfffc71d" +dependencies = [ + "delog", + "heapless 0.7.9", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -954,21 +969,21 @@ checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" name = "ndef-app" version = "0.1.0" dependencies = [ - "apdu-dispatch", + "apdu-dispatch 0.1.0", "heapless 0.7.9", - "iso7816", + "iso7816 0.1.0", ] [[package]] name = "nfc-device" version = "0.0.1" dependencies = [ - "apdu-dispatch", + "apdu-dispatch 0.1.0", "delog", "embedded-time", "heapless 0.7.9", "interchange", - "iso7816", + "iso7816 0.1.0", "nb 1.0.0", ] @@ -1060,19 +1075,20 @@ dependencies = [ [[package]] name = "oath-authenticator" -version = "0.0.0-pre" -source = "git+https://github.com/trussed-dev/oath-authenticator#5d369ca7cba4f9c8df2a2968e0110ade01e961f7" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11470bb97635a0d1943211c7b9cd473ecee002342480e8fc7347beba27f38243" dependencies = [ - "apdu-dispatch", + "apdu-dispatch 0.1.0", "delog", "flexiber", "heapless 0.7.9", "heapless-bytes 0.3.0", "hex-literal", "interchange", - "iso7816", + "iso7816 0.1.0", "serde", - "trussed", + "trussed 0.1.0 (git+https://github.com/nitrokey/trussed?branch=no-ui-status-reset)", ] [[package]] @@ -1136,15 +1152,15 @@ name = "piv-authenticator" version = "0.0.0-unreleased" source = "git+https://github.com/solokeys/piv-authenticator#91caa3c7ddbe3f8329c6a1830cab542d892c2c4d" dependencies = [ - "apdu-dispatch", + "apdu-dispatch 0.0.1", "delog", "flexiber", "heapless 0.7.9", "hex-literal", "interchange", - "iso7816", + "iso7816 0.1.0-alpha.1", "serde", - "trussed", + "trussed 0.1.0 (git+https://github.com/trussed-dev/trussed)", "untrusted", ] @@ -1189,7 +1205,7 @@ dependencies = [ name = "provisioner-app" version = "0.1.0" dependencies = [ - "apdu-dispatch", + "apdu-dispatch 0.1.0", "delog", "heapless 0.7.9", "heapless-bytes 0.3.0", @@ -1197,7 +1213,7 @@ dependencies = [ "lpc55-hal", "nisty", "salty", - "trussed", + "trussed 0.1.0 (git+https://github.com/nitrokey/trussed?branch=no-ui-status-reset)", ] [[package]] @@ -1291,13 +1307,12 @@ name = "runner" version = "1.0.3" dependencies = [ "admin-app", - "apdu-dispatch", + "apdu-dispatch 0.1.0", "board", "cortex-m-semihosting", "ctap-types", "ctaphid-dispatch", "delog", - "dispatch-fido", "fido-authenticator", "fm11nc08", "heapless 0.6.1", @@ -1312,7 +1327,7 @@ dependencies = [ "piv-authenticator", "provisioner-app", "rtt-target", - "trussed", + "trussed 0.1.0 (git+https://github.com/nitrokey/trussed?branch=no-ui-status-reset)", "usb-device", "usbd-ccid", "usbd-ctaphid", @@ -1505,6 +1520,42 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "trussed" +version = "0.1.0" +source = "git+https://github.com/nitrokey/trussed?branch=no-ui-status-reset#0994607f6fe84a3fbec9b137c9e8247f1232d536" +dependencies = [ + "aes", + "bitflags", + "block-modes", + "cbor-smol", + "cfg-if", + "chacha20", + "chacha20poly1305", + "cosey 0.3.0", + "delog", + "des", + "embedded-hal", + "flexiber", + "generic-array 0.14.5", + "heapless 0.7.9", + "heapless-bytes 0.3.0", + "hex-literal", + "hmac", + "interchange", + "littlefs2", + "nb 1.0.0", + "p256-cortex-m4", + "postcard", + "rand_core", + "salty", + "serde", + "serde-indexed", + "sha-1", + "sha2", + "zeroize", +] + [[package]] name = "trussed" version = "0.1.0" @@ -1589,7 +1640,7 @@ dependencies = [ "embedded-time", "heapless 0.7.9", "interchange", - "iso7816", + "iso7816 0.1.0", "usb-device", ] diff --git a/runners/lpc55/Cargo.toml b/runners/lpc55/Cargo.toml index 7fbc30b3..2ffab6a5 100644 --- a/runners/lpc55/Cargo.toml +++ b/runners/lpc55/Cargo.toml @@ -4,8 +4,8 @@ name = "runner" version = "1.0.3" authors = ["Nicolas Stalder ", "Conor Patrick "] -edition = "2018" -resolver = "2" +edition = "2021" +rust-version = "1.59.0" [lib] name = "runner" @@ -26,20 +26,20 @@ usb-device = "0.2.3" # usbd-hid = { version = "0.4.5", optional = true } usbd-serial = "0.1.0" -admin-app = { git = "https://github.com/solokeys/admin-app", optional = true } -apdu-dispatch = { git = "https://github.com/solokeys/apdu-dispatch" } -ctaphid-dispatch = { git = "https://github.com/solokeys/ctaphid-dispatch" } -ctap-types = { git = "https://github.com/solokeys/ctap-types" } -fido-authenticator = { git = "https://github.com/Nitrokey/fido-authenticator", optional = true } -oath-authenticator = { git = "https://github.com/trussed-dev/oath-authenticator", features = ["apdu-dispatch"], optional = true } +admin-app = { version = "0.1", optional = true } +apdu-dispatch = "0.1" +ctaphid-dispatch = "0.1" +ctap-types = "0.1" +fido-authenticator = { version = "0.1", features = ["dispatch"], optional = true } +#fido-authenticator = { git = "https://github.com/Nitrokey/fido-authenticator", features = ["dispatch"], optional = true} +oath-authenticator = { version = "0.1", features = ["apdu-dispatch"], optional = true } piv-authenticator = { git = "https://github.com/solokeys/piv-authenticator", features = ["apdu-dispatch"], optional = true } -trussed = { git = "https://github.com/trussed-dev/trussed" } +trussed = "0.1" # board board = { path = "board" } # components -dispatch-fido = {path = "../../components/dispatch-fido"} ndef-app = { path = "../../components/ndef-app", optional = true } # NB: when using this app, need to raise trussed/clients-5 provisioner-app = { path = "../../components/provisioner-app", optional = true, features = ["test-attestation"] } @@ -104,6 +104,9 @@ log-debug = [] log-warn = [] log-error = [] +[patch.crates-io] +trussed = { git = "https://github.com/nitrokey/trussed", branch = "no-ui-status-reset" } + [profile.release] codegen-units = 1 lto = true diff --git a/runners/lpc55/Makefile b/runners/lpc55/Makefile index 5db649b8..ec796fee 100644 --- a/runners/lpc55/Makefile +++ b/runners/lpc55/Makefile @@ -59,10 +59,3 @@ bacon: jlink: -../../scripts/bump-jlink JLinkGDBServer -strict -device LPC55S69 -if SWD -vd - - -PACK_VERSION := $(shell wget -O - -qq https://mcuxpresso.nxp.com/cmsis_pack/repo/NXP.pidx|grep LPC55S69|python -c'import sys; print(sys.stdin.read().rsplit("version=\"", 1)[1].split("\"", 1)[0])') -PACK := NXP.LPC55S69_DFP.$(PACK_VERSION).pack -get-cmsis-pack: - wget -qq https://mcuxpresso.nxp.com/cmsis_pack/repo/$(PACK) -O ./lpc55s69.pack - diff --git a/runners/lpc55/bacon.toml b/runners/lpc55/bacon.toml index e3fea662..b4793a9b 100644 --- a/runners/lpc55/bacon.toml +++ b/runners/lpc55/bacon.toml @@ -10,7 +10,7 @@ command = ["cargo", "check", "--color", "always", "--features", "board-lpcxpress need_stdout = false [jobs.build-dev] -command = ["cargo", "build", "--color", "always", "--features", "board-lpcxpresso55,develop"] +command = ["cargo", "build", "--color", "always", "--release", "--features", "board-lpcxpresso55,develop"] need_stdout = false [jobs.check] diff --git a/runners/lpc55/board/Cargo.toml b/runners/lpc55/board/Cargo.toml index 154555ab..291585fc 100644 --- a/runners/lpc55/board/Cargo.toml +++ b/runners/lpc55/board/Cargo.toml @@ -1,15 +1,17 @@ [package] name = "board" -version = "0.0.0-unreleased" +version = "0.1.0-unreleased" authors = ["Conor Patrick "] -edition = "2018" +edition = "2021" [dependencies] -delog = "0.1.0" +admin-app = "0.1" +delog = "0.1" fm11nc08 = {path = "../../../components/fm11nc08"} lpc55-hal = { version = "0.3", features = ["littlefs", "rtic-peripherals"] } +lpc55-rtic = "0.5.7" nb = "1" -trussed = { git = "https://github.com/trussed-dev/trussed" } +trussed = "0.1" [features] board-lpcxpresso55 = [] diff --git a/runners/lpc55/board/src/lib.rs b/runners/lpc55/board/src/lib.rs index 1f8fca73..f137da94 100644 --- a/runners/lpc55/board/src/lib.rs +++ b/runners/lpc55/board/src/lib.rs @@ -2,6 +2,7 @@ pub use lpc55_hal as hal; +pub mod shared; pub mod traits; // board support package diff --git a/runners/lpc55/board/src/lpcxpresso55/led.rs b/runners/lpc55/board/src/lpcxpresso55/led.rs index a43c0d71..9d102787 100644 --- a/runners/lpc55/board/src/lpcxpresso55/led.rs +++ b/runners/lpc55/board/src/lpcxpresso55/led.rs @@ -22,16 +22,16 @@ pub enum Color { use crate::traits::rgb_led; // OKdo E1 has pins switched for red+blue LED -#[cfg(not(feature = "board-okdoe1"))] +#[cfg(not(feature = "okdoe1"))] pub type RedLedPin = pins::Pio1_6; -#[cfg(feature = "board-okdoe1")] +#[cfg(feature = "okdoe1")] pub type RedLedPin = pins::Pio1_4; pub type GreenLedPin = pins::Pio1_7; -#[cfg(not(feature = "board-okdoe1"))] +#[cfg(not(feature = "okdoe1"))] pub type BlueLedPin = pins::Pio1_4; -#[cfg(feature = "board-okdoe1")] +#[cfg(feature = "okdoe1")] pub type BlueLedPin = pins::Pio1_6; diff --git a/runners/lpc55/board/src/shared.rs b/runners/lpc55/board/src/shared.rs new file mode 100644 index 00000000..c064841c --- /dev/null +++ b/runners/lpc55/board/src/shared.rs @@ -0,0 +1,48 @@ +use crate::hal; + +pub struct Monotonic; +pub struct Reboot; + +const CLOCK_FREQ: u32 = 96_000_000; + +impl crate::traits::Monotonic for Monotonic { + // intended to be: milliseconds + type Instant = i32;//core::time::Duration; + unsafe fn reset() {} + fn ratio() -> rtic::Fraction { + rtic::Fraction { numerator: CLOCK_FREQ/1000, denominator: 1 } + } + fn now() -> Self::Instant { + let rtc = unsafe { crate::hal::raw::Peripherals::steal() }.RTC; + let secs = rtc.count.read().bits() as i32; + let ticks_32k = rtc.subsec.read().bits() as i32; + secs*1000 + ((ticks_32k * 61)/2000) + } + fn zero() -> Self::Instant { + Self::Instant::default() + } +} + +impl crate::traits::Reboot for Reboot { + fn reboot() -> ! { + hal::raw::SCB::sys_reset() + } + fn reboot_to_firmware_update() -> ! { + hal::boot_to_bootrom() + } + fn reboot_to_firmware_update_destructive() -> ! { + // Erasing the first flash page & rebooting will keep processor in bootrom persistently. + // This is however destructive, as a valid firmware will need to be flashed. + use hal::traits::flash::WriteErase; + let flash = unsafe { hal::peripherals::flash::Flash::steal() }.enabled( + &mut unsafe {hal::peripherals::syscon::Syscon::steal()} + ); + hal::drivers::flash::FlashGordon::new(flash).erase_page(0).ok(); + hal::raw::SCB::sys_reset() + } + fn locked() -> bool { + let seal = &unsafe { hal::raw::Peripherals::steal() }.FLASH_CMPA.sha256_digest; + seal.iter().any(|word| word.read().bits() != 0) + } +} + diff --git a/runners/lpc55/board/src/traits.rs b/runners/lpc55/board/src/traits.rs index 210b3427..aba050e2 100644 --- a/runners/lpc55/board/src/traits.rs +++ b/runners/lpc55/board/src/traits.rs @@ -1,2 +1,6 @@ pub mod buttons; +pub mod monotonic; +pub use monotonic::Monotonic; +pub mod reboot; +pub use reboot::Reboot; pub mod rgb_led; diff --git a/runners/lpc55/board/src/traits/monotonic.rs b/runners/lpc55/board/src/traits/monotonic.rs new file mode 100644 index 00000000..8abd1593 --- /dev/null +++ b/runners/lpc55/board/src/traits/monotonic.rs @@ -0,0 +1 @@ +pub use rtic::Monotonic; diff --git a/runners/lpc55/board/src/traits/reboot.rs b/runners/lpc55/board/src/traits/reboot.rs new file mode 100644 index 00000000..469b617e --- /dev/null +++ b/runners/lpc55/board/src/traits/reboot.rs @@ -0,0 +1 @@ +pub use admin_app::Reboot; diff --git a/runners/lpc55/board/src/traits/rgb_led.rs b/runners/lpc55/board/src/traits/rgb_led.rs index 113fc0f6..609e7fe5 100644 --- a/runners/lpc55/board/src/traits/rgb_led.rs +++ b/runners/lpc55/board/src/traits/rgb_led.rs @@ -16,6 +16,19 @@ impl From for Intensities { } } +impl Intensities { + + pub fn scale_by(&mut self, factor: &u8) -> Self { + let scale: f32 = (factor / 255).into(); + Intensities { + red: self.red * scale as u8, + green: self.green * scale as u8, + blue: self.blue * scale as u8 + } + } +} + + pub trait RgbLed { /// Set all LEDs diff --git a/runners/lpc55/board/src/trussed.rs b/runners/lpc55/board/src/trussed.rs index 1cdfc3d1..946ce81d 100644 --- a/runners/lpc55/board/src/trussed.rs +++ b/runners/lpc55/board/src/trussed.rs @@ -8,30 +8,10 @@ use crate::hal::{ typestates::init_state, }; use crate::traits::buttons::{Press, Edge}; -use crate::traits::rgb_led::RgbLed; -use trussed::platform::{ - ui, - reboot, - consent, -}; - -// translated from https://stackoverflow.com/a/2284929/2490057 -fn sin(x: f32) -> f32 -{ - - let mut res = 0f32; - let mut pow = x; - let mut fact = 1f32; - for i in 0..5 { - res += pow/fact; - pow *= -1f32 * x * x; - fact *= ((2*(i+1))*(2*(i+1)+1)) as f32; - } - - res -} +use crate::traits::rgb_led::{Intensities, RgbLed}; +use trussed::platform::{consent, ui}; -// Assuming there will only be one way to +// Assuming there will only be one way to // get user presence, this should be fine. // Used for Ctaphid.keepalive message status. static mut WAITING: bool = false; @@ -45,7 +25,6 @@ impl UserPresenceStatus { } } - pub struct UserInterface where BUTTONS: Press + Edge, @@ -79,6 +58,16 @@ RGB: RgbLed, } } +// color codes Conor picked +const BLACK: Intensities = Intensities { red: 0, green: 0, blue: 0 }; +const RED: Intensities = Intensities { red: u8::MAX, green: 0, blue: 0 }; +const GREEN: Intensities = Intensities { red: 0, green: u8::MAX, blue: 0x02 }; +#[allow(dead_code)] +const BLUE: Intensities = Intensities { red: 0, green: 0, blue: u8::MAX }; +const TEAL: Intensities = Intensities { red: 0, green: u8::MAX, blue: 0x5a }; +const ORANGE: Intensities = Intensities { red: u8::MAX, green: 0x7e, blue: 0 }; +const WHITE: Intensities = Intensities { red: u8::MAX, green: u8::MAX, blue: u8::MAX }; + impl trussed::platform::UserInterface for UserInterface where BUTTONS: Press + Edge, @@ -119,23 +108,23 @@ RGB: RgbLed, ui::Status::Idle => { if self.provisioner { // white - rgb.set(0xff_ff_ff.into()); + rgb.set(WHITE.into()); } else { // green - rgb.set(0x00_ff_02.into()); + rgb.set(GREEN.into()); } }, ui::Status::Processing => { // teal - rgb.set(0x00_ff_5a.into()); + rgb.set(TEAL.into()); } ui::Status::WaitingForUserPresence => { // orange - rgb.set(0xff_7e_00.into()); + rgb.set(ORANGE.into()); }, ui::Status::Error => { // Red - rgb.set(0xff_00_00.into()); + rgb.set(RED.into()); }, } @@ -157,53 +146,26 @@ RGB: RgbLed, if wink.contains(&time) { // 250 ms white, 250 ms off let color = if (time - wink.start).as_millis() % 500 < 250 { - 0xff_ff_ff + WHITE } else { - 0x00_00_00 + BLACK }; self.rgb.as_mut().unwrap().set(color.into()); return; } else { + self.set_status(ui::Status::Idle); self.wink = None; } } - - if self.buttons.is_some() { - // 1. Get time & pick a period (here 4096). - // 2. Map it to a value between 0 and pi. - // 3. Calculate sine and map to amplitude between 0 and 255. - let time = (self.uptime().as_millis()) % 4096; - let amplitude = (sin((time as f32) * 3.14159265f32/4096f32) * 255f32) as u32; - - let state = self.buttons.as_mut().unwrap().state(); - let color = if state.a || state.b || state.middle { - // Use blue if button is pressed. - 0x00_00_01 | (amplitude << 0) - } else { - // Use green if no button is pressed. - 0x00_00_01 | (amplitude << 8) - }; - // use logging::hex::*; - // use logging::hex; - // crate::logger::info!("time: {}", time).ok(); - // crate::logger::info!("amp: {}", hex!(amplitude)).ok(); - // crate::logger::info!("color: {}", hex!(color)).ok(); - self.rgb.as_mut().unwrap().set(color.into()); - } } fn uptime(&mut self) -> Duration { self.rtc.uptime() } - // delete this function after trussed is updated - fn reboot(&mut self, _to: reboot::To) -> ! { - panic!("this should no longer be called."); - } - fn wink(&mut self, duration: Duration) { let time = self.uptime(); self.wink = Some(time..time + duration); - self.rgb.as_mut().unwrap().set(0xff_ff_ff.into()); + self.rgb.as_mut().unwrap().set(WHITE.into()); } } diff --git a/runners/lpc55/build.rs b/runners/lpc55/build.rs index b5957089..ae820e48 100644 --- a/runners/lpc55/build.rs +++ b/runners/lpc55/build.rs @@ -22,6 +22,13 @@ macro_rules! add_build_variable{ .expect("Could not write build_constants.rs file"); }; + ($file:expr, $name:literal, u16) => { + let value = env!($name); + let value: u16 = str::parse(value).expect("Version components must be able to fit in a u16."); + writeln!($file, "pub const {}: u16 = {};", $name, value) + .expect("Could not write build_constants.rs file"); + }; + ($file:expr, $name:literal, $value:expr, u32) => { writeln!($file, "pub const {}: u32 = {};", $name, $value) .expect("Could not write build_constants.rs file"); @@ -113,7 +120,7 @@ fn main() -> Result<(), Box> { writeln!(&mut f, "pub mod build_constants {{").expect("Could not write build_constants.rs."); add_build_variable!(&mut f, "CARGO_PKG_VERSION_MAJOR", u8); - add_build_variable!(&mut f, "CARGO_PKG_VERSION_MINOR", u8); + add_build_variable!(&mut f, "CARGO_PKG_VERSION_MINOR", u16); add_build_variable!(&mut f, "CARGO_PKG_VERSION_PATCH", u8); add_build_variable!(&mut f, "CARGO_PKG_HASH", hash_long); diff --git a/runners/lpc55/rust-toolchain.toml b/runners/lpc55/rust-toolchain.toml new file mode 100644 index 00000000..a02802c9 --- /dev/null +++ b/runners/lpc55/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.59.0" +components = ["rustfmt", "llvm-tools-preview"] +targets = ["thumbv8m.main-none-eabi"] diff --git a/runners/lpc55/src/initializer.rs b/runners/lpc55/src/initializer.rs index 0145fc07..4672e570 100644 --- a/runners/lpc55/src/initializer.rs +++ b/runners/lpc55/src/initializer.rs @@ -517,11 +517,17 @@ impl Initializer { // So for instance "Hacker Solo 2" would work, but "Solo 2 (custom)" would not. let ccid = usbd_ccid::Ccid::new(usb_bus, contact_requester, Some(b"Nitrokey 3")); let current_time = basic_stage.perf_timer.elapsed().0/1000; - let ctaphid = usbd_ctaphid::CtapHid::new(usb_bus, ctaphid_requester, current_time) + let mut ctaphid = usbd_ctaphid::CtapHid::new(usb_bus, ctaphid_requester, current_time) .implements_ctap1() .implements_ctap2() .implements_wink(); + ctaphid.set_version(usbd_ctaphid::Version { + major: crate::build_constants::CARGO_PKG_VERSION_MAJOR, + minor: crate::build_constants::CARGO_PKG_VERSION_MINOR.to_be_bytes()[0], + build: crate::build_constants::CARGO_PKG_VERSION_MINOR.to_be_bytes()[1], + }); + let serial = usbd_serial::SerialPort::new(usb_bus); // Only 16 bits, so take the upper bits of our semver diff --git a/runners/lpc55/src/lib.rs b/runners/lpc55/src/lib.rs index b1b84955..d37a518e 100644 --- a/runners/lpc55/src/lib.rs +++ b/runners/lpc55/src/lib.rs @@ -4,6 +4,7 @@ include!(concat!(env!("OUT_DIR"), "/build_constants.rs")); // panic handler, depending on debug/release build // BUT: need to run in release anyway, to have USB work use panic_halt as _; +// use panic_semihosting as _; use usb_device::device::UsbVidPid; use board::clock_controller; @@ -40,7 +41,8 @@ impl delog::Flusher for Flusher { } } -delog!(Delogger, 16*1024, 3*1024, Flusher); +// delog!(Delogger, 16*1024, 3*1024, Flusher); +delog!(Delogger, 1, 2048, Flusher); #[cfg(any(feature = "log-semihosting", feature = "log-serial"))] static FLUSHER: Flusher = Flusher {}; diff --git a/runners/lpc55/src/main.rs b/runners/lpc55/src/main.rs index a297653d..97e8e403 100644 --- a/runners/lpc55/src/main.rs +++ b/runners/lpc55/src/main.rs @@ -6,17 +6,15 @@ #![no_main] // #![deny(warnings)] -use core::convert::TryFrom; use runner::hal; use hal::traits::wg::timer::Cancel; use hal::traits::wg::timer::CountDown; use hal::drivers::timer::Elapsed; use hal::time::{DurationExtensions, Microseconds}; -use rtic::cyccnt::{Instant, U32Ext as _}; +use board::shared::Monotonic; -const CLOCK_FREQ: u32 = 96_000_000; -const PERIOD: u32 = CLOCK_FREQ/16; +const REFRESH_MILLISECS: i32 = 50; const USB_INTERRUPT: board::hal::raw::Interrupt = board::hal::raw::Interrupt::USB1; const NFC_INTERRUPT: board::hal::raw::Interrupt = board::hal::raw::Interrupt::PIN_INT0; @@ -25,7 +23,16 @@ const NFC_INTERRUPT: board::hal::raw::Interrupt = board::hal::raw::Interrupt::PI extern crate delog; generate_macros!(); -#[rtic::app(device = runner::hal::raw, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] +use core::arch::asm; + +#[inline] +pub fn msp() -> u32 { + let r; + unsafe { asm!("mrs {}, MSP", out(reg) r, options(nomem, nostack, preserves_flags)) }; + r +} + +#[rtic::app(device = runner::hal::raw, peripherals = true, monotonic = board::shared::Monotonic)] const APP: () = { struct Resources { @@ -97,8 +104,8 @@ const APP: () = { // don't toggle LED in passive mode if usb_classes.is_some() { hal::enable_cycle_counter(); - c.schedule.update_ui(Instant::now() + PERIOD.cycles()).unwrap(); - + // c.schedule.update_ui(Instant::now() + PERIOD.cycles()).unwrap(); + c.schedule.update_ui(::now() + REFRESH_MILLISECS).unwrap(); } init::LateResources { @@ -131,7 +138,7 @@ const APP: () = { let schedule = c.schedule; - info_now!("inside IDLE"); + info_now!("inside IDLE, initial SP = {:08X}", msp()); loop { let mut time = 0; @@ -171,7 +178,8 @@ const APP: () = { match usb_classes.ccid.did_start_processing() { usbd_ccid::types::Status::ReceivedData(milliseconds) => { schedule.ccid_wait_extension( - Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + // Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + ::now() + milliseconds.0 as i32 ).ok(); } _ => {} @@ -180,7 +188,8 @@ const APP: () = { match usb_classes.ctaphid.did_start_processing() { usbd_ctaphid::types::Status::ReceivedData(milliseconds) => { schedule.ctaphid_keepalive( - Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + // Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + ::now() + milliseconds.0 as i32 ).ok(); } _ => {} @@ -200,36 +209,51 @@ const APP: () = { /// Manages all traffic on the USB bus. #[task(binds = USB1, resources = [usb_classes], schedule = [ccid_wait_extension, ctaphid_keepalive], priority=6)] fn usb(c: usb::Context) { + // let remaining = msp() - 0x2000_0000; + // if remaining < 100_000 { + // debug_now!("USB interrupt: remaining stack size: {} bytes", remaining); + // } let usb = unsafe { hal::raw::Peripherals::steal().USB1 } ; - let before = Instant::now(); + // let before = Instant::now(); let usb_classes = c.resources.usb_classes.as_mut().unwrap(); ////////////// + // if remaining < 60_000 { + // debug_now!("polling usb classes"); + // } usb_classes.poll(); match usb_classes.ccid.did_start_processing() { usbd_ccid::types::Status::ReceivedData(milliseconds) => { + // if remaining < 60_000 { + // debug_now!("scheduling CCID wait extension"); + // } c.schedule.ccid_wait_extension( - Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + // Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + ::now() + milliseconds.0 as i32 ).ok(); } _ => {} } match usb_classes.ctaphid.did_start_processing() { usbd_ctaphid::types::Status::ReceivedData(milliseconds) => { + // if remaining < 60_000 { + // debug_now!("scheduling CTAPHID wait extension"); + // } c.schedule.ctaphid_keepalive( - Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + // Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + ::now() + milliseconds.0 as i32 ).ok(); } _ => {} } ////////////// - let after = Instant::now(); - let length = (after - before).as_cycles(); - if length > 10_000 { - // debug!("poll took {:?} cycles", length); - } + // let after = Instant::now(); + // let length = (after - before).as_cycles(); + // if length > 10_000 { + // // debug!("poll took {:?} cycles", length); + // } let inten = usb.inten.read().bits(); let intstat = usb.intstat.read().bits(); let mask = inten & intstat; @@ -248,6 +272,10 @@ const APP: () = { // usb.intstat.write(|w| unsafe{ w.bits( usb.intstat.read().bits() ) }); } + // if remaining < 60_000 { + // debug_now!("USB interrupt done: {} bytes", remaining); + // } + } @@ -256,12 +284,14 @@ const APP: () = { /// until the application replied. #[task(resources = [usb_classes], schedule = [ccid_wait_extension], priority = 6)] fn ccid_wait_extension(c: ccid_wait_extension::Context) { - debug!("CCID WAIT EXTENSION"); + debug_now!("CCID WAIT EXTENSION"); + debug_now!("remaining stack size: {} bytes", msp() - 0x2000_0000); let status = c.resources.usb_classes.as_mut().unwrap().ccid.send_wait_extension(); match status { usbd_ccid::types::Status::ReceivedData(milliseconds) => { c.schedule.ccid_wait_extension( - Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + // Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + ::now() + milliseconds.0 as i32 ).ok(); } _ => {} @@ -271,14 +301,16 @@ const APP: () = { /// Same as with CCID, but sending ctaphid keepalive statuses. #[task(resources = [usb_classes], schedule = [ctaphid_keepalive], priority = 6)] fn ctaphid_keepalive(c: ctaphid_keepalive::Context) { - debug!("keepalive"); + debug_now!("CTAPHID keepalive"); + debug_now!("remaining stack size: {} bytes", msp() - 0x2000_0000); let status = c.resources.usb_classes.as_mut().unwrap().ctaphid.send_keepalive( board::trussed::UserPresenceStatus::waiting() ); match status { usbd_ctaphid::types::Status::ReceivedData(milliseconds) => { c.schedule.ctaphid_keepalive( - Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + // Instant::now() + (CLOCK_FREQ/1_000 * milliseconds.0).cycles() + ::now() + milliseconds.0 as i32 ).ok(); } _ => {} @@ -288,6 +320,7 @@ const APP: () = { #[task(binds = MAILBOX, resources = [usb_classes], priority = 5)] #[allow(unused_mut,unused_variables)] fn mailbox(mut c: mailbox::Context) { + // debug_now!("mailbox: remaining stack size: {} bytes", msp() - 0x2000_0000); #[cfg(feature = "log-serial")] c.resources.usb_classes.lock(|usb_classes_maybe| { match usb_classes_maybe.as_mut() { @@ -310,6 +343,7 @@ const APP: () = { #[task(binds = OS_EVENT, resources = [trussed], priority = 5)] fn os_event(c: os_event::Context) { + // debug_now!("os event: remaining stack size: {} bytes", msp() - 0x2000_0000); c.resources.trussed.process(); } @@ -317,13 +351,14 @@ const APP: () = { fn update_ui(mut c: update_ui::Context) { static mut UPDATES: u32 = 1; + // debug_now!("update UI: remaining stack size: {} bytes", msp() - 0x2000_0000); // let wait_periods = c.resources.trussed.lock(|trussed| trussed.update_ui()); c.resources.trussed.lock(|trussed| trussed.update_ui()); // c.schedule.update_ui(Instant::now() + wait_periods * PERIOD.cycles()).unwrap(); - c.schedule.update_ui(Instant::now() + PERIOD.cycles()).unwrap(); + c.schedule.update_ui(::now() + REFRESH_MILLISECS).ok(); - *UPDATES += 1; + *UPDATES = UPDATES.wrapping_add(1); } diff --git a/runners/lpc55/src/types.rs b/runners/lpc55/src/types.rs index ae347510..5494c5d7 100644 --- a/runners/lpc55/src/types.rs +++ b/runners/lpc55/src/types.rs @@ -1,5 +1,4 @@ include!(concat!(env!("OUT_DIR"), "/build_constants.rs")); -use core::convert::TryInto; use crate::hal; use hal::drivers::timer; @@ -27,6 +26,8 @@ pub type FlashStorage = PrinceFilesystem; pub mod usb; pub use usb::{UsbClasses, EnabledUsbPeripheral, SerialClass, CcidClass, CtapHidClass}; +use board::shared::Reboot; + // 8KB of RAM const_ram_storage!( name=VolatileStorage, @@ -85,34 +86,16 @@ pub type ExternalInterrupt = hal::Pint; pub type ApduDispatch = apdu_dispatch::dispatch::ApduDispatch; pub type CtaphidDispatch = ctaphid_dispatch::dispatch::Dispatch; -pub struct Lpc55Reboot {} -impl admin_app::Reboot for Lpc55Reboot { - fn reboot() -> ! { - hal::raw::SCB::sys_reset() - } - fn reboot_to_firmware_update() -> ! { - hal::boot_to_bootrom() - } - fn reboot_to_firmware_update_destructive() -> ! { - // Erasing the first flash page & rebooting will keep processor in bootrom persistently. - // This is however destructive, as a valid firmware will need to be flashed. - use hal::traits::flash::WriteErase; - let flash = unsafe { hal::peripherals::flash::Flash::steal() }.enabled( - &mut unsafe {hal::peripherals::syscon::Syscon::steal()} - ); - hal::drivers::flash::FlashGordon::new(flash).erase_page(0).ok(); - hal::raw::SCB::sys_reset() - } -} - #[cfg(feature = "admin-app")] -pub type AdminApp = admin_app::App; +pub type AdminApp = admin_app::App; #[cfg(feature = "piv-authenticator")] pub type PivApp = piv_authenticator::Authenticator; #[cfg(feature = "oath-authenticator")] pub type OathApp = oath_authenticator::Authenticator; #[cfg(feature = "fido-authenticator")] -pub type FidoApp = dispatch_fido::Fido; +pub type FidoApp = fido_authenticator::Authenticator; +#[cfg(feature = "fido-authenticator")] +pub type FidoConfig = fido_authenticator::Config; #[cfg(feature = "ndef-app")] pub type NdefApp = ndef_app::App<'static>; #[cfg(feature = "provisioner-app")] @@ -193,10 +176,16 @@ impl TrussedApp for FidoApp { fn with_client(trussed: TrussedClient, _: ()) -> Self { let authnr = fido_authenticator::Authenticator::new( trussed, - fido_authenticator::NonSilentAuthenticator {}, + fido_authenticator::Conforming {}, + FidoConfig { + max_msg_size: usbd_ctaphid::constants::MESSAGE_SIZE, + // max_creds_in_list: ctap_types::sizes::MAX_CREDENTIAL_COUNT_IN_LIST, + // max_cred_id_length: ctap_types::sizes::MAX_CREDENTIAL_ID_LENGTH, + }, ); - Self::new(authnr) + // Self::new(authnr) + authnr } } @@ -267,6 +256,7 @@ impl Apps { } } + #[inline(never)] pub fn apdu_dispatch(&mut self, f: F) -> T where F: FnOnce(&mut [&mut dyn @@ -289,6 +279,7 @@ impl Apps { ]) } + #[inline(never)] pub fn ctaphid_dispatch(&mut self, f: F) -> T where F: FnOnce(&mut [&mut dyn CtaphidApp ]) -> T diff --git a/runners/pc/Cargo.toml b/runners/pc/Cargo.toml index 4ca6f212..ebb11cab 100644 --- a/runners/pc/Cargo.toml +++ b/runners/pc/Cargo.toml @@ -9,24 +9,22 @@ chacha20 = { version = "0.7", features = ["rng"] } delog = "0.1.0" embedded-hal = { version = "0.2", features = ["unproven"] } generic-array = "0.14.3" -heapless = "0.6" interchange = "0.2.0" nb = "1" -admin-app = { git = "https://github.com/solokeys/admin-app" } -apdu-dispatch = { git = "https://github.com/solokeys/apdu-dispatch", features = ["std"] } -ctap-types = { git = "https://github.com/solokeys/ctap-types" } -ctaphid-dispatch = { git = "https://github.com/solokeys/ctaphid-dispatch", features = ["std"] } -fido-authenticator = { git = "https://github.com/solokeys/fido-authenticator" } +admin-app = "0.1" +apdu-dispatch = "0.1" +ctap-types = "0.1" +ctaphid-dispatch = "0.1" +fido-authenticator = { version = "0.1", features = ["dispatch"], optional = true } piv-authenticator = { git = "https://github.com/solokeys/piv-authenticator" } -trussed = { git = "https://github.com/trussed-dev/trussed", features = ["clients-3"] } +trussed = { version = "0.1", features = ["clients-3"] } # components usbd-ccid = { path = "../../components/usbd-ccid" } usbd-ctaphid = { path = "../../components/usbd-ctaphid" } nfc-device = {path = "./../../components/nfc-device"} ndef-app = {path = "./../../components/ndef-app"} -dispatch-fido = {path = "./../../components/dispatch-fido"} # storage littlefs2 = "0.3.1" diff --git a/tests/basic.py b/tests/basic.py index e2b986bf..e8ea43f4 100644 --- a/tests/basic.py +++ b/tests/basic.py @@ -13,6 +13,8 @@ dev_info = dev.get_info() +N = 3 + print(dev_info) if dev_info.options.get('clientPin', False): pin_token = client_pin.get_pin_token(pin) @@ -56,6 +58,7 @@ credential_id = att.auth_data.credential_data.credential_id print(att.auth_data.credential_data) + print(f":: Credential ID (len{len(credential_id)}):\n{credential_id.hex()}") credential_ids.append(credential_id) public_key = att.auth_data.credential_data.public_key @@ -64,19 +67,20 @@ # basic sanity check - would raise assert att.fmt == "packed" verifier = fido2.attestation.Attestation.for_type(att.fmt)() - verifier.verify( - att.att_statement, att.auth_data, b"1234567890ABCDEF1234567890ABCDEF" - ) + # verifier.verify( + # att.att_statement, att.auth_data, b"1234567890ABCDEF1234567890ABCDEF" + # ) client_data_hash = b"some_client_data_hash_abcdefghij" - assn = dev.get_assertion( - "yamnord.com", - client_data_hash, - # allow_list=[{"type": "public-key", "id": credential_id}], - ) - - # basic sanity check - would raise - assn.verify(client_data_hash, public_key) + for _ in range(N): + assn = dev.get_assertion( + "yamnord.com", + client_data_hash, + allow_list=[{"type": "public-key", "id": credential_id}], + ) + + # basic sanity check - would raise + assn.verify(client_data_hash, public_key) # GA/GNA combo assn = dev.get_assertion("yamnord.com", client_data_hash)