diff --git a/codex-rs/Cargo.toml b/codex-rs/Cargo.toml index dfb89a02c..fcf8dbd9c 100644 --- a/codex-rs/Cargo.toml +++ b/codex-rs/Cargo.toml @@ -363,7 +363,7 @@ reqwest = { version = "0.12", features = ["cookies"] } rmcp = { version = "1.7.0", default-features = false } runfiles = { git = "https://github.com/dzbarsky/rules_rust", rev = "b56cbaa8465e74127f1ea216f813cd377295ad81" } rustls = { version = "0.23", default-features = false, features = [ - "ring", + "aws_lc_rs", "std", ] } rustls-native-certs = "0.8.3" diff --git a/codex-rs/utils/rustls-provider/src/lib.rs b/codex-rs/utils/rustls-provider/src/lib.rs index 39d01d182..0269819ba 100644 --- a/codex-rs/utils/rustls-provider/src/lib.rs +++ b/codex-rs/utils/rustls-provider/src/lib.rs @@ -1,5 +1,8 @@ use std::sync::Once; +const REQUIRED_SIGNATURE_SCHEME: rustls::SignatureScheme = + rustls::SignatureScheme::ECDSA_NISTP521_SHA512; + /// Ensures a process-wide rustls crypto provider is installed. /// /// rustls cannot auto-select a provider when both `ring` and `aws-lc-rs` @@ -7,6 +10,30 @@ use std::sync::Once; pub fn ensure_rustls_crypto_provider() { static RUSTLS_PROVIDER_INIT: Once = Once::new(); RUSTLS_PROVIDER_INIT.call_once(|| { - let _ = rustls::crypto::ring::default_provider().install_default(); + // aws-lc-rs supports a broader WebPKI signature set than ring, including + // ECDSA P-521/SHA-512 certs used by some enterprise TLS proxies. + if rustls::crypto::aws_lc_rs::default_provider() + .install_default() + .is_err() + { + // Preserve the previous best-effort behavior for embedded hosts that + // install a process-global provider before Codex can install one. + return; + } + + let Some(provider) = rustls::crypto::CryptoProvider::get_default() else { + panic!("aws-lc-rs rustls crypto provider should be installed"); + }; + assert!( + provider_supports_required_signature_scheme(provider), + "installed rustls crypto provider must support {REQUIRED_SIGNATURE_SCHEME:?}" + ); }); } + +fn provider_supports_required_signature_scheme(provider: &rustls::crypto::CryptoProvider) -> bool { + provider + .signature_verification_algorithms + .supported_schemes() + .contains(&REQUIRED_SIGNATURE_SCHEME) +} diff --git a/codex-rs/utils/rustls-provider/tests/preinstalled.rs b/codex-rs/utils/rustls-provider/tests/preinstalled.rs new file mode 100644 index 000000000..714f40bf6 --- /dev/null +++ b/codex-rs/utils/rustls-provider/tests/preinstalled.rs @@ -0,0 +1,26 @@ +use codex_utils_rustls_provider::ensure_rustls_crypto_provider; + +const EMPTY_ALGORITHMS: rustls::crypto::WebPkiSupportedAlgorithms = + rustls::crypto::WebPkiSupportedAlgorithms { + all: &[], + mapping: &[], + }; + +#[test] +fn ensure_provider_preserves_preinstalled_provider() { + let mut provider = rustls::crypto::aws_lc_rs::default_provider(); + provider.signature_verification_algorithms = EMPTY_ALGORITHMS; + assert!(provider.install_default().is_ok()); + + ensure_rustls_crypto_provider(); + + let Some(provider) = rustls::crypto::CryptoProvider::get_default() else { + panic!("preinstalled rustls provider should still be installed"); + }; + assert!( + !provider + .signature_verification_algorithms + .supported_schemes() + .contains(&rustls::SignatureScheme::ECDSA_NISTP521_SHA512) + ); +} diff --git a/codex-rs/utils/rustls-provider/tests/provider.rs b/codex-rs/utils/rustls-provider/tests/provider.rs new file mode 100644 index 000000000..c02f884e0 --- /dev/null +++ b/codex-rs/utils/rustls-provider/tests/provider.rs @@ -0,0 +1,16 @@ +use codex_utils_rustls_provider::ensure_rustls_crypto_provider; + +#[test] +fn ensure_provider_installs_ecdsa_p521_sha512_support() { + ensure_rustls_crypto_provider(); + + let Some(provider) = rustls::crypto::CryptoProvider::get_default() else { + panic!("rustls provider should be installed"); + }; + assert!( + provider + .signature_verification_algorithms + .supported_schemes() + .contains(&rustls::SignatureScheme::ECDSA_NISTP521_SHA512) + ); +}