diff --git a/Cargo.lock b/Cargo.lock index 7497ae280..14294cbb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,9 +299,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "block-buffer" @@ -402,21 +402,15 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.28" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" dependencies = [ "jobserver", "libc", "shlex", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfg-if" version = "1.0.0" @@ -577,16 +571,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - [[package]] name = "comfy-table" version = "7.0.1" @@ -623,9 +607,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -633,9 +617,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.7" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" @@ -1349,9 +1333,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -1377,6 +1361,7 @@ dependencies = [ "hyper", "hyper-util", "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls", @@ -1547,26 +1532,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" -[[package]] -name = "jni" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror", - "walkdir", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - [[package]] name = "jobserver" version = "0.1.32" @@ -1848,7 +1813,6 @@ dependencies = [ "regex", "reqwest", "rstest", - "rustls-platform-verifier", "schemars", "semver 1.0.17", "serde", @@ -2393,6 +2357,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls", + "rustls-native-certs", "rustls-pemfile", "rustls-pki-types", "serde", @@ -2489,7 +2454,7 @@ version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbc6396159432b5c8490d4e301d8c705f61860b8b6c863bf79942ce5401968f3" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.3.3", "errno", "libc", "linux-raw-sys", @@ -2498,9 +2463,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.14" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "once_cell", "ring", @@ -2512,9 +2477,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -2534,36 +2499,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" - -[[package]] -name = "rustls-platform-verifier" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" -dependencies = [ - "core-foundation", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki", - "security-framework", - "security-framework-sys", - "webpki-roots", - "winapi", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -2651,23 +2589,22 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "security-framework" -version = "2.11.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ - "bitflags 2.6.0", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", - "num-bigint", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "2.12.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", diff --git a/Cargo.toml b/Cargo.toml index 5d35ecb97..2c74ed66e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,10 +70,9 @@ owo-colors = "=3.5.0" pretty_assertions = "=1.3.0" rayon = "=1.7.0" regex = "=1.8.4" -reqwest = { version = "=0.12.8", default-features = false, features = ["blocking", "deflate", "gzip", "brotli", "socks", "rustls-tls"] } +reqwest = { version = "=0.12.8", default-features = false, features = ["blocking", "deflate", "gzip", "brotli", "socks", "rustls-tls-native-roots", "rustls-tls-webpki-roots"] } rstest = "=0.17.0" rstest_reuse = "=0.5.0" -rustls-platform-verifier = "=0.3.4" schemars = { version = "=0.8.12", features = ["chrono", "either", "enumset", "indexmap"] } semver = { version = "=1.0.17", features = ["serde"] } serde = { version = "=1.0.164", features = ["derive"] } diff --git a/docs/user/nextclade-cli/reference.md b/docs/user/nextclade-cli/reference.md index 4025ca8d6..d865f8f2e 100644 --- a/docs/user/nextclade-cli/reference.md +++ b/docs/user/nextclade-cli/reference.md @@ -231,6 +231,7 @@ For short help type: `nextclade -h`, for extended help type: `nextclade --help`. * `-x`, `--proxy ` — Pass all traffic over proxy server. HTTP, HTTPS, and SOCKS5 proxies are supported * `--proxy-user ` — Username for basic authentication on proxy server, if applicable. Only valid when `--proxy` is also supplied. `--proxy-user` and `--proxy-pass` must be either both specified or both omitted * `--proxy-pass ` — Password for basic authentication on proxy server, if applicable. Only valid when `--proxy` is also supplied. `--proxy-user` and `--proxy-pass` must be either both specified or both omitted +* `--extra-ca-certs ` — Path to extra CA certificates as a PEM bundle @@ -255,6 +256,7 @@ For short help type: `nextclade -h`, for extended help type: `nextclade --help`. * `-x`, `--proxy ` — Pass all traffic over proxy server. HTTP, HTTPS, and SOCKS5 proxies are supported * `--proxy-user ` — Username for basic authentication on proxy server, if applicable. Only valid when `--proxy` is also supplied. `--proxy-user` and `--proxy-pass` must be either both specified or both omitted * `--proxy-pass ` — Password for basic authentication on proxy server, if applicable. Only valid when `--proxy` is also supplied. `--proxy-user` and `--proxy-pass` must be either both specified or both omitted +* `--extra-ca-certs ` — Path to extra CA certificates as a PEM bundle @@ -295,6 +297,7 @@ For short help type: `nextclade -h`, for extended help type: `nextclade --help`. * `-x`, `--proxy ` — Pass all traffic over proxy server. HTTP, HTTPS, and SOCKS5 proxies are supported * `--proxy-user ` — Username for basic authentication on proxy server, if applicable. Only valid when `--proxy` is also supplied. `--proxy-user` and `--proxy-pass` must be either both specified or both omitted * `--proxy-pass ` — Password for basic authentication on proxy server, if applicable. Only valid when `--proxy` is also supplied. `--proxy-user` and `--proxy-pass` must be either both specified or both omitted +* `--extra-ca-certs ` — Path to extra CA certificates as a PEM bundle diff --git a/packages/nextclade-cli/Cargo.toml b/packages/nextclade-cli/Cargo.toml index a2770c26d..6072a8469 100644 --- a/packages/nextclade-cli/Cargo.toml +++ b/packages/nextclade-cli/Cargo.toml @@ -41,7 +41,6 @@ pretty_assertions = { workspace = true } rayon = { workspace = true } regex = { workspace = true } reqwest = { workspace = true } -rustls-platform-verifier = { workspace = true } schemars = { workspace = true } semver = { workspace = true } serde = { workspace = true } diff --git a/packages/nextclade-cli/src/io/http_client.rs b/packages/nextclade-cli/src/io/http_client.rs index b8cd5c0c4..1d19d33fd 100644 --- a/packages/nextclade-cli/src/io/http_client.rs +++ b/packages/nextclade-cli/src/io/http_client.rs @@ -1,11 +1,14 @@ use clap::{Parser, ValueHint}; -use eyre::Report; +use eyre::{Report, WrapErr}; use log::info; +use nextclade::io::file::open_file_or_stdin; use nextclade::make_internal_error; use nextclade::utils::info::{this_package_name, this_package_version_str}; use reqwest::blocking::Client; +use reqwest::tls::Certificate; use reqwest::{Method, Proxy}; -use rustls_platform_verifier; +use std::env; +use std::path::{Path, PathBuf}; use std::str::FromStr; use std::time::Duration; use url::Url; @@ -27,6 +30,15 @@ pub struct ProxyConfig { #[clap(long)] #[clap(value_hint = ValueHint::Other)] pub proxy_pass: Option, + + /// Path to extra CA certificates as a PEM bundle. + /// + /// You can also provide the path to CA certificates in the environment variable `NEXTCLADE_EXTRA_CA_CERTS`. The argument takes precedence over the environment variable if both are provided. + /// + /// Default CA certificates are those obtained from the platform/OS-level trust store plus those from a baked-in copy of Mozilla's common CA trust store. You can override the certs obtained from the platform trust store by setting `SSL_CERT_FILE` or `SSL_CERT_DIR`. Filenames in the latter must be hashed in the style of OpenSSL's `c_rehash` utility. + #[clap(long)] + #[clap(value_hint = ValueHint::Other)] + pub extra_ca_certs: Option, } pub struct HttpClient { @@ -60,10 +72,16 @@ impl HttpClient { client_builder }; + let extra_ca_certs_filepath = env::var_os("NEXTCLADE_EXTRA_CA_CERTS").map(PathBuf::from); + let extra_ca_certs_filepath = proxy_conf.extra_ca_certs.as_ref().or(extra_ca_certs_filepath.as_ref()); + + for cert in extra_ca_certs(extra_ca_certs_filepath)? { + client_builder = client_builder.add_root_certificate(cert); + } + let user_agent = format!("{} {}", this_package_name(), this_package_version_str()); let client = client_builder - .use_preconfigured_tls(rustls_platform_verifier::tls_config()) .connection_verbose(verbose) .connect_timeout(Some(Duration::from_secs(60))) .user_agent(user_agent) @@ -112,3 +130,16 @@ impl HttpClient { Ok(content) } } + +fn extra_ca_certs(extra_ca_certs_filepath: Option>) -> Result, Report> { + extra_ca_certs_filepath.map_or_else( + || Ok(vec![]), + |filename| { + let mut pem = vec![]; + + open_file_or_stdin(&Some(filename))?.read_to_end(&mut pem)?; + + Certificate::from_pem_bundle(&pem).wrap_err("While reading PEM bundle") + }, + ) +}