diff --git a/rust/pv/src/uvattest/additional.rs b/rust/pv/src/uvattest/additional.rs index cf663b07..2370a35b 100644 --- a/rust/pv/src/uvattest/additional.rs +++ b/rust/pv/src/uvattest/additional.rs @@ -14,8 +14,10 @@ use super::arcb::AttestationFlags; /// Hash for additional-data stuff used for parsing [`AdditionalData`] pub(super) const PHKH_SIZE: u32 = 0x20; static_assert!(Keyslot::PHKH_SIZE == PHKH_SIZE); +pub(super) const SECRET_STORE_HASH_SIZE: u32 = 0x40; +pub(super) const FW_STATE_SIZE: u32 = 0x140; -/// Struct describing the additional-data of an Attestation Request +/// Additional-data of an Attestation Request #[derive(Serialize, Debug)] #[serde(default)] pub struct AdditionalData @@ -27,6 +29,10 @@ where #[serde(skip_serializing_if = "Option::is_none")] attestation_phkh: Option, #[serde(skip_serializing_if = "Option::is_none")] + secret_store_hash: Option, + #[serde(skip_serializing_if = "Option::is_none")] + firmware_state: Option, + #[serde(skip_serializing_if = "Option::is_none")] unrecognized: Option, } @@ -51,6 +57,8 @@ where } write_field(f, "Image PHKH", &self.image_phkh)?; write_field(f, "Attestation PHKH", &self.attestation_phkh)?; + write_field(f, "Secret store hash", &self.secret_store_hash)?; + write_field(f, "Firmware state", &self.firmware_state)?; write_field(f, "Unrecognized", &self.unrecognized)?; Ok(()) } @@ -71,7 +79,7 @@ fn read_value<'a>( } impl AdditionalData { - /// Provides a reference to the image public host key hash. + /// Provides a reference to the image public host key hash, if any. /// /// This is the hash of the public host key of the corresponding private machine key that /// decrypted the Secure Execution guest. @@ -80,7 +88,7 @@ impl AdditionalData { self.image_phkh.as_ref() } - /// Provides a reference to the attestation public host key hash. + /// Provides a reference to the attestation public host key hash, if any. /// /// This is the hash of the public host key of the corresponding private machine key that /// decrypted the Attestation request. @@ -89,6 +97,24 @@ impl AdditionalData { self.attestation_phkh.as_ref() } + /// Provides a reference to the secret store hash, if any. + /// + /// This is a hash over the state of the guest's UV secret store. A SHA512 hash over the + /// concatenated request tags of all Add-secret requests and a 0 or 1 byte for the locked + /// state. + /// + /// SHA512 (n*[Add-secret-request]|locked?) + pub fn secret_store_hash(&self) -> Option<&T> { + self.secret_store_hash.as_ref() + } + + /// Provides a reference to the firmware state, if any. + /// + /// This represents the state of selected firmware parts to be interpreted by an IBM service. + pub fn firmware_state(&self) -> Option<&T> { + self.firmware_state.as_ref() + } + /// Provides a reference to the data not known by this implementation. pub fn unrecognized(&self) -> Option<&T> { self.unrecognized.as_ref() @@ -101,11 +127,15 @@ impl<'a, T: Serialize + From<&'a [u8]> + Sized> AdditionalData { let AdditionalData { image_phkh, attestation_phkh, + secret_store_hash, + firmware_state: firmware_hash, unrecognized, } = other; Self { image_phkh: image_phkh.map(|i| i.into()), attestation_phkh: attestation_phkh.map(|i| i.into()), + secret_store_hash: secret_store_hash.map(|i| i.into()), + firmware_state: firmware_hash.map(|i| i.into()), unrecognized: unrecognized.map(|i| i.into()), } } @@ -125,11 +155,21 @@ impl<'a> AdditionalData<&'a [u8]> { 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 (secret_store_hash, data) = read_value( + data, + SECRET_STORE_HASH_SIZE, + flags.secret_store_hash(), + "Secret store state", + )?; + let (firmware_state, data) = + read_value(data, FW_STATE_SIZE, flags.firmware_state(), "Firmware hash")?; let unrecognized = (!data.is_empty()).then_some(data); Ok(Self { image_phkh, attestation_phkh, + secret_store_hash, + firmware_state, unrecognized, }) } @@ -145,7 +185,9 @@ mod test { let add = AdditionalData { image_phkh: 0_u8.into(), attestation_phkh: 1_u8.into(), - unrecognized: 2_u8.into(), + secret_store_hash: 2_u8.into(), + firmware_state: 3_u8.into(), + unrecognized: 4_u8.into(), }; serde_test::assert_ser_tokens( @@ -153,7 +195,7 @@ mod test { &[ Token::Struct { name: "AdditionalData", - len: 3, + len: 5, }, Token::Str("image_phkh"), Token::Some, @@ -161,19 +203,27 @@ mod test { Token::Str("attestation_phkh"), Token::Some, Token::U8(1), - Token::Str("unrecognized"), + Token::Str("secret_store_hash"), Token::Some, Token::U8(2), + Token::Str("firmware_state"), + Token::Some, + Token::U8(3), + Token::Str("unrecognized"), + Token::Some, + Token::U8(4), Token::StructEnd, ], ); } #[test] - fn ser_no_att() { + fn ser_no_miss() { let add = AdditionalData { image_phkh: 0_u8.into(), attestation_phkh: None, + secret_store_hash: None, + firmware_state: None, unrecognized: 2_u8.into(), }; @@ -200,6 +250,8 @@ mod test { let add = AdditionalData { image_phkh: 0_u8.into(), attestation_phkh: 1_u8.into(), + secret_store_hash: None, + firmware_state: None, unrecognized: None, }; @@ -225,6 +277,8 @@ mod test { let add: AdditionalData = AdditionalData { image_phkh: None, attestation_phkh: None, + secret_store_hash: None, + firmware_state: None, unrecognized: None, }; diff --git a/rust/pv/src/uvattest/arcb.rs b/rust/pv/src/uvattest/arcb.rs index 07dd3e89..1cb7cb90 100644 --- a/rust/pv/src/uvattest/arcb.rs +++ b/rust/pv/src/uvattest/arcb.rs @@ -1,7 +1,11 @@ // SPDX-License-Identifier: MIT // // Copyright IBM Corp. 2024 -use super::{additional::PHKH_SIZE, AttNonce}; + +use openssl::pkey::{PKey, Public}; +use std::mem::size_of; +use zerocopy::{AsBytes, BigEndian, FromBytes, FromZeroes, U32}; + use crate::{ assert_size, attest::{AttestationMagic, AttestationMeasAlg}, @@ -13,9 +17,11 @@ use crate::{ uv::UvFlags, Error, Result, }; -use openssl::pkey::{PKey, Public}; -use std::mem::size_of; -use zerocopy::{AsBytes, BigEndian, FromBytes, FromZeroes, U32}; + +use super::{ + additional::{FW_STATE_SIZE, PHKH_SIZE, SECRET_STORE_HASH_SIZE}, + AttNonce, +}; #[cfg(doc)] use crate::{ @@ -310,7 +316,14 @@ static_assert!(AttestationFlags::FLAG_TO_ADD_SIZE.len() < 64); impl AttestationFlags { /// Maps the flag to the (maximum) required size for the additional data - pub(crate) const FLAG_TO_ADD_SIZE: [u32; 4] = [0, 0, PHKH_SIZE, PHKH_SIZE]; + pub(crate) const FLAG_TO_ADD_SIZE: [u32; 6] = [ + 0, + 0, + PHKH_SIZE, + PHKH_SIZE, + SECRET_STORE_HASH_SIZE, + FW_STATE_SIZE, + ]; /// Returns the maximum size this flag requires for additional data pub fn expected_additional_size(&self) -> u32 { @@ -353,6 +366,30 @@ impl AttestationFlags { pub fn attest_phkh(&self) -> bool { self.0.is_set(3) } + + /// Flag 4 - request the state of the secret store + /// + /// Asks the Ultravisor to provide the hash of the added secret requests. Requires 64 bytes. + pub fn set_secret_store_hash(&mut self) { + self.0.set_bit(4); + } + + /// Check weather the hash of the added secret requests flag is on + pub fn secret_store_hash(&self) -> bool { + self.0.is_set(4) + } + + /// Flag 5 - request the firmware hash + /// + /// Asks the Ultravisor to provide the hash of the firmware. Requires 320 bytes. + pub fn set_firmware_state(&mut self) { + self.0.set_bit(5); + } + + /// Check weather the hash of the added secret requests flag is on + pub fn firmware_state(&self) -> bool { + self.0.is_set(5) + } } #[repr(C)]