diff --git a/src/measurement/sev_hashes.rs b/src/measurement/sev_hashes.rs index 1dd2f75b..ba9820f8 100644 --- a/src/measurement/sev_hashes.rs +++ b/src/measurement/sev_hashes.rs @@ -18,7 +18,8 @@ use uuid::{uuid, Uuid}; use crate::error::*; use crate::BINCODE_CFG; -type Sha256Hash = [u8; 32]; +/// Alias for a 256-bit hash represented as a fixed-size array of 32 bytes. +pub type Sha256Hash = [u8; 32]; /// GUID stored as little endian #[derive(Debug, Clone, Copy, Serialize, Default, Encode)] @@ -182,6 +183,15 @@ impl SevHashes { }) } + /// Generate hashes from the user provided kernel, initrd, and cmdline hashes. + pub fn new_raw(kernel_hash: Sha256Hash, initrd_hash: Sha256Hash, cmdline_hash: Sha256Hash) -> Self { + Self { + kernel_hash, + initrd_hash, + cmdline_hash, + } + } + /// Generate the SEV hashes area - this must be *identical* to the way QEMU /// generates this info in order for the measurement to match. pub fn construct_table(&self) -> Result, MeasurementError> { diff --git a/src/measurement/snp.rs b/src/measurement/snp.rs index c85b9c41..011dab4d 100644 --- a/src/measurement/snp.rs +++ b/src/measurement/snp.rs @@ -7,7 +7,7 @@ use crate::{ measurement::{ gctx::{Gctx, Updating, VMSA_GPA}, ovmf::{OvmfSevMetadataSectionDesc, SectionType, OVMF}, - sev_hashes::SevHashes, + sev_hashes::{SevHashes, Sha256Hash}, vcpu_types::CpuType, vmsa::{GuestFeatures, VMMType, VMSA}, }, @@ -237,3 +237,75 @@ pub fn snp_calc_launch_digest( Ok(gctx.ld()) } + +/// Arguments required to calculate the SNP measurement +pub struct SnpMeasurementWithHashesArgs<'a> { + /// Number of vcpus + pub vcpus: u32, + /// vcpu type + pub vcpu_type: CpuType, + /// Path to OVMF file + pub ovmf_file: PathBuf, + /// Active kernel guest features + pub guest_features: GuestFeatures, + /// Kernel hash + pub kernel_hash: Sha256Hash, + /// Initrd hash + pub initrd_hash: Sha256Hash, + /// Append arguments hash for kernel + pub append_hash: Sha256Hash, + /// Already calculated OVMF hash + pub ovmf_hash_str: Option<&'a str>, + /// vmm type + pub vmm_type: Option, +} + +/// Calulate an SEV-SNP launch digest +pub fn snp_calc_launch_digest_with_hashes( + snp_measurement: SnpMeasurementWithHashesArgs, +) -> Result { + let ovmf = OVMF::new(snp_measurement.ovmf_file)?; + + let mut gctx: Gctx = match snp_measurement.ovmf_hash_str { + Some(hash) => { + let ovmf_hash = Vec::from_hex(hash)?; + Gctx::new(ovmf_hash.as_slice())? + } + None => { + let mut gctx = Gctx::default(); + + gctx.update_page(PageType::Normal, ovmf.gpa(), Some(ovmf.data()), None)?; + + gctx + } + }; + + let sev_hashes = SevHashes::new_raw( + snp_measurement.kernel_hash, + snp_measurement.initrd_hash, + snp_measurement.append_hash + ); + + let official_vmm_type = match snp_measurement.vmm_type { + Some(vmm) => vmm, + None => VMMType::QEMU, + }; + + snp_update_metadata_pages(&mut gctx, &ovmf, Some(&sev_hashes), official_vmm_type)?; + + let vmsa = VMSA::new( + ovmf.sev_es_reset_eip()?.into(), + snp_measurement.vcpu_type, + official_vmm_type, + Some(snp_measurement.vcpus as u64), + snp_measurement.guest_features, + ); + + for vmsa_page in vmsa.pages(snp_measurement.vcpus as usize)?.iter() { + gctx.update_page(PageType::Vmsa, VMSA_GPA, Some(vmsa_page.as_slice()), None)? + } + + let gctx = gctx.finished(); + + Ok(gctx.ld()) +}