diff --git a/Cargo.toml b/Cargo.toml index 3fdb6e2..b71e100 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,12 @@ required-features = ["vpicc"] [dependencies] apdu-app = { version = "0.1", optional = true } -cbor-smol = { version = "0.5", features = ["heapless-bytes-v0-3"] } +cbor-smol = { version = "0.5", features = ["heapless-bytes-v0-5"] } delog = { version = "0.1.5", optional = true } -flexiber = { version = "0.1", features = ["derive", "heapless"] } -heapless = "0.7" +flexiber = { version = "0.2", features = ["derive", "heapless"] } +heapless = "0.9.1" hex-literal = "0.3" -iso7816 = "0.1.3" +iso7816 = "0.2.0" serde = { version = "1", default-features = false, features = ["derive"] } trussed = { version = "0.1", default-features = false, features = ["aes256-cbc", "chacha8-poly1305", "crypto-client", "ed255", "filesystem-client", "p256", "p384", "shared-secret", "serde-extensions", "tdes", "x255"], optional = true } trussed-auth = "0.4" @@ -26,7 +26,7 @@ trussed-auth-backend = { version = "0.1.0", optional = true } untrusted = "0.9" vpicc = { version = "0.1.0", optional = true } log = "0.4" -heapless-bytes = "0.3.0" +heapless-bytes = "0.5.0" subtle = { version = "2", default-features = false } # TODO: only enable rsa features when needed trussed-core = { version = "0.1.0-rc.1", features = ["aes256-cbc", "chacha8-poly1305", "crypto-client", "ed255", "filesystem-client", "p256", "p384", "rsa2048", "rsa3072", "rsa4096", "shared-secret", "tdes", "x255"] } diff --git a/src/dispatch.rs b/src/dispatch.rs index b8bd0b0..eab8230 100644 --- a/src/dispatch.rs +++ b/src/dispatch.rs @@ -1,10 +1,11 @@ use crate::{reply::Reply, Authenticator, /*constants::PIV_AID,*/ Result}; -use apdu_app::{App, CommandView, Data}; +use apdu_app::{App, CommandView}; +use heapless::VecView; use iso7816::{Interface, Status}; #[cfg(feature = "apdu-dispatch")] -impl App for Authenticator +impl App for Authenticator where T: crate::Client, { @@ -12,7 +13,7 @@ where &mut self, interface: Interface, _apdu: CommandView<'_>, - reply: &mut Data, + reply: &mut VecView, ) -> Result { if interface != Interface::Contact { return Err(Status::ConditionsOfUseNotSatisfied); @@ -24,7 +25,12 @@ where self.deselect() } - fn call(&mut self, interface: Interface, apdu: CommandView<'_>, reply: &mut Data) -> Result { + fn call( + &mut self, + interface: Interface, + apdu: CommandView<'_>, + reply: &mut VecView, + ) -> Result { if interface != Interface::Contact { return Err(Status::ConditionsOfUseNotSatisfied); } diff --git a/src/lib.rs b/src/lib.rs index 83331aa..7e7b65f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ mod reply; pub mod state; mod tlv; +use heapless::VecView; pub use piv_types::{AsymmetricAlgorithms, Pin, Puk}; use trussed_chunked::ChunkedClient; use trussed_hpke::HpkeClient; @@ -35,7 +36,7 @@ use core::convert::TryInto; use flexiber::EncodableHeapless; use heapless_bytes::Bytes; -use iso7816::{Data, Status}; +use iso7816::Status; use trussed_auth::AuthClient; use trussed_core::mechanisms::Tdes; use trussed_core::types::{KeySerialization, Location, Mechanism, PathBuf, StorageAttributes}; @@ -136,7 +137,7 @@ where // The way apdu-dispatch currently works, this would deselect, resetting security indicators. pub fn deselect(&mut self) {} - pub fn select(&mut self, mut reply: Reply<'_, R>) -> Result { + pub fn select(&mut self, mut reply: Reply<'_>) -> Result { use piv_types::Algorithms::*; info!("selecting PIV maybe"); @@ -154,10 +155,10 @@ where Ok(()) } - pub fn respond( + pub fn respond( &mut self, command: iso7816::command::CommandView<'_>, - reply: &mut Data, + reply: &mut VecView, ) -> Result { let just_verified = self.state.volatile.app_security_status.pin_just_verified; self.state.volatile.app_security_status.pin_just_verified = false; @@ -192,11 +193,11 @@ where } } - pub fn yubico_piv_extension( + pub fn yubico_piv_extension( &mut self, data: &[u8], instruction: YubicoPivExtension, - mut reply: Reply<'_, R>, + mut reply: Reply<'_>, ) -> Result { info!("yubico extension: {:?}", &instruction); match instruction { @@ -256,11 +257,11 @@ where } impl LoadedAuthenticator<'_, T> { - pub fn yubico_set_administration_key( + pub fn yubico_set_administration_key( &mut self, data: &[u8], _touch_policy: TouchPolicy, - _reply: Reply<'_, R>, + _reply: Reply<'_>, ) -> Result { // cmd := apdu{ // instruction: insSetMGMKey, @@ -424,12 +425,12 @@ impl LoadedAuthenticator<'_, T> { // - 9000, 61XX for success // - 6982 security status // - 6A80, 6A86 for data, P1/P2 issue - pub fn general_authenticate( + pub fn general_authenticate( &mut self, auth: GeneralAuthenticate, data: &[u8], just_verified: bool, - mut reply: Reply<'_, R>, + mut reply: Reply<'_>, ) -> Result { // For "SSH", we need implement A.4.2 in SP-800-73-4 Part 2, ECDSA signatures // @@ -562,11 +563,7 @@ impl LoadedAuthenticator<'_, T> { Ok(self.state.persistent.keys.administration) } - fn single_auth_1( - &mut self, - auth: GeneralAuthenticate, - mut reply: Reply<'_, R>, - ) -> Result { + fn single_auth_1(&mut self, auth: GeneralAuthenticate, mut reply: Reply<'_>) -> Result { info!("Single auth 1"); let key = self.validate_auth_management(auth)?; let plaintext = syscall!(self.trussed.random_bytes(key.alg.challenge_length())).bytes; @@ -576,7 +573,7 @@ impl LoadedAuthenticator<'_, T> { .encrypt(key.alg.mechanism(), key.id, &plaintext, &[], None)) .ciphertext; self.state.volatile.command_cache = Some(CommandCache::SingleAuthChallengeReference( - Bytes::from_slice(&ciphertext).unwrap(), + Bytes::try_from(&*ciphertext).unwrap(), )); reply.expand(&[0x7C])?; @@ -619,11 +616,7 @@ impl LoadedAuthenticator<'_, T> { Ok(()) } - fn mutual_auth_1( - &mut self, - auth: GeneralAuthenticate, - mut reply: Reply<'_, R>, - ) -> Result { + fn mutual_auth_1(&mut self, auth: GeneralAuthenticate, mut reply: Reply<'_>) -> Result { info!("Mutual auth 1"); let key = self.validate_auth_management(auth)?; let plaintext = syscall!(self.trussed.random_bytes(key.alg.challenge_length())).bytes; @@ -635,7 +628,7 @@ impl LoadedAuthenticator<'_, T> { .ciphertext; self.state.volatile.command_cache = Some(CommandCache::MutualAuthWitnessReference( - Bytes::from_slice(&plaintext).unwrap(), + Bytes::try_from(&*plaintext).unwrap(), )); reply.expand(&[0x7C])?; @@ -649,12 +642,12 @@ impl LoadedAuthenticator<'_, T> { Ok(()) } - fn mutual_auth_2( + fn mutual_auth_2( &mut self, auth: GeneralAuthenticate, response: &[u8], challenge: &[u8], - mut reply: Reply<'_, R>, + mut reply: Reply<'_>, ) -> Result { use subtle::ConstantTimeEq; @@ -703,12 +696,12 @@ impl LoadedAuthenticator<'_, T> { } // Sign a message. For RSA, since the key is exposed as a raw key, so it can also be used for decryption - fn sign( + fn sign( &mut self, auth: GeneralAuthenticate, message: &[u8], just_verified: bool, - mut reply: Reply<'_, R>, + mut reply: Reply<'_>, ) -> Result { debug!("Request for sign, data length: {}, data:", message.len()); // error!("{}", delog::hexstr!(message)); @@ -754,11 +747,11 @@ impl LoadedAuthenticator<'_, T> { ) } - fn key_agreement( + fn key_agreement( &mut self, auth: GeneralAuthenticate, data: &[u8], - mut reply: Reply<'_, R>, + mut reply: Reply<'_>, just_verified: bool, ) -> Result { info!("Request for exponentiation"); @@ -839,11 +832,11 @@ impl LoadedAuthenticator<'_, T> { ) } - pub fn generate_asymmetric_keypair( + pub fn generate_asymmetric_keypair( &mut self, reference: GenerateKeyReference, data: &[u8], - mut reply: Reply<'_, R>, + mut reply: Reply<'_>, ) -> Result { if !self .state @@ -967,11 +960,7 @@ impl LoadedAuthenticator<'_, T> { Ok(()) } - fn get_data( - &mut self, - container: Container, - mut reply: Reply<'_, R>, - ) -> Result { + fn get_data(&mut self, container: Container, mut reply: Reply<'_>) -> Result { let read_valid = self.state .volatile @@ -1045,7 +1034,7 @@ impl LoadedAuthenticator<'_, T> { Ok(()) } - fn get_key_history_object(&mut self, mut reply: Reply<'_, R>) -> Result { + fn get_key_history_object(&mut self, mut reply: Reply<'_>) -> Result { use state::ContainerStorage; let mut num_certs = 0; @@ -1063,12 +1052,12 @@ impl LoadedAuthenticator<'_, T> { Ok(()) } - fn import_asymmetric_key( + fn import_asymmetric_key( &mut self, algo: AsymmetricAlgorithms, key: AsymmetricKeyReference, #[cfg_attr(not(feature = "rsa"), allow(unused))] data: &[u8], - mut _reply: Reply<'_, R>, + mut _reply: Reply<'_>, ) -> Result { if !self .state diff --git a/src/reply.rs b/src/reply.rs index ebca2a3..33509d8 100644 --- a/src/reply.rs +++ b/src/reply.rs @@ -3,22 +3,22 @@ use iso7816::Status; use core::ops::{Deref, DerefMut}; #[derive(Debug)] -pub struct Reply<'v, const R: usize>(pub &'v mut heapless::Vec); +pub struct Reply<'v>(pub &'v mut heapless::VecView); -impl<'v, const R: usize> Deref for Reply<'v, R> { - type Target = &'v mut heapless::Vec; +impl<'v> Deref for Reply<'v> { + type Target = &'v mut heapless::VecView; fn deref(&self) -> &Self::Target { &self.0 } } -impl DerefMut for Reply<'_, R> { +impl DerefMut for Reply<'_> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } -impl Reply<'_, R> { +impl Reply<'_> { /// Extend the reply and return an error otherwise /// The MoreAvailable and GET RESPONSE mechanisms are handled by adpu_dispatch /// @@ -82,7 +82,7 @@ impl Reply<'_, R> { }) } - pub fn lend(&mut self) -> Reply<'_, R> { + pub fn lend(&mut self) -> Reply<'_> { Reply(self.0) } } diff --git a/src/state.rs b/src/state.rs index d7567b2..4a24146 100644 --- a/src/state.rs +++ b/src/state.rs @@ -200,8 +200,8 @@ impl Keys { storage, user_public_key, new.id, - Bytes::from_slice(key.name().as_str().as_bytes()).unwrap(), - Bytes::from_slice(HPKE_SEALKEY_REFERENCE_INFO).unwrap(), + Bytes::try_from(key.name().as_str().as_bytes()).unwrap(), + Bytes::try_from(HPKE_SEALKEY_REFERENCE_INFO).unwrap(), )); KeyOrEncryptedWithAlg::Encrypted(match key { @@ -382,8 +382,8 @@ impl LoadedState<'_> { key.name().into(), options.storage, Location::Volatile, - Bytes::from_slice(key.name().as_str().as_bytes()).unwrap(), - Bytes::from_slice(HPKE_SEALKEY_REFERENCE_INFO).unwrap(), + Bytes::try_from(key.name().as_str().as_bytes()).unwrap(), + Bytes::try_from(HPKE_SEALKEY_REFERENCE_INFO).unwrap(), )) .map_err(|_err| { error!("Failed to unseal key: {_err:?}"); @@ -460,7 +460,7 @@ impl Volatile { client: &mut T, ) -> &'this mut PinVerified { self.clear_pin_verified(client); - let pin = Bytes::from_slice(&value.0).expect("Convertion of static array"); + let pin = Bytes::try_from(&value.0).expect("Convertion of static array"); let syscall_res = try_syscall!(client.get_pin_key(PinType::UserPin, pin)); let pin_key = match syscall_res { Err(_err) => { @@ -532,8 +532,8 @@ impl Volatile { data_encryption_sealed_key_path, options.storage, Location::Volatile, - Bytes::from_slice(ContainerStorage(container).path_key_str().as_bytes()).unwrap(), - Bytes::from_slice(HPKE_SEALKEY_CONTAINER_INFO).unwrap(), + Bytes::try_from(ContainerStorage(container).path_key_str().as_bytes()).unwrap(), + Bytes::try_from(HPKE_SEALKEY_CONTAINER_INFO).unwrap(), )) else { return Ok(ReadValid::EncryptedNotFound); }; @@ -680,7 +680,7 @@ impl Persistent { value: &Puk, client: &mut T, ) -> Result, Status> { - let puk = Bytes::from_slice(&value.0).expect("Convertion of static array"); + let puk = Bytes::try_from(&value.0).expect("Convertion of static array"); try_syscall!(client.get_pin_key(PinType::Puk, puk)) .map(|r| r.result) .map_err(|_err| { @@ -695,8 +695,8 @@ impl Persistent { new_value: &Pin, client: &mut T, ) -> bool { - let old_pin = Bytes::from_slice(&old_value.0).expect("Convertion of static array"); - let new_pin = Bytes::from_slice(&new_value.0).expect("Convertion of static array"); + let old_pin = Bytes::try_from(&old_value.0).expect("Convertion of static array"); + let new_pin = Bytes::try_from(&new_value.0).expect("Convertion of static array"); try_syscall!(client.change_pin(PinType::UserPin, old_pin, new_pin)) .map(|r| r.success) .unwrap_or(false) @@ -708,8 +708,8 @@ impl Persistent { new_value: &Puk, client: &mut T, ) -> bool { - let old_puk = Bytes::from_slice(&old_value.0).expect("Convertion of static array"); - let new_puk = Bytes::from_slice(&new_value.0).expect("Convertion of static array"); + let old_puk = Bytes::try_from(&old_value.0).expect("Convertion of static array"); + let new_puk = Bytes::try_from(&new_value.0).expect("Convertion of static array"); try_syscall!(client.change_pin(PinType::Puk, old_puk, new_puk)) .map(|r| r.success) .unwrap_or(false) @@ -721,7 +721,7 @@ impl Persistent { old_key: KeyId, client: &mut T, ) -> Result<(), Status> { - let new_pin = Bytes::from_slice(&new_pin.0).expect("Convertion of static array"); + let new_pin = Bytes::try_from(&new_pin.0).expect("Convertion of static array"); try_syscall!(client.set_pin_with_key( PinType::UserPin, new_pin, @@ -740,7 +740,7 @@ impl Persistent { new_puk: Puk, client: &mut T, ) -> Result<(), Status> { - let new_puk = Bytes::from_slice(&new_puk.0).expect("Convertion of static array"); + let new_puk = Bytes::try_from(&new_puk.0).expect("Convertion of static array"); try_syscall!(client.set_pin(PinType::Puk, new_puk, Some(Self::PUK_RETRIES_DEFAULT), true)) .map_err(|_err| { error!("Failed to set puk"); @@ -859,7 +859,7 @@ impl Persistent { fn init_pins(client: &mut T, options: &crate::Options) -> Result<(), Status> { let default_pin = - Bytes::from_slice(&Self::DEFAULT_PIN.0).expect("Convertion of static array"); + Bytes::try_from(&Self::DEFAULT_PIN.0).expect("Convertion of static array"); try_syscall!(client.set_pin( PinType::UserPin, default_pin.clone(), @@ -871,7 +871,7 @@ impl Persistent { Status::UnspecifiedPersistentExecutionError })?; let default_puk = - Bytes::from_slice(&Self::DEFAULT_PUK.0).expect("Convertion of static array"); + Bytes::try_from(&Self::DEFAULT_PUK.0).expect("Convertion of static array"); try_syscall!(client.set_pin( PinType::Puk, default_puk.clone(), @@ -933,7 +933,7 @@ impl Persistent { syscall!(client.write_file( options.storage, PathBuf::from(USER_PUBLIC_KEY), - Bytes::from_slice(&key).unwrap(), + Bytes::try_from(&*key).unwrap(), None )); @@ -1068,11 +1068,11 @@ fn load_if_exists( } /// Returns false if the file does not exist -fn load_if_exists_streaming( +fn load_if_exists_streaming( client: &mut impl crate::Client, location: Location, path: &PathBuf, - mut buffer: Reply<'_, R>, + mut buffer: Reply<'_>, encryption: Option, ) -> Result { let offset = buffer.len(); @@ -1218,11 +1218,11 @@ impl ContainerStorage { } // Write the length of the file and write - pub fn load( + pub fn load( self, client: &mut impl crate::Client, storage: Location, - mut reply: Reply<'_, R>, + mut reply: Reply<'_>, read_valid: ReadValid, ) -> Result { let encryption = match read_valid { @@ -1292,8 +1292,8 @@ impl ContainerStorage { storage, user_public_key, key_to_seal, - Bytes::from_slice(self.path_key_str().as_bytes()).unwrap(), - Bytes::from_slice(HPKE_SEALKEY_CONTAINER_INFO).unwrap(), + Bytes::try_from(self.path_key_str().as_bytes()).unwrap(), + Bytes::try_from(HPKE_SEALKEY_CONTAINER_INFO).unwrap(), )); syscall!(client.delete(user_public_key));