From 79a0b65dd61aaac3812f3c7cd6d8360668d6951d Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Fri, 5 Jun 2026 22:28:33 +0800 Subject: [PATCH 1/9] fix(attestation): include Azure vTPM AK intermediates Fetch Azure vTPM AK issuer certificates from the leaf certificate's AIA CA Issuers URLs during attestation generation and serialize them into the Azure evidence document. During verification, treat evidence-supplied intermediates as untrusted chain material, combine them with the legacy bundled intermediate for backwards compatibility, and continue pinning Azure vTPM roots. Bound the number of serialized intermediates during deserialization and keep stripping TPM NV zero padding before WebPKI verification. Add offline AK-chain fixtures for the observed Azure Cloud Virtual TPM CA - 24 -> Azure Cloud Virtual TPM CA 2025 chain. --- .../attestation/src/azure/ak_certificate.rs | 138 +++++++++++++++++- crates/attestation/src/azure/mod.rs | 70 +++++++-- .../test-assets/azure-ak-leaf-westus3.pem | 88 +++++++++++ .../azure-cloud-virtual-tpm-ca-2025.pem | 38 +++++ .../azure-cloud-virtual-tpm-ca-24.pem | 50 +++++++ 5 files changed, 371 insertions(+), 13 deletions(-) create mode 100644 crates/attestation/test-assets/azure-ak-leaf-westus3.pem create mode 100644 crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-2025.pem create mode 100644 crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-24.pem diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index cc2264e..ae637e6 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -1,9 +1,10 @@ //! Generation and verification of AK certificates from the vTPM -use std::time::Duration; +use std::{io::Read, time::Duration}; use once_cell::sync::Lazy; use tokio_rustls::rustls::pki_types::{CertificateDer, TrustAnchor, UnixTime}; use webpki::EndEntityCert; +use x509_parser::{extensions::GeneralName, prelude::*}; use crate::azure::{MaaError, nv_index}; @@ -30,8 +31,13 @@ const AZURE_VIRTUAL_TPM_ROOT_2023: &str = // Valid: 2025-04-24 to 2027-04-24 const GLOBAL_VIRTUAL_TPMCA03_PEM: &str = include_str!("../../assets/global-virtual-tpm-ca-03.pem"); -/// The intermediate chain for azure -static GLOBAL_VIRTUAL_TPMCA03: Lazy>> = Lazy::new(|| { +/// Azure intermediate certificates bundled with this crate. +/// +/// This is kept only for backwards compatibility with older evidence that +/// did not serialize AIA-fetched intermediates. New Azure vTPM evidence +/// should carry the AK issuer chain fetched from AIA instead of relying on +/// this bundled, eventually-stale list. +static BUNDLED_AZURE_INTERMEDIATES: Lazy>> = Lazy::new(|| { let (_type_label, cert_der) = pem_rfc7468::decode_vec(GLOBAL_VIRTUAL_TPMCA03_PEM.as_bytes()).expect("Cannot decode PEM"); vec![CertificateDer::from(cert_der)] @@ -50,17 +56,21 @@ static AZURE_ROOT_ANCHORS: Lazy>> = Lazy::new(|| { /// Verify an AK certificate against azure root CA pub(crate) fn verify_ak_cert_with_azure_roots( ak_cert_der: &[u8], + intermediate_cert_ders: &[Vec], now_secs: u64, ) -> Result<(), MaaError> { let ak_cert_der: CertificateDer = ak_cert_der.into(); let end_entity_cert = EndEntityCert::try_from(&ak_cert_der)?; + let mut intermediates = BUNDLED_AZURE_INTERMEDIATES.clone(); + intermediates.extend(intermediate_cert_ders.iter().cloned().map(CertificateDer::from)); + let now = UnixTime::since_unix_epoch(Duration::from_secs(now_secs)); end_entity_cert.verify_for_usage( webpki::ALL_VERIFICATION_ALGS, &AZURE_ROOT_ANCHORS, - &GLOBAL_VIRTUAL_TPMCA03, + &intermediates, now, AnyEku, None, @@ -71,6 +81,47 @@ pub(crate) fn verify_ak_cert_with_azure_roots( Ok(()) } +/// Fetch intermediate certificates from the Authority Information Access +/// (AIA) CA Issuers URLs in the leaf and each fetched intermediate. +/// +/// Azure vTPM AK intermediate CAs rotate and the public Trusted Launch FAQ +/// can lag behind the certificates observed in production. Microsoft +/// guidance is to build the chain from the CA Issuers URLs embedded in the +/// AK certificate's AIA extension; see: +/// https://learn.microsoft.com/en-us/answers/questions/5897616/download-intermediate-ca-cert-for-azure-cloud-virt +/// +/// The fetched certificates are untrusted evidence. Verification still pins +/// the Azure vTPM root in `verify_ak_cert_with_azure_roots`. +pub(crate) fn fetch_ak_intermediates_from_aia( + ak_cert: &X509Certificate<'_>, +) -> Result>, MaaError> { + const MAX_AIA_DEPTH: usize = 6; + + let mut intermediates = Vec::new(); + let mut issuer_url = first_ca_issuers_url(ak_cert); + + for _ in 0..MAX_AIA_DEPTH { + let Some(url) = issuer_url else { + break; + }; + + tracing::debug!("Fetching Azure vTPM AK issuer certificate from {url}"); + let issuer_der = fetch_certificate_der(&url)?; + let (_, issuer_cert) = X509Certificate::from_der(&issuer_der)?; + + // Stop before adding the self-signed root. The root is already pinned + // in AZURE_ROOT_ANCHORS and should not come from untrusted evidence. + if issuer_cert.subject() == issuer_cert.issuer() { + break; + } + + issuer_url = first_ca_issuers_url(&issuer_cert); + intermediates.push(issuer_der); + } + + Ok(intermediates) +} + /// Retrieve an AK certificate from the vTPM pub(crate) fn read_ak_certificate_from_tpm() -> Result, tss_esapi::Error> { tracing::debug!("Reading AK certificate from vTPM"); @@ -78,6 +129,47 @@ pub(crate) fn read_ak_certificate_from_tpm() -> Result, tss_esapi::Error nv_index::read_nv_index(&mut context, TPM_AK_CERT_IDX) } +fn first_ca_issuers_url(cert: &X509Certificate<'_>) -> Option { + cert.extensions().iter().find_map(|extension| { + let ParsedExtension::AuthorityInfoAccess(aia) = extension.parsed_extension() else { + return None; + }; + + aia.iter().find_map(|desc| { + if desc.access_method.to_id_string() != "1.3.6.1.5.5.7.48.2" { + return None; + } + + let GeneralName::URI(uri) = &desc.access_location else { + return None; + }; + + Some((*uri).to_string()) + }) + }) +} + +fn fetch_certificate_der(url: &str) -> Result, MaaError> { + if !(url.starts_with("http://") || url.starts_with("https://")) { + return Err(MaaError::UnsupportedAiaUrl { url: url.to_string() }); + } + + let response = ureq::get(url) + .timeout(Duration::from_secs(10)) + .call() + .map_err(|err| MaaError::AiaFetch { url: url.to_string(), source: err })?; + + let mut bytes = Vec::new(); + response.into_reader().take(1024 * 1024).read_to_end(&mut bytes)?; + + if bytes.starts_with(b"-----BEGIN") { + let (_type_label, der) = pem_rfc7468::decode_vec(&bytes)?; + Ok(der) + } else { + Ok(bytes) + } +} + /// Convert a PEM-encoded cert into a TrustAnchor fn pem_to_trust_anchor(pem: &str) -> TrustAnchor<'static> { let (_type_label, der_vec) = pem_rfc7468::decode_vec(pem.as_bytes()).unwrap(); @@ -99,6 +191,44 @@ impl webpki::ExtendedKeyUsageValidator for AnyEku { } } +#[cfg(test)] +#[test] +fn azure_ak_fixture_has_expected_aia_issuer_url() { + let (_type_label, ak_der) = pem_rfc7468::decode_vec( + include_bytes!("../../test-assets/azure-ak-leaf-westus3.pem").as_slice(), + ) + .unwrap(); + let (_, cert) = X509Certificate::from_der(&ak_der).unwrap(); + + assert_eq!( + first_ca_issuers_url(&cert).as_deref(), + Some( + "http://primary-cdn.pki.core.windows.net/westus3/cacerts/azurevtpmicapki/azurevtpmicausw3/cert.cer" + ) + ); +} + +#[cfg(test)] +#[test] +fn verifies_azure_ak_fixture_with_fixture_intermediates() { + let (_type_label, ak_der) = pem_rfc7468::decode_vec( + include_bytes!("../../test-assets/azure-ak-leaf-westus3.pem").as_slice(), + ) + .unwrap(); + let intermediates = [ + include_bytes!("../../test-assets/azure-cloud-virtual-tpm-ca-24.pem").as_slice(), + include_bytes!("../../test-assets/azure-cloud-virtual-tpm-ca-2025.pem").as_slice(), + ] + .into_iter() + .map(|pem| pem_rfc7468::decode_vec(pem).unwrap().1) + .collect::>(); + + // Fixed timestamp within the leaf and intermediate validity windows, so + // this offline fixture test does not expire when wall-clock time advances. + let june_5_2026 = 1_780_617_600; + verify_ak_cert_with_azure_roots(&ak_der, &intermediates, june_5_2026).unwrap(); +} + #[cfg(test)] #[tokio::test] async fn root_should_be_fresh() { diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 45d4e4c..d7ce46b 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -3,7 +3,9 @@ mod ak_certificate; mod nv_index; use std::time::Duration; -use ak_certificate::{read_ak_certificate_from_tpm, verify_ak_cert_with_azure_roots}; +use ak_certificate::{ + fetch_ak_intermediates_from_aia, read_ak_certificate_from_tpm, verify_ak_cert_with_azure_roots, +}; use az_tdx_vtpm::{hcl, imds, vtpm}; use base64::{Engine as _, engine::general_purpose::URL_SAFE as BASE64_URL_SAFE}; use dcap_qvl::QuoteCollateralV3; @@ -17,8 +19,7 @@ use x509_parser::prelude::*; use crate::{ dcap::{ - verify_dcap_attestation_with_given_timestamp, - verify_dcap_attestation_with_timestamp_sync, + verify_dcap_attestation_with_given_timestamp, verify_dcap_attestation_with_timestamp_sync, }, measurements::MultiMeasurements, }; @@ -42,6 +43,11 @@ struct AttestationDocument { struct TpmAttest { /// Attestation Key certificate from vTPM ak_certificate_pem: String, + /// Intermediate CA certificates fetched from the AK leaf certificate's + /// AIA CA Issuers URLs. These are untrusted evidence; verification + /// pins the Azure vTPM root CA. + #[serde(default, deserialize_with = "deserialize_ak_intermediate_certificates_pem")] + ak_intermediate_certificates_pem: Vec, /// vTPM quote quote: vtpm::Quote, /// Raw TCG event log bytes (UEFI + IMA) [currently not used] @@ -54,6 +60,29 @@ struct TpmAttest { instance_info: Option>, } +/// Maximum number of evidence-supplied AK intermediate certificates +/// accepted during verification. Azure chains currently observed use 2 +/// intermediates; this allows some rotation/cross-signing headroom while +/// bounding peer-controlled evidence. +const MAX_AK_INTERMEDIATE_CERTIFICATES: usize = 4; + +fn deserialize_ak_intermediate_certificates_pem<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let certificates = Vec::::deserialize(deserializer)?; + if certificates.len() > MAX_AK_INTERMEDIATE_CERTIFICATES { + return Err(serde::de::Error::custom(format_args!( + "too many AK intermediate certificates in evidence: {} > {}", + certificates.len(), + MAX_AK_INTERMEDIATE_CERTIFICATES + ))); + } + Ok(certificates) +} + /// Used during verification to support both sync and async verification /// paths without duplicating code struct PreparedAzureAttestation { @@ -77,13 +106,23 @@ pub fn create_azure_attestation(input_data: [u8; 64]) -> Result, MaaErro let td_quote_bytes = imds::get_td_quote(&td_report_from_hcl)?; let ak_certificate_der = read_ak_certificate_from_tpm()?; + let (remaining_bytes, ak_leaf_certificate) = X509Certificate::from_der(&ak_certificate_der)?; + let leaf_len = ak_certificate_der.len() - remaining_bytes.len(); + let ak_leaf_certificate_der = &ak_certificate_der[..leaf_len]; + let ak_intermediate_certificates_der = fetch_ak_intermediates_from_aia(&ak_leaf_certificate)?; let tpm_attestation = TpmAttest { ak_certificate_pem: pem_rfc7468::encode_string( "CERTIFICATE", pem_rfc7468::LineEnding::default(), - &ak_certificate_der, + ak_leaf_certificate_der, )?, + ak_intermediate_certificates_pem: ak_intermediate_certificates_der + .iter() + .map(|der| { + pem_rfc7468::encode_string("CERTIFICATE", pem_rfc7468::LineEnding::default(), der) + }) + .collect::, _>>()?, quote: vtpm::get_quote(&input_data[..32])?, event_log: Vec::new(), instance_info: None, @@ -296,8 +335,15 @@ fn finish_azure_attestation_verification( // Parse AK certificate let (_type_label, ak_certificate_der) = pem_rfc7468::decode_vec(tpm_attestation.ak_certificate_pem.as_bytes())?; + let ak_intermediate_certificate_ders = tpm_attestation + .ak_intermediate_certificates_pem + .iter() + .map(|pem| pem_rfc7468::decode_vec(pem.as_bytes()).map(|(_type_label, der)| der)) + .collect::, _>>()?; let (remaining_bytes, ak_certificate) = X509Certificate::from_der(&ak_certificate_der)?; + let leaf_len = ak_certificate_der.len() - remaining_bytes.len(); + let ak_leaf_certificate_der = &ak_certificate_der[..leaf_len]; // Check that AK public key matches that from TPM quote and HCL claims let ak_from_certificate = RsaPubKey::from_certificate(&ak_certificate)?; @@ -309,12 +355,12 @@ fn finish_azure_attestation_verification( return Err(MaaError::AkFromClaimsNotEqualAkFromCertificate); } - // Strip trailing data from AK certificate - let leaf_len = ak_certificate_der.len() - remaining_bytes.len(); - let ak_certificate_der_without_trailing_data = &ak_certificate_der[..leaf_len]; - // Verify the AK certificate against microsoft root cert - verify_ak_cert_with_azure_roots(ak_certificate_der_without_trailing_data, now)?; + verify_ak_cert_with_azure_roots( + ak_leaf_certificate_der, + &ak_intermediate_certificate_ders, + now, + )?; Ok(MultiMeasurements::from_pcrs(pcrs)) } @@ -452,6 +498,12 @@ pub enum MaaError { Json(#[from] serde_json::Error), #[error("HTTP client: {0}")] Reqwest(#[from] reqwest::Error), + #[error("AIA URL is not HTTP(S): {url}")] + UnsupportedAiaUrl { url: String }, + #[error("Failed to fetch AIA issuer certificate from {url}: {source}")] + AiaFetch { url: String, source: ureq::Error }, + #[error("IO: {0}")] + Io(#[from] std::io::Error), #[error("vTPM quote: {0}")] VtpmQuote(#[from] vtpm::QuoteError), #[error("AK public key: {0}")] diff --git a/crates/attestation/test-assets/azure-ak-leaf-westus3.pem b/crates/attestation/test-assets/azure-ak-leaf-westus3.pem new file mode 100644 index 0000000..2521228 --- /dev/null +++ b/crates/attestation/test-assets/azure-ak-leaf-westus3.pem @@ -0,0 +1,88 @@ +-----BEGIN CERTIFICATE----- +MIIGSDCCBDCgAwIBAgIRAMWpePCJCtDYocQgBibR+eMwDQYJKoZIhvcNAQENBQAw +KjEoMCYGA1UEAxMfQXp1cmUgQ2xvdWQgVmlydHVhbCBUUE0gQ0EgLSAyNDAeFw0y +NjA2MDQwMDAwMDBaFw0yNzA2MDMwMDAwMDBaMDgxNjA0BgNVBAMTLTk5MjE2OTRi +ZDM0Mi5Db25maWRlbnRpYWxWTS5BenVyZS53aW5kb3dzLm5ldDCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANdGVyQAAEvbQQ5BsnYyEazDkqx30wMhgBw2 +Dg2GijvnOF2i/EdHhz8em5Xs2oZ3L+VMI+Edh7HpVsgrWwhKGV3LE0LbYANxgPqY +hPPKB5+WaMklX5aeXHkSUqGMEl/eKO0TAvJkCuLxtSrvVyUCZzQIDZ5/mJJVRv/D +kIEiIkLAvrJg6SoH/+MUb4CMBkMyz3vQTreRH2EmZG3+9kO7Pimc8cbntvILAXSe ++bw3EWkRuLjkFAa7eeqe7jUR5IqdAOy+zfiB2dklFTmL5v+49tj56+yBcWFFA8cI +YtBjEzeyLPHBSSYwaxgZgOtOgWM8kwR7B8eLN13EMDCdT6AntQMCAwEAAaOCAlkw +ggJVMBgGA1UdIAQRMA8wDQYLKwYBBAGCN2yBSAIwDAYDVR0TAQH/BAIwADAcBgNV +HSUEFTATBgorBgEEAYI3CgMMBgVngQUIAzAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0O +BBYEFKlL0CakAru/SLwTZP44cqbA53+GMB8GA1UdIwQYMBaAFENsulav0M/GpLkV +lVnXYEXzSDJaMIIBuwYIKwYBBQUHAQEEggGtMIIBqTBtBggrBgEFBQcwAoZhaHR0 +cDovL3ByaW1hcnktY2RuLnBraS5jb3JlLndpbmRvd3MubmV0L3dlc3R1czMvY2Fj +ZXJ0cy9henVyZXZ0cG1pY2Fwa2kvYXp1cmV2dHBtaWNhdXN3My9jZXJ0LmNlcjBv +BggrBgEFBQcwAoZjaHR0cDovL3NlY29uZGFyeS1jZG4ucGtpLmNvcmUud2luZG93 +cy5uZXQvd2VzdHVzMy9jYWNlcnRzL2F6dXJldnRwbWljYXBraS9henVyZXZ0cG1p +Y2F1c3czL2NlcnQuY2VyMF4GCCsGAQUFBzAChlJodHRwOi8vY3JsLm1pY3Jvc29m +dC5jb20vd2VzdHVzMy9jYWNlcnRzL2F6dXJldnRwbWljYXBraS9henVyZXZ0cG1p +Y2F1c3czL2NlcnQuY2VyMGcGCCsGAQUFBzAChltodHRwOi8vYXp1cmV2dHBtaWNh +cGtpLndlc3R1czMucGtpLmNvcmUud2luZG93cy5uZXQvY2VydGlmaWNhdGVBdXRo +b3JpdGllcy9henVyZXZ0cG1pY2F1c3czMA0GCSqGSIb3DQEBDQUAA4ICAQA3Oenp +LqPeFIZ59il6nJ6rfGAaVtDm8qoVKybQ6K/LlGMd9KsA1vMJoe9aadOpN5b5DAna +PiM7dnB24+XKP4l8z8FYzjP4hmUjL4dKc8u8rB5b7Cn8uc//wIPWzwilOOrIITo8 +U/qIdyPhOqxBqxYPShtw77fjNiDTEivTD0lrbG9J7tp2NIREFTGt7FBZL32ZhuPq +x1eaDhGG+96b9jqtJGn+bYEaWtLyjbE2zu+S5oWU531C9rPbvtU4GP5xgRfFRw3Q +ZfzzLaGK5diVEhoIhfgu3N2Vk3qg5FHNFhUzzvkec85SEaeXFt8q9jNnCp2qkwUM +T55W2DNd+TjVA2QzAcgXldM64oLqRtkSxrrPO7PvixHQj7EQlTpdGyN239trCw3v +bWZzB0R0wuwCW1S6LDtzWVhQaD59NtV+G6tdELtZZLw14X+IHaHqvisGpq+Yik59 +ZTu+vWJnjPGP5Ps7aqlq//Pbtlir4Yv50KYirVeFuoBfI+dq20HdXHrqivvQ/zJG +fiMHysGuWo5CdpUpm/HEvuZA4/3rgpXYZTlXLWoQUmyfZMzbw+GOaJ0WHrrQCi03 +1jyWZM9biXwG+0Gm5TJCRG0ZfPQcUKvN8ilN4VtTseojnV27OEQBXzWSlWLrjv7Q +abM8e9Z9usVtV/4hvm/c2M6VWbkBRUwAYNqtlwAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAA== +-----END CERTIFICATE----- diff --git a/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-2025.pem b/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-2025.pem new file mode 100644 index 0000000..a24fea9 --- /dev/null +++ b/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-2025.pem @@ -0,0 +1,38 @@ +-----BEGIN CERTIFICATE----- +MIIGqjCCBJKgAwIBAgITMwAAAA3hTgyMJlm7XAAAAAAADTANBgkqhkiG9w0BAQwF +ADBpMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u +MTowOAYDVQQDEzFBenVyZSBWaXJ0dWFsIFRQTSBSb290IENlcnRpZmljYXRlIEF1 +dGhvcml0eSAyMDIzMB4XDTI1MDgwNjIxMDIwMloXDTMxMDgwNTIxMDIwMlowKjEo +MCYGA1UEAxMfQXp1cmUgQ2xvdWQgVmlydHVhbCBUUE0gQ0EgMjAyNTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAIa4QCuPJi5ehBDiXG6HYkmy17bgAtrQ +mK/+Ik9MHnmZoRw+Th08dgXZRNZf5A73WCC78r9O1hLqdiOIGf19Ejf8UxU6cRXj +UPpkn1Gfru8G/Rn488R2sJ/OJIncTKbJFVUNEt6HhABXRz/I6xlYLpXoU0HcgfB4 +Cw+8h/jQsXqnVXWrMmjQJ6+DgJR2Yk32zi75NY5Z6j3L0he+nO9P/uZ6ZSLOn/Lj +ftoPVs26Ay6Q/h7bJ7wtcC06k8qHxplimiWrEtNU7A74PaUGWZfgFXeOrUZXSURb +YxqbCTW6isbvS2D7IkNq/OasRVEUY3gNXFu3g8d08JCmvSY6P1peJQN0yvbFx43L +/nfY7CXRhF/sEViTcjkV1/Asa+PUT7yjzE6hf512yfUJtlBU7HXfK1n7sK2BT1xG +ds9N+jpBSXXq7dqWr2OsfmNMDF3wttnjD31OOjxmyq1yR4BuPxhJYH/AHnQQIA+/ +tIcdLgtEKISXzSwcMvKt0X5olzTKFREeEWH/x+i1zPuu4bxUY7Fd0z0PvealExtv +mT8MJ3iFhHRReJolnG8a00DUfyj++dEaSQtgf4liGQZLgBK7g4AesL3vKPgRVNP9 +ex4WEuLULIW78QiG0bOwoswc2pMePWlNVDEVju56VwB2+Y+qNQIO29ySuTf7W9NB +adXUAmuJEykrAgMBAAGjggGIMIIBhDALBgNVHQ8EBAMCAYYwIwYDVR0lBBwwGgYK +KwYBBAGCNwoDDAYFZ4EFCAEGBWeBBQgDMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYD +VR0OBBYEFBxqlvcz0egLZjNmB55lFH2P/rA8MB8GA1UdIwQYMBaAFEv+JlqUwfYz +w4NIJt3z5bBksqqVMHYGA1UdHwRvMG0wa6BpoGeGZWh0dHA6Ly93d3cubWljcm9z +b2Z0LmNvbS9wa2lvcHMvY3JsL0F6dXJlJTIwVmlydHVhbCUyMFRQTSUyMFJvb3Ql +MjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMjMuY3JsMIGDBggrBgEFBQcB +AQR3MHUwcwYIKwYBBQUHMAKGZ2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv +cHMvY2VydHMvQXp1cmUlMjBWaXJ0dWFsJTIwVFBNJTIwUm9vdCUyMENlcnRpZmlj +YXRlJTIwQXV0aG9yaXR5JTIwMjAyMy5jcnQwDQYJKoZIhvcNAQEMBQADggIBADv8 +FY5P/MusECLp6meis4Ujpce/2mq9bEBnSTV/qjTv1i59StJbqCD1uUXTPddeOnFl +jkFai5y09zMka+aJnhhS8PIHhbgFSI4SKCjdC1CVZOQoPTTM/q3/SfJoZ2Zn/PGH +2z+CxFsj7p2CNs843+swiUc+klA+X2hVy4HKEplh5HQmGPK6I3PBT/4P0PqBpqeB +2ylTEMvuhSYtDnTYTGOUCUpnEYeY/THBMLsHVL0+I/Ti5irNaRwurpP3bIPzZd3G +SO+EjQfOq/lGj3f7ipbLdwovIMVtbYuThlRK9AjsiS/mwGIZeuIiRy8T2KUqxkq/ +4Kt6i8gcIAKBgAx0/5BMbLf24KJHjtv7NN/0RissF6qOPa1ivk/rQwfr/FCilND5 +qvnHAgnHPSBKeo6cNQ1YjGl5KAQZuXxl2HWR/Pnv5ukUiBzdkozB+npXaTVQHmTx +NUIRTErbYuCYW+HASCxnhZMYcLha7lM/X6Q5NMEOgz3dPA8mkxGCInZfjYZ2JlDb +Rx9ks9aRqFpoxHuyBxas3Fycuyz77YFE6rr+p7uAQ3o+dZqbO0RatvsNUpO6aTH6 +lUl8xyTwGMw2WV3ATxAaUCtVOAA8xVpJo9Z19PSfepho+g6VKku7eXHPqGR/p9++ +MIy/GuVREnFXQXQt5Ut3pYlREPiZ/k+57avJoQhv +-----END CERTIFICATE----- diff --git a/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-24.pem b/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-24.pem new file mode 100644 index 0000000..625b63a --- /dev/null +++ b/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-24.pem @@ -0,0 +1,50 @@ +-----BEGIN CERTIFICATE----- +MIII6zCCBtOgAwIBAgIRAOy12jSrvPCNMaArM9L/ceIwDQYJKoZIhvcNAQENBQAw +KjEoMCYGA1UEAxMfQXp1cmUgQ2xvdWQgVmlydHVhbCBUUE0gQ0EgMjAyNTAeFw0y +NjAzMTEwMDAwMDBaFw0yOTAzMTAwMDAwMDBaMCoxKDAmBgNVBAMTH0F6dXJlIENs +b3VkIFZpcnR1YWwgVFBNIENBIC0gMjQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQCldZHSm3EVhrg4dBhW+P1fQzPX09vbzYsVvcXe31pLFhlokdJeJAC+ +axrPpZYP8V1DY9m0vPxrj6dm52vzoNErt6zuSRH4lNeQGWkZB6FLagyJwpDSDZ3B +sM6Y54Uwxi6YOG4yCkVjKY2CTvLbGxODEYv1U2NjM/CIQvqob49JBM64Qq/6gWFI +raNbJwA70ILysJwYjVB6YP4NNPuAlITNQyXZRp6k/nKCYPqxqhz/AUSbrJgH0t0T +l5v9zHo7awKV3S5bsdyxcCKTqm2IPittWrfvOF9KEs3ZRMeJPV+0DXp2e4vjKmee +9VFH9AmuHxYOa4MDa+617SxBrIPD/eE7OmdvPoSL3tgcVAtWAotykNWoVBgFdYlz +7M0WuQbZE23jhteP2rMZT5tVYr+hcWrTzzZ2GfNwiGLsilr6uL8YDm7TNE0twZIG +TtZaXJYzgaFFUMA8HpceedLD7ddS1uMUilhPHTmJXpWzRr/MdxrkU1xqo8/lvl2j +zC3EMOVPP8AhMrADMQizYzNJXLOJB24nouw0MTcaHc/VhAyW2ia/6ObYk3vpSOBN +GLmnDEoME23neYLsnOtAMvPciaBQ4pMojnuh2A8iVBKsaLasnVpwhkveBTaupknP +YzH/y9xuAFfxa1VUwouR5IofcstfMg10lWwVJRrW89bKBHZKYvSEPwIDAQABo4IE +CjCCBAYwEgYDVR0TAQH/BAgwBgEB/wIBADAjBgNVHSUEHDAaBgorBgEEAYI3CgMM +BgVngQUIAQYFZ4EFCAMwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBRDbLpWr9DP +xqS5FZVZ12BF80gyWjAfBgNVHSMEGDAWgBQcapb3M9HoC2YzZgeeZRR9j/6wPDCC +AbIGA1UdHwSCAakwggGlMGmgZ6BlhmNodHRwOi8vcHJpbWFyeS1jZG4ucGtpLmNv +cmUud2luZG93cy5uZXQvZWFzdHVzMi9jcmxzL2F6dXJldnRwbXBraS9henVyZXZ0 +cG1wb2xpY3ljYWV1czIvY3VycmVudC5jcmwwa6BpoGeGZWh0dHA6Ly9zZWNvbmRh +cnktY2RuLnBraS5jb3JlLndpbmRvd3MubmV0L2Vhc3R1czIvY3Jscy9henVyZXZ0 +cG1wa2kvYXp1cmV2dHBtcG9saWN5Y2FldXMyL2N1cnJlbnQuY3JsMFqgWKBWhlRo +dHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vZWFzdHVzMi9jcmxzL2F6dXJldnRwbXBr +aS9henVyZXZ0cG1wb2xpY3ljYWV1czIvY3VycmVudC5jcmwwb6BtoGuGaWh0dHA6 +Ly9henVyZXZ0cG1wa2kuZWFzdHVzMi5wa2kuY29yZS53aW5kb3dzLm5ldC9jZXJ0 +aWZpY2F0ZUF1dGhvcml0aWVzL2F6dXJldnRwbXBvbGljeWNhZXVzMi9jdXJyZW50 +LmNybDCCAcMGCCsGAQUFBwEBBIIBtTCCAbEwbwYIKwYBBQUHMAKGY2h0dHA6Ly9w +cmltYXJ5LWNkbi5wa2kuY29yZS53aW5kb3dzLm5ldC9lYXN0dXMyL2NhY2VydHMv +YXp1cmV2dHBtcGtpL2F6dXJldnRwbXBvbGljeWNhZXVzMi9jZXJ0LmNlcjBxBggr +BgEFBQcwAoZlaHR0cDovL3NlY29uZGFyeS1jZG4ucGtpLmNvcmUud2luZG93cy5u +ZXQvZWFzdHVzMi9jYWNlcnRzL2F6dXJldnRwbXBraS9henVyZXZ0cG1wb2xpY3lj +YWV1czIvY2VydC5jZXIwYAYIKwYBBQUHMAKGVGh0dHA6Ly9jcmwubWljcm9zb2Z0 +LmNvbS9lYXN0dXMyL2NhY2VydHMvYXp1cmV2dHBtcGtpL2F6dXJldnRwbXBvbGlj +eWNhZXVzMi9jZXJ0LmNlcjBpBggrBgEFBQcwAoZdaHR0cDovL2F6dXJldnRwbXBr +aS5lYXN0dXMyLnBraS5jb3JlLndpbmRvd3MubmV0L2NlcnRpZmljYXRlQXV0aG9y +aXRpZXMvYXp1cmV2dHBtcG9saWN5Y2FldXMyMA0GCSqGSIb3DQEBDQUAA4ICAQBZ +y/ScjLcaLqOFMMg/wqHHIuL+upqKnDhpl4joXXszc8xIsxYlzUdxUflcvC/midw3 +kPVRz8hNbXfzawHoIfh9/81u59uMk/NOExLflcd3a99sjfNwELmxTr7+nd8CjJmo +wCJoj/y/8noiDlBFTkKty7ngMooYV0XkisOS65McErEWT0hO0Gvb4FKTH2XAuc+7 +8mQe2J73O9SIkw4QljBg36wkSDT9P3R5cMcLbfeAEsa/n1llrg93x+A5Q8Tqwz6O +DrfiTNisaQQpVzhX+/PmdBpFiGspwTu81RGvo0kj5YhMhVoQ6zBuol21xv7VwLxB +oKVrDN59rQ6gnn6JK0QIvNRk0sYipVQP7wh2J1M39DpF0E0+KkkFg3dzUSSfmM8F +fDsaW227gPBjvXIumPOSlAF6b8G+Or/VFIiQ5Cc8Hi3icYCSc9jOtp4UGVvCAcMU +6Fj1aFUCeh1dtbCMAWDMVM08OF0Wae1YpXUuF7SeHkLNRg+DXcdCGb9FCRyJ8QQN +WQkEAe+fIV2WM5W6OUB+S3S4k3PHK0Rah73nACo0Qeh9hMIlhkMdzIgBqFieSo9m +HNIxnnDWlmpTBsqRHNXZP1qgUX2g1gJmG72qLbAlP2rUW/nl5XfWawjMYQyWszV/ +5cdYaa/HYUQm6edHfFiEmadftomvhfmjm8XnVBy9ng== +-----END CERTIFICATE----- From b4797575f7527860ef24bd18443730c5c22cc6c1 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Mon, 8 Jun 2026 19:52:17 +0800 Subject: [PATCH 2/9] cargo fmt --- crates/attestation/src/azure/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index d7ce46b..60c3c3c 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -4,7 +4,9 @@ mod nv_index; use std::time::Duration; use ak_certificate::{ - fetch_ak_intermediates_from_aia, read_ak_certificate_from_tpm, verify_ak_cert_with_azure_roots, + fetch_ak_intermediates_from_aia, + read_ak_certificate_from_tpm, + verify_ak_cert_with_azure_roots, }; use az_tdx_vtpm::{hcl, imds, vtpm}; use base64::{Engine as _, engine::general_purpose::URL_SAFE as BASE64_URL_SAFE}; @@ -19,7 +21,8 @@ use x509_parser::prelude::*; use crate::{ dcap::{ - verify_dcap_attestation_with_given_timestamp, verify_dcap_attestation_with_timestamp_sync, + verify_dcap_attestation_with_given_timestamp, + verify_dcap_attestation_with_timestamp_sync, }, measurements::MultiMeasurements, }; From 74a78815e94fa5d055e6081a40e865521a5de870 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Mon, 8 Jun 2026 20:30:48 +0800 Subject: [PATCH 3/9] add capture_azure_fixture test util fix output dir for fixtures commit fixtures update test to use new yaml fixtures fix fixture generating code (serde_saphyr bug?) actually fix serializer make fixture match new serialization format --- .../attestation/src/azure/ak_certificate.rs | 38 - crates/attestation/src/azure/mod.rs | 130 ++ .../test-assets/azure-ak-leaf-westus3.pem | 88 -- .../azure-cloud-virtual-tpm-ca-2025.pem | 38 - .../azure-cloud-virtual-tpm-ca-24.pem | 50 - ...eral-with-ak-intermediates-1780922561.yaml | 109 ++ ...-tdx-with-ak-intermediates-1780922561.yaml | 1309 +++++++++++++++++ 7 files changed, 1548 insertions(+), 214 deletions(-) delete mode 100644 crates/attestation/test-assets/azure-ak-leaf-westus3.pem delete mode 100644 crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-2025.pem delete mode 100644 crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-24.pem create mode 100644 crates/attestation/test-assets/azure-collateral-with-ak-intermediates-1780922561.yaml create mode 100644 crates/attestation/test-assets/azure-tdx-with-ak-intermediates-1780922561.yaml diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index ae637e6..049e7e3 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -191,44 +191,6 @@ impl webpki::ExtendedKeyUsageValidator for AnyEku { } } -#[cfg(test)] -#[test] -fn azure_ak_fixture_has_expected_aia_issuer_url() { - let (_type_label, ak_der) = pem_rfc7468::decode_vec( - include_bytes!("../../test-assets/azure-ak-leaf-westus3.pem").as_slice(), - ) - .unwrap(); - let (_, cert) = X509Certificate::from_der(&ak_der).unwrap(); - - assert_eq!( - first_ca_issuers_url(&cert).as_deref(), - Some( - "http://primary-cdn.pki.core.windows.net/westus3/cacerts/azurevtpmicapki/azurevtpmicausw3/cert.cer" - ) - ); -} - -#[cfg(test)] -#[test] -fn verifies_azure_ak_fixture_with_fixture_intermediates() { - let (_type_label, ak_der) = pem_rfc7468::decode_vec( - include_bytes!("../../test-assets/azure-ak-leaf-westus3.pem").as_slice(), - ) - .unwrap(); - let intermediates = [ - include_bytes!("../../test-assets/azure-cloud-virtual-tpm-ca-24.pem").as_slice(), - include_bytes!("../../test-assets/azure-cloud-virtual-tpm-ca-2025.pem").as_slice(), - ] - .into_iter() - .map(|pem| pem_rfc7468::decode_vec(pem).unwrap().1) - .collect::>(); - - // Fixed timestamp within the leaf and intermediate validity windows, so - // this offline fixture test does not expire when wall-clock time advances. - let june_5_2026 = 1_780_617_600; - verify_ak_cert_with_azure_roots(&ak_der, &intermediates, june_5_2026).unwrap(); -} - #[cfg(test)] #[tokio::test] async fn root_should_be_fresh() { diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 60c3c3c..4bf5065 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -561,6 +561,89 @@ pub enum MaaError { AzureMetadataApiNonJsonResponse { content_type: Option }, } +#[cfg(test)] +mod test_utils { + use base64::{Engine as _, engine::general_purpose::URL_SAFE as BASE64_URL_SAFE}; + + use super::{AttestationDocument, create_azure_attestation}; + use crate::dcap::PCS_URL; + + /// Capture a complete Azure TDX attestation fixture from inside an + /// Azure TDX CVM. + /// + /// Run with: + /// + /// ```text + /// cargo test -p attestation --features azure capture_azure_fixture -- --ignored --nocapture + /// ``` + /// + /// This writes two timestamped YAML files: + /// + /// - `azure-tdx-with-ak-intermediates-.yaml` + /// - `azure-collateral-with-ak-intermediates-.yaml` + /// + /// The first file is the full Azure attestation payload, including + /// observed vTPM AK intermediate certificates. The second file is + /// matching Intel DCAP collateral for the TDX quote embedded in + /// that payload, so the fixture can be verified offline by tests. + #[tokio::test] + #[ignore = "requires an Azure TDX CVM with vTPM access"] + async fn capture_azure_fixture() { + let output_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("test-assets"); + std::fs::create_dir_all(&output_dir).unwrap(); + + // Keep this aligned with existing Azure fixture tests, which use zeroed + // report input data. + let attestation_json = create_azure_attestation([0u8; 64]).unwrap(); + let attestation_document: AttestationDocument = + serde_json::from_slice(&attestation_json).unwrap(); + + let intermediate_count = + attestation_document.tpm_attestation.ak_intermediate_certificates_pem.len(); + assert!(intermediate_count > 0, "captured attestation should include AK intermediates"); + + let quote_bytes = BASE64_URL_SAFE.decode(&attestation_document.tdx_quote_base64).unwrap(); + let quote = dcap_qvl::quote::Quote::parse("e_bytes).unwrap(); + let ca = quote.ca().unwrap(); + let fmspc = hex::encode_upper(quote.fmspc().unwrap()); + let collateral = dcap_qvl::collateral::get_collateral_for_fmspc( + PCS_URL, + fmspc.clone(), + ca, + false, // TDX, not SGX. + ) + .await + .unwrap(); + + let timestamp = + std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(); + let attestation_path = + output_dir.join(format!("azure-tdx-with-ak-intermediates-{timestamp}.yaml")); + let collateral_path = + output_dir.join(format!("azure-collateral-with-ak-intermediates-{timestamp}.yaml")); + + let mut serializer_options = serde_saphyr::SerializerOptions::default(); + // With compact list indentation enabled, serde_saphyr can emit an + // indentless empty sequence after a nested block sequence, e.g. + // `event_log:\n[]`, which its parser rejects. Disable compact list + // indentation for fixture output so nested/empty sequences are always + // indented under their mapping keys. + serializer_options.compact_list_indent = false; + std::fs::write( + &attestation_path, + serde_saphyr::to_string_with_options(&attestation_document, serializer_options) + .unwrap(), + ) + .unwrap(); + std::fs::write(&collateral_path, serde_saphyr::to_string(&collateral).unwrap()).unwrap(); + + println!("wrote {}", attestation_path.display()); + println!("wrote {}", collateral_path.display()); + println!("quote fmspc={fmspc} ca={ca}"); + println!("ak_intermediate_certificates_pem entries={intermediate_count}"); + } +} + #[cfg(test)] mod tests { use super::*; @@ -657,6 +740,53 @@ mod tests { measurement_policy.check_measurement(&async_measurements).unwrap(); } + /// Verify a complete observed Azure attestation payload that includes + /// AK intermediates fetched from the leaf certificate's AIA URLs. + #[tokio::test] + async fn test_verify_with_observed_ak_intermediates() { + let attestation_bytes: &'static [u8] = + include_bytes!("../../test-assets/azure-tdx-with-ak-intermediates-1780922561.yaml"); + let collateral_bytes: &'static [u8] = include_bytes!( + "../../test-assets/azure-collateral-with-ak-intermediates-1780922561.yaml" + ); + + // Fixed timestamp within the quote collateral and AK certificate + // validity windows, so this offline fixture test does not expire when + // wall-clock time advances. + let now = 1_780_922_561; + + let attestation_document: AttestationDocument = + serde_saphyr::from_slice(attestation_bytes).unwrap(); + assert_eq!(attestation_document.tpm_attestation.ak_intermediate_certificates_pem.len(), 2); + + let attestation_json = serde_json::to_vec(&attestation_document).unwrap(); + let async_collateral = serde_saphyr::from_slice(collateral_bytes).unwrap(); + let sync_collateral = serde_saphyr::from_slice(collateral_bytes).unwrap(); + + let async_measurements = verify_azure_attestation_with_given_timestamp( + attestation_json.clone(), + [0; 64], + None, + Some(async_collateral), + now, + false, + ) + .await + .unwrap(); + + let sync_measurements = verify_azure_attestation_with_given_timestamp_sync( + attestation_json, + [0; 64], + Pccs::new_without_prewarm(None), + Some(sync_collateral), + now, + false, + ) + .unwrap(); + + assert_eq!(async_measurements, sync_measurements); + } + #[tokio::test] async fn test_verify_fails_on_input_mismatch() { let attestation_bytes: &'static [u8] = diff --git a/crates/attestation/test-assets/azure-ak-leaf-westus3.pem b/crates/attestation/test-assets/azure-ak-leaf-westus3.pem deleted file mode 100644 index 2521228..0000000 --- a/crates/attestation/test-assets/azure-ak-leaf-westus3.pem +++ /dev/null @@ -1,88 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGSDCCBDCgAwIBAgIRAMWpePCJCtDYocQgBibR+eMwDQYJKoZIhvcNAQENBQAw -KjEoMCYGA1UEAxMfQXp1cmUgQ2xvdWQgVmlydHVhbCBUUE0gQ0EgLSAyNDAeFw0y -NjA2MDQwMDAwMDBaFw0yNzA2MDMwMDAwMDBaMDgxNjA0BgNVBAMTLTk5MjE2OTRi -ZDM0Mi5Db25maWRlbnRpYWxWTS5BenVyZS53aW5kb3dzLm5ldDCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANdGVyQAAEvbQQ5BsnYyEazDkqx30wMhgBw2 -Dg2GijvnOF2i/EdHhz8em5Xs2oZ3L+VMI+Edh7HpVsgrWwhKGV3LE0LbYANxgPqY -hPPKB5+WaMklX5aeXHkSUqGMEl/eKO0TAvJkCuLxtSrvVyUCZzQIDZ5/mJJVRv/D -kIEiIkLAvrJg6SoH/+MUb4CMBkMyz3vQTreRH2EmZG3+9kO7Pimc8cbntvILAXSe -+bw3EWkRuLjkFAa7eeqe7jUR5IqdAOy+zfiB2dklFTmL5v+49tj56+yBcWFFA8cI -YtBjEzeyLPHBSSYwaxgZgOtOgWM8kwR7B8eLN13EMDCdT6AntQMCAwEAAaOCAlkw -ggJVMBgGA1UdIAQRMA8wDQYLKwYBBAGCN2yBSAIwDAYDVR0TAQH/BAIwADAcBgNV -HSUEFTATBgorBgEEAYI3CgMMBgVngQUIAzAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0O -BBYEFKlL0CakAru/SLwTZP44cqbA53+GMB8GA1UdIwQYMBaAFENsulav0M/GpLkV -lVnXYEXzSDJaMIIBuwYIKwYBBQUHAQEEggGtMIIBqTBtBggrBgEFBQcwAoZhaHR0 -cDovL3ByaW1hcnktY2RuLnBraS5jb3JlLndpbmRvd3MubmV0L3dlc3R1czMvY2Fj -ZXJ0cy9henVyZXZ0cG1pY2Fwa2kvYXp1cmV2dHBtaWNhdXN3My9jZXJ0LmNlcjBv -BggrBgEFBQcwAoZjaHR0cDovL3NlY29uZGFyeS1jZG4ucGtpLmNvcmUud2luZG93 -cy5uZXQvd2VzdHVzMy9jYWNlcnRzL2F6dXJldnRwbWljYXBraS9henVyZXZ0cG1p -Y2F1c3czL2NlcnQuY2VyMF4GCCsGAQUFBzAChlJodHRwOi8vY3JsLm1pY3Jvc29m -dC5jb20vd2VzdHVzMy9jYWNlcnRzL2F6dXJldnRwbWljYXBraS9henVyZXZ0cG1p -Y2F1c3czL2NlcnQuY2VyMGcGCCsGAQUFBzAChltodHRwOi8vYXp1cmV2dHBtaWNh -cGtpLndlc3R1czMucGtpLmNvcmUud2luZG93cy5uZXQvY2VydGlmaWNhdGVBdXRo -b3JpdGllcy9henVyZXZ0cG1pY2F1c3czMA0GCSqGSIb3DQEBDQUAA4ICAQA3Oenp -LqPeFIZ59il6nJ6rfGAaVtDm8qoVKybQ6K/LlGMd9KsA1vMJoe9aadOpN5b5DAna -PiM7dnB24+XKP4l8z8FYzjP4hmUjL4dKc8u8rB5b7Cn8uc//wIPWzwilOOrIITo8 -U/qIdyPhOqxBqxYPShtw77fjNiDTEivTD0lrbG9J7tp2NIREFTGt7FBZL32ZhuPq -x1eaDhGG+96b9jqtJGn+bYEaWtLyjbE2zu+S5oWU531C9rPbvtU4GP5xgRfFRw3Q -ZfzzLaGK5diVEhoIhfgu3N2Vk3qg5FHNFhUzzvkec85SEaeXFt8q9jNnCp2qkwUM -T55W2DNd+TjVA2QzAcgXldM64oLqRtkSxrrPO7PvixHQj7EQlTpdGyN239trCw3v -bWZzB0R0wuwCW1S6LDtzWVhQaD59NtV+G6tdELtZZLw14X+IHaHqvisGpq+Yik59 -ZTu+vWJnjPGP5Ps7aqlq//Pbtlir4Yv50KYirVeFuoBfI+dq20HdXHrqivvQ/zJG -fiMHysGuWo5CdpUpm/HEvuZA4/3rgpXYZTlXLWoQUmyfZMzbw+GOaJ0WHrrQCi03 -1jyWZM9biXwG+0Gm5TJCRG0ZfPQcUKvN8ilN4VtTseojnV27OEQBXzWSlWLrjv7Q -abM8e9Z9usVtV/4hvm/c2M6VWbkBRUwAYNqtlwAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAA== ------END CERTIFICATE----- diff --git a/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-2025.pem b/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-2025.pem deleted file mode 100644 index a24fea9..0000000 --- a/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-2025.pem +++ /dev/null @@ -1,38 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGqjCCBJKgAwIBAgITMwAAAA3hTgyMJlm7XAAAAAAADTANBgkqhkiG9w0BAQwF -ADBpMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u -MTowOAYDVQQDEzFBenVyZSBWaXJ0dWFsIFRQTSBSb290IENlcnRpZmljYXRlIEF1 -dGhvcml0eSAyMDIzMB4XDTI1MDgwNjIxMDIwMloXDTMxMDgwNTIxMDIwMlowKjEo -MCYGA1UEAxMfQXp1cmUgQ2xvdWQgVmlydHVhbCBUUE0gQ0EgMjAyNTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAIa4QCuPJi5ehBDiXG6HYkmy17bgAtrQ -mK/+Ik9MHnmZoRw+Th08dgXZRNZf5A73WCC78r9O1hLqdiOIGf19Ejf8UxU6cRXj -UPpkn1Gfru8G/Rn488R2sJ/OJIncTKbJFVUNEt6HhABXRz/I6xlYLpXoU0HcgfB4 -Cw+8h/jQsXqnVXWrMmjQJ6+DgJR2Yk32zi75NY5Z6j3L0he+nO9P/uZ6ZSLOn/Lj -ftoPVs26Ay6Q/h7bJ7wtcC06k8qHxplimiWrEtNU7A74PaUGWZfgFXeOrUZXSURb -YxqbCTW6isbvS2D7IkNq/OasRVEUY3gNXFu3g8d08JCmvSY6P1peJQN0yvbFx43L -/nfY7CXRhF/sEViTcjkV1/Asa+PUT7yjzE6hf512yfUJtlBU7HXfK1n7sK2BT1xG -ds9N+jpBSXXq7dqWr2OsfmNMDF3wttnjD31OOjxmyq1yR4BuPxhJYH/AHnQQIA+/ -tIcdLgtEKISXzSwcMvKt0X5olzTKFREeEWH/x+i1zPuu4bxUY7Fd0z0PvealExtv -mT8MJ3iFhHRReJolnG8a00DUfyj++dEaSQtgf4liGQZLgBK7g4AesL3vKPgRVNP9 -ex4WEuLULIW78QiG0bOwoswc2pMePWlNVDEVju56VwB2+Y+qNQIO29ySuTf7W9NB -adXUAmuJEykrAgMBAAGjggGIMIIBhDALBgNVHQ8EBAMCAYYwIwYDVR0lBBwwGgYK -KwYBBAGCNwoDDAYFZ4EFCAEGBWeBBQgDMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYD -VR0OBBYEFBxqlvcz0egLZjNmB55lFH2P/rA8MB8GA1UdIwQYMBaAFEv+JlqUwfYz -w4NIJt3z5bBksqqVMHYGA1UdHwRvMG0wa6BpoGeGZWh0dHA6Ly93d3cubWljcm9z -b2Z0LmNvbS9wa2lvcHMvY3JsL0F6dXJlJTIwVmlydHVhbCUyMFRQTSUyMFJvb3Ql -MjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMjMuY3JsMIGDBggrBgEFBQcB -AQR3MHUwcwYIKwYBBQUHMAKGZ2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv -cHMvY2VydHMvQXp1cmUlMjBWaXJ0dWFsJTIwVFBNJTIwUm9vdCUyMENlcnRpZmlj -YXRlJTIwQXV0aG9yaXR5JTIwMjAyMy5jcnQwDQYJKoZIhvcNAQEMBQADggIBADv8 -FY5P/MusECLp6meis4Ujpce/2mq9bEBnSTV/qjTv1i59StJbqCD1uUXTPddeOnFl -jkFai5y09zMka+aJnhhS8PIHhbgFSI4SKCjdC1CVZOQoPTTM/q3/SfJoZ2Zn/PGH -2z+CxFsj7p2CNs843+swiUc+klA+X2hVy4HKEplh5HQmGPK6I3PBT/4P0PqBpqeB -2ylTEMvuhSYtDnTYTGOUCUpnEYeY/THBMLsHVL0+I/Ti5irNaRwurpP3bIPzZd3G -SO+EjQfOq/lGj3f7ipbLdwovIMVtbYuThlRK9AjsiS/mwGIZeuIiRy8T2KUqxkq/ -4Kt6i8gcIAKBgAx0/5BMbLf24KJHjtv7NN/0RissF6qOPa1ivk/rQwfr/FCilND5 -qvnHAgnHPSBKeo6cNQ1YjGl5KAQZuXxl2HWR/Pnv5ukUiBzdkozB+npXaTVQHmTx -NUIRTErbYuCYW+HASCxnhZMYcLha7lM/X6Q5NMEOgz3dPA8mkxGCInZfjYZ2JlDb -Rx9ks9aRqFpoxHuyBxas3Fycuyz77YFE6rr+p7uAQ3o+dZqbO0RatvsNUpO6aTH6 -lUl8xyTwGMw2WV3ATxAaUCtVOAA8xVpJo9Z19PSfepho+g6VKku7eXHPqGR/p9++ -MIy/GuVREnFXQXQt5Ut3pYlREPiZ/k+57avJoQhv ------END CERTIFICATE----- diff --git a/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-24.pem b/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-24.pem deleted file mode 100644 index 625b63a..0000000 --- a/crates/attestation/test-assets/azure-cloud-virtual-tpm-ca-24.pem +++ /dev/null @@ -1,50 +0,0 @@ ------BEGIN CERTIFICATE----- -MIII6zCCBtOgAwIBAgIRAOy12jSrvPCNMaArM9L/ceIwDQYJKoZIhvcNAQENBQAw -KjEoMCYGA1UEAxMfQXp1cmUgQ2xvdWQgVmlydHVhbCBUUE0gQ0EgMjAyNTAeFw0y -NjAzMTEwMDAwMDBaFw0yOTAzMTAwMDAwMDBaMCoxKDAmBgNVBAMTH0F6dXJlIENs -b3VkIFZpcnR1YWwgVFBNIENBIC0gMjQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQCldZHSm3EVhrg4dBhW+P1fQzPX09vbzYsVvcXe31pLFhlokdJeJAC+ -axrPpZYP8V1DY9m0vPxrj6dm52vzoNErt6zuSRH4lNeQGWkZB6FLagyJwpDSDZ3B -sM6Y54Uwxi6YOG4yCkVjKY2CTvLbGxODEYv1U2NjM/CIQvqob49JBM64Qq/6gWFI -raNbJwA70ILysJwYjVB6YP4NNPuAlITNQyXZRp6k/nKCYPqxqhz/AUSbrJgH0t0T -l5v9zHo7awKV3S5bsdyxcCKTqm2IPittWrfvOF9KEs3ZRMeJPV+0DXp2e4vjKmee -9VFH9AmuHxYOa4MDa+617SxBrIPD/eE7OmdvPoSL3tgcVAtWAotykNWoVBgFdYlz -7M0WuQbZE23jhteP2rMZT5tVYr+hcWrTzzZ2GfNwiGLsilr6uL8YDm7TNE0twZIG -TtZaXJYzgaFFUMA8HpceedLD7ddS1uMUilhPHTmJXpWzRr/MdxrkU1xqo8/lvl2j -zC3EMOVPP8AhMrADMQizYzNJXLOJB24nouw0MTcaHc/VhAyW2ia/6ObYk3vpSOBN -GLmnDEoME23neYLsnOtAMvPciaBQ4pMojnuh2A8iVBKsaLasnVpwhkveBTaupknP -YzH/y9xuAFfxa1VUwouR5IofcstfMg10lWwVJRrW89bKBHZKYvSEPwIDAQABo4IE -CjCCBAYwEgYDVR0TAQH/BAgwBgEB/wIBADAjBgNVHSUEHDAaBgorBgEEAYI3CgMM -BgVngQUIAQYFZ4EFCAMwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBRDbLpWr9DP -xqS5FZVZ12BF80gyWjAfBgNVHSMEGDAWgBQcapb3M9HoC2YzZgeeZRR9j/6wPDCC -AbIGA1UdHwSCAakwggGlMGmgZ6BlhmNodHRwOi8vcHJpbWFyeS1jZG4ucGtpLmNv -cmUud2luZG93cy5uZXQvZWFzdHVzMi9jcmxzL2F6dXJldnRwbXBraS9henVyZXZ0 -cG1wb2xpY3ljYWV1czIvY3VycmVudC5jcmwwa6BpoGeGZWh0dHA6Ly9zZWNvbmRh -cnktY2RuLnBraS5jb3JlLndpbmRvd3MubmV0L2Vhc3R1czIvY3Jscy9henVyZXZ0 -cG1wa2kvYXp1cmV2dHBtcG9saWN5Y2FldXMyL2N1cnJlbnQuY3JsMFqgWKBWhlRo -dHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vZWFzdHVzMi9jcmxzL2F6dXJldnRwbXBr -aS9henVyZXZ0cG1wb2xpY3ljYWV1czIvY3VycmVudC5jcmwwb6BtoGuGaWh0dHA6 -Ly9henVyZXZ0cG1wa2kuZWFzdHVzMi5wa2kuY29yZS53aW5kb3dzLm5ldC9jZXJ0 -aWZpY2F0ZUF1dGhvcml0aWVzL2F6dXJldnRwbXBvbGljeWNhZXVzMi9jdXJyZW50 -LmNybDCCAcMGCCsGAQUFBwEBBIIBtTCCAbEwbwYIKwYBBQUHMAKGY2h0dHA6Ly9w -cmltYXJ5LWNkbi5wa2kuY29yZS53aW5kb3dzLm5ldC9lYXN0dXMyL2NhY2VydHMv -YXp1cmV2dHBtcGtpL2F6dXJldnRwbXBvbGljeWNhZXVzMi9jZXJ0LmNlcjBxBggr -BgEFBQcwAoZlaHR0cDovL3NlY29uZGFyeS1jZG4ucGtpLmNvcmUud2luZG93cy5u -ZXQvZWFzdHVzMi9jYWNlcnRzL2F6dXJldnRwbXBraS9henVyZXZ0cG1wb2xpY3lj -YWV1czIvY2VydC5jZXIwYAYIKwYBBQUHMAKGVGh0dHA6Ly9jcmwubWljcm9zb2Z0 -LmNvbS9lYXN0dXMyL2NhY2VydHMvYXp1cmV2dHBtcGtpL2F6dXJldnRwbXBvbGlj -eWNhZXVzMi9jZXJ0LmNlcjBpBggrBgEFBQcwAoZdaHR0cDovL2F6dXJldnRwbXBr -aS5lYXN0dXMyLnBraS5jb3JlLndpbmRvd3MubmV0L2NlcnRpZmljYXRlQXV0aG9y -aXRpZXMvYXp1cmV2dHBtcG9saWN5Y2FldXMyMA0GCSqGSIb3DQEBDQUAA4ICAQBZ -y/ScjLcaLqOFMMg/wqHHIuL+upqKnDhpl4joXXszc8xIsxYlzUdxUflcvC/midw3 -kPVRz8hNbXfzawHoIfh9/81u59uMk/NOExLflcd3a99sjfNwELmxTr7+nd8CjJmo -wCJoj/y/8noiDlBFTkKty7ngMooYV0XkisOS65McErEWT0hO0Gvb4FKTH2XAuc+7 -8mQe2J73O9SIkw4QljBg36wkSDT9P3R5cMcLbfeAEsa/n1llrg93x+A5Q8Tqwz6O -DrfiTNisaQQpVzhX+/PmdBpFiGspwTu81RGvo0kj5YhMhVoQ6zBuol21xv7VwLxB -oKVrDN59rQ6gnn6JK0QIvNRk0sYipVQP7wh2J1M39DpF0E0+KkkFg3dzUSSfmM8F -fDsaW227gPBjvXIumPOSlAF6b8G+Or/VFIiQ5Cc8Hi3icYCSc9jOtp4UGVvCAcMU -6Fj1aFUCeh1dtbCMAWDMVM08OF0Wae1YpXUuF7SeHkLNRg+DXcdCGb9FCRyJ8QQN -WQkEAe+fIV2WM5W6OUB+S3S4k3PHK0Rah73nACo0Qeh9hMIlhkMdzIgBqFieSo9m -HNIxnnDWlmpTBsqRHNXZP1qgUX2g1gJmG72qLbAlP2rUW/nl5XfWawjMYQyWszV/ -5cdYaa/HYUQm6edHfFiEmadftomvhfmjm8XnVBy9ng== ------END CERTIFICATE----- diff --git a/crates/attestation/test-assets/azure-collateral-with-ak-intermediates-1780922561.yaml b/crates/attestation/test-assets/azure-collateral-with-ak-intermediates-1780922561.yaml new file mode 100644 index 0000000..008c4fd --- /dev/null +++ b/crates/attestation/test-assets/azure-collateral-with-ak-intermediates-1780922561.yaml @@ -0,0 +1,109 @@ +pck_crl_issuer_chain: | + -----BEGIN CERTIFICATE----- + MIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC + MGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD + b3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw + CQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg + BgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs + IENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex + CzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO + 2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl + eTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS + BgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy + dmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d + zb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB + Af8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue + nA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+ + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw + aDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv + cnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ + BgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG + A1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0 + aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT + AlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7 + 1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB + uzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ + MEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50 + ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV + Ur9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI + KoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg + AiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI= + -----END CERTIFICATE----- +root_ca_crl: >- + 308201223081c8020101300a06082a8648ce3d0403023068311a301806035504030c11496e74656c2053475820526f6f74204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3236303232363133303430305a170d3237303232363133303430305aa02f302d300a0603551d140403020101301f0603551d2304183016801422650cd65a9d3489f383b49552bf501b392706ac300a06082a8648ce3d0403020349003046022100c252ed59c795ba2b11496a4a99758bb8cbc380a1ebbb0865be69f2c4b38bb6400221009a7d8b03602a9ee2d62322d759166d6933d24d9dfa01ab3fde4520691d715bd7 +pck_crl: >- + 30820d1730820cbd020101300a06082a8648ce3d04030230703122302006035504030c19496e74656c205347582050434b20506c6174666f726d204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3236303630383132323432325a170d3236303730383132323432325a30820be9303302146fc34e5023e728923435d61aa4b83c618166ad35170d3236303630383132323432325a300c300a0603551d1504030a01013034021500efae6e9715fca13b87e333e8261ed6d990a926ad170d3236303630383132323432325a300c300a0603551d1504030a01013034021500fd608648629cba73078b4d492f4b3ea741ad08cd170d3236303630383132323432325a300c300a0603551d1504030a010130340215008af924184e1d5afddd73c3d63a12f5e8b5737e56170d3236303630383132323432325a300c300a0603551d1504030a01013034021500b1257978cfa9ccdd0759abf8c5ca72fae3a78a9b170d3236303630383132323432325a300c300a0603551d1504030a01013033021474fea614a972be0e2843f2059835811ed872f9b3170d3236303630383132323432325a300c300a0603551d1504030a01013034021500f9c4ef56b3ab48d577e108baedf4bf88014214b9170d3236303630383132323432325a300c300a0603551d1504030a010130330214071de0778f9e5fc4f2878f30d6b07c9a30e6b30b170d3236303630383132323432325a300c300a0603551d1504030a01013034021500cde2424f972cea94ff239937f4d80c25029dd60b170d3236303630383132323432325a300c300a0603551d1504030a0101303302146c3319e5109b64507d3cf1132ce00349ef527319170d3236303630383132323432325a300c300a0603551d1504030a01013034021500df08d756b66a7497f43b5bb58ada04d3f4f7a937170d3236303630383132323432325a300c300a0603551d1504030a01013033021428af485b6cf67e409a39d5cb5aee4598f7a8fa7b170d3236303630383132323432325a300c300a0603551d1504030a01013034021500fb8b2daec092cada8aa9bc4ff2f1c20d0346668c170d3236303630383132323432325a300c300a0603551d1504030a01013034021500cd4850ac52bdcc69a6a6f058c8bc57bbd0b5f864170d3236303630383132323432325a300c300a0603551d1504030a01013034021500994dd3666f5275fb805f95dd02bd50cb2679d8ad170d3236303630383132323432325a300c300a0603551d1504030a0101303302140702136900252274d9035eedf5457462fad0ef4c170d3236303630383132323432325a300c300a0603551d1504030a01013033021461f2bf73e39b4e04aa27d801bd73d24319b5bf80170d3236303630383132323432325a300c300a0603551d1504030a0101303302143992be851b96902eff38959e6c2eff1b0651a4b5170d3236303630383132323432325a300c300a0603551d1504030a0101303302140fda43a00b68ea79b7c2deaeac0b498bdfb2af90170d3236303630383132323432325a300c300a0603551d1504030a010130330214639f139a5040fdcff191e8a4fb1bf086ed603971170d3236303630383132323432325a300c300a0603551d1504030a01013034021500959d533f9249dc1e513544cdc830bf19b7f1f301170d3236303630383132323432325a300c300a0603551d1504030a0101303302147ae37748a9f912f4c63ba7ab07c593ce1d1d1181170d3236303630383132323432325a300c300a0603551d1504030a01013033021413884b33269938c195aa170fca75da177538df0b170d3236303630383132323432325a300c300a0603551d1504030a0101303402150085d3c9381b77a7e04d119c9e5ad6749ff3ffab87170d3236303630383132323432325a300c300a0603551d1504030a0101303402150093887ca4411e7a923bd1fed2819b2949f201b5b4170d3236303630383132323432325a300c300a0603551d1504030a0101303302142498dc6283930996fd8bf23a37acbe26a3bed457170d3236303630383132323432325a300c300a0603551d1504030a010130340215008a66f1a749488667689cc3903ac54c662b712e73170d3236303630383132323432325a300c300a0603551d1504030a01013034021500afc13610bdd36cb7985d106481a880d3a01fda07170d3236303630383132323432325a300c300a0603551d1504030a01013034021500efe04b2c33d036aac96ca673bf1e9a47b64d5cbb170d3236303630383132323432325a300c300a0603551d1504030a0101303402150083d9ac8d8bb509d1c6c809ad712e8430559ed7f3170d3236303630383132323432325a300c300a0603551d1504030a0101303302147931fd50b5071c1bbfc5b7b6ded8b45b9d8b8529170d3236303630383132323432325a300c300a0603551d1504030a0101303302141fa20e2970bde5d57f7b8ddf8339484e1f1d0823170d3236303630383132323432325a300c300a0603551d1504030a0101303302141e87b2c3b32d8d23e411cef34197b95af0c8adf5170d3236303630383132323432325a300c300a0603551d1504030a010130340215009afd2ee90a473550a167d996911437c7502d1f09170d3236303630383132323432325a300c300a0603551d1504030a0101303302144481b0f11728a13b696d3ea9c770a0b15ec58dda170d3236303630383132323432325a300c300a0603551d1504030a01013034021500a7859f57982ef0e67d37bc8ef2ef5ac835ff1aa9170d3236303630383132323432325a300c300a0603551d1504030a010130340215009d67753b81e47090aea763fbec4c4549bcdb9933170d3236303630383132323432325a300c300a0603551d1504030a01013033021434bfbb7a1d9c568147e118b614f7b76ed3ef68df170d3236303630383132323432325a300c300a0603551d1504030a0101303302142c3cc6fe9279db1516d5ce39f2a898cda5a175e1170d3236303630383132323432325a300c300a0603551d1504030a010130330214717948687509234be979e4b7dce6f31bef64b68c170d3236303630383132323432325a300c300a0603551d1504030a010130340215009d76ef2c39c136e8658b6e7396b1d7445a27631f170d3236303630383132323432325a300c300a0603551d1504030a01013034021500c3e025fca995f36f59b48467939e3e34e6361a6f170d3236303630383132323432325a300c300a0603551d1504030a010130340215008c5f6b3257da05b17429e2e61ba965d67330606a170d3236303630383132323432325a300c300a0603551d1504030a01013034021500a17c51722ec1e0c3278fe8bdf052059cbec4e648170d3236303630383132323432325a300c300a0603551d1504030a01013033021411c943b866fa04944e3057e5a67146596475a023170d3236303630383132323432325a300c300a0603551d1504030a01013034021500be6913785406155454a28885a515b3da5767d3a9170d3236303630383132323432325a300c300a0603551d1504030a0101303302140ac5ec91bd934c07b9ea41625e9cc09681002eb0170d3236303630383132323432325a300c300a0603551d1504030a0101303302146d51a0eabc1f9a1e9ddd5b36bdda1631ae6c182a170d3236303630383132323432325a300c300a0603551d1504030a01013034021500a52c5d71c4166b4fc0ded8b679951e5ee9193de5170d3236303630383132323432325a300c300a0603551d1504030a010130330214249779aedd85fcac93c8853516be5428c26b3bf8170d3236303630383132323432325a300c300a0603551d1504030a01013033021434ba4fd76bde5309210cf1dd1ffb494c638a9157170d3236303630383132323432325a300c300a0603551d1504030a010130330214043e04919daae13443248395094d2a2eacfc76fe170d3236303630383132323432325a300c300a0603551d1504030a01013033021447fc577d2d094cbdf270715ed6848a93855ad34b170d3236303630383132323432325a300c300a0603551d1504030a0101303302147d62a2f5e6f386e469653fffff045d0a8178e8e7170d3236303630383132323432325a300c300a0603551d1504030a01013034021500c4ed45fe026bb6a47eaec35ea80b7ef407ce062c170d3236303630383132323432325a300c300a0603551d1504030a01013034021500cf9831077a3ca4f1a2c56867bf55b18eccbeffd8170d3236303630383132323432325a300c300a0603551d1504030a0101303302146c2b81d7ea2e436720ce29f1d0b1ccb7a218600f170d3236303630383132323432325a300c300a0603551d1504030a0101a02f302d300a0603551d140403020101301f0603551d23041830168014956f5dcdbd1be1e94049c9d4f433ce01570bde54300a06082a8648ce3d040302034800304502202b10885b6ba51577ad9ee43f07f0513cd27228a1423e5ab216f3dfdceed9445b022100f5c067068bf40a8eb2732770f5b0ab7d222887bce4d1e39a49b5ccd518a6ba0e +tcb_info_issuer_chain: | + -----BEGIN CERTIFICATE----- + MIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw + aDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv + cnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ + BgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG + A1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw + b3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD + VQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv + P+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju + ypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f + BEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz + LmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK + QEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG + SM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh + AKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw + aDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv + cnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ + BgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG + A1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0 + aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT + AlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7 + 1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB + uzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ + MEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50 + ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV + Ur9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI + KoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg + AiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI= + -----END CERTIFICATE----- +tcb_info: "{\"id\":\"TDX\",\"version\":3,\"issueDate\":\"2026-06-08T11:32:35Z\",\"nextUpdate\":\"2026-07-08T11:32:35Z\",\"fmspc\":\"90C06F000000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":19,\"tdxModule\":{\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\"},\"tdxModuleIdentities\":[{\"id\":\"TDX_03\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":3},\"tcbDate\":\"2025-05-14T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]},{\"id\":\"TDX_01\",\"mrsigner\":\"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"attributes\":\"0000000000000000\",\"attributesMask\":\"FFFFFFFFFFFFFFFF\",\"tcbLevels\":[{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2025-05-14T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01099\"]},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01099\"]}]}],\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":3,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":4,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2025-05-14T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":2,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2024-03-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-01036\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":2,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":2,\"category\":\"BIOS\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":1,\"category\":\"BIOS\"},{\"svn\":0},{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":2,\"category\":\"OS/VMM\",\"type\":\"TDX Late Microcode Update\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}]},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00837\",\"INTEL-SA-01036\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]}]}" +tcb_info_signature: >- + 291827b96b08682bd30e8c8f0f20a321fc6d84a4fe020a8a588d63a7ea4e33f6193669e6c02c600d86389e5197ce6b7f9a221f63661cc6d8c32827becd67230e +qe_identity_issuer_chain: | + -----BEGIN CERTIFICATE----- + MIICjTCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw + aDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv + cnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ + BgNVBAYTAlVTMB4XDTI1MDUwNjA5MjUwMFoXDTMyMDUwNjA5MjUwMFowbDEeMBwG + A1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw + b3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD + VQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv + P+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju + ypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f + BEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz + LmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK + QEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG + SM49BAMCA0kAMEYCIQDdmmRuAo3qCO8TC1IoJMITAoOEw4dlgEBHzSz1TuMSTAIh + AKVTqOkt59+co0O3m3hC+v5Fb00FjYWcgeu3EijOULo5 + -----END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw + aDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv + cnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ + BgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG + A1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0 + aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT + AlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7 + 1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB + uzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ + MEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50 + ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV + Ur9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI + KoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg + AiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI= + -----END CERTIFICATE----- +qe_identity: "{\"id\":\"TD_QE\",\"version\":2,\"issueDate\":\"2026-06-08T11:28:48Z\",\"nextUpdate\":\"2026-07-08T11:28:48Z\",\"tcbEvaluationDataNumber\":19,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"DC9E2A7C6F948F17474E34A7FC43ED030F7C1563F1BABDDF6340C82E0E54A8C5\",\"isvprodid\":2,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2025-05-14T00:00:00Z\",\"tcbStatus\":\"UpToDate\"}]}" +qe_identity_signature: >- + d3f21394cb17271d0690b3f50c0c9c27f3d4a0977a5eedc1c38dc612733e10161044b4e9415d146d42cbd95d5280d18c5ce2ac1defb26e621bcc807d41000549 diff --git a/crates/attestation/test-assets/azure-tdx-with-ak-intermediates-1780922561.yaml b/crates/attestation/test-assets/azure-tdx-with-ak-intermediates-1780922561.yaml new file mode 100644 index 0000000..67da3f8 --- /dev/null +++ b/crates/attestation/test-assets/azure-tdx-with-ak-intermediates-1780922561.yaml @@ -0,0 +1,1309 @@ +tdx_quote_base64: >- + BAACAIEAAAAAAAAAk5pyM_ecTKmUCg2zlX8GByzSuWcsRFHc8qIVvDuerbAAAAAADQEEAAAAAAAAAAAAAAAAAEieWF8cVLxaAgZsjG7CFhn_AzTsbyHgfio1ICxZGDeJyAV-fZfdWRuwgxSxhYGecgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAADnGAYAAAAAAP9FCxOMXuZzSkPcNa-0N6v6JO90O8npSE70rzZfzYmmxQkTJI7X_LkqfUKxun2phAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEi9CZtuApvU-WsUJmRE8UU9L556F3w0bcM59dFrytffAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMEAAA4BSAjddR-2DezImKmIoCxAodFQ_yxoq9DnaAxIl1NPBA2ZUvjCEaXee8iphc5PZpFdvQcUKmIwAM7N2rNh-9scYbHNLSQbpoHbnXf84kw1WeIB1Wkqh0FZuNCNebfTWSWRzdb5rGCuqyXiG8MnV8qbs6HDcrM6RUPnnhaghWGdEGAEYQAAAEBBkbBP8ABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAAAOcAAAAAAAAAt66atp5293lKVrDbGRUoHUNdSIyR1AbtM6eTnK-HMPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANyeKnxvlI8XR040p_xD7QMPfBVj8bq932NAyC4OVKjFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHDZ8zWjHh20kliSUUL-IX5jVQbc1QoPVoSGaXoYd1YkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBQxjye4CTB91sYTBbC0UE9aAPqmKWiAeLGogXT1SkRPRoHte8zUcurYLoj-1eJ4EWXyDEdISOk_zt8P2cCX1IAAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHwUAXg4AAC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFOERDQ0JKZWdBd0lCQWdJVkFPZEJlQ3hrdks4RVZiMUVnbWZ4eEdQSHVWcFRNQW9HQ0NxR1NNNDlCQU1DCk1IQXhJakFnQmdOVkJBTU1HVWx1ZEdWc0lGTkhXQ0JRUTBzZ1VHeGhkR1p2Y20wZ1EwRXhHakFZQmdOVkJBb00KRVVsdWRHVnNJRU52Y25CdmNtRjBhVzl1TVJRd0VnWURWUVFIREF0VFlXNTBZU0JEYkdGeVlURUxNQWtHQTFVRQpDQXdDUTBFeEN6QUpCZ05WQkFZVEFsVlRNQjRYRFRJMU1USXhOakEyTVRreU5Wb1hEVE15TVRJeE5qQTJNVGt5Ck5Wb3djREVpTUNBR0ExVUVBd3daU1c1MFpXd2dVMGRZSUZCRFN5QkRaWEowYVdacFkyRjBaVEVhTUJnR0ExVUUKQ2d3UlNXNTBaV3dnUTI5eWNHOXlZWFJwYjI0eEZEQVNCZ05WQkFjTUMxTmhiblJoSUVOc1lYSmhNUXN3Q1FZRApWUVFJREFKRFFURUxNQWtHQTFVRUJoTUNWVk13V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVNICnE5dmVYNnlxbEhUcUh3cWF1dnprakpiUFZMUW9qb2FOWFQ0ejBucVB0MFpZUWZ1WUtMQzNrYURESmJST2hicmMKbHZyU3h0UTNiMnplTDJFUUIyNzBvNElERERDQ0F3Z3dId1lEVlIwakJCZ3dGb0FVbFc5ZHpiMGI0ZWxBU2NuVQo5RFBPQVZjTDNsUXdhd1lEVlIwZkJHUXdZakJnb0Y2Z1hJWmFhSFIwY0hNNkx5OWhjR2t1ZEhKMWMzUmxaSE5sCmNuWnBZMlZ6TG1sdWRHVnNMbU52YlM5elozZ3ZZMlZ5ZEdsbWFXTmhkR2x2Ymk5Mk5DOXdZMnRqY213L1kyRTkKY0d4aGRHWnZjbTBtWlc1amIyUnBibWM5WkdWeU1CMEdBMVVkRGdRV0JCUkRQN0U2cXVGSFJqTlF1ZWNmUFpIRAoxaHpTRkRBT0JnTlZIUThCQWY4RUJBTUNCc0F3REFZRFZSMFRBUUgvQkFJd0FEQ0NBamtHQ1NxR1NJYjRUUUVOCkFRU0NBaW93Z2dJbU1CNEdDaXFHU0liNFRRRU5BUUVFRUx5Qm9uaXFvaVY3VGI0VnUvc1ZONkF3Z2dGakJnb3EKaGtpRytFMEJEUUVDTUlJQlV6QVFCZ3NxaGtpRytFMEJEUUVDQVFJQkJEQVFCZ3NxaGtpRytFMEJEUUVDQWdJQgpCREFRQmdzcWhraUcrRTBCRFFFQ0F3SUJBakFRQmdzcWhraUcrRTBCRFFFQ0JBSUJBakFRQmdzcWhraUcrRTBCCkRRRUNCUUlCQkRBUUJnc3Foa2lHK0UwQkRRRUNCZ0lCQVRBUUJnc3Foa2lHK0UwQkRRRUNCd0lCQURBUUJnc3EKaGtpRytFMEJEUUVDQ0FJQkJUQVFCZ3NxaGtpRytFMEJEUUVDQ1FJQkFEQVFCZ3NxaGtpRytFMEJEUUVDQ2dJQgpBREFRQmdzcWhraUcrRTBCRFFFQ0N3SUJBREFRQmdzcWhraUcrRTBCRFFFQ0RBSUJBREFRQmdzcWhraUcrRTBCCkRRRUNEUUlCQURBUUJnc3Foa2lHK0UwQkRRRUNEZ0lCQURBUUJnc3Foa2lHK0UwQkRRRUNEd0lCQURBUUJnc3EKaGtpRytFMEJEUUVDRUFJQkFEQVFCZ3NxaGtpRytFMEJEUUVDRVFJQkRUQWZCZ3NxaGtpRytFMEJEUUVDRWdRUQpCQVFDQWdRQkFBVUFBQUFBQUFBQUFEQVFCZ29xaGtpRytFMEJEUUVEQkFJQUFEQVVCZ29xaGtpRytFMEJEUUVFCkJBYVF3RzhBQUFBd0R3WUtLb1pJaHZoTkFRMEJCUW9CQVRBZUJnb3Foa2lHK0UwQkRRRUdCQkJBbzFWQnIzNkYKMTBUZ241ZUYxSTA3TUVRR0NpcUdTSWI0VFFFTkFRY3dOakFRQmdzcWhraUcrRTBCRFFFSEFRRUIvekFRQmdzcQpoa2lHK0UwQkRRRUhBZ0VCQURBUUJnc3Foa2lHK0UwQkRRRUhBd0VCL3pBS0JnZ3Foa2pPUFFRREFnTkhBREJFCkFpQUpSUm9qako5UW5Ba0UwZHdqT1VwNVA3eVhJeHZzdGZ4ajlCTTZaN1ZscUFJZ1k4clgxVzVzZmVLMzkyd2gKem5EY3FRL2Y4cVk2WnltK05BWUtRQTlQRElNPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDbGpDQ0FqMmdBd0lCQWdJVkFKVnZYYzI5RytIcFFFbkoxUFF6emdGWEM5NVVNQW9HQ0NxR1NNNDlCQU1DCk1HZ3hHakFZQmdOVkJBTU1FVWx1ZEdWc0lGTkhXQ0JTYjI5MElFTkJNUm93R0FZRFZRUUtEQkZKYm5SbGJDQkQKYjNKd2IzSmhkR2x2YmpFVU1CSUdBMVVFQnd3TFUyRnVkR0VnUTJ4aGNtRXhDekFKQmdOVkJBZ01Ba05CTVFzdwpDUVlEVlFRR0V3SlZVekFlRncweE9EQTFNakV4TURVd01UQmFGdzB6TXpBMU1qRXhNRFV3TVRCYU1IQXhJakFnCkJnTlZCQU1NR1VsdWRHVnNJRk5IV0NCUVEwc2dVR3hoZEdadmNtMGdRMEV4R2pBWUJnTlZCQW9NRVVsdWRHVnMKSUVOdmNuQnZjbUYwYVc5dU1SUXdFZ1lEVlFRSERBdFRZVzUwWVNCRGJHRnlZVEVMTUFrR0ExVUVDQXdDUTBFeApDekFKQmdOVkJBWVRBbFZUTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFTlNCLzd0MjFsWFNPCjJDdXpweHc3NGVKQjcyRXlER2dXNXJYQ3R4MnRWVExxNmhLazZ6K1VpUlpDbnFSN3BzT3ZncUZlU3hsbVRsSmwKZVRtaTJXWXozcU9CdXpDQnVEQWZCZ05WSFNNRUdEQVdnQlFpWlF6V1dwMDBpZk9EdEpWU3YxQWJPU2NHckRCUwpCZ05WSFI4RVN6QkpNRWVnUmFCRGhrRm9kSFJ3Y3pvdkwyTmxjblJwWm1sallYUmxjeTUwY25WemRHVmtjMlZ5CmRtbGpaWE11YVc1MFpXd3VZMjl0TDBsdWRHVnNVMGRZVW05dmRFTkJMbVJsY2pBZEJnTlZIUTRFRmdRVWxXOWQKemIwYjRlbEFTY25VOURQT0FWY0wzbFF3RGdZRFZSMFBBUUgvQkFRREFnRUdNQklHQTFVZEV3RUIvd1FJTUFZQgpBZjhDQVFBd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1hzVmtpMHcraTZWWUdXM1VGLzIydWFYZTBZSkRqMVVlCm5BK1RqRDFhaTVjQ0lDWWIxU0FtRDV4a2ZUVnB2bzRVb3lpU1l4ckRXTG1VUjRDSTlOS3lmUE4rCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNqekNDQWpTZ0F3SUJBZ0lVSW1VTTFscWROSW56ZzdTVlVyOVFHemtuQnF3d0NnWUlLb1pJemowRUF3SXcKYURFYU1CZ0dBMVVFQXd3UlNXNTBaV3dnVTBkWUlGSnZiM1FnUTBFeEdqQVlCZ05WQkFvTUVVbHVkR1ZzSUVOdgpjbkJ2Y21GMGFXOXVNUlF3RWdZRFZRUUhEQXRUWVc1MFlTQkRiR0Z5WVRFTE1Ba0dBMVVFQ0F3Q1EwRXhDekFKCkJnTlZCQVlUQWxWVE1CNFhEVEU0TURVeU1URXdORFV4TUZvWERUUTVNVEl6TVRJek5UazFPVm93YURFYU1CZ0cKQTFVRUF3d1JTVzUwWld3Z1UwZFlJRkp2YjNRZ1EwRXhHakFZQmdOVkJBb01FVWx1ZEdWc0lFTnZjbkJ2Y21GMAphVzl1TVJRd0VnWURWUVFIREF0VFlXNTBZU0JEYkdGeVlURUxNQWtHQTFVRUNBd0NRMEV4Q3pBSkJnTlZCQVlUCkFsVlRNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVDNm5Fd01ESVlaT2ovaVBXc0N6YUVLaTcKMU9pT1NMUkZoV0dqYm5CVkpmVm5rWTR1M0lqa0RZWUwwTXhPNG1xc3lZamxCYWxUVll4RlAyc0pCSzV6bEtPQgp1ekNCdURBZkJnTlZIU01FR0RBV2dCUWlaUXpXV3AwMGlmT0R0SlZTdjFBYk9TY0dyREJTQmdOVkhSOEVTekJKCk1FZWdSYUJEaGtGb2RIUndjem92TDJObGNuUnBabWxqWVhSbGN5NTBjblZ6ZEdWa2MyVnlkbWxqWlhNdWFXNTAKWld3dVkyOXRMMGx1ZEdWc1UwZFlVbTl2ZEVOQkxtUmxjakFkQmdOVkhRNEVGZ1FVSW1VTTFscWROSW56ZzdTVgpVcjlRR3prbkJxd3dEZ1lEVlIwUEFRSC9CQVFEQWdFR01CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRRXdDZ1lJCktvWkl6ajBFQXdJRFNRQXdSZ0loQU9XLzVRa1IrUzlDaVNEY05vb3dMdVBSTHNXR2YvWWk3R1NYOTRCZ3dUd2cKQWlFQTRKMGxySG9NcytYbzVvL3NYNk85UVd4SFJBdlpVR09kUlE3Y3ZxUlhhcUk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +hcl_report_base64: >- + SENMQQIAAACACQAAAgAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAAAAAAAAAAAAABAQZGwT_AAYAAAAAAAAAABjl_zdaGAkhqwWBdHz7VYfVQy6FVDBoEZEinFpeNi273zlF-i-vRfdKsF3ruoLXbN7eFM_cuJOZWR0QvVZc77bpDlAT5Meler0Oz7SBe2bD7vPFmx7PEAYvgmDj37X2Zki9CZtuApvU-WsUJmRE8UU9L556F3w0bcM59dFrytffAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAF4fNHGcMylLX-ZlmGlcz6UtkS1QpA1v69xMPChc5wGf_wEDAAAAAAANAQQAAAAAAAAAAAAAAAAASJ5YXxxUvFoCBmyMbsIWGf8DNOxvIeB-KjUgLFkYN4nIBX59l91ZG7CDFLGFgZ5yAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANAQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA5xgGAAAAAAD_RQsTjF7mc0pD3DWvtDer-iTvdDvJ6UhO9K82X82JpsUJEySO1_y5Kn1Csbp9qYQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAEAAABAAAABAAAAAEAAACsBAAAeyJrZXlzIjpbeyJraWQiOiJIQ0xBa1B1YiIsImtleV9vcHMiOlsic2lnbiJdLCJrdHkiOiJSU0EiLCJlIjoiQVFBQiIsIm4iOiIxMFpYSkFBQVM5dEJEa0d5ZGpJUnJNT1NySGZUQXlHQUhEWU9EWWFLTy1jNFhhTDhSMGVIUHg2YmxlemFobmN2NVV3ajRSMkhzZWxXeUN0YkNFb1pYY3NUUXR0Z0EzR0EtcGlFODhvSG41Wm95U1ZmbHA1Y2VSSlNvWXdTWDk0bzdSTUM4bVFLNHZHMUt1OVhKUUpuTkFnTm5uLVlrbFZHXzhPUWdTSWlRc0Mtc21EcEtnZl80eFJ2Z0l3R1F6TFBlOUJPdDVFZllTWmtiZjcyUTdzLUtaenh4dWUyOGdzQmRKNzV2RGNSYVJHNHVPUVVCcnQ1NnA3dU5SSGtpcDBBN0w3Ti1JSFoyU1VWT1l2bV83ajIyUG5yN0lGeFlVVUR4d2hpMEdNVE43SXM4Y0ZKSmpCckdCbUE2MDZCWXp5VEJIc0h4NHMzWGNRd01KMVBvQ2UxQXcifSx7ImtpZCI6IkhDTEVrUHViIiwia2V5X29wcyI6WyJlbmNyeXB0Il0sImt0eSI6IlJTQSIsImUiOiJBUUFCIiwibiI6InlDcV9RQUFCRl9uZ2NCRmxPNkdzcHdDcjYybFMxMnNISUU1TjNRNHR4TDRqOWF3TjA2c2RfVnBiN09hT012QVR6R0thU3MySXBlcUxDUWlPSlg4My0wbUMtTzlsUHluTmpLSzFvVkJzaGJPWENtUGZTcFV0eEVSSEFocjhGb3ZuVER3Q1M3aTFNc1ItY3I0cXVjdkhGYVExYXRIS1dQSF9ud1libjNPRDRwOV9wcHBJcG9qd0NXc1VLVHhaUW5OT0dqMjdfNWRCcDlXOUFyYUdpM0Vscm52cWFuVmk4Ujh2dW9yUFd0ZUZvcHBNazhTZ1JRVV9laU9LSmViaHRkeWl5REgzLVpnMlkzTjBDWXAzNnhXUEo2d3NOVW5WRFNtZnJWTTQ1UjhpR21vV3d5TUMzQV9qS1Z6OXR3azlQYTFuSE1HYWxYVEVRVzZhUG91M0kxcDU4dyJ9XSwidm0tY29uZmlndXJhdGlvbiI6eyJyb290LWNlcnQtdGh1bWJwcmludCI6IiIsImNvbnNvbGUtZW5hYmxlZCI6dHJ1ZSwic2VjdXJlLWJvb3QiOnRydWUsInRwbS1lbmFibGVkIjp0cnVlLCJ0cG0tcGVyc2lzdGVkIjpmYWxzZSwiZmlsdGVyZWQtdnBjaS1kZXZpY2VzLWFsbG93ZWQiOmZhbHNlLCJ2bVVuaXF1ZUlkIjoiM2MxOGM5N2EtMGQyYS00NTY1LTk2OWQtMTY2Y2RjZWYyNmEzIn0sInVzZXItZGF0YSI6IjAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwIn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +tpm_attestation: + ak_certificate_pem: | + -----BEGIN CERTIFICATE----- + MIIGSDCCBDCgAwIBAgIRAJAvqNCllxZIu6pQsYTrMbAwDQYJKoZIhvcNAQENBQAw + KjEoMCYGA1UEAxMfQXp1cmUgQ2xvdWQgVmlydHVhbCBUUE0gQ0EgLSAyNDAeFw0y + NjA2MDgwMDAwMDBaFw0yNzA2MDcwMDAwMDBaMDgxNjA0BgNVBAMTLTJlZGUyZDUz + MmFhZi5Db25maWRlbnRpYWxWTS5BenVyZS53aW5kb3dzLm5ldDCCASIwDQYJKoZI + hvcNAQEBBQADggEPADCCAQoCggEBANdGVyQAAEvbQQ5BsnYyEazDkqx30wMhgBw2 + Dg2GijvnOF2i/EdHhz8em5Xs2oZ3L+VMI+Edh7HpVsgrWwhKGV3LE0LbYANxgPqY + hPPKB5+WaMklX5aeXHkSUqGMEl/eKO0TAvJkCuLxtSrvVyUCZzQIDZ5/mJJVRv/D + kIEiIkLAvrJg6SoH/+MUb4CMBkMyz3vQTreRH2EmZG3+9kO7Pimc8cbntvILAXSe + +bw3EWkRuLjkFAa7eeqe7jUR5IqdAOy+zfiB2dklFTmL5v+49tj56+yBcWFFA8cI + YtBjEzeyLPHBSSYwaxgZgOtOgWM8kwR7B8eLN13EMDCdT6AntQMCAwEAAaOCAlkw + ggJVMBgGA1UdIAQRMA8wDQYLKwYBBAGCN2yBSAIwDAYDVR0TAQH/BAIwADAcBgNV + HSUEFTATBgorBgEEAYI3CgMMBgVngQUIAzAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0O + BBYEFKlL0CakAru/SLwTZP44cqbA53+GMB8GA1UdIwQYMBaAFENsulav0M/GpLkV + lVnXYEXzSDJaMIIBuwYIKwYBBQUHAQEEggGtMIIBqTBtBggrBgEFBQcwAoZhaHR0 + cDovL3ByaW1hcnktY2RuLnBraS5jb3JlLndpbmRvd3MubmV0L3dlc3R1czMvY2Fj + ZXJ0cy9henVyZXZ0cG1pY2Fwa2kvYXp1cmV2dHBtaWNhdXN3My9jZXJ0LmNlcjBv + BggrBgEFBQcwAoZjaHR0cDovL3NlY29uZGFyeS1jZG4ucGtpLmNvcmUud2luZG93 + cy5uZXQvd2VzdHVzMy9jYWNlcnRzL2F6dXJldnRwbWljYXBraS9henVyZXZ0cG1p + Y2F1c3czL2NlcnQuY2VyMF4GCCsGAQUFBzAChlJodHRwOi8vY3JsLm1pY3Jvc29m + dC5jb20vd2VzdHVzMy9jYWNlcnRzL2F6dXJldnRwbWljYXBraS9henVyZXZ0cG1p + Y2F1c3czL2NlcnQuY2VyMGcGCCsGAQUFBzAChltodHRwOi8vYXp1cmV2dHBtaWNh + cGtpLndlc3R1czMucGtpLmNvcmUud2luZG93cy5uZXQvY2VydGlmaWNhdGVBdXRo + b3JpdGllcy9henVyZXZ0cG1pY2F1c3czMA0GCSqGSIb3DQEBDQUAA4ICAQA0chCl + DoEJFnu3ymmz8KOBRe6fo2PDFKcHuEgkjysXOHYmtddESh5KOroymS4GIRBZpeUV + FkuZPx32nhJgVAGFvuj8BZlpLfvAWQnKtDdoAV1L6pHT+43irH2aTtUgrvH+8LiB + GlP/UvyNs7yDvAAUJQsENraNnilNY/n5nNN4Rhq3pYGBLGGi35AEMmhUKdxRTO74 + FMM6wEJHxVEP4TL/fkGpcQMEfptHCR5qAo4CGU/GiGsZPyBT4FBno1RW1C5GW3NL + xECrqVDv0I4HZ5JbOAuKeWDs+XWTTUn4ovHnvEiUeIVdIGKzvhse7qvLWSrYB4AB + 9SGpxjGP3qQmXj+dJwk6ww7JWo8jURsS7QO1/kuHqHQ9gD6rJnmV+cOx+wGsE1PW + +kX+1q6Ms6uUsEPItFKdjvB8dpvhyIXhKfunAnC7MvMbaXUTciD0mxb27k+GB9PM + c22Ykv7DJCDVrTc43UljnaH3pXviMOArKBhyHV85i38nTCqAF4/avWPoBnS6+Q9V + TwGIRurIONvQ+gPI8yTlOZhZBw8KoGy771Z7qy57MN0MdOFFQfZI0HtvP/xioeWy + QBmqZSkBB2tN9PlmAsJPHVzUmxWGOWNqLewcr4NTxrNyqDOFjjZOyk2JtfRDy07N + swynEeTtLqAyRqjW7k9x3USDdmg+haPlnAYiyw== + -----END CERTIFICATE----- + ak_intermediate_certificates_pem: + - | + -----BEGIN CERTIFICATE----- + MIII6zCCBtOgAwIBAgIRAOy12jSrvPCNMaArM9L/ceIwDQYJKoZIhvcNAQENBQAw + KjEoMCYGA1UEAxMfQXp1cmUgQ2xvdWQgVmlydHVhbCBUUE0gQ0EgMjAyNTAeFw0y + NjAzMTEwMDAwMDBaFw0yOTAzMTAwMDAwMDBaMCoxKDAmBgNVBAMTH0F6dXJlIENs + b3VkIFZpcnR1YWwgVFBNIENBIC0gMjQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw + ggIKAoICAQCldZHSm3EVhrg4dBhW+P1fQzPX09vbzYsVvcXe31pLFhlokdJeJAC+ + axrPpZYP8V1DY9m0vPxrj6dm52vzoNErt6zuSRH4lNeQGWkZB6FLagyJwpDSDZ3B + sM6Y54Uwxi6YOG4yCkVjKY2CTvLbGxODEYv1U2NjM/CIQvqob49JBM64Qq/6gWFI + raNbJwA70ILysJwYjVB6YP4NNPuAlITNQyXZRp6k/nKCYPqxqhz/AUSbrJgH0t0T + l5v9zHo7awKV3S5bsdyxcCKTqm2IPittWrfvOF9KEs3ZRMeJPV+0DXp2e4vjKmee + 9VFH9AmuHxYOa4MDa+617SxBrIPD/eE7OmdvPoSL3tgcVAtWAotykNWoVBgFdYlz + 7M0WuQbZE23jhteP2rMZT5tVYr+hcWrTzzZ2GfNwiGLsilr6uL8YDm7TNE0twZIG + TtZaXJYzgaFFUMA8HpceedLD7ddS1uMUilhPHTmJXpWzRr/MdxrkU1xqo8/lvl2j + zC3EMOVPP8AhMrADMQizYzNJXLOJB24nouw0MTcaHc/VhAyW2ia/6ObYk3vpSOBN + GLmnDEoME23neYLsnOtAMvPciaBQ4pMojnuh2A8iVBKsaLasnVpwhkveBTaupknP + YzH/y9xuAFfxa1VUwouR5IofcstfMg10lWwVJRrW89bKBHZKYvSEPwIDAQABo4IE + CjCCBAYwEgYDVR0TAQH/BAgwBgEB/wIBADAjBgNVHSUEHDAaBgorBgEEAYI3CgMM + BgVngQUIAQYFZ4EFCAMwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBRDbLpWr9DP + xqS5FZVZ12BF80gyWjAfBgNVHSMEGDAWgBQcapb3M9HoC2YzZgeeZRR9j/6wPDCC + AbIGA1UdHwSCAakwggGlMGmgZ6BlhmNodHRwOi8vcHJpbWFyeS1jZG4ucGtpLmNv + cmUud2luZG93cy5uZXQvZWFzdHVzMi9jcmxzL2F6dXJldnRwbXBraS9henVyZXZ0 + cG1wb2xpY3ljYWV1czIvY3VycmVudC5jcmwwa6BpoGeGZWh0dHA6Ly9zZWNvbmRh + cnktY2RuLnBraS5jb3JlLndpbmRvd3MubmV0L2Vhc3R1czIvY3Jscy9henVyZXZ0 + cG1wa2kvYXp1cmV2dHBtcG9saWN5Y2FldXMyL2N1cnJlbnQuY3JsMFqgWKBWhlRo + dHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vZWFzdHVzMi9jcmxzL2F6dXJldnRwbXBr + aS9henVyZXZ0cG1wb2xpY3ljYWV1czIvY3VycmVudC5jcmwwb6BtoGuGaWh0dHA6 + Ly9henVyZXZ0cG1wa2kuZWFzdHVzMi5wa2kuY29yZS53aW5kb3dzLm5ldC9jZXJ0 + aWZpY2F0ZUF1dGhvcml0aWVzL2F6dXJldnRwbXBvbGljeWNhZXVzMi9jdXJyZW50 + LmNybDCCAcMGCCsGAQUFBwEBBIIBtTCCAbEwbwYIKwYBBQUHMAKGY2h0dHA6Ly9w + cmltYXJ5LWNkbi5wa2kuY29yZS53aW5kb3dzLm5ldC9lYXN0dXMyL2NhY2VydHMv + YXp1cmV2dHBtcGtpL2F6dXJldnRwbXBvbGljeWNhZXVzMi9jZXJ0LmNlcjBxBggr + BgEFBQcwAoZlaHR0cDovL3NlY29uZGFyeS1jZG4ucGtpLmNvcmUud2luZG93cy5u + ZXQvZWFzdHVzMi9jYWNlcnRzL2F6dXJldnRwbXBraS9henVyZXZ0cG1wb2xpY3lj + YWV1czIvY2VydC5jZXIwYAYIKwYBBQUHMAKGVGh0dHA6Ly9jcmwubWljcm9zb2Z0 + LmNvbS9lYXN0dXMyL2NhY2VydHMvYXp1cmV2dHBtcGtpL2F6dXJldnRwbXBvbGlj + eWNhZXVzMi9jZXJ0LmNlcjBpBggrBgEFBQcwAoZdaHR0cDovL2F6dXJldnRwbXBr + aS5lYXN0dXMyLnBraS5jb3JlLndpbmRvd3MubmV0L2NlcnRpZmljYXRlQXV0aG9y + aXRpZXMvYXp1cmV2dHBtcG9saWN5Y2FldXMyMA0GCSqGSIb3DQEBDQUAA4ICAQBZ + y/ScjLcaLqOFMMg/wqHHIuL+upqKnDhpl4joXXszc8xIsxYlzUdxUflcvC/midw3 + kPVRz8hNbXfzawHoIfh9/81u59uMk/NOExLflcd3a99sjfNwELmxTr7+nd8CjJmo + wCJoj/y/8noiDlBFTkKty7ngMooYV0XkisOS65McErEWT0hO0Gvb4FKTH2XAuc+7 + 8mQe2J73O9SIkw4QljBg36wkSDT9P3R5cMcLbfeAEsa/n1llrg93x+A5Q8Tqwz6O + DrfiTNisaQQpVzhX+/PmdBpFiGspwTu81RGvo0kj5YhMhVoQ6zBuol21xv7VwLxB + oKVrDN59rQ6gnn6JK0QIvNRk0sYipVQP7wh2J1M39DpF0E0+KkkFg3dzUSSfmM8F + fDsaW227gPBjvXIumPOSlAF6b8G+Or/VFIiQ5Cc8Hi3icYCSc9jOtp4UGVvCAcMU + 6Fj1aFUCeh1dtbCMAWDMVM08OF0Wae1YpXUuF7SeHkLNRg+DXcdCGb9FCRyJ8QQN + WQkEAe+fIV2WM5W6OUB+S3S4k3PHK0Rah73nACo0Qeh9hMIlhkMdzIgBqFieSo9m + HNIxnnDWlmpTBsqRHNXZP1qgUX2g1gJmG72qLbAlP2rUW/nl5XfWawjMYQyWszV/ + 5cdYaa/HYUQm6edHfFiEmadftomvhfmjm8XnVBy9ng== + -----END CERTIFICATE----- + - | + -----BEGIN CERTIFICATE----- + MIIGqjCCBJKgAwIBAgITMwAAAA3hTgyMJlm7XAAAAAAADTANBgkqhkiG9w0BAQwF + ADBpMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9u + MTowOAYDVQQDEzFBenVyZSBWaXJ0dWFsIFRQTSBSb290IENlcnRpZmljYXRlIEF1 + dGhvcml0eSAyMDIzMB4XDTI1MDgwNjIxMDIwMloXDTMxMDgwNTIxMDIwMlowKjEo + MCYGA1UEAxMfQXp1cmUgQ2xvdWQgVmlydHVhbCBUUE0gQ0EgMjAyNTCCAiIwDQYJ + KoZIhvcNAQEBBQADggIPADCCAgoCggIBAIa4QCuPJi5ehBDiXG6HYkmy17bgAtrQ + mK/+Ik9MHnmZoRw+Th08dgXZRNZf5A73WCC78r9O1hLqdiOIGf19Ejf8UxU6cRXj + UPpkn1Gfru8G/Rn488R2sJ/OJIncTKbJFVUNEt6HhABXRz/I6xlYLpXoU0HcgfB4 + Cw+8h/jQsXqnVXWrMmjQJ6+DgJR2Yk32zi75NY5Z6j3L0he+nO9P/uZ6ZSLOn/Lj + ftoPVs26Ay6Q/h7bJ7wtcC06k8qHxplimiWrEtNU7A74PaUGWZfgFXeOrUZXSURb + YxqbCTW6isbvS2D7IkNq/OasRVEUY3gNXFu3g8d08JCmvSY6P1peJQN0yvbFx43L + /nfY7CXRhF/sEViTcjkV1/Asa+PUT7yjzE6hf512yfUJtlBU7HXfK1n7sK2BT1xG + ds9N+jpBSXXq7dqWr2OsfmNMDF3wttnjD31OOjxmyq1yR4BuPxhJYH/AHnQQIA+/ + tIcdLgtEKISXzSwcMvKt0X5olzTKFREeEWH/x+i1zPuu4bxUY7Fd0z0PvealExtv + mT8MJ3iFhHRReJolnG8a00DUfyj++dEaSQtgf4liGQZLgBK7g4AesL3vKPgRVNP9 + ex4WEuLULIW78QiG0bOwoswc2pMePWlNVDEVju56VwB2+Y+qNQIO29ySuTf7W9NB + adXUAmuJEykrAgMBAAGjggGIMIIBhDALBgNVHQ8EBAMCAYYwIwYDVR0lBBwwGgYK + KwYBBAGCNwoDDAYFZ4EFCAEGBWeBBQgDMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYD + VR0OBBYEFBxqlvcz0egLZjNmB55lFH2P/rA8MB8GA1UdIwQYMBaAFEv+JlqUwfYz + w4NIJt3z5bBksqqVMHYGA1UdHwRvMG0wa6BpoGeGZWh0dHA6Ly93d3cubWljcm9z + b2Z0LmNvbS9wa2lvcHMvY3JsL0F6dXJlJTIwVmlydHVhbCUyMFRQTSUyMFJvb3Ql + MjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMjMuY3JsMIGDBggrBgEFBQcB + AQR3MHUwcwYIKwYBBQUHMAKGZ2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv + cHMvY2VydHMvQXp1cmUlMjBWaXJ0dWFsJTIwVFBNJTIwUm9vdCUyMENlcnRpZmlj + YXRlJTIwQXV0aG9yaXR5JTIwMjAyMy5jcnQwDQYJKoZIhvcNAQEMBQADggIBADv8 + FY5P/MusECLp6meis4Ujpce/2mq9bEBnSTV/qjTv1i59StJbqCD1uUXTPddeOnFl + jkFai5y09zMka+aJnhhS8PIHhbgFSI4SKCjdC1CVZOQoPTTM/q3/SfJoZ2Zn/PGH + 2z+CxFsj7p2CNs843+swiUc+klA+X2hVy4HKEplh5HQmGPK6I3PBT/4P0PqBpqeB + 2ylTEMvuhSYtDnTYTGOUCUpnEYeY/THBMLsHVL0+I/Ti5irNaRwurpP3bIPzZd3G + SO+EjQfOq/lGj3f7ipbLdwovIMVtbYuThlRK9AjsiS/mwGIZeuIiRy8T2KUqxkq/ + 4Kt6i8gcIAKBgAx0/5BMbLf24KJHjtv7NN/0RissF6qOPa1ivk/rQwfr/FCilND5 + qvnHAgnHPSBKeo6cNQ1YjGl5KAQZuXxl2HWR/Pnv5ukUiBzdkozB+npXaTVQHmTx + NUIRTErbYuCYW+HASCxnhZMYcLha7lM/X6Q5NMEOgz3dPA8mkxGCInZfjYZ2JlDb + Rx9ks9aRqFpoxHuyBxas3Fycuyz77YFE6rr+p7uAQ3o+dZqbO0RatvsNUpO6aTH6 + lUl8xyTwGMw2WV3ATxAaUCtVOAA8xVpJo9Z19PSfepho+g6VKku7eXHPqGR/p9++ + MIy/GuVREnFXQXQt5Ut3pYlREPiZ/k+57avJoQhv + -----END CERTIFICATE----- + quote: + signature: + - 107 + - 55 + - 140 + - 202 + - 138 + - 220 + - 148 + - 102 + - 210 + - 156 + - 116 + - 45 + - 158 + - 25 + - 144 + - 202 + - 165 + - 183 + - 255 + - 179 + - 10 + - 49 + - 114 + - 232 + - 195 + - 54 + - 142 + - 20 + - 157 + - 86 + - 177 + - 166 + - 0 + - 229 + - 35 + - 116 + - 141 + - 173 + - 222 + - 109 + - 103 + - 184 + - 10 + - 164 + - 184 + - 241 + - 125 + - 180 + - 215 + - 53 + - 166 + - 255 + - 56 + - 109 + - 205 + - 92 + - 76 + - 32 + - 134 + - 253 + - 82 + - 75 + - 217 + - 238 + - 57 + - 52 + - 6 + - 158 + - 41 + - 117 + - 195 + - 188 + - 196 + - 41 + - 43 + - 133 + - 246 + - 111 + - 52 + - 160 + - 176 + - 109 + - 174 + - 51 + - 81 + - 228 + - 247 + - 165 + - 116 + - 240 + - 196 + - 212 + - 50 + - 193 + - 84 + - 233 + - 79 + - 33 + - 189 + - 21 + - 196 + - 47 + - 163 + - 214 + - 99 + - 92 + - 157 + - 52 + - 141 + - 61 + - 66 + - 254 + - 38 + - 114 + - 227 + - 35 + - 159 + - 127 + - 155 + - 188 + - 98 + - 143 + - 130 + - 4 + - 224 + - 200 + - 16 + - 94 + - 19 + - 75 + - 90 + - 82 + - 69 + - 249 + - 210 + - 187 + - 27 + - 209 + - 102 + - 4 + - 186 + - 30 + - 189 + - 152 + - 57 + - 24 + - 171 + - 18 + - 133 + - 49 + - 139 + - 7 + - 158 + - 92 + - 32 + - 25 + - 191 + - 17 + - 107 + - 122 + - 206 + - 215 + - 119 + - 74 + - 31 + - 48 + - 69 + - 113 + - 8 + - 151 + - 118 + - 140 + - 79 + - 36 + - 207 + - 9 + - 181 + - 206 + - 214 + - 86 + - 19 + - 72 + - 20 + - 238 + - 195 + - 45 + - 212 + - 62 + - 249 + - 158 + - 115 + - 5 + - 57 + - 178 + - 239 + - 154 + - 184 + - 199 + - 50 + - 160 + - 134 + - 255 + - 222 + - 113 + - 235 + - 70 + - 14 + - 5 + - 113 + - 76 + - 64 + - 139 + - 2 + - 200 + - 238 + - 222 + - 199 + - 253 + - 100 + - 4 + - 221 + - 110 + - 48 + - 195 + - 94 + - 219 + - 27 + - 185 + - 68 + - 113 + - 91 + - 235 + - 46 + - 131 + - 27 + - 59 + - 135 + - 231 + - 28 + - 94 + - 232 + - 160 + - 88 + - 103 + - 17 + - 219 + - 28 + - 188 + - 160 + - 75 + - 169 + - 23 + - 119 + - 204 + - 16 + - 80 + message: + - 255 + - 84 + - 67 + - 71 + - 128 + - 24 + - 0 + - 34 + - 0 + - 11 + - 32 + - 238 + - 106 + - 227 + - 54 + - 240 + - 112 + - 104 + - 240 + - 98 + - 236 + - 162 + - 29 + - 19 + - 26 + - 100 + - 156 + - 156 + - 183 + - 20 + - 61 + - 241 + - 179 + - 250 + - 54 + - 18 + - 16 + - 255 + - 115 + - 167 + - 84 + - 198 + - 0 + - 32 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 42 + - 251 + - 230 + - 0 + - 0 + - 0 + - 1 + - 0 + - 0 + - 0 + - 0 + - 1 + - 32 + - 32 + - 3 + - 18 + - 0 + - 18 + - 0 + - 3 + - 0 + - 0 + - 0 + - 1 + - 0 + - 11 + - 3 + - 255 + - 255 + - 255 + - 0 + - 32 + - 38 + - 42 + - 174 + - 240 + - 151 + - 124 + - 14 + - 218 + - 25 + - 245 + - 105 + - 122 + - 119 + - 110 + - 24 + - 175 + - 196 + - 34 + - 48 + - 231 + - 119 + - 136 + - 191 + - 115 + - 252 + - 186 + - 175 + - 36 + - 113 + - 213 + - 167 + - 3 + pcrs: + - - 70 + - 124 + - 113 + - 171 + - 40 + - 28 + - 37 + - 91 + - 2 + - 170 + - 185 + - 156 + - 95 + - 248 + - 225 + - 129 + - 219 + - 145 + - 246 + - 8 + - 142 + - 144 + - 127 + - 26 + - 102 + - 170 + - 9 + - 201 + - 195 + - 130 + - 60 + - 2 + - - 57 + - 180 + - 162 + - 31 + - 73 + - 139 + - 102 + - 114 + - 168 + - 230 + - 179 + - 178 + - 177 + - 200 + - 10 + - 138 + - 185 + - 145 + - 19 + - 155 + - 145 + - 183 + - 70 + - 79 + - 148 + - 71 + - 194 + - 149 + - 134 + - 80 + - 57 + - 171 + - - 49 + - 186 + - 178 + - 218 + - 28 + - 154 + - 138 + - 96 + - 89 + - 234 + - 197 + - 154 + - 75 + - 126 + - 93 + - 236 + - 6 + - 81 + - 144 + - 168 + - 52 + - 252 + - 225 + - 139 + - 235 + - 52 + - 191 + - 92 + - 205 + - 62 + - 52 + - 67 + - - 61 + - 69 + - 140 + - 254 + - 85 + - 204 + - 3 + - 234 + - 31 + - 68 + - 63 + - 21 + - 98 + - 190 + - 236 + - 141 + - 245 + - 28 + - 117 + - 225 + - 74 + - 159 + - 207 + - 154 + - 114 + - 52 + - 161 + - 63 + - 25 + - 142 + - 121 + - 105 + - - 206 + - 45 + - 142 + - 144 + - 157 + - 76 + - 92 + - 250 + - 197 + - 218 + - 245 + - 12 + - 210 + - 61 + - 191 + - 199 + - 160 + - 112 + - 102 + - 172 + - 181 + - 76 + - 152 + - 63 + - 249 + - 3 + - 126 + - 54 + - 191 + - 140 + - 176 + - 81 + - - 21 + - 86 + - 220 + - 212 + - 123 + - 121 + - 5 + - 115 + - 154 + - 22 + - 145 + - 143 + - 184 + - 250 + - 180 + - 170 + - 189 + - 117 + - 160 + - 64 + - 246 + - 168 + - 34 + - 107 + - 101 + - 239 + - 176 + - 41 + - 25 + - 152 + - 113 + - 142 + - - 17 + - 171 + - 154 + - 50 + - 73 + - 26 + - 60 + - 122 + - 172 + - 185 + - 197 + - 165 + - 252 + - 93 + - 17 + - 157 + - 165 + - 255 + - 111 + - 199 + - 41 + - 15 + - 107 + - 91 + - 253 + - 180 + - 245 + - 205 + - 225 + - 232 + - 56 + - 2 + - - 13 + - 43 + - 127 + - 116 + - 166 + - 231 + - 145 + - 16 + - 149 + - 204 + - 19 + - 94 + - 114 + - 164 + - 92 + - 90 + - 151 + - 215 + - 225 + - 123 + - 225 + - 28 + - 33 + - 135 + - 99 + - 240 + - 232 + - 150 + - 186 + - 79 + - 159 + - 31 + - - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - - 6 + - 38 + - 216 + - 212 + - 48 + - 215 + - 11 + - 197 + - 235 + - 67 + - 97 + - 66 + - 77 + - 135 + - 231 + - 57 + - 86 + - 203 + - 175 + - 7 + - 166 + - 192 + - 189 + - 111 + - 108 + - 186 + - 26 + - 162 + - 79 + - 112 + - 99 + - 17 + - - 120 + - 225 + - 81 + - 169 + - 179 + - 82 + - 147 + - 190 + - 85 + - 214 + - 93 + - 168 + - 82 + - 174 + - 165 + - 199 + - 151 + - 252 + - 241 + - 243 + - 248 + - 79 + - 126 + - 254 + - 51 + - 21 + - 211 + - 18 + - 232 + - 219 + - 209 + - 52 + - - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - - 241 + - 161 + - 66 + - 197 + - 53 + - 134 + - 231 + - 226 + - 34 + - 62 + - 199 + - 78 + - 95 + - 77 + - 26 + - 73 + - 66 + - 149 + - 107 + - 31 + - 217 + - 172 + - 120 + - 250 + - 252 + - 223 + - 133 + - 17 + - 122 + - 163 + - 69 + - 218 + - - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - - 48 + - 111 + - 157 + - 139 + - 148 + - 241 + - 125 + - 147 + - 220 + - 110 + - 124 + - 248 + - 245 + - 199 + - 157 + - 101 + - 46 + - 180 + - 198 + - 196 + - 209 + - 61 + - 226 + - 221 + - 220 + - 36 + - 175 + - 65 + - 110 + - 19 + - 236 + - 175 + - - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - 255 + - - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + event_log: + [] + instance_info: null From f09edf1a814ea0e113f34c635a2b8a8a1411786c Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Mon, 8 Jun 2026 21:19:31 +0800 Subject: [PATCH 4/9] fix clippy: box MaaError make from maaerror box fix clippy: only box MaaError::AiaFetch --- crates/attestation/src/azure/ak_certificate.rs | 2 +- crates/attestation/src/azure/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index 049e7e3..bc2b48f 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -157,7 +157,7 @@ fn fetch_certificate_der(url: &str) -> Result, MaaError> { let response = ureq::get(url) .timeout(Duration::from_secs(10)) .call() - .map_err(|err| MaaError::AiaFetch { url: url.to_string(), source: err })?; + .map_err(|err| MaaError::AiaFetch { url: url.to_string(), source: Box::new(err) })?; let mut bytes = Vec::new(); response.into_reader().take(1024 * 1024).read_to_end(&mut bytes)?; diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 4bf5065..581b642 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -504,7 +504,7 @@ pub enum MaaError { #[error("AIA URL is not HTTP(S): {url}")] UnsupportedAiaUrl { url: String }, #[error("Failed to fetch AIA issuer certificate from {url}: {source}")] - AiaFetch { url: String, source: ureq::Error }, + AiaFetch { url: String, source: Box }, #[error("IO: {0}")] Io(#[from] std::io::Error), #[error("vTPM quote: {0}")] From bd465dd276595223418a990bd8c3649197db94fc Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Mon, 8 Jun 2026 22:26:42 +0800 Subject: [PATCH 5/9] fix(attestation): harden Azure AK issuer AIA fetching Consolidate AK intermediate bounds into a single MAX_EVIDENCE_AK_INTERMEDIATE_CERTIFICATES limit shared by generation and verification, so generated evidence cannot exceed what the verifier accepts. Fail closed when the AK issuer chain is incomplete or exceeds that limit instead of silently returning a partial chain. When following AIA CA Issuers URLs, try alternate URLs sequentially as fallbacks if earlier URLs fail, and trim fetched DER to the parsed certificate before serializing it as evidence. Box the large ureq AIA fetch error inside MaaError to keep the error enum size small enough for clippy. --- .../attestation/src/azure/ak_certificate.rs | 103 ++++++++++++------ crates/attestation/src/azure/mod.rs | 23 ++-- 2 files changed, 88 insertions(+), 38 deletions(-) diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index bc2b48f..a84e126 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -6,7 +6,7 @@ use tokio_rustls::rustls::pki_types::{CertificateDer, TrustAnchor, UnixTime}; use webpki::EndEntityCert; use x509_parser::{extensions::GeneralName, prelude::*}; -use crate::azure::{MaaError, nv_index}; +use crate::azure::{MAX_EVIDENCE_AK_INTERMEDIATE_CERTIFICATES, MaaError, nv_index}; /// The NV index where we expect to be able to read the AK certificate from /// the vTPM @@ -95,31 +95,68 @@ pub(crate) fn verify_ak_cert_with_azure_roots( pub(crate) fn fetch_ak_intermediates_from_aia( ak_cert: &X509Certificate<'_>, ) -> Result>, MaaError> { - const MAX_AIA_DEPTH: usize = 6; - let mut intermediates = Vec::new(); - let mut issuer_url = first_ca_issuers_url(ak_cert); - - for _ in 0..MAX_AIA_DEPTH { - let Some(url) = issuer_url else { - break; - }; + let mut issuer_urls = ca_issuers_urls(ak_cert); - tracing::debug!("Fetching Azure vTPM AK issuer certificate from {url}"); - let issuer_der = fetch_certificate_der(&url)?; - let (_, issuer_cert) = X509Certificate::from_der(&issuer_der)?; + while !issuer_urls.is_empty() { + let fetched_issuer = fetch_first_available_issuer(&issuer_urls)?; // Stop before adding the self-signed root. The root is already pinned // in AZURE_ROOT_ANCHORS and should not come from untrusted evidence. - if issuer_cert.subject() == issuer_cert.issuer() { - break; + if fetched_issuer.is_self_signed { + return Ok(intermediates); + } + + // This check must happen after the root check above. The self-signed + // root is fetched to prove the AIA walk reached a trust anchor, but it + // is not serialized as evidence and does not count toward the + // intermediate certificate limit. + if intermediates.len() == MAX_EVIDENCE_AK_INTERMEDIATE_CERTIFICATES { + return Err(MaaError::AkIssuerChainTooDeep { + max_depth: MAX_EVIDENCE_AK_INTERMEDIATE_CERTIFICATES, + }); } - issuer_url = first_ca_issuers_url(&issuer_cert); - intermediates.push(issuer_der); + issuer_urls = fetched_issuer.ca_issuers_urls; + intermediates.push(fetched_issuer.der); } - Ok(intermediates) + Err(MaaError::AkIssuerChainIncomplete) +} + +struct FetchedIssuer { + der: Vec, + ca_issuers_urls: Vec, + is_self_signed: bool, +} + +fn fetch_first_available_issuer(urls: &[String]) -> Result { + let mut last_error = None; + + for url in urls { + match fetch_issuer(url) { + Ok(issuer) => return Ok(issuer), + Err(err) => { + tracing::debug!( + "Failed to fetch Azure vTPM AK issuer certificate from {url}: {err}" + ); + last_error = Some(err); + } + } + } + + Err(last_error.unwrap_or(MaaError::AkIssuerChainIncomplete)) +} + +fn fetch_issuer(url: &str) -> Result { + tracing::debug!("Fetching Azure vTPM AK issuer certificate from {url}"); + let der = fetch_certificate_der(url)?; + let (remaining_bytes, cert) = X509Certificate::from_der(&der)?; + let cert_len = der.len() - remaining_bytes.len(); + let is_self_signed = cert.subject() == cert.issuer(); + let ca_issuers_urls = ca_issuers_urls(&cert); + + Ok(FetchedIssuer { der: der[..cert_len].to_vec(), ca_issuers_urls, is_self_signed }) } /// Retrieve an AK certificate from the vTPM @@ -129,24 +166,28 @@ pub(crate) fn read_ak_certificate_from_tpm() -> Result, tss_esapi::Error nv_index::read_nv_index(&mut context, TPM_AK_CERT_IDX) } -fn first_ca_issuers_url(cert: &X509Certificate<'_>) -> Option { - cert.extensions().iter().find_map(|extension| { - let ParsedExtension::AuthorityInfoAccess(aia) = extension.parsed_extension() else { - return None; - }; - - aia.iter().find_map(|desc| { - if desc.access_method.to_id_string() != "1.3.6.1.5.5.7.48.2" { - return None; - } - - let GeneralName::URI(uri) = &desc.access_location else { +fn ca_issuers_urls(cert: &X509Certificate<'_>) -> Vec { + cert.extensions() + .iter() + .filter_map(|extension| { + let ParsedExtension::AuthorityInfoAccess(aia) = extension.parsed_extension() else { return None; }; - Some((*uri).to_string()) + Some(aia.iter().filter_map(|desc| { + if desc.access_method.to_id_string() != "1.3.6.1.5.5.7.48.2" { + return None; + } + + let GeneralName::URI(uri) = &desc.access_location else { + return None; + }; + + Some((*uri).to_string()) + })) }) - }) + .flatten() + .collect() } fn fetch_certificate_der(url: &str) -> Result, MaaError> { diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 581b642..c7ccae8 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -63,11 +63,14 @@ struct TpmAttest { instance_info: Option>, } -/// Maximum number of evidence-supplied AK intermediate certificates -/// accepted during verification. Azure chains currently observed use 2 -/// intermediates; this allows some rotation/cross-signing headroom while -/// bounding peer-controlled evidence. -const MAX_AK_INTERMEDIATE_CERTIFICATES: usize = 4; +/// Maximum number of Azure vTPM AK intermediate certificates to fetch +/// during generation and accept during verification. +/// +/// This is a defensive resource/cycle bound for following untrusted AIA +/// URLs and parsing peer-supplied evidence. Azure chains currently observed +/// use 1-2 intermediates. Verification still pins Azure roots and fails +/// closed if this bound prevents collecting a complete chain. +const MAX_EVIDENCE_AK_INTERMEDIATE_CERTIFICATES: usize = 8; fn deserialize_ak_intermediate_certificates_pem<'de, D>( deserializer: D, @@ -76,11 +79,11 @@ where D: serde::Deserializer<'de>, { let certificates = Vec::::deserialize(deserializer)?; - if certificates.len() > MAX_AK_INTERMEDIATE_CERTIFICATES { + if certificates.len() > MAX_EVIDENCE_AK_INTERMEDIATE_CERTIFICATES { return Err(serde::de::Error::custom(format_args!( "too many AK intermediate certificates in evidence: {} > {}", certificates.len(), - MAX_AK_INTERMEDIATE_CERTIFICATES + MAX_EVIDENCE_AK_INTERMEDIATE_CERTIFICATES ))); } Ok(certificates) @@ -505,6 +508,12 @@ pub enum MaaError { UnsupportedAiaUrl { url: String }, #[error("Failed to fetch AIA issuer certificate from {url}: {source}")] AiaFetch { url: String, source: Box }, + #[error( + "Azure vTPM AK issuer chain exceeded maximum intermediate certificate count: {max_depth}" + )] + AkIssuerChainTooDeep { max_depth: usize }, + #[error("Azure vTPM AK issuer chain ended before reaching a self-signed root certificate")] + AkIssuerChainIncomplete, #[error("IO: {0}")] Io(#[from] std::io::Error), #[error("vTPM quote: {0}")] From fb10e9095aebc8111a6035c292fffdd011351ab9 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Mon, 8 Jun 2026 22:31:25 +0800 Subject: [PATCH 6/9] add AIA_CA_ISSUERS_ACCESS_METHOD_OID variable --- crates/attestation/src/azure/ak_certificate.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index a84e126..7a08234 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -12,6 +12,13 @@ use crate::azure::{MAX_EVIDENCE_AK_INTERMEDIATE_CERTIFICATES, MaaError, nv_index /// the vTPM const TPM_AK_CERT_IDX: u32 = 0x1C101D0; +/// id-ad-caIssuers access method OID used in X.509 Authority Information +/// Access extensions to point to issuer certificate URLs. +/// +/// Defined by RFC 5280 as `{ id-ad 2 }`, where `id-ad` is `1.3.6.1.5.5.7.48`. +/// https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1 +const AIA_CA_ISSUERS_ACCESS_METHOD_OID: &str = "1.3.6.1.5.5.7.48.2"; + // microsoftRSADevicesRoot2021 is the root CA certificate used to sign Azure // TDX vTPM certificates. This is different from the AME root CA used by // TrustedLaunch VMs. The certificate can be downloaded from: @@ -175,7 +182,7 @@ fn ca_issuers_urls(cert: &X509Certificate<'_>) -> Vec { }; Some(aia.iter().filter_map(|desc| { - if desc.access_method.to_id_string() != "1.3.6.1.5.5.7.48.2" { + if desc.access_method.to_id_string() != AIA_CA_ISSUERS_ACCESS_METHOD_OID { return None; } From dc6319aac2ea79404ca8d306f66527ee78e312cb Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Mon, 8 Jun 2026 22:38:50 +0800 Subject: [PATCH 7/9] add comment explaining the PEM guard --- crates/attestation/src/azure/ak_certificate.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index 7a08234..8dacbc6 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -15,8 +15,8 @@ const TPM_AK_CERT_IDX: u32 = 0x1C101D0; /// id-ad-caIssuers access method OID used in X.509 Authority Information /// Access extensions to point to issuer certificate URLs. /// -/// Defined by RFC 5280 as `{ id-ad 2 }`, where `id-ad` is `1.3.6.1.5.5.7.48`. -/// https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1 +/// Defined by RFC 5280 as `{ id-ad 2 }`, where `id-ad` is +/// `1.3.6.1.5.5.7.48`. https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.2.1 const AIA_CA_ISSUERS_ACCESS_METHOD_OID: &str = "1.3.6.1.5.5.7.48.2"; // microsoftRSADevicesRoot2021 is the root CA certificate used to sign Azure @@ -210,6 +210,9 @@ fn fetch_certificate_der(url: &str) -> Result, MaaError> { let mut bytes = Vec::new(); response.into_reader().take(1024 * 1024).read_to_end(&mut bytes)?; + // RFC 5280 id-ad-caIssuers HTTP URLs are expected to serve DER-encoded + // certificates. Accept explicit PEM armor as a lenient fallback for + // endpoints that serve PEM anyway. if bytes.starts_with(b"-----BEGIN") { let (_type_label, der) = pem_rfc7468::decode_vec(&bytes)?; Ok(der) From 2ef3e8554d86256660bb97c446d130f4c812a6aa Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Mon, 8 Jun 2026 22:58:59 +0800 Subject: [PATCH 8/9] docs(azure_attn): document potential network fetches --- crates/attestation/src/azure/mod.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index c7ccae8..f8ed994 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -99,7 +99,17 @@ struct PreparedAzureAttestation { tpm_attestation: TpmAttest, } -/// Generate a TDX attestation on Azure +/// Generate a TDX attestation on Azure. +/// +/// This may perform network calls. Azure's IMDS is queried for the TDX +/// quote, and the vTPM AK certificate's Authority Information Access (AIA) +/// CA Issuers URLs are followed to include the observed issuer +/// intermediates in the evidence. +/// +/// The intermediates are included as untrusted evidence so verifiers do not +/// need network access or AIA-fetching logic. This keeps verification +/// deterministic and easier to reuse in constrained verifier environments +/// such as TEEs, onchain verification, or zero-knowledge proof generation. pub fn create_azure_attestation(input_data: [u8; 64]) -> Result, MaaError> { let hcl_report_bytes = vtpm::get_report_with_report_data(&input_data)?; From 01e60d44c28fe3272b8628dff0d57e6ac6fa8c12 Mon Sep 17 00:00:00 2001 From: Samuel Laferriere <9342524+samlaf@users.noreply.github.com> Date: Mon, 8 Jun 2026 23:01:56 +0800 Subject: [PATCH 9/9] test(attestation): cover Azure AK issuer fetch fallbacks Add local HTTP server tests for AK issuer fetching to verify that AIA caIssuers URLs are tried sequentially when earlier URLs fail, and that explicit PEM responses are accepted as a lenient fallback to DER. Keep the tests deterministic by using a local server instead of depending on Azure or Microsoft CDN availability. --- .../attestation/src/azure/ak_certificate.rs | 127 ++++++++++++++++-- 1 file changed, 115 insertions(+), 12 deletions(-) diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index 8dacbc6..6ce6faa 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -243,16 +243,119 @@ impl webpki::ExtendedKeyUsageValidator for AnyEku { } #[cfg(test)] -#[tokio::test] -async fn root_should_be_fresh() { - let response = reqwest::get( - "http://www.microsoft.com/pkiops/certs/Microsoft%20RSA%20Devices%20Root%20CA%202021.crt", - ) - .await - .unwrap(); - let ca_der = response.bytes().await.unwrap(); - assert_eq!( - pem_rfc7468::decode_vec(MICROSOFT_RSA_DEVICES_ROOT_2021.as_bytes()).unwrap().1, - ca_der - ); +mod tests { + use std::{ + io::{Read, Write}, + net::TcpListener, + thread, + time::Duration, + }; + + use super::*; + + #[tokio::test] + async fn root_should_be_fresh() { + let response = reqwest::get( + "http://www.microsoft.com/pkiops/certs/Microsoft%20RSA%20Devices%20Root%20CA%202021.crt", + ) + .await + .unwrap(); + let ca_der = response.bytes().await.unwrap(); + assert_eq!( + pem_rfc7468::decode_vec(MICROSOFT_RSA_DEVICES_ROOT_2021.as_bytes()).unwrap().1, + ca_der + ); + } + + #[test] + fn fetch_first_available_issuer_tries_later_urls_after_failure() { + let (_type_label, root_der) = + pem_rfc7468::decode_vec(AZURE_VIRTUAL_TPM_ROOT_2023.as_bytes()).unwrap(); + let server_url = spawn_test_http_server(vec![ + ("/primary.cer", 500, b"unavailable".to_vec()), + ("/secondary.cer", 200, root_der.clone()), + ]); + + let fetched = fetch_first_available_issuer(&[ + format!("{server_url}/primary.cer"), + format!("{server_url}/secondary.cer"), + ]) + .unwrap(); + + assert!(fetched.is_self_signed); + assert_eq!(fetched.der, root_der); + } + + #[test] + fn fetch_certificate_der_accepts_explicit_pem() { + let (_type_label, root_der) = + pem_rfc7468::decode_vec(AZURE_VIRTUAL_TPM_ROOT_2023.as_bytes()).unwrap(); + let server_url = spawn_test_http_server(vec![( + "/root.pem", + 200, + AZURE_VIRTUAL_TPM_ROOT_2023.as_bytes().to_vec(), + )]); + + let fetched_der = fetch_certificate_der(&format!("{server_url}/root.pem")).unwrap(); + + assert_eq!(fetched_der, root_der); + } + + fn spawn_test_http_server(routes: Vec<(&'static str, u16, Vec)>) -> String { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let address = listener.local_addr().unwrap(); + + thread::spawn(move || { + for _ in 0..routes.len() { + let (mut stream, _peer) = listener.accept().unwrap(); + stream.set_read_timeout(Some(Duration::from_secs(2))).unwrap(); + + let mut request = [0u8; 4096]; + let bytes_read = stream.read(&mut request).unwrap(); + let request = String::from_utf8_lossy(&request[..bytes_read]); + let path = request_path(&request); + + let (status, body) = route_response(&routes, path); + write_http_response(&mut stream, status, body); + } + }); + + format!("http://{address}") + } + + fn request_path(request: &str) -> &str { + // HTTP/1.1 request line format is: ` `. + // The local test server only needs the request target, e.g. `/root.pem`. + request.lines().next().and_then(|line| line.split_ascii_whitespace().nth(1)).unwrap_or("/") + } + + fn route_response<'a>( + routes: &'a [(&'static str, u16, Vec)], + path: &str, + ) -> (u16, &'a [u8]) { + routes + .iter() + .find(|(route_path, _status, _body)| *route_path == path) + .map_or((404, b"not found".as_slice()), |(_route_path, status, body)| { + (*status, body.as_slice()) + }) + } + + fn write_http_response(stream: &mut impl Write, status: u16, body: &[u8]) { + let headers = format!( + "HTTP/1.1 {status} {}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n", + status_text(status), + body.len() + ); + stream.write_all(headers.as_bytes()).unwrap(); + stream.write_all(body).unwrap(); + } + + fn status_text(status: u16) -> &'static str { + match status { + 200 => "OK", + 500 => "Internal Server Error", + _ => "Not Found", + } + } }