Skip to content

Commit

Permalink
Measurement libray update and fixes
Browse files Browse the repository at this point in the history
OVMF:
- New OVMF changes added section SVSM_CAA to OvmfSevMetadata. To calculate the measurement with this new section, the new section
has to be added and needs to be treated as zero pages when encountered.
- Upstream OVMF has these changes for AmdSevOvmf, so both OVMF test
binaries AmdSevOvmf and OvmfX64 were regenerated to match the latest EDk2 release:
https://github.com/tianocore/edk2/releases/tag/edk2-stable202405

VCPU types:
- Added the ability to convert from an i32 (signature value) to a CpuType.
There are only 4 possible cpu signatures, that match to more than one CpuType.
If user provides a cpu signature, we can just match it to a
main CpuType (Epyc, Rome, Milan, Genoa).

Guest Policy:
- Make use of the Guest Policy structure defined in guest firmware.
- Fixed default policy value for ID-BLOCK, the default value should be 0x30000.

Family and Image Ids:
- Image Id is now a type of Family Id (less repetitive code)
- Instantiation Functions were added

VMMType:
- Can get vmm type from a string.

SnpLaunchDigest:
- Make use of this strucutre and return it as calculation result.
- Added a print as hex function

Signed-off-by: DGonzalezVillal <Diego.GonzalezVillalobos@amd.com>
  • Loading branch information
DGonzalezVillal authored and tylerfanelli committed Jul 31, 2024
1 parent 4f8cbc7 commit 27b4e17
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 168 deletions.
35 changes: 35 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,9 @@ pub enum IdBlockError {
/// Bincode Error Handling
BincodeError(bincode::ErrorKind),

/// TryFrom Slice Error handling
FromSliceError(TryFromSliceError),

/// Error from when handling SEV Curve algorithm
SevCurveError(),

Expand All @@ -849,6 +852,7 @@ impl std::fmt::Display for IdBlockError {
IdBlockError::LargeArrayError(e) => write!(f, "{e}"),
IdBlockError::FileError(e) => write!(f, "Failed handling file: {e}"),
IdBlockError::BincodeError(e) => write!(f, "Bincode error encountered: {e}"),
IdBlockError::FromSliceError(e) => write!(f, "Error converting slice: {e}"),
IdBlockError::SevCurveError() => {
write!(f, "Wrong curve used in the provided private key")
}
Expand Down Expand Up @@ -879,12 +883,19 @@ impl std::convert::From<std::io::Error> for IdBlockError {
Self::FileError(value)
}
}

impl std::convert::From<bincode::ErrorKind> for IdBlockError {
fn from(value: bincode::ErrorKind) -> Self {
Self::BincodeError(value)
}
}

impl std::convert::From<TryFromSliceError> for IdBlockError {
fn from(value: TryFromSliceError) -> Self {
Self::FromSliceError(value)
}
}

/// Errors which may be encountered when calculating the guest measurement.
#[derive(Debug)]
pub enum MeasurementError {
Expand Down Expand Up @@ -915,9 +926,15 @@ pub enum MeasurementError {
/// Id Block Error Handling
IdBlockError(IdBlockError),

/// Large Array Error handling
LargeArrayError(LargeArrayError),

/// Invalid VCPU provided
InvalidVcpuTypeError(String),

/// Invalid VCPU Signature provided
InvalidVcpuSignatureError(String),

/// Invalid VMM Provided
InvalidVmmError(String),

Expand All @@ -943,9 +960,15 @@ impl std::fmt::Display for MeasurementError {
MeasurementError::OVMFError(e) => write!(f, "OVMF Error Encountered: {e}"),
MeasurementError::SevHashError(e) => write!(f, "Sev hash Error Encountered: {e}"),
MeasurementError::IdBlockError(e) => write!(f, "Id Block Error Encountered: {e}"),
MeasurementError::LargeArrayError(e) => {
write!(f, "Error when handling Large arrays: {e}")
}
MeasurementError::InvalidVcpuTypeError(value) => {
write!(f, "Invalid VCPU type value provided: {value}")
}
MeasurementError::InvalidVcpuSignatureError(value) => {
write!(f, "Invalid VCPU signature provided: {value}")
}
MeasurementError::InvalidVmmError(value) => {
write!(f, "Invalid VMM type provided: {value}")
}
Expand Down Expand Up @@ -1013,3 +1036,15 @@ impl std::convert::From<SevHashError> for MeasurementError {
Self::SevHashError(value)
}
}

impl std::convert::From<IdBlockError> for MeasurementError {
fn from(value: IdBlockError) -> Self {
Self::IdBlockError(value)
}
}

impl std::convert::From<LargeArrayError> for MeasurementError {
fn from(value: LargeArrayError) -> Self {
Self::LargeArrayError(value)
}
}
46 changes: 22 additions & 24 deletions src/measurement/gctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ use openssl::sha::sha384;
use crate::error::*;

#[cfg(target_os = "linux")]
use crate::launch::snp::PageType;

// Launch digest size in bytes
pub(crate) const LD_SIZE: usize = 384 / 8;
use crate::{
launch::snp::PageType,
measurement::snp::{SnpLaunchDigest, LD_BYTES},
};

// VMSA page is recorded in the RMP table with GPA (u64)(-1).
// However, the address is page-aligned, and also all the bits above
// 51 are cleared.
pub(crate) const VMSA_GPA: u64 = 0xFFFFFFFFF000;

// Launch digest intialized in all zeros
const ZEROS: [u8; LD_SIZE] = [0; LD_SIZE];
// Launch digest sized array with all zeros
const ZEROS: [u8; LD_BYTES] = [0; LD_BYTES];

fn validate_block_size(length: usize) -> Result<(), GCTXError> {
if (length % 4096) != 0 {
Expand All @@ -33,16 +33,17 @@ pub(crate) struct Completed;

/// Guest context field structure
pub struct Gctx<T> {
/// Launch Digest, 48 bytes long
ld: [u8; LD_SIZE],
/// 48 byte Launch Digest
ld: SnpLaunchDigest,
/// Current GCTX state
_state: T,
}

/// Default init of GCTX, launch digest of all 0s
impl Default for Gctx<Updating> {
fn default() -> Self {
Self {
ld: ZEROS,
ld: SnpLaunchDigest::default(),
_state: Updating,
}
}
Expand All @@ -58,14 +59,14 @@ impl Gctx<Updating> {
}

/// Will update guest context launch digest with provided data from page
fn update(&mut self, page_type: u8, gpa: u64, contents: &[u8]) -> Result<(), GCTXError> {
fn update(&mut self, page_type: u8, gpa: u64, contents: &[u8]) -> Result<(), MeasurementError> {
let page_info_len: u16 = 0x70;
let is_imi: u8 = 0;
let vmpl3_perms: u8 = 0;
let vmpl2_perms: u8 = 0;
let vmpl1_perms: u8 = 0;

let mut page_info: Vec<u8> = self.ld.to_vec();
let mut page_info: Vec<u8> = self.ld.try_into()?;
page_info.extend_from_slice(contents);

page_info.extend_from_slice(&page_info_len.to_le_bytes());
Expand All @@ -80,17 +81,14 @@ impl Gctx<Updating> {
page_info.extend_from_slice(&gpa.to_le_bytes());

if page_info.len() != (page_info_len as usize) {
return Err(GCTXError::InvalidPageSize(
page_info.len(),
page_info_len as usize,
));
return Err(GCTXError::InvalidPageSize(page_info.len(), page_info_len as usize).into());
}
self.ld = sha384(&page_info);
self.ld = sha384(&page_info).as_slice().try_into()?;

Ok(())
}

/// Update Lanunch digest type accprding to page type and guest physical address.
/// Update Lanunch digest type according to page type and guest physical address.
/// Some Page types don't require data. Some page types just require size of the page.
#[cfg(target_os = "linux")]
pub fn update_page(
Expand All @@ -99,7 +97,7 @@ impl Gctx<Updating> {
gpa: u64,
contents: Option<&[u8]>,
length_bytes: Option<usize>,
) -> Result<(), GCTXError> {
) -> Result<(), MeasurementError> {
match page_type {
PageType::Normal => {
if let Some(data) = contents {
Expand All @@ -116,7 +114,7 @@ impl Gctx<Updating> {
}
Ok(())
} else {
Err(GCTXError::MissingData)
Err(GCTXError::MissingData.into())
}
}

Expand All @@ -126,7 +124,7 @@ impl Gctx<Updating> {
self.update(page_type as u8, VMSA_GPA, sha384(data).as_slice())?;
Ok(())
} else {
Err(GCTXError::MissingData)
Err(GCTXError::MissingData.into())
}
}

Expand All @@ -140,7 +138,7 @@ impl Gctx<Updating> {
}
Ok(())
} else {
Err(GCTXError::MissingBlockSize)
Err(GCTXError::MissingBlockSize.into())
}
}

Expand All @@ -161,7 +159,7 @@ impl Gctx<Updating> {
}
}

/// Update is done and now we switch to a completed state
/// Change State to Completed
pub(crate) fn finished(&self) -> Gctx<Completed> {
Gctx {
ld: self.ld,
Expand All @@ -172,7 +170,7 @@ impl Gctx<Updating> {

impl Gctx<Completed> {
/// Get the launch digest bytes
pub(crate) fn ld(&self) -> &[u8; LD_SIZE] {
&self.ld
pub(crate) fn ld(&self) -> SnpLaunchDigest {
self.ld
}
}
20 changes: 12 additions & 8 deletions src/measurement/idblock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ use std::{

use crate::{
error::IdBlockError,
measurement::idblock_types::{
FamilyId, IdAuth, IdBlock, IdBlockLaunchDigest, IdMeasurements, ImageId, SevEcdsaPubKey,
SevEcdsaSig, CURVE_P384_NID,
firmware::guest::GuestPolicy,
measurement::{
idblock_types::{
FamilyId, IdAuth, IdBlock, IdMeasurements, ImageId, SevEcdsaPubKey, SevEcdsaSig,
CURVE_P384_NID,
},
snp::SnpLaunchDigest,
},
};

Expand Down Expand Up @@ -99,13 +103,13 @@ pub fn load_priv_key(path: PathBuf) -> Result<EcKey<Private>, IdBlockError> {
Ok(pkey)
}

/// Generate the sha384 digest of the provided pem key
pub fn generate_key_digest(key_path: PathBuf) -> Result<IdBlockLaunchDigest, IdBlockError> {
/// Generate the sha384 digest of the provided pem key (same sized digest as SNP Launch Digest)
pub fn generate_key_digest(key_path: PathBuf) -> Result<SnpLaunchDigest, IdBlockError> {
let ec_key = load_priv_key(key_path)?;

let pub_key = SevEcdsaPubKey::try_from(&ec_key)?;

Ok(IdBlockLaunchDigest::new(
Ok(SnpLaunchDigest::new(
sha384(
bincode::serialize(&pub_key)
.map_err(|e| IdBlockError::BincodeError(*e))?
Expand All @@ -118,11 +122,11 @@ pub fn generate_key_digest(key_path: PathBuf) -> Result<IdBlockLaunchDigest, IdB
/// Calculate the different pieces needed for a complete pre-attestation.
/// ID-BLOCK, AUTH-BLOCK, id-key digest and auth-key digest.
pub fn snp_calculate_id(
ld: Option<IdBlockLaunchDigest>,
ld: Option<SnpLaunchDigest>,
family_id: Option<FamilyId>,
image_id: Option<ImageId>,
svn: Option<u32>,
policy: Option<u64>,
policy: Option<GuestPolicy>,
id_key_file: PathBuf,
auth_key_file: PathBuf,
) -> Result<IdMeasurements, IdBlockError> {
Expand Down
Loading

0 comments on commit 27b4e17

Please sign in to comment.