Skip to content

Commit

Permalink
Attestation Report versioning Update
Browse files Browse the repository at this point in the history
In spec 1.56 of the SEV firmware a new version of the attestation report
was introduced.

Here we are introducing a way to version the attestation report that
keeps security and backwards compatibility.

The main AttestationReport is now an enum that will contain the
different versions of the attestation report. This will not only handle
both of the Attestation reports, but it will also work as an interface.
Users will be able to use the enum to get any desired field and display
the report without having to manually unwrap the report themselves.

There are 2 new structs for the Attestation Report, one for each version.
There is a new trait called Attestable that all the attestation reports will implement, this
will allow users to attest their report regardless of the version.

The ReportRsp will now contain raw bytes, rather than the Attestation
Report Strucutre. The AttestationReport Enum has a TryFrom bytes that
will return the appropriate attestation report version according to the
first 4 bytes of the raw data.

Structs consumed by the attestation report that now have new fields
depending on the version, are now also versioned, and each report
will consume the appropriate version of that struct (look at PlatInfo).

Signed-off-by: DGonzalezVillal <[email protected]>
  • Loading branch information
DGonzalezVillal committed Jan 20, 2025
1 parent 18ed5c5 commit 0e42d14
Show file tree
Hide file tree
Showing 11 changed files with 738 additions and 57 deletions.
44 changes: 44 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,9 @@ pub enum UserApiError {
/// Invalid VMPL.
VmplError,

/// Attestation Report Error
AttestationReportError(AttestationReportError),

/// Unknown error
Unknown,
}
Expand All @@ -550,6 +553,7 @@ impl error::Error for UserApiError {
Self::VmmError(vmm_error) => Some(vmm_error),
Self::HashstickError(hashstick_error) => Some(hashstick_error),
Self::VmplError => None,
Self::AttestationReportError(attestation_error) => Some(attestation_error),
Self::Unknown => None,
}
}
Expand All @@ -565,6 +569,9 @@ impl std::fmt::Display for UserApiError {
Self::VmmError(error) => format!("VMM Error Encountered: {error}"),
Self::HashstickError(error) => format!("VLEK Hashstick Error Encountered: {error}"),
Self::VmplError => "Invalid VM Permission Level (VMPL)".to_string(),
Self::AttestationReportError(error) => {
format!("Attestation Report Error Encountered: {error}")
}
Self::Unknown => "Unknown Error Encountered!".to_string(),
};
write!(f, "{err_msg}")
Expand Down Expand Up @@ -619,6 +626,12 @@ impl std::convert::From<CertError> for UserApiError {
}
}

impl std::convert::From<AttestationReportError> for UserApiError {
fn from(attestation_error: AttestationReportError) -> Self {
Self::AttestationReportError(attestation_error)
}
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
/// Errors which may be encountered when handling Version Loaded Endorsement Keys
/// (VLEK) Hashsticks.
Expand Down Expand Up @@ -699,6 +712,37 @@ impl std::fmt::Display for CertError {

impl error::Error for CertError {}

#[derive(Debug)]
/// Errors which may be encountered when handling attestation reports
pub enum AttestationReportError {
/// Bincode Error Handling
BincodeError(bincode::ErrorKind),

/// Unsuported Attestation Report Version
UnsupportedReportVersion(u32),

/// Field is not supported in the current version of the Attestation Report
UnsupportedField(String),
}

impl std::fmt::Display for AttestationReportError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
AttestationReportError::BincodeError(e) => write!(f, "Bincode error encountered: {e}"),
AttestationReportError::UnsupportedReportVersion(version) => write!(f, "The encountered Attestation Report version {version} is not supported by the library yet."),
AttestationReportError::UnsupportedField(field) => write!(f,"The field {field} is not supported in the provided Attestation Report version"),
}
}
}

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

impl error::Error for AttestationReportError {}

#[derive(Debug)]
/// Errors which may be encountered when building custom guest context.
pub enum GCTXError {
Expand Down
13 changes: 10 additions & 3 deletions src/firmware/guest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::firmware::{
},
};

use std::convert::TryFrom;
#[cfg(target_os = "linux")]
use std::fs::{File, OpenOptions};

Expand Down Expand Up @@ -107,7 +108,9 @@ impl Firmware {
Err(FirmwareError::from(response.status))?
}

Ok(response.report)
let raw_report = response.report.as_array();

Ok(AttestationReport::try_from(raw_report.as_slice())?)
}

/// Request an extended attestation report from the AMD Secure Processor.
Expand Down Expand Up @@ -179,8 +182,12 @@ impl Firmware {
Err(FirmwareError::from(report_response.status))?
}

let raw_report = report_response.report.as_array();

let report = AttestationReport::try_from(raw_report.as_slice())?;

if ext_report_request.certs_len == 0 {
return Ok((report_response.report, None));
return Ok((report, None));
}

let mut certificates: Vec<CertTableEntry>;
Expand All @@ -194,7 +201,7 @@ impl Firmware {
}

// Return both the Attestation Report, as well as the Cert Table.
Ok((report_response.report, Some(certificates)))
Ok((report, Some(certificates)))
}

/// Fetches a derived key from the AMD Secure Processor. The `message_version` will default to `1` if `None` is specified.
Expand Down
Loading

0 comments on commit 0e42d14

Please sign in to comment.