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:
Marco Ripamonti committed 2026-07-28 15:43:12 +02:00
1 parent e78b5e6026
commit 0522831dcc
4 files changed
+245 -2

No files matched your search

+5 -1
View File
@@ -36,7 +36,11 @@ tokio-tungstenite = "0.26"
# (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
# 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_json = "1"
url = "2"