diff --git a/Cargo.lock b/Cargo.lock index 81e0888..64b73c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -398,6 +398,7 @@ dependencies = [ "pem-rfc7468", "rand_core 0.6.4", "reqwest 0.13.4", + "rustls", "rustls-webpki", "serde", "serde-saphyr", @@ -425,6 +426,7 @@ dependencies = [ "hex", "parity-scale-codec", "reqwest 0.13.4", + "rustls", "thiserror 2.0.18", "tokio", "tracing", @@ -3159,6 +3161,7 @@ dependencies = [ "mock-tdx", "rcgen 0.14.7", "reqwest 0.13.4", + "rustls", "serde", "serde-saphyr", "serde_json", @@ -3426,7 +3429,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", @@ -3767,7 +3769,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 e13632b..a167b37 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 52403b3..9dc0558 100644 --- a/crates/attestation/Cargo.toml +++ b/crates/attestation/Cargo.toml @@ -45,6 +45,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..6268305 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() }); } @@ -226,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", ) diff --git a/crates/attestation/src/lib.rs b/crates/attestation/src/lib.rs index 8d04bf3..a2c05f1 100644 --- a/crates/attestation/src/lib.rs +++ b/crates/attestation/src/lib.rs @@ -5,6 +5,8 @@ pub mod azure; pub mod dcap; mod gcp; pub mod measurements; +#[cfg(test)] +use std::sync::OnceLock; use std::{ fmt::{self, Display, Formatter}, io::Read, @@ -22,6 +24,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 956669e..9d09ab8 100644 --- a/crates/attestation/src/measurements.rs +++ b/crates/attestation/src/measurements.rs @@ -416,6 +416,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 a9396ed..25a386d 100644 --- a/crates/attested-tls/src/lib.rs +++ b/crates/attested-tls/src/lib.rs @@ -1031,7 +1031,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::{ @@ -1054,6 +1057,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, @@ -1089,6 +1100,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 { @@ -1531,6 +1544,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( @@ -1671,6 +1686,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( @@ -1715,6 +1732,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?;