From 3f93ae13ab328dfd962fc2590ebdbec44c36db1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 4 Nov 2022 10:34:48 +0100 Subject: [PATCH] Remove trussed from the persistent state --- src/lib.rs | 56 ++++++------ src/state.rs | 235 ++++++++++++++++++++++++++------------------------- 2 files changed, 146 insertions(+), 145 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 05ce02b..3985bb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,18 +115,19 @@ where pub fn login(&mut self, login: commands::VerifyLogin) -> Result { if let commands::VerifyLogin::PivPin(pin) = login { // the actual PIN verification - let mut persistent_state = self.state.persistent(&mut self.trussed); + let persistent_state = self.state.persistent(&mut self.trussed)?; if persistent_state.remaining_pin_retries() == 0 { return Err(Status::OperationBlocked); } if persistent_state.verify_pin(&pin) { - persistent_state.reset_consecutive_pin_mismatches(); + persistent_state.reset_consecutive_pin_mismatches(&mut self.trussed); self.state.runtime.app_security_status.pin_verified = true; Ok(()) } else { - let remaining = persistent_state.increment_consecutive_pin_mismatches(); + let remaining = + persistent_state.increment_consecutive_pin_mismatches(&mut self.trussed); // should we logout here? self.state.runtime.app_security_status.pin_verified = false; Err(Status::RemainingRetries(remaining)) @@ -155,7 +156,7 @@ where } else { let retries = self .state - .persistent(&mut self.trussed) + .persistent(&mut self.trussed)? .remaining_pin_retries(); Err(Status::RemainingRetries(retries)) } @@ -172,37 +173,39 @@ where } pub fn change_pin(&mut self, old_pin: commands::Pin, new_pin: commands::Pin) -> Result { - let mut persistent_state = self.state.persistent(&mut self.trussed); + let persistent_state = self.state.persistent(&mut self.trussed)?; if persistent_state.remaining_pin_retries() == 0 { return Err(Status::OperationBlocked); } if !persistent_state.verify_pin(&old_pin) { - let remaining = persistent_state.increment_consecutive_pin_mismatches(); + let remaining = + persistent_state.increment_consecutive_pin_mismatches(&mut self.trussed); self.state.runtime.app_security_status.pin_verified = false; return Err(Status::RemainingRetries(remaining)); } - persistent_state.reset_consecutive_pin_mismatches(); - persistent_state.set_pin(new_pin); + persistent_state.reset_consecutive_pin_mismatches(&mut self.trussed); + persistent_state.set_pin(new_pin, &mut self.trussed); self.state.runtime.app_security_status.pin_verified = true; Ok(()) } pub fn change_puk(&mut self, old_puk: commands::Puk, new_puk: commands::Puk) -> Result { - let mut persistent_state = self.state.persistent(&mut self.trussed); + let persistent_state = self.state.persistent(&mut self.trussed)?; if persistent_state.remaining_puk_retries() == 0 { return Err(Status::OperationBlocked); } if !persistent_state.verify_puk(&old_puk) { - let remaining = persistent_state.increment_consecutive_puk_mismatches(); + let remaining = + persistent_state.increment_consecutive_puk_mismatches(&mut self.trussed); self.state.runtime.app_security_status.puk_verified = false; return Err(Status::RemainingRetries(remaining)); } - persistent_state.reset_consecutive_puk_mismatches(); - persistent_state.set_puk(new_puk); + persistent_state.reset_consecutive_puk_mismatches(&mut self.trussed); + persistent_state.set_puk(new_puk, &mut self.trussed); self.state.runtime.app_security_status.puk_verified = true; Ok(()) } @@ -385,8 +388,7 @@ where if let Some(key) = self .state - .persistent(&mut self.trussed) - .state + .persistent(&mut self.trussed)? .keys .authentication_key { @@ -418,13 +420,9 @@ where // )? // .signature; // blocking::dbg!(&signature); - - self.state - .persistent(&mut self.trussed) - .state - .keys - .authentication_key = Some(key); - self.state.persistent(&mut self.trussed).save(); + let persistent_state = self.state.persistent(&mut self.trussed)?; + persistent_state.keys.authentication_key = Some(key); + persistent_state.save(&mut self.trussed); // let public_key = syscall!(self.trussed.derive_p256_public_key( let public_key = syscall!(self @@ -584,7 +582,7 @@ where // '5FC1 02' (351B) Container::CardHolderUniqueIdentifier => { - let guid = self.state.persistent(&mut self.trussed).guid(); + let guid = self.state.persistent(&mut self.trussed)?.guid(); piv_types::CardHolderUniqueIdentifier::default() .with_guid(guid) .encode_to_heapless_vec(reply) @@ -668,12 +666,12 @@ where return Err(Status::IncorrectP1OrP2Parameter); } + let persistent_state = self.state.persistent(&mut self.trussed)?; + // TODO: find out what all needs resetting :) - self.state.persistent(&mut self.trussed).reset_pin(); - self.state.persistent(&mut self.trussed).reset_puk(); - self.state - .persistent(&mut self.trussed) - .reset_management_key(); + persistent_state.reset_pin(&mut self.trussed); + persistent_state.reset_puk(&mut self.trussed); + persistent_state.reset_management_key(&mut self.trussed); self.state.runtime.app_security_status.pin_verified = false; self.state.runtime.app_security_status.puk_verified = false; self.state.runtime.app_security_status.management_verified = false; @@ -718,8 +716,8 @@ where } let new_management_key: [u8; 24] = new_management_key.try_into().unwrap(); self.state - .persistent(&mut self.trussed) - .set_management_key(&new_management_key); + .persistent(&mut self.trussed)? + .set_management_key(&new_management_key, &mut self.trussed); } _ => return Err(Status::FunctionNotSupported), diff --git a/src/state.rs b/src/state.rs index c3f49ef..c22dad7 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,17 +1,15 @@ use core::convert::{TryFrom, TryInto}; +use iso7816::Status; use trussed::{ block, syscall, try_syscall, types::{KeyId, Location, PathBuf}, - Client as TrussedClient, }; use crate::constants::*; use crate::{Pin, Puk}; -pub type Result = core::result::Result; - pub enum Key { Ed25519(KeyId), P256(KeyId), @@ -149,33 +147,48 @@ pub struct Keys { pub retired_keys: [Option; 20], } -#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[derive(Debug, Default, Eq, PartialEq)] pub struct State { pub runtime: Runtime, - // temporary "state", to be removed again - // pub hack: Hack, - // trussed: RefCell>, + pub persistent: Option, +} + +impl State { + pub fn load( + &mut self, + client: &mut impl trussed::Client, + ) -> Result, Status> { + if self.persistent.is_none() { + self.persistent = Some(Persistent::load_or_initialize(client)); + } + Ok(LoadedState { + runtime: &mut self.runtime, + persistent: self.persistent.as_mut().unwrap(), + }) + } + + pub fn persistent( + &mut self, + client: &mut impl trussed::Client, + ) -> Result<&mut Persistent, Status> { + Ok(self.load(client)?.persistent) + } +} + +#[derive(Debug, Eq, PartialEq)] +pub struct LoadedState<'t, const C: usize> { + pub runtime: &'t mut Runtime, + pub persistent: &'t mut Persistent, } impl State { pub fn new() -> Self { Default::default() } - - // it would be nicer to do this during "board bringup", by using TrussedService as Syscall - // - // TODO: it is really not good to overwrite user data on failure to decode old state. - // To fix this, need a flag to detect if we're "fresh", and/or initialize state in factory. - pub fn persistent<'t, T>(&mut self, trussed: &'t mut T) -> Persistent<'t, T> - where - T: TrussedClient + trussed::client::Tdes, - { - Persistent::load_or_initialize(trussed) - } } #[derive(Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] -pub struct PersistentState { +pub struct Persistent { pub keys: Keys, consecutive_pin_mismatches: u8, consecutive_puk_mismatches: u8, @@ -192,18 +205,6 @@ pub struct PersistentState { guid: [u8; 16], } -#[derive(Debug, Eq, PartialEq)] -pub struct Persistent<'t, Trussed> { - trussed: &'t mut Trussed, - pub(crate) state: PersistentState, -} - -impl AsRef for Persistent<'_, T> { - fn as_ref(&self) -> &PersistentState { - &self.state - } -} - #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Runtime { // aid: Option< @@ -304,10 +305,7 @@ pub struct AuthenticateManagement { pub challenge: [u8; 8], } -impl<'t, T> Persistent<'t, T> -where - T: TrussedClient + trussed::client::Tdes, -{ +impl Persistent { pub const PIN_RETRIES_DEFAULT: u8 = 3; // hmm...! pub const PUK_RETRIES_DEFAULT: u8 = 5; @@ -316,118 +314,130 @@ where const DEFAULT_PUK: &'static [u8] = b"12345678"; pub fn guid(&self) -> [u8; 16] { - self.state.guid + self.guid } pub fn remaining_pin_retries(&self) -> u8 { - if self.state.consecutive_pin_mismatches >= Self::PIN_RETRIES_DEFAULT { + if self.consecutive_pin_mismatches >= Self::PIN_RETRIES_DEFAULT { 0 } else { - Self::PIN_RETRIES_DEFAULT - self.state.consecutive_pin_mismatches + Self::PIN_RETRIES_DEFAULT - self.consecutive_pin_mismatches } } pub fn remaining_puk_retries(&self) -> u8 { - if self.state.consecutive_puk_mismatches >= Self::PUK_RETRIES_DEFAULT { + if self.consecutive_puk_mismatches >= Self::PUK_RETRIES_DEFAULT { 0 } else { - Self::PUK_RETRIES_DEFAULT - self.state.consecutive_puk_mismatches + Self::PUK_RETRIES_DEFAULT - self.consecutive_puk_mismatches } } + // FIXME: revisit with trussed pin management pub fn verify_pin(&self, other_pin: &Pin) -> bool { // hprintln!("verifying pin {:?} against {:?}", other_pin, &self.pin).ok(); - self.state.pin == *other_pin + self.pin == *other_pin } + // FIXME: revisit with trussed pin management pub fn verify_puk(&self, other_puk: &Puk) -> bool { // hprintln!("verifying puk {:?} against {:?}", other_puk, &self.puk).ok(); - self.state.puk == *other_puk + self.puk == *other_puk } - pub fn set_pin(&mut self, new_pin: Pin) { - self.state.pin = new_pin; - self.save(); + pub fn set_pin(&mut self, new_pin: Pin, client: &mut impl trussed::Client) { + self.pin = new_pin; + self.save(client); } - pub fn set_puk(&mut self, new_puk: Puk) { - self.state.puk = new_puk; - self.save(); + pub fn set_puk(&mut self, new_puk: Puk, client: &mut impl trussed::Client) { + self.puk = new_puk; + self.save(client); } - pub fn reset_pin(&mut self) { - self.set_pin(Pin::try_from(Self::DEFAULT_PIN).unwrap()); - self.reset_consecutive_pin_mismatches(); + pub fn reset_pin(&mut self, client: &mut impl trussed::Client) { + self.set_pin(Pin::try_from(Self::DEFAULT_PIN).unwrap(), client); + self.reset_consecutive_pin_mismatches(client); } - pub fn reset_puk(&mut self) { - self.set_puk(Puk::try_from(Self::DEFAULT_PUK).unwrap()); - self.reset_consecutive_puk_mismatches(); + pub fn reset_puk(&mut self, client: &mut impl trussed::Client) { + self.set_puk(Puk::try_from(Self::DEFAULT_PUK).unwrap(), client); + self.reset_consecutive_puk_mismatches(client); } - pub fn increment_consecutive_pin_mismatches(&mut self) -> u8 { - if self.state.consecutive_pin_mismatches >= Self::PIN_RETRIES_DEFAULT { + pub fn increment_consecutive_pin_mismatches( + &mut self, + client: &mut impl trussed::Client, + ) -> u8 { + if self.consecutive_pin_mismatches >= Self::PIN_RETRIES_DEFAULT { return 0; } - self.state.consecutive_pin_mismatches += 1; - self.save(); - Self::PIN_RETRIES_DEFAULT - self.state.consecutive_pin_mismatches + self.consecutive_pin_mismatches += 1; + self.save(client); + Self::PIN_RETRIES_DEFAULT - self.consecutive_pin_mismatches } - pub fn increment_consecutive_puk_mismatches(&mut self) -> u8 { - if self.state.consecutive_puk_mismatches >= Self::PUK_RETRIES_DEFAULT { + pub fn increment_consecutive_puk_mismatches( + &mut self, + client: &mut impl trussed::Client, + ) -> u8 { + if self.consecutive_puk_mismatches >= Self::PUK_RETRIES_DEFAULT { return 0; } - self.state.consecutive_puk_mismatches += 1; - self.save(); - Self::PUK_RETRIES_DEFAULT - self.state.consecutive_puk_mismatches + self.consecutive_puk_mismatches += 1; + self.save(client); + Self::PUK_RETRIES_DEFAULT - self.consecutive_puk_mismatches } - pub fn reset_consecutive_pin_mismatches(&mut self) -> u8 { - if self.state.consecutive_pin_mismatches != 0 { - self.state.consecutive_pin_mismatches = 0; - self.save(); + pub fn reset_consecutive_pin_mismatches(&mut self, client: &mut impl trussed::Client) -> u8 { + if self.consecutive_pin_mismatches != 0 { + self.consecutive_pin_mismatches = 0; + self.save(client); } Self::PIN_RETRIES_DEFAULT } - pub fn reset_consecutive_puk_mismatches(&mut self) -> u8 { - if self.state.consecutive_puk_mismatches != 0 { - self.state.consecutive_puk_mismatches = 0; - self.save(); + pub fn reset_consecutive_puk_mismatches(&mut self, client: &mut impl trussed::Client) -> u8 { + if self.consecutive_puk_mismatches != 0 { + self.consecutive_puk_mismatches = 0; + self.save(client); } Self::PUK_RETRIES_DEFAULT } - pub fn reset_management_key(&mut self) { - self.set_management_key(YUBICO_DEFAULT_MANAGEMENT_KEY); + pub fn reset_management_key(&mut self, client: &mut impl trussed::Client) { + self.set_management_key(YUBICO_DEFAULT_MANAGEMENT_KEY, client); } - pub fn set_management_key(&mut self, management_key: &[u8; 24]) { + pub fn set_management_key( + &mut self, + management_key: &[u8; 24], + client: &mut impl trussed::Client, + ) { // let new_management_key = syscall!(self.trussed.unsafe_inject_tdes_key( - let new_management_key = syscall!(self - .trussed - .unsafe_inject_shared_key(management_key, trussed::types::Location::Internal,)) - .key; - let old_management_key = self.state.keys.management_key; - self.state.keys.management_key = new_management_key; - self.save(); - syscall!(self.trussed.delete(old_management_key)); + let new_management_key = + syscall!(client + .unsafe_inject_shared_key(management_key, trussed::types::Location::Internal,)) + .key; + let old_management_key = self.keys.management_key; + self.keys.management_key = new_management_key; + self.save(client); + syscall!(client.delete(old_management_key)); } - pub fn initialize(trussed: &'t mut T) -> Self { + pub fn initialize(client: &mut impl trussed::Client) -> Self { info!("initializing PIV state"); - let management_key = syscall!(trussed.unsafe_inject_shared_key( + let management_key = syscall!(client.unsafe_inject_shared_key( YUBICO_DEFAULT_MANAGEMENT_KEY, trussed::types::Location::Internal, )) .key; - let mut guid: [u8; 16] = syscall!(trussed.random_bytes(16)) + let mut guid: [u8; 16] = syscall!(client.random_bytes(16)) .bytes .as_ref() .try_into() @@ -446,24 +456,21 @@ where }; let mut state = Self { - trussed, - state: PersistentState { - keys, - consecutive_pin_mismatches: 0, - consecutive_puk_mismatches: 0, - pin: Pin::try_from(Self::DEFAULT_PIN).unwrap(), - puk: Puk::try_from(Self::DEFAULT_PUK).unwrap(), - timestamp: 0, - guid, - }, + keys, + consecutive_pin_mismatches: 0, + consecutive_puk_mismatches: 0, + pin: Pin::try_from(Self::DEFAULT_PIN).unwrap(), + puk: Puk::try_from(Self::DEFAULT_PUK).unwrap(), + timestamp: 0, + guid, }; - state.save(); + state.save(client); state } #[allow(clippy::result_unit_err)] - pub fn load(trussed: &'t mut T) -> Result { - let data = block!(trussed + pub fn load(client: &mut impl trussed::Client) -> Result { + let data = block!(client .read_file(Location::Internal, PathBuf::from(Self::FILENAME),) .unwrap()) .map_err(|_err| { @@ -471,21 +478,17 @@ where })? .data; - let previous_state: PersistentState = trussed::cbor_deserialize(&data).map_err(|_err| { + let previous_state: Self = trussed::cbor_deserialize(&data).map_err(|_err| { info!("cbor deser error: {_err:?}"); info!("data: {:X?}", &data); })?; - // horrible deser bug to forget Ok here :) - Ok(Self { - trussed, - state: previous_state, - }) + Ok(previous_state) } - pub fn load_or_initialize(trussed: &'t mut T) -> Self { + pub fn load_or_initialize(client: &mut impl trussed::Client) -> Self { // todo: can't seem to combine load + initialize without code repetition let data = - try_syscall!(trussed.read_file(Location::Internal, PathBuf::from(Self::FILENAME))); + try_syscall!(client.read_file(Location::Internal, PathBuf::from(Self::FILENAME))); if let Ok(data) = data { let previous_state = trussed::cbor_deserialize(&data.data).map_err(|_err| { info!("cbor deser error: {_err:?}"); @@ -493,17 +496,17 @@ where }); if let Ok(state) = previous_state { // horrible deser bug to forget Ok here :) - return Self { trussed, state }; + return state; } } - Self::initialize(trussed) + Self::initialize(client) } - pub fn save(&mut self) { - let data: trussed::types::Message = trussed::cbor_serialize_bytes(self.as_ref()).unwrap(); + pub fn save(&mut self, client: &mut impl trussed::Client) { + let data: trussed::types::Message = trussed::cbor_serialize_bytes(&self).unwrap(); - syscall!(self.trussed.write_file( + syscall!(client.write_file( Location::Internal, PathBuf::from(Self::FILENAME), data, @@ -511,9 +514,9 @@ where )); } - pub fn timestamp(&mut self) -> u32 { - self.state.timestamp += 1; - self.save(); - self.state.timestamp + pub fn timestamp(&mut self, client: &mut impl trussed::Client) -> u32 { + self.timestamp += 1; + self.save(client); + self.timestamp } }