From e59ddcc8cf2a67bf43b154e4beb33aa4b3b5e8df Mon Sep 17 00:00:00 2001 From: Leonardo Milleri Date: Wed, 21 Jan 2026 14:37:35 +0000 Subject: [PATCH 1/3] Fix azure-snp-vtpm Signed-off-by: Leonardo Milleri --- deps/verifier/src/az_snp_vtpm/mod.rs | 75 +++++++++++++++++----------- 1 file changed, 46 insertions(+), 29 deletions(-) diff --git a/deps/verifier/src/az_snp_vtpm/mod.rs b/deps/verifier/src/az_snp_vtpm/mod.rs index ab26c537d9..47c178b21f 100644 --- a/deps/verifier/src/az_snp_vtpm/mod.rs +++ b/deps/verifier/src/az_snp_vtpm/mod.rs @@ -8,6 +8,7 @@ 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 async_trait::async_trait; @@ -29,10 +30,6 @@ 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, @@ -40,14 +37,12 @@ struct Evidence { 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")] @@ -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 { - 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 {}) } } @@ -137,13 +120,47 @@ 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 + 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 { + bail!( + "{}. Tried: {}", + CertError::NoMatchingProcessorGeneration, + validation_errors.join("; ") + ); + } verify_snp_report(&snp_report, &vcek)?; From d613643459d8433d9bf9ea729da02135296e5b88 Mon Sep 17 00:00:00 2001 From: Leonardo Milleri Date: Thu, 22 Jan 2026 09:29:42 +0000 Subject: [PATCH 2/3] Add more logs Signed-off-by: Leonardo Milleri --- attestation-service/src/lib.rs | 8 +++++++- deps/verifier/src/intel_dcap/claims.rs | 2 +- rvps/src/lib.rs | 2 ++ rvps/src/storage/local_json/mod.rs | 3 +++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/attestation-service/src/lib.rs b/attestation-service/src/lib.rs index a4d1256b3a..b49a7450ba 100644 --- a/attestation-service/src/lib.rs +++ b/attestation-service/src/lib.rs @@ -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, @@ -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 diff --git a/deps/verifier/src/intel_dcap/claims.rs b/deps/verifier/src/intel_dcap/claims.rs index 1ccc251ed9..afdd892fbd 100644 --- a/deps/verifier/src/intel_dcap/claims.rs +++ b/deps/verifier/src/intel_dcap/claims.rs @@ -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(); diff --git a/rvps/src/lib.rs b/rvps/src/lib.rs index 35e9480eb2..aca8aa5c50 100644 --- a/rvps/src/lib.rs +++ b/rvps/src/lib.rs @@ -90,8 +90,10 @@ impl Rvps { } pub async fn get_digests(&self) -> Result> { + 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() { diff --git a/rvps/src/storage/local_json/mod.rs b/rvps/src/storage/local_json/mod.rs index 9fd686b014..83b85c7a69 100644 --- a/rvps/src/storage/local_json/mod.rs +++ b/rvps/src/storage/local_json/mod.rs @@ -84,8 +84,11 @@ impl ReferenceValueStorage for LocalJson { } async fn get_values(&self) -> Result> { + 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 = serde_json::from_slice(&file)?; Ok(rvs) } From 49564250c2df4a0740fa324d19a2d6560d27c3f1 Mon Sep 17 00:00:00 2001 From: Leonardo Milleri Date: Wed, 18 Feb 2026 15:46:45 +0000 Subject: [PATCH 3/3] Fix thread pool exhaustion in azure-snp-vtpm verifier The azure-snp-vtpm verifier was running CPU-intensive certificate validation in async context, causing thread pool exhaustion. When all worker threads got blocked doing crypto validation, async file reads in RVPS would hang indefinitely, causing attestation requests to retry in a loop. Wrapped the blocking cryptographic operations (ca_chain.validate() and vcek.validate()) in tokio::task::spawn_blocking() to move them off the async runtime thread pool. Signed-off-by: Leonardo Milleri --- deps/verifier/src/az_snp_vtpm/mod.rs | 80 +++++++++++++++------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/deps/verifier/src/az_snp_vtpm/mod.rs b/deps/verifier/src/az_snp_vtpm/mod.rs index 47c178b21f..4f69703654 100644 --- a/deps/verifier/src/az_snp_vtpm/mod.rs +++ b/deps/verifier/src/az_snp_vtpm/mod.rs @@ -10,7 +10,7 @@ use crate::snp::{ }; 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}; @@ -121,46 +121,54 @@ impl Verifier for AzSnpVtpm { let vcek = Vcek::from_pem(&evidence.vcek)?; // Try to validate VCEK against all known processor generations - 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; - } + // 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!("VCEK validation failed for {}: {}", proc_gen, e); - validation_errors.push(format!("{}: {}", proc_gen, e)); + log::debug!("CA chain validation failed for {}: {}", proc_gen, e); + validation_errors.push(format!("{} CA chain: {}", 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 { - bail!( - "{}. Tried: {}", - CertError::NoMatchingProcessorGeneration, - validation_errors.join("; ") - ); - } + 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)?;