From 70deb790ce5d91013cb35d82db2fac70c89c6628 Mon Sep 17 00:00:00 2001 From: 0x416e746f6e Date: Tue, 7 Apr 2026 11:28:09 +0200 Subject: [PATCH 1/6] chore: make detect() non-async refs #18 --- crates/attestation/src/lib.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 5061bb8..7681860 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -102,7 +102,7 @@ impl AttestationType { } /// Detect what platform we are on by attempting an attestation - pub async fn detect() -> Result { + pub fn detect() -> Result { // First attempt azure, if the feature is present #[cfg(feature = "azure")] { @@ -113,7 +113,7 @@ impl AttestationType { // Otherwise try DCAP quote - this internally checks that the quote provider // is `tdx_guest` if configfs_tsm::create_tdx_quote([0; 64]).is_ok() { - if running_on_gcp().await? { + if running_on_gcp()? { return Ok(AttestationType::GcpTdx); } else { return Ok(AttestationType::DcapTdx); @@ -169,8 +169,8 @@ impl AttestationGenerator { /// Detect what confidential compute platform is present and create the /// appropriate attestation generator - pub async fn detect() -> Result { - Self::new_with_detection(None, None).await + pub fn detect() -> Result { + Self::new_with_detection(None, None) } /// Do not generate attestations @@ -180,7 +180,7 @@ impl AttestationGenerator { /// Create an [AttestationGenerator] detecting the attestation type if /// it is not given - pub async fn new_with_detection( + pub fn new_with_detection( attestation_type_string: Option, attestation_provider_url: Option, ) -> Result { @@ -195,7 +195,7 @@ impl AttestationGenerator { let attestation_type_string = attestation_type_string.unwrap_or_else(|| "auto".to_string()); let attestation_type = if attestation_type_string == "auto" { tracing::info!("Doing attestation type detection..."); - AttestationType::detect().await? + AttestationType::detect()? } else { serde_json::from_value(serde_json::Value::String(attestation_type_string))? }; @@ -390,10 +390,11 @@ async fn log_attestation(attestation: &AttestationExchangeMessage) { /// Test whether it looks like we are running on GCP by hitting the metadata /// API -async fn running_on_gcp() -> Result { - let client = reqwest::Client::builder().timeout(Duration::from_millis(200)).build()?; +fn running_on_gcp() -> Result { + let client = + reqwest::blocking::Client::builder().timeout(Duration::from_millis(200)).build()?; - let resp = client.get(GCP_METADATA_API).send().await; + let resp = client.get(GCP_METADATA_API).send(); if let Ok(r) = resp { return Ok(r.status().is_success() && @@ -521,16 +522,14 @@ mod tests { addr } - #[tokio::test] - async fn attestation_detection_does_not_panic() { + fn attestation_detection_does_not_panic() { // We dont enforce what platform the test is run on, only that the function // does not panic - let _ = AttestationGenerator::new_with_detection(None, None).await; + let _ = AttestationGenerator::new_with_detection(None, None); } - #[tokio::test] - async fn running_on_gcp_check_does_not_panic() { - let _ = running_on_gcp().await; + fn running_on_gcp_check_does_not_panic() { + let _ = running_on_gcp(); } #[tokio::test] From 830be9b14caf015ba4cc1beb1f6229bf3cd31541 Mon Sep 17 00:00:00 2001 From: 0x416e746f6e Date: Tue, 7 Apr 2026 12:07:26 +0200 Subject: [PATCH 2/6] chore: rename primary_name to subject --- crates/attested-tls/src/lib.rs | 42 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index fbb8e90..9007eda 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -92,7 +92,7 @@ struct ResolverState { /// Attestation generator used when renewing ceritifcate attestation_generator: AttestationGenerator, /// Primary DNS name used as certificate subject / common name. - primary_name: String, + subject: String, /// DNS subject alternative names, including the primary name. subject_alt_names: Vec, } @@ -107,7 +107,7 @@ impl fmt::Debug for ResolverState { .field("key_pair_der_len", &self.key_pair_der.len()) .field("certificate_chain_len", &certificate_chain_len) .field("attestation_generator", &self.attestation_generator) - .field("primary_name", &self.primary_name) + .field("subject", &self.subject) .field("subject_alt_names", &self.subject_alt_names) .finish() } @@ -120,13 +120,13 @@ impl AttestedCertificateResolver { pub async fn new( attestation_generator: AttestationGenerator, ca: Option, - primary_name: String, + subject: String, subject_alt_names: Vec, ) -> Result { Self::new_with_provider( attestation_generator, ca, - primary_name, + subject, subject_alt_names, default_crypto_provider()?, ) @@ -137,13 +137,12 @@ impl AttestedCertificateResolver { pub async fn new_with_provider( attestation_generator: AttestationGenerator, ca: Option, - primary_name: String, + subject: String, subject_alt_names: Vec, provider: Arc, ) -> Result { debug_assert!(CERTIFICATE_RENEWAL_LEAD_TIME < CERTIFICATE_VALIDITY); - let subject_alt_names = - normalized_subject_alt_names(primary_name.as_str(), subject_alt_names); + let subject_alt_names = normalized_subject_alt_names(subject.as_str(), subject_alt_names); // Generate keypair let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256)?; @@ -154,7 +153,7 @@ impl AttestedCertificateResolver { let certificate = Self::issue_ra_cert_chain( &key_pair, ca.as_ref(), - primary_name.as_str(), + subject.as_str(), &subject_alt_names, &attestation_generator, ) @@ -166,7 +165,7 @@ impl AttestedCertificateResolver { ca: ca.map(Arc::new), key_pair_der, attestation_generator, - primary_name, + subject, subject_alt_names, }); @@ -181,11 +180,11 @@ impl AttestedCertificateResolver { async fn issue_ra_cert_chain( key: &KeyPair, ca: Option<&CaCert>, - primary_name: &str, + subject: &str, subject_alt_names: &[String], attestation_generator: &AttestationGenerator, ) -> Result>, AttestedTlsError> { - tracing::debug!("Generating new remote-attested ceritifcate for {primary_name}"); + tracing::debug!("Generating new remote-attested ceritifcate for {subject}"); let pubkey = key.public_key_der(); let now = SystemTime::now(); let not_after = now + CERTIFICATE_VALIDITY; @@ -194,14 +193,14 @@ impl AttestedCertificateResolver { pubkey, now, not_after, - primary_name, + subject, attestation_generator, ) .await?; let cert_request = CertRequest::builder() .key(key) - .subject(primary_name) + .subject(subject) .alt_names(subject_alt_names) .not_before(now) .not_after(not_after) @@ -239,11 +238,10 @@ impl AttestedCertificateResolver { pubkey: Vec, not_before: SystemTime, not_after: SystemTime, - primary_name: &str, + subject: &str, attestation_generator: &AttestationGenerator, ) -> Result { - let report_data = - create_report_data(pubkey, not_before, not_after, primary_name.as_bytes())?; + let report_data = create_report_data(pubkey, not_before, not_after, subject.as_bytes())?; let attestation = attestation_generator.generate_attestation(report_data).await?; Ok(VersionedAttestation::V0 { attestation: Attestation { @@ -286,7 +284,7 @@ impl AttestedCertificateResolver { next_delay = match Self::issue_ra_cert_chain( &key_pair, current.ca.as_deref(), - current.primary_name.as_str(), + current.subject.as_str(), ¤t.subject_alt_names, ¤t.attestation_generator, ) @@ -335,9 +333,9 @@ fn default_crypto_provider() -> Result, AttestedTlsError> { } /// Ensures that SAN contains the primary hostname -fn normalized_subject_alt_names(primary_name: &str, subject_alt_names: Vec) -> Vec { +fn normalized_subject_alt_names(subject: &str, subject_alt_names: Vec) -> Vec { let mut normalized = Vec::with_capacity(subject_alt_names.len() + 1); - normalized.push(primary_name.to_string()); + normalized.push(subject.to_string()); for name in subject_alt_names { if !normalized.iter().any(|existing| existing == &name) { @@ -1065,13 +1063,13 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn alternate_san_completes_a_handshake() { let provider: Arc = aws_lc_rs::default_provider().into(); - let primary_name = "foo"; + let subject = "foo"; let alternate_name = "bar"; let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), None, - primary_name.to_string(), - vec![alternate_name.to_string(), primary_name.to_string()], + subject.to_string(), + vec![alternate_name.to_string(), subject.to_string()], provider.clone(), ) .await From d7ee8d64381b768a1393dc00b64ecc1c97390930 Mon Sep 17 00:00:00 2001 From: 0x416e746f6e Date: Tue, 7 Apr 2026 12:15:23 +0200 Subject: [PATCH 3/6] feat: allow using custom key-pairs --- crates/attested-tls/src/lib.rs | 46 ++++++++++++++++++++----- crates/attested-tls/tests/nested_tls.rs | 2 ++ 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index 9007eda..654e202 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -16,7 +16,7 @@ pub use ra_tls::cert::CaCert; use ra_tls::{ attestation::{Attestation, AttestationQuote, VersionedAttestation}, cert::CertRequest, - rcgen::{KeyPair, PKCS_ECDSA_P256_SHA256}, + rcgen::KeyPair, }; use rustls::{ DigitallySignedStruct, @@ -119,12 +119,14 @@ impl AttestedCertificateResolver { /// certificates will be self signed pub async fn new( attestation_generator: AttestationGenerator, + key_pair: &KeyPair, ca: Option, subject: String, subject_alt_names: Vec, ) -> Result { Self::new_with_provider( attestation_generator, + key_pair, ca, subject, subject_alt_names, @@ -136,6 +138,7 @@ impl AttestedCertificateResolver { /// Also provide a crypto provider pub async fn new_with_provider( attestation_generator: AttestationGenerator, + key_pair: &KeyPair, ca: Option, subject: String, subject_alt_names: Vec, @@ -144,14 +147,12 @@ impl AttestedCertificateResolver { debug_assert!(CERTIFICATE_RENEWAL_LEAD_TIME < CERTIFICATE_VALIDITY); let subject_alt_names = normalized_subject_alt_names(subject.as_str(), subject_alt_names); - // Generate keypair - let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256)?; let key_pair_der = key_pair.serialize_der(); - let key = Self::load_signing_key(&key_pair, provider)?; + let key = Self::load_signing_key(key_pair, provider)?; // Generate initial attested certificate let certificate = Self::issue_ra_cert_chain( - &key_pair, + key_pair, ca.as_ref(), subject.as_str(), &subject_alt_names, @@ -178,14 +179,14 @@ impl AttestedCertificateResolver { /// Create an attested certificate chain - either self-signed or with /// the provided CA async fn issue_ra_cert_chain( - key: &KeyPair, + key_pair: &KeyPair, ca: Option<&CaCert>, subject: &str, subject_alt_names: &[String], attestation_generator: &AttestationGenerator, ) -> Result>, AttestedTlsError> { tracing::debug!("Generating new remote-attested ceritifcate for {subject}"); - let pubkey = key.public_key_der(); + let pubkey = key_pair.public_key_der(); let now = SystemTime::now(); let not_after = now + CERTIFICATE_VALIDITY; @@ -199,7 +200,7 @@ impl AttestedCertificateResolver { .await?; let cert_request = CertRequest::builder() - .key(key) + .key(key_pair) .subject(subject) .alt_names(subject_alt_names) .not_before(now) @@ -806,7 +807,13 @@ pub enum AttestedTlsError { mod tests { use std::{io::Cursor, sync::Arc}; - use ra_tls::rcgen::{BasicConstraints, CertificateParams, IsCa}; + use ra_tls::rcgen::{ + BasicConstraints, + CertificateParams, + IsCa, + KeyPair, + PKCS_ECDSA_P256_SHA256, + }; use rustls::{ CertificateError, ClientConfig, @@ -840,8 +847,10 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn certificate_resolver_creates_initial_certificate() { let provider: Arc = aws_lc_rs::default_provider().into(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, "foo".to_string(), vec![], @@ -859,8 +868,10 @@ mod tests { async fn server_and_client_configs_complete_a_handshake() { let provider: Arc = aws_lc_rs::default_provider().into(); let server_name = "foo"; + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, server_name.to_string(), vec![], @@ -908,12 +919,14 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn ca_signed_server_and_client_configs_complete_a_handshake() { let provider: Arc = aws_lc_rs::default_provider().into(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let server_name = "foo"; let ca = test_ca(); let ca_cert = CertificateDer::from_pem_slice(ca.pem_cert.as_bytes()).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, Some(ca), server_name.to_string(), vec![], @@ -969,8 +982,10 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn certificate_is_renewed_before_expiry() { let provider: Arc = aws_lc_rs::default_provider().into(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, "foo".to_string(), vec![], @@ -995,10 +1010,12 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn server_and_client_configs_complete_a_mutual_auth_handshake() { let provider: Arc = aws_lc_rs::default_provider().into(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let server_name = "foo"; let server_resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, server_name.to_string(), vec![], @@ -1009,6 +1026,7 @@ mod tests { let client_resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, "client".to_string(), vec![], @@ -1063,10 +1081,12 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn alternate_san_completes_a_handshake() { let provider: Arc = aws_lc_rs::default_provider().into(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let subject = "foo"; let alternate_name = "bar"; let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, subject.to_string(), vec![alternate_name.to_string(), subject.to_string()], @@ -1156,8 +1176,10 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn self_signed_attested_certificate_with_wrong_name_is_rejected() { let provider: Arc = aws_lc_rs::default_provider().into(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, "foo".to_string(), vec![], @@ -1189,8 +1211,10 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn certificate_binding_changes_when_identity_changes() { let provider: Arc = aws_lc_rs::default_provider().into(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, "foo".to_string(), vec![], @@ -1229,8 +1253,10 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn attestation_rejection_returns_application_verification_failure() { let provider: Arc = aws_lc_rs::default_provider().into(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, "foo".to_string(), vec![], @@ -1262,8 +1288,10 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn verifier_reuses_trusted_certificate_cache() { let provider: Arc = aws_lc_rs::default_provider().into(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, "foo".to_string(), vec![], diff --git a/crates/attested-tls/tests/nested_tls.rs b/crates/attested-tls/tests/nested_tls.rs index 6bc818a..82e51dc 100644 --- a/crates/attested-tls/tests/nested_tls.rs +++ b/crates/attested-tls/tests/nested_tls.rs @@ -84,8 +84,10 @@ fn plain_tls_config_pair(provider: Arc) -> (ServerConfig, Client /// Create attested server TLS config with mock DCAP attestation and /// self-signed certs async fn attested_server_config(server_name: &str, provider: Arc) -> ServerConfig { + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), + &key_pair, None, server_name.to_string(), vec![], From 5a4cb539b341a29c144835901f68e3c3d73637f4 Mon Sep 17 00:00:00 2001 From: 0x416e746f6e Date: Tue, 7 Apr 2026 13:49:29 +0200 Subject: [PATCH 4/6] fix: re-export `ra_tls::rcgen` --- crates/attested-tls/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index 654e202..bbd0a27 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -12,12 +12,12 @@ pub use attestation::{ AttestationType, AttestationVerifier, }; -pub use ra_tls::cert::CaCert; use ra_tls::{ attestation::{Attestation, AttestationQuote, VersionedAttestation}, cert::CertRequest, rcgen::KeyPair, }; +pub use ra_tls::{cert::CaCert, rcgen}; use rustls::{ DigitallySignedStruct, DistinguishedName, From 3ac64af0b94773c115fec738421626ad43315181 Mon Sep 17 00:00:00 2001 From: 0x416e746f6e Date: Tue, 7 Apr 2026 15:36:33 +0200 Subject: [PATCH 5/6] fix: make `AttestedCertificateResolver::new()` non-async --- Cargo.lock | 18 +++++++++-- crates/attestation/Cargo.toml | 1 + crates/attestation/src/lib.rs | 41 +++++++++++++------------ crates/attested-tls/src/lib.rs | 34 ++++++-------------- crates/attested-tls/tests/nested_tls.rs | 5 ++- 5 files changed, 49 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d24ffee..bdcf747 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -320,6 +320,7 @@ dependencies = [ "tokio-rustls", "tracing", "tss-esapi", + "ureq", "x509-parser 0.18.1", ] @@ -1952,7 +1953,7 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", + "webpki-roots 1.0.6", ] [[package]] @@ -3265,7 +3266,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 1.0.6", ] [[package]] @@ -4229,11 +4230,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" dependencies = [ "base64 0.22.1", + "flate2", "log", "once_cell", + "rustls", + "rustls-pki-types", "serde", "serde_json", "url", + "webpki-roots 0.26.11", ] [[package]] @@ -4456,6 +4461,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + [[package]] name = "webpki-roots" version = "1.0.6" diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml index 1ff071d..e4ba40d 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -25,6 +25,7 @@ base64 = "0.22.1" reqwest = { version = "0.12.23", default-features = false, features = [ "rustls-tls-webpki-roots-no-provider", ] } +ureq = "2.12.1" tracing = "0.1.41" parity-scale-codec = "3.7.5" num-bigint = "0.4.6" diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 7681860..fa86855 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -7,6 +7,7 @@ pub mod measurements; use std::{ fmt::{self, Display, Formatter}, + io::Read, net::IpAddr, time::{Duration, SystemTime, UNIX_EPOCH}, }; @@ -205,12 +206,12 @@ impl AttestationGenerator { } /// Generate an attestation exchange message with given input data - pub async fn generate_attestation( + pub fn generate_attestation( &self, input_data: [u8; 64], ) -> Result { if let Some(url) = &self.attestation_provider_url { - Self::use_attestation_provider(url, self.attestation_type, input_data).await + Self::use_attestation_provider(url, self.attestation_type, input_data) } else { Ok(AttestationExchangeMessage { attestation_type: self.attestation_type, @@ -246,27 +247,29 @@ impl AttestationGenerator { /// Generate an attestation by using an external service for the /// attestation generation - async fn use_attestation_provider( + fn use_attestation_provider( url: &str, attestation_type: AttestationType, input_data: [u8; 64], ) -> Result { let url = format!("{}/attest/{}", url, hex::encode(input_data)); - let response = reqwest::get(url) - .await + let mut response = ureq::get(&url) + .timeout(Duration::from_millis(1000)) + .call() .map_err(|err| AttestationError::AttestationProvider(err.to_string()))? - .bytes() - .await - .map_err(|err| AttestationError::AttestationProvider(err.to_string()))? - .to_vec(); + .into_reader(); + let mut body = Vec::new(); + response + .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 &response[..]) { + if let Ok(message) = AttestationExchangeMessage::decode(&mut &body[..]) { Ok(message) } else { - Ok(AttestationExchangeMessage { attestation_type, attestation: response }) + Ok(AttestationExchangeMessage { attestation_type, attestation: body }) } } } @@ -391,14 +394,12 @@ async fn log_attestation(attestation: &AttestationExchangeMessage) { /// Test whether it looks like we are running on GCP by hitting the metadata /// API fn running_on_gcp() -> Result { - let client = - reqwest::blocking::Client::builder().timeout(Duration::from_millis(200)).build()?; - - let resp = client.get(GCP_METADATA_API).send(); + let agent = ureq::AgentBuilder::new().timeout(Duration::from_millis(200)).build(); + let resp = agent.get(GCP_METADATA_API).call(); if let Ok(r) = resp { - return Ok(r.status().is_success() && - r.headers().get("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) @@ -522,17 +523,19 @@ mod tests { addr } + #[test] fn attestation_detection_does_not_panic() { // We dont enforce what platform the test is run on, only that the function // does not panic let _ = AttestationGenerator::new_with_detection(None, None); } + #[test] fn running_on_gcp_check_does_not_panic() { let _ = running_on_gcp(); } - #[tokio::test] + #[tokio::test(flavor = "multi_thread")] async fn attestation_provider_response_is_wrapped_if_needed() { let input_data = [0u8; 64]; @@ -549,7 +552,6 @@ mod tests { AttestationType::GcpTdx, input_data, ) - .await .unwrap(); assert_eq!(decoded.attestation_type, AttestationType::None); assert_eq!(decoded.attestation, vec![1, 2, 3]); @@ -561,7 +563,6 @@ mod tests { AttestationType::DcapTdx, input_data, ) - .await .unwrap(); assert_eq!(wrapped.attestation_type, AttestationType::DcapTdx); assert_eq!(wrapped.attestation, vec![9, 8]); diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index bbd0a27..f7e32c8 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -117,7 +117,7 @@ impl AttestedCertificateResolver { /// Create a certificate resolver with a given attestation generator /// A private cerificate authority can also be given - otherwise /// certificates will be self signed - pub async fn new( + pub fn new( attestation_generator: AttestationGenerator, key_pair: &KeyPair, ca: Option, @@ -132,11 +132,10 @@ impl AttestedCertificateResolver { subject_alt_names, default_crypto_provider()?, ) - .await } /// Also provide a crypto provider - pub async fn new_with_provider( + pub fn new_with_provider( attestation_generator: AttestationGenerator, key_pair: &KeyPair, ca: Option, @@ -157,8 +156,7 @@ impl AttestedCertificateResolver { subject.as_str(), &subject_alt_names, &attestation_generator, - ) - .await?; + )?; let state = Arc::new(ResolverState { key, @@ -178,14 +176,14 @@ impl AttestedCertificateResolver { /// Create an attested certificate chain - either self-signed or with /// the provided CA - async fn issue_ra_cert_chain( + fn issue_ra_cert_chain( key_pair: &KeyPair, ca: Option<&CaCert>, subject: &str, subject_alt_names: &[String], attestation_generator: &AttestationGenerator, ) -> Result>, AttestedTlsError> { - tracing::debug!("Generating new remote-attested ceritifcate for {subject}"); + tracing::debug!("Generating new remote-attested certificate for {subject}"); let pubkey = key_pair.public_key_der(); let now = SystemTime::now(); let not_after = now + CERTIFICATE_VALIDITY; @@ -196,8 +194,7 @@ impl AttestedCertificateResolver { not_after, subject, attestation_generator, - ) - .await?; + )?; let cert_request = CertRequest::builder() .key(key_pair) @@ -235,7 +232,7 @@ impl AttestedCertificateResolver { /// Create an attestation, and format it to be used in certificate /// extension - async fn create_attestation_payload( + fn create_attestation_payload( pubkey: Vec, not_before: SystemTime, not_after: SystemTime, @@ -243,7 +240,7 @@ impl AttestedCertificateResolver { attestation_generator: &AttestationGenerator, ) -> Result { let report_data = create_report_data(pubkey, not_before, not_after, subject.as_bytes())?; - let attestation = attestation_generator.generate_attestation(report_data).await?; + let attestation = attestation_generator.generate_attestation(report_data)?; Ok(VersionedAttestation::V0 { attestation: Attestation { quote: ra_tls::attestation::AttestationQuote::DstackTdx( @@ -288,9 +285,7 @@ impl AttestedCertificateResolver { current.subject.as_str(), ¤t.subject_alt_names, ¤t.attestation_generator, - ) - .await - { + ) { Ok(certificate) => { *current.certificate.write().expect("Certificate lock poisoned") = certificate; @@ -856,7 +851,6 @@ mod tests { vec![], provider, ) - .await .unwrap(); let certificate = resolver.state.certificate.read().unwrap(); @@ -877,7 +871,6 @@ mod tests { vec![], provider.clone(), ) - .await .unwrap(); let verifier = AttestedCertificateVerifier::new_with_provider( @@ -932,7 +925,6 @@ mod tests { vec![], provider.clone(), ) - .await .unwrap(); let certificate_chain = resolver.state.certificate.read().unwrap().clone(); @@ -991,7 +983,6 @@ mod tests { vec![], provider, ) - .await .unwrap(); let initial_certificate = resolver.state.certificate.read().unwrap().first().unwrap().clone(); @@ -1021,7 +1012,6 @@ mod tests { vec![], provider.clone(), ) - .await .unwrap(); let client_resolver = AttestedCertificateResolver::new_with_provider( @@ -1032,7 +1022,6 @@ mod tests { vec![], provider.clone(), ) - .await .unwrap(); let server_verifier = AttestedCertificateVerifier::new_with_provider( @@ -1092,7 +1081,6 @@ mod tests { vec![alternate_name.to_string(), subject.to_string()], provider.clone(), ) - .await .unwrap(); let verifier = AttestedCertificateVerifier::new_with_provider( None, @@ -1185,7 +1173,6 @@ mod tests { vec![], provider.clone(), ) - .await .unwrap(); let verifier = AttestedCertificateVerifier::new_with_provider( None, @@ -1220,7 +1207,6 @@ mod tests { vec![], provider.clone(), ) - .await .unwrap(); let original_cert = resolver.state.certificate.read().unwrap().first().unwrap().clone(); let (original_report_data, original_not_after) = @@ -1262,7 +1248,6 @@ mod tests { vec![], provider.clone(), ) - .await .unwrap(); let verifier = AttestedCertificateVerifier::new_with_provider( None, @@ -1297,7 +1282,6 @@ mod tests { vec![], provider.clone(), ) - .await .unwrap(); let mut verifier = AttestedCertificateVerifier::new_with_provider( None, diff --git a/crates/attested-tls/tests/nested_tls.rs b/crates/attested-tls/tests/nested_tls.rs index 82e51dc..3a88d72 100644 --- a/crates/attested-tls/tests/nested_tls.rs +++ b/crates/attested-tls/tests/nested_tls.rs @@ -18,7 +18,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt, duplex}; async fn nested_tls_uses_attested_tls_for_inner_session() { let provider: Arc = aws_lc_rs::default_provider().into(); let (outer_server, outer_client) = plain_tls_config_pair(provider.clone()); - let inner_server = attested_server_config("localhost", provider.clone()).await; + let inner_server = attested_server_config("localhost", provider.clone()); let inner_client = attested_client_config(provider.clone()); let acceptor = NestingTlsAcceptor::new(Arc::new(outer_server), Arc::new(inner_server)); @@ -83,7 +83,7 @@ fn plain_tls_config_pair(provider: Arc) -> (ServerConfig, Client /// Create attested server TLS config with mock DCAP attestation and /// self-signed certs -async fn attested_server_config(server_name: &str, provider: Arc) -> ServerConfig { +fn attested_server_config(server_name: &str, provider: Arc) -> ServerConfig { let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::new_with_provider( AttestationGenerator::new(AttestationType::DcapTdx, None).unwrap(), @@ -93,7 +93,6 @@ async fn attested_server_config(server_name: &str, provider: Arc vec![], provider.clone(), ) - .await .unwrap(); ServerConfig::builder_with_provider(provider) From 5baedd44123887c9792d442f7b124568d5cbc25a Mon Sep 17 00:00:00 2001 From: 0x416e746f6e Date: Tue, 14 Apr 2026 10:49:55 +0200 Subject: [PATCH 6/6] fix: be explicit w.r.t attestation types (if in the future we add a new attestation type, the catch-all case will backfire) --- crates/attestation/src/lib.rs | 8 +++++--- crates/attestation/src/measurements.rs | 14 +++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index fa86855..109f84d 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -54,7 +54,7 @@ impl AttestationExchangeMessage { Err(AttestationError::AttestationTypeNotSupported) } } - _ => { + AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { #[cfg(any(test, feature = "mock"))] { let quote = tdx_quote::Quote::from_bytes(&self.attestation) @@ -241,7 +241,9 @@ impl AttestationGenerator { Err(AttestationError::AttestationTypeNotSupported) } } - _ => dcap::create_dcap_attestation(input_data), + AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { + dcap::create_dcap_attestation(input_data) + } } } @@ -355,7 +357,7 @@ impl AttestationVerifier { return Err(AttestationError::AttestationTypeNotSupported); } } - _ => { + AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { dcap::verify_dcap_attestation( attestation_exchange_message.attestation, expected_input_data, diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index 3484be6..2c1d1cf 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -166,6 +166,7 @@ impl MultiMeasurements { let measurements_map: HashMap = serde_json::from_str(input)?; Ok(match attestation_type { + AttestationType::None => Self::NoAttestation, AttestationType::AzureTdx => Self::Azure( measurements_map .into_iter() @@ -179,8 +180,7 @@ impl MultiMeasurements { }) .collect::>()?, ), - AttestationType::None => Self::NoAttestation, - _ => { + AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { let measurements_map = measurements_map .into_iter() .map(|(k, v)| { @@ -300,7 +300,9 @@ impl MeasurementRecord { measurements: match attestation_type { AttestationType::None => ExpectedMeasurements::NoAttestation, AttestationType::AzureTdx => ExpectedMeasurements::Azure(HashMap::new()), - _ => ExpectedMeasurements::Dcap(HashMap::new()), + AttestationType::DcapTdx | AttestationType::GcpTdx | AttestationType::QemuTdx => { + ExpectedMeasurements::Dcap(HashMap::new()) + } }, } } @@ -513,6 +515,7 @@ impl MeasurementPolicy { if let Some(measurements) = record.measurements { let expected_measurements = match attestation_type { + AttestationType::None => ExpectedMeasurements::NoAttestation, AttestationType::AzureTdx => { let azure_measurements = measurements .iter() @@ -524,8 +527,9 @@ impl MeasurementPolicy { )?; ExpectedMeasurements::Azure(azure_measurements) } - AttestationType::None => ExpectedMeasurements::NoAttestation, - _ => ExpectedMeasurements::Dcap( + AttestationType::DcapTdx | + AttestationType::GcpTdx | + AttestationType::QemuTdx => ExpectedMeasurements::Dcap( measurements .iter() .map(|(index_str, entry)| {