From 38e80bbee5de39462ed5c40a1349efa2300a541e Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 3 Jun 2026 10:26:47 +0200 Subject: [PATCH 01/35] First step towards integrating easy-tee/attest --- Cargo.lock | 295 ++++++++++++++++++++++++++++++++- crates/attestation/Cargo.toml | 2 + crates/attestation/src/dcap.rs | 31 ++-- crates/attestation/src/lib.rs | 62 +++++-- crates/attested-tls/src/lib.rs | 1 + crates/mock-tdx/Cargo.toml | 1 + crates/mock-tdx/src/lib.rs | 32 ++-- 7 files changed, 381 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9a940e..2038088 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,6 +153,15 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anes" version = "0.1.6" @@ -290,11 +299,43 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "attest-measure" +version = "0.0.1" +source = "git+https://github.com/easy-tee/attest.git?branch=ah%2Fbetter-interface#9436797ccde6354d54e1b912bb116cb66678c33d" +dependencies = [ + "anyhow", + "attest-types", + "authenticode", + "crc32fast", + "hex", + "hex-literal", + "object", + "serde", + "serde_json", + "serde_with", + "sha2", + "thiserror 2.0.18", +] + +[[package]] +name = "attest-types" +version = "0.0.1" +source = "git+https://github.com/easy-tee/attest.git?branch=ah%2Fbetter-interface#9436797ccde6354d54e1b912bb116cb66678c33d" +dependencies = [ + "parity-scale-codec", + "serde", + "serde_json", + "serde_with", +] + [[package]] name = "attestation" version = "0.0.1" dependencies = [ "anyhow", + "attest-measure", + "attest-types", "az-tdx-vtpm", "base64 0.22.1", "dcap-qvl 0.3.12 (git+https://github.com/Phala-Network/dcap-qvl.git?rev=f1dcc65371e941a7b83e3234833d23a1fb232ab1)", @@ -346,6 +387,24 @@ dependencies = [ "yasna 0.5.2", ] +[[package]] +name = "authenticode" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86c421a87e3dd1a3024c86e0787106b6ba40d9b434fe0ebeffbd24a242dc144d" +dependencies = [ + "cms", + "const-oid", + "der", + "digest", + "object", + "rsa", + "sha1", + "sha2", + "spki", + "x509-cert", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -682,6 +741,15 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -785,8 +853,10 @@ version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ + "iana-time-zone", "num-traits", "serde", + "windows-link", ] [[package]] @@ -850,6 +920,18 @@ dependencies = [ "cc", ] +[[package]] +name = "cms" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b77c319abfd5219629c45c34c89ba945ed3c5e49fcde9d16b6c3885f118a730" +dependencies = [ + "const-oid", + "der", + "spki", + "x509-cert", +] + [[package]] name = "codicon" version = "3.0.0" @@ -908,6 +990,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1255,6 +1343,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", + "serde_core", ] [[package]] @@ -1389,6 +1478,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "ecdsa" version = "0.16.9" @@ -1821,6 +1916,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.15.5" @@ -1854,6 +1955,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" + [[package]] name = "hex_fmt" version = "0.3.0" @@ -2048,6 +2155,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.1.1" @@ -2185,6 +2316,17 @@ dependencies = [ "syn", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.13.0" @@ -2483,6 +2625,7 @@ dependencies = [ name = "mock-tdx" version = "0.0.1" dependencies = [ + "attest-types", "axum", "dcap-qvl 0.3.12 (git+https://github.com/Phala-Network/dcap-qvl.git?rev=f1dcc65371e941a7b83e3234833d23a1fb232ab1)", "hex", @@ -2648,6 +2791,15 @@ dependencies = [ "libm", ] +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + [[package]] name = "oid" version = "0.2.1" @@ -3309,6 +3461,26 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "regex" version = "1.12.3" @@ -3584,6 +3756,30 @@ dependencies = [ "syn", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -3696,7 +3892,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap", + "indexmap 2.13.0", "itoa", "memchr", "serde", @@ -3727,6 +3923,38 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.13.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sev" version = "6.3.1" @@ -4195,7 +4423,7 @@ version = "0.25.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" dependencies = [ - "indexmap", + "indexmap 2.13.0", "toml_datetime", "toml_parser", "winnow", @@ -4612,7 +4840,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap", + "indexmap 2.13.0", "wasm-encoder", "wasmparser", ] @@ -4625,7 +4853,7 @@ checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ "bitflags 2.11.0", "hashbrown 0.15.5", - "indexmap", + "indexmap 2.13.0", "semver", ] @@ -4682,12 +4910,65 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -4883,7 +5164,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", - "indexmap", + "indexmap 2.13.0", "prettyplease", "syn", "wasm-metadata", @@ -4914,7 +5195,7 @@ checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", "bitflags 2.11.0", - "indexmap", + "indexmap 2.13.0", "log", "serde", "serde_derive", @@ -4933,7 +5214,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap", + "indexmap 2.13.0", "log", "semver", "serde", diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml index f27bcb5..866efb7 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -13,6 +13,8 @@ pccs = { workspace = true } mock-tdx = { workspace = true, optional = true } tokio = { workspace = true, features = ["fs"] } tokio-rustls = { workspace = true, default-features = false } +attest-types = { git = "https://github.com/easy-tee/attest.git", branch = "ah/better-interface" } +attest-measure = {git = "https://github.com/easy-tee/attest.git", branch = "ah/better-interface" } anyhow = "1.0.100" pem-rfc7468 = { version = "0.7.0", features = ["std"] } diff --git a/crates/attestation/src/dcap.rs b/crates/attestation/src/dcap.rs index dca2c10..10b52f8 100644 --- a/crates/attestation/src/dcap.rs +++ b/crates/attestation/src/dcap.rs @@ -1,5 +1,6 @@ //! Data Center Attestation Primitives (DCAP) evidence generation and //! verification +use attest_types::AttestationEvidence; use dcap_qvl::{ QuoteCollateralV3, collateral::get_collateral_for_fmspc, @@ -21,21 +22,24 @@ const AZURE_BAD_FMSPC: &str = "90C06F000000"; pub const PCS_URL: &str = "https://api.trustedservices.intel.com"; /// Generate a TDX quote -pub fn create_dcap_attestation(input_data: [u8; 64]) -> Result, AttestationError> { - let quote = generate_quote(input_data)?; - tracing::info!("Generated TDX quote of {} bytes", quote.len()); - Ok(quote) +pub fn create_dcap_attestation( + input_data: [u8; 64], +) -> Result { + let attestation_evidence = generate_quote(input_data)?; + tracing::info!("Generated TDX quote of {} bytes", attestation_evidence.quote.len()); + Ok(attestation_evidence) } /// Verify a DCAP TDX quote, and return the measurement values #[cfg(not(any(test, feature = "mock")))] pub async fn verify_dcap_attestation( - input: Vec, + attestation_evidence: AttestationEvidence, expected_input_data: [u8; 64], pccs: Option, ) -> Result { let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?.as_secs(); let override_azure_outdated_tcb = false; + let input = attestation_evidence.quote; verify_dcap_attestation_with_given_timestamp( input, expected_input_data, @@ -206,11 +210,11 @@ fn verify_dcap_attestation_with_collateral_and_timestamp( #[cfg(any(test, feature = "mock"))] pub async fn verify_dcap_attestation( - input: Vec, + attestation_evidence: AttestationEvidence, expected_input_data: [u8; 64], pccs: Option, ) -> Result { - let quote = Quote::parse(&input)?; + let quote = Quote::parse(&attestation_evidence.quote)?; let ca = quote.ca()?; let fmspc = hex::encode_upper(quote.fmspc()?); let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?.as_secs(); @@ -221,7 +225,7 @@ pub async fn verify_dcap_attestation( mock_tdx::mock_collateral() }; let verifier = mock_tdx::mock_dcap_verifier(); - verifier.verify(&input, &collateral, now)?; + verifier.verify(&attestation_evidence.quote, &collateral, now)?; let measurements = MultiMeasurements::from_dcap_qvl_quote("e)?; if get_quote_input_data(quote.report) != expected_input_data { @@ -254,7 +258,7 @@ pub fn verify_dcap_attestation_sync( /// Create a mock quote for testing on non-confidential hardware #[cfg(any(test, feature = "mock"))] -fn generate_quote(input: [u8; 64]) -> Result, tdx_attest::TdxAttestError> { +fn generate_quote(input: [u8; 64]) -> Result { generate_mock_tdx_quote(input).map_err(|error| { tdx_attest::TdxAttestError::QuoteFailure(format!("mock-tdx quote generation: {error}")) }) @@ -262,8 +266,13 @@ fn generate_quote(input: [u8; 64]) -> Result, tdx_attest::TdxAttestError /// Create a quote #[cfg(not(any(test, feature = "mock")))] -fn generate_quote(input: [u8; 64]) -> Result, tdx_attest::TdxAttestError> { - tdx_attest::get_quote(&input) +fn generate_quote(input: [u8; 64]) -> Result { + use attest_measure::platform; + + Ok(AttestationEvidence { + quote: tdx_attest::get_quote(&input)?, + platform: platform::metadata_for(attest_types::AttestationType::GcpTdx).unwrap(), + }) } /// Given a [Report] get the input data regardless of report type diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 73bc5ba..ceb1643 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -12,6 +12,7 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; +use attest_types::{AttestationEvidence, PlatformMetadata}; use measurements::MultiMeasurements; use parity_scale_codec::{Decode, Encode}; use pccs::{Pccs, PccsError}; @@ -31,13 +32,18 @@ pub struct AttestationExchangeMessage { /// The attestation evidence as bytes - in the case of DCAP this is a /// quote pub attestation: Vec, + pub platform_metadata: Option, } impl AttestationExchangeMessage { /// Create an empty attestation payload for the case that we are running /// in a non-confidential environment pub fn without_attestation() -> Self { - Self { attestation_type: AttestationType::None, attestation: Vec::new() } + Self { + attestation_type: AttestationType::None, + attestation: Vec::new(), + platform_metadata: None, + } } /// Extract the measurements from the attestation, if present, but do @@ -64,6 +70,21 @@ impl AttestationExchangeMessage { } } +impl From for AttestationExchangeMessage { + fn from(attestation_evidence: AttestationEvidence) -> Self { + let attestation_type = match attestation_evidence.platform.attestation_type { + attest_types::AttestationType::GcpTdx => AttestationType::GcpTdx, + attest_types::AttestationType::AzureTdx => AttestationType::AzureTdx, + attest_types::AttestationType::SelfHostedTdx => AttestationType::QemuTdx, + }; + Self { + attestation_type, + attestation: attestation_evidence.quote, + platform_metadata: Some(attestation_evidence.platform), + } + } +} + /// Type of attestation used /// Only supported (or soon-to-be supported) types are given #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -204,10 +225,7 @@ impl AttestationGenerator { if let Some(url) = &self.attestation_provider_url { Self::use_attestation_provider(url, self.attestation_type, input_data) } else { - Ok(AttestationExchangeMessage { - attestation_type: self.attestation_type, - attestation: self.generate_attestation_bytes(input_data)?, - }) + self.generate_attestation_bytes(input_data) } } @@ -216,9 +234,13 @@ impl AttestationGenerator { fn generate_attestation_bytes( &self, input_data: [u8; 64], - ) -> Result, AttestationError> { + ) -> Result { match self.attestation_type { - AttestationType::None => Ok(Vec::new()), + AttestationType::None => Ok(AttestationExchangeMessage { + attestation_type: AttestationType::None, + attestation: Vec::new(), + platform_metadata: None, + }), AttestationType::AzureTdx => { #[cfg(feature = "azure")] { @@ -233,7 +255,12 @@ impl AttestationGenerator { } } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { - dcap::create_dcap_attestation(input_data) + let attestaton_evidence = dcap::create_dcap_attestation(input_data)?; + Ok(AttestationExchangeMessage { + attestation_type: self.attestation_type, + attestation: attestaton_evidence.quote, + platform_metadata: Some(attestaton_evidence.platform), + }) } } } @@ -262,7 +289,11 @@ impl AttestationGenerator { if let Ok(message) = AttestationExchangeMessage::decode(&mut &body[..]) { Ok(message) } else { - Ok(AttestationExchangeMessage { attestation_type, attestation: body }) + Ok(AttestationExchangeMessage { + attestation_type, + attestation: body, + platform_metadata: None, + }) } } } @@ -399,8 +430,13 @@ impl AttestationVerifier { } } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { + let attesation_evidence = AttestationEvidence { + quote: attestation_exchange_message.attestation, + platform: attestation_exchange_message.platform_metadata.unwrap(), + }; + dcap::verify_dcap_attestation( - attestation_exchange_message.attestation, + attesation_evidence, expected_input_data, self.internal_pccs.clone(), ) @@ -662,6 +698,7 @@ mod tests { let encoded_message = AttestationExchangeMessage { attestation_type: AttestationType::None, attestation: vec![1, 2, 3], + platform_metadata: None, } .encode(); @@ -700,10 +737,7 @@ mod tests { pccs.ready().await.unwrap(); } - let result = verifier.verify_attestation_sync( - AttestationExchangeMessage { attestation_type: AttestationType::DcapTdx, attestation }, - input_data, - ); + let result = verifier.verify_attestation_sync(attestation.into(), input_data); assert!(result.is_ok(), "expected sync mock verification to succeed: {result:?}"); } diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index 1495611..f2c2a3e 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -543,6 +543,7 @@ impl AttestedCertificateVerifier { return Ok(AttestationExchangeMessage { attestation_type: AttestationType::DcapTdx, attestation: tdx_quote.quote, + platform_metadata: None, }); } diff --git a/crates/mock-tdx/Cargo.toml b/crates/mock-tdx/Cargo.toml index f13c39f..720005b 100644 --- a/crates/mock-tdx/Cargo.toml +++ b/crates/mock-tdx/Cargo.toml @@ -21,6 +21,7 @@ tokio = { workspace = true, features = ["rt", "net"] } urlencoding = "2.1.3" yasna = "0.5.2" x509-parser = "0.18.1" +attest-types = { git = "https://github.com/easy-tee/attest.git", branch = "ah/better-interface" } [lints] workspace = true diff --git a/crates/mock-tdx/src/lib.rs b/crates/mock-tdx/src/lib.rs index 50a2989..ba021d9 100644 --- a/crates/mock-tdx/src/lib.rs +++ b/crates/mock-tdx/src/lib.rs @@ -1,5 +1,6 @@ pub mod mock_pcs; +use attest_types::{AttestationEvidence, PlatformMetadata}; use dcap_qvl::{ QuoteCollateralV3, quote::{ @@ -106,9 +107,17 @@ pub(crate) fn signing_key_from_secret( /// Generate a mock TDX DCAP quote using the generated fixture material pub fn generate_mock_tdx_quote( report_data: [u8; 64], -) -> Result, Box> { +) -> Result> { let collateral = mock_collateral(); - generate_mock_tdx_quote_with_collateral(&collateral, report_data) + Ok(AttestationEvidence { + quote: generate_mock_tdx_quote_with_collateral(&collateral, report_data)?, + platform: PlatformMetadata { + attestation_type: attest_types::AttestationType::GcpTdx, + num_disks: 0, + ram_bytes: 0, + acpi: None, + }, + }) } /// Generate a mock TDX DCAP quote from a specific loaded material set @@ -250,8 +259,8 @@ mod tests { fn builds_quote_that_parses_and_verifies() { let report_data = [0xAB; 64]; - let quote_bytes = generate_mock_tdx_quote(report_data).unwrap(); - let quote = Quote::parse("e_bytes).unwrap(); + let attestation_evidence = generate_mock_tdx_quote(report_data).unwrap(); + let quote = Quote::parse(&attestation_evidence.quote).unwrap(); assert_eq!(quote.header.version, QUOTE_VERSION); assert_eq!(quote.header.tee_type, TEE_TYPE_TDX); @@ -261,7 +270,8 @@ mod tests { assert_eq!(quote.ca().unwrap(), "processor"); let verifier = mock_dcap_verifier(); - let verified = verifier.verify("e_bytes, &collateral, FIXTURE_TIME).unwrap(); + let verified = + verifier.verify(&attestation_evidence.quote, &collateral, FIXTURE_TIME).unwrap(); let dcap_qvl::quote::Report::TD10(report) = verified.report else { panic!("expected TD10 report"); }; @@ -276,13 +286,13 @@ mod tests { const TD_REPORT10_BYTE_LEN: usize = 584; const AUTH_DATA_SIZE_BYTE_LEN: usize = 4; - let mut quote_bytes = generate_mock_tdx_quote([0xCD; 64]).unwrap(); + let mut attestation_evidence = generate_mock_tdx_quote([0xCD; 64]).unwrap(); let signature_offset = HEADER_BYTE_LEN + TD_REPORT10_BYTE_LEN + AUTH_DATA_SIZE_BYTE_LEN; - quote_bytes[signature_offset] ^= 0x01; + attestation_evidence.quote[signature_offset] ^= 0x01; let verifier = mock_dcap_verifier(); let collateral = mock_collateral(); - assert!(verifier.verify("e_bytes, &collateral, FIXTURE_TIME).is_err()); + assert!(verifier.verify(&attestation_evidence.quote, &collateral, FIXTURE_TIME).is_err()); } #[test] @@ -294,11 +304,11 @@ mod tests { assert!(!EMBEDDED_ROOT_CA_DER.is_empty()); assert!(collateral.pck_certificate_chain.is_some()); - let quote_bytes = generate_mock_tdx_quote([0xEF; 64]).unwrap(); - let quote = Quote::parse("e_bytes).unwrap(); + let attestation_evidence = generate_mock_tdx_quote([0xEF; 64]).unwrap(); + let quote = Quote::parse(&attestation_evidence.quote).unwrap(); assert_eq!(hex::encode_upper(quote.fmspc().unwrap()), tcb_info.fmspc); assert_eq!(quote.header.pce_svn, tcb_info.tcb_levels[0].tcb.pce_svn); - verifier.verify("e_bytes, &collateral, FIXTURE_TIME).unwrap(); + verifier.verify(&attestation_evidence.quote, &collateral, FIXTURE_TIME).unwrap(); } } From 3227a167231ee0b3454688d0e83d2b157429c42e Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 3 Jun 2026 12:12:05 +0200 Subject: [PATCH 02/35] Add test for measurement policy --- crates/attestation/src/dcap.rs | 2 +- crates/attestation/src/lib.rs | 12 ++- crates/attestation/src/measurements.rs | 139 ++++++++++++++++++++----- 3 files changed, 121 insertions(+), 32 deletions(-) diff --git a/crates/attestation/src/dcap.rs b/crates/attestation/src/dcap.rs index 10b52f8..5b19e57 100644 --- a/crates/attestation/src/dcap.rs +++ b/crates/attestation/src/dcap.rs @@ -372,7 +372,7 @@ mod tests { .unwrap(); assert_eq!(async_measurements, sync_measurements); - measurement_policy.check_measurement(&async_measurements).unwrap(); + measurement_policy.check_measurement(&async_measurements, None).unwrap(); } // This specifically tests a quote which has outdated TCB level from Azure diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index ceb1643..7ded854 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -432,7 +432,7 @@ impl AttestationVerifier { AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { let attesation_evidence = AttestationEvidence { quote: attestation_exchange_message.attestation, - platform: attestation_exchange_message.platform_metadata.unwrap(), + platform: attestation_exchange_message.platform_metadata.clone().unwrap(), }; dcap::verify_dcap_attestation( @@ -445,7 +445,8 @@ impl AttestationVerifier { }; // Do a measurement / attestation type policy check - self.measurement_policy.check_measurement(&measurements)?; + self.measurement_policy + .check_measurement(&measurements, attestation_exchange_message.platform_metadata)?; tracing::debug!("Verification successful"); Ok(Some(measurements)) @@ -506,7 +507,8 @@ impl AttestationVerifier { }; // Do a measurement / attestation type policy check - self.measurement_policy.check_measurement(&measurements)?; + self.measurement_policy + .check_measurement(&measurements, attestation_exchange_message.platform_metadata)?; tracing::debug!("Verification successful"); Ok(Some(measurements)) @@ -549,8 +551,8 @@ fn running_on_gcp() -> Result { let resp = agent.get(GCP_METADATA_API).call(); if let Ok(r) = resp { - return Ok(r.status() == 200 && - r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); + return Ok(r.status() == 200 + && r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); } Ok(false) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index db8c2c9..8ef85e4 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -2,6 +2,8 @@ //! attestation use std::{collections::HashMap, fmt, fmt::Formatter, net::IpAddr, path::PathBuf}; +use attest_measure::dcap::{build_rtmr2, gcp, self_hosted}; +use attest_types::{AttestationType as ImageAttestationType, DcapImageHashes, PlatformMetadata}; use dcap_qvl::quote::Report; use http::{HeaderValue, header::InvalidHeaderValue, uri::InvalidUri}; use serde::Deserialize; @@ -135,6 +137,7 @@ impl fmt::Debug for AzureHexDebug<'_> { /// Expected measurement values for policy enforcement #[derive(Debug, Clone, PartialEq)] pub enum ExpectedMeasurements { + Image(DcapImageHashes), Dcap(HashMap>), Azure(HashMap>), NoAttestation, @@ -375,20 +378,53 @@ impl MeasurementPolicy { pub fn check_measurement( &self, measurements: &MultiMeasurements, + platform_metadata: Option, ) -> Result<(), AttestationError> { if self.accepted_measurements.iter().any(|measurement_record| match measurements { MultiMeasurements::Dcap(dcap_measurements) => { - if let ExpectedMeasurements::Dcap(expected) = &measurement_record.measurements { - // All measurements in our policy must be given and must match - for (k, v) in expected.iter() { - match dcap_measurements.get(k) { - Some(actual_value) if v.iter().any(|v| actual_value == v) => {} - _ => return false, + match &measurement_record.measurements { + ExpectedMeasurements::Dcap(expected) => { + // All measurements in our policy must be given and must match + for (k, v) in expected.iter() { + match dcap_measurements.get(k) { + Some(actual_value) if v.iter().any(|v| actual_value == v) => {} + _ => return false, + } } + return true; } - return true; + ExpectedMeasurements::Image(image_hashes) => { + let Some(platform_metadata) = &platform_metadata else { + return false; + }; + let expected_rtmr1 = match platform_metadata.attestation_type { + ImageAttestationType::GcpTdx => gcp::build_rtmr1(image_hashes).value(), + ImageAttestationType::SelfHostedTdx => { + self_hosted::build_rtmr1(image_hashes).value() + } + ImageAttestationType::AzureTdx => return false, + }; + let expected_rtmr2 = build_rtmr2(image_hashes).value(); + + if let Some(rtmr1) = dcap_measurements.get(&DcapMeasurementRegister::RTMR1) + { + if rtmr1 != &expected_rtmr1 { + return false; + } + } + + if let Some(rtmr2) = dcap_measurements.get(&DcapMeasurementRegister::RTMR2) + { + if rtmr2 != &expected_rtmr2 { + return false; + } + } + + // TODO how to handle mrtd and rtmr0 since they are Option + return true; + } + _ => false, } - false } MultiMeasurements::Azure(azure_measurements) => { if let ExpectedMeasurements::Azure(expected) = &measurement_record.measurements { @@ -527,9 +563,9 @@ impl MeasurementPolicy { )?; ExpectedMeasurements::Azure(azure_measurements) } - AttestationType::DcapTdx | - AttestationType::GcpTdx | - AttestationType::QemuTdx => ExpectedMeasurements::Dcap( + AttestationType::DcapTdx + | AttestationType::GcpTdx + | AttestationType::QemuTdx => ExpectedMeasurements::Dcap( measurements .iter() .map(|(index_str, entry)| { @@ -567,8 +603,8 @@ impl MeasurementPolicy { }; let normalized_host = host.trim_start_matches('[').trim_end_matches(']'); - Ok(normalized_host.eq_ignore_ascii_case("localhost") || - normalized_host.parse::().is_ok_and(|address| address.is_loopback())) + Ok(normalized_host.eq_ignore_ascii_case("localhost") + || normalized_host.parse::().is_ok_and(|address| address.is_loopback())) } } @@ -576,6 +612,8 @@ impl MeasurementPolicy { mod tests { use std::collections::HashSet; + use attest_measure::dcap::{build_rtmr2, gcp::build_rtmr1}; + use super::*; #[tokio::test] @@ -612,20 +650,22 @@ mod tests { // Will not match mock measurements assert!(matches!( - specific_measurements.check_measurement(&mock_dcap_measurements()).unwrap_err(), + specific_measurements.check_measurement(&mock_dcap_measurements(), None).unwrap_err(), AttestationError::MeasurementsNotAccepted )); // Will not match another attestation type assert!(matches!( - specific_measurements.check_measurement(&MultiMeasurements::NoAttestation).unwrap_err(), + specific_measurements + .check_measurement(&MultiMeasurements::NoAttestation, None) + .unwrap_err(), AttestationError::MeasurementsNotAccepted )); // A non-specific measurement fails assert!(matches!( specific_measurements - .check_measurement(&MultiMeasurements::Azure(HashMap::new())) + .check_measurement(&MultiMeasurements::Azure(HashMap::new()), None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -638,17 +678,64 @@ mod tests { let allowed_attestation_type = MeasurementPolicy::from_file("test-assets/measurements_2.json".into()).await.unwrap(); - allowed_attestation_type.check_measurement(&mock_dcap_measurements()).unwrap(); + allowed_attestation_type.check_measurement(&mock_dcap_measurements(), None).unwrap(); // Will not match another attestation type assert!(matches!( allowed_attestation_type - .check_measurement(&MultiMeasurements::NoAttestation) + .check_measurement(&MultiMeasurements::NoAttestation, None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); } + #[test] + fn test_gcp_image_hash_measurement_policy_accepts_matching_measurements() { + fn decode_hash(input: &str) -> [u8; 48] { + hex::decode(input).unwrap().try_into().unwrap() + } + + // Result of measuring a flashbox-l1 image + let image_hashes = DcapImageHashes { + uki_authenticode: decode_hash( + "fcaceb6d87694746ba2d93a87ef4209f2a7629b7f400097b93241e80b9ec3e1e80f9a4cd8028e6a83f297ea5de8d9abc", + ), + kernel_authenticode: decode_hash( + "b6c5133268aa8b440509f3d53ee855a5cd3aeb6441eb109a9f27f14c43bce3e2383856df4af876501ceeb4c9a3b15f0c", + ), + cmdline_hash: decode_hash( + "e03b89abf354a38976537b7a9138fd312e4cbf73b61eebc44086491701b1d167b9f6cb97a922325866c93e0834723d87", + ), + initrd_hash: decode_hash( + "a5b3d4742045e7d08aa19953c35098e784826b01a84f60568fa69f1a848dafd96ec98b8df616d6142779c9b97318166b", + ), + gpt_disk_guid_hash: decode_hash( + "180bac1af9c35cc15e909623c005289539b4da2840d9c9b658fd4968ea4f03e0159402d03da1afc9035e0db30804e282", + ), + }; + let policy = MeasurementPolicy { + accepted_measurements: vec![MeasurementRecord { + measurement_id: "image-hash-policy".to_string(), + measurements: ExpectedMeasurements::Image(image_hashes.clone()), + }], + }; + let platform_metadata = PlatformMetadata { + attestation_type: attest_types::AttestationType::GcpTdx, + ram_bytes: 0, + num_disks: 2, + acpi: None, + }; + let measurements = MultiMeasurements::Dcap(HashMap::from([ + (DcapMeasurementRegister::MRTD, mock_tdx::MOCK_MRTD), + (DcapMeasurementRegister::RTMR0, mock_tdx::MOCK_RTMR0), + (DcapMeasurementRegister::RTMR1, build_rtmr1(&image_hashes).value()), + (DcapMeasurementRegister::RTMR2, build_rtmr2(&image_hashes).value()), + (DcapMeasurementRegister::RTMR3, mock_tdx::MOCK_RTMR3), + ])); + + policy.check_measurement(&measurements, Some(platform_metadata)).unwrap(); + } + #[tokio::test] async fn test_buildernet_measurements() { // Refresh this fixture explicitly with: @@ -662,13 +749,13 @@ mod tests { assert!(!policy.accepted_measurements.is_empty()); assert!(matches!( - policy.check_measurement(&MultiMeasurements::NoAttestation).unwrap_err(), + policy.check_measurement(&MultiMeasurements::NoAttestation, None).unwrap_err(), AttestationError::MeasurementsNotAccepted )); // A non-specific measurement fails assert!(matches!( - policy.check_measurement(&MultiMeasurements::Azure(HashMap::new())).unwrap_err(), + policy.check_measurement(&MultiMeasurements::Azure(HashMap::new()), None).unwrap_err(), AttestationError::MeasurementsNotAccepted )); } @@ -724,17 +811,17 @@ mod tests { // First value should match let measurements1 = MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0u8; 48])])); - assert!(policy.check_measurement(&measurements1).is_ok()); + assert!(policy.check_measurement(&measurements1, None).is_ok()); // Second value should also match let measurements2 = MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0x11u8; 48])])); - assert!(policy.check_measurement(&measurements2).is_ok()); + assert!(policy.check_measurement(&measurements2, None).is_ok()); // Different value should not match let measurements3 = MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0x22u8; 48])])); - assert!(policy.check_measurement(&measurements3).is_err()); + assert!(policy.check_measurement(&measurements3, None).is_err()); } #[tokio::test] @@ -814,21 +901,21 @@ mod tests { (DcapMeasurementRegister::MRTD, [0u8; 48]), (DcapMeasurementRegister::RTMR0, [0x11u8; 48]), ])); - assert!(policy.check_measurement(&measurements1).is_ok()); + assert!(policy.check_measurement(&measurements1, None).is_ok()); // Both match (single + second of any) let measurements2 = MultiMeasurements::Dcap(HashMap::from([ (DcapMeasurementRegister::MRTD, [0u8; 48]), (DcapMeasurementRegister::RTMR0, [0x22u8; 48]), ])); - assert!(policy.check_measurement(&measurements2).is_ok()); + assert!(policy.check_measurement(&measurements2, None).is_ok()); // Single matches but any doesn't let measurements3 = MultiMeasurements::Dcap(HashMap::from([ (DcapMeasurementRegister::MRTD, [0u8; 48]), (DcapMeasurementRegister::RTMR0, [0x33u8; 48]), ])); - assert!(policy.check_measurement(&measurements3).is_err()); + assert!(policy.check_measurement(&measurements3, None).is_err()); } #[tokio::test] From 25ea83ffa25aa07e98fe69a059224801ce786d46 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 3 Jun 2026 12:32:27 +0200 Subject: [PATCH 03/35] Also check rtmr0 --- crates/attestation/src/measurements.rs | 49 +++++++++++++++++--------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index 8ef85e4..f73480b 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -2,7 +2,7 @@ //! attestation use std::{collections::HashMap, fmt, fmt::Formatter, net::IpAddr, path::PathBuf}; -use attest_measure::dcap::{build_rtmr2, gcp, self_hosted}; +use attest_measure::dcap::{DcapFirmware, expected_dcap_registers}; use attest_types::{AttestationType as ImageAttestationType, DcapImageHashes, PlatformMetadata}; use dcap_qvl::quote::Report; use http::{HeaderValue, header::InvalidHeaderValue, uri::InvalidUri}; @@ -397,25 +397,37 @@ impl MeasurementPolicy { let Some(platform_metadata) = &platform_metadata else { return false; }; - let expected_rtmr1 = match platform_metadata.attestation_type { - ImageAttestationType::GcpTdx => gcp::build_rtmr1(image_hashes).value(), - ImageAttestationType::SelfHostedTdx => { - self_hosted::build_rtmr1(image_hashes).value() - } + let firmware = match platform_metadata.attestation_type { + ImageAttestationType::GcpTdx => Some(DcapFirmware::gcp_hardcoded()), + ImageAttestationType::SelfHostedTdx => None, ImageAttestationType::AzureTdx => return false, }; - let expected_rtmr2 = build_rtmr2(image_hashes).value(); + let expected_measurements = match expected_dcap_registers( + image_hashes, + platform_metadata, + firmware.as_ref(), + ) { + Ok(expected_measurements) => expected_measurements, + Err(_) => return false, // TODO should we bail here + }; + + if let Some(expected_rtmr0) = expected_measurements.rtmr0 { + match dcap_measurements.get(&DcapMeasurementRegister::RTMR0) { + Some(rtmr0) if rtmr0 == &expected_rtmr0 => {} + _ => return false, + } + } if let Some(rtmr1) = dcap_measurements.get(&DcapMeasurementRegister::RTMR1) { - if rtmr1 != &expected_rtmr1 { + if rtmr1 != &expected_measurements.rtmr1 { return false; } } if let Some(rtmr2) = dcap_measurements.get(&DcapMeasurementRegister::RTMR2) { - if rtmr2 != &expected_rtmr2 { + if rtmr2 != &expected_measurements.rtmr2 { return false; } } @@ -612,7 +624,8 @@ impl MeasurementPolicy { mod tests { use std::collections::HashSet; - use attest_measure::dcap::{build_rtmr2, gcp::build_rtmr1}; + use attest_measure::dcap::expected_dcap_registers; + use attest_types::AcpiHashes; use super::*; @@ -721,15 +734,19 @@ mod tests { }; let platform_metadata = PlatformMetadata { attestation_type: attest_types::AttestationType::GcpTdx, - ram_bytes: 0, - num_disks: 2, - acpi: None, + ram_bytes: 4 * 1024 * 1024 * 1024, + num_disks: 1, + acpi: Some(AcpiHashes { loader: [0x11; 48], rsdp: [0x22; 48], tables: [0x33; 48] }), }; + let firmware = DcapFirmware::gcp_hardcoded(); + let expected_measurements = + expected_dcap_registers(&image_hashes, &platform_metadata, Some(&firmware)).unwrap(); + let measurements = MultiMeasurements::Dcap(HashMap::from([ (DcapMeasurementRegister::MRTD, mock_tdx::MOCK_MRTD), - (DcapMeasurementRegister::RTMR0, mock_tdx::MOCK_RTMR0), - (DcapMeasurementRegister::RTMR1, build_rtmr1(&image_hashes).value()), - (DcapMeasurementRegister::RTMR2, build_rtmr2(&image_hashes).value()), + (DcapMeasurementRegister::RTMR0, expected_measurements.rtmr0.unwrap()), + (DcapMeasurementRegister::RTMR1, expected_measurements.rtmr1), + (DcapMeasurementRegister::RTMR2, expected_measurements.rtmr2), (DcapMeasurementRegister::RTMR3, mock_tdx::MOCK_RTMR3), ])); From bced75d8ccc5cde8b43f5e0e30465d717be48aeb Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 3 Jun 2026 12:37:50 +0200 Subject: [PATCH 04/35] Also check mrtd --- crates/attestation/src/measurements.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index f73480b..49f9252 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -411,6 +411,13 @@ impl MeasurementPolicy { Err(_) => return false, // TODO should we bail here }; + if let Some(expected_mrtd) = expected_measurements.mrtd { + match dcap_measurements.get(&DcapMeasurementRegister::MRTD) { + Some(mrtd) if mrtd == &expected_mrtd => {} + _ => return false, + } + } + if let Some(expected_rtmr0) = expected_measurements.rtmr0 { match dcap_measurements.get(&DcapMeasurementRegister::RTMR0) { Some(rtmr0) if rtmr0 == &expected_rtmr0 => {} @@ -432,7 +439,6 @@ impl MeasurementPolicy { } } - // TODO how to handle mrtd and rtmr0 since they are Option return true; } _ => false, @@ -743,7 +749,7 @@ mod tests { expected_dcap_registers(&image_hashes, &platform_metadata, Some(&firmware)).unwrap(); let measurements = MultiMeasurements::Dcap(HashMap::from([ - (DcapMeasurementRegister::MRTD, mock_tdx::MOCK_MRTD), + (DcapMeasurementRegister::MRTD, expected_measurements.mrtd.unwrap()), (DcapMeasurementRegister::RTMR0, expected_measurements.rtmr0.unwrap()), (DcapMeasurementRegister::RTMR1, expected_measurements.rtmr1), (DcapMeasurementRegister::RTMR2, expected_measurements.rtmr2), From b25a42f568d34c10d624370442bff75295575282 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 3 Jun 2026 12:42:49 +0200 Subject: [PATCH 05/35] Fix to compile for azure feature --- crates/attestation/src/azure/mod.rs | 5 +-- crates/attestation/src/lib.rs | 63 +++++++++++++---------------- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 45d4e4c..296199f 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -17,8 +17,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, }; @@ -599,7 +598,7 @@ mod tests { .unwrap(); assert_eq!(async_measurements, sync_measurements); - measurement_policy.check_measurement(&async_measurements).unwrap(); + measurement_policy.check_measurement(&async_measurements, None).unwrap(); } #[tokio::test] diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 7ded854..6049f48 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -225,43 +225,38 @@ impl AttestationGenerator { if let Some(url) = &self.attestation_provider_url { Self::use_attestation_provider(url, self.attestation_type, input_data) } else { - self.generate_attestation_bytes(input_data) - } - } - - /// Generate attestation evidence bytes based on attestation type, with - /// given input data - fn generate_attestation_bytes( - &self, - input_data: [u8; 64], - ) -> Result { - match self.attestation_type { - AttestationType::None => Ok(AttestationExchangeMessage { - attestation_type: AttestationType::None, - attestation: Vec::new(), - platform_metadata: None, - }), - AttestationType::AzureTdx => { - #[cfg(feature = "azure")] - { - Ok(azure::create_azure_attestation(input_data)?) + match self.attestation_type { + AttestationType::None => Ok(AttestationExchangeMessage { + attestation_type: AttestationType::None, + attestation: Vec::new(), + platform_metadata: None, + }), + AttestationType::AzureTdx => { + #[cfg(feature = "azure")] + { + Ok(AttestationExchangeMessage { + attestation_type: AttestationType::AzureTdx, + attestation: azure::create_azure_attestation(input_data)?, + platform_metadata: None, + }) + } + #[cfg(not(feature = "azure"))] + { + tracing::error!( + "Attempted to generate an azure attestation but the `azure` feature not enabled" + ); + Err(AttestationError::AttestationTypeNotSupported) + } } - #[cfg(not(feature = "azure"))] - { - tracing::error!( - "Attempted to generate an azure attestation but the `azure` feature not enabled" - ); - Err(AttestationError::AttestationTypeNotSupported) + AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { + let attestaton_evidence = dcap::create_dcap_attestation(input_data)?; + Ok(AttestationExchangeMessage { + attestation_type: self.attestation_type, + attestation: attestaton_evidence.quote, + platform_metadata: Some(attestaton_evidence.platform), + }) } } - AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { - let attestaton_evidence = dcap::create_dcap_attestation(input_data)?; - Ok(AttestationExchangeMessage { - attestation_type: self.attestation_type, - attestation: attestaton_evidence.quote, - platform_metadata: Some(attestaton_evidence.platform), - }) - } } } From 9e0c26325f21b62ea1b96f06b5fad12edeef67fa Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 3 Jun 2026 12:47:02 +0200 Subject: [PATCH 06/35] Clippy --- crates/attestation/src/azure/mod.rs | 3 ++- crates/attestation/src/lib.rs | 4 ++-- crates/attestation/src/measurements.rs | 32 ++++++++++++-------------- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 296199f..08272d1 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -17,7 +17,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, }; diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 6049f48..15ab8de 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -546,8 +546,8 @@ fn running_on_gcp() -> Result { let resp = agent.get(GCP_METADATA_API).call(); if let Ok(r) = resp { - return Ok(r.status() == 200 - && r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); + return Ok(r.status() == 200 && + r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); } Ok(false) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index 49f9252..1cf841c 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -391,7 +391,7 @@ impl MeasurementPolicy { _ => return false, } } - return true; + true } ExpectedMeasurements::Image(image_hashes) => { let Some(platform_metadata) = &platform_metadata else { @@ -402,13 +402,13 @@ impl MeasurementPolicy { ImageAttestationType::SelfHostedTdx => None, ImageAttestationType::AzureTdx => return false, }; - let expected_measurements = match expected_dcap_registers( + + let Ok(expected_measurements) = expected_dcap_registers( image_hashes, platform_metadata, firmware.as_ref(), - ) { - Ok(expected_measurements) => expected_measurements, - Err(_) => return false, // TODO should we bail here + ) else { + return false; // TODO should we bail here }; if let Some(expected_mrtd) = expected_measurements.mrtd { @@ -426,20 +426,18 @@ impl MeasurementPolicy { } if let Some(rtmr1) = dcap_measurements.get(&DcapMeasurementRegister::RTMR1) + && rtmr1 != &expected_measurements.rtmr1 { - if rtmr1 != &expected_measurements.rtmr1 { - return false; - } + return false; } if let Some(rtmr2) = dcap_measurements.get(&DcapMeasurementRegister::RTMR2) + && rtmr2 != &expected_measurements.rtmr2 { - if rtmr2 != &expected_measurements.rtmr2 { - return false; - } + return false; } - return true; + true } _ => false, } @@ -581,9 +579,9 @@ impl MeasurementPolicy { )?; ExpectedMeasurements::Azure(azure_measurements) } - AttestationType::DcapTdx - | AttestationType::GcpTdx - | AttestationType::QemuTdx => ExpectedMeasurements::Dcap( + AttestationType::DcapTdx | + AttestationType::GcpTdx | + AttestationType::QemuTdx => ExpectedMeasurements::Dcap( measurements .iter() .map(|(index_str, entry)| { @@ -621,8 +619,8 @@ impl MeasurementPolicy { }; let normalized_host = host.trim_start_matches('[').trim_end_matches(']'); - Ok(normalized_host.eq_ignore_ascii_case("localhost") - || normalized_host.parse::().is_ok_and(|address| address.is_loopback())) + Ok(normalized_host.eq_ignore_ascii_case("localhost") || + normalized_host.parse::().is_ok_and(|address| address.is_loopback())) } } From 737d790d5d9ff5c082241034cfca350a136b164c Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 3 Jun 2026 13:47:54 +0200 Subject: [PATCH 07/35] Error handling --- crates/attestation/src/dcap.rs | 23 ++++++++++------------- crates/attestation/src/lib.rs | 13 +++++++------ 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/crates/attestation/src/dcap.rs b/crates/attestation/src/dcap.rs index 5b19e57..516e30c 100644 --- a/crates/attestation/src/dcap.rs +++ b/crates/attestation/src/dcap.rs @@ -33,13 +33,12 @@ pub fn create_dcap_attestation( /// Verify a DCAP TDX quote, and return the measurement values #[cfg(not(any(test, feature = "mock")))] pub async fn verify_dcap_attestation( - attestation_evidence: AttestationEvidence, + input: Vec, expected_input_data: [u8; 64], pccs: Option, ) -> Result { let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?.as_secs(); let override_azure_outdated_tcb = false; - let input = attestation_evidence.quote; verify_dcap_attestation_with_given_timestamp( input, expected_input_data, @@ -210,11 +209,11 @@ fn verify_dcap_attestation_with_collateral_and_timestamp( #[cfg(any(test, feature = "mock"))] pub async fn verify_dcap_attestation( - attestation_evidence: AttestationEvidence, + input: Vec, expected_input_data: [u8; 64], pccs: Option, ) -> Result { - let quote = Quote::parse(&attestation_evidence.quote)?; + let quote = Quote::parse(&input)?; let ca = quote.ca()?; let fmspc = hex::encode_upper(quote.fmspc()?); let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH)?.as_secs(); @@ -225,7 +224,7 @@ pub async fn verify_dcap_attestation( mock_tdx::mock_collateral() }; let verifier = mock_tdx::mock_dcap_verifier(); - verifier.verify(&attestation_evidence.quote, &collateral, now)?; + verifier.verify(&input, &collateral, now)?; let measurements = MultiMeasurements::from_dcap_qvl_quote("e)?; if get_quote_input_data(quote.report) != expected_input_data { @@ -258,20 +257,18 @@ pub fn verify_dcap_attestation_sync( /// Create a mock quote for testing on non-confidential hardware #[cfg(any(test, feature = "mock"))] -fn generate_quote(input: [u8; 64]) -> Result { - generate_mock_tdx_quote(input).map_err(|error| { - tdx_attest::TdxAttestError::QuoteFailure(format!("mock-tdx quote generation: {error}")) - }) +fn generate_quote(input: [u8; 64]) -> Result { + generate_mock_tdx_quote(input).map_err(|error| AttestationError::Mock(format!("{error}"))) } /// Create a quote #[cfg(not(any(test, feature = "mock")))] -fn generate_quote(input: [u8; 64]) -> Result { +fn generate_quote(input: [u8; 64]) -> Result { use attest_measure::platform; Ok(AttestationEvidence { quote: tdx_attest::get_quote(&input)?, - platform: platform::metadata_for(attest_types::AttestationType::GcpTdx).unwrap(), + platform: platform::metadata_for(attest_types::AttestationType::GcpTdx)?, }) } @@ -416,10 +413,10 @@ mod tests { .unwrap(); let pccs = Pccs::new(Some(mock_pcs.base_url.clone())); let expected_input_data = [0xA5; 64]; - let attestation_bytes = create_dcap_attestation(expected_input_data).unwrap(); + let attestation = create_dcap_attestation(expected_input_data).unwrap(); let measurements = - verify_dcap_attestation(attestation_bytes, expected_input_data, Some(pccs)) + verify_dcap_attestation(attestation.quote, expected_input_data, Some(pccs)) .await .unwrap(); diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 15ab8de..97b8dc5 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -12,6 +12,7 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; +use attest_measure::platform::PlatformError; use attest_types::{AttestationEvidence, PlatformMetadata}; use measurements::MultiMeasurements; use parity_scale_codec::{Decode, Encode}; @@ -425,13 +426,8 @@ impl AttestationVerifier { } } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { - let attesation_evidence = AttestationEvidence { - quote: attestation_exchange_message.attestation, - platform: attestation_exchange_message.platform_metadata.clone().unwrap(), - }; - dcap::verify_dcap_attestation( - attesation_evidence, + attestation_exchange_message.attestation, expected_input_data, self.internal_pccs.clone(), ) @@ -642,6 +638,11 @@ pub enum AttestationError { Pccs(#[from] PccsError), #[error("Sync verification requested but no PCCS configured")] NoPccs, + #[cfg(any(test, feature = "mock"))] + #[error("Cannot create mock attestation: {0}")] + Mock(String), + #[error("Cannot retrieve platform metadata: {0}")] + PlatformMetadata(#[from] PlatformError), } #[cfg(test)] From 5d2091397d912425cb6e8bd801c745ed73559c39 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 3 Jun 2026 14:15:25 +0200 Subject: [PATCH 08/35] Typo, comments --- crates/attestation/src/lib.rs | 6 +++--- crates/attested-tls/src/lib.rs | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 97b8dc5..d979bea 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -250,11 +250,11 @@ impl AttestationGenerator { } } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { - let attestaton_evidence = dcap::create_dcap_attestation(input_data)?; + let attestation_evidence = dcap::create_dcap_attestation(input_data)?; Ok(AttestationExchangeMessage { attestation_type: self.attestation_type, - attestation: attestaton_evidence.quote, - platform_metadata: Some(attestaton_evidence.platform), + attestation: attestation_evidence.quote, + platform_metadata: Some(attestation_evidence.platform), }) } } diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index f2c2a3e..d4319ad 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -540,6 +540,8 @@ impl AttestedCertificateVerifier { return Ok(message); } + // TODO maybe we have to drop support for the VersionedAttestation::V0 + // format as it cannot encode platform metadata return Ok(AttestationExchangeMessage { attestation_type: AttestationType::DcapTdx, attestation: tdx_quote.quote, From f245588ecc979b5d45e20094a3c4245ce217130f Mon Sep 17 00:00:00 2001 From: peg Date: Thu, 4 Jun 2026 17:27:26 +0200 Subject: [PATCH 09/35] Use AttestationEvidence directly in AttestationExchangeMessage --- crates/attestation/src/lib.rs | 176 +++++++++++++++++++++------------ crates/attested-tls/src/lib.rs | 14 ++- 2 files changed, 124 insertions(+), 66 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index d979bea..294f046 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -13,7 +13,7 @@ use std::{ }; use attest_measure::platform::PlatformError; -use attest_types::{AttestationEvidence, PlatformMetadata}; +pub use attest_types::{AttestationEvidence, PlatformMetadata}; use measurements::MultiMeasurements; use parity_scale_codec::{Decode, Encode}; use pccs::{Pccs, PccsError}; @@ -28,34 +28,31 @@ const GCP_METADATA_API: &str = "http://metadata.google.internal"; /// An attestation payload together with its type #[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)] pub struct AttestationExchangeMessage { - /// What CVM platform is used (including none) - pub attestation_type: AttestationType, - /// The attestation evidence as bytes - in the case of DCAP this is a - /// quote - pub attestation: Vec, - pub platform_metadata: Option, + /// Attestation payload with platform metadata, if present. + /// `None` means no evidence presented. + pub attestation_evidence: Option, } impl AttestationExchangeMessage { /// Create an empty attestation payload for the case that we are running /// in a non-confidential environment pub fn without_attestation() -> Self { - Self { - attestation_type: AttestationType::None, - attestation: Vec::new(), - platform_metadata: None, - } + Self { attestation_evidence: None } } /// Extract the measurements from the attestation, if present, but do /// not verify pub fn get_measurements(&self) -> Result, AttestationError> { - match self.attestation_type { + let Some(attestation_evidence) = &self.attestation_evidence else { + return Ok(None); + }; + + match self.attestation_type() { AttestationType::None => Ok(None), AttestationType::AzureTdx => { #[cfg(feature = "azure")] { - Ok(Some(azure::get_measurements(&self.attestation)?)) + Ok(Some(azure::get_measurements(&attestation_evidence.quote)?)) } #[cfg(not(feature = "azure"))] { @@ -63,29 +60,59 @@ impl AttestationExchangeMessage { } } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { - let quote = dcap_qvl::verify::Quote::parse(&self.attestation) + let quote = dcap_qvl::verify::Quote::parse(&attestation_evidence.quote) .map_err(DcapVerificationError::from)?; Ok(Some(MultiMeasurements::from_dcap_qvl_quote("e)?)) } } } + + pub fn attestation_type(&self) -> AttestationType { + self.attestation_evidence + .as_ref() + .map(|evidence| evidence.platform.attestation_type.into()) + .unwrap_or(AttestationType::None) + } } impl From for AttestationExchangeMessage { fn from(attestation_evidence: AttestationEvidence) -> Self { - let attestation_type = match attestation_evidence.platform.attestation_type { + Self { attestation_evidence: Some(attestation_evidence) } + } +} + +impl From for AttestationType { + fn from(attestation_type: attest_types::AttestationType) -> Self { + match attestation_type { attest_types::AttestationType::GcpTdx => AttestationType::GcpTdx, attest_types::AttestationType::AzureTdx => AttestationType::AzureTdx, attest_types::AttestationType::SelfHostedTdx => AttestationType::QemuTdx, - }; - Self { - attestation_type, - attestation: attestation_evidence.quote, - platform_metadata: Some(attestation_evidence.platform), } } } +impl From for attest_types::AttestationType { + fn from(attestation_type: AttestationType) -> Self { + match attestation_type { + AttestationType::None => attest_types::AttestationType::SelfHostedTdx, + AttestationType::AzureTdx => attest_types::AttestationType::AzureTdx, + AttestationType::GcpTdx => attest_types::AttestationType::GcpTdx, + AttestationType::DcapTdx | AttestationType::QemuTdx => { + attest_types::AttestationType::SelfHostedTdx + } + } + } +} + +fn placeholder_platform_metadata(attestation_type: AttestationType) -> PlatformMetadata { + PlatformMetadata { + attestation_type: attestation_type.into(), + ram_bytes: 0, + num_disks: 0, + acpi: None, + } +} + /// Type of attestation used /// Only supported (or soon-to-be supported) types are given #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -199,7 +226,7 @@ impl AttestationGenerator { attestation_provider_url: Option, ) -> Result { if attestation_provider_url.is_some() { - // If a remote provide is used, dont do detection + // If a remote provider is used, dont do detection let attestation_type = serde_json::from_value(serde_json::Value::String( attestation_type_string.ok_or(AttestationError::AttestationTypeNotGiven)?, ))?; @@ -227,18 +254,17 @@ impl AttestationGenerator { Self::use_attestation_provider(url, self.attestation_type, input_data) } else { match self.attestation_type { - AttestationType::None => Ok(AttestationExchangeMessage { - attestation_type: AttestationType::None, - attestation: Vec::new(), - platform_metadata: None, - }), + AttestationType::None => Ok(AttestationExchangeMessage::without_attestation()), AttestationType::AzureTdx => { #[cfg(feature = "azure")] { + let platform = + attest_measure::platform::metadata_for(self.attestation_type.into())?; Ok(AttestationExchangeMessage { - attestation_type: AttestationType::AzureTdx, - attestation: azure::create_azure_attestation(input_data)?, - platform_metadata: None, + attestation_evidence: Some(AttestationEvidence { + quote: azure::create_azure_attestation(input_data)?, + platform, + }), }) } #[cfg(not(feature = "azure"))] @@ -250,12 +276,9 @@ impl AttestationGenerator { } } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { - let attestation_evidence = dcap::create_dcap_attestation(input_data)?; - Ok(AttestationExchangeMessage { - attestation_type: self.attestation_type, - attestation: attestation_evidence.quote, - platform_metadata: Some(attestation_evidence.platform), - }) + let mut attestation_evidence = dcap::create_dcap_attestation(input_data)?; + attestation_evidence.platform.attestation_type = self.attestation_type.into(); + Ok(attestation_evidence.into()) } } } @@ -285,10 +308,13 @@ impl AttestationGenerator { if let Ok(message) = AttestationExchangeMessage::decode(&mut &body[..]) { Ok(message) } else { + if attestation_type == AttestationType::None { + return Ok(AttestationExchangeMessage::without_attestation()); + } + + let platform = placeholder_platform_metadata(attestation_type); Ok(AttestationExchangeMessage { - attestation_type, - attestation: body, - platform_metadata: None, + attestation_evidence: Some(AttestationEvidence { quote: body, platform }), }) } } @@ -391,7 +417,7 @@ impl AttestationVerifier { attestation_exchange_message: AttestationExchangeMessage, expected_input_data: [u8; 64], ) -> Result, AttestationError> { - let attestation_type = attestation_exchange_message.attestation_type; + let attestation_type = attestation_exchange_message.attestation_type(); tracing::debug!("Verifying {attestation_type} attestation"); if self.dump_dcap_quotes { @@ -403,7 +429,7 @@ impl AttestationVerifier { if self.has_remote_attestation() { return Err(AttestationError::AttestationTypeNotAccepted); } - if attestation_exchange_message.attestation.is_empty() { + if attestation_exchange_message.attestation_evidence.is_none() { return Ok(None); } else { return Err(AttestationError::AttestationGivenWhenNoneExpected); @@ -412,8 +438,12 @@ impl AttestationVerifier { AttestationType::AzureTdx => { #[cfg(feature = "azure")] { + let attestation_evidence = attestation_exchange_message + .attestation_evidence + .as_ref() + .ok_or(AttestationError::AttestationTypeNotAccepted)?; azure::verify_azure_attestation( - attestation_exchange_message.attestation, + attestation_evidence.quote.clone(), expected_input_data, self.internal_pccs.clone(), self.override_azure_outdated_tcb, @@ -426,8 +456,12 @@ impl AttestationVerifier { } } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { + let attestation_evidence = attestation_exchange_message + .attestation_evidence + .as_ref() + .ok_or(AttestationError::AttestationTypeNotAccepted)?; dcap::verify_dcap_attestation( - attestation_exchange_message.attestation, + attestation_evidence.quote.clone(), expected_input_data, self.internal_pccs.clone(), ) @@ -436,8 +470,11 @@ impl AttestationVerifier { }; // Do a measurement / attestation type policy check - self.measurement_policy - .check_measurement(&measurements, attestation_exchange_message.platform_metadata)?; + let platform_metadata = attestation_exchange_message + .attestation_evidence + .as_ref() + .map(|evidence| evidence.platform.clone()); + self.measurement_policy.check_measurement(&measurements, platform_metadata)?; tracing::debug!("Verification successful"); Ok(Some(measurements)) @@ -448,7 +485,7 @@ impl AttestationVerifier { attestation_exchange_message: AttestationExchangeMessage, expected_input_data: [u8; 64], ) -> Result, AttestationError> { - let attestation_type = attestation_exchange_message.attestation_type; + let attestation_type = attestation_exchange_message.attestation_type(); tracing::debug!("Verifying {attestation_type} attestation"); if self.dump_dcap_quotes { @@ -460,7 +497,7 @@ impl AttestationVerifier { if self.has_remote_attestation() { return Err(AttestationError::AttestationTypeNotAccepted); } - if attestation_exchange_message.attestation.is_empty() { + if attestation_exchange_message.attestation_evidence.is_none() { return Ok(None); } else { return Err(AttestationError::AttestationGivenWhenNoneExpected); @@ -469,9 +506,13 @@ impl AttestationVerifier { AttestationType::AzureTdx => { #[cfg(feature = "azure")] { + let attestation_evidence = attestation_exchange_message + .attestation_evidence + .as_ref() + .ok_or(AttestationError::AttestationTypeNotAccepted)?; let pccs = self.internal_pccs.clone().ok_or(AttestationError::NoPccs)?; azure::verify_azure_attestation_sync( - attestation_exchange_message.attestation, + attestation_evidence.quote.clone(), expected_input_data, pccs, self.override_azure_outdated_tcb, @@ -483,6 +524,10 @@ impl AttestationVerifier { } } AttestationType::DcapTdx | AttestationType::QemuTdx | AttestationType::GcpTdx => { + let attestation_evidence = attestation_exchange_message + .attestation_evidence + .as_ref() + .ok_or(AttestationError::AttestationTypeNotAccepted)?; #[cfg(any(test, feature = "mock"))] let pccs = self.internal_pccs.clone().unwrap_or_else(|| Pccs::new_without_prewarm(None)); @@ -490,7 +535,7 @@ impl AttestationVerifier { let pccs = self.internal_pccs.clone().ok_or(AttestationError::NoPccs)?; dcap::verify_dcap_attestation_sync( - attestation_exchange_message.attestation, + attestation_evidence.quote.clone(), expected_input_data, pccs, )? @@ -498,8 +543,11 @@ impl AttestationVerifier { }; // Do a measurement / attestation type policy check - self.measurement_policy - .check_measurement(&measurements, attestation_exchange_message.platform_metadata)?; + let platform_metadata = attestation_exchange_message + .attestation_evidence + .as_ref() + .map(|evidence| evidence.platform.clone()); + self.measurement_policy.check_measurement(&measurements, platform_metadata)?; tracing::debug!("Verification successful"); Ok(Some(measurements)) @@ -513,12 +561,13 @@ impl AttestationVerifier { /// Write attestation data to a log file fn log_attestation(attestation: &AttestationExchangeMessage) { - if attestation.attestation_type != AttestationType::None { + if let Some(attestation_evidence) = &attestation.attestation_evidence { let timestamp = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_nanos(); - let filename = format!("quotes/{}-{}", attestation.attestation_type, timestamp); - let attestation_bytes = attestation.attestation.clone(); + let attestation_type = attestation.attestation_type(); + let filename = format!("quotes/{attestation_type}-{timestamp}"); + let attestation_bytes = attestation_evidence.quote.clone(); if let Ok(handle) = tokio::runtime::Handle::try_current() { handle.spawn(async move { if let Err(err) = tokio::fs::write(&filename, attestation_bytes).await { @@ -542,8 +591,8 @@ fn running_on_gcp() -> Result { let resp = agent.get(GCP_METADATA_API).call(); if let Ok(r) = resp { - return Ok(r.status() == 200 && - r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); + return Ok(r.status() == 200 + && r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); } Ok(false) @@ -694,9 +743,10 @@ mod tests { let input_data = [0u8; 64]; let encoded_message = AttestationExchangeMessage { - attestation_type: AttestationType::None, - attestation: vec![1, 2, 3], - platform_metadata: None, + attestation_evidence: Some(AttestationEvidence { + quote: vec![1, 2, 3], + platform: placeholder_platform_metadata(AttestationType::GcpTdx), + }), } .encode(); @@ -708,8 +758,8 @@ mod tests { input_data, ) .unwrap(); - assert_eq!(decoded.attestation_type, AttestationType::None); - assert_eq!(decoded.attestation, vec![1, 2, 3]); + assert_eq!(decoded.attestation_type(), AttestationType::GcpTdx); + assert_eq!(decoded.attestation_evidence.unwrap().quote, vec![1, 2, 3]); let raw_addr = spawn_test_attestation_provider_server(vec![9, 8]).await; let raw_url = format!("http://{raw_addr}"); @@ -719,8 +769,8 @@ mod tests { input_data, ) .unwrap(); - assert_eq!(wrapped.attestation_type, AttestationType::DcapTdx); - assert_eq!(wrapped.attestation, vec![9, 8]); + assert_eq!(wrapped.attestation_type(), AttestationType::QemuTdx); + assert_eq!(wrapped.attestation_evidence.unwrap().quote, vec![9, 8]); } #[tokio::test] diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index d4319ad..d1f99cd 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -7,10 +7,12 @@ use std::{ }; pub use attestation::{ + AttestationEvidence, AttestationExchangeMessage, AttestationGenerator, AttestationType, AttestationVerifier, + PlatformMetadata, }; use ra_tls::{ attestation::{Attestation, AttestationQuote, VersionedAttestation}, @@ -543,9 +545,15 @@ impl AttestedCertificateVerifier { // TODO maybe we have to drop support for the VersionedAttestation::V0 // format as it cannot encode platform metadata return Ok(AttestationExchangeMessage { - attestation_type: AttestationType::DcapTdx, - attestation: tdx_quote.quote, - platform_metadata: None, + attestation_evidence: Some(AttestationEvidence { + quote: tdx_quote.quote, + platform: PlatformMetadata { + attestation_type: AttestationType::DcapTdx.into(), + ram_bytes: 0, + num_disks: 0, + acpi: None, + }, + }), }); } From 54dff2438e64744efdca2f6df23d4df945f2a11b Mon Sep 17 00:00:00 2001 From: peg Date: Thu, 4 Jun 2026 19:48:28 +0200 Subject: [PATCH 10/35] Do not allow converting AttestationType::None to a attest-types::AttestationType --- crates/attestation/src/lib.rs | 38 ++++++++++++++++++++-------------- crates/attested-tls/src/lib.rs | 2 +- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 294f046..accb759 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -91,26 +91,32 @@ impl From for AttestationType { } } -impl From for attest_types::AttestationType { - fn from(attestation_type: AttestationType) -> Self { +impl TryFrom for attest_types::AttestationType { + type Error = AttestationError; + + fn try_from(attestation_type: AttestationType) -> Result { match attestation_type { - AttestationType::None => attest_types::AttestationType::SelfHostedTdx, - AttestationType::AzureTdx => attest_types::AttestationType::AzureTdx, - AttestationType::GcpTdx => attest_types::AttestationType::GcpTdx, + AttestationType::None => Err(AttestationError::AttestationTypeNotAccepted), + AttestationType::AzureTdx => Ok(attest_types::AttestationType::AzureTdx), + AttestationType::GcpTdx => Ok(attest_types::AttestationType::GcpTdx), AttestationType::DcapTdx | AttestationType::QemuTdx => { - attest_types::AttestationType::SelfHostedTdx + Ok(attest_types::AttestationType::SelfHostedTdx) } } } } -fn placeholder_platform_metadata(attestation_type: AttestationType) -> PlatformMetadata { - PlatformMetadata { - attestation_type: attestation_type.into(), +/// WIP - create placeholder platform metadata when we don't have it. +/// Used for attestation provider server - which should be fixed. +fn placeholder_platform_metadata( + attestation_type: AttestationType, +) -> Result { + Ok(PlatformMetadata { + attestation_type: attestation_type.try_into()?, ram_bytes: 0, num_disks: 0, acpi: None, - } + }) } /// Type of attestation used @@ -258,8 +264,9 @@ impl AttestationGenerator { AttestationType::AzureTdx => { #[cfg(feature = "azure")] { - let platform = - attest_measure::platform::metadata_for(self.attestation_type.into())?; + let platform = attest_measure::platform::metadata_for( + self.attestation_type.try_into()?, + )?; Ok(AttestationExchangeMessage { attestation_evidence: Some(AttestationEvidence { quote: azure::create_azure_attestation(input_data)?, @@ -277,7 +284,8 @@ impl AttestationGenerator { } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { let mut attestation_evidence = dcap::create_dcap_attestation(input_data)?; - attestation_evidence.platform.attestation_type = self.attestation_type.into(); + attestation_evidence.platform.attestation_type = + self.attestation_type.try_into()?; Ok(attestation_evidence.into()) } } @@ -312,7 +320,7 @@ impl AttestationGenerator { return Ok(AttestationExchangeMessage::without_attestation()); } - let platform = placeholder_platform_metadata(attestation_type); + let platform = placeholder_platform_metadata(attestation_type)?; Ok(AttestationExchangeMessage { attestation_evidence: Some(AttestationEvidence { quote: body, platform }), }) @@ -745,7 +753,7 @@ mod tests { let encoded_message = AttestationExchangeMessage { attestation_evidence: Some(AttestationEvidence { quote: vec![1, 2, 3], - platform: placeholder_platform_metadata(AttestationType::GcpTdx), + platform: placeholder_platform_metadata(AttestationType::GcpTdx).unwrap(), }), } .encode(); diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index d1f99cd..2d902c4 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -548,7 +548,7 @@ impl AttestedCertificateVerifier { attestation_evidence: Some(AttestationEvidence { quote: tdx_quote.quote, platform: PlatformMetadata { - attestation_type: AttestationType::DcapTdx.into(), + attestation_type: AttestationType::DcapTdx.try_into().expect("AttestationType::DcapTdx should convert to attest-types::AttestationType::SelfHosted"), ram_bytes: 0, num_disks: 0, acpi: None, From 54e86c0d43944de80604407852a47565d39b94cc Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 5 Jun 2026 08:58:25 +0200 Subject: [PATCH 11/35] fmt --- crates/attestation/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index accb759..d47c7c6 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -599,8 +599,8 @@ fn running_on_gcp() -> Result { let resp = agent.get(GCP_METADATA_API).call(); if let Ok(r) = resp { - return Ok(r.status() == 200 - && r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); + return Ok(r.status() == 200 && + r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); } Ok(false) From 46fca4510f40da81be5df64625b9c8088ecd7573 Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 16 Jun 2026 10:09:38 +0200 Subject: [PATCH 12/35] Update to use ah/gcp-hobgen branch of the attest repo --- crates/attestation/Cargo.toml | 4 +-- crates/attestation/src/measurements.rs | 40 ++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml index 866efb7..d0730a1 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -13,8 +13,8 @@ pccs = { workspace = true } mock-tdx = { workspace = true, optional = true } tokio = { workspace = true, features = ["fs"] } tokio-rustls = { workspace = true, default-features = false } -attest-types = { git = "https://github.com/easy-tee/attest.git", branch = "ah/better-interface" } -attest-measure = {git = "https://github.com/easy-tee/attest.git", branch = "ah/better-interface" } +attest-types = { git = "https://github.com/easy-tee/attest.git", branch = "ah/gcp-hobgen" } +attest-measure = {git = "https://github.com/easy-tee/attest.git", branch = "ah/gcp-hobgen" } anyhow = "1.0.100" pem-rfc7468 = { version = "0.7.0", features = ["std"] } diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index 1cf841c..a60e6e4 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -398,7 +398,17 @@ impl MeasurementPolicy { return false; }; let firmware = match platform_metadata.attestation_type { - ImageAttestationType::GcpTdx => Some(DcapFirmware::gcp_hardcoded()), + ImageAttestationType::GcpTdx => { + let Some(mrtd) = + dcap_measurements.get(&DcapMeasurementRegister::MRTD) + else { + return false; + }; + match DcapFirmware::from_google(*mrtd) { + Ok(firmware) => Some(firmware), + Err(_) => return false, + } + } ImageAttestationType::SelfHostedTdx => None, ImageAttestationType::AzureTdx => return false, }; @@ -630,9 +640,35 @@ mod tests { use attest_measure::dcap::expected_dcap_registers; use attest_types::AcpiHashes; + use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64_STANDARD}; use super::*; + /// MRTD from the pinned GCP firmware snapshot test asset + const GCP_FIRMWARE_MRTD: &str = "feb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162"; + /// CFV from the same pinned GCP firmware snapshot test asset + const GCP_FIRMWARE_CFV: &str = "9cb6bf09aea7b4acb8549e328d0edd6f15defc0b00d744bb9fb5bab0962bc5c70f69d233e96dbc7c1105ba085781dc88"; + /// Base64-encoded HOB template from the historical GCP firmware asset + /// in the attest repo. + const GCP_HOB_TEMPLATE_B64: &str = "AQA4AAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASJKAAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAA4v8AAAAAAAAeAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAA4P8AAAAAAAACAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAgQAAAAAAAAABAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAACwgAAAAAAAACAAAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAACQgAAAAAAAACAAAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAAAAAAgAAAAAAAAGAAAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAABwAAEAAAAAAAAAAAAACAAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAABwAAEABggAAAAAAAADAAAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAABwAAEADQgAAAAAAAADAAAAAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAABwAAEAAAggAAAAAAAAB+vwAAAAADADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAABwAAEAAAAAABAAAAAAAAQAMAAAA="; + /// Offset used by the historical HOB template to patch the RAM length + /// field. + const GCP_HOB_LENGTH_OFFSET: usize = 0x240; + /// RAM threshold embedded in the historical GCP HOB template snapshot. + const GCP_RAM_THRESHOLD: u64 = 3 << 30; + + fn gcp_firmware_fixture() -> DcapFirmware { + DcapFirmware { + mrtd: hex::decode(GCP_FIRMWARE_MRTD).unwrap().try_into().unwrap(), + cfv: hex::decode(GCP_FIRMWARE_CFV).unwrap().try_into().unwrap(), + hob: attest_measure::dcap::HobTemplate { + bytes: BASE64_STANDARD.decode(GCP_HOB_TEMPLATE_B64).unwrap(), + length_offset: GCP_HOB_LENGTH_OFFSET, + ram_threshold: GCP_RAM_THRESHOLD, + }, + } + } + #[tokio::test] async fn test_read_measurements_file() { let specific_measurements = @@ -742,7 +778,7 @@ mod tests { num_disks: 1, acpi: Some(AcpiHashes { loader: [0x11; 48], rsdp: [0x22; 48], tables: [0x33; 48] }), }; - let firmware = DcapFirmware::gcp_hardcoded(); + let firmware = gcp_firmware_fixture(); let expected_measurements = expected_dcap_registers(&image_hashes, &platform_metadata, Some(&firmware)).unwrap(); From d75fda9696c8f07887316bb65d8054e5b02577e7 Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 16 Jun 2026 10:09:54 +0200 Subject: [PATCH 13/35] Update to use ah/gcp-hobgen branch of the attest repo --- Cargo.lock | 70 +++++++++++++++++++++++++++++++++++--- crates/mock-tdx/Cargo.toml | 2 +- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c53b2ba..08faa53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -346,7 +346,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attest-measure" version = "0.0.1" -source = "git+https://github.com/easy-tee/attest.git?branch=ah%2Fbetter-interface#9436797ccde6354d54e1b912bb116cb66678c33d" +source = "git+https://github.com/easy-tee/attest.git?branch=ah%2Fgcp-hobgen#e5f89321d37dbbd3b7ccc4cfee4e715dd440ffdf" dependencies = [ "anyhow", "attest-types", @@ -355,17 +355,21 @@ dependencies = [ "hex", "hex-literal", "object", + "prost", + "rsa", "serde", "serde_json", "serde_with", "sha2", "thiserror 2.0.18", + "ureq 3.3.0", + "x509-parser 0.18.1", ] [[package]] name = "attest-types" version = "0.0.1" -source = "git+https://github.com/easy-tee/attest.git?branch=ah%2Fbetter-interface#9436797ccde6354d54e1b912bb116cb66678c33d" +source = "git+https://github.com/easy-tee/attest.git?branch=ah%2Fgcp-hobgen#e5f89321d37dbbd3b7ccc4cfee4e715dd440ffdf" dependencies = [ "parity-scale-codec", "serde", @@ -406,7 +410,7 @@ dependencies = [ "tokio-rustls", "tracing", "tss-esapi", - "ureq", + "ureq 2.12.1", "x509-parser 0.18.1", ] @@ -579,7 +583,7 @@ dependencies = [ "serde", "serde_json", "thiserror 2.0.18", - "ureq", + "ureq 2.12.1", "zerocopy", ] @@ -3299,6 +3303,29 @@ dependencies = [ "yansi", ] +[[package]] +name = "prost" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quinn" version = "0.11.9" @@ -4758,6 +4785,35 @@ dependencies = [ "webpki-roots 0.26.11", ] +[[package]] +name = "ureq" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" +dependencies = [ + "base64 0.22.1", + "flate2", + "log", + "percent-encoding", + "rustls", + "rustls-pki-types", + "ureq-proto", + "utf8-zero", + "webpki-roots 1.0.7", +] + +[[package]] +name = "ureq-proto" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +dependencies = [ + "base64 0.22.1", + "http 1.4.0", + "httparse", + "log", +] + [[package]] name = "url" version = "2.5.8" @@ -4776,6 +4832,12 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + [[package]] name = "utf8_iter" version = "1.0.4" diff --git a/crates/mock-tdx/Cargo.toml b/crates/mock-tdx/Cargo.toml index 720005b..b34c49f 100644 --- a/crates/mock-tdx/Cargo.toml +++ b/crates/mock-tdx/Cargo.toml @@ -21,7 +21,7 @@ tokio = { workspace = true, features = ["rt", "net"] } urlencoding = "2.1.3" yasna = "0.5.2" x509-parser = "0.18.1" -attest-types = { git = "https://github.com/easy-tee/attest.git", branch = "ah/better-interface" } +attest-types = { git = "https://github.com/easy-tee/attest.git", branch = "ah/gcp-hobgen" } [lints] workspace = true From 52370b028319a06422362948dfeebd6c2eacdf3a Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 16 Jun 2026 10:17:01 +0200 Subject: [PATCH 14/35] Logging, fix for attestation-provider-server --- crates/attestation-provider-server/src/lib.rs | 2 +- crates/attestation/src/measurements.rs | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/attestation-provider-server/src/lib.rs b/crates/attestation-provider-server/src/lib.rs index 1db9232..e13632b 100644 --- a/crates/attestation-provider-server/src/lib.rs +++ b/crates/attestation-provider-server/src/lib.rs @@ -55,7 +55,7 @@ pub async fn attestation_provider_client( .await?; let remote_attestation_message = AttestationExchangeMessage::decode(&mut &response[..])?; - let remote_attestation_type = remote_attestation_message.attestation_type; + let remote_attestation_type = remote_attestation_message.attestation_type(); println!("Remote attestation type: {remote_attestation_type}"); diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index a60e6e4..c743bad 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -8,6 +8,7 @@ use dcap_qvl::quote::Report; use http::{HeaderValue, header::InvalidHeaderValue, uri::InvalidUri}; use serde::Deserialize; use thiserror::Error; +use tracing::warn; use crate::{AttestationError, AttestationType, dcap::DcapVerificationError}; @@ -402,11 +403,17 @@ impl MeasurementPolicy { let Some(mrtd) = dcap_measurements.get(&DcapMeasurementRegister::MRTD) else { + warn!( + "Could not match image hash measurement due to missing MRTD" + ); return false; }; match DcapFirmware::from_google(*mrtd) { Ok(firmware) => Some(firmware), - Err(_) => return false, + Err(err) => { + warn!("Could not match image hash measurement - failed to fetch or verify Google firmware: {err:?}"); + return false + }, } } ImageAttestationType::SelfHostedTdx => None, From bcc671fa13dc0a2bf76e4072dad2f9334db60750 Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 16 Jun 2026 12:11:12 +0200 Subject: [PATCH 15/35] Cache known GCP firmware indexed by MRTD --- crates/attestation/src/azure/mod.rs | 2 +- crates/attestation/src/dcap.rs | 2 +- crates/attestation/src/gcp.rs | 152 ++ crates/attestation/src/lib.rs | 54 +- crates/attestation/src/measurements.rs | 68 +- .../test-assets/gcp-known-firmware.json | 1565 +++++++++++++++++ 6 files changed, 1814 insertions(+), 29 deletions(-) create mode 100644 crates/attestation/src/gcp.rs create mode 100644 crates/attestation/test-assets/gcp-known-firmware.json diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 66bd1d5..0aba02b 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -863,7 +863,7 @@ mod tests { .unwrap(); assert_eq!(async_measurements, sync_measurements); - measurement_policy.check_measurement(&async_measurements, None).unwrap(); + measurement_policy.check_measurement(&async_measurements, None, None).unwrap(); } /// Verify a complete observed Azure attestation payload that includes diff --git a/crates/attestation/src/dcap.rs b/crates/attestation/src/dcap.rs index 516e30c..e34a697 100644 --- a/crates/attestation/src/dcap.rs +++ b/crates/attestation/src/dcap.rs @@ -369,7 +369,7 @@ mod tests { .unwrap(); assert_eq!(async_measurements, sync_measurements); - measurement_policy.check_measurement(&async_measurements, None).unwrap(); + measurement_policy.check_measurement(&async_measurements, None, None).unwrap(); } // This specifically tests a quote which has outdated TCB level from Azure diff --git a/crates/attestation/src/gcp.rs b/crates/attestation/src/gcp.rs new file mode 100644 index 0000000..6e47cd7 --- /dev/null +++ b/crates/attestation/src/gcp.rs @@ -0,0 +1,152 @@ +use std::{ + collections::HashMap, + io::Read, + sync::{Arc, RwLock}, +}; + +use attest_measure::dcap::DcapFirmware; +use serde::Deserialize; +use thiserror::Error; + +const GCS_FIRMWARE_LIST_URL: &str = + "https://storage.googleapis.com/storage/v1/b/gce_tcb_integrity/o"; +const GCS_FIRMWARE_PREFIX: &str = "ovmf_x64_csm/tdx/"; +const GCS_FIRMWARE_MAX_RESULTS: &str = "1000"; + +#[derive(Clone, Debug, Default)] +pub(crate) struct GcpFirmwareCache { + cache: Arc>>, +} + +#[derive(Debug, Error)] +pub enum GcpFirmwareCacheError { + #[error("HTTP: {0}")] + Http(String), + #[error("response body was not valid UTF-8")] + Utf8(#[from] std::string::FromUtf8Error), + #[error("listing JSON: {0}")] + Listing(#[from] serde_json::Error), + #[error("invalid GCP firmware object name: {0}")] + ObjectName(String), + #[error("invalid MRTD hex in object name: {0}")] + Mrtd(String), + #[error("firmware: {0}")] + Firmware(#[from] attest_measure::dcap::GoogleError), +} + +#[derive(Debug, Deserialize)] +struct GcsObjectsResponse { + #[serde(default)] + items: Vec, +} + +#[derive(Debug, Deserialize)] +struct GcsObject { + name: String, +} + +impl GcpFirmwareCache { + pub(crate) fn new() -> Self { + Self { cache: Default::default() } + } + + pub(crate) fn prewarm() -> Result { + let cache = Self::new(); + for mrtd in fetch_known_mrtds()? { + cache.get_or_fetch(mrtd)?; + } + Ok(cache) + } + + pub(crate) fn get_or_fetch( + &self, + mrtd: [u8; 48], + ) -> Result { + if let Some(firmware) = self.cache.read().unwrap().get(&mrtd).cloned() { + return Ok(firmware); + } + + let firmware = DcapFirmware::from_google(mrtd)?; + self.cache.write().unwrap().insert(mrtd, firmware.clone()); + Ok(firmware) + } +} + +fn fetch_known_mrtds() -> Result, GcpFirmwareCacheError> { + let response = ureq::get(GCS_FIRMWARE_LIST_URL) + .query("prefix", GCS_FIRMWARE_PREFIX) + .query("maxResults", GCS_FIRMWARE_MAX_RESULTS) + .call() + .map_err(|err| GcpFirmwareCacheError::Http(err.to_string()))?; + let mut reader = response.into_reader(); + let mut body = Vec::new(); + reader.read_to_end(&mut body).map_err(|err| GcpFirmwareCacheError::Http(err.to_string()))?; + parse_known_mrtds(&body) +} + +fn parse_known_mrtds(body: &[u8]) -> Result, GcpFirmwareCacheError> { + let body = String::from_utf8(body.to_vec())?; + let objects: GcsObjectsResponse = serde_json::from_str(&body)?; + + let mut mrtds = Vec::new(); + for object in objects.items { + if let Some(mrtd) = parse_mrtd_from_object_name(&object.name)? { + mrtds.push(mrtd); + } + } + + if mrtds.is_empty() { + return Err(GcpFirmwareCacheError::ObjectName( + "no GCP firmware objects were discovered during prewarm".to_string(), + )); + } + + Ok(mrtds) +} + +fn parse_mrtd_from_object_name(name: &str) -> Result, GcpFirmwareCacheError> { + if !name.starts_with(GCS_FIRMWARE_PREFIX) || !name.ends_with(".binarypb") { + return Ok(None); + } + + let hex = &name[GCS_FIRMWARE_PREFIX.len()..name.len() - ".binarypb".len()]; + let bytes = hex::decode(hex).map_err(|_| GcpFirmwareCacheError::Mrtd(name.to_string()))?; + let mrtd: [u8; 48] = + bytes.try_into().map_err(|_| GcpFirmwareCacheError::Mrtd(name.to_string()))?; + Ok(Some(mrtd)) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[ignore] + fn dump_gcs_firmware_listing() { + let response = ureq::get(GCS_FIRMWARE_LIST_URL) + .query("prefix", GCS_FIRMWARE_PREFIX) + .query("maxResults", GCS_FIRMWARE_MAX_RESULTS) + .call() + .unwrap(); + let mut reader = response.into_reader(); + let mut body = Vec::new(); + reader.read_to_end(&mut body).unwrap(); + println!("{}", String::from_utf8(body).unwrap()); + } + + #[test] + fn parse_known_mrtds_fixture() { + let body = include_bytes!("../test-assets/gcp-known-firmware.json"); + let mrtds = parse_known_mrtds(body).unwrap(); + + assert_eq!(mrtds.len(), 78); + assert_eq!( + hex::encode(mrtds[0]), + "038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086" + ); + assert_eq!( + hex::encode(mrtds[1]), + "0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6" + ); + } +} diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index d47c7c6..6402bc1 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -3,8 +3,8 @@ #[cfg(feature = "azure")] pub mod azure; pub mod dcap; +mod gcp; pub mod measurements; - use std::{ fmt::{self, Display, Formatter}, io::Read, @@ -14,6 +14,7 @@ use std::{ use attest_measure::platform::PlatformError; pub use attest_types::{AttestationEvidence, PlatformMetadata}; +pub use gcp::GcpFirmwareCacheError; use measurements::MultiMeasurements; use parity_scale_codec::{Decode, Encode}; use pccs::{Pccs, PccsError}; @@ -345,14 +346,17 @@ pub struct AttestationVerifier { pub override_azure_outdated_tcb: bool, /// Internal cache for collateral pub internal_pccs: Option, + /// Cached GCP firmware blobs indexed by MRTD + known_gcp_firmware: gcp::GcpFirmwareCache, } impl AttestationVerifier { - pub fn new( + fn build( measurement_policy: MeasurementPolicy, pccs_url: Option, dump_dcap_quotes: bool, override_azure_outdated_tcb: bool, + known_gcp_firmware: gcp::GcpFirmwareCache, ) -> Self { Self { measurement_policy, @@ -360,9 +364,40 @@ impl AttestationVerifier { dump_dcap_quotes, override_azure_outdated_tcb, internal_pccs: Some(Pccs::new(pccs_url)), + known_gcp_firmware, } } + pub fn new( + measurement_policy: MeasurementPolicy, + pccs_url: Option, + dump_dcap_quotes: bool, + override_azure_outdated_tcb: bool, + ) -> Self { + Self::build( + measurement_policy, + pccs_url, + dump_dcap_quotes, + override_azure_outdated_tcb, + gcp::GcpFirmwareCache::new(), + ) + } + + pub fn new_prewarmed( + measurement_policy: MeasurementPolicy, + pccs_url: Option, + dump_dcap_quotes: bool, + override_azure_outdated_tcb: bool, + ) -> Result { + Ok(Self::build( + measurement_policy, + pccs_url, + dump_dcap_quotes, + override_azure_outdated_tcb, + gcp::GcpFirmwareCache::prewarm()?, + )) + } + /// Create an [AttestationVerifier] which will only allow no attestation /// and will reject if one is given pub fn expect_none() -> Self { @@ -372,6 +407,7 @@ impl AttestationVerifier { dump_dcap_quotes: false, override_azure_outdated_tcb: false, internal_pccs: None, + known_gcp_firmware: gcp::GcpFirmwareCache::new(), } } @@ -384,6 +420,7 @@ impl AttestationVerifier { dump_dcap_quotes: false, override_azure_outdated_tcb: false, internal_pccs: None, + known_gcp_firmware: gcp::GcpFirmwareCache::new(), } } @@ -396,6 +433,7 @@ impl AttestationVerifier { dump_dcap_quotes: false, override_azure_outdated_tcb: false, internal_pccs: Some(Pccs::new(Some(pccs_url))), + known_gcp_firmware: gcp::GcpFirmwareCache::new(), } } @@ -482,7 +520,11 @@ impl AttestationVerifier { .attestation_evidence .as_ref() .map(|evidence| evidence.platform.clone()); - self.measurement_policy.check_measurement(&measurements, platform_metadata)?; + self.measurement_policy.check_measurement( + &measurements, + platform_metadata, + Some(&self.known_gcp_firmware), + )?; tracing::debug!("Verification successful"); Ok(Some(measurements)) @@ -555,7 +597,11 @@ impl AttestationVerifier { .attestation_evidence .as_ref() .map(|evidence| evidence.platform.clone()); - self.measurement_policy.check_measurement(&measurements, platform_metadata)?; + self.measurement_policy.check_measurement( + &measurements, + platform_metadata, + Some(&self.known_gcp_firmware), + )?; tracing::debug!("Verification successful"); Ok(Some(measurements)) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index c743bad..d0c16fe 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -10,7 +10,12 @@ use serde::Deserialize; use thiserror::Error; use tracing::warn; -use crate::{AttestationError, AttestationType, dcap::DcapVerificationError}; +use crate::{ + AttestationError, + AttestationType, + dcap::DcapVerificationError, + gcp::GcpFirmwareCache, +}; /// Represents the measurement register types in a TDX quote #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -376,10 +381,11 @@ impl MeasurementPolicy { /// Given an attestation type and set of measurements, check whether /// they are acceptable - pub fn check_measurement( + pub(crate) fn check_measurement( &self, measurements: &MultiMeasurements, platform_metadata: Option, + known_gcp_firmware: Option<&GcpFirmwareCache>, ) -> Result<(), AttestationError> { if self.accepted_measurements.iter().any(|measurement_record| match measurements { MultiMeasurements::Dcap(dcap_measurements) => { @@ -408,24 +414,36 @@ impl MeasurementPolicy { ); return false; }; - match DcapFirmware::from_google(*mrtd) { + + let result = if let Some(cache) = known_gcp_firmware { + cache.get_or_fetch(*mrtd) + } else { + DcapFirmware::from_google(*mrtd) + }; + match result { Ok(firmware) => Some(firmware), Err(err) => { - warn!("Could not match image hash measurement - failed to fetch or verify Google firmware: {err:?}"); - return false - }, + warn!( + "Could not match image hash measurement - failed to fetch or verify Google firmware: {err:?}" + ); + return false; + } } } ImageAttestationType::SelfHostedTdx => None, ImageAttestationType::AzureTdx => return false, }; - let Ok(expected_measurements) = expected_dcap_registers( + let expected_measurements = match expected_dcap_registers( image_hashes, platform_metadata, firmware.as_ref(), - ) else { - return false; // TODO should we bail here + ) { + Ok(expected) => expected, + Err(err) => { + warn!("Failed to compute expected DCAP registers: {err:?}"); + return false; // TODO should we bail here + } }; if let Some(expected_mrtd) = expected_measurements.mrtd { @@ -710,14 +728,16 @@ mod tests { // Will not match mock measurements assert!(matches!( - specific_measurements.check_measurement(&mock_dcap_measurements(), None).unwrap_err(), + specific_measurements + .check_measurement(&mock_dcap_measurements(), None, None) + .unwrap_err(), AttestationError::MeasurementsNotAccepted )); // Will not match another attestation type assert!(matches!( specific_measurements - .check_measurement(&MultiMeasurements::NoAttestation, None) + .check_measurement(&MultiMeasurements::NoAttestation, None, None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -725,7 +745,7 @@ mod tests { // A non-specific measurement fails assert!(matches!( specific_measurements - .check_measurement(&MultiMeasurements::Azure(HashMap::new()), None) + .check_measurement(&MultiMeasurements::Azure(HashMap::new()), None, None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -738,12 +758,12 @@ mod tests { let allowed_attestation_type = MeasurementPolicy::from_file("test-assets/measurements_2.json".into()).await.unwrap(); - allowed_attestation_type.check_measurement(&mock_dcap_measurements(), None).unwrap(); + allowed_attestation_type.check_measurement(&mock_dcap_measurements(), None, None).unwrap(); // Will not match another attestation type assert!(matches!( allowed_attestation_type - .check_measurement(&MultiMeasurements::NoAttestation, None) + .check_measurement(&MultiMeasurements::NoAttestation, None, None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -797,7 +817,7 @@ mod tests { (DcapMeasurementRegister::RTMR3, mock_tdx::MOCK_RTMR3), ])); - policy.check_measurement(&measurements, Some(platform_metadata)).unwrap(); + policy.check_measurement(&measurements, Some(platform_metadata), None).unwrap(); } #[tokio::test] @@ -813,13 +833,15 @@ mod tests { assert!(!policy.accepted_measurements.is_empty()); assert!(matches!( - policy.check_measurement(&MultiMeasurements::NoAttestation, None).unwrap_err(), + policy.check_measurement(&MultiMeasurements::NoAttestation, None, None).unwrap_err(), AttestationError::MeasurementsNotAccepted )); // A non-specific measurement fails assert!(matches!( - policy.check_measurement(&MultiMeasurements::Azure(HashMap::new()), None).unwrap_err(), + policy + .check_measurement(&MultiMeasurements::Azure(HashMap::new()), None, None) + .unwrap_err(), AttestationError::MeasurementsNotAccepted )); } @@ -875,17 +897,17 @@ mod tests { // First value should match let measurements1 = MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0u8; 48])])); - assert!(policy.check_measurement(&measurements1, None).is_ok()); + assert!(policy.check_measurement(&measurements1, None, None).is_ok()); // Second value should also match let measurements2 = MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0x11u8; 48])])); - assert!(policy.check_measurement(&measurements2, None).is_ok()); + assert!(policy.check_measurement(&measurements2, None, None).is_ok()); // Different value should not match let measurements3 = MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0x22u8; 48])])); - assert!(policy.check_measurement(&measurements3, None).is_err()); + assert!(policy.check_measurement(&measurements3, None, None).is_err()); } #[tokio::test] @@ -965,21 +987,21 @@ mod tests { (DcapMeasurementRegister::MRTD, [0u8; 48]), (DcapMeasurementRegister::RTMR0, [0x11u8; 48]), ])); - assert!(policy.check_measurement(&measurements1, None).is_ok()); + assert!(policy.check_measurement(&measurements1, None, None).is_ok()); // Both match (single + second of any) let measurements2 = MultiMeasurements::Dcap(HashMap::from([ (DcapMeasurementRegister::MRTD, [0u8; 48]), (DcapMeasurementRegister::RTMR0, [0x22u8; 48]), ])); - assert!(policy.check_measurement(&measurements2, None).is_ok()); + assert!(policy.check_measurement(&measurements2, None, None).is_ok()); // Single matches but any doesn't let measurements3 = MultiMeasurements::Dcap(HashMap::from([ (DcapMeasurementRegister::MRTD, [0u8; 48]), (DcapMeasurementRegister::RTMR0, [0x33u8; 48]), ])); - assert!(policy.check_measurement(&measurements3, None).is_err()); + assert!(policy.check_measurement(&measurements3, None, None).is_err()); } #[tokio::test] diff --git a/crates/attestation/test-assets/gcp-known-firmware.json b/crates/attestation/test-assets/gcp-known-firmware.json new file mode 100644 index 0000000..27176f4 --- /dev/null +++ b/crates/attestation/test-assets/gcp-known-firmware.json @@ -0,0 +1,1565 @@ +{ + "kind": "storage#objects", + "items": [ + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086.binarypb/1728951531410960", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086.binarypb?generation=1728951531410960&alt=media", + "name": "ovmf_x64_csm/tdx/038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951531410960", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CJCs9K6Oj4kDEAE=", + "timeCreated": "2024-10-15T00:18:51.417Z", + "updated": "2024-10-15T00:18:51.417Z", + "timeStorageClassUpdated": "2024-10-15T00:18:51.417Z", + "timeFinalized": "2024-10-15T00:18:51.417Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6.binarypb/1725637332221777", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6.binarypb?generation=1725637332221777&alt=media", + "name": "ovmf_x64_csm/tdx/0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1725637332221777", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5873", + "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", + "crc32c": "7PKCRw==", + "etag": "CNH+yoHUrogDEAE=", + "timeCreated": "2024-09-06T15:42:12.223Z", + "updated": "2024-09-06T15:42:12.223Z", + "timeStorageClassUpdated": "2024-09-06T15:42:12.223Z", + "timeFinalized": "2024-09-06T15:42:12.223Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/0801dc9908dd4fcf6a03893e6e2803be64bebb568a2651f0238d07b9afe54028246f2f7e7a1768fe2b7653427be5aff1.binarypb/1725637337880372", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0801dc9908dd4fcf6a03893e6e2803be64bebb568a2651f0238d07b9afe54028246f2f7e7a1768fe2b7653427be5aff1.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0801dc9908dd4fcf6a03893e6e2803be64bebb568a2651f0238d07b9afe54028246f2f7e7a1768fe2b7653427be5aff1.binarypb?generation=1725637337880372&alt=media", + "name": "ovmf_x64_csm/tdx/0801dc9908dd4fcf6a03893e6e2803be64bebb568a2651f0238d07b9afe54028246f2f7e7a1768fe2b7653427be5aff1.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1725637337880372", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5873", + "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", + "crc32c": "7PKCRw==", + "etag": "CLSupITUrogDEAE=", + "timeCreated": "2024-09-06T15:42:17.881Z", + "updated": "2024-09-06T15:42:17.881Z", + "timeStorageClassUpdated": "2024-09-06T15:42:17.881Z", + "timeFinalized": "2024-09-06T15:42:17.881Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/0e9616e6bca294aaa38d5127af79d212c0e8d193d1e8c4d714121e717081057b3f3b37aaa414c7b6fc29b9237ce8d142.binarypb/1723585975353261", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0e9616e6bca294aaa38d5127af79d212c0e8d193d1e8c4d714121e717081057b3f3b37aaa414c7b6fc29b9237ce8d142.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0e9616e6bca294aaa38d5127af79d212c0e8d193d1e8c4d714121e717081057b3f3b37aaa414c7b6fc29b9237ce8d142.binarypb?generation=1723585975353261&alt=media", + "name": "ovmf_x64_csm/tdx/0e9616e6bca294aaa38d5127af79d212c0e8d193d1e8c4d714121e717081057b3f3b37aaa414c7b6fc29b9237ce8d142.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723585975353261", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5868", + "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", + "crc32c": "YXklrg==", + "etag": "CK3/s4768ocDEAE=", + "timeCreated": "2024-08-13T21:52:55.356Z", + "updated": "2024-08-13T21:52:55.356Z", + "timeStorageClassUpdated": "2024-08-13T21:52:55.356Z", + "timeFinalized": "2024-08-13T21:52:55.356Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/14d4600f8d1dc8249e9cea29aad07160fa242c54005b50f1814a34cc9f766e2064658376a2409d7ffd69363e95689ec9.binarypb/1723135792757493", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F14d4600f8d1dc8249e9cea29aad07160fa242c54005b50f1814a34cc9f766e2064658376a2409d7ffd69363e95689ec9.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F14d4600f8d1dc8249e9cea29aad07160fa242c54005b50f1814a34cc9f766e2064658376a2409d7ffd69363e95689ec9.binarypb?generation=1723135792757493&alt=media", + "name": "ovmf_x64_csm/tdx/14d4600f8d1dc8249e9cea29aad07160fa242c54005b50f1814a34cc9f766e2064658376a2409d7ffd69363e95689ec9.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723135792757493", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5866", + "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", + "crc32c": "Twn57g==", + "etag": "CPX1zobt5YcDEAE=", + "timeCreated": "2024-08-08T16:49:52.759Z", + "updated": "2024-08-08T16:49:52.759Z", + "timeStorageClassUpdated": "2024-08-08T16:49:52.759Z", + "timeFinalized": "2024-08-08T16:49:52.759Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/174c707bfe72f2f86a029a01ba6917670fe90c5af9594355f3fca0e4c02afae5ac791ac2d49470e6b00333ff9732c51d.binarypb/1723135810306527", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F174c707bfe72f2f86a029a01ba6917670fe90c5af9594355f3fca0e4c02afae5ac791ac2d49470e6b00333ff9732c51d.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F174c707bfe72f2f86a029a01ba6917670fe90c5af9594355f3fca0e4c02afae5ac791ac2d49470e6b00333ff9732c51d.binarypb?generation=1723135810306527&alt=media", + "name": "ovmf_x64_csm/tdx/174c707bfe72f2f86a029a01ba6917670fe90c5af9594355f3fca0e4c02afae5ac791ac2d49470e6b00333ff9732c51d.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723135810306527", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5866", + "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", + "crc32c": "Twn57g==", + "etag": "CN+D/o7t5YcDEAE=", + "timeCreated": "2024-08-08T16:50:10.310Z", + "updated": "2024-08-08T16:50:10.310Z", + "timeStorageClassUpdated": "2024-08-08T16:50:10.310Z", + "timeFinalized": "2024-08-08T16:50:10.310Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/1859e2894b0b0a279597bd5ab46baa7d6f3a246706832709e65658396e33aa74b10541e981f5355921275227e3ca5803.binarypb/1723585984037070", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1859e2894b0b0a279597bd5ab46baa7d6f3a246706832709e65658396e33aa74b10541e981f5355921275227e3ca5803.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1859e2894b0b0a279597bd5ab46baa7d6f3a246706832709e65658396e33aa74b10541e981f5355921275227e3ca5803.binarypb?generation=1723585984037070&alt=media", + "name": "ovmf_x64_csm/tdx/1859e2894b0b0a279597bd5ab46baa7d6f3a246706832709e65658396e33aa74b10541e981f5355921275227e3ca5803.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723585984037070", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5868", + "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", + "crc32c": "YXklrg==", + "etag": "CM6BxpL68ocDEAE=", + "timeCreated": "2024-08-13T21:53:04.039Z", + "updated": "2024-08-13T21:53:04.039Z", + "timeStorageClassUpdated": "2024-08-13T21:53:04.039Z", + "timeFinalized": "2024-08-13T21:53:04.039Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/1c4b129360c4827bc42374ab0eddfe2f9e39192d65e3b27374ee930d1365f9c2cea1ed8923b3917691c676e195d9276a.binarypb/1759434910156667", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1c4b129360c4827bc42374ab0eddfe2f9e39192d65e3b27374ee930d1365f9c2cea1ed8923b3917691c676e195d9276a.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1c4b129360c4827bc42374ab0eddfe2f9e39192d65e3b27374ee930d1365f9c2cea1ed8923b3917691c676e195d9276a.binarypb?generation=1759434910156667&alt=media", + "name": "ovmf_x64_csm/tdx/1c4b129360c4827bc42374ab0eddfe2f9e39192d65e3b27374ee930d1365f9c2cea1ed8923b3917691c676e195d9276a.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1759434910156667", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "v2EL4wcxApEurObXDr2Ulg==", + "crc32c": "5ek1mQ==", + "etag": "CPuOzealhpADEAE=", + "timeCreated": "2025-10-02T19:55:10.159Z", + "updated": "2025-10-02T19:55:10.159Z", + "timeStorageClassUpdated": "2025-10-02T19:55:10.159Z", + "timeFinalized": "2025-10-02T19:55:10.159Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/1cdf036c40e4bd17c17b6c89d97292c7f4520c42d7a0e3088b5fcd65a8162b65e1285b0aad6a5ab8cb1fc0275bb568ef.binarypb/1719876450123148", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1cdf036c40e4bd17c17b6c89d97292c7f4520c42d7a0e3088b5fcd65a8162b65e1285b0aad6a5ab8cb1fc0275bb568ef.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1cdf036c40e4bd17c17b6c89d97292c7f4520c42d7a0e3088b5fcd65a8162b65e1285b0aad6a5ab8cb1fc0275bb568ef.binarypb?generation=1719876450123148&alt=media", + "name": "ovmf_x64_csm/tdx/1cdf036c40e4bd17c17b6c89d97292c7f4520c42d7a0e3088b5fcd65a8162b65e1285b0aad6a5ab8cb1fc0275bb568ef.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1719876450123148", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5865", + "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", + "crc32c": "s0O/hw==", + "etag": "CIz794b/hocDEAE=", + "timeCreated": "2024-07-01T23:27:30.124Z", + "updated": "2024-07-01T23:27:30.124Z", + "timeStorageClassUpdated": "2024-07-01T23:27:30.124Z", + "timeFinalized": "2024-07-01T23:27:30.124Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/2013fba7cf71a71f0e88d980093836e1c5a15c3f5a862f82acaa6693f04714fd82728551129d669276111805eed415a7.binarypb/1726777919296573", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2013fba7cf71a71f0e88d980093836e1c5a15c3f5a862f82acaa6693f04714fd82728551129d669276111805eed415a7.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2013fba7cf71a71f0e88d980093836e1c5a15c3f5a862f82acaa6693f04714fd82728551129d669276111805eed415a7.binarypb?generation=1726777919296573&alt=media", + "name": "ovmf_x64_csm/tdx/2013fba7cf71a71f0e88d980093836e1c5a15c3f5a862f82acaa6693f04714fd82728551129d669276111805eed415a7.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1726777919296573", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5868", + "md5Hash": "q8QrsAgVMc9+mN0gFv+2CA==", + "crc32c": "x1hIgw==", + "etag": "CL2o8YPtz4gDEAE=", + "timeCreated": "2024-09-19T20:31:59.297Z", + "updated": "2024-09-19T20:31:59.297Z", + "timeStorageClassUpdated": "2024-09-19T20:31:59.297Z", + "timeFinalized": "2024-09-19T20:31:59.297Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525.binarypb/1733428457865719", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525.binarypb?generation=1733428457865719&alt=media", + "name": "ovmf_x64_csm/tdx/2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1733428457865719", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5307", + "md5Hash": "sed+XMq9hsc2HlOdKEYlrg==", + "crc32c": "t4bzlA==", + "etag": "CPeD5pu0kYoDEAE=", + "timeCreated": "2024-12-05T19:54:17.867Z", + "updated": "2024-12-05T19:54:17.867Z", + "timeStorageClassUpdated": "2024-12-05T19:54:17.867Z", + "timeFinalized": "2024-12-05T19:54:17.867Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/2b628010aa45375938437a5e85efa0767483d8ec0c8b02f5a04cc4b5dc99e7c09255390e7b38da983b51592a596b24bf.binarypb/1723585971915609", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2b628010aa45375938437a5e85efa0767483d8ec0c8b02f5a04cc4b5dc99e7c09255390e7b38da983b51592a596b24bf.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2b628010aa45375938437a5e85efa0767483d8ec0c8b02f5a04cc4b5dc99e7c09255390e7b38da983b51592a596b24bf.binarypb?generation=1723585971915609&alt=media", + "name": "ovmf_x64_csm/tdx/2b628010aa45375938437a5e85efa0767483d8ec0c8b02f5a04cc4b5dc99e7c09255390e7b38da983b51592a596b24bf.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723585971915609", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5868", + "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", + "crc32c": "YXklrg==", + "etag": "CNmW4oz68ocDEAE=", + "timeCreated": "2024-08-13T21:52:51.921Z", + "updated": "2024-08-13T21:52:51.921Z", + "timeStorageClassUpdated": "2024-08-13T21:52:51.921Z", + "timeFinalized": "2024-08-13T21:52:51.921Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/30f70a91e36b6564c91f49c3318410efbd2e129009bd37419f97b68b96f4d5c7c878be5515001607dd3b70b5351478ef.binarypb/1719876453464805", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F30f70a91e36b6564c91f49c3318410efbd2e129009bd37419f97b68b96f4d5c7c878be5515001607dd3b70b5351478ef.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F30f70a91e36b6564c91f49c3318410efbd2e129009bd37419f97b68b96f4d5c7c878be5515001607dd3b70b5351478ef.binarypb?generation=1719876453464805&alt=media", + "name": "ovmf_x64_csm/tdx/30f70a91e36b6564c91f49c3318410efbd2e129009bd37419f97b68b96f4d5c7c878be5515001607dd3b70b5351478ef.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1719876453464805", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5865", + "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", + "crc32c": "s0O/hw==", + "etag": "COX1w4j/hocDEAE=", + "timeCreated": "2024-07-01T23:27:33.466Z", + "updated": "2024-07-01T23:27:33.466Z", + "timeStorageClassUpdated": "2024-07-01T23:27:33.466Z", + "timeFinalized": "2024-07-01T23:27:33.466Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/31fcc66cd7e1b43462da46028cd9728d49b3400906a306185b7f8091e5d6f5ecb368fb86463263ea66178aa4015459f0.binarypb/1728083460112238", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F31fcc66cd7e1b43462da46028cd9728d49b3400906a306185b7f8091e5d6f5ecb368fb86463263ea66178aa4015459f0.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F31fcc66cd7e1b43462da46028cd9728d49b3400906a306185b7f8091e5d6f5ecb368fb86463263ea66178aa4015459f0.binarypb?generation=1728083460112238&alt=media", + "name": "ovmf_x64_csm/tdx/31fcc66cd7e1b43462da46028cd9728d49b3400906a306185b7f8091e5d6f5ecb368fb86463263ea66178aa4015459f0.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728083460112238", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", + "crc32c": "k9E9bA==", + "etag": "CO7+oMbs9YgDEAE=", + "timeCreated": "2024-10-04T23:11:00.113Z", + "updated": "2024-10-04T23:11:00.113Z", + "timeStorageClassUpdated": "2024-10-04T23:11:00.113Z", + "timeFinalized": "2024-10-04T23:11:00.113Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/3a936a289984cb494bd1ece845e7b0bba293a33b560ff557e88468797a4cf7c32c12077182cbd9f2577f7a8c62956fb4.binarypb/1723135801822321", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3a936a289984cb494bd1ece845e7b0bba293a33b560ff557e88468797a4cf7c32c12077182cbd9f2577f7a8c62956fb4.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3a936a289984cb494bd1ece845e7b0bba293a33b560ff557e88468797a4cf7c32c12077182cbd9f2577f7a8c62956fb4.binarypb?generation=1723135801822321&alt=media", + "name": "ovmf_x64_csm/tdx/3a936a289984cb494bd1ece845e7b0bba293a33b560ff557e88468797a4cf7c32c12077182cbd9f2577f7a8c62956fb4.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723135801822321", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5866", + "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", + "crc32c": "Twn57g==", + "etag": "CPGY+Irt5YcDEAE=", + "timeCreated": "2024-08-08T16:50:01.824Z", + "updated": "2024-08-08T16:50:01.824Z", + "timeStorageClassUpdated": "2024-08-08T16:50:01.824Z", + "timeFinalized": "2024-08-08T16:50:01.824Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/3c8afc83fb70127b7566298d76b609bce1e3d71d88eca54e64ea1fbe33a51e8b890c6b3696e6fef2100a1aabbb9d2cb7.binarypb/1728951528515504", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3c8afc83fb70127b7566298d76b609bce1e3d71d88eca54e64ea1fbe33a51e8b890c6b3696e6fef2100a1aabbb9d2cb7.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3c8afc83fb70127b7566298d76b609bce1e3d71d88eca54e64ea1fbe33a51e8b890c6b3696e6fef2100a1aabbb9d2cb7.binarypb?generation=1728951528515504&alt=media", + "name": "ovmf_x64_csm/tdx/3c8afc83fb70127b7566298d76b609bce1e3d71d88eca54e64ea1fbe33a51e8b890c6b3696e6fef2100a1aabbb9d2cb7.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951528515504", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CLDPw62Oj4kDEAE=", + "timeCreated": "2024-10-15T00:18:48.522Z", + "updated": "2024-10-15T00:18:48.522Z", + "timeStorageClassUpdated": "2024-10-15T00:18:48.522Z", + "timeFinalized": "2024-10-15T00:18:48.522Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/3ca3714b4c15e4ea784542c386d4b51c5eae269d0d01e281c9080725a99828f050e62925560937710554d546a4fd3fe3.binarypb/1743189881640258", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3ca3714b4c15e4ea784542c386d4b51c5eae269d0d01e281c9080725a99828f050e62925560937710554d546a4fd3fe3.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3ca3714b4c15e4ea784542c386d4b51c5eae269d0d01e281c9080725a99828f050e62925560937710554d546a4fd3fe3.binarypb?generation=1743189881640258&alt=media", + "name": "ovmf_x64_csm/tdx/3ca3714b4c15e4ea784542c386d4b51c5eae269d0d01e281c9080725a99828f050e62925560937710554d546a4fd3fe3.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1743189881640258", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5307", + "md5Hash": "UmdGYR2D42Cx0X/4GfsDeA==", + "crc32c": "7sW2pg==", + "etag": "CMKqr63ArYwDEAE=", + "timeCreated": "2025-03-28T19:24:41.642Z", + "updated": "2025-03-28T19:24:41.642Z", + "timeStorageClassUpdated": "2025-03-28T19:24:41.642Z", + "timeFinalized": "2025-03-28T19:24:41.642Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/3f19f3275bb9b38d12d7bc746c0e5c4442cd7a2baca6a73a29d50a16724353f342125a54e4456443cde7f92d633bd5be.binarypb/1728951539926799", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3f19f3275bb9b38d12d7bc746c0e5c4442cd7a2baca6a73a29d50a16724353f342125a54e4456443cde7f92d633bd5be.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3f19f3275bb9b38d12d7bc746c0e5c4442cd7a2baca6a73a29d50a16724353f342125a54e4456443cde7f92d633bd5be.binarypb?generation=1728951539926799&alt=media", + "name": "ovmf_x64_csm/tdx/3f19f3275bb9b38d12d7bc746c0e5c4442cd7a2baca6a73a29d50a16724353f342125a54e4456443cde7f92d633bd5be.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951539926799", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CI+O/LKOj4kDEAE=", + "timeCreated": "2024-10-15T00:18:59.934Z", + "updated": "2024-10-15T00:18:59.934Z", + "timeStorageClassUpdated": "2024-10-15T00:18:59.934Z", + "timeFinalized": "2024-10-15T00:18:59.934Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/404b12e5d73cb9e5387b1a6927a7b2218f26fb2bbdeb317c63a58165a4c3248076cc064cefc195f90d741b7e657ee791.binarypb/1728951532803041", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F404b12e5d73cb9e5387b1a6927a7b2218f26fb2bbdeb317c63a58165a4c3248076cc064cefc195f90d741b7e657ee791.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F404b12e5d73cb9e5387b1a6927a7b2218f26fb2bbdeb317c63a58165a4c3248076cc064cefc195f90d741b7e657ee791.binarypb?generation=1728951532803041&alt=media", + "name": "ovmf_x64_csm/tdx/404b12e5d73cb9e5387b1a6927a7b2218f26fb2bbdeb317c63a58165a4c3248076cc064cefc195f90d741b7e657ee791.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951532803041", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "COGnya+Oj4kDEAE=", + "timeCreated": "2024-10-15T00:18:52.811Z", + "updated": "2024-10-15T00:18:52.811Z", + "timeStorageClassUpdated": "2024-10-15T00:18:52.811Z", + "timeFinalized": "2024-10-15T00:18:52.811Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99.binarypb/1747697989339141", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99.binarypb?generation=1747697989339141&alt=media", + "name": "ovmf_x64_csm/tdx/409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1747697989339141", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5307", + "md5Hash": "1M3SdZ6faZkGkDfYWJiQtw==", + "crc32c": "RZUtyw==", + "etag": "CIWQ0a7asI0DEAE=", + "timeCreated": "2025-05-19T23:39:49.344Z", + "updated": "2025-05-19T23:39:49.344Z", + "timeStorageClassUpdated": "2025-05-19T23:39:49.344Z", + "timeFinalized": "2025-05-19T23:39:49.344Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/4265d9a735194d336eb09392843ce4d1110c2448b1f0230d5e334254521f5a0243e4b5bedbab92cc5c06a9e123dc9150.binarypb/1723585982896905", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F4265d9a735194d336eb09392843ce4d1110c2448b1f0230d5e334254521f5a0243e4b5bedbab92cc5c06a9e123dc9150.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F4265d9a735194d336eb09392843ce4d1110c2448b1f0230d5e334254521f5a0243e4b5bedbab92cc5c06a9e123dc9150.binarypb?generation=1723585982896905&alt=media", + "name": "ovmf_x64_csm/tdx/4265d9a735194d336eb09392843ce4d1110c2448b1f0230d5e334254521f5a0243e4b5bedbab92cc5c06a9e123dc9150.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723585982896905", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5868", + "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", + "crc32c": "YXklrg==", + "etag": "CIm2gJL68ocDEAE=", + "timeCreated": "2024-08-13T21:53:02.899Z", + "updated": "2024-08-13T21:53:02.899Z", + "timeStorageClassUpdated": "2024-08-13T21:53:02.899Z", + "timeFinalized": "2024-08-13T21:53:02.899Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/426a61064914495dfd226b7c0f6df22730e41f1192a211c569c87b5473617fcc6e44df2662a233439182b852831a6237.binarypb/1728083458232616", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F426a61064914495dfd226b7c0f6df22730e41f1192a211c569c87b5473617fcc6e44df2662a233439182b852831a6237.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F426a61064914495dfd226b7c0f6df22730e41f1192a211c569c87b5473617fcc6e44df2662a233439182b852831a6237.binarypb?generation=1728083458232616&alt=media", + "name": "ovmf_x64_csm/tdx/426a61064914495dfd226b7c0f6df22730e41f1192a211c569c87b5473617fcc6e44df2662a233439182b852831a6237.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728083458232616", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", + "crc32c": "k9E9bA==", + "etag": "CKiirsXs9YgDEAE=", + "timeCreated": "2024-10-04T23:10:58.234Z", + "updated": "2024-10-04T23:10:58.234Z", + "timeStorageClassUpdated": "2024-10-04T23:10:58.234Z", + "timeFinalized": "2024-10-04T23:10:58.234Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/48a912148afd4e2d76c41d58c361523c42090fa9a8228defeee398e1d5c7f3e4f1af12a32c184db7f0baba306f71faa2.binarypb/1725637313736340", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F48a912148afd4e2d76c41d58c361523c42090fa9a8228defeee398e1d5c7f3e4f1af12a32c184db7f0baba306f71faa2.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F48a912148afd4e2d76c41d58c361523c42090fa9a8228defeee398e1d5c7f3e4f1af12a32c184db7f0baba306f71faa2.binarypb?generation=1725637313736340&alt=media", + "name": "ovmf_x64_csm/tdx/48a912148afd4e2d76c41d58c361523c42090fa9a8228defeee398e1d5c7f3e4f1af12a32c184db7f0baba306f71faa2.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1725637313736340", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5873", + "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", + "crc32c": "7PKCRw==", + "etag": "CJTd4vjTrogDEAE=", + "timeCreated": "2024-09-06T15:41:53.739Z", + "updated": "2024-09-06T15:41:53.739Z", + "timeStorageClassUpdated": "2024-09-06T15:41:53.739Z", + "timeFinalized": "2024-09-06T15:41:53.739Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/4c7805479a2e4ce42476633f697ac5158b6a9c8ea47a8e81c57bb80d282b1c68a21356de6537b0ce9f1f9aad6acd5c7f.binarypb/1728951537099216", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F4c7805479a2e4ce42476633f697ac5158b6a9c8ea47a8e81c57bb80d282b1c68a21356de6537b0ce9f1f9aad6acd5c7f.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F4c7805479a2e4ce42476633f697ac5158b6a9c8ea47a8e81c57bb80d282b1c68a21356de6537b0ce9f1f9aad6acd5c7f.binarypb?generation=1728951537099216&alt=media", + "name": "ovmf_x64_csm/tdx/4c7805479a2e4ce42476633f697ac5158b6a9c8ea47a8e81c57bb80d282b1c68a21356de6537b0ce9f1f9aad6acd5c7f.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951537099216", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CNDDz7GOj4kDEAE=", + "timeCreated": "2024-10-15T00:18:57.105Z", + "updated": "2024-10-15T00:18:57.105Z", + "timeStorageClassUpdated": "2024-10-15T00:18:57.105Z", + "timeFinalized": "2024-10-15T00:18:57.105Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/529ae548242f24cddbd0458bdf86f584530d5c18cbdc26c206dfc22fae00e431d8ee1b54f4ced3347cf555c0639f5842.binarypb/1728951527103229", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F529ae548242f24cddbd0458bdf86f584530d5c18cbdc26c206dfc22fae00e431d8ee1b54f4ced3347cf555c0639f5842.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F529ae548242f24cddbd0458bdf86f584530d5c18cbdc26c206dfc22fae00e431d8ee1b54f4ced3347cf555c0639f5842.binarypb?generation=1728951527103229&alt=media", + "name": "ovmf_x64_csm/tdx/529ae548242f24cddbd0458bdf86f584530d5c18cbdc26c206dfc22fae00e431d8ee1b54f4ced3347cf555c0639f5842.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951527103229", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CP217ayOj4kDEAE=", + "timeCreated": "2024-10-15T00:18:47.110Z", + "updated": "2024-10-15T00:18:47.110Z", + "timeStorageClassUpdated": "2024-10-15T00:18:47.110Z", + "timeFinalized": "2024-10-15T00:18:47.110Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/595e08d4588bf2cc2025784f0224d981c09a53c3c899df0516d99353b1984e2a13e7154c39c744f4949da6830f3d85dc.binarypb/1740793355286350", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F595e08d4588bf2cc2025784f0224d981c09a53c3c899df0516d99353b1984e2a13e7154c39c744f4949da6830f3d85dc.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F595e08d4588bf2cc2025784f0224d981c09a53c3c899df0516d99353b1984e2a13e7154c39c744f4949da6830f3d85dc.binarypb?generation=1740793355286350&alt=media", + "name": "ovmf_x64_csm/tdx/595e08d4588bf2cc2025784f0224d981c09a53c3c899df0516d99353b1984e2a13e7154c39c744f4949da6830f3d85dc.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1740793355286350", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "fgWKsiguSyw0G1EQeknKpg==", + "crc32c": "HdglwQ==", + "etag": "CM7uxszg54sDEAE=", + "timeCreated": "2025-03-01T01:42:35.288Z", + "updated": "2025-03-01T01:42:35.288Z", + "timeStorageClassUpdated": "2025-03-01T01:42:35.288Z", + "timeFinalized": "2025-03-01T01:42:35.288Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/5c1694ff7fa068df63ce5b4770e46d82520d6e9353e1e12ffc9ce4d6cad91c1698cc7eabd765d2c4ad519bb420228eda.binarypb/1729190359254052", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F5c1694ff7fa068df63ce5b4770e46d82520d6e9353e1e12ffc9ce4d6cad91c1698cc7eabd765d2c4ad519bb420228eda.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F5c1694ff7fa068df63ce5b4770e46d82520d6e9353e1e12ffc9ce4d6cad91c1698cc7eabd765d2c4ad519bb420228eda.binarypb?generation=1729190359254052&alt=media", + "name": "ovmf_x64_csm/tdx/5c1694ff7fa068df63ce5b4770e46d82520d6e9353e1e12ffc9ce4d6cad91c1698cc7eabd765d2c4ad519bb420228eda.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1729190359254052", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", + "crc32c": "tBQmEQ==", + "etag": "CKSI84iIlokDEAE=", + "timeCreated": "2024-10-17T18:39:19.256Z", + "updated": "2024-10-17T18:39:19.256Z", + "timeStorageClassUpdated": "2024-10-17T18:39:19.256Z", + "timeFinalized": "2024-10-17T18:39:19.256Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/5d56080eb9ef8ce0bbaf6bdcdadeeb06e7c5b0a4d1ec16be868a85a953babe0c5e54d01c8e050a54fe1ca078372530d2.binarypb/1728951525689588", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F5d56080eb9ef8ce0bbaf6bdcdadeeb06e7c5b0a4d1ec16be868a85a953babe0c5e54d01c8e050a54fe1ca078372530d2.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F5d56080eb9ef8ce0bbaf6bdcdadeeb06e7c5b0a4d1ec16be868a85a953babe0c5e54d01c8e050a54fe1ca078372530d2.binarypb?generation=1728951525689588&alt=media", + "name": "ovmf_x64_csm/tdx/5d56080eb9ef8ce0bbaf6bdcdadeeb06e7c5b0a4d1ec16be868a85a953babe0c5e54d01c8e050a54fe1ca078372530d2.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951525689588", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CPSRl6yOj4kDEAE=", + "timeCreated": "2024-10-15T00:18:45.697Z", + "updated": "2024-10-15T00:18:45.697Z", + "timeStorageClassUpdated": "2024-10-15T00:18:45.697Z", + "timeFinalized": "2024-10-15T00:18:45.697Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/68ea327ab336eaaf2b098e1f615c0ea81e9ed25ff60191dc7b420b8092c15b37033cc3624f16f67531050d4139a8c430.binarypb/1723135796804048", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F68ea327ab336eaaf2b098e1f615c0ea81e9ed25ff60191dc7b420b8092c15b37033cc3624f16f67531050d4139a8c430.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F68ea327ab336eaaf2b098e1f615c0ea81e9ed25ff60191dc7b420b8092c15b37033cc3624f16f67531050d4139a8c430.binarypb?generation=1723135796804048&alt=media", + "name": "ovmf_x64_csm/tdx/68ea327ab336eaaf2b098e1f615c0ea81e9ed25ff60191dc7b420b8092c15b37033cc3624f16f67531050d4139a8c430.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723135796804048", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5866", + "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", + "crc32c": "Twn57g==", + "etag": "CNDzxYjt5YcDEAE=", + "timeCreated": "2024-08-08T16:49:56.806Z", + "updated": "2024-08-08T16:49:56.806Z", + "timeStorageClassUpdated": "2024-08-08T16:49:56.806Z", + "timeFinalized": "2024-08-08T16:49:56.806Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/75a0d99a260dadb89b304679e9dd06862c96445c507c149cf68be8555fe41eccfa62410a87513e697117e23e36bcd6d8.binarypb/1719876445557516", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F75a0d99a260dadb89b304679e9dd06862c96445c507c149cf68be8555fe41eccfa62410a87513e697117e23e36bcd6d8.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F75a0d99a260dadb89b304679e9dd06862c96445c507c149cf68be8555fe41eccfa62410a87513e697117e23e36bcd6d8.binarypb?generation=1719876445557516&alt=media", + "name": "ovmf_x64_csm/tdx/75a0d99a260dadb89b304679e9dd06862c96445c507c149cf68be8555fe41eccfa62410a87513e697117e23e36bcd6d8.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1719876445557516", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5865", + "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", + "crc32c": "s0O/hw==", + "etag": "CIym4YT/hocDEAE=", + "timeCreated": "2024-07-01T23:27:25.558Z", + "updated": "2024-07-01T23:27:25.558Z", + "timeStorageClassUpdated": "2024-07-01T23:27:25.558Z", + "timeFinalized": "2024-07-01T23:27:25.558Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/77289bc22606e62b1e69c6222579871eba45eb03b818ad8843ccc490a22317bd220d4baea16a978f3b42a74b349bb6e5.binarypb/1731450148717872", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F77289bc22606e62b1e69c6222579871eba45eb03b818ad8843ccc490a22317bd220d4baea16a978f3b42a74b349bb6e5.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F77289bc22606e62b1e69c6222579871eba45eb03b818ad8843ccc490a22317bd220d4baea16a978f3b42a74b349bb6e5.binarypb?generation=1731450148717872&alt=media", + "name": "ovmf_x64_csm/tdx/77289bc22606e62b1e69c6222579871eba45eb03b818ad8843ccc490a22317bd220d4baea16a978f3b42a74b349bb6e5.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1731450148717872", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5254", + "md5Hash": "s5qFLCU//T5J47AqVLhJCQ==", + "crc32c": "21rV/g==", + "etag": "CLCKvrjq14kDEAE=", + "timeCreated": "2024-11-12T22:22:28.719Z", + "updated": "2024-11-12T22:22:28.719Z", + "timeStorageClassUpdated": "2024-11-12T22:22:28.719Z", + "timeFinalized": "2024-11-12T22:22:28.719Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/78a7533e575b476151ab32b3a8242117a53083d132ac3f35396b18a114fe714c9bac17db4a8d84e976f8c98d98d91a5d.binarypb/1749578071858434", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F78a7533e575b476151ab32b3a8242117a53083d132ac3f35396b18a114fe714c9bac17db4a8d84e976f8c98d98d91a5d.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F78a7533e575b476151ab32b3a8242117a53083d132ac3f35396b18a114fe714c9bac17db4a8d84e976f8c98d98d91a5d.binarypb?generation=1749578071858434&alt=media", + "name": "ovmf_x64_csm/tdx/78a7533e575b476151ab32b3a8242117a53083d132ac3f35396b18a114fe714c9bac17db4a8d84e976f8c98d98d91a5d.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1749578071858434", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "Gq3ztyZD1ivm75QPcS9cpw==", + "crc32c": "cUxfSQ==", + "etag": "CIK665u2540DEAE=", + "timeCreated": "2025-06-10T17:54:31.861Z", + "updated": "2025-06-10T17:54:31.861Z", + "timeStorageClassUpdated": "2025-06-10T17:54:31.861Z", + "timeFinalized": "2025-06-10T17:54:31.861Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/7a2177d9da9e2bce3ef91c143667ea72fe72b021e3b0c5736eb96cffefa5fa8fa4fec923e8f8cfac1298e4f1d94ce774.binarypb/1729190354504872", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F7a2177d9da9e2bce3ef91c143667ea72fe72b021e3b0c5736eb96cffefa5fa8fa4fec923e8f8cfac1298e4f1d94ce774.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F7a2177d9da9e2bce3ef91c143667ea72fe72b021e3b0c5736eb96cffefa5fa8fa4fec923e8f8cfac1298e4f1d94ce774.binarypb?generation=1729190354504872&alt=media", + "name": "ovmf_x64_csm/tdx/7a2177d9da9e2bce3ef91c143667ea72fe72b021e3b0c5736eb96cffefa5fa8fa4fec923e8f8cfac1298e4f1d94ce774.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1729190354504872", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", + "crc32c": "tBQmEQ==", + "etag": "CKiZ0YaIlokDEAE=", + "timeCreated": "2024-10-17T18:39:14.506Z", + "updated": "2024-10-17T18:39:14.506Z", + "timeStorageClassUpdated": "2024-10-17T18:39:14.506Z", + "timeFinalized": "2024-10-17T18:39:14.506Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/7df7195f7887de96bca9f57853657d28e58c40d6aaa4a87626bb32a5c8eb6a190606051d96214b91d076db3ffe396f37.binarypb/1750808594502977", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F7df7195f7887de96bca9f57853657d28e58c40d6aaa4a87626bb32a5c8eb6a190606051d96214b91d076db3ffe396f37.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F7df7195f7887de96bca9f57853657d28e58c40d6aaa4a87626bb32a5c8eb6a190606051d96214b91d076db3ffe396f37.binarypb?generation=1750808594502977&alt=media", + "name": "ovmf_x64_csm/tdx/7df7195f7887de96bca9f57853657d28e58c40d6aaa4a87626bb32a5c8eb6a190606051d96214b91d076db3ffe396f37.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1750808594502977", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "IGzKhCp3aHzUfiH9xKSr2A==", + "crc32c": "8dZRgQ==", + "etag": "CMGq4aKei44DEAE=", + "timeCreated": "2025-06-24T23:43:14.505Z", + "updated": "2025-06-24T23:43:14.505Z", + "timeStorageClassUpdated": "2025-06-24T23:43:14.505Z", + "timeFinalized": "2025-06-24T23:43:14.505Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/8370d8f6d02f2d13e211e91c93fde923049522b241425a29a7bf0071ef49b250af4ef49d852fa3e10065d1b51dfce8fb.binarypb/1763582372027922", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8370d8f6d02f2d13e211e91c93fde923049522b241425a29a7bf0071ef49b250af4ef49d852fa3e10065d1b51dfce8fb.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8370d8f6d02f2d13e211e91c93fde923049522b241425a29a7bf0071ef49b250af4ef49d852fa3e10065d1b51dfce8fb.binarypb?generation=1763582372027922&alt=media", + "name": "ovmf_x64_csm/tdx/8370d8f6d02f2d13e211e91c93fde923049522b241425a29a7bf0071ef49b250af4ef49d852fa3e10065d1b51dfce8fb.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1763582372027922", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "Mo521eXHGQ7WGdaawVWxMg==", + "crc32c": "iS84kw==", + "etag": "CJK8xKaA/5ADEAE=", + "timeCreated": "2025-11-19T19:59:32.031Z", + "updated": "2025-11-19T19:59:32.031Z", + "timeStorageClassUpdated": "2025-11-19T19:59:32.031Z", + "timeFinalized": "2025-11-19T19:59:32.031Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/887114d8385e95d306873a404297b7abed97a6a958cf672fb55b5230fa7e008a23a31c90325fed1161a62ee6718fbc8b.binarypb/1728083463190652", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F887114d8385e95d306873a404297b7abed97a6a958cf672fb55b5230fa7e008a23a31c90325fed1161a62ee6718fbc8b.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F887114d8385e95d306873a404297b7abed97a6a958cf672fb55b5230fa7e008a23a31c90325fed1161a62ee6718fbc8b.binarypb?generation=1728083463190652&alt=media", + "name": "ovmf_x64_csm/tdx/887114d8385e95d306873a404297b7abed97a6a958cf672fb55b5230fa7e008a23a31c90325fed1161a62ee6718fbc8b.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728083463190652", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", + "crc32c": "k9E9bA==", + "etag": "CPzw3Mfs9YgDEAE=", + "timeCreated": "2024-10-04T23:11:03.192Z", + "updated": "2024-10-04T23:11:03.192Z", + "timeStorageClassUpdated": "2024-10-04T23:11:03.192Z", + "timeFinalized": "2024-10-04T23:11:03.192Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/892a196239dfcd522bfce14f30fc06ac1eb82ac87b3d1593fcb9a6e389b398af6fb0b9e4b8b4d294317cc2976459fbc2.binarypb/1729190364834406", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F892a196239dfcd522bfce14f30fc06ac1eb82ac87b3d1593fcb9a6e389b398af6fb0b9e4b8b4d294317cc2976459fbc2.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F892a196239dfcd522bfce14f30fc06ac1eb82ac87b3d1593fcb9a6e389b398af6fb0b9e4b8b4d294317cc2976459fbc2.binarypb?generation=1729190364834406&alt=media", + "name": "ovmf_x64_csm/tdx/892a196239dfcd522bfce14f30fc06ac1eb82ac87b3d1593fcb9a6e389b398af6fb0b9e4b8b4d294317cc2976459fbc2.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1729190364834406", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", + "crc32c": "tBQmEQ==", + "etag": "CObUx4uIlokDEAE=", + "timeCreated": "2024-10-17T18:39:24.836Z", + "updated": "2024-10-17T18:39:24.836Z", + "timeStorageClassUpdated": "2024-10-17T18:39:24.836Z", + "timeFinalized": "2024-10-17T18:39:24.836Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/89ec252df6a6975adee91d17b3e8715955bf86252e33fbbbcca0b157c4402d886447c9d97d0cce9395bb1697bfd2208e.binarypb/1723135790538500", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F89ec252df6a6975adee91d17b3e8715955bf86252e33fbbbcca0b157c4402d886447c9d97d0cce9395bb1697bfd2208e.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F89ec252df6a6975adee91d17b3e8715955bf86252e33fbbbcca0b157c4402d886447c9d97d0cce9395bb1697bfd2208e.binarypb?generation=1723135790538500&alt=media", + "name": "ovmf_x64_csm/tdx/89ec252df6a6975adee91d17b3e8715955bf86252e33fbbbcca0b157c4402d886447c9d97d0cce9395bb1697bfd2208e.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723135790538500", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5866", + "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", + "crc32c": "Twn57g==", + "etag": "CIS+x4Xt5YcDEAE=", + "timeCreated": "2024-08-08T16:49:50.541Z", + "updated": "2024-08-08T16:49:50.541Z", + "timeStorageClassUpdated": "2024-08-08T16:49:50.541Z", + "timeFinalized": "2024-08-08T16:49:50.541Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/8a3130eef765be2391813d4fce7ea36e489f3838ffdccc479b75fb4146c32017f379589be69e33f9b3186cea221a2abb.binarypb/1719876444430165", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8a3130eef765be2391813d4fce7ea36e489f3838ffdccc479b75fb4146c32017f379589be69e33f9b3186cea221a2abb.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8a3130eef765be2391813d4fce7ea36e489f3838ffdccc479b75fb4146c32017f379589be69e33f9b3186cea221a2abb.binarypb?generation=1719876444430165&alt=media", + "name": "ovmf_x64_csm/tdx/8a3130eef765be2391813d4fce7ea36e489f3838ffdccc479b75fb4146c32017f379589be69e33f9b3186cea221a2abb.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1719876444430165", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5865", + "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", + "crc32c": "s0O/hw==", + "etag": "CNW+nIT/hocDEAE=", + "timeCreated": "2024-07-01T23:27:24.431Z", + "updated": "2024-07-01T23:27:24.431Z", + "timeStorageClassUpdated": "2024-07-01T23:27:24.431Z", + "timeFinalized": "2024-07-01T23:27:24.431Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/8a8e2f21714da855b219bd2724a86c1ac7e46e8a84b0f34fad9e84dd46ef9bc92f0ca95eda8ff629246e4aa9a72c625c.binarypb/1776213910413410", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8a8e2f21714da855b219bd2724a86c1ac7e46e8a84b0f34fad9e84dd46ef9bc92f0ca95eda8ff629246e4aa9a72c625c.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8a8e2f21714da855b219bd2724a86c1ac7e46e8a84b0f34fad9e84dd46ef9bc92f0ca95eda8ff629246e4aa9a72c625c.binarypb?generation=1776213910413410&alt=media", + "name": "ovmf_x64_csm/tdx/8a8e2f21714da855b219bd2724a86c1ac7e46e8a84b0f34fad9e84dd46ef9bc92f0ca95eda8ff629246e4aa9a72c625c.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1776213910413410", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "trnuInXRcG8FrhS6X5rRGw==", + "crc32c": "T2B4LA==", + "etag": "COLAs7nQ7pMDEAE=", + "timeCreated": "2026-04-15T00:45:10.415Z", + "updated": "2026-04-15T00:45:10.415Z", + "timeStorageClassUpdated": "2026-04-15T00:45:10.415Z", + "timeFinalized": "2026-04-15T00:45:10.415Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/9573810ddf0977c9005f6df9819c3a78e27d4b5a91777d86bb8d67b9c4344cc4d825c26a216d88b9d35e71e77a0700e3.binarypb/1723585978633920", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9573810ddf0977c9005f6df9819c3a78e27d4b5a91777d86bb8d67b9c4344cc4d825c26a216d88b9d35e71e77a0700e3.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9573810ddf0977c9005f6df9819c3a78e27d4b5a91777d86bb8d67b9c4344cc4d825c26a216d88b9d35e71e77a0700e3.binarypb?generation=1723585978633920&alt=media", + "name": "ovmf_x64_csm/tdx/9573810ddf0977c9005f6df9819c3a78e27d4b5a91777d86bb8d67b9c4344cc4d825c26a216d88b9d35e71e77a0700e3.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723585978633920", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5868", + "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", + "crc32c": "YXklrg==", + "etag": "CMCd/I/68ocDEAE=", + "timeCreated": "2024-08-13T21:52:58.637Z", + "updated": "2024-08-13T21:52:58.637Z", + "timeStorageClassUpdated": "2024-08-13T21:52:58.637Z", + "timeFinalized": "2024-08-13T21:52:58.637Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/9757d231b4ad47d683531226f5a5a78266c0abb91e2b9b90138f03719ca32bb0719844be145b5a09dd1a058a9e17fd04.binarypb/1719876463677441", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9757d231b4ad47d683531226f5a5a78266c0abb91e2b9b90138f03719ca32bb0719844be145b5a09dd1a058a9e17fd04.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9757d231b4ad47d683531226f5a5a78266c0abb91e2b9b90138f03719ca32bb0719844be145b5a09dd1a058a9e17fd04.binarypb?generation=1719876463677441&alt=media", + "name": "ovmf_x64_csm/tdx/9757d231b4ad47d683531226f5a5a78266c0abb91e2b9b90138f03719ca32bb0719844be145b5a09dd1a058a9e17fd04.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1719876463677441", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5865", + "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", + "crc32c": "s0O/hw==", + "etag": "CIGgs43/hocDEAE=", + "timeCreated": "2024-07-01T23:27:43.679Z", + "updated": "2024-07-01T23:27:43.679Z", + "timeStorageClassUpdated": "2024-07-01T23:27:43.679Z", + "timeFinalized": "2024-07-01T23:27:43.679Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/9bf86e6280ec4282b8b5822d8166410a456cdb720109aa799f0011fa63df1de3ee5e35e293fc410c061433163acb03a6.binarypb/1777588963392969", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9bf86e6280ec4282b8b5822d8166410a456cdb720109aa799f0011fa63df1de3ee5e35e293fc410c061433163acb03a6.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9bf86e6280ec4282b8b5822d8166410a456cdb720109aa799f0011fa63df1de3ee5e35e293fc410c061433163acb03a6.binarypb?generation=1777588963392969&alt=media", + "name": "ovmf_x64_csm/tdx/9bf86e6280ec4282b8b5822d8166410a456cdb720109aa799f0011fa63df1de3ee5e35e293fc410c061433163acb03a6.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1777588963392969", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "IrkChk2+BtTiml23TmjvgQ==", + "crc32c": "nnnqsQ==", + "etag": "CMn74PXSlpQDEAE=", + "timeCreated": "2026-04-30T22:42:43.395Z", + "updated": "2026-04-30T22:42:43.395Z", + "timeStorageClassUpdated": "2026-04-30T22:42:43.395Z", + "timeFinalized": "2026-04-30T22:42:43.395Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/9d00db2fc7cd2a891b83975862cf932d7cfbb4f6ef884a8d7be89be8fc10061b1fbaf49361986cdfa628f339b07e4605.binarypb/1728951534222594", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9d00db2fc7cd2a891b83975862cf932d7cfbb4f6ef884a8d7be89be8fc10061b1fbaf49361986cdfa628f339b07e4605.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9d00db2fc7cd2a891b83975862cf932d7cfbb4f6ef884a8d7be89be8fc10061b1fbaf49361986cdfa628f339b07e4605.binarypb?generation=1728951534222594&alt=media", + "name": "ovmf_x64_csm/tdx/9d00db2fc7cd2a891b83975862cf932d7cfbb4f6ef884a8d7be89be8fc10061b1fbaf49361986cdfa628f339b07e4605.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951534222594", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CIL6n7COj4kDEAE=", + "timeCreated": "2024-10-15T00:18:54.229Z", + "updated": "2024-10-15T00:18:54.229Z", + "timeStorageClassUpdated": "2024-10-15T00:18:54.229Z", + "timeFinalized": "2024-10-15T00:18:54.229Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a039f3af42d6a9e3723d04459f69d3b931a7bba2e18bdeb85d093327497af15dc16e1741df53154b685869d8ef8e79a4.binarypb/1726777920401985", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa039f3af42d6a9e3723d04459f69d3b931a7bba2e18bdeb85d093327497af15dc16e1741df53154b685869d8ef8e79a4.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa039f3af42d6a9e3723d04459f69d3b931a7bba2e18bdeb85d093327497af15dc16e1741df53154b685869d8ef8e79a4.binarypb?generation=1726777920401985&alt=media", + "name": "ovmf_x64_csm/tdx/a039f3af42d6a9e3723d04459f69d3b931a7bba2e18bdeb85d093327497af15dc16e1741df53154b685869d8ef8e79a4.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1726777920401985", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5868", + "md5Hash": "q8QrsAgVMc9+mN0gFv+2CA==", + "crc32c": "x1hIgw==", + "etag": "CMHktITtz4gDEAE=", + "timeCreated": "2024-09-19T20:32:00.404Z", + "updated": "2024-09-19T20:32:00.404Z", + "timeStorageClassUpdated": "2024-09-19T20:32:00.404Z", + "timeFinalized": "2024-09-19T20:32:00.404Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a0b4244c2077c88dd5bc3dc81c27775ea8edb4816961c2bc2eef59d700d380408fb49159e75376a6f051b0e4d32501e3.binarypb/1723135791590331", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa0b4244c2077c88dd5bc3dc81c27775ea8edb4816961c2bc2eef59d700d380408fb49159e75376a6f051b0e4d32501e3.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa0b4244c2077c88dd5bc3dc81c27775ea8edb4816961c2bc2eef59d700d380408fb49159e75376a6f051b0e4d32501e3.binarypb?generation=1723135791590331&alt=media", + "name": "ovmf_x64_csm/tdx/a0b4244c2077c88dd5bc3dc81c27775ea8edb4816961c2bc2eef59d700d380408fb49159e75376a6f051b0e4d32501e3.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723135791590331", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5866", + "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", + "crc32c": "Twn57g==", + "etag": "CLvXh4bt5YcDEAE=", + "timeCreated": "2024-08-08T16:49:51.592Z", + "updated": "2024-08-08T16:49:51.592Z", + "timeStorageClassUpdated": "2024-08-08T16:49:51.592Z", + "timeFinalized": "2024-08-08T16:49:51.592Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a22b871065d0387385c5e96dbf4356053b30eb76de061924b1d7b92c66f4d963fca88fe337408903481cf1b3480051f0.binarypb/1771959199837360", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa22b871065d0387385c5e96dbf4356053b30eb76de061924b1d7b92c66f4d963fca88fe337408903481cf1b3480051f0.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa22b871065d0387385c5e96dbf4356053b30eb76de061924b1d7b92c66f4d963fca88fe337408903481cf1b3480051f0.binarypb?generation=1771959199837360&alt=media", + "name": "ovmf_x64_csm/tdx/a22b871065d0387385c5e96dbf4356053b30eb76de061924b1d7b92c66f4d963fca88fe337408903481cf1b3480051f0.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1771959199837360", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "vjL6Yo3OJTShQWXp1hIX9g==", + "crc32c": "zTfjdA==", + "etag": "CLDZprXm8pIDEAE=", + "timeCreated": "2026-02-24T18:53:19.839Z", + "updated": "2026-02-24T18:53:19.839Z", + "timeStorageClassUpdated": "2026-02-24T18:53:19.839Z", + "timeFinalized": "2026-02-24T18:53:19.839Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a5844e88897b70c318bef929ef4dfd6c7304c52c4bc9c3f39132f0fdccecf3eb5bab70110ee42a12509a31c037288694.binarypb/1756507826221876", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa5844e88897b70c318bef929ef4dfd6c7304c52c4bc9c3f39132f0fdccecf3eb5bab70110ee42a12509a31c037288694.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa5844e88897b70c318bef929ef4dfd6c7304c52c4bc9c3f39132f0fdccecf3eb5bab70110ee42a12509a31c037288694.binarypb?generation=1756507826221876&alt=media", + "name": "ovmf_x64_csm/tdx/a5844e88897b70c318bef929ef4dfd6c7304c52c4bc9c3f39132f0fdccecf3eb5bab70110ee42a12509a31c037288694.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1756507826221876", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "BLyQeUKe9BZObADiz9vOQA==", + "crc32c": "jNZWFQ==", + "etag": "CLTmm8iNsY8DEAE=", + "timeCreated": "2025-08-29T22:50:26.224Z", + "updated": "2025-08-29T22:50:26.224Z", + "timeStorageClassUpdated": "2025-08-29T22:50:26.224Z", + "timeFinalized": "2025-08-29T22:50:26.224Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a91197faa4b8b2b757cafa9cfebc761f22d64c1d1bddcac2e79ba6cccb393f6af4504956e00ea15af5689d76050d90b2.binarypb/1744656913825170", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa91197faa4b8b2b757cafa9cfebc761f22d64c1d1bddcac2e79ba6cccb393f6af4504956e00ea15af5689d76050d90b2.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa91197faa4b8b2b757cafa9cfebc761f22d64c1d1bddcac2e79ba6cccb393f6af4504956e00ea15af5689d76050d90b2.binarypb?generation=1744656913825170&alt=media", + "name": "ovmf_x64_csm/tdx/a91197faa4b8b2b757cafa9cfebc761f22d64c1d1bddcac2e79ba6cccb393f6af4504956e00ea15af5689d76050d90b2.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1744656913825170", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "pl9ijrUMVt0Z6JjV1dZIfA==", + "crc32c": "xgeP0A==", + "etag": "CJL76byZ2IwDEAE=", + "timeCreated": "2025-04-14T18:55:13.827Z", + "updated": "2025-04-14T18:55:13.827Z", + "timeStorageClassUpdated": "2025-04-14T18:55:13.827Z", + "timeFinalized": "2025-04-14T18:55:13.827Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ab65652bbe0e62c5efdda5d8f1f768d5e91210afbbec31635deaeca84e7cc958e15ed22b80b6c13fa04b8b040c2a7b24.binarypb/1728951538509376", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fab65652bbe0e62c5efdda5d8f1f768d5e91210afbbec31635deaeca84e7cc958e15ed22b80b6c13fa04b8b040c2a7b24.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fab65652bbe0e62c5efdda5d8f1f768d5e91210afbbec31635deaeca84e7cc958e15ed22b80b6c13fa04b8b040c2a7b24.binarypb?generation=1728951538509376&alt=media", + "name": "ovmf_x64_csm/tdx/ab65652bbe0e62c5efdda5d8f1f768d5e91210afbbec31635deaeca84e7cc958e15ed22b80b6c13fa04b8b040c2a7b24.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951538509376", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CMDMpbKOj4kDEAE=", + "timeCreated": "2024-10-15T00:18:58.515Z", + "updated": "2024-10-15T00:18:58.515Z", + "timeStorageClassUpdated": "2024-10-15T00:18:58.515Z", + "timeFinalized": "2024-10-15T00:18:58.515Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ae21a81e228b5f814d13226f3ee7fb1215f3127316c13bff13c7f0aff22817afee450af0f6f2f80a42ef0ac9014c8dda.binarypb/1755553674945403", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fae21a81e228b5f814d13226f3ee7fb1215f3127316c13bff13c7f0aff22817afee450af0f6f2f80a42ef0ac9014c8dda.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fae21a81e228b5f814d13226f3ee7fb1215f3127316c13bff13c7f0aff22817afee450af0f6f2f80a42ef0ac9014c8dda.binarypb?generation=1755553674945403&alt=media", + "name": "ovmf_x64_csm/tdx/ae21a81e228b5f814d13226f3ee7fb1215f3127316c13bff13c7f0aff22817afee450af0f6f2f80a42ef0ac9014c8dda.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1755553674945403", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5307", + "md5Hash": "Y4O/USh86ewtt+ay85ShRg==", + "crc32c": "INGxXA==", + "etag": "CPvGt4mrlY8DEAE=", + "timeCreated": "2025-08-18T21:47:54.947Z", + "updated": "2025-08-18T21:47:54.947Z", + "timeStorageClassUpdated": "2025-08-18T21:47:54.947Z", + "timeFinalized": "2025-08-18T21:47:54.947Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ae270b1da076629433c4889782c33ada1f886d38f2c0de401698143a50f05252469d2272bc4fd7bb779c19d37440d047.binarypb/1729190353326042", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fae270b1da076629433c4889782c33ada1f886d38f2c0de401698143a50f05252469d2272bc4fd7bb779c19d37440d047.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fae270b1da076629433c4889782c33ada1f886d38f2c0de401698143a50f05252469d2272bc4fd7bb779c19d37440d047.binarypb?generation=1729190353326042&alt=media", + "name": "ovmf_x64_csm/tdx/ae270b1da076629433c4889782c33ada1f886d38f2c0de401698143a50f05252469d2272bc4fd7bb779c19d37440d047.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1729190353326042", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", + "crc32c": "tBQmEQ==", + "etag": "CNqfiYaIlokDEAE=", + "timeCreated": "2024-10-17T18:39:13.328Z", + "updated": "2024-10-17T18:39:13.328Z", + "timeStorageClassUpdated": "2024-10-17T18:39:13.328Z", + "timeFinalized": "2024-10-17T18:39:13.328Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/afbac113d5458025dbf33e8a5e6f82214886e1f2180ebd7c4acf8e0d6a0e2d0843bfcd9b1638d2bbd3e2e31ab98fd976.binarypb/1725637320046126", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fafbac113d5458025dbf33e8a5e6f82214886e1f2180ebd7c4acf8e0d6a0e2d0843bfcd9b1638d2bbd3e2e31ab98fd976.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fafbac113d5458025dbf33e8a5e6f82214886e1f2180ebd7c4acf8e0d6a0e2d0843bfcd9b1638d2bbd3e2e31ab98fd976.binarypb?generation=1725637320046126&alt=media", + "name": "ovmf_x64_csm/tdx/afbac113d5458025dbf33e8a5e6f82214886e1f2180ebd7c4acf8e0d6a0e2d0843bfcd9b1638d2bbd3e2e31ab98fd976.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1725637320046126", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5873", + "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", + "crc32c": "7PKCRw==", + "etag": "CK7s4/vTrogDEAE=", + "timeCreated": "2024-09-06T15:42:00.048Z", + "updated": "2024-09-06T15:42:00.048Z", + "timeStorageClassUpdated": "2024-09-06T15:42:00.048Z", + "timeFinalized": "2024-09-06T15:42:00.048Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/b3054b3fefdcff8d1e6f9a1aad2252ff01438075ded8083a1900956c3e73442f519cdddb5a1537d649a3d129f165c1df.binarypb/1773135059690086", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fb3054b3fefdcff8d1e6f9a1aad2252ff01438075ded8083a1900956c3e73442f519cdddb5a1537d649a3d129f165c1df.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fb3054b3fefdcff8d1e6f9a1aad2252ff01438075ded8083a1900956c3e73442f519cdddb5a1537d649a3d129f165c1df.binarypb?generation=1773135059690086&alt=media", + "name": "ovmf_x64_csm/tdx/b3054b3fefdcff8d1e6f9a1aad2252ff01438075ded8083a1900956c3e73442f519cdddb5a1537d649a3d129f165c1df.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1773135059690086", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "016Rlc8dl6AAzdWvkNCmqg==", + "crc32c": "MXKRQg==", + "etag": "CObE/OqClZMDEAE=", + "timeCreated": "2026-03-10T09:30:59.692Z", + "updated": "2026-03-10T09:30:59.692Z", + "timeStorageClassUpdated": "2026-03-10T09:30:59.692Z", + "timeFinalized": "2026-03-10T09:30:59.692Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ba128a84597c3c048f1c3c52d68634d9ccad4120a87b81ad40aca008b219ec1bdb4401470c8dc696d728c4507edd8611.binarypb/1728951524287910", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fba128a84597c3c048f1c3c52d68634d9ccad4120a87b81ad40aca008b219ec1bdb4401470c8dc696d728c4507edd8611.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fba128a84597c3c048f1c3c52d68634d9ccad4120a87b81ad40aca008b219ec1bdb4401470c8dc696d728c4507edd8611.binarypb?generation=1728951524287910&alt=media", + "name": "ovmf_x64_csm/tdx/ba128a84597c3c048f1c3c52d68634d9ccad4120a87b81ad40aca008b219ec1bdb4401470c8dc696d728c4507edd8611.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951524287910", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CKbLwauOj4kDEAE=", + "timeCreated": "2024-10-15T00:18:44.294Z", + "updated": "2024-10-15T00:18:44.294Z", + "timeStorageClassUpdated": "2024-10-15T00:18:44.294Z", + "timeFinalized": "2024-10-15T00:18:44.294Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/bf75843e2e234a1e6e1df6942bbdae9100411299e54f64a10ea9b48b97453c671973fbc801f9511d3148f861d9094923.binarypb/1728083449469071", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fbf75843e2e234a1e6e1df6942bbdae9100411299e54f64a10ea9b48b97453c671973fbc801f9511d3148f861d9094923.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fbf75843e2e234a1e6e1df6942bbdae9100411299e54f64a10ea9b48b97453c671973fbc801f9511d3148f861d9094923.binarypb?generation=1728083449469071&alt=media", + "name": "ovmf_x64_csm/tdx/bf75843e2e234a1e6e1df6942bbdae9100411299e54f64a10ea9b48b97453c671973fbc801f9511d3148f861d9094923.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728083449469071", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", + "crc32c": "k9E9bA==", + "etag": "CI+xl8Hs9YgDEAE=", + "timeCreated": "2024-10-04T23:10:49.470Z", + "updated": "2024-10-04T23:10:49.470Z", + "timeStorageClassUpdated": "2024-10-04T23:10:49.470Z", + "timeFinalized": "2024-10-04T23:10:49.470Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/c1850db0d5f5541a65866619dd4933f743815c606b269063e8b8424effe3ac7256d56331f2ed0dc66641fbdf10d3f21e.binarypb/1729190360578137", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc1850db0d5f5541a65866619dd4933f743815c606b269063e8b8424effe3ac7256d56331f2ed0dc66641fbdf10d3f21e.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc1850db0d5f5541a65866619dd4933f743815c606b269063e8b8424effe3ac7256d56331f2ed0dc66641fbdf10d3f21e.binarypb?generation=1729190360578137&alt=media", + "name": "ovmf_x64_csm/tdx/c1850db0d5f5541a65866619dd4933f743815c606b269063e8b8424effe3ac7256d56331f2ed0dc66641fbdf10d3f21e.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1729190360578137", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", + "crc32c": "tBQmEQ==", + "etag": "CNnww4mIlokDEAE=", + "timeCreated": "2024-10-17T18:39:20.579Z", + "updated": "2024-10-17T18:39:20.579Z", + "timeStorageClassUpdated": "2024-10-17T18:39:20.579Z", + "timeFinalized": "2024-10-17T18:39:20.579Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/c5bf87009d9aaeb2a40633710b2edab43c0b0b8cbe5a036fa45b1057e7086b0726711d0c78ed5859f12b0d76978df03c.binarypb/1753835243259865", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc5bf87009d9aaeb2a40633710b2edab43c0b0b8cbe5a036fa45b1057e7086b0726711d0c78ed5859f12b0d76978df03c.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc5bf87009d9aaeb2a40633710b2edab43c0b0b8cbe5a036fa45b1057e7086b0726711d0c78ed5859f12b0d76978df03c.binarypb?generation=1753835243259865&alt=media", + "name": "ovmf_x64_csm/tdx/c5bf87009d9aaeb2a40633710b2edab43c0b0b8cbe5a036fa45b1057e7086b0726711d0c78ed5859f12b0d76978df03c.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1753835243259865", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "GqA+IanJ1aFneQLroTIHJw==", + "crc32c": "uXG6tw==", + "etag": "CNmPrbWp444DEAE=", + "timeCreated": "2025-07-30T00:27:23.262Z", + "updated": "2025-07-30T00:27:23.262Z", + "timeStorageClassUpdated": "2025-07-30T00:27:23.262Z", + "timeFinalized": "2025-07-30T00:27:23.262Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/c75e360b2d1da4456a9113d6549f6ed9b26145526bc15eb67371238c8d35aff5d174ecaf775483f5a3cfc603e359d5cc.binarypb/1719876454565396", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc75e360b2d1da4456a9113d6549f6ed9b26145526bc15eb67371238c8d35aff5d174ecaf775483f5a3cfc603e359d5cc.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc75e360b2d1da4456a9113d6549f6ed9b26145526bc15eb67371238c8d35aff5d174ecaf775483f5a3cfc603e359d5cc.binarypb?generation=1719876454565396&alt=media", + "name": "ovmf_x64_csm/tdx/c75e360b2d1da4456a9113d6549f6ed9b26145526bc15eb67371238c8d35aff5d174ecaf775483f5a3cfc603e359d5cc.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1719876454565396", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5865", + "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", + "crc32c": "s0O/hw==", + "etag": "CJSMh4n/hocDEAE=", + "timeCreated": "2024-07-01T23:27:34.567Z", + "updated": "2024-07-01T23:27:34.567Z", + "timeStorageClassUpdated": "2024-07-01T23:27:34.567Z", + "timeFinalized": "2024-07-01T23:27:34.567Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ca514dc8e47040b4601fba79c5eba9339097171dbe988f29995f9d9185a25ba8e524924d65c1730db4782e32505509ce.binarypb/1728083450440402", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fca514dc8e47040b4601fba79c5eba9339097171dbe988f29995f9d9185a25ba8e524924d65c1730db4782e32505509ce.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fca514dc8e47040b4601fba79c5eba9339097171dbe988f29995f9d9185a25ba8e524924d65c1730db4782e32505509ce.binarypb?generation=1728083450440402&alt=media", + "name": "ovmf_x64_csm/tdx/ca514dc8e47040b4601fba79c5eba9339097171dbe988f29995f9d9185a25ba8e524924d65c1730db4782e32505509ce.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728083450440402", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", + "crc32c": "k9E9bA==", + "etag": "CNLV0sHs9YgDEAE=", + "timeCreated": "2024-10-04T23:10:50.442Z", + "updated": "2024-10-04T23:10:50.442Z", + "timeStorageClassUpdated": "2024-10-04T23:10:50.442Z", + "timeFinalized": "2024-10-04T23:10:50.442Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/cee0cff377192351bdba46457b512820e1f23d6843d77d14f23f30000086321fd15a52c7afc8ff79d63f8a341a1140b3.binarypb/1728951535641925", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fcee0cff377192351bdba46457b512820e1f23d6843d77d14f23f30000086321fd15a52c7afc8ff79d63f8a341a1140b3.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fcee0cff377192351bdba46457b512820e1f23d6843d77d14f23f30000086321fd15a52c7afc8ff79d63f8a341a1140b3.binarypb?generation=1728951535641925&alt=media", + "name": "ovmf_x64_csm/tdx/cee0cff377192351bdba46457b512820e1f23d6843d77d14f23f30000086321fd15a52c7afc8ff79d63f8a341a1140b3.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951535641925", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CMXK9rCOj4kDEAE=", + "timeCreated": "2024-10-15T00:18:55.649Z", + "updated": "2024-10-15T00:18:55.649Z", + "timeStorageClassUpdated": "2024-10-15T00:18:55.649Z", + "timeFinalized": "2024-10-15T00:18:55.649Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/d904fd4a5bcae8a1db29f21c2674474536e8c73e22591ab92dd01ddecf6bf1c8366163598e5587acdd6fe30b50ac43cc.binarypb/1725637325268290", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fd904fd4a5bcae8a1db29f21c2674474536e8c73e22591ab92dd01ddecf6bf1c8366163598e5587acdd6fe30b50ac43cc.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fd904fd4a5bcae8a1db29f21c2674474536e8c73e22591ab92dd01ddecf6bf1c8366163598e5587acdd6fe30b50ac43cc.binarypb?generation=1725637325268290&alt=media", + "name": "ovmf_x64_csm/tdx/d904fd4a5bcae8a1db29f21c2674474536e8c73e22591ab92dd01ddecf6bf1c8366163598e5587acdd6fe30b50ac43cc.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1725637325268290", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5873", + "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", + "crc32c": "7PKCRw==", + "etag": "CMLKov7TrogDEAE=", + "timeCreated": "2024-09-06T15:42:05.270Z", + "updated": "2024-09-06T15:42:05.270Z", + "timeStorageClassUpdated": "2024-09-06T15:42:05.270Z", + "timeFinalized": "2024-09-06T15:42:05.270Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/dab01619c1aeda5682e4cf3906d065ff731274a9660e4128740d5bb1a4d0947b472fe99f988e83670b6df502f5e0b5da.binarypb/1760977477152396", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdab01619c1aeda5682e4cf3906d065ff731274a9660e4128740d5bb1a4d0947b472fe99f988e83670b6df502f5e0b5da.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdab01619c1aeda5682e4cf3906d065ff731274a9660e4128740d5bb1a4d0947b472fe99f988e83670b6df502f5e0b5da.binarypb?generation=1760977477152396&alt=media", + "name": "ovmf_x64_csm/tdx/dab01619c1aeda5682e4cf3906d065ff731274a9660e4128740d5bb1a4d0947b472fe99f988e83670b6df502f5e0b5da.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1760977477152396", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "if4VFrUdw/4bNtaiA/0m4Q==", + "crc32c": "4GaQVA==", + "etag": "CIzd7qeYs5ADEAE=", + "timeCreated": "2025-10-20T16:24:37.155Z", + "updated": "2025-10-20T16:24:37.155Z", + "timeStorageClassUpdated": "2025-10-20T16:24:37.155Z", + "timeFinalized": "2025-10-20T16:24:37.155Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/db393ea2f702aa5d368298f20bdc42c4d348aef66b2a95c0df1157f656c3cb744a42435ecc22a52a1ffc3263193b34de.binarypb/1747352689299962", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdb393ea2f702aa5d368298f20bdc42c4d348aef66b2a95c0df1157f656c3cb744a42435ecc22a52a1ffc3263193b34de.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdb393ea2f702aa5d368298f20bdc42c4d348aef66b2a95c0df1157f656c3cb744a42435ecc22a52a1ffc3263193b34de.binarypb?generation=1747352689299962&alt=media", + "name": "ovmf_x64_csm/tdx/db393ea2f702aa5d368298f20bdc42c4d348aef66b2a95c0df1157f656c3cb744a42435ecc22a52a1ffc3263193b34de.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1747352689299962", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5307", + "md5Hash": "YfIh3m29FPlCKbDR8awGDw==", + "crc32c": "RR4rQA==", + "etag": "CPqj34LUpo0DEAE=", + "timeCreated": "2025-05-15T23:44:49.302Z", + "updated": "2025-05-15T23:44:49.302Z", + "timeStorageClassUpdated": "2025-05-15T23:44:49.302Z", + "timeFinalized": "2025-05-15T23:44:49.302Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/df09e135fb464db0fd53610ac380475c43a0c1f08efe412a709d929c520c723fbcd87dcc9593e45ef33f3f31152efdf1.binarypb/1728951541331594", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdf09e135fb464db0fd53610ac380475c43a0c1f08efe412a709d929c520c723fbcd87dcc9593e45ef33f3f31152efdf1.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdf09e135fb464db0fd53610ac380475c43a0c1f08efe412a709d929c520c723fbcd87dcc9593e45ef33f3f31152efdf1.binarypb?generation=1728951541331594&alt=media", + "name": "ovmf_x64_csm/tdx/df09e135fb464db0fd53610ac380475c43a0c1f08efe412a709d929c520c723fbcd87dcc9593e45ef33f3f31152efdf1.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951541331594", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "CIrt0bOOj4kDEAE=", + "timeCreated": "2024-10-15T00:19:01.336Z", + "updated": "2024-10-15T00:19:01.336Z", + "timeStorageClassUpdated": "2024-10-15T00:19:01.336Z", + "timeFinalized": "2024-10-15T00:19:01.336Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/dfc29e5a4aa9fbca5187faa64d0bd2128ee7a3005dcd09143e3c78caee7b0f94211c854da9675e7a1feb9d664e32518a.binarypb/1773450094018441", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdfc29e5a4aa9fbca5187faa64d0bd2128ee7a3005dcd09143e3c78caee7b0f94211c854da9675e7a1feb9d664e32518a.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdfc29e5a4aa9fbca5187faa64d0bd2128ee7a3005dcd09143e3c78caee7b0f94211c854da9675e7a1feb9d664e32518a.binarypb?generation=1773450094018441&alt=media", + "name": "ovmf_x64_csm/tdx/dfc29e5a4aa9fbca5187faa64d0bd2128ee7a3005dcd09143e3c78caee7b0f94211c854da9675e7a1feb9d664e32518a.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1773450094018441", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5307", + "md5Hash": "nqysDx3Cjb/RcpR7vLWxGA==", + "crc32c": "IQjOxw==", + "etag": "CIn/hbeYnpMDEAE=", + "timeCreated": "2026-03-14T01:01:34.020Z", + "updated": "2026-03-14T01:01:34.020Z", + "timeStorageClassUpdated": "2026-03-14T01:01:34.020Z", + "timeFinalized": "2026-03-14T01:01:34.020Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e18a19909470b61360f4fb23128017a18519a26893ffb0084570d89718e98806951f015ea77fba6c90b39c8a930a2313.binarypb/1736880976365063", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe18a19909470b61360f4fb23128017a18519a26893ffb0084570d89718e98806951f015ea77fba6c90b39c8a930a2313.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe18a19909470b61360f4fb23128017a18519a26893ffb0084570d89718e98806951f015ea77fba6c90b39c8a930a2313.binarypb?generation=1736880976365063&alt=media", + "name": "ovmf_x64_csm/tdx/e18a19909470b61360f4fb23128017a18519a26893ffb0084570d89718e98806951f015ea77fba6c90b39c8a930a2313.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1736880976365063", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "k4IwRlza9X8csyTFcqen+w==", + "crc32c": "/AfofA==", + "etag": "CIeM9Ozx9YoDEAE=", + "timeCreated": "2025-01-14T18:56:16.367Z", + "updated": "2025-01-14T18:56:16.367Z", + "timeStorageClassUpdated": "2025-01-14T18:56:16.367Z", + "timeFinalized": "2025-01-14T18:56:16.367Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e5230d59843192d04bd596ef5b4d65dfb417ceb5a8f19c1771ad2242ce09e6c8f4b52adea7589fb486ea96cbb41a0a8b.binarypb/1728951529982825", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe5230d59843192d04bd596ef5b4d65dfb417ceb5a8f19c1771ad2242ce09e6c8f4b52adea7589fb486ea96cbb41a0a8b.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe5230d59843192d04bd596ef5b4d65dfb417ceb5a8f19c1771ad2242ce09e6c8f4b52adea7589fb486ea96cbb41a0a8b.binarypb?generation=1728951529982825&alt=media", + "name": "ovmf_x64_csm/tdx/e5230d59843192d04bd596ef5b4d65dfb417ceb5a8f19c1771ad2242ce09e6c8f4b52adea7589fb486ea96cbb41a0a8b.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728951529982825", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5066", + "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", + "crc32c": "QGep7A==", + "etag": "COmWna6Oj4kDEAE=", + "timeCreated": "2024-10-15T00:18:49.991Z", + "updated": "2024-10-15T00:18:49.991Z", + "timeStorageClassUpdated": "2024-10-15T00:18:49.991Z", + "timeFinalized": "2024-10-15T00:18:49.991Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e7f7c781f3758823d88b5c66d09106752abf0734e1b2ab44351b1a29628383fc33075b3b7dd52b6b33f22dd8ab75edef.binarypb/1725637323120078", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe7f7c781f3758823d88b5c66d09106752abf0734e1b2ab44351b1a29628383fc33075b3b7dd52b6b33f22dd8ab75edef.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe7f7c781f3758823d88b5c66d09106752abf0734e1b2ab44351b1a29628383fc33075b3b7dd52b6b33f22dd8ab75edef.binarypb?generation=1725637323120078&alt=media", + "name": "ovmf_x64_csm/tdx/e7f7c781f3758823d88b5c66d09106752abf0734e1b2ab44351b1a29628383fc33075b3b7dd52b6b33f22dd8ab75edef.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1725637323120078", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5873", + "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", + "crc32c": "7PKCRw==", + "etag": "CM67n/3TrogDEAE=", + "timeCreated": "2024-09-06T15:42:03.122Z", + "updated": "2024-09-06T15:42:03.122Z", + "timeStorageClassUpdated": "2024-09-06T15:42:03.122Z", + "timeFinalized": "2024-09-06T15:42:03.122Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e858ba2038b2de3dbc3e3feed04738e28f664066db04889689d7230d1eaf9d24db80883e51c6e890e3e856f74540359a.binarypb/1728083459187750", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe858ba2038b2de3dbc3e3feed04738e28f664066db04889689d7230d1eaf9d24db80883e51c6e890e3e856f74540359a.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe858ba2038b2de3dbc3e3feed04738e28f664066db04889689d7230d1eaf9d24db80883e51c6e890e3e856f74540359a.binarypb?generation=1728083459187750&alt=media", + "name": "ovmf_x64_csm/tdx/e858ba2038b2de3dbc3e3feed04738e28f664066db04889689d7230d1eaf9d24db80883e51c6e890e3e856f74540359a.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1728083459187750", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", + "crc32c": "k9E9bA==", + "etag": "CKbI6MXs9YgDEAE=", + "timeCreated": "2024-10-04T23:10:59.189Z", + "updated": "2024-10-04T23:10:59.189Z", + "timeStorageClassUpdated": "2024-10-04T23:10:59.189Z", + "timeFinalized": "2024-10-04T23:10:59.189Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e88719a23871c90574a02b3ce7c9725e7e29813e69b7243686d3e37d76ef8877abec199742ce84029c5f3bff0b661707.binarypb/1749835943054254", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe88719a23871c90574a02b3ce7c9725e7e29813e69b7243686d3e37d76ef8877abec199742ce84029c5f3bff0b661707.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe88719a23871c90574a02b3ce7c9725e7e29813e69b7243686d3e37d76ef8877abec199742ce84029c5f3bff0b661707.binarypb?generation=1749835943054254&alt=media", + "name": "ovmf_x64_csm/tdx/e88719a23871c90574a02b3ce7c9725e7e29813e69b7243686d3e37d76ef8877abec199742ce84029c5f3bff0b661707.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1749835943054254", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "Cxj19jTRUoBXz7bLSxsREg==", + "crc32c": "t1YYZg==", + "etag": "CK6XtO727o0DEAE=", + "timeCreated": "2025-06-13T17:32:23.057Z", + "updated": "2025-06-13T17:32:23.057Z", + "timeStorageClassUpdated": "2025-06-13T17:32:23.057Z", + "timeFinalized": "2025-06-13T17:32:23.057Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/edbc2e630231a058685db03ffc86cc919d97d8978eda1a5d7822fcc71189ed030bad5499e4895d8e8e41084c115db8fc.binarypb/1767815579144687", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fedbc2e630231a058685db03ffc86cc919d97d8978eda1a5d7822fcc71189ed030bad5499e4895d8e8e41084c115db8fc.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fedbc2e630231a058685db03ffc86cc919d97d8978eda1a5d7822fcc71189ed030bad5499e4895d8e8e41084c115db8fc.binarypb?generation=1767815579144687&alt=media", + "name": "ovmf_x64_csm/tdx/edbc2e630231a058685db03ffc86cc919d97d8978eda1a5d7822fcc71189ed030bad5499e4895d8e8e41084c115db8fc.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1767815579144687", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "NUzVZKtQ2hTweKzhS8X7Zw==", + "crc32c": "tb2kzw==", + "etag": "CO+j/pya+pEDEAE=", + "timeCreated": "2026-01-07T19:52:59.147Z", + "updated": "2026-01-07T19:52:59.147Z", + "timeStorageClassUpdated": "2026-01-07T19:52:59.147Z", + "timeFinalized": "2026-01-07T19:52:59.147Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/f0cfe5b84301d459e05be84b2a92821378dbf7c89088f91cf6f76cb2758811906bbdc6c82b077059adc429ff5642c4de.binarypb/1723585988775887", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff0cfe5b84301d459e05be84b2a92821378dbf7c89088f91cf6f76cb2758811906bbdc6c82b077059adc429ff5642c4de.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff0cfe5b84301d459e05be84b2a92821378dbf7c89088f91cf6f76cb2758811906bbdc6c82b077059adc429ff5642c4de.binarypb?generation=1723585988775887&alt=media", + "name": "ovmf_x64_csm/tdx/f0cfe5b84301d459e05be84b2a92821378dbf7c89088f91cf6f76cb2758811906bbdc6c82b077059adc429ff5642c4de.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1723585988775887", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5868", + "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", + "crc32c": "YXklrg==", + "etag": "CM+f55T68ocDEAE=", + "timeCreated": "2024-08-13T21:53:08.778Z", + "updated": "2024-08-13T21:53:08.778Z", + "timeStorageClassUpdated": "2024-08-13T21:53:08.778Z", + "timeFinalized": "2024-08-13T21:53:08.778Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/f21617ea292291450f68a7909664faead9760a94537b771549b5280a841ed39eb2b12612bb4ecca5e6d4bdcc0cea439b.binarypb/1738630574573147", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff21617ea292291450f68a7909664faead9760a94537b771549b5280a841ed39eb2b12612bb4ecca5e6d4bdcc0cea439b.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff21617ea292291450f68a7909664faead9760a94537b771549b5280a841ed39eb2b12612bb4ecca5e6d4bdcc0cea439b.binarypb?generation=1738630574573147&alt=media", + "name": "ovmf_x64_csm/tdx/f21617ea292291450f68a7909664faead9760a94537b771549b5280a841ed39eb2b12612bb4ecca5e6d4bdcc0cea439b.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1738630574573147", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "K6K133aqs7O38l1ZlKvgBw==", + "crc32c": "tzSyKg==", + "etag": "CNuMrM7nqIsDEAE=", + "timeCreated": "2025-02-04T00:56:14.574Z", + "updated": "2025-02-04T00:56:14.574Z", + "timeStorageClassUpdated": "2025-02-04T00:56:14.574Z", + "timeFinalized": "2025-02-04T00:56:14.574Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/f272d8492d31f6fffa1d0ae81ed2d240a2dd4b81a5f5ebec7e89c9a35f79c3d831588f18d3af13a9b337398ef91bb36b.binarypb/1742241747340264", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff272d8492d31f6fffa1d0ae81ed2d240a2dd4b81a5f5ebec7e89c9a35f79c3d831588f18d3af13a9b337398ef91bb36b.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff272d8492d31f6fffa1d0ae81ed2d240a2dd4b81a5f5ebec7e89c9a35f79c3d831588f18d3af13a9b337398ef91bb36b.binarypb?generation=1742241747340264&alt=media", + "name": "ovmf_x64_csm/tdx/f272d8492d31f6fffa1d0ae81ed2d240a2dd4b81a5f5ebec7e89c9a35f79c3d831588f18d3af13a9b337398ef91bb36b.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1742241747340264", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "80TsozNXqP6cgkI7aUwDMw==", + "crc32c": "HAQx6w==", + "etag": "COiX2qP0kYwDEAE=", + "timeCreated": "2025-03-17T20:02:27.341Z", + "updated": "2025-03-17T20:02:27.341Z", + "timeStorageClassUpdated": "2025-03-17T20:02:27.341Z", + "timeFinalized": "2025-03-17T20:02:27.341Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/f762c0050e56acf0074303393b376a442b896cc795acb8fa348b4e33fb85bf431ca33cdbb9b0ae289f849e9185778602.binarypb/1729190363785814", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff762c0050e56acf0074303393b376a442b896cc795acb8fa348b4e33fb85bf431ca33cdbb9b0ae289f849e9185778602.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff762c0050e56acf0074303393b376a442b896cc795acb8fa348b4e33fb85bf431ca33cdbb9b0ae289f849e9185778602.binarypb?generation=1729190363785814&alt=media", + "name": "ovmf_x64_csm/tdx/f762c0050e56acf0074303393b376a442b896cc795acb8fa348b4e33fb85bf431ca33cdbb9b0ae289f849e9185778602.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1729190363785814", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5869", + "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", + "crc32c": "tBQmEQ==", + "etag": "CNbUh4uIlokDEAE=", + "timeCreated": "2024-10-17T18:39:23.788Z", + "updated": "2024-10-17T18:39:23.788Z", + "timeStorageClassUpdated": "2024-10-17T18:39:23.788Z", + "timeFinalized": "2024-10-17T18:39:23.788Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/fd4eda3653e0179b19655716effba08b1285eeb810196a4653a9e23b62e2f1b671df3e5f37ad821897782be807a85acf.binarypb/1761952076603348", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ffd4eda3653e0179b19655716effba08b1285eeb810196a4653a9e23b62e2f1b671df3e5f37ad821897782be807a85acf.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ffd4eda3653e0179b19655716effba08b1285eeb810196a4653a9e23b62e2f1b671df3e5f37ad821897782be807a85acf.binarypb?generation=1761952076603348&alt=media", + "name": "ovmf_x64_csm/tdx/fd4eda3653e0179b19655716effba08b1285eeb810196a4653a9e23b62e2f1b671df3e5f37ad821897782be807a85acf.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1761952076603348", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5307", + "md5Hash": "6keyAMuscNoyqyIzduiPdA==", + "crc32c": "uF51mg==", + "etag": "CNS/jP3Gz5ADEAE=", + "timeCreated": "2025-10-31T23:07:56.605Z", + "updated": "2025-10-31T23:07:56.605Z", + "timeStorageClassUpdated": "2025-10-31T23:07:56.605Z", + "timeFinalized": "2025-10-31T23:07:56.605Z" + }, + { + "kind": "storage#object", + "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/feb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162.binarypb/1773355463154784", + "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ffeb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162.binarypb", + "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ffeb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162.binarypb?generation=1773355463154784&alt=media", + "name": "ovmf_x64_csm/tdx/feb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162.binarypb", + "bucket": "gce_tcb_integrity", + "generation": "1773355463154784", + "metageneration": "1", + "contentType": "application/octet-stream", + "storageClass": "STANDARD", + "size": "5308", + "md5Hash": "TYybKoEwVCW1UlFMsbyUvw==", + "crc32c": "NqZFYg==", + "etag": "COC4xPO3m5MDEAE=", + "timeCreated": "2026-03-12T22:44:23.156Z", + "updated": "2026-03-12T22:44:23.156Z", + "timeStorageClassUpdated": "2026-03-12T22:44:23.156Z", + "timeFinalized": "2026-03-12T22:44:23.156Z" + } + ] +} From ef5908d875cbd7ab9f2107edab5e74e85abf9732 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 24 Jun 2026 11:54:26 +0200 Subject: [PATCH 16/35] Rm cache prewarm --- crates/attestation/src/gcp.rs | 139 +++---------------------- crates/attestation/src/lib.rs | 20 +--- crates/attestation/src/measurements.rs | 3 +- 3 files changed, 21 insertions(+), 141 deletions(-) diff --git a/crates/attestation/src/gcp.rs b/crates/attestation/src/gcp.rs index 6e47cd7..60777e1 100644 --- a/crates/attestation/src/gcp.rs +++ b/crates/attestation/src/gcp.rs @@ -1,152 +1,47 @@ use std::{ collections::HashMap, - io::Read, sync::{Arc, RwLock}, }; use attest_measure::dcap::DcapFirmware; -use serde::Deserialize; use thiserror::Error; -const GCS_FIRMWARE_LIST_URL: &str = - "https://storage.googleapis.com/storage/v1/b/gce_tcb_integrity/o"; -const GCS_FIRMWARE_PREFIX: &str = "ovmf_x64_csm/tdx/"; -const GCS_FIRMWARE_MAX_RESULTS: &str = "1000"; - +/// Maps MRTD values to GCP firmware to avoid re-fetching on subsequent +/// verification #[derive(Clone, Debug, Default)] pub(crate) struct GcpFirmwareCache { cache: Arc>>, } -#[derive(Debug, Error)] -pub enum GcpFirmwareCacheError { - #[error("HTTP: {0}")] - Http(String), - #[error("response body was not valid UTF-8")] - Utf8(#[from] std::string::FromUtf8Error), - #[error("listing JSON: {0}")] - Listing(#[from] serde_json::Error), - #[error("invalid GCP firmware object name: {0}")] - ObjectName(String), - #[error("invalid MRTD hex in object name: {0}")] - Mrtd(String), - #[error("firmware: {0}")] - Firmware(#[from] attest_measure::dcap::GoogleError), -} - -#[derive(Debug, Deserialize)] -struct GcsObjectsResponse { - #[serde(default)] - items: Vec, -} - -#[derive(Debug, Deserialize)] -struct GcsObject { - name: String, -} - impl GcpFirmwareCache { pub(crate) fn new() -> Self { Self { cache: Default::default() } } - pub(crate) fn prewarm() -> Result { - let cache = Self::new(); - for mrtd in fetch_known_mrtds()? { - cache.get_or_fetch(mrtd)?; - } - Ok(cache) - } - + /// Retrieve firmware from cache or fetch if not present pub(crate) fn get_or_fetch( &self, mrtd: [u8; 48], - ) -> Result { - if let Some(firmware) = self.cache.read().unwrap().get(&mrtd).cloned() { + ) -> Result { + if let Some(firmware) = + self.cache.read().map_err(|_| GcpFirmwareCacheError::CacheLock)?.get(&mrtd).cloned() + { return Ok(firmware); } let firmware = DcapFirmware::from_google(mrtd)?; - self.cache.write().unwrap().insert(mrtd, firmware.clone()); + self.cache + .write() + .map_err(|_| GcpFirmwareCacheError::CacheLock)? + .insert(mrtd, firmware.clone()); Ok(firmware) } } -fn fetch_known_mrtds() -> Result, GcpFirmwareCacheError> { - let response = ureq::get(GCS_FIRMWARE_LIST_URL) - .query("prefix", GCS_FIRMWARE_PREFIX) - .query("maxResults", GCS_FIRMWARE_MAX_RESULTS) - .call() - .map_err(|err| GcpFirmwareCacheError::Http(err.to_string()))?; - let mut reader = response.into_reader(); - let mut body = Vec::new(); - reader.read_to_end(&mut body).map_err(|err| GcpFirmwareCacheError::Http(err.to_string()))?; - parse_known_mrtds(&body) -} - -fn parse_known_mrtds(body: &[u8]) -> Result, GcpFirmwareCacheError> { - let body = String::from_utf8(body.to_vec())?; - let objects: GcsObjectsResponse = serde_json::from_str(&body)?; - - let mut mrtds = Vec::new(); - for object in objects.items { - if let Some(mrtd) = parse_mrtd_from_object_name(&object.name)? { - mrtds.push(mrtd); - } - } - - if mrtds.is_empty() { - return Err(GcpFirmwareCacheError::ObjectName( - "no GCP firmware objects were discovered during prewarm".to_string(), - )); - } - - Ok(mrtds) -} - -fn parse_mrtd_from_object_name(name: &str) -> Result, GcpFirmwareCacheError> { - if !name.starts_with(GCS_FIRMWARE_PREFIX) || !name.ends_with(".binarypb") { - return Ok(None); - } - - let hex = &name[GCS_FIRMWARE_PREFIX.len()..name.len() - ".binarypb".len()]; - let bytes = hex::decode(hex).map_err(|_| GcpFirmwareCacheError::Mrtd(name.to_string()))?; - let mrtd: [u8; 48] = - bytes.try_into().map_err(|_| GcpFirmwareCacheError::Mrtd(name.to_string()))?; - Ok(Some(mrtd)) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[ignore] - fn dump_gcs_firmware_listing() { - let response = ureq::get(GCS_FIRMWARE_LIST_URL) - .query("prefix", GCS_FIRMWARE_PREFIX) - .query("maxResults", GCS_FIRMWARE_MAX_RESULTS) - .call() - .unwrap(); - let mut reader = response.into_reader(); - let mut body = Vec::new(); - reader.read_to_end(&mut body).unwrap(); - println!("{}", String::from_utf8(body).unwrap()); - } - - #[test] - fn parse_known_mrtds_fixture() { - let body = include_bytes!("../test-assets/gcp-known-firmware.json"); - let mrtds = parse_known_mrtds(body).unwrap(); - - assert_eq!(mrtds.len(), 78); - assert_eq!( - hex::encode(mrtds[0]), - "038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086" - ); - assert_eq!( - hex::encode(mrtds[1]), - "0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6" - ); - } +#[derive(Debug, Error)] +pub(crate) enum GcpFirmwareCacheError { + #[error("Cache lock poisoned")] + CacheLock, + #[error("firmware: {0}")] + Firmware(#[from] attest_measure::dcap::GoogleError), } diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 6402bc1..1d79064 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -14,7 +14,6 @@ use std::{ use attest_measure::platform::PlatformError; pub use attest_types::{AttestationEvidence, PlatformMetadata}; -pub use gcp::GcpFirmwareCacheError; use measurements::MultiMeasurements; use parity_scale_codec::{Decode, Encode}; use pccs::{Pccs, PccsError}; @@ -383,21 +382,6 @@ impl AttestationVerifier { ) } - pub fn new_prewarmed( - measurement_policy: MeasurementPolicy, - pccs_url: Option, - dump_dcap_quotes: bool, - override_azure_outdated_tcb: bool, - ) -> Result { - Ok(Self::build( - measurement_policy, - pccs_url, - dump_dcap_quotes, - override_azure_outdated_tcb, - gcp::GcpFirmwareCache::prewarm()?, - )) - } - /// Create an [AttestationVerifier] which will only allow no attestation /// and will reject if one is given pub fn expect_none() -> Self { @@ -645,8 +629,8 @@ fn running_on_gcp() -> Result { let resp = agent.get(GCP_METADATA_API).call(); if let Ok(r) = resp { - return Ok(r.status() == 200 && - r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); + return Ok(r.status() == 200 + && r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); } Ok(false) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index d0c16fe..e5712a7 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -14,7 +14,7 @@ use crate::{ AttestationError, AttestationType, dcap::DcapVerificationError, - gcp::GcpFirmwareCache, + gcp::{GcpFirmwareCache, GcpFirmwareCacheError}, }; /// Represents the measurement register types in a TDX quote @@ -419,6 +419,7 @@ impl MeasurementPolicy { cache.get_or_fetch(*mrtd) } else { DcapFirmware::from_google(*mrtd) + .map_err(GcpFirmwareCacheError::from) }; match result { Ok(firmware) => Some(firmware), From 52579b8358b25d296a29e9be2cf17fd10fa90bce Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 24 Jun 2026 11:55:22 +0200 Subject: [PATCH 17/35] Fmt --- crates/attestation/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 1d79064..0be0811 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -629,8 +629,8 @@ fn running_on_gcp() -> Result { let resp = agent.get(GCP_METADATA_API).call(); if let Ok(r) = resp { - return Ok(r.status() == 200 - && r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); + return Ok(r.status() == 200 && + r.header("Metadata-Flavor").map(|v| v == "Google").unwrap_or(false)); } Ok(false) From bbabfffdbf5029789c4d7e0e8cadc9f560adf0c1 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 24 Jun 2026 12:06:40 +0200 Subject: [PATCH 18/35] Avoid api breaking change --- crates/attestation/src/gcp.rs | 2 +- crates/attestation/src/lib.rs | 4 ++-- crates/attestation/src/measurements.rs | 10 +++++++++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/attestation/src/gcp.rs b/crates/attestation/src/gcp.rs index 60777e1..069b477 100644 --- a/crates/attestation/src/gcp.rs +++ b/crates/attestation/src/gcp.rs @@ -42,6 +42,6 @@ impl GcpFirmwareCache { pub(crate) enum GcpFirmwareCacheError { #[error("Cache lock poisoned")] CacheLock, - #[error("firmware: {0}")] + #[error("Firmware fetch: {0}")] Firmware(#[from] attest_measure::dcap::GoogleError), } diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 0be0811..a649cca 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -504,7 +504,7 @@ impl AttestationVerifier { .attestation_evidence .as_ref() .map(|evidence| evidence.platform.clone()); - self.measurement_policy.check_measurement( + self.measurement_policy.check_measurement_with_gcp_cache( &measurements, platform_metadata, Some(&self.known_gcp_firmware), @@ -581,7 +581,7 @@ impl AttestationVerifier { .attestation_evidence .as_ref() .map(|evidence| evidence.platform.clone()); - self.measurement_policy.check_measurement( + self.measurement_policy.check_measurement_with_gcp_cache( &measurements, platform_metadata, Some(&self.known_gcp_firmware), diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index e5712a7..3fcba15 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -381,7 +381,15 @@ impl MeasurementPolicy { /// Given an attestation type and set of measurements, check whether /// they are acceptable - pub(crate) fn check_measurement( + pub fn check_measurement( + &self, + measurements: &MultiMeasurements, + platform_metadata: Option, + ) -> Result<(), AttestationError> { + self.check_measurement_with_gcp_cache(measurements, platform_metadata, None) + } + + pub(crate) fn check_measurement_with_gcp_cache( &self, measurements: &MultiMeasurements, platform_metadata: Option, From 7d3f3ce3a28501f5a83f6f22a10607b2f7b40844 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 24 Jun 2026 12:10:01 +0200 Subject: [PATCH 19/35] Rm unused test asset --- .../test-assets/gcp-known-firmware.json | 1565 ----------------- 1 file changed, 1565 deletions(-) delete mode 100644 crates/attestation/test-assets/gcp-known-firmware.json diff --git a/crates/attestation/test-assets/gcp-known-firmware.json b/crates/attestation/test-assets/gcp-known-firmware.json deleted file mode 100644 index 27176f4..0000000 --- a/crates/attestation/test-assets/gcp-known-firmware.json +++ /dev/null @@ -1,1565 +0,0 @@ -{ - "kind": "storage#objects", - "items": [ - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086.binarypb/1728951531410960", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086.binarypb?generation=1728951531410960&alt=media", - "name": "ovmf_x64_csm/tdx/038de02f6584df60c9ad245045aecf6f0b9d90018eeff5736357334c37965b1cd5bf09032a94e6b721f34fa8973a1086.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951531410960", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CJCs9K6Oj4kDEAE=", - "timeCreated": "2024-10-15T00:18:51.417Z", - "updated": "2024-10-15T00:18:51.417Z", - "timeStorageClassUpdated": "2024-10-15T00:18:51.417Z", - "timeFinalized": "2024-10-15T00:18:51.417Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6.binarypb/1725637332221777", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6.binarypb?generation=1725637332221777&alt=media", - "name": "ovmf_x64_csm/tdx/0622b08df0d75dbce72c4870879daec46898227536ad12473ed73dbed8b3f6f7ab834f76f656196b5a92d715027890a6.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1725637332221777", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5873", - "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", - "crc32c": "7PKCRw==", - "etag": "CNH+yoHUrogDEAE=", - "timeCreated": "2024-09-06T15:42:12.223Z", - "updated": "2024-09-06T15:42:12.223Z", - "timeStorageClassUpdated": "2024-09-06T15:42:12.223Z", - "timeFinalized": "2024-09-06T15:42:12.223Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/0801dc9908dd4fcf6a03893e6e2803be64bebb568a2651f0238d07b9afe54028246f2f7e7a1768fe2b7653427be5aff1.binarypb/1725637337880372", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0801dc9908dd4fcf6a03893e6e2803be64bebb568a2651f0238d07b9afe54028246f2f7e7a1768fe2b7653427be5aff1.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0801dc9908dd4fcf6a03893e6e2803be64bebb568a2651f0238d07b9afe54028246f2f7e7a1768fe2b7653427be5aff1.binarypb?generation=1725637337880372&alt=media", - "name": "ovmf_x64_csm/tdx/0801dc9908dd4fcf6a03893e6e2803be64bebb568a2651f0238d07b9afe54028246f2f7e7a1768fe2b7653427be5aff1.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1725637337880372", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5873", - "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", - "crc32c": "7PKCRw==", - "etag": "CLSupITUrogDEAE=", - "timeCreated": "2024-09-06T15:42:17.881Z", - "updated": "2024-09-06T15:42:17.881Z", - "timeStorageClassUpdated": "2024-09-06T15:42:17.881Z", - "timeFinalized": "2024-09-06T15:42:17.881Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/0e9616e6bca294aaa38d5127af79d212c0e8d193d1e8c4d714121e717081057b3f3b37aaa414c7b6fc29b9237ce8d142.binarypb/1723585975353261", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0e9616e6bca294aaa38d5127af79d212c0e8d193d1e8c4d714121e717081057b3f3b37aaa414c7b6fc29b9237ce8d142.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F0e9616e6bca294aaa38d5127af79d212c0e8d193d1e8c4d714121e717081057b3f3b37aaa414c7b6fc29b9237ce8d142.binarypb?generation=1723585975353261&alt=media", - "name": "ovmf_x64_csm/tdx/0e9616e6bca294aaa38d5127af79d212c0e8d193d1e8c4d714121e717081057b3f3b37aaa414c7b6fc29b9237ce8d142.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723585975353261", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5868", - "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", - "crc32c": "YXklrg==", - "etag": "CK3/s4768ocDEAE=", - "timeCreated": "2024-08-13T21:52:55.356Z", - "updated": "2024-08-13T21:52:55.356Z", - "timeStorageClassUpdated": "2024-08-13T21:52:55.356Z", - "timeFinalized": "2024-08-13T21:52:55.356Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/14d4600f8d1dc8249e9cea29aad07160fa242c54005b50f1814a34cc9f766e2064658376a2409d7ffd69363e95689ec9.binarypb/1723135792757493", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F14d4600f8d1dc8249e9cea29aad07160fa242c54005b50f1814a34cc9f766e2064658376a2409d7ffd69363e95689ec9.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F14d4600f8d1dc8249e9cea29aad07160fa242c54005b50f1814a34cc9f766e2064658376a2409d7ffd69363e95689ec9.binarypb?generation=1723135792757493&alt=media", - "name": "ovmf_x64_csm/tdx/14d4600f8d1dc8249e9cea29aad07160fa242c54005b50f1814a34cc9f766e2064658376a2409d7ffd69363e95689ec9.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723135792757493", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5866", - "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", - "crc32c": "Twn57g==", - "etag": "CPX1zobt5YcDEAE=", - "timeCreated": "2024-08-08T16:49:52.759Z", - "updated": "2024-08-08T16:49:52.759Z", - "timeStorageClassUpdated": "2024-08-08T16:49:52.759Z", - "timeFinalized": "2024-08-08T16:49:52.759Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/174c707bfe72f2f86a029a01ba6917670fe90c5af9594355f3fca0e4c02afae5ac791ac2d49470e6b00333ff9732c51d.binarypb/1723135810306527", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F174c707bfe72f2f86a029a01ba6917670fe90c5af9594355f3fca0e4c02afae5ac791ac2d49470e6b00333ff9732c51d.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F174c707bfe72f2f86a029a01ba6917670fe90c5af9594355f3fca0e4c02afae5ac791ac2d49470e6b00333ff9732c51d.binarypb?generation=1723135810306527&alt=media", - "name": "ovmf_x64_csm/tdx/174c707bfe72f2f86a029a01ba6917670fe90c5af9594355f3fca0e4c02afae5ac791ac2d49470e6b00333ff9732c51d.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723135810306527", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5866", - "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", - "crc32c": "Twn57g==", - "etag": "CN+D/o7t5YcDEAE=", - "timeCreated": "2024-08-08T16:50:10.310Z", - "updated": "2024-08-08T16:50:10.310Z", - "timeStorageClassUpdated": "2024-08-08T16:50:10.310Z", - "timeFinalized": "2024-08-08T16:50:10.310Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/1859e2894b0b0a279597bd5ab46baa7d6f3a246706832709e65658396e33aa74b10541e981f5355921275227e3ca5803.binarypb/1723585984037070", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1859e2894b0b0a279597bd5ab46baa7d6f3a246706832709e65658396e33aa74b10541e981f5355921275227e3ca5803.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1859e2894b0b0a279597bd5ab46baa7d6f3a246706832709e65658396e33aa74b10541e981f5355921275227e3ca5803.binarypb?generation=1723585984037070&alt=media", - "name": "ovmf_x64_csm/tdx/1859e2894b0b0a279597bd5ab46baa7d6f3a246706832709e65658396e33aa74b10541e981f5355921275227e3ca5803.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723585984037070", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5868", - "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", - "crc32c": "YXklrg==", - "etag": "CM6BxpL68ocDEAE=", - "timeCreated": "2024-08-13T21:53:04.039Z", - "updated": "2024-08-13T21:53:04.039Z", - "timeStorageClassUpdated": "2024-08-13T21:53:04.039Z", - "timeFinalized": "2024-08-13T21:53:04.039Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/1c4b129360c4827bc42374ab0eddfe2f9e39192d65e3b27374ee930d1365f9c2cea1ed8923b3917691c676e195d9276a.binarypb/1759434910156667", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1c4b129360c4827bc42374ab0eddfe2f9e39192d65e3b27374ee930d1365f9c2cea1ed8923b3917691c676e195d9276a.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1c4b129360c4827bc42374ab0eddfe2f9e39192d65e3b27374ee930d1365f9c2cea1ed8923b3917691c676e195d9276a.binarypb?generation=1759434910156667&alt=media", - "name": "ovmf_x64_csm/tdx/1c4b129360c4827bc42374ab0eddfe2f9e39192d65e3b27374ee930d1365f9c2cea1ed8923b3917691c676e195d9276a.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1759434910156667", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "v2EL4wcxApEurObXDr2Ulg==", - "crc32c": "5ek1mQ==", - "etag": "CPuOzealhpADEAE=", - "timeCreated": "2025-10-02T19:55:10.159Z", - "updated": "2025-10-02T19:55:10.159Z", - "timeStorageClassUpdated": "2025-10-02T19:55:10.159Z", - "timeFinalized": "2025-10-02T19:55:10.159Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/1cdf036c40e4bd17c17b6c89d97292c7f4520c42d7a0e3088b5fcd65a8162b65e1285b0aad6a5ab8cb1fc0275bb568ef.binarypb/1719876450123148", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1cdf036c40e4bd17c17b6c89d97292c7f4520c42d7a0e3088b5fcd65a8162b65e1285b0aad6a5ab8cb1fc0275bb568ef.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F1cdf036c40e4bd17c17b6c89d97292c7f4520c42d7a0e3088b5fcd65a8162b65e1285b0aad6a5ab8cb1fc0275bb568ef.binarypb?generation=1719876450123148&alt=media", - "name": "ovmf_x64_csm/tdx/1cdf036c40e4bd17c17b6c89d97292c7f4520c42d7a0e3088b5fcd65a8162b65e1285b0aad6a5ab8cb1fc0275bb568ef.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1719876450123148", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5865", - "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", - "crc32c": "s0O/hw==", - "etag": "CIz794b/hocDEAE=", - "timeCreated": "2024-07-01T23:27:30.124Z", - "updated": "2024-07-01T23:27:30.124Z", - "timeStorageClassUpdated": "2024-07-01T23:27:30.124Z", - "timeFinalized": "2024-07-01T23:27:30.124Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/2013fba7cf71a71f0e88d980093836e1c5a15c3f5a862f82acaa6693f04714fd82728551129d669276111805eed415a7.binarypb/1726777919296573", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2013fba7cf71a71f0e88d980093836e1c5a15c3f5a862f82acaa6693f04714fd82728551129d669276111805eed415a7.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2013fba7cf71a71f0e88d980093836e1c5a15c3f5a862f82acaa6693f04714fd82728551129d669276111805eed415a7.binarypb?generation=1726777919296573&alt=media", - "name": "ovmf_x64_csm/tdx/2013fba7cf71a71f0e88d980093836e1c5a15c3f5a862f82acaa6693f04714fd82728551129d669276111805eed415a7.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1726777919296573", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5868", - "md5Hash": "q8QrsAgVMc9+mN0gFv+2CA==", - "crc32c": "x1hIgw==", - "etag": "CL2o8YPtz4gDEAE=", - "timeCreated": "2024-09-19T20:31:59.297Z", - "updated": "2024-09-19T20:31:59.297Z", - "timeStorageClassUpdated": "2024-09-19T20:31:59.297Z", - "timeFinalized": "2024-09-19T20:31:59.297Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525.binarypb/1733428457865719", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525.binarypb?generation=1733428457865719&alt=media", - "name": "ovmf_x64_csm/tdx/2a90c8fa38672cafd791d994beb6836b99383b2563736858632284f0f760a6446efd1e7ec457cf08b629ea630f7b4525.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1733428457865719", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5307", - "md5Hash": "sed+XMq9hsc2HlOdKEYlrg==", - "crc32c": "t4bzlA==", - "etag": "CPeD5pu0kYoDEAE=", - "timeCreated": "2024-12-05T19:54:17.867Z", - "updated": "2024-12-05T19:54:17.867Z", - "timeStorageClassUpdated": "2024-12-05T19:54:17.867Z", - "timeFinalized": "2024-12-05T19:54:17.867Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/2b628010aa45375938437a5e85efa0767483d8ec0c8b02f5a04cc4b5dc99e7c09255390e7b38da983b51592a596b24bf.binarypb/1723585971915609", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2b628010aa45375938437a5e85efa0767483d8ec0c8b02f5a04cc4b5dc99e7c09255390e7b38da983b51592a596b24bf.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F2b628010aa45375938437a5e85efa0767483d8ec0c8b02f5a04cc4b5dc99e7c09255390e7b38da983b51592a596b24bf.binarypb?generation=1723585971915609&alt=media", - "name": "ovmf_x64_csm/tdx/2b628010aa45375938437a5e85efa0767483d8ec0c8b02f5a04cc4b5dc99e7c09255390e7b38da983b51592a596b24bf.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723585971915609", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5868", - "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", - "crc32c": "YXklrg==", - "etag": "CNmW4oz68ocDEAE=", - "timeCreated": "2024-08-13T21:52:51.921Z", - "updated": "2024-08-13T21:52:51.921Z", - "timeStorageClassUpdated": "2024-08-13T21:52:51.921Z", - "timeFinalized": "2024-08-13T21:52:51.921Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/30f70a91e36b6564c91f49c3318410efbd2e129009bd37419f97b68b96f4d5c7c878be5515001607dd3b70b5351478ef.binarypb/1719876453464805", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F30f70a91e36b6564c91f49c3318410efbd2e129009bd37419f97b68b96f4d5c7c878be5515001607dd3b70b5351478ef.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F30f70a91e36b6564c91f49c3318410efbd2e129009bd37419f97b68b96f4d5c7c878be5515001607dd3b70b5351478ef.binarypb?generation=1719876453464805&alt=media", - "name": "ovmf_x64_csm/tdx/30f70a91e36b6564c91f49c3318410efbd2e129009bd37419f97b68b96f4d5c7c878be5515001607dd3b70b5351478ef.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1719876453464805", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5865", - "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", - "crc32c": "s0O/hw==", - "etag": "COX1w4j/hocDEAE=", - "timeCreated": "2024-07-01T23:27:33.466Z", - "updated": "2024-07-01T23:27:33.466Z", - "timeStorageClassUpdated": "2024-07-01T23:27:33.466Z", - "timeFinalized": "2024-07-01T23:27:33.466Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/31fcc66cd7e1b43462da46028cd9728d49b3400906a306185b7f8091e5d6f5ecb368fb86463263ea66178aa4015459f0.binarypb/1728083460112238", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F31fcc66cd7e1b43462da46028cd9728d49b3400906a306185b7f8091e5d6f5ecb368fb86463263ea66178aa4015459f0.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F31fcc66cd7e1b43462da46028cd9728d49b3400906a306185b7f8091e5d6f5ecb368fb86463263ea66178aa4015459f0.binarypb?generation=1728083460112238&alt=media", - "name": "ovmf_x64_csm/tdx/31fcc66cd7e1b43462da46028cd9728d49b3400906a306185b7f8091e5d6f5ecb368fb86463263ea66178aa4015459f0.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728083460112238", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", - "crc32c": "k9E9bA==", - "etag": "CO7+oMbs9YgDEAE=", - "timeCreated": "2024-10-04T23:11:00.113Z", - "updated": "2024-10-04T23:11:00.113Z", - "timeStorageClassUpdated": "2024-10-04T23:11:00.113Z", - "timeFinalized": "2024-10-04T23:11:00.113Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/3a936a289984cb494bd1ece845e7b0bba293a33b560ff557e88468797a4cf7c32c12077182cbd9f2577f7a8c62956fb4.binarypb/1723135801822321", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3a936a289984cb494bd1ece845e7b0bba293a33b560ff557e88468797a4cf7c32c12077182cbd9f2577f7a8c62956fb4.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3a936a289984cb494bd1ece845e7b0bba293a33b560ff557e88468797a4cf7c32c12077182cbd9f2577f7a8c62956fb4.binarypb?generation=1723135801822321&alt=media", - "name": "ovmf_x64_csm/tdx/3a936a289984cb494bd1ece845e7b0bba293a33b560ff557e88468797a4cf7c32c12077182cbd9f2577f7a8c62956fb4.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723135801822321", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5866", - "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", - "crc32c": "Twn57g==", - "etag": "CPGY+Irt5YcDEAE=", - "timeCreated": "2024-08-08T16:50:01.824Z", - "updated": "2024-08-08T16:50:01.824Z", - "timeStorageClassUpdated": "2024-08-08T16:50:01.824Z", - "timeFinalized": "2024-08-08T16:50:01.824Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/3c8afc83fb70127b7566298d76b609bce1e3d71d88eca54e64ea1fbe33a51e8b890c6b3696e6fef2100a1aabbb9d2cb7.binarypb/1728951528515504", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3c8afc83fb70127b7566298d76b609bce1e3d71d88eca54e64ea1fbe33a51e8b890c6b3696e6fef2100a1aabbb9d2cb7.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3c8afc83fb70127b7566298d76b609bce1e3d71d88eca54e64ea1fbe33a51e8b890c6b3696e6fef2100a1aabbb9d2cb7.binarypb?generation=1728951528515504&alt=media", - "name": "ovmf_x64_csm/tdx/3c8afc83fb70127b7566298d76b609bce1e3d71d88eca54e64ea1fbe33a51e8b890c6b3696e6fef2100a1aabbb9d2cb7.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951528515504", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CLDPw62Oj4kDEAE=", - "timeCreated": "2024-10-15T00:18:48.522Z", - "updated": "2024-10-15T00:18:48.522Z", - "timeStorageClassUpdated": "2024-10-15T00:18:48.522Z", - "timeFinalized": "2024-10-15T00:18:48.522Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/3ca3714b4c15e4ea784542c386d4b51c5eae269d0d01e281c9080725a99828f050e62925560937710554d546a4fd3fe3.binarypb/1743189881640258", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3ca3714b4c15e4ea784542c386d4b51c5eae269d0d01e281c9080725a99828f050e62925560937710554d546a4fd3fe3.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3ca3714b4c15e4ea784542c386d4b51c5eae269d0d01e281c9080725a99828f050e62925560937710554d546a4fd3fe3.binarypb?generation=1743189881640258&alt=media", - "name": "ovmf_x64_csm/tdx/3ca3714b4c15e4ea784542c386d4b51c5eae269d0d01e281c9080725a99828f050e62925560937710554d546a4fd3fe3.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1743189881640258", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5307", - "md5Hash": "UmdGYR2D42Cx0X/4GfsDeA==", - "crc32c": "7sW2pg==", - "etag": "CMKqr63ArYwDEAE=", - "timeCreated": "2025-03-28T19:24:41.642Z", - "updated": "2025-03-28T19:24:41.642Z", - "timeStorageClassUpdated": "2025-03-28T19:24:41.642Z", - "timeFinalized": "2025-03-28T19:24:41.642Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/3f19f3275bb9b38d12d7bc746c0e5c4442cd7a2baca6a73a29d50a16724353f342125a54e4456443cde7f92d633bd5be.binarypb/1728951539926799", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3f19f3275bb9b38d12d7bc746c0e5c4442cd7a2baca6a73a29d50a16724353f342125a54e4456443cde7f92d633bd5be.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F3f19f3275bb9b38d12d7bc746c0e5c4442cd7a2baca6a73a29d50a16724353f342125a54e4456443cde7f92d633bd5be.binarypb?generation=1728951539926799&alt=media", - "name": "ovmf_x64_csm/tdx/3f19f3275bb9b38d12d7bc746c0e5c4442cd7a2baca6a73a29d50a16724353f342125a54e4456443cde7f92d633bd5be.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951539926799", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CI+O/LKOj4kDEAE=", - "timeCreated": "2024-10-15T00:18:59.934Z", - "updated": "2024-10-15T00:18:59.934Z", - "timeStorageClassUpdated": "2024-10-15T00:18:59.934Z", - "timeFinalized": "2024-10-15T00:18:59.934Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/404b12e5d73cb9e5387b1a6927a7b2218f26fb2bbdeb317c63a58165a4c3248076cc064cefc195f90d741b7e657ee791.binarypb/1728951532803041", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F404b12e5d73cb9e5387b1a6927a7b2218f26fb2bbdeb317c63a58165a4c3248076cc064cefc195f90d741b7e657ee791.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F404b12e5d73cb9e5387b1a6927a7b2218f26fb2bbdeb317c63a58165a4c3248076cc064cefc195f90d741b7e657ee791.binarypb?generation=1728951532803041&alt=media", - "name": "ovmf_x64_csm/tdx/404b12e5d73cb9e5387b1a6927a7b2218f26fb2bbdeb317c63a58165a4c3248076cc064cefc195f90d741b7e657ee791.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951532803041", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "COGnya+Oj4kDEAE=", - "timeCreated": "2024-10-15T00:18:52.811Z", - "updated": "2024-10-15T00:18:52.811Z", - "timeStorageClassUpdated": "2024-10-15T00:18:52.811Z", - "timeFinalized": "2024-10-15T00:18:52.811Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99.binarypb/1747697989339141", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99.binarypb?generation=1747697989339141&alt=media", - "name": "ovmf_x64_csm/tdx/409c0cd3e63d9ea54d817cf851983a220131262664ac8cd02cc6a2e19fd291d2fdd0cc035d7789b982a43a92a4424c99.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1747697989339141", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5307", - "md5Hash": "1M3SdZ6faZkGkDfYWJiQtw==", - "crc32c": "RZUtyw==", - "etag": "CIWQ0a7asI0DEAE=", - "timeCreated": "2025-05-19T23:39:49.344Z", - "updated": "2025-05-19T23:39:49.344Z", - "timeStorageClassUpdated": "2025-05-19T23:39:49.344Z", - "timeFinalized": "2025-05-19T23:39:49.344Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/4265d9a735194d336eb09392843ce4d1110c2448b1f0230d5e334254521f5a0243e4b5bedbab92cc5c06a9e123dc9150.binarypb/1723585982896905", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F4265d9a735194d336eb09392843ce4d1110c2448b1f0230d5e334254521f5a0243e4b5bedbab92cc5c06a9e123dc9150.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F4265d9a735194d336eb09392843ce4d1110c2448b1f0230d5e334254521f5a0243e4b5bedbab92cc5c06a9e123dc9150.binarypb?generation=1723585982896905&alt=media", - "name": "ovmf_x64_csm/tdx/4265d9a735194d336eb09392843ce4d1110c2448b1f0230d5e334254521f5a0243e4b5bedbab92cc5c06a9e123dc9150.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723585982896905", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5868", - "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", - "crc32c": "YXklrg==", - "etag": "CIm2gJL68ocDEAE=", - "timeCreated": "2024-08-13T21:53:02.899Z", - "updated": "2024-08-13T21:53:02.899Z", - "timeStorageClassUpdated": "2024-08-13T21:53:02.899Z", - "timeFinalized": "2024-08-13T21:53:02.899Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/426a61064914495dfd226b7c0f6df22730e41f1192a211c569c87b5473617fcc6e44df2662a233439182b852831a6237.binarypb/1728083458232616", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F426a61064914495dfd226b7c0f6df22730e41f1192a211c569c87b5473617fcc6e44df2662a233439182b852831a6237.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F426a61064914495dfd226b7c0f6df22730e41f1192a211c569c87b5473617fcc6e44df2662a233439182b852831a6237.binarypb?generation=1728083458232616&alt=media", - "name": "ovmf_x64_csm/tdx/426a61064914495dfd226b7c0f6df22730e41f1192a211c569c87b5473617fcc6e44df2662a233439182b852831a6237.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728083458232616", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", - "crc32c": "k9E9bA==", - "etag": "CKiirsXs9YgDEAE=", - "timeCreated": "2024-10-04T23:10:58.234Z", - "updated": "2024-10-04T23:10:58.234Z", - "timeStorageClassUpdated": "2024-10-04T23:10:58.234Z", - "timeFinalized": "2024-10-04T23:10:58.234Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/48a912148afd4e2d76c41d58c361523c42090fa9a8228defeee398e1d5c7f3e4f1af12a32c184db7f0baba306f71faa2.binarypb/1725637313736340", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F48a912148afd4e2d76c41d58c361523c42090fa9a8228defeee398e1d5c7f3e4f1af12a32c184db7f0baba306f71faa2.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F48a912148afd4e2d76c41d58c361523c42090fa9a8228defeee398e1d5c7f3e4f1af12a32c184db7f0baba306f71faa2.binarypb?generation=1725637313736340&alt=media", - "name": "ovmf_x64_csm/tdx/48a912148afd4e2d76c41d58c361523c42090fa9a8228defeee398e1d5c7f3e4f1af12a32c184db7f0baba306f71faa2.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1725637313736340", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5873", - "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", - "crc32c": "7PKCRw==", - "etag": "CJTd4vjTrogDEAE=", - "timeCreated": "2024-09-06T15:41:53.739Z", - "updated": "2024-09-06T15:41:53.739Z", - "timeStorageClassUpdated": "2024-09-06T15:41:53.739Z", - "timeFinalized": "2024-09-06T15:41:53.739Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/4c7805479a2e4ce42476633f697ac5158b6a9c8ea47a8e81c57bb80d282b1c68a21356de6537b0ce9f1f9aad6acd5c7f.binarypb/1728951537099216", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F4c7805479a2e4ce42476633f697ac5158b6a9c8ea47a8e81c57bb80d282b1c68a21356de6537b0ce9f1f9aad6acd5c7f.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F4c7805479a2e4ce42476633f697ac5158b6a9c8ea47a8e81c57bb80d282b1c68a21356de6537b0ce9f1f9aad6acd5c7f.binarypb?generation=1728951537099216&alt=media", - "name": "ovmf_x64_csm/tdx/4c7805479a2e4ce42476633f697ac5158b6a9c8ea47a8e81c57bb80d282b1c68a21356de6537b0ce9f1f9aad6acd5c7f.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951537099216", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CNDDz7GOj4kDEAE=", - "timeCreated": "2024-10-15T00:18:57.105Z", - "updated": "2024-10-15T00:18:57.105Z", - "timeStorageClassUpdated": "2024-10-15T00:18:57.105Z", - "timeFinalized": "2024-10-15T00:18:57.105Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/529ae548242f24cddbd0458bdf86f584530d5c18cbdc26c206dfc22fae00e431d8ee1b54f4ced3347cf555c0639f5842.binarypb/1728951527103229", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F529ae548242f24cddbd0458bdf86f584530d5c18cbdc26c206dfc22fae00e431d8ee1b54f4ced3347cf555c0639f5842.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F529ae548242f24cddbd0458bdf86f584530d5c18cbdc26c206dfc22fae00e431d8ee1b54f4ced3347cf555c0639f5842.binarypb?generation=1728951527103229&alt=media", - "name": "ovmf_x64_csm/tdx/529ae548242f24cddbd0458bdf86f584530d5c18cbdc26c206dfc22fae00e431d8ee1b54f4ced3347cf555c0639f5842.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951527103229", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CP217ayOj4kDEAE=", - "timeCreated": "2024-10-15T00:18:47.110Z", - "updated": "2024-10-15T00:18:47.110Z", - "timeStorageClassUpdated": "2024-10-15T00:18:47.110Z", - "timeFinalized": "2024-10-15T00:18:47.110Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/595e08d4588bf2cc2025784f0224d981c09a53c3c899df0516d99353b1984e2a13e7154c39c744f4949da6830f3d85dc.binarypb/1740793355286350", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F595e08d4588bf2cc2025784f0224d981c09a53c3c899df0516d99353b1984e2a13e7154c39c744f4949da6830f3d85dc.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F595e08d4588bf2cc2025784f0224d981c09a53c3c899df0516d99353b1984e2a13e7154c39c744f4949da6830f3d85dc.binarypb?generation=1740793355286350&alt=media", - "name": "ovmf_x64_csm/tdx/595e08d4588bf2cc2025784f0224d981c09a53c3c899df0516d99353b1984e2a13e7154c39c744f4949da6830f3d85dc.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1740793355286350", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "fgWKsiguSyw0G1EQeknKpg==", - "crc32c": "HdglwQ==", - "etag": "CM7uxszg54sDEAE=", - "timeCreated": "2025-03-01T01:42:35.288Z", - "updated": "2025-03-01T01:42:35.288Z", - "timeStorageClassUpdated": "2025-03-01T01:42:35.288Z", - "timeFinalized": "2025-03-01T01:42:35.288Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/5c1694ff7fa068df63ce5b4770e46d82520d6e9353e1e12ffc9ce4d6cad91c1698cc7eabd765d2c4ad519bb420228eda.binarypb/1729190359254052", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F5c1694ff7fa068df63ce5b4770e46d82520d6e9353e1e12ffc9ce4d6cad91c1698cc7eabd765d2c4ad519bb420228eda.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F5c1694ff7fa068df63ce5b4770e46d82520d6e9353e1e12ffc9ce4d6cad91c1698cc7eabd765d2c4ad519bb420228eda.binarypb?generation=1729190359254052&alt=media", - "name": "ovmf_x64_csm/tdx/5c1694ff7fa068df63ce5b4770e46d82520d6e9353e1e12ffc9ce4d6cad91c1698cc7eabd765d2c4ad519bb420228eda.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1729190359254052", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", - "crc32c": "tBQmEQ==", - "etag": "CKSI84iIlokDEAE=", - "timeCreated": "2024-10-17T18:39:19.256Z", - "updated": "2024-10-17T18:39:19.256Z", - "timeStorageClassUpdated": "2024-10-17T18:39:19.256Z", - "timeFinalized": "2024-10-17T18:39:19.256Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/5d56080eb9ef8ce0bbaf6bdcdadeeb06e7c5b0a4d1ec16be868a85a953babe0c5e54d01c8e050a54fe1ca078372530d2.binarypb/1728951525689588", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F5d56080eb9ef8ce0bbaf6bdcdadeeb06e7c5b0a4d1ec16be868a85a953babe0c5e54d01c8e050a54fe1ca078372530d2.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F5d56080eb9ef8ce0bbaf6bdcdadeeb06e7c5b0a4d1ec16be868a85a953babe0c5e54d01c8e050a54fe1ca078372530d2.binarypb?generation=1728951525689588&alt=media", - "name": "ovmf_x64_csm/tdx/5d56080eb9ef8ce0bbaf6bdcdadeeb06e7c5b0a4d1ec16be868a85a953babe0c5e54d01c8e050a54fe1ca078372530d2.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951525689588", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CPSRl6yOj4kDEAE=", - "timeCreated": "2024-10-15T00:18:45.697Z", - "updated": "2024-10-15T00:18:45.697Z", - "timeStorageClassUpdated": "2024-10-15T00:18:45.697Z", - "timeFinalized": "2024-10-15T00:18:45.697Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/68ea327ab336eaaf2b098e1f615c0ea81e9ed25ff60191dc7b420b8092c15b37033cc3624f16f67531050d4139a8c430.binarypb/1723135796804048", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F68ea327ab336eaaf2b098e1f615c0ea81e9ed25ff60191dc7b420b8092c15b37033cc3624f16f67531050d4139a8c430.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F68ea327ab336eaaf2b098e1f615c0ea81e9ed25ff60191dc7b420b8092c15b37033cc3624f16f67531050d4139a8c430.binarypb?generation=1723135796804048&alt=media", - "name": "ovmf_x64_csm/tdx/68ea327ab336eaaf2b098e1f615c0ea81e9ed25ff60191dc7b420b8092c15b37033cc3624f16f67531050d4139a8c430.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723135796804048", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5866", - "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", - "crc32c": "Twn57g==", - "etag": "CNDzxYjt5YcDEAE=", - "timeCreated": "2024-08-08T16:49:56.806Z", - "updated": "2024-08-08T16:49:56.806Z", - "timeStorageClassUpdated": "2024-08-08T16:49:56.806Z", - "timeFinalized": "2024-08-08T16:49:56.806Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/75a0d99a260dadb89b304679e9dd06862c96445c507c149cf68be8555fe41eccfa62410a87513e697117e23e36bcd6d8.binarypb/1719876445557516", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F75a0d99a260dadb89b304679e9dd06862c96445c507c149cf68be8555fe41eccfa62410a87513e697117e23e36bcd6d8.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F75a0d99a260dadb89b304679e9dd06862c96445c507c149cf68be8555fe41eccfa62410a87513e697117e23e36bcd6d8.binarypb?generation=1719876445557516&alt=media", - "name": "ovmf_x64_csm/tdx/75a0d99a260dadb89b304679e9dd06862c96445c507c149cf68be8555fe41eccfa62410a87513e697117e23e36bcd6d8.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1719876445557516", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5865", - "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", - "crc32c": "s0O/hw==", - "etag": "CIym4YT/hocDEAE=", - "timeCreated": "2024-07-01T23:27:25.558Z", - "updated": "2024-07-01T23:27:25.558Z", - "timeStorageClassUpdated": "2024-07-01T23:27:25.558Z", - "timeFinalized": "2024-07-01T23:27:25.558Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/77289bc22606e62b1e69c6222579871eba45eb03b818ad8843ccc490a22317bd220d4baea16a978f3b42a74b349bb6e5.binarypb/1731450148717872", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F77289bc22606e62b1e69c6222579871eba45eb03b818ad8843ccc490a22317bd220d4baea16a978f3b42a74b349bb6e5.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F77289bc22606e62b1e69c6222579871eba45eb03b818ad8843ccc490a22317bd220d4baea16a978f3b42a74b349bb6e5.binarypb?generation=1731450148717872&alt=media", - "name": "ovmf_x64_csm/tdx/77289bc22606e62b1e69c6222579871eba45eb03b818ad8843ccc490a22317bd220d4baea16a978f3b42a74b349bb6e5.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1731450148717872", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5254", - "md5Hash": "s5qFLCU//T5J47AqVLhJCQ==", - "crc32c": "21rV/g==", - "etag": "CLCKvrjq14kDEAE=", - "timeCreated": "2024-11-12T22:22:28.719Z", - "updated": "2024-11-12T22:22:28.719Z", - "timeStorageClassUpdated": "2024-11-12T22:22:28.719Z", - "timeFinalized": "2024-11-12T22:22:28.719Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/78a7533e575b476151ab32b3a8242117a53083d132ac3f35396b18a114fe714c9bac17db4a8d84e976f8c98d98d91a5d.binarypb/1749578071858434", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F78a7533e575b476151ab32b3a8242117a53083d132ac3f35396b18a114fe714c9bac17db4a8d84e976f8c98d98d91a5d.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F78a7533e575b476151ab32b3a8242117a53083d132ac3f35396b18a114fe714c9bac17db4a8d84e976f8c98d98d91a5d.binarypb?generation=1749578071858434&alt=media", - "name": "ovmf_x64_csm/tdx/78a7533e575b476151ab32b3a8242117a53083d132ac3f35396b18a114fe714c9bac17db4a8d84e976f8c98d98d91a5d.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1749578071858434", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "Gq3ztyZD1ivm75QPcS9cpw==", - "crc32c": "cUxfSQ==", - "etag": "CIK665u2540DEAE=", - "timeCreated": "2025-06-10T17:54:31.861Z", - "updated": "2025-06-10T17:54:31.861Z", - "timeStorageClassUpdated": "2025-06-10T17:54:31.861Z", - "timeFinalized": "2025-06-10T17:54:31.861Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/7a2177d9da9e2bce3ef91c143667ea72fe72b021e3b0c5736eb96cffefa5fa8fa4fec923e8f8cfac1298e4f1d94ce774.binarypb/1729190354504872", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F7a2177d9da9e2bce3ef91c143667ea72fe72b021e3b0c5736eb96cffefa5fa8fa4fec923e8f8cfac1298e4f1d94ce774.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F7a2177d9da9e2bce3ef91c143667ea72fe72b021e3b0c5736eb96cffefa5fa8fa4fec923e8f8cfac1298e4f1d94ce774.binarypb?generation=1729190354504872&alt=media", - "name": "ovmf_x64_csm/tdx/7a2177d9da9e2bce3ef91c143667ea72fe72b021e3b0c5736eb96cffefa5fa8fa4fec923e8f8cfac1298e4f1d94ce774.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1729190354504872", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", - "crc32c": "tBQmEQ==", - "etag": "CKiZ0YaIlokDEAE=", - "timeCreated": "2024-10-17T18:39:14.506Z", - "updated": "2024-10-17T18:39:14.506Z", - "timeStorageClassUpdated": "2024-10-17T18:39:14.506Z", - "timeFinalized": "2024-10-17T18:39:14.506Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/7df7195f7887de96bca9f57853657d28e58c40d6aaa4a87626bb32a5c8eb6a190606051d96214b91d076db3ffe396f37.binarypb/1750808594502977", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F7df7195f7887de96bca9f57853657d28e58c40d6aaa4a87626bb32a5c8eb6a190606051d96214b91d076db3ffe396f37.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F7df7195f7887de96bca9f57853657d28e58c40d6aaa4a87626bb32a5c8eb6a190606051d96214b91d076db3ffe396f37.binarypb?generation=1750808594502977&alt=media", - "name": "ovmf_x64_csm/tdx/7df7195f7887de96bca9f57853657d28e58c40d6aaa4a87626bb32a5c8eb6a190606051d96214b91d076db3ffe396f37.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1750808594502977", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "IGzKhCp3aHzUfiH9xKSr2A==", - "crc32c": "8dZRgQ==", - "etag": "CMGq4aKei44DEAE=", - "timeCreated": "2025-06-24T23:43:14.505Z", - "updated": "2025-06-24T23:43:14.505Z", - "timeStorageClassUpdated": "2025-06-24T23:43:14.505Z", - "timeFinalized": "2025-06-24T23:43:14.505Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/8370d8f6d02f2d13e211e91c93fde923049522b241425a29a7bf0071ef49b250af4ef49d852fa3e10065d1b51dfce8fb.binarypb/1763582372027922", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8370d8f6d02f2d13e211e91c93fde923049522b241425a29a7bf0071ef49b250af4ef49d852fa3e10065d1b51dfce8fb.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8370d8f6d02f2d13e211e91c93fde923049522b241425a29a7bf0071ef49b250af4ef49d852fa3e10065d1b51dfce8fb.binarypb?generation=1763582372027922&alt=media", - "name": "ovmf_x64_csm/tdx/8370d8f6d02f2d13e211e91c93fde923049522b241425a29a7bf0071ef49b250af4ef49d852fa3e10065d1b51dfce8fb.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1763582372027922", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "Mo521eXHGQ7WGdaawVWxMg==", - "crc32c": "iS84kw==", - "etag": "CJK8xKaA/5ADEAE=", - "timeCreated": "2025-11-19T19:59:32.031Z", - "updated": "2025-11-19T19:59:32.031Z", - "timeStorageClassUpdated": "2025-11-19T19:59:32.031Z", - "timeFinalized": "2025-11-19T19:59:32.031Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/887114d8385e95d306873a404297b7abed97a6a958cf672fb55b5230fa7e008a23a31c90325fed1161a62ee6718fbc8b.binarypb/1728083463190652", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F887114d8385e95d306873a404297b7abed97a6a958cf672fb55b5230fa7e008a23a31c90325fed1161a62ee6718fbc8b.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F887114d8385e95d306873a404297b7abed97a6a958cf672fb55b5230fa7e008a23a31c90325fed1161a62ee6718fbc8b.binarypb?generation=1728083463190652&alt=media", - "name": "ovmf_x64_csm/tdx/887114d8385e95d306873a404297b7abed97a6a958cf672fb55b5230fa7e008a23a31c90325fed1161a62ee6718fbc8b.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728083463190652", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", - "crc32c": "k9E9bA==", - "etag": "CPzw3Mfs9YgDEAE=", - "timeCreated": "2024-10-04T23:11:03.192Z", - "updated": "2024-10-04T23:11:03.192Z", - "timeStorageClassUpdated": "2024-10-04T23:11:03.192Z", - "timeFinalized": "2024-10-04T23:11:03.192Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/892a196239dfcd522bfce14f30fc06ac1eb82ac87b3d1593fcb9a6e389b398af6fb0b9e4b8b4d294317cc2976459fbc2.binarypb/1729190364834406", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F892a196239dfcd522bfce14f30fc06ac1eb82ac87b3d1593fcb9a6e389b398af6fb0b9e4b8b4d294317cc2976459fbc2.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F892a196239dfcd522bfce14f30fc06ac1eb82ac87b3d1593fcb9a6e389b398af6fb0b9e4b8b4d294317cc2976459fbc2.binarypb?generation=1729190364834406&alt=media", - "name": "ovmf_x64_csm/tdx/892a196239dfcd522bfce14f30fc06ac1eb82ac87b3d1593fcb9a6e389b398af6fb0b9e4b8b4d294317cc2976459fbc2.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1729190364834406", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", - "crc32c": "tBQmEQ==", - "etag": "CObUx4uIlokDEAE=", - "timeCreated": "2024-10-17T18:39:24.836Z", - "updated": "2024-10-17T18:39:24.836Z", - "timeStorageClassUpdated": "2024-10-17T18:39:24.836Z", - "timeFinalized": "2024-10-17T18:39:24.836Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/89ec252df6a6975adee91d17b3e8715955bf86252e33fbbbcca0b157c4402d886447c9d97d0cce9395bb1697bfd2208e.binarypb/1723135790538500", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F89ec252df6a6975adee91d17b3e8715955bf86252e33fbbbcca0b157c4402d886447c9d97d0cce9395bb1697bfd2208e.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F89ec252df6a6975adee91d17b3e8715955bf86252e33fbbbcca0b157c4402d886447c9d97d0cce9395bb1697bfd2208e.binarypb?generation=1723135790538500&alt=media", - "name": "ovmf_x64_csm/tdx/89ec252df6a6975adee91d17b3e8715955bf86252e33fbbbcca0b157c4402d886447c9d97d0cce9395bb1697bfd2208e.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723135790538500", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5866", - "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", - "crc32c": "Twn57g==", - "etag": "CIS+x4Xt5YcDEAE=", - "timeCreated": "2024-08-08T16:49:50.541Z", - "updated": "2024-08-08T16:49:50.541Z", - "timeStorageClassUpdated": "2024-08-08T16:49:50.541Z", - "timeFinalized": "2024-08-08T16:49:50.541Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/8a3130eef765be2391813d4fce7ea36e489f3838ffdccc479b75fb4146c32017f379589be69e33f9b3186cea221a2abb.binarypb/1719876444430165", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8a3130eef765be2391813d4fce7ea36e489f3838ffdccc479b75fb4146c32017f379589be69e33f9b3186cea221a2abb.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8a3130eef765be2391813d4fce7ea36e489f3838ffdccc479b75fb4146c32017f379589be69e33f9b3186cea221a2abb.binarypb?generation=1719876444430165&alt=media", - "name": "ovmf_x64_csm/tdx/8a3130eef765be2391813d4fce7ea36e489f3838ffdccc479b75fb4146c32017f379589be69e33f9b3186cea221a2abb.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1719876444430165", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5865", - "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", - "crc32c": "s0O/hw==", - "etag": "CNW+nIT/hocDEAE=", - "timeCreated": "2024-07-01T23:27:24.431Z", - "updated": "2024-07-01T23:27:24.431Z", - "timeStorageClassUpdated": "2024-07-01T23:27:24.431Z", - "timeFinalized": "2024-07-01T23:27:24.431Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/8a8e2f21714da855b219bd2724a86c1ac7e46e8a84b0f34fad9e84dd46ef9bc92f0ca95eda8ff629246e4aa9a72c625c.binarypb/1776213910413410", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8a8e2f21714da855b219bd2724a86c1ac7e46e8a84b0f34fad9e84dd46ef9bc92f0ca95eda8ff629246e4aa9a72c625c.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F8a8e2f21714da855b219bd2724a86c1ac7e46e8a84b0f34fad9e84dd46ef9bc92f0ca95eda8ff629246e4aa9a72c625c.binarypb?generation=1776213910413410&alt=media", - "name": "ovmf_x64_csm/tdx/8a8e2f21714da855b219bd2724a86c1ac7e46e8a84b0f34fad9e84dd46ef9bc92f0ca95eda8ff629246e4aa9a72c625c.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1776213910413410", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "trnuInXRcG8FrhS6X5rRGw==", - "crc32c": "T2B4LA==", - "etag": "COLAs7nQ7pMDEAE=", - "timeCreated": "2026-04-15T00:45:10.415Z", - "updated": "2026-04-15T00:45:10.415Z", - "timeStorageClassUpdated": "2026-04-15T00:45:10.415Z", - "timeFinalized": "2026-04-15T00:45:10.415Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/9573810ddf0977c9005f6df9819c3a78e27d4b5a91777d86bb8d67b9c4344cc4d825c26a216d88b9d35e71e77a0700e3.binarypb/1723585978633920", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9573810ddf0977c9005f6df9819c3a78e27d4b5a91777d86bb8d67b9c4344cc4d825c26a216d88b9d35e71e77a0700e3.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9573810ddf0977c9005f6df9819c3a78e27d4b5a91777d86bb8d67b9c4344cc4d825c26a216d88b9d35e71e77a0700e3.binarypb?generation=1723585978633920&alt=media", - "name": "ovmf_x64_csm/tdx/9573810ddf0977c9005f6df9819c3a78e27d4b5a91777d86bb8d67b9c4344cc4d825c26a216d88b9d35e71e77a0700e3.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723585978633920", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5868", - "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", - "crc32c": "YXklrg==", - "etag": "CMCd/I/68ocDEAE=", - "timeCreated": "2024-08-13T21:52:58.637Z", - "updated": "2024-08-13T21:52:58.637Z", - "timeStorageClassUpdated": "2024-08-13T21:52:58.637Z", - "timeFinalized": "2024-08-13T21:52:58.637Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/9757d231b4ad47d683531226f5a5a78266c0abb91e2b9b90138f03719ca32bb0719844be145b5a09dd1a058a9e17fd04.binarypb/1719876463677441", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9757d231b4ad47d683531226f5a5a78266c0abb91e2b9b90138f03719ca32bb0719844be145b5a09dd1a058a9e17fd04.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9757d231b4ad47d683531226f5a5a78266c0abb91e2b9b90138f03719ca32bb0719844be145b5a09dd1a058a9e17fd04.binarypb?generation=1719876463677441&alt=media", - "name": "ovmf_x64_csm/tdx/9757d231b4ad47d683531226f5a5a78266c0abb91e2b9b90138f03719ca32bb0719844be145b5a09dd1a058a9e17fd04.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1719876463677441", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5865", - "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", - "crc32c": "s0O/hw==", - "etag": "CIGgs43/hocDEAE=", - "timeCreated": "2024-07-01T23:27:43.679Z", - "updated": "2024-07-01T23:27:43.679Z", - "timeStorageClassUpdated": "2024-07-01T23:27:43.679Z", - "timeFinalized": "2024-07-01T23:27:43.679Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/9bf86e6280ec4282b8b5822d8166410a456cdb720109aa799f0011fa63df1de3ee5e35e293fc410c061433163acb03a6.binarypb/1777588963392969", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9bf86e6280ec4282b8b5822d8166410a456cdb720109aa799f0011fa63df1de3ee5e35e293fc410c061433163acb03a6.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9bf86e6280ec4282b8b5822d8166410a456cdb720109aa799f0011fa63df1de3ee5e35e293fc410c061433163acb03a6.binarypb?generation=1777588963392969&alt=media", - "name": "ovmf_x64_csm/tdx/9bf86e6280ec4282b8b5822d8166410a456cdb720109aa799f0011fa63df1de3ee5e35e293fc410c061433163acb03a6.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1777588963392969", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "IrkChk2+BtTiml23TmjvgQ==", - "crc32c": "nnnqsQ==", - "etag": "CMn74PXSlpQDEAE=", - "timeCreated": "2026-04-30T22:42:43.395Z", - "updated": "2026-04-30T22:42:43.395Z", - "timeStorageClassUpdated": "2026-04-30T22:42:43.395Z", - "timeFinalized": "2026-04-30T22:42:43.395Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/9d00db2fc7cd2a891b83975862cf932d7cfbb4f6ef884a8d7be89be8fc10061b1fbaf49361986cdfa628f339b07e4605.binarypb/1728951534222594", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9d00db2fc7cd2a891b83975862cf932d7cfbb4f6ef884a8d7be89be8fc10061b1fbaf49361986cdfa628f339b07e4605.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2F9d00db2fc7cd2a891b83975862cf932d7cfbb4f6ef884a8d7be89be8fc10061b1fbaf49361986cdfa628f339b07e4605.binarypb?generation=1728951534222594&alt=media", - "name": "ovmf_x64_csm/tdx/9d00db2fc7cd2a891b83975862cf932d7cfbb4f6ef884a8d7be89be8fc10061b1fbaf49361986cdfa628f339b07e4605.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951534222594", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CIL6n7COj4kDEAE=", - "timeCreated": "2024-10-15T00:18:54.229Z", - "updated": "2024-10-15T00:18:54.229Z", - "timeStorageClassUpdated": "2024-10-15T00:18:54.229Z", - "timeFinalized": "2024-10-15T00:18:54.229Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a039f3af42d6a9e3723d04459f69d3b931a7bba2e18bdeb85d093327497af15dc16e1741df53154b685869d8ef8e79a4.binarypb/1726777920401985", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa039f3af42d6a9e3723d04459f69d3b931a7bba2e18bdeb85d093327497af15dc16e1741df53154b685869d8ef8e79a4.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa039f3af42d6a9e3723d04459f69d3b931a7bba2e18bdeb85d093327497af15dc16e1741df53154b685869d8ef8e79a4.binarypb?generation=1726777920401985&alt=media", - "name": "ovmf_x64_csm/tdx/a039f3af42d6a9e3723d04459f69d3b931a7bba2e18bdeb85d093327497af15dc16e1741df53154b685869d8ef8e79a4.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1726777920401985", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5868", - "md5Hash": "q8QrsAgVMc9+mN0gFv+2CA==", - "crc32c": "x1hIgw==", - "etag": "CMHktITtz4gDEAE=", - "timeCreated": "2024-09-19T20:32:00.404Z", - "updated": "2024-09-19T20:32:00.404Z", - "timeStorageClassUpdated": "2024-09-19T20:32:00.404Z", - "timeFinalized": "2024-09-19T20:32:00.404Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a0b4244c2077c88dd5bc3dc81c27775ea8edb4816961c2bc2eef59d700d380408fb49159e75376a6f051b0e4d32501e3.binarypb/1723135791590331", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa0b4244c2077c88dd5bc3dc81c27775ea8edb4816961c2bc2eef59d700d380408fb49159e75376a6f051b0e4d32501e3.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa0b4244c2077c88dd5bc3dc81c27775ea8edb4816961c2bc2eef59d700d380408fb49159e75376a6f051b0e4d32501e3.binarypb?generation=1723135791590331&alt=media", - "name": "ovmf_x64_csm/tdx/a0b4244c2077c88dd5bc3dc81c27775ea8edb4816961c2bc2eef59d700d380408fb49159e75376a6f051b0e4d32501e3.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723135791590331", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5866", - "md5Hash": "KWZYD5mI9E9GCWxm7RXakg==", - "crc32c": "Twn57g==", - "etag": "CLvXh4bt5YcDEAE=", - "timeCreated": "2024-08-08T16:49:51.592Z", - "updated": "2024-08-08T16:49:51.592Z", - "timeStorageClassUpdated": "2024-08-08T16:49:51.592Z", - "timeFinalized": "2024-08-08T16:49:51.592Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a22b871065d0387385c5e96dbf4356053b30eb76de061924b1d7b92c66f4d963fca88fe337408903481cf1b3480051f0.binarypb/1771959199837360", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa22b871065d0387385c5e96dbf4356053b30eb76de061924b1d7b92c66f4d963fca88fe337408903481cf1b3480051f0.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa22b871065d0387385c5e96dbf4356053b30eb76de061924b1d7b92c66f4d963fca88fe337408903481cf1b3480051f0.binarypb?generation=1771959199837360&alt=media", - "name": "ovmf_x64_csm/tdx/a22b871065d0387385c5e96dbf4356053b30eb76de061924b1d7b92c66f4d963fca88fe337408903481cf1b3480051f0.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1771959199837360", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "vjL6Yo3OJTShQWXp1hIX9g==", - "crc32c": "zTfjdA==", - "etag": "CLDZprXm8pIDEAE=", - "timeCreated": "2026-02-24T18:53:19.839Z", - "updated": "2026-02-24T18:53:19.839Z", - "timeStorageClassUpdated": "2026-02-24T18:53:19.839Z", - "timeFinalized": "2026-02-24T18:53:19.839Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a5844e88897b70c318bef929ef4dfd6c7304c52c4bc9c3f39132f0fdccecf3eb5bab70110ee42a12509a31c037288694.binarypb/1756507826221876", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa5844e88897b70c318bef929ef4dfd6c7304c52c4bc9c3f39132f0fdccecf3eb5bab70110ee42a12509a31c037288694.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa5844e88897b70c318bef929ef4dfd6c7304c52c4bc9c3f39132f0fdccecf3eb5bab70110ee42a12509a31c037288694.binarypb?generation=1756507826221876&alt=media", - "name": "ovmf_x64_csm/tdx/a5844e88897b70c318bef929ef4dfd6c7304c52c4bc9c3f39132f0fdccecf3eb5bab70110ee42a12509a31c037288694.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1756507826221876", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "BLyQeUKe9BZObADiz9vOQA==", - "crc32c": "jNZWFQ==", - "etag": "CLTmm8iNsY8DEAE=", - "timeCreated": "2025-08-29T22:50:26.224Z", - "updated": "2025-08-29T22:50:26.224Z", - "timeStorageClassUpdated": "2025-08-29T22:50:26.224Z", - "timeFinalized": "2025-08-29T22:50:26.224Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/a91197faa4b8b2b757cafa9cfebc761f22d64c1d1bddcac2e79ba6cccb393f6af4504956e00ea15af5689d76050d90b2.binarypb/1744656913825170", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa91197faa4b8b2b757cafa9cfebc761f22d64c1d1bddcac2e79ba6cccb393f6af4504956e00ea15af5689d76050d90b2.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fa91197faa4b8b2b757cafa9cfebc761f22d64c1d1bddcac2e79ba6cccb393f6af4504956e00ea15af5689d76050d90b2.binarypb?generation=1744656913825170&alt=media", - "name": "ovmf_x64_csm/tdx/a91197faa4b8b2b757cafa9cfebc761f22d64c1d1bddcac2e79ba6cccb393f6af4504956e00ea15af5689d76050d90b2.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1744656913825170", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "pl9ijrUMVt0Z6JjV1dZIfA==", - "crc32c": "xgeP0A==", - "etag": "CJL76byZ2IwDEAE=", - "timeCreated": "2025-04-14T18:55:13.827Z", - "updated": "2025-04-14T18:55:13.827Z", - "timeStorageClassUpdated": "2025-04-14T18:55:13.827Z", - "timeFinalized": "2025-04-14T18:55:13.827Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ab65652bbe0e62c5efdda5d8f1f768d5e91210afbbec31635deaeca84e7cc958e15ed22b80b6c13fa04b8b040c2a7b24.binarypb/1728951538509376", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fab65652bbe0e62c5efdda5d8f1f768d5e91210afbbec31635deaeca84e7cc958e15ed22b80b6c13fa04b8b040c2a7b24.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fab65652bbe0e62c5efdda5d8f1f768d5e91210afbbec31635deaeca84e7cc958e15ed22b80b6c13fa04b8b040c2a7b24.binarypb?generation=1728951538509376&alt=media", - "name": "ovmf_x64_csm/tdx/ab65652bbe0e62c5efdda5d8f1f768d5e91210afbbec31635deaeca84e7cc958e15ed22b80b6c13fa04b8b040c2a7b24.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951538509376", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CMDMpbKOj4kDEAE=", - "timeCreated": "2024-10-15T00:18:58.515Z", - "updated": "2024-10-15T00:18:58.515Z", - "timeStorageClassUpdated": "2024-10-15T00:18:58.515Z", - "timeFinalized": "2024-10-15T00:18:58.515Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ae21a81e228b5f814d13226f3ee7fb1215f3127316c13bff13c7f0aff22817afee450af0f6f2f80a42ef0ac9014c8dda.binarypb/1755553674945403", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fae21a81e228b5f814d13226f3ee7fb1215f3127316c13bff13c7f0aff22817afee450af0f6f2f80a42ef0ac9014c8dda.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fae21a81e228b5f814d13226f3ee7fb1215f3127316c13bff13c7f0aff22817afee450af0f6f2f80a42ef0ac9014c8dda.binarypb?generation=1755553674945403&alt=media", - "name": "ovmf_x64_csm/tdx/ae21a81e228b5f814d13226f3ee7fb1215f3127316c13bff13c7f0aff22817afee450af0f6f2f80a42ef0ac9014c8dda.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1755553674945403", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5307", - "md5Hash": "Y4O/USh86ewtt+ay85ShRg==", - "crc32c": "INGxXA==", - "etag": "CPvGt4mrlY8DEAE=", - "timeCreated": "2025-08-18T21:47:54.947Z", - "updated": "2025-08-18T21:47:54.947Z", - "timeStorageClassUpdated": "2025-08-18T21:47:54.947Z", - "timeFinalized": "2025-08-18T21:47:54.947Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ae270b1da076629433c4889782c33ada1f886d38f2c0de401698143a50f05252469d2272bc4fd7bb779c19d37440d047.binarypb/1729190353326042", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fae270b1da076629433c4889782c33ada1f886d38f2c0de401698143a50f05252469d2272bc4fd7bb779c19d37440d047.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fae270b1da076629433c4889782c33ada1f886d38f2c0de401698143a50f05252469d2272bc4fd7bb779c19d37440d047.binarypb?generation=1729190353326042&alt=media", - "name": "ovmf_x64_csm/tdx/ae270b1da076629433c4889782c33ada1f886d38f2c0de401698143a50f05252469d2272bc4fd7bb779c19d37440d047.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1729190353326042", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", - "crc32c": "tBQmEQ==", - "etag": "CNqfiYaIlokDEAE=", - "timeCreated": "2024-10-17T18:39:13.328Z", - "updated": "2024-10-17T18:39:13.328Z", - "timeStorageClassUpdated": "2024-10-17T18:39:13.328Z", - "timeFinalized": "2024-10-17T18:39:13.328Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/afbac113d5458025dbf33e8a5e6f82214886e1f2180ebd7c4acf8e0d6a0e2d0843bfcd9b1638d2bbd3e2e31ab98fd976.binarypb/1725637320046126", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fafbac113d5458025dbf33e8a5e6f82214886e1f2180ebd7c4acf8e0d6a0e2d0843bfcd9b1638d2bbd3e2e31ab98fd976.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fafbac113d5458025dbf33e8a5e6f82214886e1f2180ebd7c4acf8e0d6a0e2d0843bfcd9b1638d2bbd3e2e31ab98fd976.binarypb?generation=1725637320046126&alt=media", - "name": "ovmf_x64_csm/tdx/afbac113d5458025dbf33e8a5e6f82214886e1f2180ebd7c4acf8e0d6a0e2d0843bfcd9b1638d2bbd3e2e31ab98fd976.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1725637320046126", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5873", - "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", - "crc32c": "7PKCRw==", - "etag": "CK7s4/vTrogDEAE=", - "timeCreated": "2024-09-06T15:42:00.048Z", - "updated": "2024-09-06T15:42:00.048Z", - "timeStorageClassUpdated": "2024-09-06T15:42:00.048Z", - "timeFinalized": "2024-09-06T15:42:00.048Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/b3054b3fefdcff8d1e6f9a1aad2252ff01438075ded8083a1900956c3e73442f519cdddb5a1537d649a3d129f165c1df.binarypb/1773135059690086", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fb3054b3fefdcff8d1e6f9a1aad2252ff01438075ded8083a1900956c3e73442f519cdddb5a1537d649a3d129f165c1df.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fb3054b3fefdcff8d1e6f9a1aad2252ff01438075ded8083a1900956c3e73442f519cdddb5a1537d649a3d129f165c1df.binarypb?generation=1773135059690086&alt=media", - "name": "ovmf_x64_csm/tdx/b3054b3fefdcff8d1e6f9a1aad2252ff01438075ded8083a1900956c3e73442f519cdddb5a1537d649a3d129f165c1df.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1773135059690086", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "016Rlc8dl6AAzdWvkNCmqg==", - "crc32c": "MXKRQg==", - "etag": "CObE/OqClZMDEAE=", - "timeCreated": "2026-03-10T09:30:59.692Z", - "updated": "2026-03-10T09:30:59.692Z", - "timeStorageClassUpdated": "2026-03-10T09:30:59.692Z", - "timeFinalized": "2026-03-10T09:30:59.692Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ba128a84597c3c048f1c3c52d68634d9ccad4120a87b81ad40aca008b219ec1bdb4401470c8dc696d728c4507edd8611.binarypb/1728951524287910", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fba128a84597c3c048f1c3c52d68634d9ccad4120a87b81ad40aca008b219ec1bdb4401470c8dc696d728c4507edd8611.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fba128a84597c3c048f1c3c52d68634d9ccad4120a87b81ad40aca008b219ec1bdb4401470c8dc696d728c4507edd8611.binarypb?generation=1728951524287910&alt=media", - "name": "ovmf_x64_csm/tdx/ba128a84597c3c048f1c3c52d68634d9ccad4120a87b81ad40aca008b219ec1bdb4401470c8dc696d728c4507edd8611.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951524287910", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CKbLwauOj4kDEAE=", - "timeCreated": "2024-10-15T00:18:44.294Z", - "updated": "2024-10-15T00:18:44.294Z", - "timeStorageClassUpdated": "2024-10-15T00:18:44.294Z", - "timeFinalized": "2024-10-15T00:18:44.294Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/bf75843e2e234a1e6e1df6942bbdae9100411299e54f64a10ea9b48b97453c671973fbc801f9511d3148f861d9094923.binarypb/1728083449469071", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fbf75843e2e234a1e6e1df6942bbdae9100411299e54f64a10ea9b48b97453c671973fbc801f9511d3148f861d9094923.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fbf75843e2e234a1e6e1df6942bbdae9100411299e54f64a10ea9b48b97453c671973fbc801f9511d3148f861d9094923.binarypb?generation=1728083449469071&alt=media", - "name": "ovmf_x64_csm/tdx/bf75843e2e234a1e6e1df6942bbdae9100411299e54f64a10ea9b48b97453c671973fbc801f9511d3148f861d9094923.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728083449469071", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", - "crc32c": "k9E9bA==", - "etag": "CI+xl8Hs9YgDEAE=", - "timeCreated": "2024-10-04T23:10:49.470Z", - "updated": "2024-10-04T23:10:49.470Z", - "timeStorageClassUpdated": "2024-10-04T23:10:49.470Z", - "timeFinalized": "2024-10-04T23:10:49.470Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/c1850db0d5f5541a65866619dd4933f743815c606b269063e8b8424effe3ac7256d56331f2ed0dc66641fbdf10d3f21e.binarypb/1729190360578137", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc1850db0d5f5541a65866619dd4933f743815c606b269063e8b8424effe3ac7256d56331f2ed0dc66641fbdf10d3f21e.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc1850db0d5f5541a65866619dd4933f743815c606b269063e8b8424effe3ac7256d56331f2ed0dc66641fbdf10d3f21e.binarypb?generation=1729190360578137&alt=media", - "name": "ovmf_x64_csm/tdx/c1850db0d5f5541a65866619dd4933f743815c606b269063e8b8424effe3ac7256d56331f2ed0dc66641fbdf10d3f21e.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1729190360578137", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", - "crc32c": "tBQmEQ==", - "etag": "CNnww4mIlokDEAE=", - "timeCreated": "2024-10-17T18:39:20.579Z", - "updated": "2024-10-17T18:39:20.579Z", - "timeStorageClassUpdated": "2024-10-17T18:39:20.579Z", - "timeFinalized": "2024-10-17T18:39:20.579Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/c5bf87009d9aaeb2a40633710b2edab43c0b0b8cbe5a036fa45b1057e7086b0726711d0c78ed5859f12b0d76978df03c.binarypb/1753835243259865", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc5bf87009d9aaeb2a40633710b2edab43c0b0b8cbe5a036fa45b1057e7086b0726711d0c78ed5859f12b0d76978df03c.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc5bf87009d9aaeb2a40633710b2edab43c0b0b8cbe5a036fa45b1057e7086b0726711d0c78ed5859f12b0d76978df03c.binarypb?generation=1753835243259865&alt=media", - "name": "ovmf_x64_csm/tdx/c5bf87009d9aaeb2a40633710b2edab43c0b0b8cbe5a036fa45b1057e7086b0726711d0c78ed5859f12b0d76978df03c.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1753835243259865", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "GqA+IanJ1aFneQLroTIHJw==", - "crc32c": "uXG6tw==", - "etag": "CNmPrbWp444DEAE=", - "timeCreated": "2025-07-30T00:27:23.262Z", - "updated": "2025-07-30T00:27:23.262Z", - "timeStorageClassUpdated": "2025-07-30T00:27:23.262Z", - "timeFinalized": "2025-07-30T00:27:23.262Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/c75e360b2d1da4456a9113d6549f6ed9b26145526bc15eb67371238c8d35aff5d174ecaf775483f5a3cfc603e359d5cc.binarypb/1719876454565396", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc75e360b2d1da4456a9113d6549f6ed9b26145526bc15eb67371238c8d35aff5d174ecaf775483f5a3cfc603e359d5cc.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fc75e360b2d1da4456a9113d6549f6ed9b26145526bc15eb67371238c8d35aff5d174ecaf775483f5a3cfc603e359d5cc.binarypb?generation=1719876454565396&alt=media", - "name": "ovmf_x64_csm/tdx/c75e360b2d1da4456a9113d6549f6ed9b26145526bc15eb67371238c8d35aff5d174ecaf775483f5a3cfc603e359d5cc.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1719876454565396", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5865", - "md5Hash": "WpNMjqeuwVY3MpYiYiW9vQ==", - "crc32c": "s0O/hw==", - "etag": "CJSMh4n/hocDEAE=", - "timeCreated": "2024-07-01T23:27:34.567Z", - "updated": "2024-07-01T23:27:34.567Z", - "timeStorageClassUpdated": "2024-07-01T23:27:34.567Z", - "timeFinalized": "2024-07-01T23:27:34.567Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/ca514dc8e47040b4601fba79c5eba9339097171dbe988f29995f9d9185a25ba8e524924d65c1730db4782e32505509ce.binarypb/1728083450440402", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fca514dc8e47040b4601fba79c5eba9339097171dbe988f29995f9d9185a25ba8e524924d65c1730db4782e32505509ce.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fca514dc8e47040b4601fba79c5eba9339097171dbe988f29995f9d9185a25ba8e524924d65c1730db4782e32505509ce.binarypb?generation=1728083450440402&alt=media", - "name": "ovmf_x64_csm/tdx/ca514dc8e47040b4601fba79c5eba9339097171dbe988f29995f9d9185a25ba8e524924d65c1730db4782e32505509ce.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728083450440402", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", - "crc32c": "k9E9bA==", - "etag": "CNLV0sHs9YgDEAE=", - "timeCreated": "2024-10-04T23:10:50.442Z", - "updated": "2024-10-04T23:10:50.442Z", - "timeStorageClassUpdated": "2024-10-04T23:10:50.442Z", - "timeFinalized": "2024-10-04T23:10:50.442Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/cee0cff377192351bdba46457b512820e1f23d6843d77d14f23f30000086321fd15a52c7afc8ff79d63f8a341a1140b3.binarypb/1728951535641925", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fcee0cff377192351bdba46457b512820e1f23d6843d77d14f23f30000086321fd15a52c7afc8ff79d63f8a341a1140b3.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fcee0cff377192351bdba46457b512820e1f23d6843d77d14f23f30000086321fd15a52c7afc8ff79d63f8a341a1140b3.binarypb?generation=1728951535641925&alt=media", - "name": "ovmf_x64_csm/tdx/cee0cff377192351bdba46457b512820e1f23d6843d77d14f23f30000086321fd15a52c7afc8ff79d63f8a341a1140b3.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951535641925", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CMXK9rCOj4kDEAE=", - "timeCreated": "2024-10-15T00:18:55.649Z", - "updated": "2024-10-15T00:18:55.649Z", - "timeStorageClassUpdated": "2024-10-15T00:18:55.649Z", - "timeFinalized": "2024-10-15T00:18:55.649Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/d904fd4a5bcae8a1db29f21c2674474536e8c73e22591ab92dd01ddecf6bf1c8366163598e5587acdd6fe30b50ac43cc.binarypb/1725637325268290", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fd904fd4a5bcae8a1db29f21c2674474536e8c73e22591ab92dd01ddecf6bf1c8366163598e5587acdd6fe30b50ac43cc.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fd904fd4a5bcae8a1db29f21c2674474536e8c73e22591ab92dd01ddecf6bf1c8366163598e5587acdd6fe30b50ac43cc.binarypb?generation=1725637325268290&alt=media", - "name": "ovmf_x64_csm/tdx/d904fd4a5bcae8a1db29f21c2674474536e8c73e22591ab92dd01ddecf6bf1c8366163598e5587acdd6fe30b50ac43cc.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1725637325268290", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5873", - "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", - "crc32c": "7PKCRw==", - "etag": "CMLKov7TrogDEAE=", - "timeCreated": "2024-09-06T15:42:05.270Z", - "updated": "2024-09-06T15:42:05.270Z", - "timeStorageClassUpdated": "2024-09-06T15:42:05.270Z", - "timeFinalized": "2024-09-06T15:42:05.270Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/dab01619c1aeda5682e4cf3906d065ff731274a9660e4128740d5bb1a4d0947b472fe99f988e83670b6df502f5e0b5da.binarypb/1760977477152396", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdab01619c1aeda5682e4cf3906d065ff731274a9660e4128740d5bb1a4d0947b472fe99f988e83670b6df502f5e0b5da.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdab01619c1aeda5682e4cf3906d065ff731274a9660e4128740d5bb1a4d0947b472fe99f988e83670b6df502f5e0b5da.binarypb?generation=1760977477152396&alt=media", - "name": "ovmf_x64_csm/tdx/dab01619c1aeda5682e4cf3906d065ff731274a9660e4128740d5bb1a4d0947b472fe99f988e83670b6df502f5e0b5da.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1760977477152396", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "if4VFrUdw/4bNtaiA/0m4Q==", - "crc32c": "4GaQVA==", - "etag": "CIzd7qeYs5ADEAE=", - "timeCreated": "2025-10-20T16:24:37.155Z", - "updated": "2025-10-20T16:24:37.155Z", - "timeStorageClassUpdated": "2025-10-20T16:24:37.155Z", - "timeFinalized": "2025-10-20T16:24:37.155Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/db393ea2f702aa5d368298f20bdc42c4d348aef66b2a95c0df1157f656c3cb744a42435ecc22a52a1ffc3263193b34de.binarypb/1747352689299962", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdb393ea2f702aa5d368298f20bdc42c4d348aef66b2a95c0df1157f656c3cb744a42435ecc22a52a1ffc3263193b34de.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdb393ea2f702aa5d368298f20bdc42c4d348aef66b2a95c0df1157f656c3cb744a42435ecc22a52a1ffc3263193b34de.binarypb?generation=1747352689299962&alt=media", - "name": "ovmf_x64_csm/tdx/db393ea2f702aa5d368298f20bdc42c4d348aef66b2a95c0df1157f656c3cb744a42435ecc22a52a1ffc3263193b34de.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1747352689299962", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5307", - "md5Hash": "YfIh3m29FPlCKbDR8awGDw==", - "crc32c": "RR4rQA==", - "etag": "CPqj34LUpo0DEAE=", - "timeCreated": "2025-05-15T23:44:49.302Z", - "updated": "2025-05-15T23:44:49.302Z", - "timeStorageClassUpdated": "2025-05-15T23:44:49.302Z", - "timeFinalized": "2025-05-15T23:44:49.302Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/df09e135fb464db0fd53610ac380475c43a0c1f08efe412a709d929c520c723fbcd87dcc9593e45ef33f3f31152efdf1.binarypb/1728951541331594", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdf09e135fb464db0fd53610ac380475c43a0c1f08efe412a709d929c520c723fbcd87dcc9593e45ef33f3f31152efdf1.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdf09e135fb464db0fd53610ac380475c43a0c1f08efe412a709d929c520c723fbcd87dcc9593e45ef33f3f31152efdf1.binarypb?generation=1728951541331594&alt=media", - "name": "ovmf_x64_csm/tdx/df09e135fb464db0fd53610ac380475c43a0c1f08efe412a709d929c520c723fbcd87dcc9593e45ef33f3f31152efdf1.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951541331594", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "CIrt0bOOj4kDEAE=", - "timeCreated": "2024-10-15T00:19:01.336Z", - "updated": "2024-10-15T00:19:01.336Z", - "timeStorageClassUpdated": "2024-10-15T00:19:01.336Z", - "timeFinalized": "2024-10-15T00:19:01.336Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/dfc29e5a4aa9fbca5187faa64d0bd2128ee7a3005dcd09143e3c78caee7b0f94211c854da9675e7a1feb9d664e32518a.binarypb/1773450094018441", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdfc29e5a4aa9fbca5187faa64d0bd2128ee7a3005dcd09143e3c78caee7b0f94211c854da9675e7a1feb9d664e32518a.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fdfc29e5a4aa9fbca5187faa64d0bd2128ee7a3005dcd09143e3c78caee7b0f94211c854da9675e7a1feb9d664e32518a.binarypb?generation=1773450094018441&alt=media", - "name": "ovmf_x64_csm/tdx/dfc29e5a4aa9fbca5187faa64d0bd2128ee7a3005dcd09143e3c78caee7b0f94211c854da9675e7a1feb9d664e32518a.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1773450094018441", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5307", - "md5Hash": "nqysDx3Cjb/RcpR7vLWxGA==", - "crc32c": "IQjOxw==", - "etag": "CIn/hbeYnpMDEAE=", - "timeCreated": "2026-03-14T01:01:34.020Z", - "updated": "2026-03-14T01:01:34.020Z", - "timeStorageClassUpdated": "2026-03-14T01:01:34.020Z", - "timeFinalized": "2026-03-14T01:01:34.020Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e18a19909470b61360f4fb23128017a18519a26893ffb0084570d89718e98806951f015ea77fba6c90b39c8a930a2313.binarypb/1736880976365063", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe18a19909470b61360f4fb23128017a18519a26893ffb0084570d89718e98806951f015ea77fba6c90b39c8a930a2313.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe18a19909470b61360f4fb23128017a18519a26893ffb0084570d89718e98806951f015ea77fba6c90b39c8a930a2313.binarypb?generation=1736880976365063&alt=media", - "name": "ovmf_x64_csm/tdx/e18a19909470b61360f4fb23128017a18519a26893ffb0084570d89718e98806951f015ea77fba6c90b39c8a930a2313.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1736880976365063", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "k4IwRlza9X8csyTFcqen+w==", - "crc32c": "/AfofA==", - "etag": "CIeM9Ozx9YoDEAE=", - "timeCreated": "2025-01-14T18:56:16.367Z", - "updated": "2025-01-14T18:56:16.367Z", - "timeStorageClassUpdated": "2025-01-14T18:56:16.367Z", - "timeFinalized": "2025-01-14T18:56:16.367Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e5230d59843192d04bd596ef5b4d65dfb417ceb5a8f19c1771ad2242ce09e6c8f4b52adea7589fb486ea96cbb41a0a8b.binarypb/1728951529982825", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe5230d59843192d04bd596ef5b4d65dfb417ceb5a8f19c1771ad2242ce09e6c8f4b52adea7589fb486ea96cbb41a0a8b.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe5230d59843192d04bd596ef5b4d65dfb417ceb5a8f19c1771ad2242ce09e6c8f4b52adea7589fb486ea96cbb41a0a8b.binarypb?generation=1728951529982825&alt=media", - "name": "ovmf_x64_csm/tdx/e5230d59843192d04bd596ef5b4d65dfb417ceb5a8f19c1771ad2242ce09e6c8f4b52adea7589fb486ea96cbb41a0a8b.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728951529982825", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5066", - "md5Hash": "BGMVv8x0G7Zc8naSC24cYQ==", - "crc32c": "QGep7A==", - "etag": "COmWna6Oj4kDEAE=", - "timeCreated": "2024-10-15T00:18:49.991Z", - "updated": "2024-10-15T00:18:49.991Z", - "timeStorageClassUpdated": "2024-10-15T00:18:49.991Z", - "timeFinalized": "2024-10-15T00:18:49.991Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e7f7c781f3758823d88b5c66d09106752abf0734e1b2ab44351b1a29628383fc33075b3b7dd52b6b33f22dd8ab75edef.binarypb/1725637323120078", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe7f7c781f3758823d88b5c66d09106752abf0734e1b2ab44351b1a29628383fc33075b3b7dd52b6b33f22dd8ab75edef.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe7f7c781f3758823d88b5c66d09106752abf0734e1b2ab44351b1a29628383fc33075b3b7dd52b6b33f22dd8ab75edef.binarypb?generation=1725637323120078&alt=media", - "name": "ovmf_x64_csm/tdx/e7f7c781f3758823d88b5c66d09106752abf0734e1b2ab44351b1a29628383fc33075b3b7dd52b6b33f22dd8ab75edef.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1725637323120078", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5873", - "md5Hash": "YsiRZ+qbYKfA87Occ72IaA==", - "crc32c": "7PKCRw==", - "etag": "CM67n/3TrogDEAE=", - "timeCreated": "2024-09-06T15:42:03.122Z", - "updated": "2024-09-06T15:42:03.122Z", - "timeStorageClassUpdated": "2024-09-06T15:42:03.122Z", - "timeFinalized": "2024-09-06T15:42:03.122Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e858ba2038b2de3dbc3e3feed04738e28f664066db04889689d7230d1eaf9d24db80883e51c6e890e3e856f74540359a.binarypb/1728083459187750", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe858ba2038b2de3dbc3e3feed04738e28f664066db04889689d7230d1eaf9d24db80883e51c6e890e3e856f74540359a.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe858ba2038b2de3dbc3e3feed04738e28f664066db04889689d7230d1eaf9d24db80883e51c6e890e3e856f74540359a.binarypb?generation=1728083459187750&alt=media", - "name": "ovmf_x64_csm/tdx/e858ba2038b2de3dbc3e3feed04738e28f664066db04889689d7230d1eaf9d24db80883e51c6e890e3e856f74540359a.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1728083459187750", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "Lszbx2qIbIvCSGwUT9qwAA==", - "crc32c": "k9E9bA==", - "etag": "CKbI6MXs9YgDEAE=", - "timeCreated": "2024-10-04T23:10:59.189Z", - "updated": "2024-10-04T23:10:59.189Z", - "timeStorageClassUpdated": "2024-10-04T23:10:59.189Z", - "timeFinalized": "2024-10-04T23:10:59.189Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/e88719a23871c90574a02b3ce7c9725e7e29813e69b7243686d3e37d76ef8877abec199742ce84029c5f3bff0b661707.binarypb/1749835943054254", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe88719a23871c90574a02b3ce7c9725e7e29813e69b7243686d3e37d76ef8877abec199742ce84029c5f3bff0b661707.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fe88719a23871c90574a02b3ce7c9725e7e29813e69b7243686d3e37d76ef8877abec199742ce84029c5f3bff0b661707.binarypb?generation=1749835943054254&alt=media", - "name": "ovmf_x64_csm/tdx/e88719a23871c90574a02b3ce7c9725e7e29813e69b7243686d3e37d76ef8877abec199742ce84029c5f3bff0b661707.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1749835943054254", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "Cxj19jTRUoBXz7bLSxsREg==", - "crc32c": "t1YYZg==", - "etag": "CK6XtO727o0DEAE=", - "timeCreated": "2025-06-13T17:32:23.057Z", - "updated": "2025-06-13T17:32:23.057Z", - "timeStorageClassUpdated": "2025-06-13T17:32:23.057Z", - "timeFinalized": "2025-06-13T17:32:23.057Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/edbc2e630231a058685db03ffc86cc919d97d8978eda1a5d7822fcc71189ed030bad5499e4895d8e8e41084c115db8fc.binarypb/1767815579144687", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fedbc2e630231a058685db03ffc86cc919d97d8978eda1a5d7822fcc71189ed030bad5499e4895d8e8e41084c115db8fc.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Fedbc2e630231a058685db03ffc86cc919d97d8978eda1a5d7822fcc71189ed030bad5499e4895d8e8e41084c115db8fc.binarypb?generation=1767815579144687&alt=media", - "name": "ovmf_x64_csm/tdx/edbc2e630231a058685db03ffc86cc919d97d8978eda1a5d7822fcc71189ed030bad5499e4895d8e8e41084c115db8fc.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1767815579144687", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "NUzVZKtQ2hTweKzhS8X7Zw==", - "crc32c": "tb2kzw==", - "etag": "CO+j/pya+pEDEAE=", - "timeCreated": "2026-01-07T19:52:59.147Z", - "updated": "2026-01-07T19:52:59.147Z", - "timeStorageClassUpdated": "2026-01-07T19:52:59.147Z", - "timeFinalized": "2026-01-07T19:52:59.147Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/f0cfe5b84301d459e05be84b2a92821378dbf7c89088f91cf6f76cb2758811906bbdc6c82b077059adc429ff5642c4de.binarypb/1723585988775887", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff0cfe5b84301d459e05be84b2a92821378dbf7c89088f91cf6f76cb2758811906bbdc6c82b077059adc429ff5642c4de.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff0cfe5b84301d459e05be84b2a92821378dbf7c89088f91cf6f76cb2758811906bbdc6c82b077059adc429ff5642c4de.binarypb?generation=1723585988775887&alt=media", - "name": "ovmf_x64_csm/tdx/f0cfe5b84301d459e05be84b2a92821378dbf7c89088f91cf6f76cb2758811906bbdc6c82b077059adc429ff5642c4de.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1723585988775887", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5868", - "md5Hash": "4c7DWZSvyI/lkciF3dGwIw==", - "crc32c": "YXklrg==", - "etag": "CM+f55T68ocDEAE=", - "timeCreated": "2024-08-13T21:53:08.778Z", - "updated": "2024-08-13T21:53:08.778Z", - "timeStorageClassUpdated": "2024-08-13T21:53:08.778Z", - "timeFinalized": "2024-08-13T21:53:08.778Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/f21617ea292291450f68a7909664faead9760a94537b771549b5280a841ed39eb2b12612bb4ecca5e6d4bdcc0cea439b.binarypb/1738630574573147", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff21617ea292291450f68a7909664faead9760a94537b771549b5280a841ed39eb2b12612bb4ecca5e6d4bdcc0cea439b.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff21617ea292291450f68a7909664faead9760a94537b771549b5280a841ed39eb2b12612bb4ecca5e6d4bdcc0cea439b.binarypb?generation=1738630574573147&alt=media", - "name": "ovmf_x64_csm/tdx/f21617ea292291450f68a7909664faead9760a94537b771549b5280a841ed39eb2b12612bb4ecca5e6d4bdcc0cea439b.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1738630574573147", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "K6K133aqs7O38l1ZlKvgBw==", - "crc32c": "tzSyKg==", - "etag": "CNuMrM7nqIsDEAE=", - "timeCreated": "2025-02-04T00:56:14.574Z", - "updated": "2025-02-04T00:56:14.574Z", - "timeStorageClassUpdated": "2025-02-04T00:56:14.574Z", - "timeFinalized": "2025-02-04T00:56:14.574Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/f272d8492d31f6fffa1d0ae81ed2d240a2dd4b81a5f5ebec7e89c9a35f79c3d831588f18d3af13a9b337398ef91bb36b.binarypb/1742241747340264", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff272d8492d31f6fffa1d0ae81ed2d240a2dd4b81a5f5ebec7e89c9a35f79c3d831588f18d3af13a9b337398ef91bb36b.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff272d8492d31f6fffa1d0ae81ed2d240a2dd4b81a5f5ebec7e89c9a35f79c3d831588f18d3af13a9b337398ef91bb36b.binarypb?generation=1742241747340264&alt=media", - "name": "ovmf_x64_csm/tdx/f272d8492d31f6fffa1d0ae81ed2d240a2dd4b81a5f5ebec7e89c9a35f79c3d831588f18d3af13a9b337398ef91bb36b.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1742241747340264", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "80TsozNXqP6cgkI7aUwDMw==", - "crc32c": "HAQx6w==", - "etag": "COiX2qP0kYwDEAE=", - "timeCreated": "2025-03-17T20:02:27.341Z", - "updated": "2025-03-17T20:02:27.341Z", - "timeStorageClassUpdated": "2025-03-17T20:02:27.341Z", - "timeFinalized": "2025-03-17T20:02:27.341Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/f762c0050e56acf0074303393b376a442b896cc795acb8fa348b4e33fb85bf431ca33cdbb9b0ae289f849e9185778602.binarypb/1729190363785814", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff762c0050e56acf0074303393b376a442b896cc795acb8fa348b4e33fb85bf431ca33cdbb9b0ae289f849e9185778602.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ff762c0050e56acf0074303393b376a442b896cc795acb8fa348b4e33fb85bf431ca33cdbb9b0ae289f849e9185778602.binarypb?generation=1729190363785814&alt=media", - "name": "ovmf_x64_csm/tdx/f762c0050e56acf0074303393b376a442b896cc795acb8fa348b4e33fb85bf431ca33cdbb9b0ae289f849e9185778602.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1729190363785814", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5869", - "md5Hash": "glaeiJ8ez0jo8Djtgt+jfw==", - "crc32c": "tBQmEQ==", - "etag": "CNbUh4uIlokDEAE=", - "timeCreated": "2024-10-17T18:39:23.788Z", - "updated": "2024-10-17T18:39:23.788Z", - "timeStorageClassUpdated": "2024-10-17T18:39:23.788Z", - "timeFinalized": "2024-10-17T18:39:23.788Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/fd4eda3653e0179b19655716effba08b1285eeb810196a4653a9e23b62e2f1b671df3e5f37ad821897782be807a85acf.binarypb/1761952076603348", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ffd4eda3653e0179b19655716effba08b1285eeb810196a4653a9e23b62e2f1b671df3e5f37ad821897782be807a85acf.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ffd4eda3653e0179b19655716effba08b1285eeb810196a4653a9e23b62e2f1b671df3e5f37ad821897782be807a85acf.binarypb?generation=1761952076603348&alt=media", - "name": "ovmf_x64_csm/tdx/fd4eda3653e0179b19655716effba08b1285eeb810196a4653a9e23b62e2f1b671df3e5f37ad821897782be807a85acf.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1761952076603348", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5307", - "md5Hash": "6keyAMuscNoyqyIzduiPdA==", - "crc32c": "uF51mg==", - "etag": "CNS/jP3Gz5ADEAE=", - "timeCreated": "2025-10-31T23:07:56.605Z", - "updated": "2025-10-31T23:07:56.605Z", - "timeStorageClassUpdated": "2025-10-31T23:07:56.605Z", - "timeFinalized": "2025-10-31T23:07:56.605Z" - }, - { - "kind": "storage#object", - "id": "gce_tcb_integrity/ovmf_x64_csm/tdx/feb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162.binarypb/1773355463154784", - "selfLink": "https://www.googleapis.com/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ffeb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162.binarypb", - "mediaLink": "https://storage.googleapis.com/download/storage/v1/b/gce_tcb_integrity/o/ovmf_x64_csm%2Ftdx%2Ffeb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162.binarypb?generation=1773355463154784&alt=media", - "name": "ovmf_x64_csm/tdx/feb7486608382c1ff0e15b4648ddc0acea6ca974eb53e3529f4c4bd5ffbaa20bf335cb75965cea65fe473aed9647c162.binarypb", - "bucket": "gce_tcb_integrity", - "generation": "1773355463154784", - "metageneration": "1", - "contentType": "application/octet-stream", - "storageClass": "STANDARD", - "size": "5308", - "md5Hash": "TYybKoEwVCW1UlFMsbyUvw==", - "crc32c": "NqZFYg==", - "etag": "COC4xPO3m5MDEAE=", - "timeCreated": "2026-03-12T22:44:23.156Z", - "updated": "2026-03-12T22:44:23.156Z", - "timeStorageClassUpdated": "2026-03-12T22:44:23.156Z", - "timeFinalized": "2026-03-12T22:44:23.156Z" - } - ] -} From b61da0237e6666eaa9d955ceefe55dd3395d7f2a Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 24 Jun 2026 12:43:06 +0200 Subject: [PATCH 20/35] Fixes following revert breaking api change --- crates/attestation/src/azure/mod.rs | 2 +- crates/attestation/src/dcap.rs | 2 +- crates/attestation/src/measurements.rs | 28 +++++++++++++------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 0aba02b..66bd1d5 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -863,7 +863,7 @@ mod tests { .unwrap(); assert_eq!(async_measurements, sync_measurements); - measurement_policy.check_measurement(&async_measurements, None, None).unwrap(); + measurement_policy.check_measurement(&async_measurements, None).unwrap(); } /// Verify a complete observed Azure attestation payload that includes diff --git a/crates/attestation/src/dcap.rs b/crates/attestation/src/dcap.rs index e34a697..516e30c 100644 --- a/crates/attestation/src/dcap.rs +++ b/crates/attestation/src/dcap.rs @@ -369,7 +369,7 @@ mod tests { .unwrap(); assert_eq!(async_measurements, sync_measurements); - measurement_policy.check_measurement(&async_measurements, None, None).unwrap(); + measurement_policy.check_measurement(&async_measurements, None).unwrap(); } // This specifically tests a quote which has outdated TCB level from Azure diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index 3fcba15..61ee276 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -738,7 +738,7 @@ mod tests { // Will not match mock measurements assert!(matches!( specific_measurements - .check_measurement(&mock_dcap_measurements(), None, None) + .check_measurement(&mock_dcap_measurements(), None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -746,7 +746,7 @@ mod tests { // Will not match another attestation type assert!(matches!( specific_measurements - .check_measurement(&MultiMeasurements::NoAttestation, None, None) + .check_measurement(&MultiMeasurements::NoAttestation, None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -754,7 +754,7 @@ mod tests { // A non-specific measurement fails assert!(matches!( specific_measurements - .check_measurement(&MultiMeasurements::Azure(HashMap::new()), None, None) + .check_measurement(&MultiMeasurements::Azure(HashMap::new()), None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -767,12 +767,12 @@ mod tests { let allowed_attestation_type = MeasurementPolicy::from_file("test-assets/measurements_2.json".into()).await.unwrap(); - allowed_attestation_type.check_measurement(&mock_dcap_measurements(), None, None).unwrap(); + allowed_attestation_type.check_measurement(&mock_dcap_measurements(), None).unwrap(); // Will not match another attestation type assert!(matches!( allowed_attestation_type - .check_measurement(&MultiMeasurements::NoAttestation, None, None) + .check_measurement(&MultiMeasurements::NoAttestation, None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -826,7 +826,7 @@ mod tests { (DcapMeasurementRegister::RTMR3, mock_tdx::MOCK_RTMR3), ])); - policy.check_measurement(&measurements, Some(platform_metadata), None).unwrap(); + policy.check_measurement(&measurements, Some(platform_metadata)).unwrap(); } #[tokio::test] @@ -842,14 +842,14 @@ mod tests { assert!(!policy.accepted_measurements.is_empty()); assert!(matches!( - policy.check_measurement(&MultiMeasurements::NoAttestation, None, None).unwrap_err(), + policy.check_measurement(&MultiMeasurements::NoAttestation, None).unwrap_err(), AttestationError::MeasurementsNotAccepted )); // A non-specific measurement fails assert!(matches!( policy - .check_measurement(&MultiMeasurements::Azure(HashMap::new()), None, None) + .check_measurement(&MultiMeasurements::Azure(HashMap::new()), None) .unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -906,17 +906,17 @@ mod tests { // First value should match let measurements1 = MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0u8; 48])])); - assert!(policy.check_measurement(&measurements1, None, None).is_ok()); + assert!(policy.check_measurement(&measurements1, None).is_ok()); // Second value should also match let measurements2 = MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0x11u8; 48])])); - assert!(policy.check_measurement(&measurements2, None, None).is_ok()); + assert!(policy.check_measurement(&measurements2, None).is_ok()); // Different value should not match let measurements3 = MultiMeasurements::Dcap(HashMap::from([(DcapMeasurementRegister::MRTD, [0x22u8; 48])])); - assert!(policy.check_measurement(&measurements3, None, None).is_err()); + assert!(policy.check_measurement(&measurements3, None).is_err()); } #[tokio::test] @@ -996,21 +996,21 @@ mod tests { (DcapMeasurementRegister::MRTD, [0u8; 48]), (DcapMeasurementRegister::RTMR0, [0x11u8; 48]), ])); - assert!(policy.check_measurement(&measurements1, None, None).is_ok()); + assert!(policy.check_measurement(&measurements1, None).is_ok()); // Both match (single + second of any) let measurements2 = MultiMeasurements::Dcap(HashMap::from([ (DcapMeasurementRegister::MRTD, [0u8; 48]), (DcapMeasurementRegister::RTMR0, [0x22u8; 48]), ])); - assert!(policy.check_measurement(&measurements2, None, None).is_ok()); + assert!(policy.check_measurement(&measurements2, None).is_ok()); // Single matches but any doesn't let measurements3 = MultiMeasurements::Dcap(HashMap::from([ (DcapMeasurementRegister::MRTD, [0u8; 48]), (DcapMeasurementRegister::RTMR0, [0x33u8; 48]), ])); - assert!(policy.check_measurement(&measurements3, None, None).is_err()); + assert!(policy.check_measurement(&measurements3, None).is_err()); } #[tokio::test] From 6ae5aeb8aaea25cd707e546e66e8b7ccffdaba60 Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 24 Jun 2026 12:57:51 +0200 Subject: [PATCH 21/35] Fmt --- crates/attestation/src/measurements.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index 61ee276..c644cf8 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -737,9 +737,7 @@ mod tests { // Will not match mock measurements assert!(matches!( - specific_measurements - .check_measurement(&mock_dcap_measurements(), None) - .unwrap_err(), + specific_measurements.check_measurement(&mock_dcap_measurements(), None).unwrap_err(), AttestationError::MeasurementsNotAccepted )); @@ -848,9 +846,7 @@ mod tests { // A non-specific measurement fails assert!(matches!( - policy - .check_measurement(&MultiMeasurements::Azure(HashMap::new()), None) - .unwrap_err(), + policy.check_measurement(&MultiMeasurements::Azure(HashMap::new()), None).unwrap_err(), AttestationError::MeasurementsNotAccepted )); } From 4f53f7d9232674099959aff7470934fb8a21480e Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 24 Jun 2026 13:46:10 +0200 Subject: [PATCH 22/35] Fmt --- crates/attestation/src/azure/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index c7368cf..5a59766 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -856,8 +856,9 @@ mod tests { let mut expected_input_data = input_data_from_attestation(attestation_bytes); expected_input_data[63] ^= 0x01; - let collateral_bytes: &'static [u8] = - include_bytes!("../../test-assets/azure-collateral-with-ak-intermediates-1780922561.yaml"); + let collateral_bytes: &'static [u8] = include_bytes!( + "../../test-assets/azure-collateral-with-ak-intermediates-1780922561.yaml" + ); let collateral = serde_saphyr::from_slice(collateral_bytes).unwrap(); let attestation_json = serde_json::to_vec( &serde_saphyr::from_slice::(attestation_bytes).unwrap(), From e99e89a6292eb543143974bf2567e90d2d9daa8a Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 30 Jun 2026 11:25:04 +0200 Subject: [PATCH 23/35] Add test demonstrating portable measurement policy with observed data from GCP --- .../test-assets/gcp-tdx-1782809233226668671 | Bin 0 -> 8000 bytes ...cp-tdx-collateral-1782809233226668671.yaml | 109 ++++++++++++++++++ .../gcp-tdx-firmware-1782809233226668671.yaml | 9 ++ 3 files changed, 118 insertions(+) create mode 100644 crates/attestation/test-assets/gcp-tdx-1782809233226668671 create mode 100644 crates/attestation/test-assets/gcp-tdx-collateral-1782809233226668671.yaml create mode 100644 crates/attestation/test-assets/gcp-tdx-firmware-1782809233226668671.yaml diff --git a/crates/attestation/test-assets/gcp-tdx-1782809233226668671 b/crates/attestation/test-assets/gcp-tdx-1782809233226668671 new file mode 100644 index 0000000000000000000000000000000000000000..d04b298591afba0ad6907f4b3aec8c17f5a82084 GIT binary patch literal 8000 zcmeHKeUKYv89%P2Eh|)%QeX-Uh@x^HxB0qU_!xNK-8Y-vWH;H*WP^&yCb!vSlU$O! zY!XVLV1a^A++UYbz*aUKz;a` z!#&$quRHRzdoK9ta~~WZzHZ>@)o?ZQSpPv+oIDa^Pu_LZ{K5M^*s<<2$DVh@cdxqK zfA#%;cxmC;7rZ`vb^nR1QsJO!@o`FVqGX{p_*D4>-gGjhr1AKh}&Vc#m6mu~u(YyHnJ3%z;b#_e0LT4~K= z$MavBZ_T}QL%nK0{_1V&b2rWFL)eN13wAA;yK9P8GmY%|b>tNK+SGIF+S?x3Kt6HZ z={Lv`TVK02y2<;x=iQwvR}m|oUGVL~Z+cGB1#Vh%%F^<+tBzs>?` zk371?IQ!{S7b-t_va9Q-^4h=uuJ>I3)*WBH=koOT*8ctMzoh3pd(4g8SsyNQRj$7N zxKnRgz36>Q>p7?k%m%ocn`EV^3bQbH&c@7yf+w3;k~` zcrSIuihF+j#;EHnFRxs;p)AvPZnM+7igf(K$lKdb=$fnd>%o2BSlHJ$*uEfQSm6W; zNeUZeDWISZO7JX;MrewHT*?Fv3xUb1VP7g)@@5<_6w^kd=BiKltRa<~2%-^(GIcgw zPO_~$iEw|1Flc1)6kvc$#ekEP<32JOcTAPc=xh+uaud(O1j%GE&`isa78R7@q1owA znT|wE4-nmfrojZ7dO{jYyS$S}wh-Hn`4L=CD1xVDP~4m-A9fL(qu$l)}#1(Q7F8Q82aGVcul6EPGu_3oe$ zAXxxuU!IV|Zp|1S6^d2K-At06W^KG&^(zwz!9cRxlMM~~%|IbA4o3u!S_#ERW^@uy@q+}myl(bfc z(F%rJYZ4h8*<^yBNKF!GLU#woBOalYr2-h|$W%Nzrn`gq8JLK8bTZm`#-2#FT!mzUbwX{jNMsa39R;~DzBN>{i{8kHT}X5G@URk=G9hAs zGg%&Z+uN0)9R!CQvCVPDp#f$r_Fv*57#%?%4*-q}6%}=^oeQ~oP5>ea35daPo}z%I zJ0VjKcQ*o26d_q0D)9bFuAY@fRTnF|bT)*O55#eltO`TOY}%`c2+zhkrWsW5dJNUx z`#m_O3SxWUR2wIHG|;$#>VczPIDuCV;s(@X0E2PZ0}o*w2WZmLZWmbGz)UxExxjS~ z=)%Koyq61+eGK4x;cXX$UJV$J?gNi??P600C%% z-B%|Lc#ro?!s8vlM1o>x@Au#$BA`iuw4(w*gBUc+m0ZDM1`vr)PZXp&yWrhxkd9C| zP)(J}T26E+M8a!Da%`wBgjh!cGnoim!2Qu(F(42_L(_Oy3=9h3G?;GKW2QlO27vPJ z6A1z=1f&Ugq*4S6EhuRfF9q~c}{ZT>dwCr2#D7&4X zdH1x~X@Jw}3Bw&=20~*ZDsiru*lL-<1Qqb9{9euxJYzPPJkZ;x0rnOw3N$0)u|f{vCPfKLq8Ow_c3MLGl4u%+Se$ID%x1R>{ZK6OV%4zIvy#il9yrwLby2^69zs(?&e$V+?A(uS7nPT@3Jcy zfi1O6zpSa%fXK88C0KFx_RAqs^q#^K7pl^9-8osPa`m)F+$ZVVoF_gB>D!#2O1&x4 zLvMmskQe7{lUI-<&}xGZmN6#!c!h1XZ$T-zqFULRww#!%u@BhvY0HUr?R22|+MTY% z{^lz+TtW^{vwAX`AF^Wc8r4dnu;nLQQ7bA(q+l-2d>0#`T?V5oWqjI=0G$)J8-dvf%tl}~0<#gAjlgUK{;wkNUpTUp#Q*>R literal 0 HcmV?d00001 diff --git a/crates/attestation/test-assets/gcp-tdx-collateral-1782809233226668671.yaml b/crates/attestation/test-assets/gcp-tdx-collateral-1782809233226668671.yaml new file mode 100644 index 0000000..567d688 --- /dev/null +++ b/crates/attestation/test-assets/gcp-tdx-collateral-1782809233226668671.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: >- + 30820d1830820cbd020101300a06082a8648ce3d04030230703122302006035504030c19496e74656c205347582050434b20506c6174666f726d204341311a3018060355040a0c11496e74656c20436f72706f726174696f6e3114301206035504070c0b53616e746120436c617261310b300906035504080c024341310b3009060355040613025553170d3236303633303037353632315a170d3236303733303037353632315a30820be9303302146fc34e5023e728923435d61aa4b83c618166ad35170d3236303633303037353632315a300c300a0603551d1504030a01013034021500efae6e9715fca13b87e333e8261ed6d990a926ad170d3236303633303037353632315a300c300a0603551d1504030a01013034021500fd608648629cba73078b4d492f4b3ea741ad08cd170d3236303633303037353632315a300c300a0603551d1504030a010130340215008af924184e1d5afddd73c3d63a12f5e8b5737e56170d3236303633303037353632315a300c300a0603551d1504030a01013034021500b1257978cfa9ccdd0759abf8c5ca72fae3a78a9b170d3236303633303037353632315a300c300a0603551d1504030a01013033021474fea614a972be0e2843f2059835811ed872f9b3170d3236303633303037353632315a300c300a0603551d1504030a01013034021500f9c4ef56b3ab48d577e108baedf4bf88014214b9170d3236303633303037353632315a300c300a0603551d1504030a010130330214071de0778f9e5fc4f2878f30d6b07c9a30e6b30b170d3236303633303037353632315a300c300a0603551d1504030a01013034021500cde2424f972cea94ff239937f4d80c25029dd60b170d3236303633303037353632315a300c300a0603551d1504030a0101303302146c3319e5109b64507d3cf1132ce00349ef527319170d3236303633303037353632315a300c300a0603551d1504030a01013034021500df08d756b66a7497f43b5bb58ada04d3f4f7a937170d3236303633303037353632315a300c300a0603551d1504030a01013033021428af485b6cf67e409a39d5cb5aee4598f7a8fa7b170d3236303633303037353632315a300c300a0603551d1504030a01013034021500fb8b2daec092cada8aa9bc4ff2f1c20d0346668c170d3236303633303037353632315a300c300a0603551d1504030a01013034021500cd4850ac52bdcc69a6a6f058c8bc57bbd0b5f864170d3236303633303037353632315a300c300a0603551d1504030a01013034021500994dd3666f5275fb805f95dd02bd50cb2679d8ad170d3236303633303037353632315a300c300a0603551d1504030a0101303302140702136900252274d9035eedf5457462fad0ef4c170d3236303633303037353632315a300c300a0603551d1504030a01013033021461f2bf73e39b4e04aa27d801bd73d24319b5bf80170d3236303633303037353632315a300c300a0603551d1504030a0101303302143992be851b96902eff38959e6c2eff1b0651a4b5170d3236303633303037353632315a300c300a0603551d1504030a0101303302140fda43a00b68ea79b7c2deaeac0b498bdfb2af90170d3236303633303037353632315a300c300a0603551d1504030a010130330214639f139a5040fdcff191e8a4fb1bf086ed603971170d3236303633303037353632315a300c300a0603551d1504030a01013034021500959d533f9249dc1e513544cdc830bf19b7f1f301170d3236303633303037353632315a300c300a0603551d1504030a0101303302147ae37748a9f912f4c63ba7ab07c593ce1d1d1181170d3236303633303037353632315a300c300a0603551d1504030a01013033021413884b33269938c195aa170fca75da177538df0b170d3236303633303037353632315a300c300a0603551d1504030a0101303402150085d3c9381b77a7e04d119c9e5ad6749ff3ffab87170d3236303633303037353632315a300c300a0603551d1504030a0101303402150093887ca4411e7a923bd1fed2819b2949f201b5b4170d3236303633303037353632315a300c300a0603551d1504030a0101303302142498dc6283930996fd8bf23a37acbe26a3bed457170d3236303633303037353632315a300c300a0603551d1504030a010130340215008a66f1a749488667689cc3903ac54c662b712e73170d3236303633303037353632315a300c300a0603551d1504030a01013034021500afc13610bdd36cb7985d106481a880d3a01fda07170d3236303633303037353632315a300c300a0603551d1504030a01013034021500efe04b2c33d036aac96ca673bf1e9a47b64d5cbb170d3236303633303037353632315a300c300a0603551d1504030a0101303402150083d9ac8d8bb509d1c6c809ad712e8430559ed7f3170d3236303633303037353632315a300c300a0603551d1504030a0101303302147931fd50b5071c1bbfc5b7b6ded8b45b9d8b8529170d3236303633303037353632315a300c300a0603551d1504030a0101303302141fa20e2970bde5d57f7b8ddf8339484e1f1d0823170d3236303633303037353632315a300c300a0603551d1504030a0101303302141e87b2c3b32d8d23e411cef34197b95af0c8adf5170d3236303633303037353632315a300c300a0603551d1504030a010130340215009afd2ee90a473550a167d996911437c7502d1f09170d3236303633303037353632315a300c300a0603551d1504030a0101303302144481b0f11728a13b696d3ea9c770a0b15ec58dda170d3236303633303037353632315a300c300a0603551d1504030a01013034021500a7859f57982ef0e67d37bc8ef2ef5ac835ff1aa9170d3236303633303037353632315a300c300a0603551d1504030a010130340215009d67753b81e47090aea763fbec4c4549bcdb9933170d3236303633303037353632315a300c300a0603551d1504030a01013033021434bfbb7a1d9c568147e118b614f7b76ed3ef68df170d3236303633303037353632315a300c300a0603551d1504030a0101303302142c3cc6fe9279db1516d5ce39f2a898cda5a175e1170d3236303633303037353632315a300c300a0603551d1504030a010130330214717948687509234be979e4b7dce6f31bef64b68c170d3236303633303037353632315a300c300a0603551d1504030a010130340215009d76ef2c39c136e8658b6e7396b1d7445a27631f170d3236303633303037353632315a300c300a0603551d1504030a01013034021500c3e025fca995f36f59b48467939e3e34e6361a6f170d3236303633303037353632315a300c300a0603551d1504030a010130340215008c5f6b3257da05b17429e2e61ba965d67330606a170d3236303633303037353632315a300c300a0603551d1504030a01013034021500a17c51722ec1e0c3278fe8bdf052059cbec4e648170d3236303633303037353632315a300c300a0603551d1504030a01013033021411c943b866fa04944e3057e5a67146596475a023170d3236303633303037353632315a300c300a0603551d1504030a01013034021500be6913785406155454a28885a515b3da5767d3a9170d3236303633303037353632315a300c300a0603551d1504030a0101303302140ac5ec91bd934c07b9ea41625e9cc09681002eb0170d3236303633303037353632315a300c300a0603551d1504030a0101303302146d51a0eabc1f9a1e9ddd5b36bdda1631ae6c182a170d3236303633303037353632315a300c300a0603551d1504030a01013034021500a52c5d71c4166b4fc0ded8b679951e5ee9193de5170d3236303633303037353632315a300c300a0603551d1504030a010130330214249779aedd85fcac93c8853516be5428c26b3bf8170d3236303633303037353632315a300c300a0603551d1504030a01013033021434ba4fd76bde5309210cf1dd1ffb494c638a9157170d3236303633303037353632315a300c300a0603551d1504030a010130330214043e04919daae13443248395094d2a2eacfc76fe170d3236303633303037353632315a300c300a0603551d1504030a01013033021447fc577d2d094cbdf270715ed6848a93855ad34b170d3236303633303037353632315a300c300a0603551d1504030a0101303302147d62a2f5e6f386e469653fffff045d0a8178e8e7170d3236303633303037353632315a300c300a0603551d1504030a01013034021500c4ed45fe026bb6a47eaec35ea80b7ef407ce062c170d3236303633303037353632315a300c300a0603551d1504030a01013034021500cf9831077a3ca4f1a2c56867bf55b18eccbeffd8170d3236303633303037353632315a300c300a0603551d1504030a0101303302146c2b81d7ea2e436720ce29f1d0b1ccb7a218600f170d3236303633303037353632315a300c300a0603551d1504030a0101a02f302d300a0603551d140403020101301f0603551d23041830168014956f5dcdbd1be1e94049c9d4f433ce01570bde54300a06082a8648ce3d0403020349003046022100f6319860a35e9dc53a9693abe9e82bfcdd2e3f3774cb3e10547f742e241b09bc022100f16e9c2545ed59911c6b02ad73cb48204797b00a4428c421a7d30eeab7ed4c56 +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-30T07:53:47Z\",\"nextUpdate\":\"2026-07-30T07:53:47Z\",\"fmspc\":\"00806F050000\",\"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\":8,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":8,\"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\":6,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":8,\"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\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":7,\"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\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":5,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":7,\"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-01010\",\"INTEL-SA-01036\",\"INTEL-SA-01076\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":6,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":6,\"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\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":6,\"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\":\"2023-08-09T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\",\"INTEL-SA-01010\",\"INTEL-SA-01036\",\"INTEL-SA-01076\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"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\":3,\"category\":\"OS/VMM\",\"type\":\"SEAMLDR ACM\"},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11,\"tdxtcbcomponents\":[{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"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\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00837\",\"INTEL-SA-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\",\"INTEL-SA-01010\",\"INTEL-SA-01036\",\"INTEL-SA-01076\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":5,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":5,\"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\":3,\"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\":3,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":0,\"category\":\"OS/VMM\",\"type\":\"TDX Module\"},{\"svn\":5,\"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-00960\",\"INTEL-SA-00982\",\"INTEL-SA-00986\",\"INTEL-SA-01010\",\"INTEL-SA-01036\",\"INTEL-SA-01076\",\"INTEL-SA-01079\",\"INTEL-SA-01099\",\"INTEL-SA-01103\",\"INTEL-SA-01111\"]}]}" +tcb_info_signature: >- + 9a0940311cebac796d0c1e6378331a21d712afcbc81b6cb2accd222cef33a55bda5e6a94eb406fb6506911c5293d6b848e9d77a776938821e6eaecc20f37a759 +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-30T08:12:19Z\",\"nextUpdate\":\"2026-07-30T08:12:19Z\",\"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: >- + 078a0202d36801e43dd3bfb7b8f77cefc2ed23558cb3472550c21f43a0bdffd7b10bc2a70c50b589c4f07d0df53e7a4be9082775ac4232f5c17a39f1e24da491 diff --git a/crates/attestation/test-assets/gcp-tdx-firmware-1782809233226668671.yaml b/crates/attestation/test-assets/gcp-tdx-firmware-1782809233226668671.yaml new file mode 100644 index 0000000..65618b6 --- /dev/null +++ b/crates/attestation/test-assets/gcp-tdx-firmware-1782809233226668671.yaml @@ -0,0 +1,9 @@ +mrtd: >- + 9bf86e6280ec4282b8b5822d8166410a456cdb720109aa799f0011fa63df1de3ee5e35e293fc410c061433163acb03a6 +cfv: >- + d10d31022a1ef32ee501f31745257f84e7c753a8b79a3fdb82ffda9dc57684a1cfefba3edcdabc8b4ea791c17dd8a02b +hob: + bytes: >- + 010038000000000009000000000000000000000000000000000000000000000000000000000000000000000000000000489280000000000003003000000000000000000000000000000000000000000000000000070000000000e2ff0000000000001e000000000003003000000000000000000000000000000000000000000000000000070000000000e0ff000000000000020000000000030030000000000000000000000000000000000000000000000000000700000000008100000000000000010000000000030030000000000000000000000000000000000000000000000000000700000000b08000000000000020000000000000030030000000000000000000000000000000000000000000000000000700000000908000000000000020000000000000030030000000000000000000000000000000000000000000000000000700000000008000000000000060000000000000030030000000000000000000000000000000000000000000070000000700001000000000000000000000800000000000030030000000000000000000000000000000000000000000070000000700001000608000000000000030000000000000030030000000000000000000000000000000000000000000070000000700001000d080000000000000300000000000000300300000000000000000000000000000000000000000000700000007000010000082000000000000007ebf00000000030030000000000000000000000000000000000000000000070000000700001000000000010000000000000000000000 + length_offset: 576 + ram_threshold: 3221225472 From c78d66092bc1fd5dfb7ab2a41ebe6313d41c43d7 Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 30 Jun 2026 11:25:20 +0200 Subject: [PATCH 24/35] Add test demonstrating portable measurement policy with observed data from GCP --- crates/attestation/src/gcp.rs | 119 ++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/crates/attestation/src/gcp.rs b/crates/attestation/src/gcp.rs index 069b477..5d6fdfe 100644 --- a/crates/attestation/src/gcp.rs +++ b/crates/attestation/src/gcp.rs @@ -45,3 +45,122 @@ pub(crate) enum GcpFirmwareCacheError { #[error("Firmware fetch: {0}")] Firmware(#[from] attest_measure::dcap::GoogleError), } + +#[cfg(test)] +mod tests { + use attest_measure::dcap::DcapFirmware; + use attest_types::{AcpiHashes, DcapImageHashes}; + use dcap_qvl::quote::Quote; + + use crate::{ + PlatformMetadata, + dcap::{get_quote_input_data, verify_dcap_attestation_with_given_timestamp}, + gcp::GcpFirmwareCache, + measurements::{ExpectedMeasurements, MeasurementPolicy, MeasurementRecord}, + }; + + /// Timestamp used with test fixture + const GCP_TDX_PORTABLE_FIXTURE_TIMESTAMP: u64 = 1_782_809_233; + + /// Create a firmware cache with given firmware loaded + fn create_cache_with_firmware(firmware: DcapFirmware) -> GcpFirmwareCache { + let cache = GcpFirmwareCache::new(); + cache.cache.write().unwrap().insert(firmware.mrtd, firmware); + cache + } + + fn decode_dcap_hash(input: &str) -> [u8; 48] { + hex::decode(input).unwrap().try_into().unwrap() + } + + /// Image hashes associated with test fixture + fn gcp_portable_image_hashes() -> DcapImageHashes { + DcapImageHashes { + uki_authenticode: decode_dcap_hash( + "82500f977e16a1e3fd47db792ac9c9fdd69caa73d8e719fe4489416355f23f5d0863ad796febfc1241bc3e868c3649a6", + ), + kernel_authenticode: decode_dcap_hash( + "b2a6076ae199d325e553a5102cf1f4a18b5e67e36b33261ef20352052199ec5853b5133c0231b16f1198bb086f1cbfac", + ), + cmdline_hash: decode_dcap_hash( + "e03b89abf354a38976537b7a9138fd312e4cbf73b61eebc44086491701b1d167b9f6cb97a922325866c93e0834723d87", + ), + initrd_hash: decode_dcap_hash( + "99251a9997f552ce98364e3f7311ca47471e299b6fdb31226d738a10577959ab741cc2e7b8c268236153de568265d3f2", + ), + gpt_disk_guid_hash: decode_dcap_hash( + "488fa3f08aae01c1a46b497319e8a7d3b7335c9ff4f4d7fe6a3dd62c844b03de22157c0303be58f10e3152687778e68d", + ), + } + } + + /// Platform metadata associated with test fixture + fn gcp_portable_platform_metadata() -> PlatformMetadata { + PlatformMetadata { + attestation_type: attest_types::AttestationType::GcpTdx, + ram_bytes: 17_179_869_184, + num_disks: 1, + acpi: Some(AcpiHashes { + loader: [ + 246, 12, 53, 229, 59, 178, 27, 70, 117, 207, 168, 219, 49, 14, 200, 142, 56, + 205, 54, 157, 141, 70, 58, 205, 222, 129, 81, 34, 250, 139, 137, 59, 136, 150, + 165, 120, 59, 83, 136, 86, 105, 62, 215, 100, 93, 219, 137, 126, + ], + rsdp: [ + 80, 157, 207, 225, 11, 235, 93, 71, 12, 64, 242, 94, 48, 137, 83, 112, 148, + 136, 49, 185, 207, 121, 219, 21, 217, 119, 231, 187, 168, 235, 66, 247, 32, 2, + 18, 7, 26, 216, 177, 157, 96, 17, 117, 151, 121, 236, 237, 90, + ], + tables: [ + 11, 176, 175, 160, 8, 135, 59, 220, 32, 222, 224, 247, 65, 218, 120, 150, 194, + 191, 238, 233, 74, 229, 46, 155, 219, 249, 75, 200, 124, 50, 208, 74, 75, 31, + 29, 130, 68, 144, 241, 218, 229, 116, 255, 109, 78, 75, 176, 179, + ], + }), + } + } + + #[tokio::test] + async fn test_gcp_tdx_portable_policy_with_stored_collateral() { + let attestation_bytes: &'static [u8] = + include_bytes!("../test-assets/gcp-tdx-1782809233226668671"); + let collateral_bytes: &'static [u8] = + include_bytes!("../test-assets/gcp-tdx-collateral-1782809233226668671.yaml"); + let firmware_bytes: &'static [u8] = + include_bytes!("../test-assets/gcp-tdx-firmware-1782809233226668671.yaml"); + + let expected_input_data = { + let quote = Quote::parse(attestation_bytes).unwrap(); + get_quote_input_data(quote.report) + }; + + let collateral = serde_saphyr::from_slice(collateral_bytes).unwrap(); + let firmware = serde_saphyr::from_slice(firmware_bytes).unwrap(); + let measurements = verify_dcap_attestation_with_given_timestamp( + attestation_bytes.to_vec(), + expected_input_data, + None, + Some(collateral), + GCP_TDX_PORTABLE_FIXTURE_TIMESTAMP, + false, + ) + .await + .unwrap(); + + let measurement_policy = MeasurementPolicy { + accepted_measurements: vec![MeasurementRecord { + measurement_id: "gcp-tdx-portable-image-hashes".to_string(), + measurements: ExpectedMeasurements::Image(gcp_portable_image_hashes()), + }], + }; + let gcp_firmware_cache = create_cache_with_firmware(firmware); + + measurement_policy + .check_measurement_with_gcp_cache( + &measurements, + Some(gcp_portable_platform_metadata()), + Some(&gcp_firmware_cache), + ) + .unwrap(); + } +} From bab2de8f085d1b36fbb2cb9d3b3fb5bfa7ae3f7d Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 30 Jun 2026 13:05:54 +0200 Subject: [PATCH 25/35] Quote generator should not assume tdx-gcp --- Cargo.lock | 1 - crates/attestation/src/dcap.rs | 28 +++++++++------------------- crates/attestation/src/lib.rs | 23 +++++++++++++++++------ crates/mock-tdx/Cargo.toml | 1 - crates/mock-tdx/src/lib.rs | 32 +++++++++++--------------------- 5 files changed, 37 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 76041f3..2641577 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2786,7 +2786,6 @@ dependencies = [ name = "mock-tdx" version = "0.0.1" dependencies = [ - "attest-types", "axum", "dcap-qvl 0.3.12 (git+https://github.com/Phala-Network/dcap-qvl.git?rev=f1dcc65371e941a7b83e3234833d23a1fb232ab1)", "hex", diff --git a/crates/attestation/src/dcap.rs b/crates/attestation/src/dcap.rs index 516e30c..e8f1767 100644 --- a/crates/attestation/src/dcap.rs +++ b/crates/attestation/src/dcap.rs @@ -1,6 +1,5 @@ //! Data Center Attestation Primitives (DCAP) evidence generation and //! verification -use attest_types::AttestationEvidence; use dcap_qvl::{ QuoteCollateralV3, collateral::get_collateral_for_fmspc, @@ -22,12 +21,10 @@ const AZURE_BAD_FMSPC: &str = "90C06F000000"; pub const PCS_URL: &str = "https://api.trustedservices.intel.com"; /// Generate a TDX quote -pub fn create_dcap_attestation( - input_data: [u8; 64], -) -> Result { - let attestation_evidence = generate_quote(input_data)?; - tracing::info!("Generated TDX quote of {} bytes", attestation_evidence.quote.len()); - Ok(attestation_evidence) +pub fn create_dcap_attestation(input_data: [u8; 64]) -> Result, AttestationError> { + let quote = generate_quote(input_data)?; + tracing::info!("Generated TDX quote of {} bytes", quote.len()); + Ok(quote) } /// Verify a DCAP TDX quote, and return the measurement values @@ -257,19 +254,14 @@ pub fn verify_dcap_attestation_sync( /// Create a mock quote for testing on non-confidential hardware #[cfg(any(test, feature = "mock"))] -fn generate_quote(input: [u8; 64]) -> Result { +fn generate_quote(input: [u8; 64]) -> Result, AttestationError> { generate_mock_tdx_quote(input).map_err(|error| AttestationError::Mock(format!("{error}"))) } /// Create a quote #[cfg(not(any(test, feature = "mock")))] -fn generate_quote(input: [u8; 64]) -> Result { - use attest_measure::platform; - - Ok(AttestationEvidence { - quote: tdx_attest::get_quote(&input)?, - platform: platform::metadata_for(attest_types::AttestationType::GcpTdx)?, - }) +fn generate_quote(input: [u8; 64]) -> Result, AttestationError> { + Ok(tdx_attest::get_quote(&input)?) } /// Given a [Report] get the input data regardless of report type @@ -413,12 +405,10 @@ mod tests { .unwrap(); let pccs = Pccs::new(Some(mock_pcs.base_url.clone())); let expected_input_data = [0xA5; 64]; - let attestation = create_dcap_attestation(expected_input_data).unwrap(); + let quote = create_dcap_attestation(expected_input_data).unwrap(); let measurements = - verify_dcap_attestation(attestation.quote, expected_input_data, Some(pccs)) - .await - .unwrap(); + verify_dcap_attestation(quote, expected_input_data, Some(pccs)).await.unwrap(); assert_eq!(measurements, crate::measurements::mock_dcap_measurements()); assert_eq!(mock_pcs.tcb_call_count(), 1); diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index a649cca..7b0aa39 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -283,10 +283,17 @@ impl AttestationGenerator { } } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { - let mut attestation_evidence = dcap::create_dcap_attestation(input_data)?; - attestation_evidence.platform.attestation_type = - self.attestation_type.try_into()?; - Ok(attestation_evidence.into()) + #[cfg(any(test, feature = "mock"))] + let platform = placeholder_platform_metadata(self.attestation_type)?; + #[cfg(not(any(test, feature = "mock")))] + let platform = + attest_measure::platform::metadata_for(self.attestation_type.try_into()?)?; + Ok(AttestationExchangeMessage { + attestation_evidence: Some(AttestationEvidence { + quote: dcap::create_dcap_attestation(input_data)?, + platform, + }), + }) } } } @@ -814,7 +821,11 @@ mod tests { #[tokio::test] async fn mock_verifier_supports_sync_verification() { let input_data = [7u8; 64]; - let attestation = dcap::create_dcap_attestation(input_data).unwrap(); + let quote = dcap::create_dcap_attestation(input_data).unwrap(); + let attestation_evidence = AttestationEvidence { + quote, + platform: placeholder_platform_metadata(AttestationType::GcpTdx).unwrap(), + }; let mock_pcs_server = spawn_mock_pcs_server(MockPcsConfig::default()).await.unwrap(); @@ -823,7 +834,7 @@ mod tests { pccs.ready().await.unwrap(); } - let result = verifier.verify_attestation_sync(attestation.into(), input_data); + let result = verifier.verify_attestation_sync(attestation_evidence.into(), input_data); assert!(result.is_ok(), "expected sync mock verification to succeed: {result:?}"); } diff --git a/crates/mock-tdx/Cargo.toml b/crates/mock-tdx/Cargo.toml index b34c49f..f13c39f 100644 --- a/crates/mock-tdx/Cargo.toml +++ b/crates/mock-tdx/Cargo.toml @@ -21,7 +21,6 @@ tokio = { workspace = true, features = ["rt", "net"] } urlencoding = "2.1.3" yasna = "0.5.2" x509-parser = "0.18.1" -attest-types = { git = "https://github.com/easy-tee/attest.git", branch = "ah/gcp-hobgen" } [lints] workspace = true diff --git a/crates/mock-tdx/src/lib.rs b/crates/mock-tdx/src/lib.rs index ba021d9..50a2989 100644 --- a/crates/mock-tdx/src/lib.rs +++ b/crates/mock-tdx/src/lib.rs @@ -1,6 +1,5 @@ pub mod mock_pcs; -use attest_types::{AttestationEvidence, PlatformMetadata}; use dcap_qvl::{ QuoteCollateralV3, quote::{ @@ -107,17 +106,9 @@ pub(crate) fn signing_key_from_secret( /// Generate a mock TDX DCAP quote using the generated fixture material pub fn generate_mock_tdx_quote( report_data: [u8; 64], -) -> Result> { +) -> Result, Box> { let collateral = mock_collateral(); - Ok(AttestationEvidence { - quote: generate_mock_tdx_quote_with_collateral(&collateral, report_data)?, - platform: PlatformMetadata { - attestation_type: attest_types::AttestationType::GcpTdx, - num_disks: 0, - ram_bytes: 0, - acpi: None, - }, - }) + generate_mock_tdx_quote_with_collateral(&collateral, report_data) } /// Generate a mock TDX DCAP quote from a specific loaded material set @@ -259,8 +250,8 @@ mod tests { fn builds_quote_that_parses_and_verifies() { let report_data = [0xAB; 64]; - let attestation_evidence = generate_mock_tdx_quote(report_data).unwrap(); - let quote = Quote::parse(&attestation_evidence.quote).unwrap(); + let quote_bytes = generate_mock_tdx_quote(report_data).unwrap(); + let quote = Quote::parse("e_bytes).unwrap(); assert_eq!(quote.header.version, QUOTE_VERSION); assert_eq!(quote.header.tee_type, TEE_TYPE_TDX); @@ -270,8 +261,7 @@ mod tests { assert_eq!(quote.ca().unwrap(), "processor"); let verifier = mock_dcap_verifier(); - let verified = - verifier.verify(&attestation_evidence.quote, &collateral, FIXTURE_TIME).unwrap(); + let verified = verifier.verify("e_bytes, &collateral, FIXTURE_TIME).unwrap(); let dcap_qvl::quote::Report::TD10(report) = verified.report else { panic!("expected TD10 report"); }; @@ -286,13 +276,13 @@ mod tests { const TD_REPORT10_BYTE_LEN: usize = 584; const AUTH_DATA_SIZE_BYTE_LEN: usize = 4; - let mut attestation_evidence = generate_mock_tdx_quote([0xCD; 64]).unwrap(); + let mut quote_bytes = generate_mock_tdx_quote([0xCD; 64]).unwrap(); let signature_offset = HEADER_BYTE_LEN + TD_REPORT10_BYTE_LEN + AUTH_DATA_SIZE_BYTE_LEN; - attestation_evidence.quote[signature_offset] ^= 0x01; + quote_bytes[signature_offset] ^= 0x01; let verifier = mock_dcap_verifier(); let collateral = mock_collateral(); - assert!(verifier.verify(&attestation_evidence.quote, &collateral, FIXTURE_TIME).is_err()); + assert!(verifier.verify("e_bytes, &collateral, FIXTURE_TIME).is_err()); } #[test] @@ -304,11 +294,11 @@ mod tests { assert!(!EMBEDDED_ROOT_CA_DER.is_empty()); assert!(collateral.pck_certificate_chain.is_some()); - let attestation_evidence = generate_mock_tdx_quote([0xEF; 64]).unwrap(); - let quote = Quote::parse(&attestation_evidence.quote).unwrap(); + let quote_bytes = generate_mock_tdx_quote([0xEF; 64]).unwrap(); + let quote = Quote::parse("e_bytes).unwrap(); assert_eq!(hex::encode_upper(quote.fmspc().unwrap()), tcb_info.fmspc); assert_eq!(quote.header.pce_svn, tcb_info.tcb_levels[0].tcb.pce_svn); - verifier.verify(&attestation_evidence.quote, &collateral, FIXTURE_TIME).unwrap(); + verifier.verify("e_bytes, &collateral, FIXTURE_TIME).unwrap(); } } From 59dd749511d76c3142b9ab6d8896e970c5a5d9a2 Mon Sep 17 00:00:00 2001 From: peg Date: Thu, 2 Jul 2026 11:32:36 +0200 Subject: [PATCH 26/35] Switch to using pinned commit from head of main of attest repo now that ah/gcp-hobgen has been merged --- Cargo.lock | 4 ++-- crates/attestation/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2641577..81e0888 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -346,7 +346,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attest-measure" version = "0.0.1" -source = "git+https://github.com/easy-tee/attest.git?branch=ah%2Fgcp-hobgen#e5f89321d37dbbd3b7ccc4cfee4e715dd440ffdf" +source = "git+https://github.com/easy-tee/attest.git?rev=a64f147362b8948e2288015e476c40d04b11b661#a64f147362b8948e2288015e476c40d04b11b661" dependencies = [ "anyhow", "attest-types", @@ -369,7 +369,7 @@ dependencies = [ [[package]] name = "attest-types" version = "0.0.1" -source = "git+https://github.com/easy-tee/attest.git?branch=ah%2Fgcp-hobgen#e5f89321d37dbbd3b7ccc4cfee4e715dd440ffdf" +source = "git+https://github.com/easy-tee/attest.git?rev=a64f147362b8948e2288015e476c40d04b11b661#a64f147362b8948e2288015e476c40d04b11b661" dependencies = [ "parity-scale-codec", "serde", diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml index 9ae93bf..e9df0f3 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -13,8 +13,8 @@ pccs = { workspace = true } mock-tdx = { workspace = true, optional = true } tokio = { workspace = true, features = ["fs"] } tokio-rustls = { workspace = true, default-features = false } -attest-types = { git = "https://github.com/easy-tee/attest.git", branch = "ah/gcp-hobgen" } -attest-measure = {git = "https://github.com/easy-tee/attest.git", branch = "ah/gcp-hobgen" } +attest-types = { git = "https://github.com/easy-tee/attest.git", rev = "a64f147362b8948e2288015e476c40d04b11b661" } +attest-measure = {git = "https://github.com/easy-tee/attest.git", rev = "a64f147362b8948e2288015e476c40d04b11b661" } anyhow = "1.0.100" pem-rfc7468 = { version = "0.7.0", features = ["std"] } From f002fa6ced4cf944848f31f8a48ed849a17613c5 Mon Sep 17 00:00:00 2001 From: peg Date: Thu, 2 Jul 2026 12:01:31 +0200 Subject: [PATCH 27/35] Never use placeholder platform metadata in production - drop support for dstack ratls built attested certs, and attestation provider server implementations other than our own --- crates/attestation/src/lib.rs | 111 +++++++-------------------------- crates/attested-tls/src/lib.rs | 26 +++----- 2 files changed, 28 insertions(+), 109 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 7b0aa39..8d66cae 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -106,19 +106,6 @@ impl TryFrom for attest_types::AttestationType { } } -/// WIP - create placeholder platform metadata when we don't have it. -/// Used for attestation provider server - which should be fixed. -fn placeholder_platform_metadata( - attestation_type: AttestationType, -) -> Result { - Ok(PlatformMetadata { - attestation_type: attestation_type.try_into()?, - ram_bytes: 0, - num_disks: 0, - acpi: None, - }) -} - /// Type of attestation used /// Only supported (or soon-to-be supported) types are given #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -284,7 +271,7 @@ impl AttestationGenerator { } AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { #[cfg(any(test, feature = "mock"))] - let platform = placeholder_platform_metadata(self.attestation_type)?; + let platform = mock_platform_metadata(self.attestation_type)?; #[cfg(not(any(test, feature = "mock")))] let platform = attest_measure::platform::metadata_for(self.attestation_type.try_into()?)?; @@ -306,6 +293,10 @@ impl AttestationGenerator { attestation_type: AttestationType, input_data: [u8; 64], ) -> Result { + if attestation_type == AttestationType::None { + return Ok(AttestationExchangeMessage::without_attestation()); + } + let url = format!("{}/attest/{}", url, hex::encode(input_data)); let mut response = ureq::get(&url) @@ -318,20 +309,8 @@ impl AttestationGenerator { .read_to_end(&mut body) .map_err(|err| AttestationError::AttestationProvider(err.to_string()))?; - // If the response is not already wrapped in an attestation exchange - // message, wrap it in one - if let Ok(message) = AttestationExchangeMessage::decode(&mut &body[..]) { - Ok(message) - } else { - if attestation_type == AttestationType::None { - return Ok(AttestationExchangeMessage::without_attestation()); - } - - let platform = placeholder_platform_metadata(attestation_type)?; - Ok(AttestationExchangeMessage { - attestation_evidence: Some(AttestationEvidence { quote: body, platform }), - }) - } + AttestationExchangeMessage::decode(&mut &body[..]) + .map_err(|err| AttestationError::AttestationProvider(err.to_string())) } } @@ -694,6 +673,19 @@ fn is_local_ip(ip: IpAddr) -> bool { } } +#[cfg(any(test, feature = "mock"))] +/// Create mock platform metadata for tests +pub fn mock_platform_metadata( + attestation_type: AttestationType, +) -> Result { + Ok(PlatformMetadata { + attestation_type: attestation_type.try_into()?, + ram_bytes: 0, + num_disks: 0, + acpi: None, + }) +} + /// An error when generating or verifying an attestation #[derive(Error, Debug)] pub enum AttestationError { @@ -742,35 +734,9 @@ pub enum AttestationError { #[cfg(test)] mod tests { use mock_tdx::mock_pcs::{MockPcsConfig, spawn_mock_pcs_server}; - use tokio::{ - io::{AsyncReadExt, AsyncWriteExt}, - net::TcpListener, - }; use super::*; - async fn spawn_test_attestation_provider_server(body: Vec) -> std::net::SocketAddr { - let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = listener.local_addr().unwrap(); - - tokio::spawn(async move { - if let Ok((mut socket, _)) = listener.accept().await { - let mut buf = [0u8; 1024]; - let _ = socket.read(&mut buf).await; - - let response = format!( - "HTTP/1.1 200 OK\r\nContent-Length: {}\r\nConnection: close\r\n\r\n", - body.len() - ); - let _ = socket.write_all(response.as_bytes()).await; - let _ = socket.write_all(&body).await; - let _ = socket.shutdown().await; - } - }); - - addr - } - #[test] fn attestation_detection_does_not_panic() { // We dont enforce what platform the test is run on, only that the function @@ -783,48 +749,13 @@ mod tests { let _ = running_on_gcp(); } - #[tokio::test(flavor = "multi_thread")] - async fn attestation_provider_response_is_wrapped_if_needed() { - let input_data = [0u8; 64]; - - let encoded_message = AttestationExchangeMessage { - attestation_evidence: Some(AttestationEvidence { - quote: vec![1, 2, 3], - platform: placeholder_platform_metadata(AttestationType::GcpTdx).unwrap(), - }), - } - .encode(); - - let encoded_addr = spawn_test_attestation_provider_server(encoded_message).await; - let encoded_url = format!("http://{encoded_addr}"); - let decoded = AttestationGenerator::use_attestation_provider( - &encoded_url, - AttestationType::GcpTdx, - input_data, - ) - .unwrap(); - assert_eq!(decoded.attestation_type(), AttestationType::GcpTdx); - assert_eq!(decoded.attestation_evidence.unwrap().quote, vec![1, 2, 3]); - - let raw_addr = spawn_test_attestation_provider_server(vec![9, 8]).await; - let raw_url = format!("http://{raw_addr}"); - let wrapped = AttestationGenerator::use_attestation_provider( - &raw_url, - AttestationType::DcapTdx, - input_data, - ) - .unwrap(); - assert_eq!(wrapped.attestation_type(), AttestationType::QemuTdx); - assert_eq!(wrapped.attestation_evidence.unwrap().quote, vec![9, 8]); - } - #[tokio::test] async fn mock_verifier_supports_sync_verification() { let input_data = [7u8; 64]; let quote = dcap::create_dcap_attestation(input_data).unwrap(); let attestation_evidence = AttestationEvidence { quote, - platform: placeholder_platform_metadata(AttestationType::GcpTdx).unwrap(), + platform: mock_platform_metadata(AttestationType::GcpTdx).unwrap(), }; let mock_pcs_server = spawn_mock_pcs_server(MockPcsConfig::default()).await.unwrap(); diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index 2d902c4..a9396ed 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -536,25 +536,13 @@ impl AttestedCertificateVerifier { ra_tls::attestation::from_cert(cert) && let AttestationQuote::DstackTdx(tdx_quote) = attestation.quote { - if let Ok(message) = - serde_json::from_slice::(&tdx_quote.quote) - { - return Ok(message); - } - - // TODO maybe we have to drop support for the VersionedAttestation::V0 - // format as it cannot encode platform metadata - return Ok(AttestationExchangeMessage { - attestation_evidence: Some(AttestationEvidence { - quote: tdx_quote.quote, - platform: PlatformMetadata { - attestation_type: AttestationType::DcapTdx.try_into().expect("AttestationType::DcapTdx should convert to attest-types::AttestationType::SelfHosted"), - ram_bytes: 0, - num_disks: 0, - acpi: None, - }, - }), - }); + return serde_json::from_slice::(&tdx_quote.quote).map_err( + |err| { + rustls::Error::General(format!( + "Failed to parse AttestationExchangeMessage: {err:?}" + )) + }, + ); } // If that fails, extract and parse the extension From bd68d39987851d07b4c15c043b2cb6bc0ff9d55e Mon Sep 17 00:00:00 2001 From: peg Date: Thu, 2 Jul 2026 12:11:40 +0200 Subject: [PATCH 28/35] Warn and bail when trying to match non-gcp measurements with portable measurement policy --- crates/attestation/src/measurements.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index c644cf8..ce7cfb7 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -439,8 +439,16 @@ impl MeasurementPolicy { } } } - ImageAttestationType::SelfHostedTdx => None, - ImageAttestationType::AzureTdx => return false, + // These may be supported in the future but currently regarded as too + // experimental to work with 'portable' measurement policies + ImageAttestationType::SelfHostedTdx => { + warn!("Attempting to match portable measurement policy with bare metal TDX - not yet supported"); + return false; + }, + ImageAttestationType::AzureTdx => { + warn!("Attempting to match portable measurement policy with Azure TDX - not yet supported"); + return false; + }, }; let expected_measurements = match expected_dcap_registers( From 202434386c82a55d357d351df59e57df063e07a0 Mon Sep 17 00:00:00 2001 From: peg Date: Thu, 2 Jul 2026 13:02:19 +0200 Subject: [PATCH 29/35] Update measurements JSON format and cover the new format in tests --- crates/attestation/src/measurements.rs | 132 ++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 12 deletions(-) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index ce7cfb7..591ce1d 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -276,6 +276,10 @@ pub enum MeasurementFormatError { NoExpectedValue(String), #[error("Measurement entry for register '{0}' has empty 'expected_any' list")] EmptyExpectedAny(String), + #[error("Measurement record has both 'measurements' and 'dcap_image_hashes' — set only one")] + BothMeasurementsAndDcapImageHashes, + #[error("Attestation type '{0}' does not support 'dcap_image_hashes'")] + DcapImageHashesUnsupportedAttestationType(String), } /// An accepted measurement value given in the measurements file @@ -556,6 +560,9 @@ impl MeasurementPolicy { measurement_id: Option, attestation_type: String, measurements: Option>, + /// Image-component hashes for "portable" verification. + /// Mutually exclusive with `measurements`. + dcap_image_hashes: Option, } /// Measurement entry for a single register in the measurements JSON @@ -614,11 +621,14 @@ impl MeasurementPolicy { let mut measurement_policy = Vec::new(); for record in records_simple { - let attestation_type = - serde_json::from_value(serde_json::Value::String(record.attestation_type))?; + let attestation_type: AttestationType = + serde_json::from_value(serde_json::Value::String(record.attestation_type.clone()))?; - if let Some(measurements) = record.measurements { - let expected_measurements = match attestation_type { + let expected_measurements = match (record.measurements, record.dcap_image_hashes) { + (Some(_), Some(_)) => { + return Err(MeasurementFormatError::BothMeasurementsAndDcapImageHashes); + } + (Some(measurements), None) => match attestation_type { AttestationType::None => ExpectedMeasurements::NoAttestation, AttestationType::AzureTdx => { let azure_measurements = measurements @@ -647,15 +657,33 @@ impl MeasurementPolicy { MeasurementFormatError, >>()?, ), - }; - - measurement_policy.push(MeasurementRecord { - measurement_id: record.measurement_id.unwrap_or_default(), - measurements: expected_measurements, - }); - } else { - measurement_policy.push(MeasurementRecord::allow_any_measurement(attestation_type)); + }, + (None, Some(image_hashes)) => match attestation_type { + // Currently only GCP is supported for portable measurement policy - but support + // for other types is planned + AttestationType::GcpTdx => ExpectedMeasurements::Image(image_hashes), + AttestationType::DcapTdx | + AttestationType::QemuTdx | + AttestationType::None | + AttestationType::AzureTdx => { + return Err( + MeasurementFormatError::DcapImageHashesUnsupportedAttestationType( + record.attestation_type, + ), + ); + } + }, + (None, None) => { + measurement_policy + .push(MeasurementRecord::allow_any_measurement(attestation_type)); + continue; + } }; + + measurement_policy.push(MeasurementRecord { + measurement_id: record.measurement_id.unwrap_or_default(), + measurements: expected_measurements, + }); } Ok(MeasurementPolicy { accepted_measurements: measurement_policy }) @@ -888,6 +916,86 @@ mod tests { } } + /// A JSON policy that pins image-component hashes rather than raw + /// register values must parse into [`ExpectedMeasurements::Image`] + /// so the verifier can reconstruct the expected RTMRs from platform + /// metadata and firmware + #[tokio::test] + async fn test_parse_image_hash_policy() { + let json = r#"[ + { + "measurement_id": "gcp-image-hash-example", + "attestation_type": "gcp-tdx", + "dcap_image_hashes": { + "uki_authenticode": "fcaceb6d87694746ba2d93a87ef4209f2a7629b7f400097b93241e80b9ec3e1e80f9a4cd8028e6a83f297ea5de8d9abc", + "kernel_authenticode": "b6c5133268aa8b440509f3d53ee855a5cd3aeb6441eb109a9f27f14c43bce3e2383856df4af876501ceeb4c9a3b15f0c", + "cmdline_hash": "e03b89abf354a38976537b7a9138fd312e4cbf73b61eebc44086491701b1d167b9f6cb97a922325866c93e0834723d87", + "initrd_hash": "a5b3d4742045e7d08aa19953c35098e784826b01a84f60568fa69f1a848dafd96ec98b8df616d6142779c9b97318166b", + "gpt_disk_guid_hash": "180bac1af9c35cc15e909623c005289539b4da2840d9c9b658fd4968ea4f03e0159402d03da1afc9035e0db30804e282" + } + } + ]"#; + + let policy = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()).unwrap(); + assert_eq!(policy.accepted_measurements.len(), 1); + assert!(matches!( + policy.accepted_measurements[0].measurements, + ExpectedMeasurements::Image(_) + )); + } + + /// A record cannot specify both raw register values and image-component + /// hashes as they express the same intent through different schemas. + #[tokio::test] + async fn test_parse_rejects_both_measurements_and_dcap_image_hashes() { + let json = r#"[ + { + "attestation_type": "gcp-tdx", + "measurements": { + "mrtd": { + "expected_any": [ + "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + ] + } + }, + "dcap_image_hashes": { + "uki_authenticode": "fcaceb6d87694746ba2d93a87ef4209f2a7629b7f400097b93241e80b9ec3e1e80f9a4cd8028e6a83f297ea5de8d9abc", + "kernel_authenticode": "b6c5133268aa8b440509f3d53ee855a5cd3aeb6441eb109a9f27f14c43bce3e2383856df4af876501ceeb4c9a3b15f0c", + "cmdline_hash": "e03b89abf354a38976537b7a9138fd312e4cbf73b61eebc44086491701b1d167b9f6cb97a922325866c93e0834723d87", + "initrd_hash": "a5b3d4742045e7d08aa19953c35098e784826b01a84f60568fa69f1a848dafd96ec98b8df616d6142779c9b97318166b", + "gpt_disk_guid_hash": "180bac1af9c35cc15e909623c005289539b4da2840d9c9b658fd4968ea4f03e0159402d03da1afc9035e0db30804e282" + } + } + ]"#; + + let result = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()); + assert!(matches!(result, Err(MeasurementFormatError::BothMeasurementsAndDcapImageHashes))); + } + + /// Using one of the not yet supported attestation types with + /// dcap_image_hashes fails + #[tokio::test] + async fn test_parse_rejects_unsupported_attestation_type_for_image_hashes() { + let json = r#"[ + { + "attestation_type": "azure-tdx", + "dcap_image_hashes": { + "uki_authenticode": "fcaceb6d87694746ba2d93a87ef4209f2a7629b7f400097b93241e80b9ec3e1e80f9a4cd8028e6a83f297ea5de8d9abc", + "kernel_authenticode": "b6c5133268aa8b440509f3d53ee855a5cd3aeb6441eb109a9f27f14c43bce3e2383856df4af876501ceeb4c9a3b15f0c", + "cmdline_hash": "e03b89abf354a38976537b7a9138fd312e4cbf73b61eebc44086491701b1d167b9f6cb97a922325866c93e0834723d87", + "initrd_hash": "a5b3d4742045e7d08aa19953c35098e784826b01a84f60568fa69f1a848dafd96ec98b8df616d6142779c9b97318166b", + "gpt_disk_guid_hash": "180bac1af9c35cc15e909623c005289539b4da2840d9c9b658fd4968ea4f03e0159402d03da1afc9035e0db30804e282" + } + } + ]"#; + + let result = MeasurementPolicy::from_json_bytes(json.as_bytes().to_vec()); + assert!(matches!( + result, + Err(MeasurementFormatError::DcapImageHashesUnsupportedAttestationType(_)) + )); + } + #[tokio::test] async fn test_check_measurement_with_or_semantics() { let json = r#"[ From 0f67d370cd89e21bce6c28bb302c0e9bcb9146c5 Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 3 Jul 2026 09:27:44 +0200 Subject: [PATCH 30/35] Document new measurement policy type --- crates/attestation/README.md | 65 +++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/crates/attestation/README.md b/crates/attestation/README.md index 5620969..65c3922 100644 --- a/crates/attestation/README.md +++ b/crates/attestation/README.md @@ -106,6 +106,13 @@ These objects have the following fields: - `measurements` - an object with fields referring to the five measurement registers. Field names are the same as for the measurement headers (see below). +- `dcap_image_hashes` - an alternative to `measurements` that pins the hashes + of the boot components (UKI, kernel, initrd, cmdline, GPT disk GUID) rather + than raw register values. The verifier reconstructs the expected RTMRs at + check time from these hashes and platform-fetched firmware. See + [Portable measurement policies](#portable-measurement-policies) below. + +A record may set either `measurements` or `dcap_image_hashes`, not both. Each measurement register entry supports two mutually exclusive fields: @@ -190,10 +197,11 @@ compatibility: The only mandatory field is `attestation_type`. If an attestation type is -specified, but no measurements, *any* measurements will be accepted for this -attestation type. The measurements can still be checked up-stream by the source -client or target service using header injection described below. But it is then -up to these external programs to reject unacceptable measurements. +specified with neither `measurements` nor `dcap_image_hashes`, *any* +measurements will be accepted for this attestation type. The measurements can +still be checked up-stream by the source client or target service using header +injection for example. But it is then up to external programs to reject +unacceptable measurements. ### Measurement field names @@ -240,3 +248,52 @@ Legacy numeric field names are still supported for backwards compatibility: - "2" - RTMR1 - "3" - RTMR2 - "4" - RTMR3 + +### Portable measurement policies + +The `measurements` format above specifies register values, so any change +to platform-injected values (firmware, RAM size, disk count, ACPI tables) +changes the expected register values even when the OS image is unchanged. + +The `dcap_image_hashes` alternative allows you to specify the OS image's +boot-component hashes instead, and the verifier reconstructs the expected +register values from those hashes plus platform metadata fetched attest +verification time. The same policy record then matches the same OS images +across platform variants. + +This can be done with the `attest measure` CLI from +[Easy-TEE/attest](https://github.com/Easy-TEE/attest) which outputs five +hex-encoded SHA-384 values: + +- `uki_authenticode` - authenticode hash of the UKI (unified kernel image) +- `kernel_authenticode` - authenticode hash of the kernel binary +- `cmdline_hash` - hash of the kernel command line +- `initrd_hash` - hash of the initramfs +- `gpt_disk_guid_hash` - hash derived from GPT partition GUIDs + +Example: + +```JSON +[ + { + "measurement_id": "flashbox-l1-v1.0.0", + "attestation_type": "gcp-tdx", + "dcap_image_hashes": { + "uki_authenticode": "fcaceb6d87694746ba2d93a87ef4209f2a7629b7f400097b93241e80b9ec3e1e80f9a4cd8028e6a83f297ea5de8d9abc", + "kernel_authenticode": "b6c5133268aa8b440509f3d53ee855a5cd3aeb6441eb109a9f27f14c43bce3e2383856df4af876501ceeb4c9a3b15f0c", + "cmdline_hash": "e03b89abf354a38976537b7a9138fd312e4cbf73b61eebc44086491701b1d167b9f6cb97a922325866c93e0834723d87", + "initrd_hash": "a5b3d4742045e7d08aa19953c35098e784826b01a84f60568fa69f1a848dafd96ec98b8df616d6142779c9b97318166b", + "gpt_disk_guid_hash": "180bac1af9c35cc15e909623c005289539b4da2840d9c9b658fd4968ea4f03e0159402d03da1afc9035e0db30804e282" + } + } +] +``` + +#### Supported attestation types for portable measurements + +Portable policies currently only work with the `"gcp-tdx"` attestation type. +For GCP, the verifier fetches the platform firmware blob from Google's metadata +service (keyed by MRTD) and combines it with the image hashes to reconstruct +the expected registers. Support for other attestation types is planned; but +`dcap_image_hashes` record with any other attestation type is rejected at when +parsing from JSON. From 7dd722393c3a090e251c41412b472980802a1201 Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 3 Jul 2026 09:49:03 +0200 Subject: [PATCH 31/35] Improve error handling during measurement checks --- crates/attestation/src/measurements.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index 591ce1d..2395757 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -393,6 +393,9 @@ impl MeasurementPolicy { self.check_measurement_with_gcp_cache(measurements, platform_metadata, None) } + /// Given an attestation type and set of measurements, check whether + /// they are acceptable, passing an optional cache for known GCP + /// firmware pub(crate) fn check_measurement_with_gcp_cache( &self, measurements: &MultiMeasurements, @@ -463,7 +466,7 @@ impl MeasurementPolicy { Ok(expected) => expected, Err(err) => { warn!("Failed to compute expected DCAP registers: {err:?}"); - return false; // TODO should we bail here + return false; } }; @@ -472,6 +475,10 @@ impl MeasurementPolicy { Some(mrtd) if mrtd == &expected_mrtd => {} _ => return false, } + } else { + // This will only be the case with SelfHostedTdx which currently would + // already bail with the check above + return false; } if let Some(expected_rtmr0) = expected_measurements.rtmr0 { @@ -479,6 +486,10 @@ impl MeasurementPolicy { Some(rtmr0) if rtmr0 == &expected_rtmr0 => {} _ => return false, } + } else { + // This will only be the case with SelfHostedTdx which currently would + // already bail with the check above + return false; } if let Some(rtmr1) = dcap_measurements.get(&DcapMeasurementRegister::RTMR1) From 17ac5d619d84db170ca39e6e08fd405d3a3edb65 Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 3 Jul 2026 11:06:16 +0200 Subject: [PATCH 32/35] Revert changes from merge commit which are unrelated to this PR --- crates/attestation/src/azure/mod.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 5a59766..42c88ed 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -802,7 +802,7 @@ mod tests { /// 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_attestation_with_ak_intermediates() { + async fn test_verify() { // generated using [capture_azure_fixture] above. let attestation_bytes: &'static [u8] = include_bytes!("../../test-assets/azure-tdx-with-ak-intermediates-1780922561.yaml"); @@ -850,15 +850,14 @@ mod tests { #[tokio::test] async fn test_verify_fails_on_input_mismatch() { let attestation_bytes: &'static [u8] = - include_bytes!("../../test-assets/azure-tdx-with-ak-intermediates-1780922561.yaml"); - let now = 1_780_922_561; + include_bytes!("../../test-assets/azure-tdx-1764662251380464271.yaml"); + let now = 1771423480; let mut expected_input_data = input_data_from_attestation(attestation_bytes); expected_input_data[63] ^= 0x01; - let collateral_bytes: &'static [u8] = include_bytes!( - "../../test-assets/azure-collateral-with-ak-intermediates-1780922561.yaml" - ); + let collateral_bytes: &'static [u8] = + include_bytes!("../../test-assets/azure-collateral02.yaml"); let collateral = serde_saphyr::from_slice(collateral_bytes).unwrap(); let attestation_json = serde_json::to_vec( &serde_saphyr::from_slice::(attestation_bytes).unwrap(), From 5790f1917d095e88fda26e2c85ac0b81d3fbb9de Mon Sep 17 00:00:00 2001 From: peg Date: Fri, 3 Jul 2026 11:41:06 +0200 Subject: [PATCH 33/35] On tokio runtime, wrap GCP firmware fetch in spawn_blocking to avoid stalling async workers --- crates/attestation/Cargo.toml | 2 +- crates/attestation/README.md | 2 +- crates/attestation/src/gcp.rs | 24 +++++++++++++++++++++++- crates/attestation/src/measurements.rs | 11 +++++------ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml index e9df0f3..52403b3 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["attestation", "CVM", "TDX"] dcap-qvl = { workspace = true, features = ["danger-allow-tcb-override"] } pccs = { workspace = true } mock-tdx = { workspace = true, optional = true } -tokio = { workspace = true, features = ["fs"] } +tokio = { workspace = true, features = ["fs", "rt", "rt-multi-thread"] } tokio-rustls = { workspace = true, default-features = false } attest-types = { git = "https://github.com/easy-tee/attest.git", rev = "a64f147362b8948e2288015e476c40d04b11b661" } attest-measure = {git = "https://github.com/easy-tee/attest.git", rev = "a64f147362b8948e2288015e476c40d04b11b661" } diff --git a/crates/attestation/README.md b/crates/attestation/README.md index 65c3922..d487292 100644 --- a/crates/attestation/README.md +++ b/crates/attestation/README.md @@ -295,5 +295,5 @@ Portable policies currently only work with the `"gcp-tdx"` attestation type. For GCP, the verifier fetches the platform firmware blob from Google's metadata service (keyed by MRTD) and combines it with the image hashes to reconstruct the expected registers. Support for other attestation types is planned; but -`dcap_image_hashes` record with any other attestation type is rejected at when +`dcap_image_hashes` record with any other attestation type is rejected when parsing from JSON. diff --git a/crates/attestation/src/gcp.rs b/crates/attestation/src/gcp.rs index 5d6fdfe..26f2488 100644 --- a/crates/attestation/src/gcp.rs +++ b/crates/attestation/src/gcp.rs @@ -29,7 +29,7 @@ impl GcpFirmwareCache { return Ok(firmware); } - let firmware = DcapFirmware::from_google(mrtd)?; + let firmware = fetch_firmware(mrtd)?; self.cache .write() .map_err(|_| GcpFirmwareCacheError::CacheLock)? @@ -38,12 +38,34 @@ impl GcpFirmwareCache { } } +/// Fetch firmware from Google. If we are running inside a mutli-threaded +/// tokio runtime the blocking HTTP fetch is wrapped in `spawn_blocking` +pub(crate) fn fetch_firmware(mrtd: [u8; 48]) -> Result { + match tokio::runtime::Handle::try_current() { + Ok(handle) + if matches!(handle.runtime_flavor(), tokio::runtime::RuntimeFlavor::MultiThread) => + { + tokio::task::block_in_place(|| { + handle.block_on(async move { + tokio::task::spawn_blocking(move || DcapFirmware::from_google(mrtd)) + .await + .map_err(|err| GcpFirmwareCacheError::Join(err.to_string()))? + .map_err(GcpFirmwareCacheError::from) + }) + }) + } + _ => DcapFirmware::from_google(mrtd).map_err(GcpFirmwareCacheError::from), + } +} + #[derive(Debug, Error)] pub(crate) enum GcpFirmwareCacheError { #[error("Cache lock poisoned")] CacheLock, #[error("Firmware fetch: {0}")] Firmware(#[from] attest_measure::dcap::GoogleError), + #[error("Firmware fetch task join: {0}")] + Join(String), } #[cfg(test)] diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index 2395757..f42dfe3 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -2,7 +2,7 @@ //! attestation use std::{collections::HashMap, fmt, fmt::Formatter, net::IpAddr, path::PathBuf}; -use attest_measure::dcap::{DcapFirmware, expected_dcap_registers}; +use attest_measure::dcap::expected_dcap_registers; use attest_types::{AttestationType as ImageAttestationType, DcapImageHashes, PlatformMetadata}; use dcap_qvl::quote::Report; use http::{HeaderValue, header::InvalidHeaderValue, uri::InvalidUri}; @@ -14,7 +14,7 @@ use crate::{ AttestationError, AttestationType, dcap::DcapVerificationError, - gcp::{GcpFirmwareCache, GcpFirmwareCacheError}, + gcp::{GcpFirmwareCache, fetch_firmware}, }; /// Represents the measurement register types in a TDX quote @@ -433,8 +433,7 @@ impl MeasurementPolicy { let result = if let Some(cache) = known_gcp_firmware { cache.get_or_fetch(*mrtd) } else { - DcapFirmware::from_google(*mrtd) - .map_err(GcpFirmwareCacheError::from) + fetch_firmware(*mrtd) }; match result { Ok(firmware) => Some(firmware), @@ -506,7 +505,7 @@ impl MeasurementPolicy { true } - _ => false, + ExpectedMeasurements::Azure(_) | ExpectedMeasurements::NoAttestation => false, } } MultiMeasurements::Azure(azure_measurements) => { @@ -719,7 +718,7 @@ impl MeasurementPolicy { mod tests { use std::collections::HashSet; - use attest_measure::dcap::expected_dcap_registers; + use attest_measure::dcap::{DcapFirmware, expected_dcap_registers}; use attest_types::AcpiHashes; use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64_STANDARD}; From f4f4011b4bf1ef360b3e4058c54273aa5a8e4dd1 Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 7 Jul 2026 08:36:41 +0200 Subject: [PATCH 34/35] Fixes following review --- crates/attestation/src/gcp.rs | 28 ++++++++++---------------- crates/attestation/src/lib.rs | 4 ++-- crates/attestation/src/measurements.rs | 6 +++--- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/crates/attestation/src/gcp.rs b/crates/attestation/src/gcp.rs index 26f2488..a85d0be 100644 --- a/crates/attestation/src/gcp.rs +++ b/crates/attestation/src/gcp.rs @@ -10,7 +10,7 @@ use thiserror::Error; /// verification #[derive(Clone, Debug, Default)] pub(crate) struct GcpFirmwareCache { - cache: Arc>>, + cache: Arc>>, } impl GcpFirmwareCache { @@ -123,21 +123,15 @@ mod tests { ram_bytes: 17_179_869_184, num_disks: 1, acpi: Some(AcpiHashes { - loader: [ - 246, 12, 53, 229, 59, 178, 27, 70, 117, 207, 168, 219, 49, 14, 200, 142, 56, - 205, 54, 157, 141, 70, 58, 205, 222, 129, 81, 34, 250, 139, 137, 59, 136, 150, - 165, 120, 59, 83, 136, 86, 105, 62, 215, 100, 93, 219, 137, 126, - ], - rsdp: [ - 80, 157, 207, 225, 11, 235, 93, 71, 12, 64, 242, 94, 48, 137, 83, 112, 148, - 136, 49, 185, 207, 121, 219, 21, 217, 119, 231, 187, 168, 235, 66, 247, 32, 2, - 18, 7, 26, 216, 177, 157, 96, 17, 117, 151, 121, 236, 237, 90, - ], - tables: [ - 11, 176, 175, 160, 8, 135, 59, 220, 32, 222, 224, 247, 65, 218, 120, 150, 194, - 191, 238, 233, 74, 229, 46, 155, 219, 249, 75, 200, 124, 50, 208, 74, 75, 31, - 29, 130, 68, 144, 241, 218, 229, 116, 255, 109, 78, 75, 176, 179, - ], + loader: decode_dcap_hash( + "f60c35e53bb21b4675cfa8db310ec88e38cd369d8d463acdde815122fa8b893b8896a5783b538856693ed7645ddb897e", + ), + rsdp: decode_dcap_hash( + "509dcfe10beb5d470c40f25e30895370948831b9cf79db15d977e7bba8eb42f7200212071ad8b19d6011759779eced5a", + ), + tables: decode_dcap_hash( + "0bb0afa008873bdc20dee0f741da7896c2bfeee94ae52e9bdbf94bc87c32d04a4b1f1d824490f1dae574ff6d4e4bb0b3", + ), }), } } @@ -180,7 +174,7 @@ mod tests { measurement_policy .check_measurement_with_gcp_cache( &measurements, - Some(gcp_portable_platform_metadata()), + Some(&gcp_portable_platform_metadata()), Some(&gcp_firmware_cache), ) .unwrap(); diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 8d66cae..4fe5dd8 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -492,7 +492,7 @@ impl AttestationVerifier { .map(|evidence| evidence.platform.clone()); self.measurement_policy.check_measurement_with_gcp_cache( &measurements, - platform_metadata, + platform_metadata.as_ref(), Some(&self.known_gcp_firmware), )?; @@ -569,7 +569,7 @@ impl AttestationVerifier { .map(|evidence| evidence.platform.clone()); self.measurement_policy.check_measurement_with_gcp_cache( &measurements, - platform_metadata, + platform_metadata.as_ref(), Some(&self.known_gcp_firmware), )?; diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index f42dfe3..b4aaa58 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -388,7 +388,7 @@ impl MeasurementPolicy { pub fn check_measurement( &self, measurements: &MultiMeasurements, - platform_metadata: Option, + platform_metadata: Option<&PlatformMetadata>, ) -> Result<(), AttestationError> { self.check_measurement_with_gcp_cache(measurements, platform_metadata, None) } @@ -399,7 +399,7 @@ impl MeasurementPolicy { pub(crate) fn check_measurement_with_gcp_cache( &self, measurements: &MultiMeasurements, - platform_metadata: Option, + platform_metadata: Option<&PlatformMetadata>, known_gcp_firmware: Option<&GcpFirmwareCache>, ) -> Result<(), AttestationError> { if self.accepted_measurements.iter().any(|measurement_record| match measurements { @@ -870,7 +870,7 @@ mod tests { (DcapMeasurementRegister::RTMR3, mock_tdx::MOCK_RTMR3), ])); - policy.check_measurement(&measurements, Some(platform_metadata)).unwrap(); + policy.check_measurement(&measurements, Some(&platform_metadata)).unwrap(); } #[tokio::test] From 5ec1b1bc60c92f934e66a02c28a7351bbb478604 Mon Sep 17 00:00:00 2001 From: peg Date: Tue, 7 Jul 2026 09:34:47 +0200 Subject: [PATCH 35/35] Small refactor, stricter checks on DCAP measurement values being present --- crates/attestation/src/gcp.rs | 2 + crates/attestation/src/measurements.rs | 273 +++++++++++++------------ 2 files changed, 146 insertions(+), 129 deletions(-) diff --git a/crates/attestation/src/gcp.rs b/crates/attestation/src/gcp.rs index a85d0be..a8cd3f0 100644 --- a/crates/attestation/src/gcp.rs +++ b/crates/attestation/src/gcp.rs @@ -1,3 +1,5 @@ +//! Google Cloud Platform specific attestation logic + use std::{ collections::HashMap, sync::{Arc, RwLock}, diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index b4aaa58..fbdba06 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -243,45 +243,6 @@ pub fn mock_dcap_measurements() -> MultiMeasurements { ])) } -/// An error when converting measurements / to or from HTTP header format -#[derive(Error, Debug)] -pub enum MeasurementFormatError { - #[error("JSON: {0}")] - Json(#[from] serde_json::Error), - #[error("Missing value: {0}")] - MissingValue(String), - #[error("Invalid header value: {0}")] - BadHeaderValue(#[from] InvalidHeaderValue), - #[error("IO: {0}")] - Io(#[from] std::io::Error), - #[error("Attestation type not valid")] - AttestationTypeNotValid, - #[error("Hex: {0}")] - Hex(#[from] hex::FromHexError), - #[error("Expected 48 byte value")] - BadLength, - #[error("TDX quote register index must be in the ranger 0-3")] - BadRegisterIndex, - #[error("ParseInt: {0}")] - ParseInt(#[from] std::num::ParseIntError), - #[error("Failed to read measurements from URL: {0}")] - Reqwest(#[from] reqwest::Error), - #[error("Invalid URL: {0}")] - InvalidUri(#[from] InvalidUri), - #[error("Refusing to load measurement policy over plain HTTP from non-loopback host: {0}")] - InsecureHttpNotLoopback(String), - #[error("Measurement entry for register '{0}' has both 'expected' and 'expected_any'")] - BothExpectedAndExpectedAny(String), - #[error("Measurement entry for register '{0}' has neither 'expected' nor 'expected_any'")] - NoExpectedValue(String), - #[error("Measurement entry for register '{0}' has empty 'expected_any' list")] - EmptyExpectedAny(String), - #[error("Measurement record has both 'measurements' and 'dcap_image_hashes' — set only one")] - BothMeasurementsAndDcapImageHashes, - #[error("Attestation type '{0}' does not support 'dcap_image_hashes'")] - DcapImageHashesUnsupportedAttestationType(String), -} - /// An accepted measurement value given in the measurements file #[derive(Clone, Debug, PartialEq)] pub struct MeasurementRecord { @@ -415,96 +376,12 @@ impl MeasurementPolicy { } true } - ExpectedMeasurements::Image(image_hashes) => { - let Some(platform_metadata) = &platform_metadata else { - return false; - }; - let firmware = match platform_metadata.attestation_type { - ImageAttestationType::GcpTdx => { - let Some(mrtd) = - dcap_measurements.get(&DcapMeasurementRegister::MRTD) - else { - warn!( - "Could not match image hash measurement due to missing MRTD" - ); - return false; - }; - - let result = if let Some(cache) = known_gcp_firmware { - cache.get_or_fetch(*mrtd) - } else { - fetch_firmware(*mrtd) - }; - match result { - Ok(firmware) => Some(firmware), - Err(err) => { - warn!( - "Could not match image hash measurement - failed to fetch or verify Google firmware: {err:?}" - ); - return false; - } - } - } - // These may be supported in the future but currently regarded as too - // experimental to work with 'portable' measurement policies - ImageAttestationType::SelfHostedTdx => { - warn!("Attempting to match portable measurement policy with bare metal TDX - not yet supported"); - return false; - }, - ImageAttestationType::AzureTdx => { - warn!("Attempting to match portable measurement policy with Azure TDX - not yet supported"); - return false; - }, - }; - - let expected_measurements = match expected_dcap_registers( - image_hashes, - platform_metadata, - firmware.as_ref(), - ) { - Ok(expected) => expected, - Err(err) => { - warn!("Failed to compute expected DCAP registers: {err:?}"); - return false; - } - }; - - if let Some(expected_mrtd) = expected_measurements.mrtd { - match dcap_measurements.get(&DcapMeasurementRegister::MRTD) { - Some(mrtd) if mrtd == &expected_mrtd => {} - _ => return false, - } - } else { - // This will only be the case with SelfHostedTdx which currently would - // already bail with the check above - return false; - } - - if let Some(expected_rtmr0) = expected_measurements.rtmr0 { - match dcap_measurements.get(&DcapMeasurementRegister::RTMR0) { - Some(rtmr0) if rtmr0 == &expected_rtmr0 => {} - _ => return false, - } - } else { - // This will only be the case with SelfHostedTdx which currently would - // already bail with the check above - return false; - } - - if let Some(rtmr1) = dcap_measurements.get(&DcapMeasurementRegister::RTMR1) - && rtmr1 != &expected_measurements.rtmr1 - { - return false; - } - - if let Some(rtmr2) = dcap_measurements.get(&DcapMeasurementRegister::RTMR2) - && rtmr2 != &expected_measurements.rtmr2 - { - return false; - } - - true - } + ExpectedMeasurements::Image(image_hashes) => compare_portable_dcap_measurement( + image_hashes, + dcap_measurements, + platform_metadata, + known_gcp_firmware, + ), ExpectedMeasurements::Azure(_) | ExpectedMeasurements::NoAttestation => false, } } @@ -714,6 +591,144 @@ impl MeasurementPolicy { } } +/// Checks a set of DCAP measurement values against a set of OS image hashes +/// and platform metadata. +/// +/// Returns true if the given measurements match the expected ones, +/// otherwise logs a warning and returns false. +pub(crate) fn compare_portable_dcap_measurement( + image_hashes: &DcapImageHashes, + dcap_measurements: &HashMap, + platform_metadata: Option<&PlatformMetadata>, + known_gcp_firmware: Option<&GcpFirmwareCache>, +) -> bool { + let Some(platform_metadata) = &platform_metadata else { + return false; + }; + + // On GCP, fetch the firmware associated with the MRTD + let firmware = match platform_metadata.attestation_type { + ImageAttestationType::GcpTdx => { + let Some(mrtd) = dcap_measurements.get(&DcapMeasurementRegister::MRTD) else { + warn!("Could not match image hash measurement due to missing MRTD"); + return false; + }; + + let result = if let Some(cache) = known_gcp_firmware { + cache.get_or_fetch(*mrtd) + } else { + fetch_firmware(*mrtd) + }; + match result { + Ok(firmware) => Some(firmware), + Err(err) => { + warn!( + "Could not match image hash measurement - failed to fetch or verify Google firmware: {err:?}" + ); + return false; + } + } + } + // These may be supported in the future but currently regarded as too + // experimental to work with 'portable' measurement policies + ImageAttestationType::SelfHostedTdx => { + warn!( + "Attempting to match portable measurement policy with bare metal TDX - not yet supported" + ); + return false; + } + ImageAttestationType::AzureTdx => { + warn!( + "Attempting to match portable measurement policy with Azure TDX - not yet supported" + ); + return false; + } + }; + + // Compute expect measurements + let expected_measurements = + match expected_dcap_registers(image_hashes, platform_metadata, firmware.as_ref()) { + Ok(expected) => expected, + Err(err) => { + warn!("Failed to compute expected DCAP registers: {err:?}"); + return false; + } + }; + + if let Some(expected_mrtd) = expected_measurements.mrtd { + match dcap_measurements.get(&DcapMeasurementRegister::MRTD) { + Some(mrtd) if mrtd == &expected_mrtd => {} + _ => return false, + } + } else { + // This will only be the case with SelfHostedTdx which currently would + // already bail with the check above + return false; + } + + if let Some(expected_rtmr0) = expected_measurements.rtmr0 { + match dcap_measurements.get(&DcapMeasurementRegister::RTMR0) { + Some(rtmr0) if rtmr0 == &expected_rtmr0 => {} + _ => return false, + } + } else { + // This will only be the case with SelfHostedTdx which currently would + // already bail with the check above + return false; + } + + if dcap_measurements.get(&DcapMeasurementRegister::RTMR1) != Some(&expected_measurements.rtmr1) + { + return false; + } + + if dcap_measurements.get(&DcapMeasurementRegister::RTMR2) != Some(&expected_measurements.rtmr2) + { + return false; + } + + true +} + +/// An error when converting measurements / to or from HTTP header format +#[derive(Error, Debug)] +pub enum MeasurementFormatError { + #[error("JSON: {0}")] + Json(#[from] serde_json::Error), + #[error("Missing value: {0}")] + MissingValue(String), + #[error("Invalid header value: {0}")] + BadHeaderValue(#[from] InvalidHeaderValue), + #[error("IO: {0}")] + Io(#[from] std::io::Error), + #[error("Attestation type not valid")] + AttestationTypeNotValid, + #[error("Hex: {0}")] + Hex(#[from] hex::FromHexError), + #[error("Expected 48 byte value")] + BadLength, + #[error("TDX quote register index must be in the ranger 0-3")] + BadRegisterIndex, + #[error("ParseInt: {0}")] + ParseInt(#[from] std::num::ParseIntError), + #[error("Failed to read measurements from URL: {0}")] + Reqwest(#[from] reqwest::Error), + #[error("Invalid URL: {0}")] + InvalidUri(#[from] InvalidUri), + #[error("Refusing to load measurement policy over plain HTTP from non-loopback host: {0}")] + InsecureHttpNotLoopback(String), + #[error("Measurement entry for register '{0}' has both 'expected' and 'expected_any'")] + BothExpectedAndExpectedAny(String), + #[error("Measurement entry for register '{0}' has neither 'expected' nor 'expected_any'")] + NoExpectedValue(String), + #[error("Measurement entry for register '{0}' has empty 'expected_any' list")] + EmptyExpectedAny(String), + #[error("Measurement record has both 'measurements' and 'dcap_image_hashes' — set only one")] + BothMeasurementsAndDcapImageHashes, + #[error("Attestation type '{0}' does not support 'dcap_image_hashes'")] + DcapImageHashesUnsupportedAttestationType(String), +} + #[cfg(test)] mod tests { use std::collections::HashSet;