Skip to content

Commit

Permalink
Added necessary helper functions, made better use of the Launch Diges…
Browse files Browse the repository at this point in the history
…t type, and included GuestPolicy in IdBlock.

Signed-off-by: DGonzalezVillal <Diego.GonzalezVillalobos@amd.com>
  • Loading branch information
DGonzalezVillal committed Jul 23, 2024
1 parent 4cddd41 commit 68584f0
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 80 deletions.
18 changes: 18 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,9 @@ pub enum MeasurementError {
/// Id Block Error Handling
IdBlockError(IdBlockError),

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

/// Invalid VCPU provided
InvalidVcpuTypeError(String),

Expand Down Expand Up @@ -946,6 +949,9 @@ 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}")
}
Expand Down Expand Up @@ -1019,3 +1025,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)
}
}
21 changes: 12 additions & 9 deletions src/measurement/idblock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ 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::{
GuestId, IdAuth, IdBlock, IdMeasurements, SevEcdsaPubKey, SevEcdsaSig, CURVE_P384_NID,
},
snp::LaunchDigest,
},
};

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

/// Generate the sha384 digest of the provided pem key
pub fn generate_key_digest(key_path: PathBuf) -> Result<IdBlockLaunchDigest, IdBlockError> {
pub fn generate_key_digest(key_path: PathBuf) -> Result<LaunchDigest, IdBlockError> {
let ec_key = load_priv_key(key_path)?;

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

Ok(IdBlockLaunchDigest::new(
Ok(LaunchDigest::new(
sha384(
bincode::serialize(&pub_key)
.map_err(|e| IdBlockError::BincodeError(*e))?
Expand All @@ -118,11 +121,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>,
family_id: Option<FamilyId>,
image_id: Option<ImageId>,
ld: Option<LaunchDigest>,
family_id: Option<GuestId>,
image_id: Option<GuestId>,
svn: Option<u32>,
policy: Option<u64>,
policy: Option<GuestPolicy>,
id_key_file: PathBuf,
auth_key_file: PathBuf,
) -> Result<IdMeasurements, IdBlockError> {
Expand Down
73 changes: 23 additions & 50 deletions src/measurement/idblock_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ use openssl::{
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};

use crate::{error::IdBlockError, measurement::large_array::LargeArray};
use crate::{
error::IdBlockError,
firmware::guest::GuestPolicy,
measurement::{large_array::LargeArray, snp::LaunchDigest},
};

pub(crate) const DEFAULT_ID_VERSION: u32 = 1;
pub(crate) const DEFAULT_ID_POLICY: u64 = 0x30000;
Expand All @@ -23,9 +27,6 @@ pub(crate) const CURVE_P384_NID: Nid = openssl::nid::Nid::SECP384R1;
pub(crate) const DEFAULT_KEY_ALGO: u32 = 1;
pub(crate) const CURVE_P384: u32 = 2;

pub(crate) const ID_BLK_DIGEST_BITS: usize = 384;
pub(crate) const ID_BLK_DIGEST_BYTES: usize = ID_BLK_DIGEST_BITS / 8;

pub(crate) const ID_BLK_ID_BITS: usize = 128;
pub(crate) const ID_BLK_ID_BYTES: usize = ID_BLK_ID_BITS / 8;

Expand All @@ -39,46 +40,18 @@ pub(crate) const ECDSA_POINT_SIZE_BYTES: usize = ECDSA_POINT_SIZE_BITS / 8;
pub(crate) const ECDSA_PUBKEY_RESERVED: usize = 0x403 - 0x94 + 1;
pub(crate) const ECDSA_SIG_RESERVED: usize = 0x1ff - 0x90 + 1;

/// The expected launch digest of the guest
/// Family-Id or Image-Id of the guest, provided by the guest owner and uninterpreted by the firmware.
#[repr(C)]
#[derive(Default, Serialize, Deserialize, Clone, Copy)]
pub struct IdBlockLaunchDigest(LargeArray<u8, ID_BLK_DIGEST_BYTES>);
pub struct GuestId([u8; ID_BLK_ID_BYTES]);

impl TryFrom<&[u8]> for IdBlockLaunchDigest {
type Error = IdBlockError;

fn try_from(bytes: &[u8]) -> Result<Self, IdBlockError> {
Ok(IdBlockLaunchDigest(bytes.try_into()?))
}
}

impl TryInto<Vec<u8>> for IdBlockLaunchDigest {
type Error = &'static str;

fn try_into(self) -> Result<Vec<u8>, Self::Error> {
let array = self.0.as_array();
let vec: Vec<u8> = array.to_vec(); // Convert the array into a Vec<u8>
Ok(vec)
}
}

impl IdBlockLaunchDigest {
/// Create Launch Digest from large array
pub fn new(data: LargeArray<u8, ID_BLK_DIGEST_BYTES>) -> Self {
impl GuestId {
/// Create either a Family Id or an Image Id with the provided data
pub fn new(data: [u8; ID_BLK_ID_BYTES]) -> Self {
Self(data)
}
}

/// Family ID of the guest, provided by the guest owner and uninterpreted by the firmware.
#[repr(C)]
#[derive(Default, Serialize, Deserialize, Clone, Copy)]
pub struct FamilyId([u8; ID_BLK_ID_BYTES]);

/// Image ID to be provided to the ID-BLOCK
#[repr(C)]
#[derive(Default, Serialize, Deserialize, Clone, Copy)]
pub struct ImageId([u8; ID_BLK_ID_BYTES]);

/// The way the ECDSA SEV signature is strucutred. Need it in this format to calculate the AUTH-ID.
#[repr(C)]
#[derive(Default, Serialize, Deserialize, Clone, Copy)]
Expand Down Expand Up @@ -213,17 +186,17 @@ impl TryFrom<&EcKey<Private>> for SevEcdsaPubKey {
#[derive(Serialize, Deserialize, Clone, Copy)]
pub struct IdBlock {
/// The expected launch digest of the guest (aka measurement)
pub launch_digest: IdBlockLaunchDigest,
pub launch_digest: LaunchDigest,
/// Family ID of the guest, provided by the guest owner and uninterpreted by the firmware.
pub family_id: FamilyId,
pub family_id: GuestId,
/// Image ID of the guest, provided by the guest owner and uninterpreted by the firmware.
pub image_id: ImageId,
pub image_id: GuestId,
/// Version of the ID block format
pub version: u32,
/// SVN of the guest.
pub guest_svn: u32,
///The policy of the guest.
pub policy: u64,
pub policy: GuestPolicy,
}

impl Default for IdBlock {
Expand All @@ -234,19 +207,19 @@ impl Default for IdBlock {
image_id: Default::default(),
version: DEFAULT_ID_VERSION,
guest_svn: Default::default(),
policy: DEFAULT_ID_POLICY,
policy: GuestPolicy(DEFAULT_ID_POLICY),
}
}
}

impl IdBlock {
/// Function to create a new ID-BLOCK with provided parameters.
/// Create a new ID-BLOCK with provided parameters.
pub fn new(
ld: Option<IdBlockLaunchDigest>,
family_id: Option<FamilyId>,
image_id: Option<ImageId>,
ld: Option<LaunchDigest>,
family_id: Option<GuestId>,
image_id: Option<GuestId>,
svn: Option<u32>,
policy: Option<u64>,
policy: Option<GuestPolicy>,
) -> Result<Self, IdBlockError> {
let mut id_block = IdBlock::default();

Expand Down Expand Up @@ -348,14 +321,14 @@ impl Default for IdAuth {
}

#[derive(Default)]
/// All the measurments that can be used for pre-attestation
/// All the calculated pieces needed for ID verfication
pub struct IdMeasurements {
/// ID-BLOCK
pub id_block: IdBlock,
/// ID-AUTH-BLOCK
pub id_auth: IdAuth,
/// ID-KEY DIGEST
pub id_key_digest: IdBlockLaunchDigest,
pub id_key_digest: LaunchDigest,
/// AUTH-KEY DIGEST
pub auth_key_digest: IdBlockLaunchDigest,
pub auth_key_digest: LaunchDigest,
}
46 changes: 42 additions & 4 deletions src/measurement/snp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@

//! Operations to calculate guest measurement for different SEV modes
use crate::{
error::*,
launch::snp::PageType,
measurement::{
gctx::{Gctx, Updating, VMSA_GPA},
large_array::LargeArray,
ovmf::{OvmfSevMetadataSectionDesc, SectionType, OVMF},
sev_hashes::SevHashes,
vcpu_types::CpuType,
vmsa::{VMMType, VMSA},
},
};
use hex::FromHex;
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
use std::path::PathBuf;

use crate::error::*;

use super::{gctx::LD_SIZE, vmsa::GuestFeatures};

const _PAGE_MASK: u64 = 0xfff;
Expand Down Expand Up @@ -128,6 +130,42 @@ pub fn calc_snp_ovmf_hash(ovmf_file: PathBuf) -> Result<[u8; LD_SIZE], Measureme
Ok(*gctx.ld())
}

/// Launch Digest sizes
pub(crate) const LD_BITS: usize = 384;
pub(crate) const LD_BYTES: usize = LD_BITS / 8;

/// The expected launch digest of the guest
#[repr(C)]
#[derive(Debug, Default, Serialize, Deserialize, Clone, Copy)]
pub struct LaunchDigest(LargeArray<u8, LD_BYTES>);

// Try from slice
impl TryFrom<&[u8]> for LaunchDigest {
type Error = MeasurementError;

fn try_from(bytes: &[u8]) -> Result<Self, MeasurementError> {
Ok(LaunchDigest(bytes.try_into()?))
}
}

/// Vecotrize Launch Digest
impl TryInto<Vec<u8>> for LaunchDigest {
type Error = &'static str;

fn try_into(self) -> Result<Vec<u8>, Self::Error> {
let array = self.0.as_array();
let vec: Vec<u8> = array.to_vec(); // Convert the array into a Vec<u8>
Ok(vec)
}
}

impl LaunchDigest {
/// Create Launch Digest from large array
pub fn new(data: LargeArray<u8, LD_BYTES>) -> Self {
Self(data)
}
}

/// Arguments required to calculate the SNP measurement
pub struct SnpMeasurementArgs<'a> {
/// Number of vcpus
Expand All @@ -153,7 +191,7 @@ pub struct SnpMeasurementArgs<'a> {
/// Calulate an SEV-SNP launch digest
pub fn snp_calc_launch_digest(
snp_measurement: SnpMeasurementArgs,
) -> Result<[u8; LD_SIZE], MeasurementError> {
) -> Result<LaunchDigest, MeasurementError> {
let ovmf = OVMF::new(snp_measurement.ovmf_file)?;

let mut gctx: Gctx<Updating> = match snp_measurement.ovmf_hash_str {
Expand Down Expand Up @@ -200,5 +238,5 @@ pub fn snp_calc_launch_digest(

let gctx = gctx.finished();

Ok(*gctx.ld())
gctx.ld().as_slice().try_into()
}
6 changes: 3 additions & 3 deletions tests/id-block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use hex::{self, FromHex};

use sev::measurement::{
idblock::{load_priv_key, snp_calculate_id},
idblock_types::{IdAuth, IdBlockLaunchDigest, SevEcdsaPubKey, SevEcdsaSig},
idblock_types::{IdAuth, SevEcdsaPubKey, SevEcdsaSig},
snp::LaunchDigest,
};

// Testing that the appropriate id-block and key digests are being generated.
Expand All @@ -29,8 +30,7 @@ fn test_id_block_and_key_digests() {

// Pre-generated launch digest
let launch_digest = Vec::from_hex("a14d638341e5674628fe1e02fbedebe5e5ab4faf1dd72d8966068e615bb99efd13d214b35c231715b38e263dc6059745").unwrap();
let id_launch_digest: IdBlockLaunchDigest =
IdBlockLaunchDigest::new(launch_digest.try_into().unwrap());
let id_launch_digest: LaunchDigest = LaunchDigest::new(launch_digest.try_into().unwrap());

// Generating ID-block and key digests
let block_calculations = snp_calculate_id(
Expand Down
Loading

0 comments on commit 68584f0

Please sign in to comment.