From f36c34038bd3423067db2c5130e11f8f7ce2febb Mon Sep 17 00:00:00 2001 From: Steffen Eiden Date: Tue, 30 Jan 2024 12:55:53 +0100 Subject: [PATCH] rust/pv: Add-Secret: Add user-data types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add four new user-data types an add-secret request could have: Unsigned, Signed(EcSECP521R1, Rsa(2048, 3072)) As the user-data enum was not marked as non-exaustive this might be a breaking change for users. (Not for any crate in this repo though). The addition of such user-data is provided by following patches. Reviewed-by: Marc Hartmayer Signed-off-by: Steffen Eiden Signed-off-by: Jan Höppner --- rust/pv/src/uvsecret/asrcb.rs | 6 +- rust/pv/src/uvsecret/uvc.rs | 2 +- rust/pv_core/src/error.rs | 3 + rust/pv_core/src/uvsecret.rs | 147 +++++++++++++++++++++++++++++++--- 4 files changed, 143 insertions(+), 15 deletions(-) diff --git a/rust/pv/src/uvsecret/asrcb.rs b/rust/pv/src/uvsecret/asrcb.rs index 515a23b9..dd2481bd 100644 --- a/rust/pv/src/uvsecret/asrcb.rs +++ b/rust/pv/src/uvsecret/asrcb.rs @@ -240,11 +240,7 @@ impl AddSecretRequest { self.keyslots.iter().for_each(|k| aad.push(Aad::Ks(k))); aad.push(Aad::Plain(&secr_auth)); - ctx.build_aad(self.version.into(), &aad, conf_len, self.magic()) - } - - fn magic(&self) -> crate::request::RequestMagic { - self.magic.as_bytes().try_into().unwrap() + ctx.build_aad(self.version.into(), &aad, conf_len, self.magic.get()) } #[doc(hidden)] diff --git a/rust/pv/src/uvsecret/uvc.rs b/rust/pv/src/uvsecret/uvc.rs index cdcd3579..c2c42279 100644 --- a/rust/pv/src/uvsecret/uvc.rs +++ b/rust/pv/src/uvsecret/uvc.rs @@ -63,7 +63,7 @@ impl AddCmd { let mut data = Vec::with_capacity(PAGESIZE); bin_add_secret_req.read_to_end(&mut data)?; - if !AddSecretMagic::starts_with_magic(&data[..6]) { + if !AddSecretMagic::starts_with_magic(&data) { return Err(Error::NoAsrcb); } Ok(Self(data)) diff --git a/rust/pv_core/src/error.rs b/rust/pv_core/src/error.rs index e2954eb7..e05ea9d5 100644 --- a/rust/pv_core/src/error.rs +++ b/rust/pv_core/src/error.rs @@ -44,6 +44,9 @@ pub enum Error { #[error("Input does not contain an add-secret request")] NoAsrcb, + #[error("Input contains unsupported user-data type: {0:#06x}")] + UnsupportedUserData(u16), + // errors from other crates #[error(transparent)] Io(#[from] std::io::Error), diff --git a/rust/pv_core/src/uvsecret.rs b/rust/pv_core/src/uvsecret.rs index 3fbac315..5a91d2fd 100644 --- a/rust/pv_core/src/uvsecret.rs +++ b/rust/pv_core/src/uvsecret.rs @@ -4,14 +4,17 @@ use crate::{ misc::to_u16, - request::MagicValue, + request::{MagicValue, RequestMagic}, uv::{ListCmd, UvCmd}, Error, Result, }; +use byteorder::{BigEndian, ByteOrder}; use std::{ fmt::Display, io::{Cursor, Read, Seek, Write}, + mem::size_of, }; +use utils::{assert_size, static_assert}; use zerocopy::{AsBytes, FromBytes, U16, U32}; /// The magic value used to identify an add-secret request`] @@ -29,30 +32,156 @@ use zerocopy::{AsBytes, FromBytes, U16, U32}; ///``` /// #[repr(C)] -#[derive(Debug, Clone, Copy, AsBytes)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, AsBytes)] pub struct AddSecretMagic { magic: [u8; 6], // [0x61, 0x73, 0x72, 0x63, 0x62, 0x4D] - tp: UserDataType, + kind: U16, } +assert_size!(AddSecretMagic, 8); impl MagicValue<6> for AddSecretMagic { // "asrcbM" const MAGIC: [u8; 6] = [0x61, 0x73, 0x72, 0x63, 0x62, 0x4D]; } +impl AddSecretMagic { + /// Get the magic value. + pub fn get(&self) -> RequestMagic { + let mut res = RequestMagic::default(); + debug_assert!(res.len() == size_of::()); + // Panic: does not panic, buf is 8 bytes long + self.write_to(&mut res).unwrap(); + res + } + + /// Try to convert from a byte slice. + /// + /// Retuns [`None`] if the byte slice does not contain a valid magic value variant. + pub fn try_from_bytes(bytes: &[u8]) -> Result { + if !Self::starts_with_magic(bytes) || bytes.len() < size_of::() { + return Err(Error::NoAsrcb); + } + + // Panic: Will not panic, bytes is at least 8 elements long + let kind = BigEndian::read_u16(&bytes[6..8]); + let kind = UserDataType::try_from(kind)?; + Ok(Self::from(kind)) + } +} + /// Types of (non architectured) user data for an add-secret request #[repr(u16)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, zerocopy::AsBytes)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UserDataType { /// Marker that the request does not contain any user data Null = 0x0000, + /// Arbitrary user data (max 512 bytes) + Unsigned = 0x0001, + /// User data message signed with an Ec key, (max 256 byte) + SgnEcSECP521R1 = 0x0002, + /// User data message signature with a Rsa key of 2048 bit size, (max 256 byte) + SgnRsa2048 = 0x0003, + /// User data message signature with a Rsa key of 3072 bit size, (max 128 byte) + SgnRsa3072 = 0x0004, } -impl From for AddSecretMagic { - fn from(tp: UserDataType) -> Self { - Self { - magic: Self::MAGIC, - tp, +impl UserDataType { + /// Returns the maximum user-data size in bytes. + pub fn max(&self) -> usize { + match self { + UserDataType::Null => 0, + UserDataType::Unsigned => 512, + UserDataType::SgnEcSECP521R1 => 256, + UserDataType::SgnRsa2048 => 256, + UserDataType::SgnRsa3072 => 128, } } } + +impl Display for UserDataType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Self::Null => "None", + Self::Unsigned => "unsigned", + Self::SgnEcSECP521R1 => "ECDSA signed", + Self::SgnRsa2048 => "RSA 2048 signed", + Self::SgnRsa3072 => "RSA 3072 signed", + } + ) + } +} + +impl TryFrom for UserDataType { + type Error = Error; + + fn try_from(value: u16) -> std::result::Result { + if value == UserDataType::Null as u16 { + Ok(UserDataType::Null) + } else if value == UserDataType::Unsigned as u16 { + Ok(UserDataType::Unsigned) + } else if value == UserDataType::SgnEcSECP521R1 as u16 { + Ok(UserDataType::SgnEcSECP521R1) + } else if value == UserDataType::SgnRsa2048 as u16 { + Ok(UserDataType::SgnRsa2048) + } else if value == UserDataType::SgnRsa3072 as u16 { + Ok(UserDataType::SgnRsa3072) + } else { + Err(Error::UnsupportedUserData(value)) + } + } +} + +impl From for AddSecretMagic { + fn from(kind: UserDataType) -> Self { + Self { + magic: Self::MAGIC, + kind: (kind as u16).into(), + } + } +} + +#[cfg(test)] +mod test { + use crate::{ + request::{ + uvsecret::{AddSecretMagic, UserDataType}, + MagicValue, + }, + Error, + }; + + #[test] + fn convert_user_data() { + assert!(matches!( + UserDataType::try_from(5), + Err(Error::UnsupportedUserData(5)) + )); + } + + #[test] + fn magic_get() { + let user_data = AddSecretMagic::from(UserDataType::SgnEcSECP521R1); + + assert_eq!( + user_data.get(), + [0x61, 0x73, 0x72, 0x63, 0x62, 0x4D, 0x00, 0x02] + ); + } + + #[test] + fn magic_try_from() { + let bin = [0x61, 0x73, 0x72, 0x63, 0x62, 0x4D, 0x00, 0x02]; + + let magic = AddSecretMagic::try_from_bytes(&bin).unwrap(); + assert_eq!( + magic, + AddSecretMagic { + magic: AddSecretMagic::MAGIC, + kind: (UserDataType::SgnEcSECP521R1 as u16).into() + } + ); + } +}