Skip to content

Commit

Permalink
feat: Support a NEXTCLADE_EXTRA_CA_CERTS environment variable
Browse files Browse the repository at this point in the history
Allows adding additional CA certificates to the trust store specifically
for Nextclade, for when modifying the system's trust store isn't
desirable/possible.  Works across all platforms.

Currently requires using landed unreleased changes to
rustls-platform-verifier so that macOS and Windows have the needed
Verifier::new_with_extra_certs() API.¹  That API also has signature
changes proposed² which, while unmerged, seem likely to land, so use
those in anticipation.  They actually bring the signature back closer to
the latest release (0.3.4).

¹ <rustls/rustls-platform-verifier#58>
² <rustls/rustls-platform-verifier#145>

Related-to: <#1529>
Related-to: <#726>
  • Loading branch information
tsibley committed Oct 15, 2024
1 parent 9b2d9dd commit edf5adc
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 11 deletions.
26 changes: 19 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ regex = "=1.8.4"
reqwest = { version = "=0.12.8", default-features = false, features = ["blocking", "deflate", "gzip", "brotli", "socks", "rustls-tls"] }
rstest = "=0.17.0"
rstest_reuse = "=0.5.0"
rustls-platform-verifier = "=0.3.4"
rustls = { version = "=0.23.14", default-features = false, features = ["ring", "logging", "std", "tls12"] }
rustls-platform-verifier = { git = "https://github.com/rustls/rustls-platform-verifier.git", rev = "ca87571fe47730665917b8c29f14a3989f3cbe57" }
rustls-pemfile = "=2.2.0"
rustls-pki-types = "=1.9.0"
rustls-webpki = { version = "=0.102.8", features = ["ring"] }
schemars = { version = "=0.8.12", features = ["chrono", "either", "enumset", "indexmap"] }
semver = { version = "=1.0.17", features = ["serde"] }
serde = { version = "=1.0.164", features = ["derive"] }
Expand Down
4 changes: 4 additions & 0 deletions packages/nextclade-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ pretty_assertions = { workspace = true }
rayon = { workspace = true }
regex = { workspace = true }
reqwest = { workspace = true }
rustls = { workspace = true }
rustls-platform-verifier = { workspace = true }
rustls-pemfile = { workspace = true }
rustls-pki-types = { workspace = true }
rustls-webpki = { workspace = true }
schemars = { workspace = true }
semver = { workspace = true }
serde = { workspace = true }
Expand Down
36 changes: 33 additions & 3 deletions packages/nextclade-cli/src/io/http_client.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
use clap::{Parser, ValueHint};
use eyre::Report;
use eyre::{Report, WrapErr};
use log::info;
use nextclade::make_internal_error;
use nextclade::utils::info::{this_package_name, this_package_version_str};
use reqwest::blocking::Client;
use reqwest::{Method, Proxy};
use rustls_platform_verifier;
use rustls::ClientConfig;
use rustls_pemfile;
use rustls_pki_types::CertificateDer;
use rustls_platform_verifier::Verifier;
use std::env;
use std::io::BufReader;
use std::fs::File;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;
use url::Url;

Expand Down Expand Up @@ -62,8 +69,13 @@ impl HttpClient {

let user_agent = format!("{} {}", this_package_name(), this_package_version_str());

let tls_config = ClientConfig::builder()
.dangerous() // …but the rustls_platform_verifier::Verifier is safe
.with_custom_certificate_verifier(Arc::new(Verifier::new_with_extra_roots(extra_ca_certs()?)?))
.with_no_client_auth();

let client = client_builder
.use_preconfigured_tls(rustls_platform_verifier::tls_config())
.use_preconfigured_tls(tls_config)
.connection_verbose(verbose)
.connect_timeout(Some(Duration::from_secs(60)))
.user_agent(user_agent)
Expand Down Expand Up @@ -112,3 +124,21 @@ impl HttpClient {
Ok(content)
}
}

fn extra_ca_certs() -> Result<impl IntoIterator<Item = CertificateDer<'static>>, Report> {
match env::var_os("NEXTCLADE_EXTRA_CA_CERTS") {
Some(filename) => {
let file = File::open(filename.clone())
.wrap_err_with(|| format!("When opening NEXTCLADE_EXTRA_CA_CERTS file {filename:?}"))?;

let mut reader = BufReader::new(file);

let certs = rustls_pemfile::certs(&mut reader)
.map(|c| c.wrap_err_with(|| "When parsing an extra CA certificate".to_owned()))
.collect::<Result<Vec<_>, Report>>()?;

Ok(certs)
}
None => Ok(vec![])
}
}

0 comments on commit edf5adc

Please sign in to comment.