From 13a1ad12dfbc1a4f45b5cf319254b9a2f7472947 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Thu, 9 Jan 2025 17:57:24 +0100 Subject: [PATCH] feat(client): allow to disable server cert verification on dangerous feature for all http version --- client/Cargo.toml | 2 +- client/src/builder.rs | 89 ++++++++++--------------------------- client/src/tls/connector.rs | 29 ++++++++++-- client/src/tls/dangerous.rs | 67 ++++++++++++++++++++++++++++ client/src/tls/mod.rs | 2 + test/tests/h3.rs | 6 +-- 6 files changed, 122 insertions(+), 73 deletions(-) create mode 100644 client/src/tls/dangerous.rs diff --git a/client/Cargo.toml b/client/Cargo.toml index 9f72871c5..ba4358e23 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -30,7 +30,7 @@ json = ["serde", "serde_json"] websocket = ["http-ws"] # feature for trusted local network: # - http/2 clear text over plain tcp connection -# - http/3 connection to server with self signed certificates +# - allow invalid certificates for client in http/1, http/2 and/or http/3 dangerous = [] [dependencies] diff --git a/client/src/builder.rs b/client/src/builder.rs index f709077dc..e02212bfb 100644 --- a/client/src/builder.rs +++ b/client/src/builder.rs @@ -29,6 +29,8 @@ pub struct ClientBuilder { local_addr: Option, max_http_version: Version, service: HttpService, + #[cfg(feature = "dangerous")] + allow_invalid_certificate: bool, } impl Default for ClientBuilder { @@ -49,6 +51,8 @@ impl ClientBuilder { local_addr: None, max_http_version: max_http_version(), service: base_service(), + #[cfg(feature = "dangerous")] + allow_invalid_certificate: false, } } @@ -155,14 +159,22 @@ impl ClientBuilder { #[cfg(feature = "openssl")] /// enable openssl as tls connector. pub fn openssl(mut self) -> Self { - self.connector = connector::openssl::connect(self.alpn_from_version()); + self.connector = connector::openssl::connect( + self.alpn_from_version(), + #[cfg(feature = "dangerous")] + self.allow_invalid_certificate, + ); self } #[cfg(any(feature = "rustls", feature = "rustls-ring-crypto"))] /// enable rustls as tls connector. pub fn rustls(mut self) -> Self { - self.connector = connector::rustls::connect(self.alpn_from_version()); + self.connector = connector::rustls::connect( + self.alpn_from_version(), + #[cfg(feature = "dangerous")] + self.allow_invalid_certificate, + ); self } @@ -381,6 +393,13 @@ impl ClientBuilder { self } + #[cfg(feature = "dangerous")] + /// Allow invalid certificate for tls connection. + pub fn allow_invalid_certificate(mut self) -> Self { + self.allow_invalid_certificate = true; + self + } + /// Finish the builder and construct [Client] instance. pub fn finish(self) -> Client { #[cfg(feature = "http3")] @@ -403,70 +422,10 @@ impl ClientBuilder { #[cfg(feature = "dangerous")] { - use xitca_tls::rustls::{ - self, DigitallySignedStruct, - client::danger::HandshakeSignatureValid, - crypto::{verify_tls12_signature, verify_tls13_signature}, - pki_types::{CertificateDer, ServerName, UnixTime}, - }; - - #[derive(Debug)] - pub(crate) struct SkipServerVerification; - - impl SkipServerVerification { - fn new() -> Arc { - Arc::new(Self) - } - } - - impl rustls::client::danger::ServerCertVerifier for SkipServerVerification { - fn verify_server_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp: &[u8], - _now: UnixTime, - ) -> Result { - Ok(rustls::client::danger::ServerCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result { - verify_tls12_signature( - message, - cert, - dss, - &rustls::crypto::ring::default_provider().signature_verification_algorithms, - ) - } - - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result { - verify_tls13_signature( - message, - cert, - dss, - &rustls::crypto::ring::default_provider().signature_verification_algorithms, - ) - } - - fn supported_verify_schemes(&self) -> Vec { - rustls::crypto::ring::default_provider() - .signature_verification_algorithms - .supported_schemes() - } + if self.allow_invalid_certificate { + cfg.dangerous() + .set_certificate_verifier(crate::tls::dangerous::rustls::SkipServerVerification::new()); } - - cfg.dangerous().set_certificate_verifier(SkipServerVerification::new()); } let mut endpoint = match self.local_addr { diff --git a/client/src/tls/connector.rs b/client/src/tls/connector.rs index af7fdedea..06aaf430a 100644 --- a/client/src/tls/connector.rs +++ b/client/src/tls/connector.rs @@ -69,7 +69,7 @@ pub(crate) mod openssl { } } - pub(crate) fn connect(protocols: &[&[u8]]) -> Connector { + pub(crate) fn connect(protocols: &[&[u8]], #[cfg(feature = "dangerous")] allow_invalid_certs: bool) -> Connector { let mut alpn = Vec::with_capacity(20); for proto in protocols { alpn.put_u8(proto.len() as u8); @@ -81,6 +81,13 @@ pub(crate) mod openssl { ssl.set_alpn_protos(&alpn) .unwrap_or_else(|e| panic!("Can not set ALPN protocol: {e:?}")); + #[cfg(feature = "dangerous")] + { + if allow_invalid_certs { + ssl.set_verify(openssl::ssl::SslVerifyMode::NONE); + } + } + Box::new(ssl.build()) } } @@ -89,11 +96,10 @@ pub(crate) mod openssl { pub(crate) mod rustls { use std::sync::Arc; + use super::*; use webpki_roots::TLS_SERVER_ROOTS; use xitca_tls::rustls::{self, ClientConfig, ClientConnection, RootCertStore, pki_types::ServerName}; - use super::*; - pub struct TlsConnector(Arc); impl<'n> Service<(&'n str, TlsStream)> for TlsConnector { @@ -123,7 +129,7 @@ pub(crate) mod rustls { } } - pub(crate) fn connect(protocols: &[&[u8]]) -> Connector { + pub(crate) fn connect(protocols: &[&[u8]], #[cfg(feature = "dangerous")] allow_invalid_certs: bool) -> Connector { let mut root_certs = RootCertStore::empty(); root_certs.extend(TLS_SERVER_ROOTS.iter().cloned()); @@ -134,6 +140,21 @@ pub(crate) mod rustls { config.alpn_protocols = protocols.iter().map(|p| p.to_vec()).collect(); + #[cfg(feature = "dangerous")] + { + if allow_invalid_certs { + #[cfg(feature = "rustls-ring-crypto")] + { + config + .dangerous() + .set_certificate_verifier(crate::tls::dangerous::rustls::SkipServerVerification::new()); + } + + #[cfg(not(feature = "rustls-ring-crypto"))] + unimplemented!("cannot skip server verification without `rustls-ring-crypto` feature"); + } + } + Box::new(TlsConnector(Arc::new(config))) } } diff --git a/client/src/tls/dangerous.rs b/client/src/tls/dangerous.rs new file mode 100644 index 000000000..1b7771353 --- /dev/null +++ b/client/src/tls/dangerous.rs @@ -0,0 +1,67 @@ +#[cfg(feature = "rustls-ring-crypto")] +pub(crate) mod rustls { + use std::sync::Arc; + use xitca_tls::rustls::{ + self, + client::danger::HandshakeSignatureValid, + crypto::{verify_tls12_signature, verify_tls13_signature}, + pki_types::{CertificateDer, ServerName, UnixTime}, + DigitallySignedStruct, + }; + + #[derive(Debug)] + pub(crate) struct SkipServerVerification; + + impl SkipServerVerification { + pub(crate) fn new() -> Arc { + Arc::new(Self) + } + } + + impl rustls::client::danger::ServerCertVerifier for SkipServerVerification { + fn verify_server_cert( + &self, + _end_entity: &CertificateDer<'_>, + _intermediates: &[CertificateDer<'_>], + _server_name: &ServerName<'_>, + _ocsp: &[u8], + _now: UnixTime, + ) -> Result { + Ok(rustls::client::danger::ServerCertVerified::assertion()) + } + + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + verify_tls12_signature( + message, + cert, + dss, + &rustls::crypto::ring::default_provider().signature_verification_algorithms, + ) + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> Result { + verify_tls13_signature( + message, + cert, + dss, + &rustls::crypto::ring::default_provider().signature_verification_algorithms, + ) + } + + fn supported_verify_schemes(&self) -> Vec { + rustls::crypto::ring::default_provider() + .signature_verification_algorithms + .supported_schemes() + } + } +} diff --git a/client/src/tls/mod.rs b/client/src/tls/mod.rs index dcd7c0ccf..973a82451 100644 --- a/client/src/tls/mod.rs +++ b/client/src/tls/mod.rs @@ -1,3 +1,5 @@ pub(crate) mod connector; +#[cfg(feature = "dangerous")] +pub(crate) mod dangerous; pub type TlsStream = Box; diff --git a/test/tests/h3.rs b/test/tests/h3.rs index 0154bc426..c8bc86abe 100644 --- a/test/tests/h3.rs +++ b/test/tests/h3.rs @@ -13,7 +13,7 @@ use xitca_test::{test_h3_server, Error}; async fn h3_get() -> Result<(), Error> { let mut handle = test_h3_server(fn_service(handle))?; - let c = Client::new(); + let c = Client::builder().allow_invalid_certificate().finish(); let server_url = format!("https://localhost:{}/", handle.addr().port()); for _ in 0..3 { @@ -37,7 +37,7 @@ async fn h3_no_host_header() -> Result<(), Error> { let server_url = format!("https://{}/host", handle.ip_port_string()); - let c = Client::new(); + let c = Client::builder().allow_invalid_certificate().finish(); for _ in 0..3 { let mut req = c.get(&server_url).version(Version::HTTP_3); @@ -61,7 +61,7 @@ async fn h3_no_host_header() -> Result<(), Error> { async fn h3_post() -> Result<(), Error> { let mut handle = test_h3_server(fn_service(handle))?; - let c = Client::new(); + let c = Client::builder().allow_invalid_certificate().finish(); let server_url = format!("https://localhost:{}/", handle.addr().port());