Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion attestation-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ impl AttestationService {
verification_request.tee
);

debug!("Processing {} claims from verifier", claims.len());
for (claims_from_tee_evidence, tee_class) in claims {
tee_claims.push(TeeClaims {
tee: verification_request.tee,
Expand All @@ -228,13 +229,18 @@ impl AttestationService {
runtime_data_claims: runtime_data_claims.clone(),
});
}
debug!("Finished processing claims. Total tee_claims: {}", tee_claims.len());
}

debug!("Finished processing all verification requests. About to call rvps.get_digests()");
let reference_data_map = self
.rvps
.get_digests()
.await
.map_err(|e| anyhow!("Generate reference data failed: {:?}", e))?;
.map_err(|e| {
debug!("rvps.get_digests() failed: {:?}", e);
anyhow!("Generate reference data failed: {:?}", e)
})?;
debug!("reference_data_map: {:#?}", reference_data_map);

let attestation_results_token = self
Expand Down
85 changes: 55 additions & 30 deletions deps/verifier/src/az_snp_vtpm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ use crate::snp::{
get_common_name, get_oid_int, get_oid_octets, ProcessorGeneration, CERT_CHAINS, HW_ID_OID,
LOADER_SPL_OID, SNP_SPL_OID, TEE_SPL_OID, UCODE_SPL_OID,
};
use strum::IntoEnumIterator;
use crate::{InitDataHash, ReportData};
use anyhow::{bail, Context, Result};
use anyhow::{anyhow, bail, Context, Result};
use async_trait::async_trait;
use az_snp_vtpm::certs::{AmdChain, Vcek};
use az_snp_vtpm::hcl::{HclReport, SNP_REPORT_SIZE};
Expand All @@ -29,25 +30,19 @@ const HCL_VMPL_VALUE: u32 = 0;
const INITDATA_PCR: usize = 8;
const SNP_REPORT_SIGNATURE_OFFSET: usize = 0x2a0; // 672 bytes

struct AzVendorCertificates {
ca_chain: AmdChain,
}

#[derive(Serialize, Deserialize)]
struct Evidence {
quote: Quote,
report: Vec<u8>,
vcek: String,
}

pub struct AzSnpVtpm {
vendor_certs: AzVendorCertificates,
}
pub struct AzSnpVtpm {}

#[derive(Error, Debug)]
pub enum CertError {
#[error("Failed to load Milan cert chain")]
LoadMilanCert,
#[error("Failed to validate VCEK against any known processor generation (Milan, Genoa, Turin)")]
NoMatchingProcessorGeneration,
#[error("TPM quote nonce doesn't match expected report_data")]
NonceMismatch,
#[error("SNP report report_data mismatch")]
Expand All @@ -62,21 +57,9 @@ pub enum CertError {
Anyhow(#[from] anyhow::Error),
}

// Azure vTPM still initialized to Milan only certs until az_snp_vtpm crate gets updated.
impl AzSnpVtpm {
pub fn new() -> Result<Self, CertError> {
let vendor_certs = CERT_CHAINS
.get(&ProcessorGeneration::Milan)
.ok_or(CertError::LoadMilanCert)?
.clone();
Ok(Self {
vendor_certs: AzVendorCertificates {
ca_chain: AmdChain {
ask: vendor_certs.ask.into(),
ark: vendor_certs.ark.into(),
},
},
})
Ok(Self {})
}
}

Expand Down Expand Up @@ -137,13 +120,55 @@ impl Verifier for AzSnpVtpm {

let vcek = Vcek::from_pem(&evidence.vcek)?;

//Verify certificates
self.vendor_certs
.ca_chain
.validate()
.context("Failed to validate CA chain")?;
vcek.validate(&self.vendor_certs.ca_chain)
.context("Failed to validate VCEK")?;
// Try to validate VCEK against all known processor generations
// Wrap in spawn_blocking since certificate validation is CPU-intensive
let vcek = tokio::task::spawn_blocking(move || {
let mut validation_errors = Vec::new();
let mut validated = false;

for proc_gen in ProcessorGeneration::iter() {
let Some(vendor_certs) = CERT_CHAINS.get(&proc_gen) else {
continue;
};

let ca_chain = AmdChain {
ask: vendor_certs.ask.clone().into(),
ark: vendor_certs.ark.clone().into(),
};

// Try to validate with this processor generation
match ca_chain.validate() {
Ok(_) => match vcek.validate(&ca_chain) {
Ok(_) => {
log::info!("Successfully validated VCEK against {} processor certificates", proc_gen);
validated = true;
break;
}
Err(e) => {
log::debug!("VCEK validation failed for {}: {}", proc_gen, e);
validation_errors.push(format!("{}: {}", proc_gen, e));
}
},
Err(e) => {
log::debug!("CA chain validation failed for {}: {}", proc_gen, e);
validation_errors.push(format!("{} CA chain: {}", proc_gen, e));
}
}
}

if validated {
Ok(vcek)
} else {
Err(format!(
"{}. Tried: {}",
CertError::NoMatchingProcessorGeneration,
validation_errors.join("; ")
))
}
})
.await
.context("VCEK validation task panicked")?
.map_err(|e| anyhow!(e))?;

verify_snp_report(&snp_report, &vcek)?;

Expand Down
2 changes: 1 addition & 1 deletion deps/verifier/src/intel_dcap/claims.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ pub(crate) fn prepare_custom_claims_map(
claims_map
}

fn get_sa_list(sa_list: &[c_char; 320]) -> Value {
fn get_sa_list(sa_list: &[c_char; 450]) -> Value {
let c_str = unsafe { CStr::from_ptr(sa_list.as_ptr()) };

let advisory_ids = c_str.to_string_lossy();
Expand Down
2 changes: 2 additions & 0 deletions rvps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,10 @@ impl Rvps {
}

pub async fn get_digests(&self) -> Result<HashMap<String, Value>> {
log::debug!("Rvps::get_digests() - about to call storage.get_values()");
let mut rv_map = HashMap::new();
let reference_values = self.storage.get_values().await?;
log::debug!("Rvps::get_digests() - got {} values", reference_values.len());

for rv in reference_values {
if rv.expired() {
Expand Down
3 changes: 3 additions & 0 deletions rvps/src/storage/local_json/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,11 @@ impl ReferenceValueStorage for LocalJson {
}

async fn get_values(&self) -> Result<Vec<ReferenceValue>> {
log::debug!("LocalJson::get_values() - entering, file_path={}", self.file_path);
let _ = self.lock.read().await;
log::debug!("LocalJson::get_values() - lock acquired, about to read file");
let file = tokio::fs::read(&self.file_path).await?;
log::debug!("LocalJson::get_values() - file read, {} bytes", file.len());
let rvs: Vec<ReferenceValue> = serde_json::from_slice(&file)?;
Ok(rvs)
}
Expand Down