diff --git a/src/commands.rs b/src/commands.rs index 0b8cdde..5416343 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -15,7 +15,7 @@ use crate::state::TouchPolicy; pub use crate::{ container::{ self as containers, AttestKeyReference, AuthenticateKeyReference, - ChangeReferenceKeyReference, GenerateAsymmetricKeyReference, VerifyKeyReference, + ChangeReferenceKeyReference, AsymmetricKeyReference, VerifyKeyReference, }, piv_types, Pin, Puk, }; @@ -58,7 +58,7 @@ pub enum Command<'l> { GeneralAuthenticate(GeneralAuthenticate), /// Store a data object / container. PutData(PutData), - GenerateAsymmetric(GenerateAsymmetricKeyReference), + GenerateAsymmetric(AsymmetricKeyReference), /* Yubico commands */ YkExtension(YubicoPivExtension), @@ -327,7 +327,7 @@ impl<'l, const C: usize> TryFrom<&'l iso7816::Command> for Command<'l> { } (0x00, Instruction::GenerateAsymmetricKeyPair, 0x00, p2) => { - Self::GenerateAsymmetric(GenerateAsymmetricKeyReference::try_from(p2)?) + Self::GenerateAsymmetric(AsymmetricKeyReference::try_from(p2)?) } // (0x00, 0x01, 0x10, 0x00) (0x00, Instruction::Unknown(0x01), 0x00, 0x00) => { diff --git a/src/container.rs b/src/container.rs index 7206a96..02d18b4 100644 --- a/src/container.rs +++ b/src/container.rs @@ -132,8 +132,8 @@ enum_subset! { enum_subset! { #[derive(Clone, Copy, Debug, Eq, PartialEq)] - pub enum GenerateAsymmetricKeyReference: KeyReference { - SecureMessaging, + pub enum AsymmetricKeyReference: KeyReference { + // SecureMessaging, PivAuthentication, DigitalSignature, KeyManagement, diff --git a/src/lib.rs b/src/lib.rs index be0e796..5cafcb5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ delog::generate_macros!(); pub mod commands; use commands::containers::KeyReference; -use commands::GeneralAuthenticate; +use commands::{AsymmetricKeyReference, GeneralAuthenticate}; pub use commands::{Command, YubicoPivExtension}; pub mod constants; pub mod container; @@ -23,7 +23,7 @@ mod dispatch; pub mod piv_types; pub mod state; -pub use piv_types::{Pin, Puk}; +pub use piv_types::{AsymmetricAlgorithms, Pin, Puk}; #[cfg(feature = "virtual")] pub mod vpicc; @@ -126,6 +126,10 @@ where self.load()? .general_authenticate(authenticate, command.data(), reply) } + Command::GenerateAsymmetric(reference) => { + self.load()? + .generate_asymmetric_keypair(reference, command.data(), reply) + } Command::YkExtension(yk_command) => { self.yubico_piv_extension(command.data(), yk_command, reply) } @@ -595,9 +599,9 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T> todo!() } - #[allow(unused)] - pub fn generate_asymmetric_keypair( + pub fn generate_asymmetric_keypair( &mut self, + reference: AsymmetricKeyReference, data: &[u8], reply: &mut Data, ) -> Result { @@ -629,37 +633,32 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T> // TODO: iterate on this, don't expect tags.. let input = derp::Input::from(data); // let (mechanism, parameter) = input.read_all(derp::Error::Read, |input| { - let (mechanism, _pin_policy, _touch_policy) = input + let mechanism_data = input .read_all(derp::Error::Read, |input| { derp::nested(input, 0xac, |input| { - let mechanism = derp::expect_tag_and_get_value(input, 0x80)?; - // let parameter = derp::expect_tag_and_get_value(input, 0x81)?; - let pin_policy = derp::expect_tag_and_get_value(input, 0xaa)?; - let touch_policy = derp::expect_tag_and_get_value(input, 0xab)?; - // Ok((mechanism.as_slice_less_safe(), parameter.as_slice_less_safe())) - Ok(( - mechanism.as_slice_less_safe(), - pin_policy.as_slice_less_safe(), - touch_policy.as_slice_less_safe(), - )) + derp::expect_tag_and_get_value(input, 0x80) + .map(|input| input.as_slice_less_safe()) }) }) .map_err(|_e| { - info!("error parsing GenerateAsymmetricKeypair: {:?}", &_e); + warn!("error parsing GenerateAsymmetricKeypair: {:?}", &_e); Status::IncorrectDataParameter })?; - // if mechanism != &[0x11] { - // HA! patch in Ed255 - if mechanism != [0x22] { - return Err(Status::InstructionNotSupportedOrInvalid); - } + let [mechanism] = mechanism_data else { + warn!("Mechanism of len not 1: {mechanism_data:02x?}"); + return Err(Status::IncorrectDataParameter); + }; + + let parsed_mechanism: AsymmetricAlgorithms = (*mechanism).try_into().map_err(|_| { + warn!("Unknown mechanism: {mechanism:x}"); + Status::IncorrectDataParameter + })?; // ble policy - - if let Some(key) = self.state.persistent.keys.authentication_key { - syscall!(self.trussed.delete(key)); - } + // if let Some(key) = self.state.persistent.keys.authentication_key { + // // syscall!(self.trussed.delete(key)); + // } // let key = syscall!(self.trussed.generate_p256_private_key( // let key = syscall!(self.trussed.generate_p256_private_key( @@ -686,7 +685,7 @@ impl<'a, T: trussed::Client + trussed::client::Ed255> LoadedAuthenticator<'a, T> // )? // .signature; // blocking::dbg!(&signature); - self.state.persistent.keys.authentication_key = Some(key); + // self.state.persistent.keys.authentication_key = Some(key); self.state.persistent.save(self.trussed); // let public_key = syscall!(self.trussed.derive_p256_public_key( diff --git a/src/piv_types.rs b/src/piv_types.rs index 7b3c76d..df2e128 100644 --- a/src/piv_types.rs +++ b/src/piv_types.rs @@ -92,7 +92,7 @@ impl TryFrom<&[u8]> for Puk { } enum_u8! { - #[derive(Clone, Copy, Eq, PartialEq, Debug)] + #[derive(Clone, Copy, Eq, PartialEq, Debug,Deserialize,Serialize)] // As additional reference, see: // https://globalplatform.org/wp-content/uploads/2014/03/GPC_ISO_Framework_v1.0.pdf#page=15 // @@ -129,6 +129,32 @@ enum_u8! { P384Sha384 = 0xF4, } } + +crate::container::enum_subset! { + #[derive(Clone, Copy, Eq, PartialEq, Debug,Deserialize,Serialize)] + pub enum AsymmetricAlgorithms: Algorithms { + Rsa2048, + Rsa4096, + P256, + + // Not supported + // Rsa1024 = 0x6, + // Rsa3072 = 0xE0, + // P384 = 0x14, + // P521 = 0x15, + + // non-standard! in piv-go though! + // Ed255_prev = 0x22, + // https://globalplatform.org/wp-content/uploads/2014/03/GPC_ISO_Framework_v1.0.pdf#page=15 + // non-standard! + // Ed25519 = 0xE2, + // X25519 = 0xE3, + // Ed448 = 0xE4, + // X448 = 0xE5, + + } +} + /// TODO: #[derive(Clone, Copy, Default, Eq, PartialEq)] pub struct CryptographicAlgorithmTemplate<'a> { diff --git a/src/state.rs b/src/state.rs index e6de4d7..3e84665 100644 --- a/src/state.rs +++ b/src/state.rs @@ -12,8 +12,8 @@ use trussed::{ types::{KeyId, KeySerialization, Location, Mechanism, PathBuf}, }; -use crate::constants::*; -use crate::piv_types::Algorithms; +use crate::{constants::*, piv_types::AsymmetricAlgorithms}; +use crate::{container::AsymmetricKeyReference, piv_types::Algorithms}; use crate::{Pin, Puk}; @@ -166,29 +166,43 @@ impl ManagementAlgorithm { } #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] -pub struct ManagementKey { +pub struct KeyWithAlg { pub id: KeyId, - pub alg: ManagementAlgorithm, + pub alg: A, } #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub struct Keys { // 9a "PIV Authentication Key" (YK: PIV Authentication) #[serde(skip_serializing_if = "Option::is_none")] - pub authentication_key: Option, + pub authentication_key: Option>, // 9b "PIV Card Application Administration Key" (YK: PIV Management) - pub management_key: ManagementKey, + pub management_key: KeyWithAlg, // 9c "Digital Signature Key" (YK: Digital Signature) #[serde(skip_serializing_if = "Option::is_none")] - pub signature_key: Option, + pub signature_key: Option>, // 9d "Key Management Key" (YK: Key Management) #[serde(skip_serializing_if = "Option::is_none")] - pub encryption_key: Option, + pub encryption_key: Option>, // 9e "Card Authentication Key" (YK: Card Authentication) #[serde(skip_serializing_if = "Option::is_none")] - pub pinless_authentication_key: Option, + pub pinless_authentication_key: Option>, // 0x82..=0x95 (130-149) - pub retired_keys: [Option; 20], + pub retired_keys: [Option>; 20], +} + +impl Keys { + pub fn asymetric_for_reference( + &self, + key: AsymmetricKeyReference, + ) -> &Option> { + match key { + AsymmetricKeyReference::PivAuthentication => &self.authentication_key, + AsymmetricKeyReference::DigitalSignature => &self.signature_key, + AsymmetricKeyReference::KeyManagement => &self.authentication_key, + AsymmetricKeyReference::CardAuthentication => &self.authentication_key, + } + } } #[derive(Debug, Default, Eq, PartialEq)] @@ -466,14 +480,33 @@ impl Persistent { )) .key; let old_management_key = self.keys.management_key.id; - self.keys.management_key = ManagementKey { id, alg }; + self.keys.management_key = KeyWithAlg { id, alg }; self.save(client); syscall!(client.delete(old_management_key)); } + pub fn set_asymmetric_key( + &mut self, + _key: AsymmetricKeyReference, + _id: KeyId, + _alg: AsymmetricAlgorithms, + _client: &mut impl trussed::Client, + ) -> Result>, Status> { + todo!() + } + + pub fn generate_asymmetric_key( + &mut self, + _key: AsymmetricKeyReference, + _alg: AsymmetricAlgorithms, + _client: &mut impl trussed::Client, + ) -> Result { + todo!() + } + pub fn initialize(client: &mut impl trussed::Client) -> Self { info!("initializing PIV state"); - let management_key = ManagementKey { + let management_key = KeyWithAlg { id: syscall!(client.unsafe_inject_key( YUBICO_DEFAULT_MANAGEMENT_KEY_ALG.mechanism(), YUBICO_DEFAULT_MANAGEMENT_KEY,