From 4302640e11856ec1f4c1dc00e1abc1ebe975942c Mon Sep 17 00:00:00 2001 From: peg Date: Thu, 19 Mar 2026 14:54:16 +0100 Subject: [PATCH 1/7] Make public the method to extract attestation from cert and add a method to extract measurements --- crates/attestation/src/azure/mod.rs | 9 +++++++++ crates/attestation/src/lib.rs | 23 +++++++++++++++++++++++ crates/attested-tls/src/lib.rs | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 7d3a7ab..119de9d 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -199,6 +199,15 @@ async fn verify_azure_attestation_with_given_timestamp( Ok(MultiMeasurements::from_pcrs(pcrs)) } +/// Extract the measurements from the attestation, but do not verify +/// anything +pub fn get_measurements(input: &[u8]) -> Result { + let attestation_document: AttestationDocument = serde_json::from_slice(&input)?; + let vtpm_quote = attestation_document.tpm_attestation.quote; + let pcrs = vtpm_quote.pcrs_sha256(); + Ok(MultiMeasurements::from_pcrs(pcrs)) +} + /// JSON Web Key used in [HclRuntimeClaims] #[derive(Debug, Deserialize)] struct Jwk { diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index df5c5ae..cf1c2d9 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -38,6 +38,29 @@ impl AttestationExchangeMessage { pub fn without_attestation() -> Self { Self { attestation_type: AttestationType::None, attestation: Vec::new() } } + + /// Extract the measurements from the attestation, if present, but do + /// not verify + pub fn get_measurements(&self) -> Result, AttestationError> { + match self.attestation_type { + AttestationType::None => Ok(None), + AttestationType::AzureTdx => { + #[cfg(feature = "azure")] + { + Ok(Some(azure::get_measurements(&self.attestation)?)) + } + #[cfg(not(feature = "azure"))] + { + Err(AttestationError::AttestationTypeNotSupported) + } + } + _ => { + let quote = dcap_qvl::verify::Quote::parse(&self.attestation) + .map_err(DcapVerificationError::from)?; + Ok(Some(MultiMeasurements::from_dcap_qvl_quote("e)?)) + } + } + } } /// Type of attestaion used diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index ff7a5a0..e7821cb 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -438,7 +438,7 @@ impl AttestedCertificateVerifier { } /// Given a TLS certificate, return the embedded attestation - fn extract_custom_attestation_from_cert( + pub fn extract_custom_attestation_from_cert( cert: &CertificateDer<'_>, ) -> Result { // First try to parse using ra_tls which assumes DCAP From f503773fab3bdfdad02991d75c398c5327f21745 Mon Sep 17 00:00:00 2001 From: peg Date: Thu, 19 Mar 2026 15:01:45 +0100 Subject: [PATCH 2/7] Clippy --- crates/attestation/src/azure/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/attestation/src/azure/mod.rs b/crates/attestation/src/azure/mod.rs index 119de9d..59faf51 100644 --- a/crates/attestation/src/azure/mod.rs +++ b/crates/attestation/src/azure/mod.rs @@ -202,7 +202,7 @@ async fn verify_azure_attestation_with_given_timestamp( /// Extract the measurements from the attestation, but do not verify /// anything pub fn get_measurements(input: &[u8]) -> Result { - let attestation_document: AttestationDocument = serde_json::from_slice(&input)?; + let attestation_document: AttestationDocument = serde_json::from_slice(input)?; let vtpm_quote = attestation_document.tpm_attestation.quote; let pcrs = vtpm_quote.pcrs_sha256(); Ok(MultiMeasurements::from_pcrs(pcrs)) From ed0a0c5125562b45631a2522d1212b4ece143393 Mon Sep 17 00:00:00 2001 From: peg Date: Mon, 23 Mar 2026 09:28:50 +0100 Subject: [PATCH 3/7] Fix how attestation is extracted from certificates --- crates/attested-tls/src/lib.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index e7821cb..9f6b131 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -441,14 +441,19 @@ impl AttestedCertificateVerifier { pub fn extract_custom_attestation_from_cert( cert: &CertificateDer<'_>, ) -> Result { - // First try to parse using ra_tls which assumes DCAP - if let Ok(Some(attestation)) = ra_tls::attestation::from_der(cert.as_ref()) && - let AttestationQuote::DstackTdx(tdx_quote) = attestation.quote - { - return Ok(AttestationExchangeMessage { - attestation_type: AttestationType::DcapTdx, - attestation: tdx_quote.quote, - }); + if let Ok(Some(attestation)) = ra_tls::attestation::from_der(cert.as_ref()) { + if let AttestationQuote::DstackTdx(tdx_quote) = attestation.quote { + if let Ok(message) = + serde_json::from_slice::(&tdx_quote.quote) + { + return Ok(message); + } + + return Ok(AttestationExchangeMessage { + attestation_type: AttestationType::DcapTdx, + attestation: tdx_quote.quote, + }); + } } // If that fails, extract and parse the extension From f630fa040f893c44484a3008d16301eeefb4649c Mon Sep 17 00:00:00 2001 From: peg Date: Mon, 23 Mar 2026 09:43:52 +0100 Subject: [PATCH 4/7] Clippy --- crates/attested-tls/src/lib.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index 9f6b131..fbb8e90 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -441,19 +441,19 @@ impl AttestedCertificateVerifier { pub fn extract_custom_attestation_from_cert( cert: &CertificateDer<'_>, ) -> Result { - if let Ok(Some(attestation)) = ra_tls::attestation::from_der(cert.as_ref()) { - if let AttestationQuote::DstackTdx(tdx_quote) = attestation.quote { - if let Ok(message) = - serde_json::from_slice::(&tdx_quote.quote) - { - return Ok(message); - } - - return Ok(AttestationExchangeMessage { - attestation_type: AttestationType::DcapTdx, - attestation: tdx_quote.quote, - }); + if let Ok(Some(attestation)) = ra_tls::attestation::from_der(cert.as_ref()) && + let AttestationQuote::DstackTdx(tdx_quote) = attestation.quote + { + if let Ok(message) = + serde_json::from_slice::(&tdx_quote.quote) + { + return Ok(message); } + + return Ok(AttestationExchangeMessage { + attestation_type: AttestationType::DcapTdx, + attestation: tdx_quote.quote, + }); } // If that fails, extract and parse the extension From 781ed22aafb74789b6fb0f9cbea05fa38088909a Mon Sep 17 00:00:00 2001 From: peg Date: Mon, 23 Mar 2026 10:57:50 +0100 Subject: [PATCH 5/7] Attestation measurement extractor should support mock quotes --- crates/attestation/src/lib.rs | 43 +++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index cf1c2d9..c6df341 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -43,23 +43,32 @@ impl AttestationExchangeMessage { /// not verify pub fn get_measurements(&self) -> Result, AttestationError> { match self.attestation_type { - AttestationType::None => Ok(None), - AttestationType::AzureTdx => { - #[cfg(feature = "azure")] - { - Ok(Some(azure::get_measurements(&self.attestation)?)) - } - #[cfg(not(feature = "azure"))] - { - Err(AttestationError::AttestationTypeNotSupported) - } - } - _ => { - let quote = dcap_qvl::verify::Quote::parse(&self.attestation) - .map_err(DcapVerificationError::from)?; - Ok(Some(MultiMeasurements::from_dcap_qvl_quote("e)?)) - } - } + AttestationType::None => Ok(None), + AttestationType::AzureTdx => { + #[cfg(feature = "azure")] + { + Ok(Some(azure::get_measurements(&self.attestation)?)) + } + #[cfg(not(feature = "azure"))] + { + Err(AttestationError::AttestationTypeNotSupported) + } + } + _ => { + #[cfg(any(test, feature = "mock"))] + { + let quote = tdx_quote::Quote::from_bytes(&self.attestation)?; + Ok(Some(MultiMeasurements::from_tdx_quote("e))) + } + + #[cfg(not(any(test, feature = "mock")))] + { + let quote = dcap_qvl::verify::Quote::parse(&self.attestation) + .map_err(DcapVerificationError::from)?; + Ok(Some(MultiMeasurements::from_dcap_qvl_quote("e)?)) + } + } + } } } From c37cdaa6b07e777ba4a9ffa58e98a5dda642c2f3 Mon Sep 17 00:00:00 2001 From: peg Date: Mon, 23 Mar 2026 11:00:06 +0100 Subject: [PATCH 6/7] Fmt --- crates/attestation/src/lib.rs | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index c6df341..2686f76 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -43,32 +43,32 @@ impl AttestationExchangeMessage { /// not verify pub fn get_measurements(&self) -> Result, AttestationError> { match self.attestation_type { - AttestationType::None => Ok(None), - AttestationType::AzureTdx => { - #[cfg(feature = "azure")] - { - Ok(Some(azure::get_measurements(&self.attestation)?)) - } - #[cfg(not(feature = "azure"))] - { - Err(AttestationError::AttestationTypeNotSupported) - } - } - _ => { - #[cfg(any(test, feature = "mock"))] - { - let quote = tdx_quote::Quote::from_bytes(&self.attestation)?; - Ok(Some(MultiMeasurements::from_tdx_quote("e))) - } - - #[cfg(not(any(test, feature = "mock")))] - { - let quote = dcap_qvl::verify::Quote::parse(&self.attestation) - .map_err(DcapVerificationError::from)?; - Ok(Some(MultiMeasurements::from_dcap_qvl_quote("e)?)) - } - } - } + AttestationType::None => Ok(None), + AttestationType::AzureTdx => { + #[cfg(feature = "azure")] + { + Ok(Some(azure::get_measurements(&self.attestation)?)) + } + #[cfg(not(feature = "azure"))] + { + Err(AttestationError::AttestationTypeNotSupported) + } + } + _ => { + #[cfg(any(test, feature = "mock"))] + { + let quote = tdx_quote::Quote::from_bytes(&self.attestation)?; + Ok(Some(MultiMeasurements::from_tdx_quote("e))) + } + + #[cfg(not(any(test, feature = "mock")))] + { + let quote = dcap_qvl::verify::Quote::parse(&self.attestation) + .map_err(DcapVerificationError::from)?; + Ok(Some(MultiMeasurements::from_dcap_qvl_quote("e)?)) + } + } + } } } From 2e4273cd93670e705e789555c00d43ca9c1e4af2 Mon Sep 17 00:00:00 2001 From: peg Date: Mon, 23 Mar 2026 11:05:09 +0100 Subject: [PATCH 7/7] Error handling --- crates/attestation/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 2686f76..84240d2 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -57,7 +57,8 @@ impl AttestationExchangeMessage { _ => { #[cfg(any(test, feature = "mock"))] { - let quote = tdx_quote::Quote::from_bytes(&self.attestation)?; + let quote = tdx_quote::Quote::from_bytes(&self.attestation) + .map_err(DcapVerificationError::from)?; Ok(Some(MultiMeasurements::from_tdx_quote("e))) }