diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0d99f5c..8cca4a0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,5 +3,5 @@ repos: rev: v1.0 hooks: - id: fmt - - id: cargo-check - - id: clippy +# - id: cargo-check +# - id: clippy diff --git a/Cargo.lock b/Cargo.lock index 17d6e2e..4725021 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -606,28 +606,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "git-version" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6b0decc02f4636b9ccad390dcbe77b722a77efedfa393caf8379a51d5c61899" -dependencies = [ - "git-version-macro", - "proc-macro-hack", -] - -[[package]] -name = "git-version-macro" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe69f1cbdb6e28af2bac214e943b99ce8a0a06b447d15d3e61161b0423139f3f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "glob" version = "0.3.1" @@ -1181,12 +1159,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - [[package]] name = "proc-macro2" version = "1.0.60" @@ -1376,6 +1348,15 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "serde_bytes" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c5113243e4a3a1c96587342d067f3e6b0f50790b6cf40d2868eb647a3eef0e" +dependencies = [ + "serde", +] + [[package]] name = "serde_cbor" version = "0.11.2" @@ -1827,7 +1808,7 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "webcrypt" -version = "0.7.0" +version = "0.8.0" dependencies = [ "admin-app", "apdu-dispatch", @@ -1839,12 +1820,12 @@ dependencies = [ "delog", "fido-authenticator", "generic-array", - "git-version", "heapless", "heapless-bytes", "pretty_env_logger", "serde", "serde-indexed", + "serde_bytes", "trussed", "trussed-auth", "trussed-rsa-alloc", diff --git a/Cargo.toml b/Cargo.toml index 43a3e08..5890acd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ heapless-bytes = { version = "0.3.0", features = ["cbor"] } heapless = "0.7" serde = { version = "1.0", default-features = false } serde-indexed = "0.1.0" +serde_bytes = { version = "0.11.10", default-features = false, features=["alloc"] } generic-array = "0.14.3" ctap-types = "0.1" ctaphid-dispatch = "0.1" @@ -24,7 +25,6 @@ apdu-dispatch = "0.1" trussed = "0.1.0" pretty_env_logger = { version = "0.4.0", optional = true } -git-version = "0.3.5" trussed-rsa-alloc = { version = "0.1.0", optional = true } trussed-staging = { version = "0.1.0"} diff --git a/Makefile b/Makefile index 2ca8b7b..34a1881 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,9 @@ setup-fedora: ci: $(MAKE) check - cargo test + cargo build --example usbip --features $(FEATURES) + -timeout 2 $(MAKE) usbip + # TODO: run cargo test check: cargo fmt --check diff --git a/examples/udp_sim/main.rs b/examples/udp_sim/main.rs index 19ce794..21982e0 100644 --- a/examples/udp_sim/main.rs +++ b/examples/udp_sim/main.rs @@ -1,9 +1,10 @@ #[macro_use] extern crate delog; +use delog::log; use heapless_bytes::{Bytes, Bytes32}; -use webcrypt::{RequestDetails, RequestSource, Webcrypt}; +use webcrypt::{Options, RequestDetails, RequestSource, Webcrypt}; use crate::udp_server::UDPServer; @@ -13,6 +14,7 @@ mod udp_server; #[cfg(feature = "enable-logs")] use pretty_env_logger::env_logger; +use trussed::types::Location; mod virt; @@ -21,7 +23,10 @@ fn main() { env_logger::init(); virt::with_ram_client("webcrypt", |client| { - let mut w = Webcrypt::new(client); + let mut w = webcrypt::Webcrypt::new_with_options( + client, + Options::new(Location::External, *b"1234", 10000), + ); let mut server = UDPServer::new(); loop { diff --git a/examples/udp_sim/virt.rs b/examples/udp_sim/virt.rs index 7199859..c85847d 100644 --- a/examples/udp_sim/virt.rs +++ b/examples/udp_sim/virt.rs @@ -19,7 +19,7 @@ pub mod dispatch { platform::Platform, serde_extensions::{ExtensionDispatch, ExtensionId, ExtensionImpl}, service::ServiceResources, - types::{Bytes, Context, Location}, + types::{Bytes, Context}, }; use trussed_auth::{AuthBackend, AuthContext, AuthExtension, MAX_HW_KEY_LEN}; @@ -144,11 +144,10 @@ pub mod dispatch { } } -use std::path::PathBuf; use trussed::types::Location; use trussed::{ types::Bytes, - virt::{self, Client, Filesystem, Ram, StoreProvider}, + virt::{self, Client, Ram, StoreProvider}, }; /// Client type using a dispatcher with the backends required by opcard diff --git a/examples/usbip/main.rs b/examples/usbip/main.rs index 223a623..9cd6b06 100644 --- a/examples/usbip/main.rs +++ b/examples/usbip/main.rs @@ -11,15 +11,14 @@ mod dispatch { use trussed_staging::StagingBackend; use trussed_staging::StagingContext; - use trussed::serde_extensions::ExtensionImpl; use trussed::{ api::{reply, request, Reply, Request}, backend::{Backend as _, BackendId}, error::Error, platform::Platform, - serde_extensions::{ExtensionDispatch, ExtensionId, ExtensionImpl as _}, + serde_extensions::{ExtensionDispatch, ExtensionId, ExtensionImpl}, service::ServiceResources, - types::{Bytes, Context, Location}, + types::{Bytes, Context}, }; use trussed_auth::{AuthBackend, AuthContext, AuthExtension, MAX_HW_KEY_LEN}; @@ -95,6 +94,12 @@ mod dispatch { } } + impl Default for Dispatch { + fn default() -> Self { + Self::new() + } + } + impl ExtensionDispatch for Dispatch { type BackendId = Backend; type Context = DispatchContext; @@ -180,12 +185,11 @@ use clap::Parser; use clap_num::maybe_hex; use trussed::backend::BackendId; use trussed::platform::{consent, reboot, ui}; -use trussed::serde_extensions::ExtensionId; + use trussed::types::Location; use trussed::{virt, ClientImplementation, Platform}; use trussed_usbip::ClientBuilder; -use crate::dispatch::Extension; use usbd_ctaphid::constants::MESSAGE_SIZE; use webcrypt::{debug, info, try_debug, try_info, try_warn, warn}; use webcrypt::{Options, PeekingBypass}; @@ -311,11 +315,11 @@ impl trussed::platform::UserInterface for UserInterface { fn set_status(&mut self, status: ui::Status) { debug!("Set status: {:?}", status); if let ui::Status::Custom(s) = status { - let cs: CustomStatus = CustomStatus::try_from(s).unwrap_or_else(|_| { + let _cs: CustomStatus = CustomStatus::try_from(s).unwrap_or_else(|_| { warn!("Unsupported status value: {:?}", status); CustomStatus::Unknown }); - info!("Set status: [{}] {:?}", s, cs); + info!("Set status: [{}] {:?}", s, _cs); } if status == ui::Status::WaitingForUserPresence { @@ -332,8 +336,8 @@ impl trussed::platform::UserInterface for UserInterface { self.start_time.elapsed() } - fn reboot(&mut self, to: reboot::To) -> ! { - info!("Restart! ({:?})", to); + fn reboot(&mut self, _to: reboot::To) -> ! { + info!("Restart! ({:?})", _to); std::process::exit(25); } } @@ -395,7 +399,7 @@ struct Apps { const MAX_RESIDENT_CREDENTIAL_COUNT: u32 = 50; -impl<'a> trussed_usbip::Apps<'static, VirtClient, dispatch::Dispatch> for Apps { +impl trussed_usbip::Apps<'static, VirtClient, dispatch::Dispatch> for Apps { type Data = (); fn new>(builder: &B, _data: ()) -> Self { let fido = fido_authenticator::Authenticator::new( diff --git a/src/lib/commands.rs b/src/lib/commands.rs index 355bdd6..2c2795f 100644 --- a/src/lib/commands.rs +++ b/src/lib/commands.rs @@ -20,7 +20,7 @@ use crate::commands_types::*; use crate::constants::GIT_VERSION; use crate::constants::{WEBCRYPT_AVAILABLE_SLOTS_MAX, WEBCRYPT_VERSION}; use crate::rk_files::*; -use crate::transport::Webcrypt; +use crate::transport::{send_to_output, WebcryptInternal}; use crate::types::CommandID::{ChangePin, SetPin}; use crate::types::Error; @@ -82,7 +82,7 @@ impl< } #[inline(never)] -pub fn cmd_status(w: &mut Webcrypt) -> CommandResult +pub fn cmd_status(w: &mut WebcryptInternal, reply: &mut Message) -> CommandResult where C: WebcryptTrussedClient, { @@ -94,27 +94,27 @@ where pin_attempts: w.state.pin.get_counter(), version_string: Some(git_version_bytes), }; - w.send_to_output(resp); + send_to_output(resp, reply); Ok(()) } #[inline(never)] -pub fn cmd_test_ping(w: &mut Webcrypt) -> CommandResult -where - C: WebcryptTrussedClient, -{ - w.send_input_to_output(); +pub fn cmd_test_ping(req: &Message, reply: &mut Message) -> CommandResult { + reply.extend_from_slice(&req[3..]).unwrap(); Ok(()) } #[inline(never)] -pub fn cmd_generate_key(w: &mut Webcrypt) -> CommandResult +pub fn cmd_generate_key( + w: &mut WebcryptInternal, + req: CommandGenerateRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req: CommandGenerateRequest = w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; // Generate a new P256 key pair. @@ -135,24 +135,27 @@ where syscall!(w.trussed.delete(public_key)); syscall!(w.trussed.delete(private_key)); - w.send_to_output({ - let mut pubkey = Bytes65::from_slice(serialized_raw_public_key.as_slice()).unwrap(); - // add identifier for uncompressed form - 0x04 - pubkey - .insert(0, 0x04) - .map_err(|_| Error::FailedLoadingData)?; - CommandGenerateResponse { - pubkey, - keyhandle: KeyHandleSerialized::from_slice(&keyhandle_ser_enc[..]).unwrap(), - } - }); + send_to_output( + { + let mut pubkey = Bytes65::from_slice(serialized_raw_public_key.as_slice()).unwrap(); + // add identifier for uncompressed form - 0x04 + pubkey + .insert(0, 0x04) + .map_err(|_| Error::FailedLoadingData)?; + CommandGenerateResponse { + pubkey, + keyhandle: KeyHandleSerialized::from_slice(&keyhandle_ser_enc[..]).unwrap(), + } + }, + reply, + ); Ok(()) } #[inline(never)] pub fn wrap_key_to_keyhandle( - w: &mut Webcrypt, + w: &mut WebcryptInternal, private_key: KeyId, ) -> Result where @@ -207,27 +210,27 @@ where } #[inline(never)] -pub fn cmd_sign(w: &mut Webcrypt) -> CommandResult +pub fn cmd_sign( + w: &mut WebcryptInternal, + req: CommandSignRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req: CommandSignRequest = w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; - if !(req.keyhandle.len() > 0 && req.hash.len() > 0) { + if !(!req.keyhandle.is_empty() && !req.hash.is_empty()) { return Err(Error::FailedLoadingData); } let (key, mechanism, keyhandle_points_to_rk) = get_key_from_keyhandle(w, req.keyhandle)?; - let signature = syscall!(w.trussed.sign( - mechanism, - key, - req.hash.as_slice(), - SignatureSerialization::Raw - )) + let signature = syscall!(w + .trussed + .sign(mechanism, key, req.hash, SignatureSerialization::Raw)) .signature; let signature = signature.to_bytes().expect("Too small target buffer"); @@ -235,41 +238,39 @@ where syscall!(w.trussed.delete(key)); } - w.send_to_output({ + send_to_output( CommandSignResponse { inhash: req.hash, signature, - } - }); + }, + reply, + ); Ok(()) } #[inline(never)] fn get_key_from_keyhandle( - w: &mut Webcrypt, - keyhandle: KeyHandleSerialized, + w: &mut WebcryptInternal, + keyhandle: &[u8], ) -> ResultW<(KeyId, Mechanism, bool)> where C: WebcryptTrussedClient, { - if keyhandle.len() == 0 { + if keyhandle.is_empty() { return Err(BadFormat); } let res = if keyhandle.len() > 32 { // invalid keyhandle or lack of memory - let (keyid, mechanism) = import_key_from_keyhandle(w, &keyhandle)?; + let (keyid, mechanism) = import_key_from_keyhandle(w, keyhandle)?; (keyid, mechanism, false) } else { // this is RK let rp_id_hash = w.session.rp_id_hash.as_ref().unwrap(); let cred_data = try_syscall!(w.trussed.read_file( w.options.location, - rk_path( - rp_id_hash, - &Bytes32::from_slice(keyhandle.as_slice()).unwrap() - ) + rk_path(rp_id_hash, &Bytes32::from_slice(keyhandle).unwrap()) )) .map_err(|_| Error::MemoryFull)? .data; @@ -282,18 +283,17 @@ where #[inline(never)] fn cred_to_mechanism(cred: &CredentialData) -> Mechanism { - let mech = match cred.algorithm { + match cred.algorithm { 0 => Mechanism::P256, 1 => Mechanism::Rsa2048Pkcs1v15, _ => Mechanism::P256, - }; - mech + } } #[inline(never)] fn import_key_from_keyhandle( - w: &mut Webcrypt, - encrypted_serialized_keyhandle: &KeyHandleSerialized, + w: &mut WebcryptInternal, + encrypted_serialized_keyhandle: &[u8], ) -> Result<(KeyId, Mechanism), Error> where C: WebcryptTrussedClient, @@ -307,8 +307,8 @@ where let appid = w.session.rp_id_hash.clone().ok_or(Error::BadOrigin)?; - let encr_message: Encrypt = cbor_deserialize(encrypted_serialized_keyhandle.as_slice()) - .map_err(|_| Error::BadFormat)?; + let encr_message: Encrypt = + cbor_deserialize(encrypted_serialized_keyhandle).map_err(|_| Error::BadFormat)?; let kek = w .store @@ -354,28 +354,28 @@ where } #[inline(never)] -pub fn cmd_openpgp_generate(w: &mut Webcrypt) -> CommandResult +pub fn cmd_openpgp_generate( + w: &mut WebcryptInternal, + _req: CommandOpenPGPInitRequest, + _reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let _: CommandOpenPGPInitRequest = w - .get_input_deserialized() - .map_err(|_| Error::FailedLoadingData)?; - w.state.openpgp_data = Some(OpenPGPData::init(&mut w.trussed, w.options.location)); w.state.save(&mut w.trussed); Ok(()) } #[inline(never)] -pub fn cmd_openpgp_info(w: &mut Webcrypt) -> CommandResult +pub fn cmd_openpgp_info( + w: &mut WebcryptInternal, + _req: CommandOpenPGPInfoRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let _: CommandOpenPGPInfoRequest = w - .get_input_deserialized() - .map_err(|_| Error::FailedLoadingData)?; - // FIXME remove -> initialize in a separate command // move to state initialization if w.state.openpgp_data.is_none() { @@ -413,32 +413,30 @@ where // let sign_keyhandle = wrap_key_to_keyhandle(w, openpgp_data.signing.key)?; let date = DataBytes::from_slice(&openpgp_data.date).map_err(|_| Error::InternalError)?; - w.send_to_output(CommandOpenPGPInfoResponse { - encr_pubkey, - auth_pubkey, - sign_pubkey, - date, - }); + send_to_output( + CommandOpenPGPInfoResponse { + encr_pubkey, + auth_pubkey, + sign_pubkey, + date, + }, + reply, + ); Ok(()) } #[inline(never)] -pub fn cmd_openpgp_import(w: &mut Webcrypt) -> CommandResult +pub fn cmd_openpgp_import( + w: &mut WebcryptInternal, + req: CommandOpenPGPImportRequest, + _reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req = match w.get_input_deserialized() { - Ok(x) => Ok(x), - Err(e) => { - error!("Deserialization error: {:?}", e); - Err(e) - } - }; - - let req: CommandOpenPGPImportRequest = req.map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; w.state.openpgp_data = Some(OpenPGPData::import( @@ -455,21 +453,16 @@ where } #[inline(never)] -pub fn cmd_openpgp_sign(w: &mut Webcrypt) -> CommandResult +pub fn cmd_openpgp_sign( + w: &mut WebcryptInternal, + req: CommandOpenPGPSignRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req = match w.get_input_deserialized() { - Ok(x) => Ok(x), - Err(e) => { - error!("Deserialization error: {:?}", e); - Err(e) - } - }; - - let req: CommandOpenPGPSignRequest = req.map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; // FIXME remove -> initialize in a separate command @@ -485,34 +478,29 @@ where req.data.as_slice(), SignatureSerialization::Raw )) - .map_err(|e| { - error!("Signing error: {:?}", e); + .map_err(|_e| { + error!("Signing error: {:?}", _e); Error::FailedLoadingData })? .signature; let signature = signature.to_bytes().expect("Too small target buffer"); - w.send_to_output(CommandOpenPGPSignResponse { signature }); + send_to_output(CommandOpenPGPSignResponse { signature }, reply); Ok(()) } #[inline(never)] -pub fn cmd_openpgp_decrypt(w: &mut Webcrypt) -> CommandResult +pub fn cmd_openpgp_decrypt( + w: &mut WebcryptInternal, + req: CommandOpenPGPDecryptRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req = match w.get_input_deserialized() { - Ok(x) => Ok(x), - Err(e) => { - error!("Deserialization error: {:?}", e); - Err(e) - } - }; - - let req: CommandOpenPGPDecryptRequest = req.map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; // FIXME remove -> initialize in a separate command @@ -525,7 +513,7 @@ where // TODO find via provided fingerprint if not, get from openpgp info struct, or use the first one // Currently check for the exact match of the held openpgp keys and their fingerprints // if provided, use keyhandle or just default encryption key - let (kh_key, mech, is_rk) = if req.fingerprint.is_none() && req.keyhandle.is_none() { + let (kh_key, _mech, _is_rk) = if req.fingerprint.is_none() && req.keyhandle.is_none() { let open_pgpkey = &w .state .openpgp_data @@ -590,39 +578,37 @@ where agreed_shared_secret_id, KeySerialization::Raw )) - .map_err(|e| { - error!("Deserialization error: {:?}", e); + .map_err(|_e| { + error!("Deserialization error: {:?}", _e); Error::InternalError })?; syscall!(w.trussed.delete(agreed_shared_secret_id)); - w.send_to_output(CommandOpenPGPDecryptResponse { - data: DataBytes::from_slice(&serialized_shared_secret.serialized_key) - .map_err(|_| Error::InternalError)?, - }); + send_to_output( + CommandOpenPGPDecryptResponse { + data: DataBytes::from_slice(&serialized_shared_secret.serialized_key) + .map_err(|_| Error::InternalError)?, + }, + reply, + ); Ok(()) } #[inline(never)] -pub fn cmd_decrypt(w: &mut Webcrypt) -> CommandResult +pub fn cmd_decrypt( + w: &mut WebcryptInternal, + req: CommandDecryptRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req = match w.get_input_deserialized() { - Ok(x) => Ok(x), - Err(e) => { - error!("Deserialization error: {:?}", e); - Err(e) - } - }; - - let req: CommandDecryptRequest = req.map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp.clone()) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; - let (kh_key, mech, is_rk) = get_key_from_keyhandle(w, req.keyhandle.clone())?; + let (kh_key, mech, is_rk) = get_key_from_keyhandle(w, req.keyhandle)?; let decrypted = match mech { Mechanism::P256 => decrypt_ecc_p256(w, req, kh_key), @@ -635,26 +621,29 @@ where syscall!(w.trussed.delete(kh_key)); } - w.send_to_output(CommandDecryptResponse { - data: Bytes::from_slice(decrypted.as_slice()).unwrap(), - }); + send_to_output( + CommandDecryptResponse { + data: Bytes::from_slice(decrypted.as_slice()).unwrap(), + }, + reply, + ); Ok(()) } #[inline(never)] fn decrypt_rsa( - w: &mut Webcrypt, + _w: &mut WebcryptInternal, req: CommandDecryptRequest, - kh_key: KeyId, + _kh_key: KeyId, ) -> ResultW where C: WebcryptTrussedClient, { - if !(req.keyhandle.len() > 0 - && req.data.len() > 0 - && req.hmac.is_none() - && req.eccekey.is_none()) + if req.keyhandle.is_empty() + || req.data.is_empty() + || req.hmac.is_some() + || req.eccekey.is_some() { return Err(Error::BadFormat); } @@ -673,7 +662,7 @@ where #[inline(never)] fn decrypt_ecc_p256( - w: &mut Webcrypt, + w: &mut WebcryptInternal, req: CommandDecryptRequest, kh_key: KeyId, ) -> ResultW @@ -682,23 +671,23 @@ where { let req_eccekey = req.eccekey.ok_or(BadFormat)?; let req_hmac = req.hmac.ok_or(BadFormat)?; - if !(req.keyhandle.len() > 0 - && req_eccekey.len() > 0 - && req.data.len() > 0 - && req_hmac.len() > 0) + if !(!req.keyhandle.is_empty() + && !req_eccekey.is_empty() + && !req.data.is_empty() + && !req_hmac.is_empty()) { return Err(BadFormat); } - let ecc_key: Vec = match req_eccekey.len() { - 65 => Vec::::from_slice(&req_eccekey[1..65]).unwrap(), - 64 => Vec::::from_slice(&req_eccekey[0..64]).unwrap(), + let ecc_key = match req_eccekey.len() { + 65 => &req_eccekey[1..65], + 64 => &req_eccekey[0..64], _ => return Err(Error::FailedLoadingData), }; // import incoming public key let ephem_pub_bin_key = try_syscall!(w.trussed.deserialize_p256_key( - &ecc_key, + ecc_key, trussed::types::KeySerialization::Raw, trussed::types::StorageAttributes::new() .set_persistence(trussed::types::Location::Volatile) @@ -722,10 +711,18 @@ where // TODO DESIGN derive separate key for HMAC let encoded_ciphertext_len: [u8; 2] = (req.data.len() as u16).to_le_bytes(); let mut data_to_hmac = Message::new(); // FIXME check length - data_to_hmac.extend(req.data.clone()); - data_to_hmac.extend(req_eccekey); - data_to_hmac.extend(encoded_ciphertext_len); - data_to_hmac.extend(req.keyhandle); + data_to_hmac + .extend_from_slice(req.data) + .map_err(|_| InternalError)?; + data_to_hmac + .extend_from_slice(req_eccekey) + .map_err(|_| InternalError)?; + data_to_hmac + .extend_from_slice(&encoded_ciphertext_len) + .map_err(|_| InternalError)?; + data_to_hmac + .extend_from_slice(req.keyhandle) + .map_err(|_| InternalError)?; let calculated_hmac = try_syscall!(w.trussed.sign( Mechanism::HmacSha256, @@ -755,8 +752,8 @@ where shared_secret, KeySerialization::Raw )) - .map_err(|e| { - error!("Deserialization error: {:?}", e); + .map_err(|_e| { + error!("Deserialization error: {:?}", _e); Error::InternalError })? .serialized_key; @@ -774,34 +771,34 @@ where .ok_or(Error::FailedLoadingData)?; // decrypt with shared secret - let decrypted = try_syscall!(w - .trussed - .decrypt_aes256cbc(serialized_reimported, &req.data)) - .map_err(|e| { - error!("Decryption error: {:?}", e); - Error::FailedLoadingData - })? - .plaintext - .ok_or(Error::InternalError)?; + let decrypted = try_syscall!(w.trussed.decrypt_aes256cbc(serialized_reimported, req.data)) + .map_err(|_e| { + error!("Decryption error: {:?}", _e); + Error::FailedLoadingData + })? + .plaintext + .ok_or(Error::InternalError)?; syscall!(w.trussed.delete(shared_secret)); syscall!(w.trussed.delete(serialized_reimported)); syscall!(w.trussed.delete(ephem_pub_bin_key)); - Ok(decrypted + decrypted .try_convert_into() - .map_err(|_| Error::InternalError)?) + .map_err(|_| Error::InternalError) } #[cfg(feature = "hmacsha256p256")] #[inline(never)] -pub fn cmd_generate_key_from_data(w: &mut Webcrypt) -> CommandResult +pub fn cmd_generate_key_from_data( + w: &mut WebcryptInternal, + req: CommandGenerateFromDataRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req: CommandGenerateFromDataRequest = - w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; let kek = w.state.get_key_master(&mut w.trussed).unwrap(); @@ -810,7 +807,7 @@ where // req.hash // .extend_from_slice(rpid.as_slice()) // .map_err(|_| Error::FailedLoadingData)?; - let data_for_key = &req.hash[..]; + let data_for_key = req.hash; if req.hash.len() < 32 { return Err(Error::FailedLoadingData); } @@ -837,31 +834,36 @@ where syscall!(w.trussed.delete(public_key)); syscall!(w.trussed.delete(private_key)); - w.send_to_output({ - let mut pubkey = Bytes65::from_slice(serialized_raw_public_key.as_slice()).unwrap(); - // add identifier for uncompressed form - 0x04 - pubkey - .insert(0, 0x04) - .map_err(|_| Error::FailedLoadingData)?; - CommandGenerateResponse { - pubkey, - keyhandle: KeyHandleSerialized::from_slice(&keyhandle_ser_enc[..]).unwrap(), - } - }); + send_to_output( + { + let mut pubkey = Bytes65::from_slice(serialized_raw_public_key.as_slice()).unwrap(); + // add identifier for uncompressed form - 0x04 + pubkey + .insert(0, 0x04) + .map_err(|_| Error::FailedLoadingData)?; + CommandGenerateResponse { + pubkey, + keyhandle: KeyHandleSerialized::from_slice(&keyhandle_ser_enc[..]).unwrap(), + } + }, + reply, + ); Ok(()) } #[inline(never)] -pub fn cmd_read_resident_key_public(w: &mut Webcrypt) -> CommandResult +pub fn cmd_read_resident_key_public( + w: &mut WebcryptInternal, + req: CommandReadResidentKeyRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req: CommandReadResidentKeyRequest = - w.get_input_deserialized().map_err(|_| Error::BadFormat)?; info!("WC cmd_read_resident_key_public {:?}", req); w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; // Get private keyid @@ -894,7 +896,7 @@ where // .to_bytes() // .unwrap(); - let (private_key, mech, is_rk) = get_key_from_keyhandle(w, req.keyhandle.clone())?; + let (private_key, mech, is_rk) = get_key_from_keyhandle(w, req.keyhandle)?; let kind = match mech { Mechanism::P256 => Kind::P256, @@ -908,38 +910,41 @@ where // FIXME introduce types to distinct derived and resident keys syscall!(w.trussed.delete(private_key)); } - w.send_to_output({ - let mut pubkey = Message::from_slice(serialized_raw_public_key.as_slice()).unwrap(); - if kind == Kind::P256 { - // add identifier for uncompressed form - 0x04 - pubkey.insert(0, 0x04).map_err(|_| InternalError)?; - } - CommandGenerateResidentKeyResponse { - pubkey: pubkey.try_convert_into().map_err(|_| InternalError)?, - keyhandle: req.keyhandle, - } - }); + send_to_output( + { + let mut pubkey = Message::from_slice(serialized_raw_public_key.as_slice()).unwrap(); + if kind == Kind::P256 { + // add identifier for uncompressed form - 0x04 + pubkey.insert(0, 0x04).map_err(|_| InternalError)?; + } + CommandGenerateResidentKeyResponse { + pubkey: pubkey.try_convert_into().map_err(|_| InternalError)?, + keyhandle: req.keyhandle, + } + }, + reply, + ); Ok(()) } #[inline(never)] -pub fn cmd_login(w: &mut Webcrypt) -> CommandResult +pub fn cmd_login( + w: &mut WebcryptInternal, + req: CommandLoginRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { // Check PIN and return temporary password for the further communication - let req: CommandLoginRequest = w.get_input_deserialized().map_err(|_| Error::BadFormat)?; // hash rpid if the request is coming from FIDO2 // TODO move hashing to transport let rpid = { let rpid = &w.req_details.as_ref().unwrap().rpid; if w.req_details.as_ref().unwrap().source == RequestSource::RS_FIDO2 { - hash( - &mut w.trussed, - Message::from_slice(rpid.as_slice()).unwrap(), - ) + hash(&mut w.trussed, rpid.as_slice()).map_err(|_| Error::InternalError)? } else { rpid.clone() } @@ -965,17 +970,21 @@ where w.state.save(&mut w.trussed); let tp = login_result?; - w.send_to_output(CommandLoginResponse { tp }); + send_to_output(CommandLoginResponse { tp }, reply); Ok(()) } #[inline(never)] -pub fn cmd_logout(w: &mut Webcrypt) -> CommandResult +pub fn cmd_logout( + w: &mut WebcryptInternal, + _req: CommandLogoutRequest, + _reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let _: CommandLogoutRequest = w.get_input_deserialized().map_err(|_| Error::BadFormat)?; + // let _: CommandLogoutRequest = w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.state.save(&mut w.trussed); // Clear session @@ -992,7 +1001,7 @@ where } #[inline(never)] -pub fn cmd_factory_reset(w: &mut Webcrypt) -> CommandResult +pub fn cmd_factory_reset(w: &mut WebcryptInternal, _reply: &mut Message) -> CommandResult where C: WebcryptTrussedClient, { @@ -1026,17 +1035,21 @@ where } #[inline(never)] -pub fn cmd_configure(w: &mut Webcrypt) -> CommandResult +pub fn cmd_configure( + w: &mut WebcryptInternal, + mut req: CommandConfigureRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { // Allow to set some configuration options, like when to require user touch confirmation // To decide: same handler for both setting and getting? - let mut req: CommandConfigureRequest = - w.get_input_deserialized().map_err(|_| Error::BadFormat)?; + // let mut req: CommandConfigureRequest = + // w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; if req.confirmation.is_some() { @@ -1044,13 +1057,18 @@ where } req.confirmation = Some(w.state.configuration.confirmation); req.tp = None; - w.send_to_output(req); + send_to_output(req, reply); Ok(()) } #[inline(never)] -pub fn cmd_manage_pin(w: &mut Webcrypt) -> CommandResult +pub fn cmd_manage_pin( + w: &mut WebcryptInternal, + req: Option, + req2: Option, + _reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { @@ -1058,8 +1076,7 @@ where match w.current_command_id { SetPin => { - let req: CommandSetPINRequest = - w.get_input_deserialized().map_err(|_| Error::BadFormat)?; + let req = req.unwrap(); w.state.pin.set_pin(req.pin)?; #[cfg(feature = "transparent-encryption")] @@ -1076,8 +1093,7 @@ where Ok(()) } ChangePin => { - let req: CommandChangePINRequest = - w.get_input_deserialized().map_err(|_| Error::BadFormat)?; + let req = req2.unwrap(); w.state.pin.change_pin(req.pin, req.newpin)?; #[cfg(feature = "transparent-encryption")] try_syscall!(w @@ -1092,16 +1108,18 @@ where } #[inline(never)] -pub fn cmd_discover_resident_key(w: &mut Webcrypt) -> CommandResult +pub fn cmd_discover_resident_key( + w: &mut WebcryptInternal, + req: CommandDiscoverResidentKeyRequest, + _reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { // Discover all RKs connected to this RP. Should be protected with PIN (L3 credprotect as of CTAP2.1). - let req: CommandDiscoverResidentKeyRequest = - w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; // then store key, making it resident @@ -1152,14 +1170,16 @@ where } #[inline(never)] -pub fn cmd_write_resident_key(w: &mut Webcrypt) -> CommandResult +pub fn cmd_write_resident_key( + w: &mut WebcryptInternal, + req: CommandWriteResidentKeyRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req: CommandWriteResidentKeyRequest = - w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; let rp_id_hash = w.session.rp_id_hash.as_ref().unwrap(); @@ -1232,17 +1252,20 @@ where syscall!(w.trussed.delete(public_key)); - w.send_to_output({ - let mut pubkey = Message::from_slice(serialized_raw_public_key.as_slice()).unwrap(); - if kind == Kind::P256 { - // add identifier for uncompressed form - 0x04 - pubkey.insert(0, 0x04).map_err(|_| Error::InternalError)?; - } - CommandWriteResidentKeyResponse { - pubkey: pubkey.try_convert_into().map_err(|_| InternalError)?, - keyhandle: Bytes::from_slice(credential_id_hash.as_slice()).unwrap(), - } - }); + send_to_output( + { + let mut pubkey = Message::from_slice(serialized_raw_public_key.as_slice()).unwrap(); + if kind == Kind::P256 { + // add identifier for uncompressed form - 0x04 + pubkey.insert(0, 0x04).map_err(|_| Error::InternalError)?; + } + CommandWriteResidentKeyResponse { + pubkey: pubkey.try_convert_into().map_err(|_| InternalError)?, + keyhandle: credential_id_hash.as_slice(), + } + }, + reply, + ); Ok(()) } @@ -1261,7 +1284,7 @@ fn keytype_to_kind(key_type: &KeyType) -> Kind { #[inline(never)] fn get_public_key( - w: &mut Webcrypt, + w: &mut WebcryptInternal, kind: Kind, private_key: KeyId, ) -> ResultW<(KeyId, SerializedKey)> @@ -1305,16 +1328,18 @@ where } #[inline(never)] -pub fn cmd_generate_resident_key(w: &mut Webcrypt) -> CommandResult +pub fn cmd_generate_resident_key( + w: &mut WebcryptInternal, + req: CommandGenerateResidentKeyRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient + client::Sha256, { // write the RK similarly, as done with FIDO2, potentially with some extensions - let req: CommandGenerateResidentKeyRequest = - w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; // Generate a new P256 key pair. @@ -1352,27 +1377,33 @@ where syscall!(w.trussed.delete(public_key)); - w.send_to_output({ - let mut pubkey = Message::from_slice(serialized_raw_public_key.as_slice()).unwrap(); - // add identifier for uncompressed form - 0x04 - pubkey.insert(0, 0x04).map_err(|_| Error::InternalError)?; - CommandGenerateResidentKeyResponse { - pubkey: pubkey.try_convert_into().map_err(|_| InternalError)?, - keyhandle: Bytes::from_slice(credential_id_hash.as_slice()).unwrap(), - } - }); + send_to_output( + { + let mut pubkey = Message::from_slice(serialized_raw_public_key.as_slice()).unwrap(); + // add identifier for uncompressed form - 0x04 + pubkey.insert(0, 0x04).map_err(|_| Error::InternalError)?; + CommandGenerateResidentKeyResponse { + pubkey: pubkey.try_convert_into().map_err(|_| InternalError)?, + keyhandle: credential_id_hash.as_slice(), + } + }, + reply, + ); Ok(()) } #[inline(never)] -pub fn cmd_restore_from_seed(w: &mut Webcrypt) -> CommandResult +pub fn cmd_restore_from_seed( + w: &mut WebcryptInternal, + req: CommandRestoreRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req: CommandRestoreRequest = w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; let master = &req.master; @@ -1396,19 +1427,22 @@ where .to_bytes() .unwrap(); - w.send_to_output(CommandRestoreResponse { hash }); + send_to_output(CommandRestoreResponse { hash }, reply); Ok(()) } #[inline(never)] -pub fn cmd_initialize_seed(w: &mut Webcrypt) -> CommandResult +pub fn cmd_initialize_seed( + w: &mut WebcryptInternal, + req: CommandInitializeRequest, + reply: &mut Message, +) -> CommandResult where C: WebcryptTrussedClient, { - let req: CommandInitializeRequest = w.get_input_deserialized().map_err(|_| Error::BadFormat)?; w.session - .check_token_res(req.tp) + .check_token_res(&req.tp) .map_err(|_| Error::RequireAuthentication)?; if req.entropy.is_some() && req.entropy.unwrap().len() > 0 { @@ -1421,12 +1455,13 @@ where // TODO DESIGN to reconsider publishing raw key let master = w.state.get_master_key_raw().unwrap_or_default(); - w.send_to_output({ + send_to_output( CommandInitializeResponse { master, salt: Default::default(), - } - }); + }, + reply, + ); Ok(()) } diff --git a/src/lib/commands_types.rs b/src/lib/commands_types.rs index 6728c91..fbe204b 100644 --- a/src/lib/commands_types.rs +++ b/src/lib/commands_types.rs @@ -1,5 +1,5 @@ use crate::MAX_MESSAGE_LENGTH; -use heapless_bytes::{Bytes, Bytes32, Bytes64}; +use heapless_bytes::{Bytes, Bytes32}; use serde::{Deserialize, Serialize}; use trussed::types::{KeyId, Mechanism, Message}; @@ -23,13 +23,12 @@ pub struct CommandStatusResponse { pub type Bytes8 = Bytes<8>; pub type Bytes40 = Bytes<40>; pub type Bytes65 = Bytes<65>; -pub type Bytes200 = Bytes<200>; -pub type Bytes250 = Bytes<250>; pub type Bytes512 = Bytes<512>; pub type WebcryptMessage = Bytes<{ MAX_MESSAGE_LENGTH }>; pub type DataBytes = WebcryptMessage; // pub type WebcryptMessage = Message; pub type SessionToken = Bytes32; +pub type PinBytes = Bytes32; pub type ExpectedSessionToken = Option; pub(crate) type SerializedCredential = Message; pub type ResultW = Result; @@ -83,9 +82,10 @@ pub struct CommandGenerateResponse { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] -pub struct CommandSignResponse { +pub struct CommandSignResponse<'a> { /// signed hash, the same given on input, 32 bytes - pub(crate) inhash: Bytes64, + #[serde(with = "serde_bytes")] + pub(crate) inhash: &'a [u8], /// signature, should be less than 100 bytes pub(crate) signature: Message, @@ -93,12 +93,14 @@ pub struct CommandSignResponse { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] -pub struct CommandSignRequest { +pub struct CommandSignRequest<'a> { /// hash to sign, 32 bytes - pub(crate) hash: Bytes64, + #[serde(with = "serde_bytes")] + pub(crate) hash: &'a [u8], /// key handle, should be less than 200 bytes - pub(crate) keyhandle: KeyHandleSerialized, + #[serde(with = "serde_bytes")] + pub(crate) keyhandle: &'a [u8], #[serde(skip_serializing_if = "Option::is_none")] pub(crate) tp: ExpectedSessionToken, @@ -106,13 +108,14 @@ pub struct CommandSignRequest { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] -pub struct CommandOpenPGPDecryptRequest { +pub struct CommandOpenPGPDecryptRequest<'a> { /// ephemeral ecc encryption key pub(crate) eccekey: DataBytes, /// key handle, should be less than 200 bytes #[serde(skip_serializing_if = "Option::is_none")] - pub(crate) keyhandle: Option, + #[serde(with = "serde_bytes")] + pub(crate) keyhandle: Option<&'a [u8]>, /// public key fingerprint #[serde(skip_serializing_if = "Option::is_none")] @@ -156,16 +159,18 @@ pub struct CommandOpenPGPSignResponse { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] -pub struct CommandOpenPGPInfoRequest { +pub struct CommandOpenPGPEmptyRequest { #[serde(skip_serializing_if = "Option::is_none")] pub(crate) tp: ExpectedSessionToken, } -pub type CommandOpenPGPInitRequest = CommandOpenPGPInfoRequest; +pub type CommandOpenPGPInitRequest = CommandOpenPGPEmptyRequest; +pub type CommandOpenPGPInfoRequest = CommandOpenPGPEmptyRequest; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] pub struct CommandOpenPGPInfoResponse { + // TODO: move from Message to &[u8] pub(crate) encr_pubkey: DataBytes, pub(crate) auth_pubkey: DataBytes, pub(crate) sign_pubkey: DataBytes, @@ -176,6 +181,7 @@ pub struct CommandOpenPGPInfoResponse { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] pub struct CommandOpenPGPImportRequest { + // TODO: move from Message to &[u8] pub(crate) encr_privkey: DataBytes, pub(crate) auth_privkey: DataBytes, pub(crate) sign_privkey: DataBytes, @@ -191,20 +197,24 @@ pub struct CommandOpenPGPImportRequest { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] -pub struct CommandDecryptRequest { +pub struct CommandDecryptRequest<'a> { /// data to decrypt - pub(crate) data: DataBytes, + #[serde(with = "serde_bytes")] + pub(crate) data: &'a [u8], #[serde(skip_serializing_if = "Option::is_none")] /// ciphertext's hmac - pub(crate) hmac: Option, + #[serde(with = "serde_bytes")] + pub(crate) hmac: Option<&'a [u8]>, #[serde(skip_serializing_if = "Option::is_none")] /// ephemeral ecc encryption key - pub(crate) eccekey: Option, + #[serde(with = "serde_bytes")] + pub(crate) eccekey: Option<&'a [u8]>, /// key handle, should be less than 200 bytes - pub(crate) keyhandle: KeyHandleSerialized, + #[serde(with = "serde_bytes")] + pub(crate) keyhandle: &'a [u8], #[serde(skip_serializing_if = "Option::is_none")] pub(crate) tp: ExpectedSessionToken, @@ -230,9 +240,10 @@ pub type CommandLogoutRequest = CommandEmptyRequest; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] -pub struct CommandGenerateFromDataRequest { +pub struct CommandGenerateFromDataRequest<'a> { /// data to be used for key derivation - pub(crate) hash: DataBytes, + #[serde(with = "serde_bytes")] + pub(crate) hash: &'a [u8], #[serde(skip_serializing_if = "Option::is_none")] pub(crate) tp: ExpectedSessionToken, @@ -330,18 +341,18 @@ pub struct CommandGenerateResidentKeyRequest { pub(crate) tp: ExpectedSessionToken, } -pub type CommandWriteResidentKeyResponse = CommandGenerateResidentKeyResponse; +pub type CommandWriteResidentKeyResponse<'a> = CommandGenerateResidentKeyResponse<'a>; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] -pub struct CommandGenerateResidentKeyResponse { +pub struct CommandGenerateResidentKeyResponse<'a> { /// resulting public key pub(crate) pubkey: Message, /// key handle, should be less than 200 bytes /// should contain short KH, with the type==RK - // pub(crate) keyhandle: KeyHandleSerialized, - pub(crate) keyhandle: KeyHandleSerialized, + #[serde(with = "serde_bytes")] + pub(crate) keyhandle: &'a [u8], } #[derive(Serialize, Deserialize, Debug)] @@ -367,10 +378,11 @@ pub struct CommandDiscoverResidentKeyResponse { #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "UPPERCASE")] -pub struct CommandReadResidentKeyRequest { +pub struct CommandReadResidentKeyRequest<'a> { /// key handle, should be less than 200 bytes /// should contain short KH, with the type==RK - pub(crate) keyhandle: KeyHandleSerialized, + #[serde(with = "serde_bytes")] + pub(crate) keyhandle: &'a [u8], #[serde(skip_serializing_if = "Option::is_none")] pub(crate) tp: ExpectedSessionToken, @@ -380,7 +392,7 @@ pub struct CommandReadResidentKeyRequest { #[serde(rename_all = "UPPERCASE")] pub struct CommandLoginRequest { /// User PIN. Equal requirements to the FIDO2 PIN. - pub(crate) pin: Bytes64, + pub(crate) pin: PinBytes, // TODO this command does not need TP, but added this field // to make the calls unified. Remove later? @@ -392,7 +404,7 @@ pub struct CommandLoginRequest { #[serde(rename_all = "UPPERCASE")] pub struct CommandSetPINRequest { /// User PIN. Equal requirements to the FIDO2 PIN. - pub(crate) pin: Bytes64, + pub(crate) pin: PinBytes, // TODO this command does not need TP, but added this field // to make the calls unified. Remove later? @@ -404,8 +416,8 @@ pub struct CommandSetPINRequest { #[serde(rename_all = "UPPERCASE")] pub struct CommandChangePINRequest { /// User PIN. Equal requirements to the FIDO2 PIN. - pub(crate) pin: Bytes64, - pub(crate) newpin: Bytes64, + pub(crate) pin: PinBytes, + pub(crate) newpin: PinBytes, // TODO this command does not need TP, but added this field // to make the calls unified. Remove later? diff --git a/src/lib/constants.rs b/src/lib/constants.rs index 7b5e02d..e687d3c 100644 --- a/src/lib/constants.rs +++ b/src/lib/constants.rs @@ -1,6 +1,4 @@ -use git_version::git_version; - -pub const GIT_VERSION: &str = git_version!(); +pub const GIT_VERSION: &str = env!("CARGO_PKG_VERSION"); // TODO rename to not confuse with FIDO2 RKs pub const RESIDENT_KEY_COUNT: usize = 50; diff --git a/src/lib/ctap_app.rs b/src/lib/ctap_app.rs index fd3c65e..c160f50 100644 --- a/src/lib/ctap_app.rs +++ b/src/lib/ctap_app.rs @@ -10,14 +10,12 @@ use ctap_types::webauthn::PublicKeyCredentialUserEntity; use ctap_types::{ctap1, ctap2}; use ctaphid_dispatch::app; use ctaphid_dispatch::app as ctaphid; -use ctaphid_dispatch::app::{AppResult, Command}; use heapless_bytes::Bytes; use crate::helpers::hash; use crate::transport::Webcrypt; use crate::types::RequestSource::RS_FIDO2; use crate::types::{CtapSignatureSize, RequestDetails, RequestSource}; -use crate::Message; #[inline(never)] fn try_handle_ctap1( @@ -96,7 +94,7 @@ where } Err(status) => { let code: [u8; 2] = status.into(); - info!("WC CTAP1 error: {:?} ({})", status, hex_str!(&code)); + info!("WC CTAP1 error: {:?} ({:?})", status, code); response.extend_from_slice(&code).ok(); } } @@ -132,10 +130,8 @@ where let output = Bytes::new(); let data = request.allow_list.unwrap(); let data = &data[0].id; - let rpid_hash = hash( - &mut w.trussed, - Message::from_slice(request.rp_id.as_bytes()).unwrap(), - ); + let rpid_hash = hash(&mut w.wc.trussed, request.rp_id.as_bytes()) + .map_err(|_| ctap2::Error::InvalidParameter as u8)?; let maybe_output = w.bridge_u2f_to_webcrypt_raw( output, &data.clone(), @@ -248,7 +244,7 @@ fn handle_ctap2( response.push(error).ok(); } } -use trussed::{client, interrupt::InterruptFlag}; +use trussed::interrupt::InterruptFlag; impl app::App<'static> for Webcrypt where @@ -281,7 +277,7 @@ where } fn interrupt(&self) -> Option<&'static InterruptFlag> { - self.trussed.interrupt() + self.wc.trussed.interrupt() } } diff --git a/src/lib/helpers.rs b/src/lib/helpers.rs index 582bd7b..7edeb99 100644 --- a/src/lib/helpers.rs +++ b/src/lib/helpers.rs @@ -3,7 +3,7 @@ use heapless_bytes::{Bytes, Bytes32}; use trussed::{client, syscall}; #[inline(never)] -pub fn hash(trussed: &mut C, data: Message) -> Bytes<32> +pub fn hash(trussed: &mut C, data: &[u8]) -> Result, ()> where C: trussed::Client + client::Client @@ -13,12 +13,8 @@ where + client::Sha256, { use trussed::types::Mechanism; - let hash = syscall!(trussed.hash( - Mechanism::Sha256, - Bytes::from_slice(data.as_slice()).unwrap() - )) - .hash; - Bytes32::from_slice(hash.as_slice()).unwrap() + let hash = syscall!(trussed.hash(Mechanism::Sha256, Bytes::from_slice(data)?)).hash; + Bytes32::from_slice(hash.as_slice()) } pub fn cbor_serialize_message( diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 15ee45e..3f2d3f9 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -1,6 +1,5 @@ #![no_std] -#[macro_use] extern crate delog; delog::generate_macros!(); @@ -26,6 +25,8 @@ pub use peeking::Peeking; pub use peeking::PeekingBypass; pub const MAX_MESSAGE_LENGTH: usize = 800; // TODO required 1000 for the ping tests +const OUTPUT_BUFFER_SIZE_FOR_CBOR_SERIALIZATION: usize = MAX_MESSAGE_LENGTH; +const OUTPUT_BUFFER_SIZE_FOR_CBOR_SERIALIZATION_STATE: usize = MAX_MESSAGE_LENGTH; #[cfg(feature = "transparent-encryption")] pub const DEFAULT_ENCRYPTION_PIN: &str = "12345678"; diff --git a/src/lib/openpgp.rs b/src/lib/openpgp.rs index a314bce..0f98110 100644 --- a/src/lib/openpgp.rs +++ b/src/lib/openpgp.rs @@ -15,9 +15,9 @@ impl KeyFingerprint { // TODO // https://www.rfc-editor.org/rfc/rfc4880#section-12.2 // https://crypto.stackexchange.com/a/32097 - pub fn from_public_key(_trussed: &mut impl client::Client, _pk: Bytes<64>) -> Result { - todo!(); - } + // pub fn from_public_key(_trussed: &mut impl client::Client, _pk: Bytes<64>) -> Result { + // todo!(); + // } } impl TryFrom<&[u8]> for KeyFingerprint { @@ -123,15 +123,13 @@ impl OpenPGPData { } pub fn import( - trussed: &mut (impl WebcryptTrussedClient), + trussed: &mut impl WebcryptTrussedClient, auth: DataBytes, sign: DataBytes, enc: DataBytes, date: DataBytes, location: Location, ) -> ResultW { - use trussed::types::Location; - Ok(OpenPGPData { authentication: OpenPGPKey { key: { diff --git a/src/lib/state.rs b/src/lib/state.rs index 6da72c5..6b88602 100644 --- a/src/lib/state.rs +++ b/src/lib/state.rs @@ -73,7 +73,7 @@ impl PersistentState { if result.is_err() { info!("err deser'ing: {:?}", result.err().unwrap()); - info!("{}", hex_str!(&data)); + info!("{:?}", data); return Err(Error::Other); } diff --git a/src/lib/transport.rs b/src/lib/transport.rs index aae5f0a..4980049 100644 --- a/src/lib/transport.rs +++ b/src/lib/transport.rs @@ -15,169 +15,18 @@ use crate::{Bytes, Message, Options}; pub struct Webcrypt { WC_INPUT_BUFFER: WebcryptMessage, WC_OUTPUT_BUFFER: WebcryptMessage, - pub(crate) current_command_id: CommandID, - pub(crate) trussed: C, - pub(crate) state: WebcryptState, - pub(crate) store: State, - pub(crate) session: WebcryptSession, - pub(crate) req_details: Option, - pub(crate) options: Options, + pub(crate) wc: WebcryptInternal, } -pub type WebcryptError = Error; -impl Webcrypt -where - C: WebcryptTrussedClient, -{ - #[inline(never)] +impl Webcrypt { pub fn new_with_options(client: C, options: Options) -> Self { - Webcrypt { + Self { WC_INPUT_BUFFER: Default::default(), WC_OUTPUT_BUFFER: Default::default(), - current_command_id: Default::default(), - trussed: client, - state: WebcryptState::new(options.location), - store: State::new(options.location), - session: Default::default(), - req_details: None, - options, + wc: WebcryptInternal::new_with_options(client, options), } } - #[inline(never)] - fn get_webcrypt_cmd(&self, keyh: &Bytes<255>) -> Result { - let webcrypt: WebcryptRequest = keyh.try_into().map_err(|_| Error::BadFormat)?; - webcrypt.try_into() - } - #[inline(never)] - fn webcrypt_write_request( - &mut self, - _output: &[u8], - cmd: &ExtWebcryptCmd, - ) -> Result<(), WebcryptError> { - info!("Write"); - self.WC_INPUT_BUFFER - .extend_from_slice(&cmd.data_first_byte) - .map_err(|_| Error::TooLongRequest)?; - Ok(()) - } - #[inline(never)] - fn parse_execute(&mut self) -> Result<(Error, CommandID), ()> { - self.WC_OUTPUT_BUFFER.clear(); - let parsed: ResponseReadFirst = self.WC_INPUT_BUFFER.clone().into(); - let id_u8 = parsed.cmd_id; - let operation = id_u8; - self.current_command_id = operation; - info!("Input buffer: {:?}", parsed); - info!("Received operation: {:?} {:x?}", id_u8, operation); - use CommandID::*; - let res = match operation { - Status => cmd_status(self), - Login => cmd_login(self), - Logout => cmd_logout(self), - FactoryReset => cmd_factory_reset(self), - GetConfiguration => cmd_configure(self), - SetConfiguration => cmd_configure(self), - SetPin => cmd_manage_pin(self), - ChangePin => cmd_manage_pin(self), - InitializeSeed => cmd_initialize_seed(self), - RestoreFromSeed => cmd_restore_from_seed(self), - - GenerateKey => cmd_generate_key(self), - Sign => cmd_sign(self), - Decrypt => cmd_decrypt(self), - - OpenPgpImport => cmd_openpgp_import(self), - OpenPgpSign => cmd_openpgp_sign(self), - OpenPgpDecrypt => cmd_openpgp_decrypt(self), - OpenPgpInfo => cmd_openpgp_info(self), - OpenPgpGenerate => cmd_openpgp_generate(self), - - #[cfg(feature = "hmacsha256p256")] - GenerateKeyFromData => cmd_generate_key_from_data(self), - - ReadResidentKeyPublic => cmd_read_resident_key_public(self), - GenerateResidentKey => cmd_generate_resident_key(self), - DiscoverResidentKeys => cmd_discover_resident_key(self), - WriteResidentKey => cmd_write_resident_key(self), - - TestPing => cmd_test_ping(self), - #[cfg(feature = "test-commands")] - TestClear => { - todo!() - } - #[cfg(feature = "test-commands")] - TestReboot => { - todo!() - } - _ => Err(Error::InvalidCommand), - }; - if res.is_err() { - return Ok((res.err().unwrap(), operation)); - } - Ok((Error::Success, operation)) - } - - #[inline(never)] - pub fn get_input(&self) -> &[u8] { - self.WC_INPUT_BUFFER.as_slice() - } - - #[inline(never)] - pub fn get_input_deserialized<'a, T: Deserialize<'a>>(&'a self) -> Result { - cbor_deserialize::(&self.WC_INPUT_BUFFER[3..]).map_err(|e| { - debug_now!("Input deserialization error: {:?}", e); - e - }) - } - - #[inline(never)] - pub fn send_to_output(&mut self, o: T) { - // send data to output - // limited to 256*8 bytes for now for a single write - let mut buffer = [0u8; 256 * 8]; - let encoded = cbor_serialize(&o, &mut buffer).unwrap(); - // info!("Encoded: {:?}", hex::encode(encoded)); - self.WC_OUTPUT_BUFFER.extend_from_slice(encoded).unwrap(); - } - - #[inline(never)] - pub fn send_to_output_arr(&mut self, o: &WebcryptMessage) { - info!("Clear write: {:?}", o); - self.WC_OUTPUT_BUFFER.extend_from_slice(o).unwrap(); - } - #[inline(never)] - fn webcrypt_read_request(&self, output: &mut WebcryptMessage, cmd: &ExtWebcryptCmd) -> Error { - let offset = (u8::from(cmd.packet_no)) as usize * (cmd.chunk_size) as usize; - let offset_right = offset + cmd.this_chunk_length as usize; - let offset_right_clamp = offset_right.min(self.WC_OUTPUT_BUFFER.len()); - - if self.WC_OUTPUT_BUFFER.len() == 0 { - error!("No data available for read in the output buffer"); - } - - if offset >= self.WC_OUTPUT_BUFFER.len() { - error!( - "Requested offset bigger than available buffer length: {} > {}", - offset, - self.WC_OUTPUT_BUFFER.len() - ); - return Error::FailedLoadingData; - } - - output - .extend_from_slice(&self.WC_OUTPUT_BUFFER[offset..offset_right_clamp]) - .unwrap(); - // info!( - // "Read: [{}..{})({})/{} {:?}", - // offset, - // offset_right_clamp, - // output.len(), - // self.WC_OUTPUT_BUFFER.len(), - // hex::encode(output) - // ); - Error::Success - } /// The main transport function, gateway to the extension from the Webauthn perspective /// Decodes incoming request low-level packet data, and either saves it to the input buffer, /// triggers execution or allows reading output buffer. @@ -188,7 +37,7 @@ where keyh: &Bytes<255>, req_details: RequestDetails, ) -> Result { - let cmd = self.get_webcrypt_cmd(keyh)?; + let cmd = self.wc.get_webcrypt_cmd(keyh)?; info!(" in < cmd: {:?}", cmd); let ret = self.bridge_u2f_to_webcrypt(cmd, req_details)?; info!("out > ret: {:?}", ret); @@ -207,7 +56,7 @@ where output.extend([x.result as u8]); } } - // info!("> outputH: {:?}", hex::encode(output.clone())); + info!("> outputH: {:?}", output.clone()); Ok(output) } @@ -226,8 +75,8 @@ where if webcrypt_req.packet_no.0 == 0 { self.WC_INPUT_BUFFER.clear(); self.WC_OUTPUT_BUFFER.clear(); - self.req_details = Some(req_details); - } else if self.req_details != Some(req_details) { + self.wc.req_details = Some(req_details); + } else if self.wc.req_details != Some(req_details) { // either method or host changes, while not writing the first packet, abort return Ok(WebcryptResponseType::Write(ResponseWrite { result: Error::BadOrigin, @@ -239,9 +88,19 @@ where output.status_code = Error::Success; let should_execute = webcrypt_req.is_final(); if should_execute { - let res = self.parse_execute().map_err(|_| Error::InternalError)?; - output.status_code = res.0; - self.current_command_id = res.1; + let mut tmp_buffer = self.WC_OUTPUT_BUFFER.clone(); + let res = self.parse_execute(&mut tmp_buffer); + self.WC_OUTPUT_BUFFER = tmp_buffer; + match res { + Ok(res) => { + output.status_code = res.0; + self.wc.current_command_id = res.1; + } + Err(e) => { + output.status_code = e; + self.wc.current_command_id = CommandID::NotSetInvalid; + } + } } Ok(WebcryptResponseType::Write(ResponseWrite { result: output.status_code, @@ -249,7 +108,7 @@ where } TRANSPORT_CMD_ID::COMM_CMD_READ => { - if self.req_details != Some(req_details) { + if self.wc.req_details != Some(req_details) { // on bad request return first packet format output.status_code = Error::BadOrigin; output.cbor_payload = Default::default(); @@ -272,7 +131,7 @@ where 0 => { Ok(WebcryptResponseType::First(ResponseReadFirst { data_len: self.WC_OUTPUT_BUFFER.len() as u16 + 3, // +3, // size (2) + commandID (1) - cmd_id: self.current_command_id, + cmd_id: self.wc.current_command_id, data: CborPart( output .cbor_payload @@ -293,10 +152,252 @@ where } } } + #[inline(never)] - pub fn send_input_to_output(&mut self) { - self.WC_OUTPUT_BUFFER - .extend_from_slice(&self.WC_INPUT_BUFFER[3..]) + fn webcrypt_read_request(&self, output: &mut WebcryptMessage, cmd: &ExtWebcryptCmd) -> Error { + let offset = (u8::from(cmd.packet_no)) as usize * (cmd.chunk_size) as usize; + let offset_right = offset + cmd.this_chunk_length as usize; + let offset_right_clamp = offset_right.min(self.WC_OUTPUT_BUFFER.len()); + + if self.WC_OUTPUT_BUFFER.len() == 0 { + error!("No data available for read in the output buffer"); + } + + if offset >= self.WC_OUTPUT_BUFFER.len() { + error!( + "Requested offset bigger than available buffer length: {} > {}", + offset, + self.WC_OUTPUT_BUFFER.len() + ); + return Error::FailedLoadingData; + } + + output + .extend_from_slice(&self.WC_OUTPUT_BUFFER[offset..offset_right_clamp]) .unwrap(); + info!( + "Read: [{}..{})({})/{} {:?}", + offset, + offset_right_clamp, + output.len(), + self.WC_OUTPUT_BUFFER.len(), + output + ); + Error::Success + } + + #[inline(never)] + fn webcrypt_write_request( + &mut self, + _output: &[u8], + cmd: &ExtWebcryptCmd, + ) -> Result<(), WebcryptError> { + info!("Write"); + self.WC_INPUT_BUFFER + .extend_from_slice(&cmd.data_first_byte) + .map_err(|_| Error::TooLongRequest)?; + Ok(()) + } + + #[inline(never)] + pub fn get_request<'a, T: Deserialize<'a>>(message: &'a Message) -> Result { + WebcryptInternal::::get_input_deserialized_from_slice(message) + .map_err(|_| Error::BadFormat) + } + + #[inline(never)] + fn parse_execute(&mut self, reply: &mut Message) -> Result<(Error, CommandID), Error> { + reply.clear(); + let parsed: ResponseReadFirst = (&self.WC_INPUT_BUFFER).into(); + let id_u8 = parsed.cmd_id; + let operation = id_u8; + self.wc.current_command_id = operation; + info!("Input buffer: {:?}", parsed); + info!("Received operation: {:?} {:x?}", id_u8, operation); + use CommandID::*; + let res = match operation { + Status => cmd_status(&mut self.wc, reply), + Login => cmd_login( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + Logout => cmd_logout( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + FactoryReset => cmd_factory_reset(&mut self.wc, reply), + // Proper command variant is selected inside the cmd_configure + GetConfiguration | SetConfiguration => cmd_configure( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + SetPin => cmd_manage_pin( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER).map_err(|_| Error::InternalError)?, // TODO use BadFormat + None, + reply, + ), + ChangePin => cmd_manage_pin( + &mut self.wc, + None, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + InitializeSeed => cmd_initialize_seed( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + RestoreFromSeed => cmd_restore_from_seed( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + + GenerateKey => cmd_generate_key( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + Sign => cmd_sign( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + Decrypt => cmd_decrypt( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + + OpenPgpImport => cmd_openpgp_import( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + OpenPgpSign => cmd_openpgp_sign( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + OpenPgpDecrypt => cmd_openpgp_decrypt( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + OpenPgpInfo => cmd_openpgp_info( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + OpenPgpGenerate => cmd_openpgp_generate( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + + #[cfg(feature = "hmacsha256p256")] + GenerateKeyFromData => cmd_generate_key_from_data( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + + ReadResidentKeyPublic => cmd_read_resident_key_public( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + GenerateResidentKey => cmd_generate_resident_key( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + DiscoverResidentKeys => cmd_discover_resident_key( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + WriteResidentKey => cmd_write_resident_key( + &mut self.wc, + Self::get_request(&self.WC_INPUT_BUFFER)?, + reply, + ), + + TestPing => cmd_test_ping(&self.WC_INPUT_BUFFER, reply), + #[cfg(feature = "test-commands")] + TestClear => { + todo!() + } + #[cfg(feature = "test-commands")] + TestReboot => { + todo!() + } + _ => Err(Error::InvalidCommand), + }; + if res.is_err() { + return Ok((res.err().unwrap(), operation)); + } + Ok((Error::Success, operation)) } } + +#[allow(non_snake_case)] +pub struct WebcryptInternal { + pub(crate) current_command_id: CommandID, + pub(crate) trussed: C, + pub(crate) state: WebcryptState, + pub(crate) store: State, + pub(crate) session: WebcryptSession, + pub(crate) req_details: Option, + pub(crate) options: Options, +} + +pub type WebcryptError = Error; + +impl WebcryptInternal +where + C: WebcryptTrussedClient, +{ + #[inline(never)] + pub fn new_with_options(client: C, options: Options) -> Self { + WebcryptInternal { + current_command_id: Default::default(), + trussed: client, + state: WebcryptState::new(options.location), + store: State::new(options.location), + session: Default::default(), + req_details: None, + options, + } + } + + #[inline(never)] + fn get_webcrypt_cmd(&self, keyh: &Bytes<255>) -> Result { + let webcrypt: WebcryptRequest = keyh.try_into().map_err(|_| Error::BadFormat)?; + webcrypt.try_into() + } + + #[inline(never)] + pub fn get_input_deserialized_from_slice<'a, T: Deserialize<'a>>( + message: &'a Message, + ) -> Result { + cbor_deserialize::(&message[3..]).map_err(|e| { + debug_now!("Input deserialization error: {:?}", e); + e + }) + } +} + +#[inline(never)] +pub fn send_to_output(o: T, output: &mut Message) { + // send data to output + // limited to 256*8 bytes for now for a single write + let mut buffer = [0u8; crate::OUTPUT_BUFFER_SIZE_FOR_CBOR_SERIALIZATION]; + let encoded = cbor_serialize(&o, &mut buffer).unwrap(); + info!("Encoded: {:?}", encoded); + output.extend_from_slice(encoded).unwrap(); +} diff --git a/src/lib/types.rs b/src/lib/types.rs index b3d27be..c832af3 100644 --- a/src/lib/types.rs +++ b/src/lib/types.rs @@ -5,6 +5,7 @@ use crate::types::Error::BadFormat; use crate::types::TRANSPORT_CMD_ID::COMM_CMD_WRITE; use crate::{Bytes, Message}; use ctap_types::ctap2::PinAuth; +use delog::log; use heapless_bytes::Bytes32; pub type CtapSignatureSize = Bytes<72>; @@ -414,6 +415,7 @@ impl From for u8 { } #[derive(Debug, Default)] +// TODO: move from Message to &[u8] pub struct CborPart(pub Message); impl From for CborPart { @@ -456,8 +458,8 @@ impl ResponseReadFirst { } } -impl From for ResponseReadFirst { - fn from(v: Message) -> Self { +impl From<&Message> for ResponseReadFirst { + fn from(v: &Message) -> Self { let mut rr = ResponseReadFirst::new(); rr.data_len = u16::from_le_bytes(v[0..2].try_into().unwrap()); // rr.cmd_id = CommandID::rdr.read_u8(); @@ -514,16 +516,10 @@ impl WebcryptResponseType { pub fn log_hex(&self) { match &self { WebcryptResponseType::First(_d) => { - // log::info!( - // "WebcryptResponseType data: {:?}", - // hex::encode(_d.data.0.clone()) - // ) + log::info!("WebcryptResponseType data: {:?}", _d.data.0.clone()) } WebcryptResponseType::Next(_d) => { - // log::info!( - // "WebcryptResponseType data: {:?}", - // hex::encode(_d.data.0.clone()) - // ) + log::info!("WebcryptResponseType data: {:?}", _d.data.0.clone()) } WebcryptResponseType::Write(_d) => {} } diff --git a/src/lib/wcstate.rs b/src/lib/wcstate.rs index 6cbc3fa..e776272 100644 --- a/src/lib/wcstate.rs +++ b/src/lib/wcstate.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types)] -use heapless_bytes::{Bytes, Bytes32, Bytes64}; +use heapless_bytes::{Bytes, Bytes32}; use trussed::{ client, syscall, try_syscall, types::{KeyId, Location}, @@ -9,7 +9,7 @@ use trussed::{ // use std::borrow::Borrow; use crate::constants::RESIDENT_KEY_COUNT; use crate::types::Error; -use crate::Message; +use crate::OUTPUT_BUFFER_SIZE_FOR_CBOR_SERIALIZATION_STATE; use trussed::key::Kind; use trussed::types::PathBuf; @@ -32,14 +32,14 @@ impl Default for WebcryptConfiguration { } use crate::commands::WebcryptTrussedClient; -use crate::commands_types::ExpectedSessionToken; +use crate::commands_types::{ExpectedSessionToken, PinBytes}; use crate::openpgp::OpenPGPData; use cbor_smol::{cbor_deserialize, cbor_serialize}; use serde::{Deserialize, Serialize}; #[derive(Default, Serialize, Deserialize)] pub struct WebcryptPIN { - pin: Option, + pin: Option, counter: u8, } @@ -60,7 +60,7 @@ impl WebcryptPIN { } #[inline(never)] - pub fn check_pin(&mut self, pin: Bytes64) -> Result { + pub fn check_pin(&mut self, pin: PinBytes) -> Result { if self.pin.is_none() { info!("PIN not set"); return Err(Error::NotAllowed); @@ -82,7 +82,7 @@ impl WebcryptPIN { Ok(true) } #[inline(never)] - fn validate_pin(&self, pin: &Bytes64) -> Result<(), Error> { + fn validate_pin(&self, pin: &PinBytes) -> Result<(), Error> { let l = pin.len(); if !(4..=64).contains(&l) { Err(Error::NotAllowed) @@ -92,7 +92,7 @@ impl WebcryptPIN { } #[inline(never)] - pub fn set_pin(&mut self, pin: Bytes64) -> Result { + pub fn set_pin(&mut self, pin: PinBytes) -> Result { if self.pin.is_some() { return Err(Error::NotAllowed); } @@ -102,7 +102,7 @@ impl WebcryptPIN { Ok(true) } #[inline(never)] - pub fn change_pin(&mut self, pin: Bytes64, new_pin: Bytes64) -> Result { + pub fn change_pin(&mut self, pin: PinBytes, new_pin: PinBytes) -> Result { if self.pin.is_none() { return Err(Error::NotAllowed); } @@ -162,7 +162,7 @@ impl WebcryptSession { #[inline(never)] pub fn login( &mut self, - pin: Bytes64, + pin: PinBytes, trussed: &mut C, rp_id_hash: &Bytes<32>, state: &mut WebcryptState, @@ -178,15 +178,7 @@ impl WebcryptSession { } #[inline(never)] - pub fn check_token(&self, token: Bytes32) -> bool { - match &self.temporary_password_token { - None => false, - Some(current) => token == current, - } - } - - #[inline(never)] - pub fn check_token_res(&self, token: ExpectedSessionToken) -> Result<(), ()> { + pub fn check_token_res(&self, token: &ExpectedSessionToken) -> Result<(), ()> { #[cfg(feature = "no-authentication")] return Ok(()); @@ -238,8 +230,8 @@ impl WebcryptState { info!("Resetting state"); self.pin = Default::default(); if let Some(x) = &self.openpgp_data { - if let Err(e) = x.clear(t) { - error!("Failed resetting state: {:?}", e); + if let Err(_e) = x.clear(t) { + error!("Failed resetting state: {:?}", _e); } } self.openpgp_data = None; @@ -369,23 +361,6 @@ impl WebcryptState { } cbor_deserialize(data).map_err(|_| Error::InternalError) } - #[inline(never)] - fn serialize(&self) -> Message { - // TODO decide on memory limits - let mut slice = [0u8; 2 * 1024]; - Message::from_slice(cbor_serialize(self, &mut slice).unwrap()).unwrap() - } - - #[inline(never)] - pub fn file_reset(&self, t: &mut T) - where - T: client::Client, - { - let r = try_syscall!(t.remove_file(self.location, PathBuf::from(STATE_FILE_PATH))); - if r.is_ok() { - info!("State removed"); - } - } #[inline(never)] pub fn initialized(&self) -> bool { @@ -403,17 +378,23 @@ impl WebcryptState { // abort save on uninitialized structure return; } - // todo!(); - try_syscall!(t.write_file( - self.location, - PathBuf::from(STATE_FILE_PATH), - Bytes::from_slice(self.serialize().as_slice()).unwrap(), - None, - )) - .map_err(|_| Error::MemoryFull) - .unwrap(); - info!("State saved"); + // TODO decide on memory limits + let mut buffer = [0u8; OUTPUT_BUFFER_SIZE_FOR_CBOR_SERIALIZATION_STATE]; + let serialized = cbor_serialize(self, &mut buffer); + if let Ok(serialized) = serialized { + try_syscall!(t.write_file( + self.location, + PathBuf::from(STATE_FILE_PATH), + Bytes::from_slice(serialized).unwrap(), + None, + )) + .map_err(|_| Error::MemoryFull) + .unwrap(); + info!("State saved"); + } else { + warn!("State not saved"); + } } #[inline(never)]