From 425bcb9e4becb64ba450ffb026c22e5c82abbedb Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sun, 10 Mar 2024 22:12:36 -0400 Subject: [PATCH] Use rustls-tls with manual SSL_CERT_FILE implementation --- Cargo.lock | 52 ++++--------------------- Cargo.toml | 2 +- crates/uv-client/src/middleware.rs | 23 +++++++++-- crates/uv-client/src/registry_client.rs | 19 +++++++-- 4 files changed, 44 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b3743590..ff12bfbae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2857,7 +2857,6 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", - "rustls-native-certs", "rustls-pemfile", "serde", "serde_json", @@ -2873,6 +2872,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots", "winreg", ] @@ -3092,18 +3092,6 @@ dependencies = [ "sct", ] -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -3160,15 +3148,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -3211,29 +3190,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "serde" version = "1.0.197" @@ -4915,6 +4871,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "weezl" version = "0.1.8" diff --git a/Cargo.toml b/Cargo.toml index dd50ebb38..74e62e120 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,7 @@ rand = { version = "0.8.5" } rayon = { version = "1.8.0" } reflink-copy = { version = "0.1.14" } regex = { version = "1.10.2" } -reqwest = { version = "0.11.23", default-features = false, features = ["json", "gzip", "brotli", "stream", "rustls-tls-native-roots"] } +reqwest = { version = "0.11.23", default-features = false, features = ["json", "gzip", "brotli", "stream", "rustls-tls"] } reqwest-middleware = { version = "0.2.4" } reqwest-retry = { version = "0.3.0" } rkyv = { version = "0.7.43", features = ["strict", "validation"] } diff --git a/crates/uv-client/src/middleware.rs b/crates/uv-client/src/middleware.rs index df7e0b59d..60d3144e7 100644 --- a/crates/uv-client/src/middleware.rs +++ b/crates/uv-client/src/middleware.rs @@ -1,8 +1,10 @@ +use std::ffi::OsStr; use std::fmt::Debug; +use std::io::Read; use http::HeaderValue; -use netrc::{Netrc, Result}; -use reqwest::{Request, Response}; +use netrc::Netrc; +use reqwest::{Certificate, Request, Response}; use reqwest_middleware::{Middleware, Next}; use task_local_extensions::Extensions; use url::Url; @@ -56,7 +58,7 @@ pub(crate) struct NetrcMiddleware { } impl NetrcMiddleware { - pub(crate) fn new() -> Result { + pub(crate) fn new() -> netrc::Result { Netrc::new().map(|nrc| NetrcMiddleware { nrc }) } } @@ -121,3 +123,18 @@ where header.set_sensitive(true); header } + +#[derive(thiserror::Error, Debug)] +pub(crate) enum CertificateError { + #[error(transparent)] + Io(#[from] std::io::Error), + #[error(transparent)] + Reqwest(#[from] reqwest::Error), +} + +/// Return the `Certificate` from the provided file. +pub(crate) fn read_certificate(ssl_cert_file: &OsStr) -> Result { + let mut buf = Vec::new(); + fs_err::File::open(ssl_cert_file)?.read_to_end(&mut buf)?; + Ok(Certificate::from_pem(&buf)?) +} diff --git a/crates/uv-client/src/registry_client.rs b/crates/uv-client/src/registry_client.rs index b28960919..2f18cb110 100644 --- a/crates/uv-client/src/registry_client.rs +++ b/crates/uv-client/src/registry_client.rs @@ -29,7 +29,7 @@ use uv_warnings::warn_user_once; use crate::cached_client::CacheControl; use crate::html::SimpleHtml; -use crate::middleware::{NetrcMiddleware, OfflineMiddleware}; +use crate::middleware::{read_certificate, NetrcMiddleware, OfflineMiddleware}; use crate::remote_metadata::wheel_metadata_from_remote_zip; use crate::rkyvutil::OwnedArchive; use crate::{CachedClient, CachedClientError, Error, ErrorKind}; @@ -111,12 +111,25 @@ impl RegistryClientBuilder { // Initialize the base client. let client = self.client.unwrap_or_else(|| { // Disallow any connections. - let client_core = ClientBuilder::new() + let builder = ClientBuilder::new() .user_agent(user_agent_string) .pool_max_idle_per_host(20) .timeout(std::time::Duration::from_secs(timeout)); - client_core.build().expect("Failed to build HTTP client.") + // Add the `SSL_CERT_FILE`, if set. + let builder = if let Some(ssl_cert_file) = env::var_os("SSL_CERT_FILE") { + match read_certificate(&ssl_cert_file) { + Ok(certificate) => builder.add_root_certificate(certificate), + Err(err) => { + warn!("Failed to read SSL certificate file: {err}"); + builder + } + } + } else { + builder + }; + + builder.build().expect("Failed to build HTTP client.") }); // Wrap in any relevant middleware.