From 48f1e0da0af96dcad56730c32c568df014bd607c Mon Sep 17 00:00:00 2001 From: Steffen Eiden Date: Mon, 18 Nov 2024 14:50:07 +0100 Subject: [PATCH] rust/pv: Add unrecognized field to additional-data handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an unrecognized field to the AdditionalData struct that contains any data that is not known by the library. Generalize the intention of the additional data read function and make extensions to Additional data easier. Add tests for serialization. Reviewed-by: Jan Höppner Reviewed-by: Marc Hartmayer Signed-off-by: Steffen Eiden --- rust/pv/src/uvattest/additional.rs | 157 +++++++++++++++++++++++++---- 1 file changed, 138 insertions(+), 19 deletions(-) diff --git a/rust/pv/src/uvattest/additional.rs b/rust/pv/src/uvattest/additional.rs index 0502a022..cf663b07 100644 --- a/rust/pv/src/uvattest/additional.rs +++ b/rust/pv/src/uvattest/additional.rs @@ -1,16 +1,17 @@ // SPDX-License-Identifier: MIT // // Copyright IBM Corp. 2024 -use super::arcb::AttestationFlags; + +use serde::Serialize; +use std::fmt::Display; + use crate::req::Keyslot; use crate::static_assert; use crate::{Error, Result}; -use serde::Serialize; -use std::fmt::Display; -use zerocopy::FromBytes; + +use super::arcb::AttestationFlags; /// Hash for additional-data stuff used for parsing [`AdditionalData`] -pub(crate) type AttAddHash = [u8; PHKH_SIZE as usize]; pub(super) const PHKH_SIZE: u32 = 0x20; static_assert!(Keyslot::PHKH_SIZE == PHKH_SIZE); @@ -25,6 +26,8 @@ where image_phkh: Option, #[serde(skip_serializing_if = "Option::is_none")] attestation_phkh: Option, + #[serde(skip_serializing_if = "Option::is_none")] + unrecognized: Option, } impl Display for AdditionalData @@ -47,22 +50,22 @@ where Ok(()) } write_field(f, "Image PHKH", &self.image_phkh)?; - write_field(f, "Attestation PHKH", &self.attestation_phkh) + write_field(f, "Attestation PHKH", &self.attestation_phkh)?; + write_field(f, "Unrecognized", &self.unrecognized)?; + Ok(()) } } -fn read_hash<'a>( +fn read_value<'a>( data: &'a [u8], + size: u32, read: bool, name: &'static str, -) -> Result<(Option<&'a AttAddHash>, &'a [u8])> { +) -> Result<(Option<&'a [u8]>, &'a [u8])> { + let size = size as usize; match read { - true => { - let (v, data) = - AttAddHash::slice_from_prefix(data, 1).ok_or(Error::AddDataMissing(name))?; - // slice from prefix ensures that there is 1 element. - Ok((Some(&v[0]), data)) - } + true if data.len() >= size => Ok((Some(&data[..size]), &data[size..])), + true => Err(Error::AddDataMissing(name)), false => Ok((None, data)), } } @@ -85,6 +88,11 @@ impl AdditionalData { pub fn attestation_public_host_key_hash(&self) -> Option<&T> { self.attestation_phkh.as_ref() } + + /// Provides a reference to the data not known by this implementation. + pub fn unrecognized(&self) -> Option<&T> { + self.unrecognized.as_ref() + } } impl<'a, T: Serialize + From<&'a [u8]> + Sized> AdditionalData { @@ -93,10 +101,12 @@ impl<'a, T: Serialize + From<&'a [u8]> + Sized> AdditionalData { let AdditionalData { image_phkh, attestation_phkh, + unrecognized, } = other; Self { image_phkh: image_phkh.map(|i| i.into()), attestation_phkh: attestation_phkh.map(|i| i.into()), + unrecognized: unrecognized.map(|i| i.into()), } } } @@ -104,6 +114,7 @@ impl<'a, T: Serialize + From<&'a [u8]> + Sized> AdditionalData { impl<'a> AdditionalData<&'a [u8]> { /// Create from a slice of additional-data /// + /// `data`: Unstructured additional-data /// `flags`: Flags indicating which additional-data field is present. /// /// # Error @@ -111,13 +122,121 @@ impl<'a> AdditionalData<&'a [u8]> { /// Fails if there is a mismatch between the data and the flags. Should not happen after a /// successful attestation verification. pub fn from_slice(data: &'a [u8], flags: &AttestationFlags) -> Result { - let _data = data; - let (image_phkh, _data) = read_hash(data, flags.image_phkh(), "Image PHKH")?; - let (attestation_phkh, _data) = read_hash(data, flags.attest_phkh(), "Attestation PHKH")?; + let (image_phkh, data) = read_value(data, PHKH_SIZE, flags.image_phkh(), "Image PHKH")?; + let (attestation_phkh, data) = + read_value(data, PHKH_SIZE, flags.attest_phkh(), "Attestation PHKH")?; + let unrecognized = (!data.is_empty()).then_some(data); Ok(Self { - image_phkh: image_phkh.map(|v| v.as_slice()), - attestation_phkh: attestation_phkh.map(|v| v.as_slice()), + image_phkh, + attestation_phkh, + unrecognized, }) } } + +#[cfg(test)] +mod test { + use serde_test::Token; + + use super::*; + #[test] + fn ser() { + let add = AdditionalData { + image_phkh: 0_u8.into(), + attestation_phkh: 1_u8.into(), + unrecognized: 2_u8.into(), + }; + + serde_test::assert_ser_tokens( + &add, + &[ + Token::Struct { + name: "AdditionalData", + len: 3, + }, + Token::Str("image_phkh"), + Token::Some, + Token::U8(0), + Token::Str("attestation_phkh"), + Token::Some, + Token::U8(1), + Token::Str("unrecognized"), + Token::Some, + Token::U8(2), + Token::StructEnd, + ], + ); + } + + #[test] + fn ser_no_att() { + let add = AdditionalData { + image_phkh: 0_u8.into(), + attestation_phkh: None, + unrecognized: 2_u8.into(), + }; + + serde_test::assert_ser_tokens( + &add, + &[ + Token::Struct { + name: "AdditionalData", + len: 2, + }, + Token::Str("image_phkh"), + Token::Some, + Token::U8(0), + Token::Str("unrecognized"), + Token::Some, + Token::U8(2), + Token::StructEnd, + ], + ); + } + + #[test] + fn ser_no_unrec() { + let add = AdditionalData { + image_phkh: 0_u8.into(), + attestation_phkh: 1_u8.into(), + unrecognized: None, + }; + + serde_test::assert_ser_tokens( + &add, + &[ + Token::Struct { + name: "AdditionalData", + len: 2, + }, + Token::Str("image_phkh"), + Token::Some, + Token::U8(0), + Token::Str("attestation_phkh"), + Token::Some, + Token::U8(1), + Token::StructEnd, + ], + ); + } + #[test] + fn ser_no() { + let add: AdditionalData = AdditionalData { + image_phkh: None, + attestation_phkh: None, + unrecognized: None, + }; + + serde_test::assert_ser_tokens( + &add, + &[ + Token::Struct { + name: "AdditionalData", + len: 0, + }, + Token::StructEnd, + ], + ); + } +}