Skip to content

Commit

Permalink
fix: trait implementations, rename error, remove dup Error
Browse files Browse the repository at this point in the history
  • Loading branch information
bredamatt committed Feb 6, 2025
1 parent 8e6477f commit cd5ff4a
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 16 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ atoma-sui = { path = "./atoma-sui" }
atoma-utils = { path = "./atoma-utils" }
axum = "0.7.5"
base64 = "0.22.1"
bincode = "1.3.3"
blake2 = "0.10.6"
clap = "4.5.4"
config = "0.14.0"
Expand Down
1 change: 1 addition & 0 deletions atoma-confidential/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ aes-gcm = { workspace = true }
anyhow = { workspace = true }
atoma-sui = { workspace = true }
atoma-utils = { workspace = true }
bincode = { workspace = true }
blake2 = { workspace = true }
dcap-rs = { workspace = true, optional = true }
flume = { workspace = true }
Expand Down
57 changes: 41 additions & 16 deletions atoma-confidential/src/sev_snp.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use bincode::{serialize, deserialize};

use crate::ToBytes;

use sev::{
attestation::{AttestationReport, AttestationReportSignature, Chain},
error::SevError,
firmware::Firmware,
};

use thiserror::Error;

pub const SEV_SNP_REPORT_DATA_SIZE: usize = 64;

type Result<T> = std::result::Result<T, SevError>;
type Result<T> = std::result::Result<T, SnpError>;

/// Generates an SEV-SNP attestation report for the given compute data.
///
Expand All @@ -20,18 +21,18 @@ type Result<T> = std::result::Result<T, SevError>;
///
/// # Arguments
///
/// * `attested_data` - A slice of bytes containing the data to be attested (public key)
/// * `attested_data` - A slice of bytes containing the data to be attested for (public key)
///
/// # Returns
///
/// * `Result<AttestationReport>` - On success, returns an AttestationReport.
/// On failure, returns a SevError.
/// On failure, returns a SnpError.
///
/// # Errors
///
/// Returns `SevError::InvalidAttestedDataSize` if the input data size is not 64 bytes.
/// Returns `SevError::FailedToOpenFirmware` if the firmware interface cannot be opened.
/// Returns `SevError::FailedToGetAttestationReport` if the attestation report cannot be generated.
/// Returns `SnpError::InvalidAttestedDataSize` if the input data size is not 64 bytes.
/// Returns `SnpError::FailedToOpenFirmware` if the firmware interface cannot be opened.
/// Returns `SnpError::FailedToGetAttestationReport` if the attestation report cannot be generated.
///
/// # Example
///
Expand All @@ -45,10 +46,11 @@ type Result<T> = std::result::Result<T, SevError>;
#[cfg(all(target_os="linux", feature="sev-snp"))]
pub fn get_compute_data_attestation(attested_data: &[u8]) -> Result<SNPAttestationReport> {
if attested_data.len() != SEV_SNP_REPORT_DATA_SIZE {
return Err(SevError::InvalidAttestedDataSize(attested_data.len()));
return Err(SnpError::InvalidAttestedDataSize(attested_data.len()));
}

let mut firmware = Firmware::open().map_err(SevError::FailedToOpenFirmware)?;
// Open the SEV-SNP firmware interface
let mut firmware = Firmware::open().map_err(SnpError::FailedToOpenFirmware)?;

// Message version is set as a protocol version indicator, default is 1.
let message_version = 1;
Expand All @@ -59,10 +61,10 @@ pub fn get_compute_data_attestation(attested_data: &[u8]) -> Result<SNPAttestati
// See: https://docs.enclaive.cloud/confidential-cloud/technology-in-depth/amd-sev/technology/fundamentals/features/virtual-machine-privilege-levels
let vmpl = 0;

// Ask the PSP to generate an extended attestation report for the given data as the proxy will need to verify the report.
// Ask the PSP to generate an extended attestation report for the given data (the atoma-proxy will need to verify the report) to store key-rotation event on-chain.
let (chain, report): (Chain, AttestationReport) = firmware
.get_ext_report(Some(message_version), Some(attested_data), Some(vmpl))
.map_err(SevError::FailedToGetAttestationReport)?;
.map_err(SnpError::FailedToGetAttestationReport)?;

let snp_attestation_report = (chain, report).to_snp_attestation_report();

Expand All @@ -78,6 +80,25 @@ pub struct SNPAttestationReport {
pub report: AttestationReport,
}

impl ToBytes for SNPAttestationReport {
fn to_bytes(&self) -> Vec<u8> {
bincode::serialize(&self).unwrap()
}
}

/// Trait for converting Vec<u8> to an SNPAttestationReport.
pub trait FromBytes {
fn from_bytes(bytes: Vec<u8>) -> Result<Self, SnpError>;
}

impl FromBytes for SNPAttestationReport {
fn from_bytes(bytes: Vec<u8>) -> Result<Self, SnpError> {
bincode::deserialize(&bytes).map_err(|e| {
SnpError::FailedToDeserializeBytes(format!("Unable to deserialize bytes for SNPAttestationReport: {}", e))
})
}
}

/// Trait for converting a tuple of (Chain, AttestationReport) to an SNPAttestationReport.
pub trait ToSNPAttestationReport {
fn to_snp_attestation_report(&self) -> SNPAttestationReport;
Expand All @@ -99,7 +120,7 @@ impl sev::snp::certs::Verifiable for SNPAttestationReport {

/// Verifies the attestation report against the VCEK certificate.
/// Taken from: https://docs.rs/sev/5.0.0/src/sev/firmware/guest/types/snp.rs.html#351-391
fn verify(&self) -> Result<(), SevError> {
fn verify(&self) -> Result<(), SnpError> {
// According to Chapter 3 of the [Versioned Chip Endorsement Key (VCEK) Certificate and
// KDS Interface Specification][spec], the VCEK certificate certifies an ECDSA public key on curve P-384,
// and the signature hash algorithm is sha384.
Expand All @@ -109,26 +130,26 @@ impl sev::snp::certs::Verifiable for SNPAttestationReport {
let sig = p384::ecdsa::Signature::try_from(&self.1.signature)?;

let measurable_bytes: &[u8] = &bincode::serialize(self.1).map_err(|e| {
SevError::FailedVerification(format!("Unable to serialize bytes: {}", e))
SnpError::FailedVerification(format!("Unable to serialize bytes for AttestationReport: {}", e))
})?[..0x2a0];

use sha2::Digest;
let base_digest = sha2::Sha384::new_with_prefix(measurable_bytes);

let verifying_key = p384::ecdsa::VerifyingKey::from_sec1_bytes(vcek.public_key_sec1())
.map_err(|e| {
SevError::FailedVerification(format!("failed to deserialize public key from sec1 bytes: {e:?}"))
SnpError::FailedVerification(format!("Failed to deserialize public key from sec1 bytes: {e:?}"))
})?;

use p384::ecdsa::signature::DigestVerifier;
verifying_key.verify_digest(base_digest, &sig).map_err(|e| {
SevError::FailedVerification(format!("VCEK does not sign the attestation report: {e:?}"))
SnpError::FailedVerification(format!("VCEK does not sign the attestation report: {e:?}"))
})
}
}

#[derive(Error, Debug)]
pub enum SevError {
pub enum SnpError {
#[error("Invalid attested data size: expected {expected}, got {actual}", expected = SEV_SNP_REPORT_DATA_SIZE, actual = _0)]
InvalidAttestedDataSize(usize),
#[error("Failed to verify attestation report: {0}")]
Expand All @@ -137,6 +158,10 @@ pub enum SevError {
FailedToOpenFirmware(#[source] std::io::Error),
#[error("Failed to get attestation report: {0}")]
FailedToGetAttestationReport(#[source] std::io::Error),
#[error("Failed to serialize bytes for SNPAttestationReport: {0}")]
FailedToSerializeBytes(#[source] std::io::Error),
#[error("Failed to deserialize bytes for SNPAttestationReport: {0}")]
FailedToDeserializeBytes(#[source] std::io::Error),
#[error("SEV-SNP attestation is only supported on Linux platforms")]
UnsupportedPlatform,
}

0 comments on commit cd5ff4a

Please sign in to comment.