diff --git a/Cargo.lock b/Cargo.lock index 7508fdc..b748aff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "base64" -version = "0.13.1" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "bitflags" @@ -105,6 +105,7 @@ version = "0.9.3" dependencies = [ "native-tls", "rustls", + "rustls-pemfile", "unicase", "webpki", "webpki-roots", @@ -261,9 +262,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.13" +version = "0.38.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" dependencies = [ "bitflags 2.4.0", "errno", @@ -274,15 +275,33 @@ dependencies = [ [[package]] name = "rustls" -version = "0.19.1" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" dependencies = [ - "base64", "log", "ring", + "rustls-webpki", "sct", - "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a27e3b59326c16e23d30aeb7a36a24cc0d29e71d68ff611cdfb4a01d013bed" +dependencies = [ + "ring", + "untrusted", ] [[package]] @@ -296,9 +315,9 @@ dependencies = [ [[package]] name = "sct" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ "ring", "untrusted", @@ -335,9 +354,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "syn" -version = "2.0.36" +version = "2.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e02e55d62894af2a08aca894c6577281f76769ba47c94d5756bec8ac6e7373" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" dependencies = [ "proc-macro2", "quote", @@ -456,9 +475,9 @@ dependencies = [ [[package]] name = "webpki" -version = "0.21.4" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" +checksum = "f0e74f82d49d545ad128049b7e88f6576df2da6b02e9ce565c6f533be576957e" dependencies = [ "ring", "untrusted", @@ -466,12 +485,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.21.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" -dependencies = [ - "webpki", -] +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index f2ad32a..6810584 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,20 +15,24 @@ unicase = "^2.6" [features] default = ["native-tls"] -rust-tls = ["rustls", "webpki", "webpki-roots"] +rust-tls = ["rustls", "webpki", "webpki-roots", "rustls-pemfile"] [dependencies.native-tls] version = "^0.2" optional = true [dependencies.rustls] -version = "^0.19" +version = "^0.21" +optional = true + +[dependencies.rustls-pemfile] +version = "^1.0" optional = true [dependencies.webpki] -version = "^0.21" +version = "^0.22" optional = true [dependencies.webpki-roots] -version = "^0.21" +version = "^0.25" optional = true diff --git a/src/error.rs b/src/error.rs index 55bf752..477d4bd 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,6 +10,8 @@ pub enum ParseErr { UriErr, Invalid, Empty, + #[cfg(feature = "rust-tls")] + Rustls(rustls::Error), } impl error::Error for ParseErr { @@ -19,6 +21,8 @@ impl error::Error for ParseErr { match self { Utf8(e) => Some(e), Int(e) => Some(e), + #[cfg(feature = "rust-tls")] + Rustls(e) => Some(e), StatusErr | HeadersErr | UriErr | Invalid | Empty => None, } } @@ -36,11 +40,20 @@ impl fmt::Display for ParseErr { StatusErr => "status line contains invalid values", HeadersErr => "headers contain invalid values", UriErr => "uri contains invalid characters", + #[cfg(feature = "rust-tls")] + Rustls(_) => "rustls error", }; write!(f, "ParseErr: {}", err) } } +#[cfg(feature = "rust-tls")] +impl From for ParseErr { + fn from(e: rustls::Error) -> Self { + ParseErr::Rustls(e) + } +} + impl From for ParseErr { fn from(e: num::ParseIntError) -> Self { ParseErr::Int(e) diff --git a/src/tls.rs b/src/tls.rs index ebb5b91..5d6a713 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -23,7 +23,7 @@ pub struct Conn { stream: native_tls::TlsStream, #[cfg(feature = "rust-tls")] - stream: rustls::StreamOwned, + stream: rustls::StreamOwned, } impl io::Read for Conn { @@ -63,7 +63,7 @@ pub struct Config { #[cfg(feature = "native-tls")] extra_root_certs: Vec, #[cfg(feature = "rust-tls")] - client_config: std::sync::Arc, + root_certs: std::sync::Arc, } impl Default for Config { @@ -76,13 +76,16 @@ impl Default for Config { #[cfg(feature = "rust-tls")] fn default() -> Self { - let mut config = rustls::ClientConfig::new(); - config - .root_store - .add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS); - + let mut root_store = rustls::RootCertStore::empty(); + root_store.add_trust_anchors(webpki_roots::TLS_SERVER_ROOTS.iter().map(|ta| { + rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( + ta.subject, + ta.spki, + ta.name_constraints, + ) + })); Config { - client_config: std::sync::Arc::new(config), + root_certs: std::sync::Arc::new(root_store), } } } @@ -127,11 +130,8 @@ impl Config { pub fn add_root_cert_file_pem(&mut self, file_path: &Path) -> Result<&mut Self, HttpError> { let f = File::open(file_path)?; let mut f = BufReader::new(f); - let config = std::sync::Arc::make_mut(&mut self.client_config); - let _ = config - .root_store - .add_pem_file(&mut f) - .map_err(|_| HttpError::from(ParseErr::Invalid))?; + let root_certs = std::sync::Arc::make_mut(&mut self.root_certs); + root_certs.add_parsable_certificates(&rustls_pemfile::certs(&mut f)?); Ok(self) } @@ -141,13 +141,17 @@ impl Config { H: AsRef, S: io::Read + io::Write, { - use rustls::{ClientSession, StreamOwned}; - - let session = ClientSession::new( - &self.client_config, - webpki::DNSNameRef::try_from_ascii_str(hostname.as_ref()) - .map_err(|_| HttpError::Tls)?, - ); + use rustls::{ClientConnection, StreamOwned}; + + let client_config = rustls::ClientConfig::builder() + .with_safe_defaults() + .with_root_certificates(self.root_certs.clone()) + .with_no_client_auth(); + let session = ClientConnection::new( + std::sync::Arc::new(client_config), + hostname.as_ref().try_into().map_err(|_| HttpError::Tls)?, + ) + .map_err(|e| ParseErr::Rustls(e))?; let stream = StreamOwned::new(session, stream); Ok(Conn { stream })