From 1b87b6d5871e785e68afabd9298b294248d6681d Mon Sep 17 00:00:00 2001 From: avtrujillo Date: Tue, 7 May 2024 14:06:57 -0700 Subject: [PATCH 1/2] update rustls dependency and make edits to support its api changes --- Cargo.lock | 50 ++++---- sqlx-core/Cargo.toml | 6 +- sqlx-core/src/error.rs | 8 ++ sqlx-core/src/net/tls/tls_rustls.rs | 189 +++++++++++++++++++--------- 4 files changed, 168 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b351e99184..909bbad45a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -465,12 +465,6 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.0" @@ -2824,31 +2818,42 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.11" +version = "0.23.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fecbfb7b1444f477b345853b1fce097a2c6fb637b2bfb87e6bc5db0f043fae4" +checksum = "afabcee0551bd1aa3e18e5adbf2c0544722014b899adb31bd186ec638d3da97e" dependencies = [ + "once_cell", "ring", + "rustls-pki-types", "rustls-webpki", - "sct", + "subtle", + "zeroize", ] [[package]] name = "rustls-pemfile" -version = "1.0.4" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" dependencies = [ - "base64 0.21.7", + "base64 0.22.0", + "rustls-pki-types", ] +[[package]] +name = "rustls-pki-types" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beb461507cee2c2ff151784c52762cf4d9ff6a61f3e80968600ed24fa837fa54" + [[package]] name = "rustls-webpki" -version = "0.101.7" +version = "0.102.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" dependencies = [ "ring", + "rustls-pki-types", "untrusted", ] @@ -2906,16 +2911,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "seahash" version = "4.1.0" @@ -4232,9 +4227,12 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.4" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +dependencies = [ + "rustls-pki-types", +] [[package]] name = "whoami" diff --git a/sqlx-core/Cargo.toml b/sqlx-core/Cargo.toml index d81414b521..dae09bdc91 100644 --- a/sqlx-core/Cargo.toml +++ b/sqlx-core/Cargo.toml @@ -36,9 +36,9 @@ tokio = { workspace = true, optional = true } # TLS native-tls = { version = "0.2.10", optional = true } -rustls = { version = "0.21.11", default-features = false, features = ["dangerous_configuration", "tls12"], optional = true } -rustls-pemfile = { version = "1.0", optional = true } -webpki-roots = { version = "0.25", optional = true } +rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"], optional = true} +rustls-pemfile = { version = "2.1.2", optional = true } +webpki-roots = { version = "0.26.1", optional = true } # Type Integrations bit-vec = { workspace = true, optional = true } diff --git a/sqlx-core/src/error.rs b/sqlx-core/src/error.rs index 5c4c223fad..d203067a7d 100644 --- a/sqlx-core/src/error.rs +++ b/sqlx-core/src/error.rs @@ -6,6 +6,10 @@ use std::error::Error as StdError; use std::fmt::Display; use std::io; +// use rustls::server::VerifierBuilderError; +#[cfg(feature = "_tls-rustls")] +use rustls::server::VerifierBuilderError; + use crate::database::Database; use crate::type_info::TypeInfo; @@ -107,6 +111,10 @@ pub enum Error { #[cfg(feature = "migrate")] #[error("{0}")] Migrate(#[source] Box), + + #[cfg(feature = "_tls-rustls")] + #[error("Error building server verifier: {0}")] + VerifierBuilder(#[from] VerifierBuilderError) } impl StdError for Box {} diff --git a/sqlx-core/src/net/tls/tls_rustls.rs b/sqlx-core/src/net/tls/tls_rustls.rs index 7246e794e1..381ccb2bda 100644 --- a/sqlx-core/src/net/tls/tls_rustls.rs +++ b/sqlx-core/src/net/tls/tls_rustls.rs @@ -1,13 +1,16 @@ use futures_util::future; +use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; +use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName, UnixTime}; +use rustls::ClientConnection; use std::io::{self, BufReader, Cursor, Read, Write}; use std::sync::Arc; use std::task::{Context, Poll}; -use std::time::SystemTime; use rustls::{ - client::{ServerCertVerified, ServerCertVerifier, WebPkiVerifier}, - CertificateError, ClientConfig, ClientConnection, Error as TlsError, OwnedTrustAnchor, - RootCertStore, ServerName, + CertificateError, ClientConfig, + Error as TlsError, + client::WebPkiServerVerifier, + RootCertStore, }; use crate::error::Error; @@ -18,7 +21,7 @@ use crate::net::Socket; pub struct RustlsSocket { inner: StdSocket, - state: ClientConnection, + state: rustls::ClientConnection, close_notify_sent: bool, } @@ -85,7 +88,7 @@ pub async fn handshake(socket: S, tls_config: TlsConfig<'_>) -> Result { + Some(Error::Tls(format!("Invalid certificate {ca}").into())) + }, + Ok(v) => { + match cert_store.add(v) { + Err(e) => Some(Error::Tls(e.into())), + Ok(()) => None + } + } + } + }); + // Return the first error + if let Some(e) = errors.next() { + return Err(e) } } if tls_config.accept_invalid_hostnames { - let verifier = WebPkiVerifier::new(cert_store, None); + let verifier = WebPkiServerVerifier::builder( + Arc::new(cert_store) + ).build()?; if let Some(user_auth) = user_auth { - config + builder.dangerous() .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier })) .with_client_auth_cert(user_auth.0, user_auth.1) .map_err(Error::tls)? } else { - config + builder.dangerous() .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier })) .with_no_client_auth() } } else if let Some(user_auth) = user_auth { - config + builder .with_root_certificates(cert_store) .with_client_auth_cert(user_auth.0, user_auth.1) .map_err(Error::tls)? } else { - config + builder .with_root_certificates(cert_store) .with_no_client_auth() } }; - let host = rustls::ServerName::try_from(tls_config.hostname).map_err(Error::tls)?; + let host = ServerName::try_from(tls_config.hostname.to_string()).map_err(Error::tls)?; let mut socket = RustlsSocket { inner: StdSocket::new(socket), @@ -175,26 +188,47 @@ where Ok(socket) } -fn certs_from_pem(pem: Vec) -> Result, Error> { +fn certs_from_pem(pem: Vec) -> Result>, Error> { let cur = Cursor::new(pem); let mut reader = BufReader::new(cur); - rustls_pemfile::certs(&mut reader)? - .into_iter() - .map(|v| Ok(rustls::Certificate(v))) - .collect() + let mut err: Option = None; + let mut certs: Vec> = Vec::new(); + let mut certs_iter = rustls_pemfile::certs(&mut reader).into_iter(); + // Iterate over all results of rustls_pemfile::certs, collection them into a vec and + // returning on the first error + while let Some(cert_result) = certs_iter.next() { + if err.is_none() { + match cert_result { + Err(e) => { + err = Some(Error::Io(e)); + }, + Ok(v) => { + certs.push(v); + } + } + } + }; + match err { + Some(e) => Err(e), + None => Ok(certs) + } } -fn private_key_from_pem(pem: Vec) -> Result { +fn private_key_from_pem(pem: Vec) -> Result, Error> { let cur = Cursor::new(pem); let mut reader = BufReader::new(cur); loop { match rustls_pemfile::read_one(&mut reader)? { - Some( - rustls_pemfile::Item::RSAKey(key) - | rustls_pemfile::Item::PKCS8Key(key) - | rustls_pemfile::Item::ECKey(key), - ) => return Ok(rustls::PrivateKey(key)), + Some(rustls_pemfile::Item::Pkcs8Key(key)) => { + return Ok(PrivateKeyDer::Pkcs8(key)) + }, + Some(rustls_pemfile::Item::Sec1Key(key)) => { + return Ok(PrivateKeyDer::Sec1(key)) + }, + Some(rustls_pemfile::Item::Pkcs1Key(key)) => { + return Ok(PrivateKeyDer::Pkcs1(key)) + }, None => break, _ => {} } @@ -203,41 +237,62 @@ fn private_key_from_pem(pem: Vec) -> Result { Err(Error::Configuration("no keys found pem file".into())) } +#[derive(Debug)] struct DummyTlsVerifier; impl ServerCertVerifier for DummyTlsVerifier { fn verify_server_cert( &self, - _end_entity: &rustls::Certificate, - _intermediates: &[rustls::Certificate], - _server_name: &ServerName, - _scts: &mut dyn Iterator, + _end_entity: &rustls::pki_types::CertificateDer<'_>, + _intermediates: &[rustls::pki_types::CertificateDer<'_>], + _server_name: &ServerName<'_>, _ocsp_response: &[u8], - _now: SystemTime, + _now: UnixTime, ) -> Result { Ok(ServerCertVerified::assertion()) } + + fn verify_tls12_signature( + &self, + _message: &[u8], + _cert: &CertificateDer<'_>, + _dss: &rustls::DigitallySignedStruct, + ) -> Result { + Ok(HandshakeSignatureValid::assertion()) + } + + fn verify_tls13_signature( + &self, + _message: &[u8], + _cert: &CertificateDer<'_>, + _dss: &rustls::DigitallySignedStruct, + ) -> Result { + Ok(HandshakeSignatureValid::assertion()) + } + + fn supported_verify_schemes(&self) -> Vec { + vec!() + } } +#[derive(Debug)] pub struct NoHostnameTlsVerifier { - verifier: WebPkiVerifier, + verifier: Arc, } impl ServerCertVerifier for NoHostnameTlsVerifier { fn verify_server_cert( &self, - end_entity: &rustls::Certificate, - intermediates: &[rustls::Certificate], - server_name: &ServerName, - scts: &mut dyn Iterator, + end_entity: &rustls::pki_types::CertificateDer<'_>, + intermediates: &[rustls::pki_types::CertificateDer<'_>], + server_name: &ServerName<'_>, ocsp_response: &[u8], - now: SystemTime, + now: UnixTime, ) -> Result { match self.verifier.verify_server_cert( end_entity, intermediates, server_name, - scts, ocsp_response, now, ) { @@ -249,4 +304,26 @@ impl ServerCertVerifier for NoHostnameTlsVerifier { res => res, } } + + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &rustls::DigitallySignedStruct, + ) -> Result { + self.verifier.verify_tls12_signature(message, cert, dss) + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &rustls::DigitallySignedStruct, + ) -> Result { + self.verifier.verify_tls13_signature(message, cert, dss) + } + + fn supported_verify_schemes(&self) -> Vec { + self.verifier.supported_verify_schemes() + } } From 076d5fad94a661cedc0b5dd5c0a412d5911d6d25 Mon Sep 17 00:00:00 2001 From: avtrujillo Date: Tue, 7 May 2024 14:42:42 -0700 Subject: [PATCH 2/2] Remove unnecessary addition of ring feature in rustls dep of sqlx-core --- Cargo.lock | 1 - sqlx-core/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 909bbad45a..35f2018cd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2823,7 +2823,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afabcee0551bd1aa3e18e5adbf2c0544722014b899adb31bd186ec638d3da97e" dependencies = [ "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", diff --git a/sqlx-core/Cargo.toml b/sqlx-core/Cargo.toml index dae09bdc91..51fca0fb84 100644 --- a/sqlx-core/Cargo.toml +++ b/sqlx-core/Cargo.toml @@ -36,7 +36,7 @@ tokio = { workspace = true, optional = true } # TLS native-tls = { version = "0.2.10", optional = true } -rustls = { version = "0.23.5", default-features = false, features = ["std", "ring", "tls12"], optional = true} +rustls = { version = "0.23.5", default-features = false, features = ["std", "tls12"], optional = true} rustls-pemfile = { version = "2.1.2", optional = true } webpki-roots = { version = "0.26.1", optional = true }