diff --git a/Cargo.lock b/Cargo.lock index 76fd031a0e..10d9cd581e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2184,6 +2184,7 @@ dependencies = [ "rs_tracing", "rustls", "rustls-platform-verifier", + "rustls-webpki", "same-file", "scopeguard", "semver", @@ -2198,6 +2199,7 @@ dependencies = [ "threadpool", "tokio", "tokio-retry", + "tokio-rustls", "tokio-stream", "toml", "tracing", @@ -2207,6 +2209,7 @@ dependencies = [ "url", "wait-timeout", "walkdir", + "webpki-root-certs", "windows-registry", "windows-result", "windows-sys 0.61.2", diff --git a/Cargo.toml b/Cargo.toml index 8d3e0e0d1c..cc2fd7cd60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -140,6 +140,9 @@ http-body-util = "0.1.0" hyper = { version = "1.0", default-features = false, features = ["server", "http1"] } hyper-util = { version = "0.1.1", features = ["tokio"] } proptest = "1.1.0" +rustls-webpki = { version = "0.103.3" } +tokio-rustls = "0.26.4" +webpki-root-certs = "1" [build-dependencies] platforms = "3.4" diff --git a/src/anchors.rs b/src/anchors.rs new file mode 100644 index 0000000000..b539a0415d --- /dev/null +++ b/src/anchors.rs @@ -0,0 +1,92 @@ +// @generated by tests/static_roots.rs +use rustls::pki_types::CertificateDer; + +pub(crate) const RUSTUP_TRUST_ANCHORS: &[CertificateDer<'static>] = &[ + CertificateDer::from_slice(&[ + 48, 130, 3, 95, 48, 130, 2, 71, 160, 3, 2, 1, 2, 2, 11, 4, 0, 0, 0, 0, 1, 33, 88, 83, 8, + 162, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 11, 5, 0, 48, 76, 49, 32, 48, 30, 6, 3, + 85, 4, 11, 19, 23, 71, 108, 111, 98, 97, 108, 83, 105, 103, 110, 32, 82, 111, 111, 116, 32, + 67, 65, 32, 45, 32, 82, 51, 49, 19, 48, 17, 6, 3, 85, 4, 10, 19, 10, 71, 108, 111, 98, 97, + 108, 83, 105, 103, 110, 49, 19, 48, 17, 6, 3, 85, 4, 3, 19, 10, 71, 108, 111, 98, 97, 108, + 83, 105, 103, 110, 48, 30, 23, 13, 48, 57, 48, 51, 49, 56, 49, 48, 48, 48, 48, 48, 90, 23, + 13, 50, 57, 48, 51, 49, 56, 49, 48, 48, 48, 48, 48, 90, 48, 76, 49, 32, 48, 30, 6, 3, 85, + 4, 11, 19, 23, 71, 108, 111, 98, 97, 108, 83, 105, 103, 110, 32, 82, 111, 111, 116, 32, 67, + 65, 32, 45, 32, 82, 51, 49, 19, 48, 17, 6, 3, 85, 4, 10, 19, 10, 71, 108, 111, 98, 97, 108, + 83, 105, 103, 110, 49, 19, 48, 17, 6, 3, 85, 4, 3, 19, 10, 71, 108, 111, 98, 97, 108, 83, + 105, 103, 110, 48, 130, 1, 34, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, + 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, 1, 1, 0, 204, 37, 118, 144, 121, 6, 120, 34, 22, + 245, 192, 131, 182, 132, 202, 40, 158, 253, 5, 118, 17, 197, 173, 136, 114, 252, 70, 2, 67, + 199, 178, 138, 157, 4, 95, 36, 203, 46, 75, 225, 96, 130, 70, 225, 82, 171, 12, 129, 71, + 112, 108, 221, 100, 209, 235, 245, 44, 163, 15, 130, 61, 12, 43, 174, 151, 215, 182, 20, + 134, 16, 121, 187, 59, 19, 128, 119, 140, 8, 225, 73, 210, 106, 98, 47, 31, 94, 250, 150, + 104, 223, 137, 39, 149, 56, 159, 6, 215, 62, 201, 203, 38, 89, 13, 115, 222, 176, 200, 233, + 38, 14, 131, 21, 198, 239, 91, 139, 210, 4, 96, 202, 73, 166, 40, 246, 105, 59, 246, 203, + 200, 40, 145, 229, 157, 138, 97, 87, 55, 172, 116, 20, 220, 116, 224, 58, 238, 114, 47, 46, + 156, 251, 208, 187, 191, 245, 61, 0, 225, 6, 51, 232, 130, 43, 174, 83, 166, 58, 22, 115, + 140, 221, 65, 14, 32, 58, 192, 180, 167, 161, 233, 178, 79, 144, 46, 50, 96, 233, 87, 203, + 185, 4, 146, 104, 104, 229, 56, 38, 96, 117, 178, 159, 119, 255, 145, 20, 239, 174, 32, 73, + 252, 173, 64, 21, 72, 209, 2, 49, 97, 25, 94, 184, 151, 239, 173, 119, 183, 100, 154, 122, + 191, 95, 193, 19, 239, 155, 98, 251, 13, 108, 224, 84, 105, 22, 169, 3, 218, 110, 233, 131, + 147, 113, 118, 198, 105, 133, 130, 23, 2, 3, 1, 0, 1, 163, 66, 48, 64, 48, 14, 6, 3, 85, + 29, 15, 1, 1, 255, 4, 4, 3, 2, 1, 6, 48, 15, 6, 3, 85, 29, 19, 1, 1, 255, 4, 5, 48, 3, 1, + 1, 255, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 143, 240, 75, 127, 168, 46, 69, 36, 174, + 77, 80, 250, 99, 154, 139, 222, 226, 221, 27, 188, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, + 1, 1, 11, 5, 0, 3, 130, 1, 1, 0, 75, 64, 219, 192, 80, 170, 254, 200, 12, 239, 247, 150, + 84, 69, 73, 187, 150, 0, 9, 65, 172, 179, 19, 134, 134, 40, 7, 51, 202, 107, 230, 116, 185, + 186, 0, 45, 174, 164, 10, 211, 245, 241, 241, 15, 138, 191, 115, 103, 74, 131, 199, 68, + 123, 120, 224, 175, 110, 108, 111, 3, 41, 142, 51, 57, 69, 195, 142, 228, 185, 87, 108, + 170, 252, 18, 150, 236, 83, 198, 45, 228, 36, 108, 185, 148, 99, 251, 220, 83, 104, 103, + 86, 62, 131, 184, 207, 53, 33, 195, 201, 104, 254, 206, 218, 194, 83, 170, 204, 144, 138, + 233, 240, 93, 70, 140, 149, 221, 122, 88, 40, 26, 47, 29, 222, 205, 0, 55, 65, 143, 237, + 68, 109, 215, 83, 40, 151, 126, 243, 103, 4, 30, 21, 215, 138, 150, 180, 211, 222, 76, 39, + 164, 76, 27, 115, 115, 118, 244, 23, 153, 194, 31, 122, 14, 227, 45, 8, 173, 10, 28, 44, + 255, 60, 171, 85, 14, 15, 145, 126, 54, 235, 195, 87, 73, 190, 225, 46, 45, 124, 96, 139, + 195, 65, 81, 19, 35, 157, 206, 247, 50, 107, 148, 1, 168, 153, 231, 44, 51, 31, 58, 59, 37, + 210, 134, 64, 206, 59, 44, 134, 120, 201, 97, 47, 20, 186, 238, 219, 85, 111, 223, 132, + 238, 5, 9, 77, 189, 40, 216, 114, 206, 211, 98, 80, 101, 30, 235, 146, 151, 131, 49, 217, + 179, 181, 202, 71, 88, 63, 95, + ]), + CertificateDer::from_slice(&[ + 48, 130, 3, 65, 48, 130, 2, 41, 160, 3, 2, 1, 2, 2, 19, 6, 108, 159, 207, 153, 191, 140, + 10, 57, 226, 240, 120, 138, 67, 230, 150, 54, 91, 202, 48, 13, 6, 9, 42, 134, 72, 134, 247, + 13, 1, 1, 11, 5, 0, 48, 57, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 15, 48, 13, + 6, 3, 85, 4, 10, 19, 6, 65, 109, 97, 122, 111, 110, 49, 25, 48, 23, 6, 3, 85, 4, 3, 19, 16, + 65, 109, 97, 122, 111, 110, 32, 82, 111, 111, 116, 32, 67, 65, 32, 49, 48, 30, 23, 13, 49, + 53, 48, 53, 50, 54, 48, 48, 48, 48, 48, 48, 90, 23, 13, 51, 56, 48, 49, 49, 55, 48, 48, 48, + 48, 48, 48, 90, 48, 57, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 15, 48, 13, 6, 3, + 85, 4, 10, 19, 6, 65, 109, 97, 122, 111, 110, 49, 25, 48, 23, 6, 3, 85, 4, 3, 19, 16, 65, + 109, 97, 122, 111, 110, 32, 82, 111, 111, 116, 32, 67, 65, 32, 49, 48, 130, 1, 34, 48, 13, + 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 1, 5, 0, 3, 130, 1, 15, 0, 48, 130, 1, 10, 2, 130, + 1, 1, 0, 178, 120, 128, 113, 202, 120, 213, 227, 113, 175, 71, 128, 80, 116, 125, 110, 216, + 215, 136, 118, 244, 153, 104, 247, 88, 33, 96, 249, 116, 132, 1, 47, 172, 2, 45, 134, 211, + 160, 67, 122, 78, 178, 164, 208, 54, 186, 1, 190, 141, 219, 72, 200, 7, 23, 54, 76, 244, + 238, 136, 35, 199, 62, 235, 55, 245, 181, 25, 248, 73, 104, 176, 222, 215, 185, 118, 56, + 29, 97, 158, 164, 254, 130, 54, 165, 229, 74, 86, 228, 69, 225, 249, 253, 180, 22, 250, + 116, 218, 156, 155, 53, 57, 47, 250, 176, 32, 80, 6, 108, 122, 208, 128, 178, 166, 249, + 175, 236, 71, 25, 143, 80, 56, 7, 220, 162, 135, 57, 88, 248, 186, 213, 169, 249, 72, 103, + 48, 150, 238, 148, 120, 94, 111, 137, 163, 81, 192, 48, 134, 102, 161, 69, 102, 186, 84, + 235, 163, 195, 145, 249, 72, 220, 255, 209, 232, 48, 45, 125, 45, 116, 112, 53, 215, 136, + 36, 247, 158, 196, 89, 110, 187, 115, 135, 23, 242, 50, 70, 40, 184, 67, 250, 183, 29, 170, + 202, 180, 242, 159, 36, 14, 45, 75, 247, 113, 92, 94, 105, 255, 234, 149, 2, 203, 56, 138, + 174, 80, 56, 111, 219, 251, 45, 98, 27, 197, 199, 30, 84, 225, 119, 224, 103, 200, 15, 156, + 135, 35, 214, 63, 64, 32, 127, 32, 128, 196, 128, 76, 62, 59, 36, 38, 142, 4, 174, 108, + 154, 200, 170, 13, 2, 3, 1, 0, 1, 163, 66, 48, 64, 48, 15, 6, 3, 85, 29, 19, 1, 1, 255, 4, + 5, 48, 3, 1, 1, 255, 48, 14, 6, 3, 85, 29, 15, 1, 1, 255, 4, 4, 3, 2, 1, 134, 48, 29, 6, 3, + 85, 29, 14, 4, 22, 4, 20, 132, 24, 204, 133, 52, 236, 188, 12, 148, 148, 46, 8, 89, 156, + 199, 178, 16, 78, 10, 8, 48, 13, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 11, 5, 0, 3, 130, + 1, 1, 0, 152, 242, 55, 90, 65, 144, 161, 26, 197, 118, 81, 40, 32, 54, 35, 14, 174, 230, + 40, 187, 170, 248, 148, 174, 72, 164, 48, 127, 27, 252, 36, 141, 75, 180, 200, 161, 151, + 246, 182, 241, 122, 112, 200, 83, 147, 204, 8, 40, 227, 152, 37, 207, 35, 164, 249, 222, + 33, 211, 124, 133, 9, 173, 78, 154, 117, 58, 194, 11, 106, 137, 120, 118, 68, 71, 24, 101, + 108, 141, 65, 142, 59, 127, 154, 203, 244, 181, 167, 80, 215, 5, 44, 55, 232, 3, 75, 173, + 233, 97, 160, 2, 110, 245, 242, 240, 197, 178, 237, 91, 183, 220, 250, 148, 92, 119, 158, + 19, 165, 127, 82, 173, 149, 242, 248, 147, 59, 222, 139, 92, 91, 202, 90, 82, 91, 96, 175, + 20, 247, 75, 239, 163, 251, 159, 64, 149, 109, 49, 84, 252, 66, 211, 199, 70, 31, 35, 173, + 217, 15, 72, 112, 154, 217, 117, 120, 113, 209, 114, 67, 52, 117, 110, 87, 89, 194, 2, 92, + 38, 96, 41, 207, 35, 25, 22, 142, 136, 67, 165, 212, 228, 203, 8, 251, 35, 17, 67, 232, 67, + 41, 114, 98, 161, 169, 93, 94, 8, 212, 144, 174, 184, 216, 206, 20, 194, 208, 85, 242, 134, + 246, 196, 147, 67, 119, 102, 97, 192, 185, 232, 65, 215, 151, 120, 96, 3, 110, 74, 114, + 174, 165, 209, 125, 186, 16, 158, 134, 108, 27, 138, 185, 89, 51, 248, 235, 196, 144, 190, + 241, 185, + ]), +]; diff --git a/src/download/mod.rs b/src/download/mod.rs index b32524a596..34d209d9c8 100644 --- a/src/download/mod.rs +++ b/src/download/mod.rs @@ -546,12 +546,14 @@ mod reqwest_be { use std::sync::{Arc, OnceLock}; use std::time::Duration; + #[cfg(feature = "reqwest-rustls-tls")] + use crate::anchors::RUSTUP_TRUST_ANCHORS; use anyhow::{Context, anyhow}; use reqwest::{Client, ClientBuilder, Proxy, Response, header}; #[cfg(feature = "reqwest-rustls-tls")] use rustls::crypto::aws_lc_rs; #[cfg(feature = "reqwest-rustls-tls")] - use rustls_platform_verifier::BuilderVerifierExt; + use rustls_platform_verifier::Verifier; use tokio_stream::StreamExt; use url::Url; @@ -607,15 +609,19 @@ mod reqwest_be { return Ok(client); } - let mut tls_config = - rustls::ClientConfig::builder_with_provider(Arc::new(aws_lc_rs::default_provider())) - .with_safe_default_protocol_versions() - .unwrap() - .with_platform_verifier() + let provider = Arc::new(aws_lc_rs::default_provider()); + let verifier = + Verifier::new_with_extra_roots(RUSTUP_TRUST_ANCHORS.iter().cloned(), provider.clone()) .map_err(|err| { DownloadError::Message(format!("failed to initialize platform verifier: {err}")) - })? - .with_no_client_auth(); + })?; + + let mut tls_config = rustls::ClientConfig::builder_with_provider(provider) + .with_safe_default_protocol_versions() + .unwrap() + .dangerous() // We're using a rustls verifier, so it's okay + .with_custom_certificate_verifier(Arc::new(verifier)) + .with_no_client_auth(); tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()]; let client = client_generic() diff --git a/src/lib.rs b/src/lib.rs index 14f2583a43..bae66fd58a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,6 +70,8 @@ fn component_for_bin(binary: &str) -> Option<&'static str> { #[macro_use] pub mod cli; +#[cfg(feature = "reqwest-rustls-tls")] +mod anchors; mod command; mod config; mod diskio; diff --git a/tests/suite/mod.rs b/tests/suite/mod.rs index ce3956ca3d..d36dba144b 100644 --- a/tests/suite/mod.rs +++ b/tests/suite/mod.rs @@ -10,3 +10,4 @@ mod cli_v1; mod cli_v2; mod dist_install; mod known_triples; +mod static_roots; diff --git a/tests/suite/static_roots.rs b/tests/suite/static_roots.rs new file mode 100644 index 0000000000..f4eb3479bf --- /dev/null +++ b/tests/suite/static_roots.rs @@ -0,0 +1,172 @@ +//! Connects to a known set of `HOSTS`, captures the root certificates for the +//! certificate chain presented, and writes them to `src/anchors.rs` in a way +//! that is easy to consume for use as `extra_roots` in rustls-platform-verifier. + +use std::{ + fs, + process::Command, + sync::{Arc, Mutex}, +}; + +use rustls::{ + DigitallySignedStruct, Error, RootCertStore, SignatureScheme, + client::{ + WebPkiServerVerifier, + danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}, + }, + crypto::{CryptoProvider, aws_lc_rs}, + pki_types::{CertificateDer, ServerName, TrustAnchor, UnixTime}, +}; +use tempfile::NamedTempFile; +use tokio::net::TcpStream; +use tokio_rustls::TlsConnector; +use webpki::{EndEntityCert, anchor_from_trusted_cert}; +use webpki_root_certs::TLS_SERVER_ROOT_CERTS; + +#[tokio::test] +async fn store_static_roots() { + let provider = Arc::new(aws_lc_rs::default_provider()); + let mut root_store = RootCertStore::empty(); + let mut roots = Vec::with_capacity(TLS_SERVER_ROOT_CERTS.len()); + for cert_der in TLS_SERVER_ROOT_CERTS { + let ta = anchor_from_trusted_cert(cert_der).unwrap(); + roots.push((cert_der, ta.clone())); + root_store.roots.push(ta); + } + + let root_store = Arc::new(root_store); + let inner = WebPkiServerVerifier::builder_with_provider(root_store.clone(), provider.clone()) + .build() + .unwrap(); + + let verifier = Arc::new(TrackRootVerifier { + root: Mutex::default(), + roots: root_store, + inner, + provider: provider.clone(), + }); + + let config = Arc::new( + rustls::ClientConfig::builder_with_provider(provider) + .with_safe_default_protocol_versions() + .unwrap() + .dangerous() + .with_custom_certificate_verifier(verifier.clone()) + .with_no_client_auth(), + ); + + let mut code = "// @generated by tests/static_roots.rs\n".to_string(); + code.push_str("use rustls::pki_types::CertificateDer;\n\n"); + code.push_str("pub(crate) const RUSTUP_TRUST_ANCHORS: &[CertificateDer<'static>] = &[\n"); + let connector = TlsConnector::from(config); + for &host in HOSTS { + connector + .connect( + ServerName::try_from(host).unwrap(), + TcpStream::connect((host, 443)).await.unwrap(), + ) + .await + .unwrap(); + + let root = verifier.root.lock().unwrap().take().unwrap(); + let root_cert = roots + .iter() + .find_map(|(cert_der, ta)| match ta == &root { + true => Some(cert_der), + false => None, + }) + .unwrap(); + + code.push_str(&format!( + " CertificateDer::from_slice(&{:?}),\n", + root_cert.as_ref() + )); + } + code.push_str("];\n"); + + let tmp = NamedTempFile::new().unwrap(); + fs::write(&tmp, &code).unwrap(); + Command::new("rustfmt").arg(tmp.path()).status().unwrap(); + let new = fs::read_to_string(&tmp).unwrap(); + + let old = fs::read_to_string(PATH).unwrap(); + if old != new { + fs::rename(tmp.path(), PATH).unwrap(); + panic!("anchors.rs is outdated; updated it"); + } +} + +const PATH: &str = "src/anchors.rs"; + +#[derive(Debug)] +struct TrackRootVerifier { + root: Mutex>>, + inner: Arc, + roots: Arc, + provider: Arc, +} + +impl ServerCertVerifier for TrackRootVerifier { + fn verify_server_cert( + &self, + end_entity: &CertificateDer<'_>, + intermediates: &[CertificateDer<'_>], + server_name: &ServerName<'_>, + ocsp_response: &[u8], + now: UnixTime, + ) -> Result { + let verified = self.inner.verify_server_cert( + end_entity, + intermediates, + server_name, + ocsp_response, + now, + )?; + + let cert = EndEntityCert::try_from(end_entity) + .map_err(|e| Error::General(format!("invalid end entity certificate: {e}")))?; + + let path = cert + .verify_for_usage( + &self.provider.signature_verification_algorithms.all, + &self.roots.roots, + intermediates, + now, + webpki::KeyUsage::server_auth(), + None, + None, + ) + .unwrap(); + + let mut root = self.root.lock().unwrap(); + *root = Some(path.anchor().to_owned()); + Ok(verified) + } + + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + self.inner.verify_tls12_signature(message, cert, dss) + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + self.inner.verify_tls13_signature(message, cert, dss) + } + + fn supported_verify_schemes(&self) -> Vec { + self.inner.supported_verify_schemes() + } +} + +const HOSTS: &[&str] = &[ + "fastly-static.rust-lang.org", + "cloudfront-static.rust-lang.org", +];