diff --git a/src/container.rs b/src/container.rs index 11db397..76b197c 100644 --- a/src/container.rs +++ b/src/container.rs @@ -250,6 +250,7 @@ enum_subset! { Retired20, } } + impl_use_security_condition!( AttestKeyReference, AsymmetricKeyReference, diff --git a/src/lib.rs b/src/lib.rs index ec94c75..2b148c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,7 @@ use core::convert::TryInto; use flexiber::EncodableHeapless; use heapless_bytes::Bytes; use iso7816::{Data, Status}; -use trussed::types::{Location, StorageAttributes}; +use trussed::types::{KeySerialization, Location, StorageAttributes}; use trussed::{client, syscall, try_syscall}; use constants::*; @@ -507,12 +507,72 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T> pub fn exponentiation( &mut self, - _auth: GeneralAuthenticate, - _data: derp::Input<'_>, - _reply: Reply<'_, R>, + auth: GeneralAuthenticate, + data: derp::Input<'_>, + mut reply: Reply<'_, R>, ) -> Result { info!("Request for exponentiation"); - todo!() + let key_reference = auth.key_reference.try_into().map_err(|_| { + warn!( + "Attempt to use non asymetric key for exponentiation: {:?}", + auth.key_reference + ); + Status::IncorrectP1OrP2Parameter + })?; + let Some(KeyWithAlg { alg, id }) = self.state.persistent.keys.asymetric_for_reference(key_reference) else { + warn!("Attempt to use unset key"); + return Err(Status::ConditionsOfUseNotSatisfied); + }; + + if *alg != auth.algorithm { + warn!("Attempt to exponentiate with incorrect algorithm"); + return Err(Status::IncorrectP1OrP2Parameter); + } + + let Some(mechanism) = alg.ecdh_mechanism() else { + warn!("Attempt to exponentiate with non ECDH algorithm"); + return Err(Status::ConditionsOfUseNotSatisfied); + }; + + let data = data.as_slice_less_safe(); + if data.first() != Some(&0x04) { + warn!("Bad data format for ECDH"); + return Err(Status::IncorrectDataParameter); + } + + let public_key = try_syscall!(self.trussed.deserialize_key( + mechanism, + &data[1..], + KeySerialization::Raw, + StorageAttributes::default().set_persistence(Location::Volatile) + )) + .map_err(|_err| { + warn!("Failed to load public key: {:?}", _err); + Status::IncorrectDataParameter + })? + .key; + let shared_secret = syscall!(self.trussed.agree( + mechanism, + *id, + public_key, + StorageAttributes::default() + .set_persistence(Location::Volatile) + .set_serializable(true) + )) + .shared_secret; + + let serialized_secret = syscall!(self.trussed.serialize_key( + trussed::types::Mechanism::SharedSecret, + shared_secret, + KeySerialization::Raw + )) + .serialized_key; + syscall!(self.trussed.delete(public_key)); + syscall!(self.trussed.delete(shared_secret)); + + reply.expand(&[0x82])?; + reply.append_len(serialized_secret.len())?; + reply.expand(&serialized_secret) } pub fn challenge( diff --git a/src/piv_types.rs b/src/piv_types.rs index c121e83..36cd39a 100644 --- a/src/piv_types.rs +++ b/src/piv_types.rs @@ -142,6 +142,15 @@ impl AsymmetricAlgorithms { } } + pub fn ecdh_mechanism(self) -> Option { + use AsymmetricAlgorithms::*; + match self { + P256 => Some(Mechanism::P256), + /* P384 | P521 | X25519 | X448 */ + _ => None, + } + } + pub fn sign_mechanism(self) -> Mechanism { match self { Self::Rsa2048 => Mechanism::Rsa2048Pkcs, @@ -149,6 +158,11 @@ impl AsymmetricAlgorithms { Self::P256 => Mechanism::P256Prehashed, } } + + pub fn is_rsa(self) -> bool { + use AsymmetricAlgorithms::*; + matches!(self, Rsa2048 | Rsa4096) + } } /// TODO: