From 0ca6b293220b58cb6a6af2d4c57a21a91b4441dd Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 8 Jul 2026 13:36:20 +0200 Subject: [PATCH 1/2] Make library crates be crypto provider agnostic --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- crates/attestation-provider-server/Cargo.toml | 1 + crates/attestation-provider-server/src/lib.rs | 2 ++ crates/attestation/Cargo.toml | 1 + .../attestation/src/azure/ak_certificate.rs | 3 +++ crates/attestation/src/lib.rs | 12 +++++++++++ crates/attestation/src/measurements.rs | 3 +++ crates/attested-tls/src/lib.rs | 21 ++++++++++++++++++- crates/attested-tls/tests/nested_tls.rs | 16 +++++++++++++- crates/pccs/Cargo.toml | 1 + crates/pccs/src/lib.rs | 15 +++++++++++++ 12 files changed, 77 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 08abe81..b600544 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,6 +353,7 @@ dependencies = [ "pem-rfc7468", "rand_core 0.6.4", "reqwest 0.13.4", + "rustls", "rustls-webpki", "serde", "serde-saphyr", @@ -380,6 +381,7 @@ dependencies = [ "hex", "parity-scale-codec", "reqwest 0.13.4", + "rustls", "thiserror 2.0.18", "tokio", "tracing", @@ -3010,6 +3012,7 @@ dependencies = [ "mock-tdx", "rcgen 0.14.7", "reqwest 0.13.4", + "rustls", "serde", "serde-saphyr", "serde_json", @@ -3254,7 +3257,6 @@ version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ - "aws-lc-rs", "bytes", "getrandom 0.3.4", "lru-slab", @@ -3575,7 +3577,6 @@ dependencies = [ "log", "percent-encoding", "pin-project-lite", - "quinn", "rustls", "rustls-pki-types", "rustls-platform-verifier", diff --git a/Cargo.toml b/Cargo.toml index 7b56e67..2ebea6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ unused_async = "warn" [workspace.dependencies] attestation = { path = "crates/attestation" } mock-tdx = { path = "crates/mock-tdx" } -reqwest = { version = "0.13.4", default-features = false, features = ["rustls"] } +reqwest = { version = "0.13.4", default-features = false, features = ["rustls-no-provider"] } rustls = { version = "0.23.37", default-features = false, features = ["brotli"] } tokio = { version = "1.50.0", features = ["default"] } tokio-rustls = { version = "0.26.4", default-features = false } diff --git a/crates/attestation-provider-server/Cargo.toml b/crates/attestation-provider-server/Cargo.toml index 0b5521c..ca72e80 100644 --- a/crates/attestation-provider-server/Cargo.toml +++ b/crates/attestation-provider-server/Cargo.toml @@ -13,6 +13,7 @@ workspace = true [dependencies] attestation = { workspace = true } tokio = { workspace = true } +rustls = { workspace = true, default-features = false, features = ["aws_lc_rs"] } axum = "0.8.6" clap = { version = "4.5.51", features = ["derive", "env"] } diff --git a/crates/attestation-provider-server/src/lib.rs b/crates/attestation-provider-server/src/lib.rs index 1db9232..2022f24 100644 --- a/crates/attestation-provider-server/src/lib.rs +++ b/crates/attestation-provider-server/src/lib.rs @@ -48,6 +48,8 @@ pub async fn attestation_provider_client( server_addr: SocketAddr, attestation_verifier: AttestationVerifier, ) -> anyhow::Result { + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + let input_data = [0; 64]; let response = reqwest::get(format!("http://{server_addr}/attest/{}", hex::encode(input_data))) .await? diff --git a/crates/attestation/Cargo.toml b/crates/attestation/Cargo.toml index 138d819..587d927 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -43,6 +43,7 @@ openssl = { version = "0.10.79", optional = true } mock-tdx = { workspace = true } tempfile = "3.23.0" tokio-rustls = { workspace = true, default-features = true } +rustls = { workspace = true, default-features = false, features = ["aws_lc_rs"] } serde-saphyr = "0.0.22" diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index e91d4b8..03f4c28 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -177,6 +177,9 @@ fn ca_issuers_urls(cert: &X509Certificate<'_>) -> Vec { } fn fetch_certificate_der(url: &str) -> Result, MaaError> { + #[cfg(test)] + crate::install_test_crypto_provider(); + if !(url.starts_with("http://") || url.starts_with("https://")) { return Err(MaaError::UnsupportedAiaUrl { url: url.to_string() }); } diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 73bc5ba..b2c6b56 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -5,6 +5,8 @@ pub mod azure; pub mod dcap; pub mod measurements; +#[cfg(test)] +use std::sync::OnceLock; use std::{ fmt::{self, Display, Formatter}, io::Read, @@ -20,6 +22,16 @@ use thiserror::Error; use crate::{dcap::DcapVerificationError, measurements::MeasurementPolicy}; +#[cfg(test)] +static TEST_CRYPTO_PROVIDER: OnceLock<()> = OnceLock::new(); + +#[cfg(test)] +pub(crate) fn install_test_crypto_provider() { + TEST_CRYPTO_PROVIDER.get_or_init(|| { + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + }); +} + /// Used in attestation type detection to check if we are on GCP const GCP_METADATA_API: &str = "http://metadata.google.internal"; diff --git a/crates/attestation/src/measurements.rs b/crates/attestation/src/measurements.rs index db8c2c9..58c98c7 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -423,6 +423,9 @@ impl MeasurementPolicy { /// Given either a URL or the path to a file, parse the measurement /// policy from JSON pub async fn from_file_or_url(file_or_url: String) -> Result { + #[cfg(test)] + crate::install_test_crypto_provider(); + if file_or_url.to_lowercase().trim_ascii().starts_with("https://") { let measurements_json = reqwest::get(file_or_url).await?.bytes().await?; Self::from_json_bytes(measurements_json.to_vec()) diff --git a/crates/attested-tls/src/lib.rs b/crates/attested-tls/src/lib.rs index 1495611..fdf6095 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -1032,7 +1032,10 @@ pub enum AttestedTlsError { #[cfg(test)] mod tests { - use std::{io::Cursor, sync::Arc}; + use std::{ + io::Cursor, + sync::{Arc, OnceLock}, + }; use mock_tdx::mock_pcs::{MockPcsConfig, spawn_mock_pcs_server}; use ra_tls::rcgen::{ @@ -1055,6 +1058,14 @@ mod tests { use super::*; + static TEST_CRYPTO_PROVIDER: OnceLock<()> = OnceLock::new(); + + fn install_test_crypto_provider() { + TEST_CRYPTO_PROVIDER.get_or_init(|| { + let _ = aws_lc_rs::default_provider().install_default(); + }); + } + /// Test helper to verify a certificate fn verify_server_cert_direct( verifier: &AttestedCertificateVerifier, @@ -1090,6 +1101,8 @@ mod tests { root_store: Option, provider: Arc, ) -> AttestedCertificateVerifier { + install_test_crypto_provider(); + let mock_pcs_server = spawn_mock_pcs_server(MockPcsConfig::default()).await.unwrap(); let verifier = AttestationVerifier::mock_with_pccs(mock_pcs_server.base_url.clone()); if let Some(ref pccs) = verifier.internal_pccs { @@ -1532,6 +1545,8 @@ mod tests { #[tokio::test] async fn self_signed_attested_certificate_with_allowed_pubkey_is_accepted() { + install_test_crypto_provider(); + let provider: Arc = aws_lc_rs::default_provider().into(); let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::build( @@ -1672,6 +1687,8 @@ mod tests { #[tokio::test] async fn verifier_reuses_trusted_certificate_cache() { + install_test_crypto_provider(); + let provider: Arc = aws_lc_rs::default_provider().into(); let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::build( @@ -1716,6 +1733,8 @@ mod tests { #[tokio::test(flavor = "multi_thread")] async fn sync_verifier_cache_miss_fails_then_succeeds_after_background_fetch() { + install_test_crypto_provider(); + let provider: Arc = aws_lc_rs::default_provider().into(); let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::build( diff --git a/crates/attested-tls/tests/nested_tls.rs b/crates/attested-tls/tests/nested_tls.rs index 7110e8f..a3dcdf2 100644 --- a/crates/attested-tls/tests/nested_tls.rs +++ b/crates/attested-tls/tests/nested_tls.rs @@ -1,5 +1,5 @@ //! Provides a test demonstrating using nested-tls and attested-tls together -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use attestation::{AttestationGenerator, AttestationType, AttestationVerifier}; use attested_tls::{AttestedCertificateResolver, AttestedCertificateVerifier}; @@ -15,8 +15,18 @@ use rustls::{ }; use tokio::io::{AsyncReadExt, AsyncWriteExt, duplex}; +static TEST_CRYPTO_PROVIDER: OnceLock<()> = OnceLock::new(); + +fn install_test_crypto_provider() { + TEST_CRYPTO_PROVIDER.get_or_init(|| { + let _ = aws_lc_rs::default_provider().install_default(); + }); +} + #[tokio::test(flavor = "multi_thread")] async fn nested_tls_uses_attested_tls_for_inner_session() { + install_test_crypto_provider(); + 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()); @@ -85,6 +95,8 @@ fn plain_tls_config_pair(provider: Arc) -> (ServerConfig, Client /// Create attested server TLS config with mock DCAP attestation and /// self-signed certs fn attested_server_config(server_name: &str, provider: Arc) -> ServerConfig { + install_test_crypto_provider(); + let key_pair = KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(); let resolver = AttestedCertificateResolver::build( server_name, @@ -104,6 +116,8 @@ fn attested_server_config(server_name: &str, provider: Arc) -> S /// Create client TLS config with attestation verification async fn attested_client_config(provider: Arc) -> ClientConfig { + install_test_crypto_provider(); + let mock_pcs_server = spawn_mock_pcs_server(MockPcsConfig::default()).await.unwrap(); let verifier = AttestationVerifier::mock_with_pccs(mock_pcs_server.base_url.clone()); if let Some(ref pccs) = verifier.internal_pccs { diff --git a/crates/pccs/Cargo.toml b/crates/pccs/Cargo.toml index 4a2e7d0..9ea11a2 100644 --- a/crates/pccs/Cargo.toml +++ b/crates/pccs/Cargo.toml @@ -24,3 +24,4 @@ rcgen = "0.14.5" tracing-subscriber = { version = "0.3.20", features = ["env-filter", "fmt"] } serde-saphyr = "0.0.22" mock-tdx = { workspace = true } +rustls = { workspace = true, default-features = false, features = ["aws_lc_rs"] } diff --git a/crates/pccs/src/lib.rs b/crates/pccs/src/lib.rs index 774443b..ae8ee81 100644 --- a/crates/pccs/src/lib.rs +++ b/crates/pccs/src/lib.rs @@ -1,3 +1,5 @@ +#[cfg(test)] +use std::sync::OnceLock; use std::{ collections::{HashMap, HashSet}, sync::{ @@ -20,6 +22,16 @@ use tokio::{ use tracing::debug; use x509_parser::{prelude::FromDer, revocation_list::CertificateRevocationList}; +#[cfg(test)] +static TEST_CRYPTO_PROVIDER: OnceLock<()> = OnceLock::new(); + +#[cfg(test)] +fn install_test_crypto_provider() { + TEST_CRYPTO_PROVIDER.get_or_init(|| { + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + }); +} + /// For fetching collateral directly from Intel pub const PCS_URL: &str = "https://api.trustedservices.intel.com"; /// How long before expiry to refresh collateral @@ -377,6 +389,9 @@ impl Pccs { /// Fetches available FMSPC entries from configured PCCS/PCS endpoint async fn fetch_fmspcs(&self) -> Result, PccsError> { + #[cfg(test)] + install_test_crypto_provider(); + let url = format!("{}/sgx/certification/v4/fmspcs", self.url); let client = reqwest::Client::builder().timeout(Duration::from_secs(15)).build()?; let response = client.get(&url).send().await?; From 5e1d295f2a6b6bdddf64ce27cb06152705635cde Mon Sep 17 00:00:00 2001 From: peg Date: Wed, 8 Jul 2026 14:11:10 +0200 Subject: [PATCH 2/2] Azure feature - add crypto provider for tests --- crates/attestation/src/azure/ak_certificate.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/crates/attestation/src/azure/ak_certificate.rs b/crates/attestation/src/azure/ak_certificate.rs index 03f4c28..6268305 100644 --- a/crates/attestation/src/azure/ak_certificate.rs +++ b/crates/attestation/src/azure/ak_certificate.rs @@ -229,14 +229,25 @@ mod tests { use std::{ io::{Read, Write}, net::TcpListener, + sync::OnceLock, thread, time::Duration, }; use super::*; + static TEST_CRYPTO_PROVIDER: OnceLock<()> = OnceLock::new(); + + fn install_test_crypto_provider() { + TEST_CRYPTO_PROVIDER.get_or_init(|| { + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + }); + } + #[tokio::test] async fn root_should_be_fresh() { + install_test_crypto_provider(); + let response = reqwest::get( "http://www.microsoft.com/pkiops/certs/Microsoft%20RSA%20Devices%20Root%20CA%202021.crt", )