Skip to content

Commit

Permalink
Merge pull request #139 from DGonzalezVillal/id-block
Browse files Browse the repository at this point in the history
Adding functions and types to calculate AUTH and ID blocks
  • Loading branch information
larrydewey authored Feb 22, 2024
2 parents f017cdd + 9d2e130 commit 2e391a8
Show file tree
Hide file tree
Showing 17 changed files with 1,158 additions and 47 deletions.
7 changes: 7 additions & 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 @@ -67,6 +67,7 @@ rsa = { version = "0.9.2", optional = true }
sha2 = { version = "0.10.8", optional = true }
x509-cert = { version = "0.2.4", optional = true }
byteorder = "1.4.3"
base64 = "0.21.5"

[dev-dependencies]
kvm-ioctls = ">=0.12"
Expand Down
102 changes: 102 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,104 @@ impl std::fmt::Display for SevHashError {

impl std::error::Error for SevHashError {}

/// Possible errors when working with the large array type
#[derive(Debug)]
pub enum LargeArrayError {
/// Error when trying from slice
SliceError(TryFromSliceError),

/// Error when converting from vector
VectorError(String),
}

impl std::fmt::Display for LargeArrayError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
LargeArrayError::SliceError(error) => {
write!(f, "Error when trying from slice: {error}")
}
LargeArrayError::VectorError(error) => {
write!(f, "Error when trying from vector: {error}")
}
}
}
}

impl std::error::Error for LargeArrayError {}

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

/// Errors when calculating the ID BLOCK
#[derive(Debug)]
pub enum IdBlockError {
#[cfg(all(feature = "snp", feature = "openssl"))]
/// TryFrom Slice Error handling
CryptoErrorStack(openssl::error::ErrorStack),

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

/// File Error Handling
FileError(std::io::Error),

/// Bincode Error Handling
BincodeError(bincode::ErrorKind),

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

/// Error when handling SEV ECDSA Signature
SevEcsdsaSigError(String),
}

impl std::fmt::Display for IdBlockError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
#[cfg(all(feature = "snp", feature = "openssl"))]
IdBlockError::CryptoErrorStack(e) => write!(f, "Error when with OPENSSL: {e}"),
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::SevCurveError() => {
write!(f, "Wrong curve used in the provided private key")
}
IdBlockError::SevEcsdsaSigError(msg) => {
write!(f, "Error validation SEV signature: {msg}")
}
}
}
}

impl std::error::Error for IdBlockError {}

#[cfg(all(feature = "snp", feature = "openssl"))]
impl std::convert::From<openssl::error::ErrorStack> for IdBlockError {
fn from(value: openssl::error::ErrorStack) -> Self {
Self::CryptoErrorStack(value)
}
}

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

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

/// Errors which may be encountered when calculating the guest measurement.
#[derive(Debug)]
pub enum MeasurementError {
Expand Down Expand Up @@ -767,6 +865,9 @@ pub enum MeasurementError {
/// SEV Hash Error Handling
SevHashError(SevHashError),

/// Id Block Error Handling
IdBlockError(IdBlockError),

/// Invalid VCPU provided
InvalidVcpuTypeError(String),

Expand Down Expand Up @@ -794,6 +895,7 @@ impl std::fmt::Display for MeasurementError {
MeasurementError::GCTXError(e) => write!(f, "GCTX Error Encountered: {e}"),
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::InvalidVcpuTypeError(value) => {
write!(f, "Invalid VCPU type value provided: {value}")
}
Expand Down
139 changes: 139 additions & 0 deletions src/measurement/idblock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: Apache-2.0

//! Functions to use to calculate the ID-BLOCK and the AUTH-BLOCK.
use bincode;
use openssl::{ec::EcKey, pkey::Private, sha::sha384};
use std::{
convert::{TryFrom, TryInto},
fs::File,
io::Read,
path::PathBuf,
};

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

/// Generate an AUTH-BLOCK using 2 EC P-384 keys and an already calculated ID-BlOCK
pub fn gen_id_auth_block(
id_block: &IdBlock,
id_key_file: PathBuf,
author_key_file: PathBuf,
) -> Result<IdAuth, IdBlockError> {
let id_ec_priv_key = load_priv_key(id_key_file)?;
let id_ec_pub_key = SevEcdsaPubKey::try_from(&id_ec_priv_key)?;
let id_sig = SevEcdsaSig::try_from((
id_ec_priv_key,
bincode::serialize(id_block)
.map_err(|e| IdBlockError::BincodeError(*e))?
.as_slice(),
))?;

let author_ec_priv_key = load_priv_key(author_key_file)?;
let author_pub_key = SevEcdsaPubKey::try_from(&author_ec_priv_key)?;
let author_sig = SevEcdsaSig::try_from((
author_ec_priv_key,
bincode::serialize(&id_ec_pub_key)
.map_err(|e| IdBlockError::BincodeError(*e))?
.as_slice(),
))?;

Ok(IdAuth::new(
None,
None,
id_sig,
id_ec_pub_key,
author_sig,
author_pub_key,
))
}

enum KeyFormat {
Pem,
Der,
}

/// Identifies the format of a key based upon the first twenty-seven
/// bytes of a byte stream. A non-PEM format assumes DER format.
fn identify_priv_key_format(bytes: &[u8]) -> KeyFormat {
const PEM_START: &[u8] = b"-----BEGIN PRIVATE KEY-----";
match &bytes[0..27] {
PEM_START => KeyFormat::Pem,
_ => KeyFormat::Der,
}
}
///Read a key file and return a private EcKey.
/// Key has to be an EC P-384 key.
pub fn load_priv_key(path: PathBuf) -> Result<EcKey<Private>, IdBlockError> {
let mut key_data = Vec::new();
let mut file = match File::open(path) {
Ok(file) => file,
Err(e) => return Err(IdBlockError::FileError(e)),
};

file.read_to_end(&mut key_data)
.map_err(IdBlockError::FileError)?;

let pkey = match identify_priv_key_format(&key_data) {
KeyFormat::Pem => {
EcKey::private_key_from_pem(&key_data).map_err(IdBlockError::CryptoErrorStack)?
}
KeyFormat::Der => {
EcKey::private_key_from_der(&key_data).map_err(IdBlockError::CryptoErrorStack)?
}
};

pkey.check_key().map_err(IdBlockError::CryptoErrorStack)?;

if let Some(name) = pkey.group().curve_name() {
if name != CURVE_P384_NID {
return Err(IdBlockError::SevCurveError());
};
};

Ok(pkey)
}

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

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

Ok(IdBlockLaunchDigest::new(
sha384(
bincode::serialize(&pub_key)
.map_err(|e| IdBlockError::BincodeError(*e))?
.as_slice(),
)
.try_into()?,
))
}

/// 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>,
svn: Option<u32>,
policy: Option<u64>,
id_key_file: PathBuf,
auth_key_file: PathBuf,
) -> Result<IdMeasurements, IdBlockError> {
let id_block = IdBlock::new(ld, family_id, image_id, svn, policy)?;

Ok(IdMeasurements {
id_block,
id_auth: gen_id_auth_block(&id_block, id_key_file.clone(), auth_key_file.clone())?,

id_key_digest: generate_key_digest(id_key_file)?,

auth_key_digest: generate_key_digest(auth_key_file)?,
})
}
Loading

0 comments on commit 2e391a8

Please sign in to comment.