feat(net): trust platform CA roots alongside bundled webpki roots
reqwest was pinned to rustls-tls, so HTTPS only trusted the bundled webpki roots: SSL_CERT_FILE, SSL_CERT_DIR, and the system CA store were ignored, and obscura-net exposes no add-CA hook. Deployments behind a TLS-inspecting egress proxy or an internal CA cannot fetch at all, and a caching proxy in front of --proxy cannot terminate TLS. Enable rustls-tls-native-roots alongside rustls-tls. reqwest merges the two root stores into one, so the default trust surface only grows and certificate verification is otherwise unchanged: unknown CAs are still rejected. The stealth (wreq) client has its own TLS stack and is out of scope here. Tests: an in-process HTTPS fixture with an rcgen-minted private CA, served via tokio-rustls (pinned to the ring provider so the test binary has a single rustls CryptoProvider). With SSL_CERT_FILE pointing at the CA the fetch succeeds; without it the same fixture is rejected. Fixes #525.
This commit is contained in:
1 parent
e78b5e6026
commit
0522831dcc
4 files changed
+245
-2
No files matched your search
Generated
+140
@@ -510,6 +510,22 @@ version = "5.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f"
|
checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@@ -697,6 +713,12 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deranged"
|
||||||
|
version = "0.5.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "0.99.20"
|
version = "0.99.20"
|
||||||
@@ -1209,6 +1231,7 @@ dependencies = [
|
|||||||
"hyper",
|
"hyper",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls",
|
"rustls",
|
||||||
|
"rustls-native-certs",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
@@ -1608,6 +1631,12 @@ dependencies = [
|
|||||||
"rand 0.8.6",
|
"rand 0.8.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-conv"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.46"
|
version = "0.1.46"
|
||||||
@@ -1764,12 +1793,14 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
|
"rcgen",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
"wreq",
|
"wreq",
|
||||||
@@ -1805,6 +1836,12 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "outref"
|
name = "outref"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -1850,6 +1887,16 @@ dependencies = [
|
|||||||
"hmac",
|
"hmac",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem"
|
||||||
|
version = "3.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.2"
|
version = "2.3.2"
|
||||||
@@ -1961,6 +2008,12 @@ dependencies = [
|
|||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "powerfmt"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.21"
|
version = "0.2.21"
|
||||||
@@ -2147,6 +2200,19 @@ dependencies = [
|
|||||||
"getrandom 0.3.4",
|
"getrandom 0.3.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rcgen"
|
||||||
|
version = "0.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2"
|
||||||
|
dependencies = [
|
||||||
|
"pem",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"time",
|
||||||
|
"yasna",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.18"
|
version = "0.5.18"
|
||||||
@@ -2206,6 +2272,7 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"quinn",
|
"quinn",
|
||||||
"rustls",
|
"rustls",
|
||||||
|
"rustls-native-certs",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -2275,6 +2342,7 @@ version = "0.23.40"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
|
checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@@ -2283,6 +2351,18 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-native-certs"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
|
||||||
|
dependencies = [
|
||||||
|
"openssl-probe",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.14.1"
|
version = "1.14.1"
|
||||||
@@ -2316,12 +2396,44 @@ version = "1.0.23"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "3.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selectors"
|
name = "selectors"
|
||||||
version = "0.26.0"
|
version = "0.26.0"
|
||||||
@@ -2737,6 +2849,25 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.3.54"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244"
|
||||||
|
dependencies = [
|
||||||
|
"deranged",
|
||||||
|
"num-conv",
|
||||||
|
"powerfmt",
|
||||||
|
"serde_core",
|
||||||
|
"time-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time-core"
|
||||||
|
version = "0.1.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
@@ -3682,6 +3813,15 @@ dependencies = [
|
|||||||
"tap",
|
"tap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yasna"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd"
|
||||||
|
dependencies = [
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.8.3"
|
version = "0.8.3"
|
||||||
|
|||||||
+5
-1
@@ -36,7 +36,11 @@ tokio-tungstenite = "0.26"
|
|||||||
# (obscura-net/src/cookies.rs) and never uses reqwest's cookie store. Pulling
|
# (obscura-net/src/cookies.rs) and never uses reqwest's cookie store. Pulling
|
||||||
# it in only added the cookie/cookie_store crates, and cookie 0.18.1's blanket
|
# it in only added the cookie/cookie_store crates, and cookie 0.18.1's blanket
|
||||||
# From impl fails to compile under coherence on some toolchains (issue #295).
|
# From impl fails to compile under coherence on some toolchains (issue #295).
|
||||||
reqwest = { version = "0.12", features = ["gzip", "brotli", "deflate", "rustls-tls", "socks"], default-features = false }
|
# "rustls-tls-native-roots" adds the platform trust store (and SSL_CERT_FILE /
|
||||||
|
# SSL_CERT_DIR) on top of the bundled webpki roots, so deployments behind a
|
||||||
|
# corporate CA or an inspecting egress proxy can trust their own roots. The
|
||||||
|
# two root sets merge, so the default trust surface only grows.
|
||||||
|
reqwest = { version = "0.12", features = ["gzip", "brotli", "deflate", "rustls-tls", "rustls-tls-native-roots", "socks"], default-features = false }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
url = "2"
|
url = "2"
|
||||||
|
|||||||
@@ -25,6 +25,15 @@ tempfile = "3"
|
|||||||
# Pin exact versions so the build always resolves to the API wreq_client.rs targets.
|
# Pin exact versions so the build always resolves to the API wreq_client.rs targets.
|
||||||
wreq-util = { version = "=3.0.0-rc.12", optional = true }
|
wreq-util = { version = "=3.0.0-rc.12", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
# TLS fixtures for the native-roots tests: rcgen mints a throwaway CA + leaf,
|
||||||
|
# tokio-rustls serves one HTTPS response with them. Pinned to the ring
|
||||||
|
# provider so the test binary has a single rustls CryptoProvider (reqwest's
|
||||||
|
# rustls also uses ring; adding aws-lc-rs would make provider auto-selection
|
||||||
|
# panic).
|
||||||
|
rcgen = "0.13"
|
||||||
|
tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12", "logging"] }
|
||||||
|
|
||||||
# `prefix-symbols` renames BoringSSL exports to avoid clashes with system OpenSSL,
|
# `prefix-symbols` renames BoringSSL exports to avoid clashes with system OpenSSL,
|
||||||
# but the renaming is only correct on Linux and Android (per wreq's README).
|
# but the renaming is only correct on Linux and Android (per wreq's README).
|
||||||
# Enabling it on other platforms produces unresolved `build_script_main_*`
|
# Enabling it on other platforms produces unresolved `build_script_main_*`
|
||||||
|
|||||||
@@ -764,10 +764,12 @@ pub enum ObscuraNetError {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod ssrf_tests {
|
mod ssrf_tests {
|
||||||
use super::{is_forbidden_ip, validate_url, SsrfGuardResolver};
|
use super::{is_forbidden_ip, validate_url, ObscuraHttpClient, SsrfGuardResolver};
|
||||||
|
use crate::cookies::CookieJar;
|
||||||
use reqwest::dns::{Name, Resolve};
|
use reqwest::dns::{Name, Resolve};
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
fn ip(s: &str) -> IpAddr {
|
fn ip(s: &str) -> IpAddr {
|
||||||
@@ -852,4 +854,92 @@ mod ssrf_tests {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mint a throwaway CA plus a 127.0.0.1 leaf it signed, and serve one
|
||||||
|
/// canned HTTPS response with the leaf on an ephemeral port. Returns the
|
||||||
|
/// port and the CA certificate as PEM.
|
||||||
|
async fn https_fixture_with_private_ca() -> (u16, String) {
|
||||||
|
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
|
||||||
|
let ca_key = rcgen::KeyPair::generate().unwrap();
|
||||||
|
let mut ca_params = rcgen::CertificateParams::new(Vec::new()).unwrap();
|
||||||
|
ca_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
|
||||||
|
let ca_cert = ca_params.self_signed(&ca_key).unwrap();
|
||||||
|
|
||||||
|
let leaf_key = rcgen::KeyPair::generate().unwrap();
|
||||||
|
let leaf_params =
|
||||||
|
rcgen::CertificateParams::new(vec!["127.0.0.1".to_string()]).unwrap();
|
||||||
|
let leaf_cert = leaf_params.signed_by(&leaf_key, &ca_cert, &ca_key).unwrap();
|
||||||
|
|
||||||
|
let certs = vec![tokio_rustls::rustls::pki_types::CertificateDer::from(
|
||||||
|
leaf_cert.der().to_vec(),
|
||||||
|
)];
|
||||||
|
let key = tokio_rustls::rustls::pki_types::PrivateKeyDer::Pkcs8(
|
||||||
|
tokio_rustls::rustls::pki_types::PrivatePkcs8KeyDer::from(
|
||||||
|
leaf_key.serialize_der(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
let config = tokio_rustls::rustls::ServerConfig::builder()
|
||||||
|
.with_no_client_auth()
|
||||||
|
.with_single_cert(certs, key)
|
||||||
|
.unwrap();
|
||||||
|
let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(config));
|
||||||
|
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
|
||||||
|
let port = listener.local_addr().unwrap().port();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
while let Ok((stream, _)) = listener.accept().await {
|
||||||
|
let acceptor = acceptor.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let Ok(mut tls) = acceptor.accept(stream).await else {
|
||||||
|
return; // Handshake rejection is the point of one test.
|
||||||
|
};
|
||||||
|
let mut buf = [0u8; 1024];
|
||||||
|
let _ = tls.read(&mut buf).await;
|
||||||
|
let body = "private ca ok";
|
||||||
|
let resp = format!(
|
||||||
|
"HTTP/1.1 200 OK\r\ncontent-type: text/plain\r\ncontent-length: {}\r\nconnection: close\r\n\r\n{}",
|
||||||
|
body.len(),
|
||||||
|
body
|
||||||
|
);
|
||||||
|
let _ = tls.write_all(resp.as_bytes()).await;
|
||||||
|
let _ = tls.shutdown().await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
(port, ca_cert.pem())
|
||||||
|
}
|
||||||
|
|
||||||
|
// The two native-roots tests set/rely on SSL_CERT_FILE, which
|
||||||
|
// rustls-native-certs reads once per process at client build. They are
|
||||||
|
// only correct under `cargo nextest` (one process per test) — the same
|
||||||
|
// constraint the whole workspace already has.
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn native_roots_trusts_a_private_ca_via_ssl_cert_file() {
|
||||||
|
let (port, ca_pem) = https_fixture_with_private_ca().await;
|
||||||
|
let ca_file = tempfile::NamedTempFile::new().unwrap();
|
||||||
|
std::fs::write(ca_file.path(), ca_pem).unwrap();
|
||||||
|
std::env::set_var("SSL_CERT_FILE", ca_file.path());
|
||||||
|
|
||||||
|
let client =
|
||||||
|
ObscuraHttpClient::with_full_options(Arc::new(CookieJar::new()), None, true);
|
||||||
|
let url = Url::parse(&format!("https://127.0.0.1:{port}/")).unwrap();
|
||||||
|
let resp = client.fetch(&url).await.expect("private CA in SSL_CERT_FILE must be trusted");
|
||||||
|
assert_eq!(resp.status, 200);
|
||||||
|
assert_eq!(resp.text(), "private ca ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn private_ca_is_still_rejected_without_ssl_cert_file() {
|
||||||
|
// Guards against the native-roots feature weakening verification: the
|
||||||
|
// same fixture that the SSL_CERT_FILE test trusts must fail here. The
|
||||||
|
// listener is reachable (same setup), so an Err can only be TLS.
|
||||||
|
let (port, _ca_pem) = https_fixture_with_private_ca().await;
|
||||||
|
let client =
|
||||||
|
ObscuraHttpClient::with_full_options(Arc::new(CookieJar::new()), None, true);
|
||||||
|
let url = Url::parse(&format!("https://127.0.0.1:{port}/")).unwrap();
|
||||||
|
assert!(client.fetch(&url).await.is_err(), "unknown CA must be rejected");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user