From e249f2f2c6b2fa277470a161f667fecd06649f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Wed, 29 Mar 2023 17:32:59 +0200 Subject: [PATCH] Add reading of large data objects --- Cargo.toml | 2 +- src/lib.rs | 13 +++++++---- src/state.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4bb1c0f..3763d61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,7 +74,7 @@ log-warn = [] log-error = [] [patch.crates-io] -trussed = { git = "https://github.com/Nitrokey/trussed", tag = "v0.1.0-nitrokey.8"} +trussed = { git = "https://github.com/sosthene-nitrokey/trussed", rev = "25ae084251b76bacfa8919eb8"} trussed-auth = { git = "https://github.com/trussed-dev/trussed-auth", tag = "v0.2.1"} littlefs2 = { git = "https://github.com/Nitrokey/littlefs2", tag = "v0.3.2-nitrokey-2" } diff --git a/src/lib.rs b/src/lib.rs index a31b42b..debf3a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -910,10 +910,15 @@ impl<'a, T: trussed::Client + AuthClient + trussed::client::Ed255> LoadedAuthent let offset = reply.len(); match container { Container::KeyHistoryObject => self.get_key_history_object(reply.lend())?, - _ => match ContainerStorage(container).load(self.trussed, self.options.storage)? { - Some(data) => reply.expand(&data)?, - None => return Err(Status::NotFound), - }, + _ => { + if !ContainerStorage(container).load( + self.trussed, + self.options.storage, + reply.lend(), + )? { + return Err(Status::NotFound); + } + } } reply.prepend_len(offset)?; diff --git a/src/state.rs b/src/state.rs index 93c145e..b2cf0f3 100644 --- a/src/state.rs +++ b/src/state.rs @@ -8,6 +8,7 @@ use flexiber::EncodableHeapless; use heapless::Vec; use heapless_bytes::Bytes; use iso7816::Status; +use trussed::types::OpenSeekFrom; use trussed::{ api::reply::Metadata, config::MAX_MESSAGE_LENGTH, @@ -17,6 +18,7 @@ use trussed::{ use trussed_auth::AuthClient; use crate::piv_types::CardHolderUniqueIdentifier; +use crate::reply::Reply; use crate::{constants::*, piv_types::AsymmetricAlgorithms}; use crate::{ container::{AsymmetricKeyReference, Container, ReadAccessRule, SecurityCondition}, @@ -617,6 +619,53 @@ fn load_if_exists( } } +/// Returns false if the file does not exist +fn load_if_exists_streaming( + client: &mut impl trussed::Client, + location: Location, + path: &PathBuf, + mut buffer: Reply<'_, R>, +) -> Result { + let mut read_len = 0; + let file_len; + match try_syscall!(client.read_file_chunk(location, path.clone(), OpenSeekFrom::Start(0))) { + Ok(r) => { + read_len += r.data.len(); + file_len = r.len; + buffer.expand(&r.data)?; + } + Err(_) => match try_syscall!(client.entry_metadata(location, path.clone())) { + Ok(Metadata { metadata: None }) => return Ok(false), + Ok(Metadata { + metadata: Some(_metadata), + }) => { + error!("File {path} exists but couldn't be read: {_metadata:?}"); + return Err(Status::UnspecifiedPersistentExecutionError); + } + Err(_err) => { + error!("File {path} couldn't be read: {_err:?}"); + return Err(Status::UnspecifiedPersistentExecutionError); + } + }, + } + + while read_len < file_len { + match try_syscall!(client.read_file_chunk( + location, + path.clone(), + OpenSeekFrom::Start(read_len as u32) + )) { + Ok(r) => { + read_len += r.data.len(); + buffer.expand(&r.data)?; + } + Err(_err) => error!("Failed to read chunk: {:?}", _err), + } + } + + Ok(true) +} + #[derive(Clone, Copy, Debug)] pub struct ContainerStorage(pub Container); @@ -703,13 +752,22 @@ impl ContainerStorage { } } - pub fn load( + pub fn load( self, client: &mut impl trussed::Client, storage: Location, - ) -> Result>, Status> { - load_if_exists(client, storage, &self.path()) - .map(|data| data.or_else(|| self.default().map(Bytes::from))) + mut reply: Reply<'_, R>, + ) -> Result { + if load_if_exists_streaming(client, storage, &self.path(), reply.lend())? { + return Ok(true); + } + + if let Some(data) = self.default() { + reply.expand(&data)?; + Ok(true) + } else { + Ok(false) + } } pub fn save(