From c097beacefcdc6e7355b238fedd47278e71ccbef Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Tue, 17 Dec 2024 22:08:59 -0800 Subject: [PATCH 1/3] Add SslOpts::disable_built_in_roots flag --- src/io/tls/native_tls_io.rs | 1 + src/io/tls/rustls_io.rs | 4 +++- src/opts/mod.rs | 12 ++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/io/tls/native_tls_io.rs b/src/io/tls/native_tls_io.rs index adc8d980..9478303b 100644 --- a/src/io/tls/native_tls_io.rs +++ b/src/io/tls/native_tls_io.rs @@ -36,6 +36,7 @@ impl Endpoint { } builder.danger_accept_invalid_hostnames(ssl_opts.skip_domain_validation()); builder.danger_accept_invalid_certs(ssl_opts.accept_invalid_certs()); + builder.disable_built_in_roots(ssl_opts.disable_built_in_roots()); let tls_connector: tokio_native_tls::TlsConnector = builder.build()?.into(); *self = match self { diff --git a/src/io/tls/rustls_io.rs b/src/io/tls/rustls_io.rs index 76080ff2..c4da0fcf 100644 --- a/src/io/tls/rustls_io.rs +++ b/src/io/tls/rustls_io.rs @@ -46,7 +46,9 @@ impl Endpoint { } let mut root_store = RootCertStore::empty(); - root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().map(|x| x.to_owned())); + if !ssl_opts.disable_built_in_roots() { + root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().map(|x| x.to_owned())); + } for cert in ssl_opts.load_root_certs().await? { root_store.add(cert)?; diff --git a/src/opts/mod.rs b/src/opts/mod.rs index e9044450..c8e47596 100644 --- a/src/opts/mod.rs +++ b/src/opts/mod.rs @@ -214,6 +214,7 @@ pub struct SslOpts { #[cfg(any(feature = "native-tls-tls", feature = "rustls-tls"))] client_identity: Option, root_certs: Vec>, + disable_built_in_roots: bool, skip_domain_validation: bool, accept_invalid_certs: bool, tls_hostname_override: Option>, @@ -236,6 +237,13 @@ impl SslOpts { self } + /// If `true`, use only the root certificates configured via `with_root_certs`, + /// not any system or built-in certs. + pub fn with_disable_built_in_roots(mut self, disable_built_in_roots: bool) -> Self { + self.disable_built_in_roots = disable_built_in_roots; + self + } + /// The way to not validate the server's domain /// name against its certificate (defaults to `false`). pub fn with_danger_skip_domain_validation(mut self, value: bool) -> Self { @@ -271,6 +279,10 @@ impl SslOpts { &self.root_certs } + pub fn disable_built_in_roots(&self) -> bool { + self.disable_built_in_roots + } + pub fn skip_domain_validation(&self) -> bool { self.skip_domain_validation } From 26e48988abd93c6047aa6863906dae5e4c5fc291 Mon Sep 17 00:00:00 2001 From: Anatoly Ikorsky Date: Fri, 20 Dec 2024 11:27:11 +0300 Subject: [PATCH 2/3] Add `built_in_roots` parameter to connection URL. Update docs --- src/opts/mod.rs | 73 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 11 deletions(-) diff --git a/src/opts/mod.rs b/src/opts/mod.rs index c8e47596..7fac74af 100644 --- a/src/opts/mod.rs +++ b/src/opts/mod.rs @@ -237,22 +237,61 @@ impl SslOpts { self } - /// If `true`, use only the root certificates configured via `with_root_certs`, - /// not any system or built-in certs. + /// If `true`, use only the root certificates configured via [`SslOpts::with_root_certs`], + /// not any system or built-in certs. By default system built-in certs _will be_ used. + /// + /// # Connection URL + /// + /// Use `built_in_roots` URL parameter to set this value: + /// + /// ``` + /// # use mysql_async::*; + /// # use std::time::Duration; + /// # fn main() -> Result<()> { + /// let opts = Opts::from_url("mysql://localhost/db?require_ssl=true&built_in_roots=false")?; + /// assert_eq!(opts.ssl_opts().unwrap().disable_built_in_roots(), true); + /// # Ok(()) } + /// ``` pub fn with_disable_built_in_roots(mut self, disable_built_in_roots: bool) -> Self { self.disable_built_in_roots = disable_built_in_roots; self } - /// The way to not validate the server's domain - /// name against its certificate (defaults to `false`). + /// The way to not validate the server's domain name against its certificate. + /// By default domain name _will be_ validated. + /// + /// # Connection URL + /// + /// Use `built_in_roots` URL parameter to set this value: + /// + /// ``` + /// # use mysql_async::*; + /// # use std::time::Duration; + /// # fn main() -> Result<()> { + /// let opts = Opts::from_url("mysql://localhost/db?require_ssl=true&verify_identity=false")?; + /// assert_eq!(opts.ssl_opts().unwrap().skip_domain_validation(), true); + /// # Ok(()) } + /// ``` pub fn with_danger_skip_domain_validation(mut self, value: bool) -> Self { self.skip_domain_validation = value; self } - /// If `true` then client will accept invalid certificate (expired, not trusted, ..) - /// (defaults to `false`). + /// If `true` then client will accept invalid certificate (expired, not trusted, ..). + /// Invalid certificates _won't get_ accepted by default. + /// + /// # Connection URL + /// + /// Use `verify_ca` URL parameter to set this value: + /// + /// ``` + /// # use mysql_async::*; + /// # use std::time::Duration; + /// # fn main() -> Result<()> { + /// let opts = Opts::from_url("mysql://localhost/db?require_ssl=true&verify_ca=false")?; + /// assert_eq!(opts.ssl_opts().unwrap().accept_invalid_certs(), true); + /// # Ok(()) } + /// ``` pub fn with_danger_accept_invalid_certs(mut self, value: bool) -> Self { self.accept_invalid_certs = value; self @@ -1596,6 +1635,7 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result { let mut skip_domain_validation = false; let mut accept_invalid_certs = false; + let mut disable_built_in_roots = false; for (key, value) in query_pairs { if key == "pool_min" { @@ -1696,10 +1736,7 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result { } } else if key == "max_allowed_packet" { match usize::from_str(&value) { - Ok(value) => { - opts.max_allowed_packet = - Some(std::cmp::max(1024, std::cmp::min(1073741824, value))) - } + Ok(value) => opts.max_allowed_packet = Some(value.clamp(1024, 1073741824)), _ => { return Err(UrlError::InvalidParamValue { param: "max_allowed_packet".into(), @@ -1851,6 +1888,18 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result { }); } } + } else if key == "built_in_roots" { + match bool::from_str(&value) { + Ok(x) => { + disable_built_in_roots = !x; + } + _ => { + return Err(UrlError::InvalidParamValue { + param: "built_in_roots".into(), + value, + }); + } + } } else { return Err(UrlError::UnknownParameter { param: key }); } @@ -1868,6 +1917,7 @@ fn mysqlopts_from_url(url: &Url) -> std::result::Result { if let Some(ref mut ssl_opts) = opts.ssl_opts.as_mut() { ssl_opts.accept_invalid_certs = accept_invalid_certs; ssl_opts.skip_domain_validation = skip_domain_validation; + ssl_opts.disable_built_in_roots = disable_built_in_roots; } Ok(opts) @@ -1985,7 +2035,7 @@ mod test { ); const URL4: &str = - "mysql://localhost/foo?require_ssl=true&verify_ca=false&verify_identity=false"; + "mysql://localhost/foo?require_ssl=true&verify_ca=false&verify_identity=false&built_in_roots=false"; let opts = Opts::from_url(URL4).unwrap(); assert_eq!( opts.ssl_opts(), @@ -1993,6 +2043,7 @@ mod test { &SslOpts::default() .with_danger_accept_invalid_certs(true) .with_danger_skip_domain_validation(true) + .with_disable_built_in_roots(true) ) ); From add2a3970dd8747210ad715c8396f9aec3e2b76a Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Fri, 20 Dec 2024 13:00:08 -0800 Subject: [PATCH 3/3] verify_identity --- src/opts/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opts/mod.rs b/src/opts/mod.rs index 7fac74af..04118846 100644 --- a/src/opts/mod.rs +++ b/src/opts/mod.rs @@ -262,7 +262,7 @@ impl SslOpts { /// /// # Connection URL /// - /// Use `built_in_roots` URL parameter to set this value: + /// Use `verify_identity` URL parameter to set this value: /// /// ``` /// # use mysql_async::*;