diff --git a/src/client.rs b/src/client.rs index 15a30a6..9c9f3b7 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{Context, Result}; use reqwest::header::HeaderMap; use reqwest::{redirect::Policy, Client, Proxy}; use std::collections::HashMap; @@ -22,7 +22,7 @@ pub fn initialize( ) -> Result where I: IntoIterator, - I::Item: AsRef, + I::Item: AsRef + std::fmt::Debug, { let policy = if redirects { Policy::limited(10) @@ -51,50 +51,31 @@ where } for cert_path in server_certs { - let cert_path = Path::new(&cert_path); + let buf = std::fs::read(&cert_path)?; - // if the root certificate path is not empty, open it - // and read it into a buffer - - let buf = std::fs::read(cert_path)?; - let cert = match cert_path - .extension() - .map(|s| s.to_str().unwrap_or_default()) - { - // depending upon the extension of the file, create a - // certificate object from it using either the "pem" or "der" parser - Some("pem") => reqwest::Certificate::from_pem(&buf)?, - Some("der") => reqwest::Certificate::from_der(&buf)?, - - // if we cannot determine the extension, do nothing - _ => { - log::warn!( - "unable to determine extension: assuming PEM format for root certificate" - ); - reqwest::Certificate::from_pem(&buf)? - } + let cert = match reqwest::Certificate::from_pem(&buf) { + Ok(cert) => cert, + Err(err) => reqwest::Certificate::from_der(&buf).with_context(|| { + format!( + "{:?} does not contain a valid PEM or DER certificate\n{}", + &cert_path, err + ) + })?, }; - // in either case, add the root certificate to the client client = client.add_root_certificate(cert); } if let (Some(cert_path), Some(key_path)) = (client_cert, client_key) { - let cert_path = Path::new(cert_path); - let cert = std::fs::read(cert_path)?; let key = std::fs::read(key_path)?; - let identity = match cert_path - .extension() - .map(|s| s.to_str().unwrap_or_default()) - { - Some("pem") => reqwest::Identity::from_pkcs8_pem(&cert, &key)?, - _ => { - log::warn!("unable to determine extension: assuming PEM format for client key and certificate"); - reqwest::Identity::from_pkcs8_pem(&cert, &key)? - } - }; + let identity = reqwest::Identity::from_pkcs8_pem(&cert, &key).with_context(|| { + format!( + "either {} or {} are invalid; expecting PEM encoded certificate and key", + cert_path, key_path + ) + })?; client = client.identity(identity); } @@ -130,7 +111,7 @@ mod tests { fn client_with_good_proxy() { let headers = HashMap::new(); let proxy = "http://127.0.0.1:8080"; - initialize::>( + initialize( 0, "stuff", true, @@ -143,4 +124,86 @@ mod tests { ) .unwrap(); } + + #[test] + /// create client with a server cert in pem format, expect no error + fn client_with_valid_server_pem() { + let headers = HashMap::new(); + + initialize( + 0, + "stuff", + true, + true, + &headers, + None, + vec!["tests/server-test-cert-1.pem".to_string()], + None, + None, + ) + .unwrap(); + } + + #[test] + /// create client with a server cert in der format, expect no error + fn client_with_valid_server_der() { + let headers = HashMap::new(); + + initialize( + 0, + "stuff", + true, + true, + &headers, + None, + vec!["tests/server-test-cert.der".to_string()], + None, + None, + ) + .unwrap(); + } + + #[test] + /// create client with two server certs (pem and der), expect no error + fn client_with_valid_server_pem_and_der() { + let headers = HashMap::new(); + + println!("{}", std::env::current_dir().unwrap().display()); + + initialize( + 0, + "stuff", + true, + true, + &headers, + None, + vec![ + "tests/server-test-cert-1.pem".to_string(), + "tests/server-test-cert.der".to_string(), + ], + None, + None, + ) + .unwrap(); + } + + /// create client with invalid certificate, expect panic + #[test] + #[should_panic] + fn client_with_invalid_server_cert() { + let headers = HashMap::new(); + + initialize( + 0, + "stuff", + true, + true, + &headers, + None, + vec!["tests/client-test-key.pem".to_string()], + None, + None, + ) + .unwrap(); + } } diff --git a/src/scan_manager/tests.rs b/src/scan_manager/tests.rs index b549935..73e32c0 100644 --- a/src/scan_manager/tests.rs +++ b/src/scan_manager/tests.rs @@ -489,6 +489,9 @@ fn feroxstates_feroxserialize_implementation() { r#""url_denylist":[]"#, r#""responses""#, r#""type":"response""#, + r#""client_cert":"""#, + r#""client_key":"""#, + r#""server_certs":[]"#, r#""url":"https://nerdcore.com/css""#, r#""path":"/css""#, r#""wildcard":true"#, diff --git a/tests/server-test-cert.der b/tests/server-test-cert.der new file mode 100644 index 0000000..5c2fa22 Binary files /dev/null and b/tests/server-test-cert.der differ