From 9754975e8fb7c8e9cf02e1e16515a03125ed8743 Mon Sep 17 00:00:00 2001 From: Thomas Constantine Moore Date: Fri, 18 Feb 2022 12:02:17 -0500 Subject: [PATCH] add ssl_ca to accepted connection url query params --- CHANGELOG.md | 2 ++ diesel/src/mysql/connection/mod.rs | 5 +++-- diesel/src/mysql/connection/raw.rs | 13 ++++++++++++ diesel/src/mysql/connection/url.rs | 32 ++++++++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1eaf29f6d3..7e9081246c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/ ### Added +* `MysqlConnection::establish` is able to initiate SSL connection while specifying certificate roots. The database URL should contain `ssl_ca` parameter with a path pointing to the certificate roots. [See docs](https://dev.mysql.com/doc/refman/5.7/en/connection-options.html#option_general_ssl-ca) if desired. + * `MysqlConnection::establish` is able to initiate SSL connection. The database URL should contain `ssl_mode` parameter with a value of the [MySQL client command option `--ssl-mode`](https://dev.mysql.com/doc/refman/5.7/en/connection-options.html#option_general_ssl-mode) if desired. * `Connection` and `SimpleConnection` traits are implemented for a broader range diff --git a/diesel/src/mysql/connection/mod.rs b/diesel/src/mysql/connection/mod.rs index f9e95592e2..2227a82215 100644 --- a/diesel/src/mysql/connection/mod.rs +++ b/diesel/src/mysql/connection/mod.rs @@ -58,9 +58,10 @@ impl Connection for MysqlConnection { /// Establishes a new connection to the MySQL database /// `database_url` may be enhanced by GET parameters - /// `mysql://[user[:password]@]host/database_name[?unix_socket=socket-path&ssl_mode=SSL_MODE*]` + /// `mysql://[user[:password]@]host/database_name[?unix_socket=socket-path&ssl_mode=SSL_MODE*&ssl_ca=/etc/ssl/certs/ca-certificates.crt]` /// - /// * `unix_socket` excepts the path to the unix socket + /// * `unix_socket` expects the path to the unix socket + /// * `ssl_ca` accepts a path to the system's certificate roots /// * `ssl_mode` expects a value defined for MySQL client command option `--ssl-mode` /// See fn establish(database_url: &str) -> ConnectionResult { diff --git a/diesel/src/mysql/connection/raw.rs b/diesel/src/mysql/connection/raw.rs index 0f1fae5a98..3a4433e02b 100644 --- a/diesel/src/mysql/connection/raw.rs +++ b/diesel/src/mysql/connection/raw.rs @@ -51,6 +51,9 @@ impl RawConnection { if let Some(ssl_mode) = connection_options.ssl_mode() { self.set_ssl_mode(ssl_mode) } + if let Some(ssl_ca) = connection_options.ssl_ca() { + self.set_ssl_ca(ssl_ca) + } unsafe { // Make sure you don't use the fake one! @@ -197,6 +200,16 @@ impl RawConnection { ) }; } + + fn set_ssl_ca(&self, ssl_ca: &CStr) { + unsafe { + mysqlclient_sys::mysql_options( + self.0.as_ptr(), + mysqlclient_sys::mysql_option::MYSQL_OPT_SSL_CA, + ssl_ca.as_ptr() as *const std::ffi::c_void, + ) + }; + } } impl Drop for RawConnection { diff --git a/diesel/src/mysql/connection/url.rs b/diesel/src/mysql/connection/url.rs index 582b7cc2d2..f052f8ee15 100644 --- a/diesel/src/mysql/connection/url.rs +++ b/diesel/src/mysql/connection/url.rs @@ -49,6 +49,7 @@ pub struct ConnectionOptions { unix_socket: Option, client_flags: CapabilityFlags, ssl_mode: Option, + ssl_ca: Option, } impl ConnectionOptions { @@ -76,6 +77,11 @@ impl ConnectionOptions { _ => None, }; + let ssl_ca = match query_pairs.get("ssl_ca") { + Some(v) => Some(CString::new(v.as_bytes())?), + _ => None, + }; + let ssl_mode = match query_pairs.get("ssl_mode") { Some(v) => { let ssl_mode = match v.to_lowercase().as_str() { @@ -123,6 +129,7 @@ impl ConnectionOptions { unix_socket: unix_socket, client_flags: client_flags, ssl_mode: ssl_mode, + ssl_ca: ssl_ca, }) } @@ -150,6 +157,10 @@ impl ConnectionOptions { self.unix_socket.as_deref() } + pub fn ssl_ca(&self) -> Option<&CStr> { + self.ssl_ca.as_deref() + } + pub fn client_flags(&self) -> CapabilityFlags { self.client_flags } @@ -293,6 +304,27 @@ fn unix_socket_tests() { ); } +#[test] +fn ssl_ca_tests() { + let ssl_ca = "/etc/ssl/certs/ca-certificates.crt"; + let username = "foo"; + let password = "bar"; + let db_url = format!( + "mysql://{}:{}@localhost?ssl_ca={}", + username, password, ssl_ca + ); + let conn_opts = ConnectionOptions::parse(db_url.as_str()).unwrap(); + let cstring = |s| CString::new(s).unwrap(); + assert_eq!(None, conn_opts.host); + assert_eq!(None, conn_opts.port); + assert_eq!(cstring(username), conn_opts.user); + assert_eq!(cstring(password), conn_opts.password.unwrap()); + assert_eq!( + CString::new(ssl_ca).unwrap(), + conn_opts.ssl_ca.unwrap() + ); +} + #[test] fn ssl_mode() { let ssl_mode = |url| ConnectionOptions::parse(url).unwrap().ssl_mode();