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.
  • Loading branch information
tsibley committed Oct 14, 2024
1 parent 8816fe2 commit 4005505
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 3 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions 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 = { version = "=0.23.14", default-features = false, features = ["ring", "logging", "std", "tls12"] }
rustls-platform-verifier = "=0.3.4"
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
42 changes: 39 additions & 3 deletions packages/nextclade-cli/src/io/http_client.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
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::TrustAnchor;
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;
use webpki::anchor_from_trusted_cert;

#[derive(Parser, Debug, Default)]
#[clap(verbatim_doc_comment)]
Expand Down Expand Up @@ -62,8 +70,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 +125,26 @@ impl HttpClient {
Ok(content)
}
}

fn extra_ca_certs() -> Result<impl IntoIterator<Item = TrustAnchor<'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>>()?;

let anchors = certs
.into_iter()
.map(|c| anchor_from_trusted_cert(&c).wrap_err_with(|| "When converting an extra CA certificate to a trust anchor".to_owned()).map(|a| a.to_owned()))
.collect::<Result<Vec<_>, Report>>()?;

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

0 comments on commit 4005505

Please sign in to comment.