From d719292328be30de040a1d0a398a2585273c5ae5 Mon Sep 17 00:00:00 2001 From: Santhosh Kumar Tekuri Date: Thu, 25 Apr 2024 22:44:49 +0530 Subject: [PATCH] cli: add --cacert option --- Cargo.lock | 21 +++++++++++++++++++-- Cargo.toml | 1 + examples/boon.rs | 33 +++++++++++++++++++++++++++++---- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8694e5..3825d19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,6 +60,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "bitflags" version = "1.3.2" @@ -78,7 +84,7 @@ version = "0.5.3" dependencies = [ "ahash", "appendlist", - "base64", + "base64 0.21.7", "criterion", "fluent-uri", "getopts", @@ -88,6 +94,7 @@ dependencies = [ "regex", "regex-syntax", "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_yaml", @@ -593,6 +600,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.0", + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.4.1" @@ -762,7 +779,7 @@ version = "2.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" dependencies = [ - "base64", + "base64 0.21.7", "flate2", "log", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index 37be69a..20b26cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.9" ureq = "2.9.6" rustls = "0.22" +rustls-pemfile = "2.1" criterion = "0.5" [[bench]] diff --git a/examples/boon.rs b/examples/boon.rs index cc4d9d5..ee35e25 100644 --- a/examples/boon.rs +++ b/examples/boon.rs @@ -1,3 +1,4 @@ +use core::panic; use std::{env, error::Error, fs::File, io::BufReader, process, str::FromStr, sync::Arc}; use boon::{Compiler, Draft, Schemas, UrlLoader}; @@ -77,8 +78,10 @@ fn main() { let mut schemas = Schemas::new(); let mut compiler = Compiler::new(); compiler.register_url_loader("file", Box::new(FileUrlLoader)); - compiler.register_url_loader("http", Box::new(HttpUrlLoader::new(insecure))); - compiler.register_url_loader("https", Box::new(HttpUrlLoader::new(insecure))); + let cacert = matches.opt_str("cacert"); + let cacert = cacert.as_deref(); + compiler.register_url_loader("http", Box::new(HttpUrlLoader::new(cacert, insecure))); + compiler.register_url_loader("https", Box::new(HttpUrlLoader::new(cacert, insecure))); compiler.set_default_draft(draft); if assert_format { compiler.enable_format_assertions(); @@ -189,6 +192,12 @@ fn options() -> Options { "assert-content", "Enable content assertions with draft >= 7", ); + opts.optopt( + "", + "cacert", + "Use the specified PEM certificate file to verify the peer. The file may contain multiple CA certificates", + "", + ); opts.optflag("k", "insecure", "Use insecure TLS connection"); opts } @@ -214,9 +223,25 @@ impl UrlLoader for FileUrlLoader { struct HttpUrlLoader(Agent); impl HttpUrlLoader { - fn new(insecure: bool) -> Self { + fn new(cacert: Option<&str>, insecure: bool) -> Self { let mut builder = ureq::builder(); - if insecure { + if let Some(cacert) = cacert { + let file = File::open(cacert).unwrap_or_else(|e| panic!("error opening {cacert}: {e}")); + let certs: Result, _> = + rustls_pemfile::certs(&mut BufReader::new(file)).collect(); + let certs = certs.unwrap_or_else(|e| panic!("error reading cacert: {e}")); + assert!(!certs.is_empty(), "no certs in cacert"); + let mut store = rustls::RootCertStore::empty(); + for cert in certs { + store + .add(cert) + .unwrap_or_else(|e| panic!("error adding cert: {e}")) + } + let tls_config = rustls::ClientConfig::builder() + .with_root_certificates(store) + .with_no_client_auth(); + builder = builder.tls_config(tls_config.into()); + } else if insecure { let tls_config = rustls::ClientConfig::builder() .dangerous() .with_custom_certificate_verifier(Arc::new(InsecureVerifier))