Skip to content

Commit 6a16f7f

Browse files
bors[bot]messense
andauthored
Merge #1483
1483: Add support for custom TLS certificate authority bundle r=messense a=messense Custom TLS CA can be configured via one of the `MATURIN_CA_BUNDLE`, `REQUESTS_CA_BUNDLE` and `CURL_CA_BUNDLE` env vars. Closes #1418 Co-authored-by: messense <[email protected]>
2 parents 83e6b70 + 57193fc commit 6a16f7f

File tree

4 files changed

+95
-33
lines changed

4 files changed

+95
-33
lines changed

Cargo.lock

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+5-3
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ bytesize = { version = "1.0.1", optional = true }
8181
configparser = { version = "3.0.0", optional = true }
8282
multipart = { version = "0.18.0", features = ["client"], default-features = false, optional = true }
8383
ureq = { version = "2.6.1", features = ["gzip", "socks-proxy"], default-features = false, optional = true }
84-
native-tls-crate = { package = "native-tls", version = "0.2.8", optional = true }
84+
native-tls = { version = "0.2.8", optional = true }
85+
rustls = { version = "0.20.8", optional = true }
86+
rustls-pemfile = { version = "1.0.1", optional = true }
8587
keyring = { version = "1.1.1", optional = true }
8688

8789
[dev-dependencies]
@@ -105,8 +107,8 @@ upload = ["ureq", "multipart", "configparser", "bytesize", "dialoguer/password"]
105107
# keyring doesn't support *BSD so it's not enabled in `full` by default
106108
password-storage = ["upload", "keyring"]
107109

108-
rustls = ["ureq/tls", "cargo-xwin/rustls-tls"]
109-
native-tls = ["ureq/native-tls", "native-tls-crate", "cargo-xwin/native-tls"]
110+
rustls = ["dep:rustls", "ureq?/tls", "cargo-xwin?/rustls-tls", "dep:rustls-pemfile"]
111+
native-tls = ["dep:native-tls", "ureq?/native-tls", "cargo-xwin?/native-tls", "dep:rustls-pemfile"]
110112

111113
# cross compile using zig or xwin
112114
cross-compile = ["zig", "xwin"]

Changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
* Respect `rustflags` settings in cargo configuration file in [#1405](https://github.com/PyO3/maturin/pull/1405)
1717
* Bump MSRV to 1.63.0 in [#1407](https://github.com/PyO3/maturin/pull/1407)
1818
* Add support for uniffi 0.23 in [#1481](https://github.com/PyO3/maturin/pull/1481)
19+
* Add support for custom TLS certificate authority bundle in [#1483](https://github.com/PyO3/maturin/pull/1483)
1920
* Add support for Emscripten in `generate-ci` command in [#1484](https://github.com/PyO3/maturin/pull/1484)
2021
* Add support for linking with pyo3 in abi3 debug mode on Windows in [#1487](https://github.com/PyO3/maturin/pull/1487)
2122

src/upload.rs

+78-30
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use fs_err::File;
1010
use multipart::client::lazy::Multipart;
1111
use regex::Regex;
1212
use std::env;
13+
#[cfg(any(feature = "native-tls", feature = "rustls"))]
14+
use std::ffi::OsString;
1315
use std::io;
1416
use std::path::{Path, PathBuf};
1517
use thiserror::Error;
@@ -84,7 +86,7 @@ pub enum UploadError {
8486
/// TLS error
8587
#[cfg(feature = "native-tls")]
8688
#[error("TLS Error")]
87-
TlsError(#[source] native_tls_crate::Error),
89+
TlsError(#[source] native_tls::Error),
8890
}
8991

9092
impl From<io::Error> for UploadError {
@@ -100,8 +102,8 @@ impl From<ureq::Error> for UploadError {
100102
}
101103

102104
#[cfg(feature = "native-tls")]
103-
impl From<native_tls_crate::Error> for UploadError {
104-
fn from(error: native_tls_crate::Error) -> Self {
105+
impl From<native_tls::Error> for UploadError {
106+
fn from(error: native_tls::Error) -> Self {
105107
UploadError::TlsError(error)
106108
}
107109
}
@@ -262,6 +264,78 @@ fn canonicalize_name(name: &str) -> String {
262264
.to_lowercase()
263265
}
264266

267+
fn http_proxy() -> Result<String, env::VarError> {
268+
env::var("HTTPS_PROXY")
269+
.or_else(|_| env::var("https_proxy"))
270+
.or_else(|_| env::var("HTTP_PROXY"))
271+
.or_else(|_| env::var("http_proxy"))
272+
}
273+
274+
#[cfg(any(feature = "native-tls", feature = "rustls"))]
275+
fn tls_ca_bundle() -> Option<OsString> {
276+
env::var_os("MATURIN_CA_BUNDLE")
277+
.or_else(|| env::var_os("REQUESTS_CA_BUNDLE"))
278+
.or_else(|| env::var_os("CURL_CA_BUNDLE"))
279+
}
280+
281+
// Prefer rustls if both native-tls and rustls features are enabled
282+
#[cfg(all(feature = "native-tls", not(feature = "rustls")))]
283+
#[allow(clippy::result_large_err)]
284+
fn http_agent() -> Result<ureq::Agent, UploadError> {
285+
use std::sync::Arc;
286+
287+
let mut builder = ureq::builder();
288+
if let Ok(proxy) = http_proxy() {
289+
let proxy = ureq::Proxy::new(proxy)?;
290+
builder = builder.proxy(proxy);
291+
};
292+
let mut tls_builder = native_tls::TlsConnector::builder();
293+
if let Some(ca_bundle) = tls_ca_bundle() {
294+
let mut reader = io::BufReader::new(File::open(ca_bundle)?);
295+
for cert in rustls_pemfile::certs(&mut reader)? {
296+
tls_builder.add_root_certificate(native_tls::Certificate::from_pem(&cert)?);
297+
}
298+
}
299+
builder = builder.tls_connector(Arc::new(tls_builder.build()?));
300+
Ok(builder.build())
301+
}
302+
303+
#[cfg(feature = "rustls")]
304+
#[allow(clippy::result_large_err)]
305+
fn http_agent() -> Result<ureq::Agent, UploadError> {
306+
use std::sync::Arc;
307+
308+
let mut builder = ureq::builder();
309+
if let Ok(proxy) = http_proxy() {
310+
let proxy = ureq::Proxy::new(proxy)?;
311+
builder = builder.proxy(proxy);
312+
};
313+
if let Some(ca_bundle) = tls_ca_bundle() {
314+
let mut reader = io::BufReader::new(File::open(ca_bundle)?);
315+
let certs = rustls_pemfile::certs(&mut reader)?;
316+
let mut root_certs = rustls::RootCertStore::empty();
317+
root_certs.add_parsable_certificates(&certs);
318+
let client_config = rustls::ClientConfig::builder()
319+
.with_safe_defaults()
320+
.with_root_certificates(root_certs)
321+
.with_no_client_auth();
322+
Ok(builder.tls_config(Arc::new(client_config)).build())
323+
} else {
324+
Ok(builder.build())
325+
}
326+
}
327+
328+
#[cfg(not(any(feature = "native-tls", feature = "rustls")))]
329+
#[allow(clippy::result_large_err)]
330+
fn http_agent() -> Result<ureq::Agent, UploadError> {
331+
let mut builder = ureq::builder();
332+
if let Ok(proxy) = http_proxy() {
333+
let proxy = ureq::Proxy::new(proxy)?;
334+
builder = builder.proxy(proxy);
335+
};
336+
Ok(builder.build())
337+
}
338+
265339
/// Uploads a single wheel to the registry
266340
#[allow(clippy::result_large_err)]
267341
pub fn upload(registry: &Registry, wheel_path: &Path) -> Result<(), UploadError> {
@@ -339,35 +413,9 @@ pub fn upload(registry: &Registry, wheel_path: &Path) -> Result<(), UploadError>
339413

340414
form.add_stream("content", &wheel, Some(wheel_name), None);
341415
let multipart_data = form.prepare().map_err(|e| e.error)?;
342-
343416
let encoded = base64::encode(format!("{}:{}", registry.username, registry.password));
344417

345-
let http_proxy = env::var("HTTPS_PROXY")
346-
.or_else(|_| env::var("https_proxy"))
347-
.or_else(|_| env::var("HTTP_PROXY"))
348-
.or_else(|_| env::var("http_proxy"));
349-
350-
#[cfg(not(feature = "native-tls"))]
351-
let agent = {
352-
let mut builder = ureq::builder();
353-
if let Ok(proxy) = http_proxy {
354-
let proxy = ureq::Proxy::new(proxy)?;
355-
builder = builder.proxy(proxy);
356-
};
357-
builder.build()
358-
};
359-
360-
#[cfg(feature = "native-tls")]
361-
let agent = {
362-
use std::sync::Arc;
363-
let mut builder =
364-
ureq::builder().tls_connector(Arc::new(native_tls_crate::TlsConnector::new()?));
365-
if let Ok(proxy) = http_proxy {
366-
let proxy = ureq::Proxy::new(proxy)?;
367-
builder = builder.proxy(proxy);
368-
};
369-
builder.build()
370-
};
418+
let agent = http_agent()?;
371419

372420
let response = agent
373421
.post(registry.url.as_str())

0 commit comments

Comments
 (0)