diff --git a/crates/pccs/Cargo.toml b/crates/pccs/Cargo.toml index 9ea11a2..ac4f30d 100644 --- a/crates/pccs/Cargo.toml +++ b/crates/pccs/Cargo.toml @@ -17,6 +17,9 @@ serde_json = "1.0.145" hex = "0.4.3" anyhow = "1.0.100" reqwest = { workspace = true } +# No provider feature: only the process-default lookup is needed here — which +# crypto provider backs it stays the application's choice. +rustls = { workspace = true, default-features = false } x509-parser = "0.18.0" [dev-dependencies] @@ -24,4 +27,6 @@ rcgen = "0.14.5" tracing-subscriber = { version = "0.3.20", features = ["env-filter", "fmt"] } serde-saphyr = "0.0.22" mock-tdx = { workspace = true } +# Tests exercise real TLS fetches against local mock servers, so they install +# a concrete provider. 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 ae8ee81..2945104 100644 --- a/crates/pccs/src/lib.rs +++ b/crates/pccs/src/lib.rs @@ -43,6 +43,13 @@ const REFRESH_RETRY_SECS: u64 = 60; const STARTUP_PREWARM_CONCURRENCY: usize = 8; /// PCCS collateral cache with proactive background refresh +/// +/// Fetching runs over rustls-backed HTTP, so the application must install a +/// process-level rustls [crypto provider] before collateral can be fetched, +/// e.g. `rustls::crypto::aws_lc_rs::default_provider().install_default()`. +/// Without one, fetches fail with [`PccsError::MissingCryptoProvider`]. +/// +/// [crypto provider]: https://github.com/rustls/rustls#cryptography-providers #[derive(Clone)] pub struct Pccs { /// The URL of the service used to fetch collateral (PCS / PCCS) @@ -300,7 +307,11 @@ impl Pccs { let fmspcs = match self.fetch_fmspcs().await { Ok(fmspcs) => fmspcs, Err(e) => { - tracing::warn!(error = %e, "Failed to fetch FMSPC list for startup pre-provision"); + tracing::warn!( + error = %e, + "Failed to fetch FMSPC list for startup pre-provision; continuing \ + without a warm cache — collateral is fetched on demand" + ); return PrewarmOutcome::Failed(format!( "Failed to fetch FMSPC list for prewarm: {e}" )); @@ -392,6 +403,13 @@ impl Pccs { #[cfg(test)] install_test_crypto_provider(); + // Without a process-level crypto provider, building the reqwest + // client panics; error instead, so the pre-warm task logs a warning + // rather than dumping a panic backtrace. + if rustls::crypto::CryptoProvider::get_default().is_none() { + return Err(PccsError::MissingCryptoProvider); + } + 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?; @@ -719,6 +737,12 @@ pub enum PccsError { SystemTime(#[from] std::time::SystemTimeError), #[error("HTTP client: {0}")] Reqwest(#[from] reqwest::Error), + #[error( + "no process-level rustls crypto provider is installed; install one at application \ + startup, e.g. `rustls::crypto::aws_lc_rs::default_provider().install_default()` — \ + see https://github.com/rustls/rustls#cryptography-providers" + )] + MissingCryptoProvider, #[error("Failed to fetch FMSPC: {0}")] FmspcFetch(reqwest::StatusCode), #[error("JSON: {0}")]