From 4d50c8982937066e96cd00802d1db67392b287b2 Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Wed, 29 Jun 2022 13:33:32 +0700 Subject: [PATCH 01/24] Updated README.md with patch submission instructions --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b9b5caf..704ac17 100644 --- a/README.md +++ b/README.md @@ -20,3 +20,7 @@ let connect_fut = tokio_postgres::connect("sslmode=require host=localhost user=p # License tokio-postgres-rustls is distributed under the MIT license. + +# Submitting patches + +To submit a patch, please familiarise yourself with [mailing list etiquette](https://man.sr.ht/lists.sr.ht/etiquette.md) and the use of [git-send-email](https://man.sr.ht/git.sr.ht/send-email.md) and then send your patch to the [https://lists.sr.ht/~jbg/patches](~jbg/patches mailing list). Please prefix the subject with [PATCH tokio-postgres-rustls]. From 1f1b61fa5ee5d620af73731ea5f1c1142e3aea11 Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Wed, 29 Jun 2022 13:34:40 +0700 Subject: [PATCH 02/24] corrected markdown syntax in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 704ac17..30ef17a 100644 --- a/README.md +++ b/README.md @@ -23,4 +23,4 @@ tokio-postgres-rustls is distributed under the MIT license. # Submitting patches -To submit a patch, please familiarise yourself with [mailing list etiquette](https://man.sr.ht/lists.sr.ht/etiquette.md) and the use of [git-send-email](https://man.sr.ht/git.sr.ht/send-email.md) and then send your patch to the [https://lists.sr.ht/~jbg/patches](~jbg/patches mailing list). Please prefix the subject with [PATCH tokio-postgres-rustls]. +To submit a patch, please familiarise yourself with [mailing list etiquette](https://man.sr.ht/lists.sr.ht/etiquette.md) and the use of [git-send-email](https://man.sr.ht/git.sr.ht/send-email.md) and then send your patch to the [~jbg/patches mailing list](https://lists.sr.ht/~jbg/patches). Please prefix the subject with [PATCH tokio-postgres-rustls]. From e1c0177254cc3347c94a460f6541871b58c611ad Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Fri, 6 Jan 2023 11:26:00 +0800 Subject: [PATCH 03/24] Move back to GitHub --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 30ef17a..b9b5caf 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,3 @@ let connect_fut = tokio_postgres::connect("sslmode=require host=localhost user=p # License tokio-postgres-rustls is distributed under the MIT license. - -# Submitting patches - -To submit a patch, please familiarise yourself with [mailing list etiquette](https://man.sr.ht/lists.sr.ht/etiquette.md) and the use of [git-send-email](https://man.sr.ht/git.sr.ht/send-email.md) and then send your patch to the [~jbg/patches mailing list](https://lists.sr.ht/~jbg/patches). Please prefix the subject with [PATCH tokio-postgres-rustls]. From 80f212d0d94193b4d7a94c98214fee901627dbbf Mon Sep 17 00:00:00 2001 From: Ning Sun Date: Sun, 9 Apr 2023 20:37:14 +0800 Subject: [PATCH 04/24] chore: update rustls libraries --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 520ee65..1855f17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,13 +11,13 @@ readme = "README.md" [dependencies] futures = "0.3" ring = "0.16" -rustls = "0.20" +rustls = "0.21" tokio = "1" tokio-postgres = "0.7" -tokio-rustls = "0.23" +tokio-rustls = "0.24" [dev-dependencies] env_logger = { version = "0.8", default-features = false } tokio = { version = "1", features = ["macros", "rt"] } -rustls = { version = "0.20", features = ["dangerous_configuration"] } +rustls = { version = "0.21", features = ["dangerous_configuration"] } From f8ef31e11d6932ecaba9fcf1f1e864cdded23d44 Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Fri, 14 Apr 2023 11:43:48 +0800 Subject: [PATCH 05/24] Prune unneeded features from dependencies --- Cargo.toml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1855f17..253da9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,15 +9,15 @@ license = "MIT" readme = "README.md" [dependencies] -futures = "0.3" -ring = "0.16" -rustls = "0.21" -tokio = "1" -tokio-postgres = "0.7" -tokio-rustls = "0.24" +futures = { version = "0.3", default-features = false } +ring = { version = "0.16", default-features = false } +rustls = { version = "0.21", default-features = false } +tokio = { version = "1", default-features = false } +tokio-postgres = { version = "0.7", default-features = false } +tokio-rustls = { version = "0.24", default-features = false } [dev-dependencies] env_logger = { version = "0.8", default-features = false } tokio = { version = "1", features = ["macros", "rt"] } +tokio-postgres = "0.7" rustls = { version = "0.21", features = ["dangerous_configuration"] } - From f536e4d8098cfcdc513c2b4e974f87ed7096dcba Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Fri, 14 Apr 2023 11:44:11 +0800 Subject: [PATCH 06/24] Bump version to 0.10.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 253da9b..5587d51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tokio-postgres-rustls" description = "Rustls integration for tokio-postgres" -version = "0.9.0" +version = "0.10.0" authors = ["Jasper Hugo "] repository = "https://github.com/jbg/tokio-postgres-rustls" edition = "2018" From 9b0344bd0ac11d8d4d2fec83bdd535e5712cc6c2 Mon Sep 17 00:00:00 2001 From: ol Date: Tue, 5 Dec 2023 11:21:59 +0100 Subject: [PATCH 07/24] add support for rustls 0.22 --- Cargo.toml | 7 ++++--- src/lib.rs | 57 ++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5587d51..d5ad5ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,13 +11,14 @@ readme = "README.md" [dependencies] futures = { version = "0.3", default-features = false } ring = { version = "0.16", default-features = false } -rustls = { version = "0.21", default-features = false } +rustls = { version = "0.22", default-features = false } +rustls-pki-types = { version = "1", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } -tokio-rustls = { version = "0.24", default-features = false } +tokio-rustls = { version = "0.25", default-features = false } [dev-dependencies] env_logger = { version = "0.8", default-features = false } tokio = { version = "1", features = ["macros", "rt"] } tokio-postgres = "0.7" -rustls = { version = "0.21", features = ["dangerous_configuration"] } +rustls = { version = "0.22" } diff --git a/src/lib.rs b/src/lib.rs index a3a4fc2..572a9b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,8 @@ use std::{ use futures::future::{FutureExt, TryFutureExt}; use ring::digest; -use rustls::{ClientConfig, ServerName}; +use rustls::ClientConfig; +use rustls_pki_types::ServerName; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_postgres::tls::{ChannelBinding, MakeTlsConnect, TlsConnect}; use tokio_rustls::{client::TlsStream, TlsConnector}; @@ -39,7 +40,7 @@ where ServerName::try_from(hostname) .map(|dns_name| { RustlsConnect(Some(RustlsConnectData { - hostname: dns_name, + hostname: dns_name.to_owned(), connector: Arc::clone(&self.config).into(), })) }) @@ -50,7 +51,7 @@ where pub struct RustlsConnect(Option); struct RustlsConnectData { - hostname: ServerName, + hostname: ServerName<'static>, connector: TlsConnector, } @@ -130,22 +131,55 @@ where mod tests { use super::*; use futures::future::TryFutureExt; - use rustls::{client::ServerCertVerified, client::ServerCertVerifier, Certificate, Error}; - use std::time::SystemTime; - + use rustls::{ + client::danger::ServerCertVerifier, + client::danger::{HandshakeSignatureValid, ServerCertVerified}, + Error, SignatureScheme, + }; + use rustls_pki_types::{CertificateDer, UnixTime}; + + #[derive(Debug)] struct AcceptAllVerifier {} impl ServerCertVerifier for AcceptAllVerifier { fn verify_server_cert( &self, - _end_entity: &Certificate, - _intermediates: &[Certificate], - _server_name: &ServerName, - _scts: &mut dyn Iterator, + _end_entity: &CertificateDer<'_>, + _intermediates: &[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![ + SignatureScheme::ECDSA_NISTP384_SHA384, + SignatureScheme::ECDSA_NISTP256_SHA256, + SignatureScheme::RSA_PSS_SHA512, + SignatureScheme::RSA_PSS_SHA384, + SignatureScheme::RSA_PSS_SHA256, + SignatureScheme::ED25519, + ] + } } #[tokio::test] @@ -153,7 +187,6 @@ mod tests { env_logger::builder().is_test(true).try_init().unwrap(); let mut config = rustls::ClientConfig::builder() - .with_safe_defaults() .with_root_certificates(rustls::RootCertStore::empty()) .with_no_client_auth(); config From d78fad4c4ece18ec51b9d139101285f8ad3b8024 Mon Sep 17 00:00:00 2001 From: ol Date: Tue, 5 Dec 2023 11:44:11 +0100 Subject: [PATCH 08/24] remove with_safe_defaults from readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index b9b5caf..e10efb5 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ and the [tokio-postgres asynchronous PostgreSQL client library](https://github.c ``` let config = rustls::ClientConfig::builder() - .with_safe_defaults() .with_root_certificates(rustls::RootCertStore::empty()) .with_no_client_auth(); let tls = tokio_postgres_rustls::MakeRustlsConnect::new(config); From 77adc956c87625c422edc3090611b8743e621028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Mon, 25 Dec 2023 15:12:23 +0000 Subject: [PATCH 09/24] Don't explicitly depend on rustls-pki-types --- Cargo.toml | 3 +-- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d5ad5ae..7705cf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,7 @@ readme = "README.md" [dependencies] futures = { version = "0.3", default-features = false } ring = { version = "0.16", default-features = false } -rustls = { version = "0.22", default-features = false } -rustls-pki-types = { version = "1", default-features = false } +rustls = { version = "0.22.1", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } tokio-rustls = { version = "0.25", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index 572a9b0..0b5b076 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ use std::{ use futures::future::{FutureExt, TryFutureExt}; use ring::digest; use rustls::ClientConfig; -use rustls_pki_types::ServerName; +use rustls::pki_types::ServerName; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_postgres::tls::{ChannelBinding, MakeTlsConnect, TlsConnect}; use tokio_rustls::{client::TlsStream, TlsConnector}; @@ -136,7 +136,7 @@ mod tests { client::danger::{HandshakeSignatureValid, ServerCertVerified}, Error, SignatureScheme, }; - use rustls_pki_types::{CertificateDer, UnixTime}; + use rustls::pki_types::{CertificateDer, UnixTime}; #[derive(Debug)] struct AcceptAllVerifier {} From 531c8af4420fcd1b551ffe9eb5e9f3c714812333 Mon Sep 17 00:00:00 2001 From: Fletcher Nichol Date: Mon, 8 Jan 2024 13:44:36 -0700 Subject: [PATCH 10/24] Upgrade ring to 0.17 The only direct usage of `ring` is calling `ring::digest::digest` which has not changed from the 0.16.x ring releases. Signed-off-by: Fletcher Nichol --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5587d51..c1ddfa6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" [dependencies] futures = { version = "0.3", default-features = false } -ring = { version = "0.16", default-features = false } +ring = { version = "0.17", default-features = false } rustls = { version = "0.21", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } From 1d6c54cfe79de4e49d54311f1e3beeb60bfa167b Mon Sep 17 00:00:00 2001 From: James Guthrie Date: Mon, 21 Aug 2023 12:11:32 +0200 Subject: [PATCH 11/24] fix: Use correct digest for SCRAM channel binding Currently, when connecting to a server using a certificate with a SHA2-384-based signature algorithm in "sslmode=require", the connection fails with the following error: "FATAL: SCRAM channel binding check failed". This is because the client is hard-coded to use the SHA2-256 digest algorithm to calculate the channel binding. The digest algorithm used should be derived from the server's certificate. This change parses the server's certificate, extracting the digest algorithm and using that to calculate the channel binding. --- Cargo.toml | 1 + src/lib.rs | 29 +++++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5587d51..11d56fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ rustls = { version = "0.21", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } tokio-rustls = { version = "0.24", default-features = false } +x509-certificate = {version = "0.21.0", default-features = false } [dev-dependencies] env_logger = { version = "0.8", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index a3a4fc2..fc42c4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ use std::{ sync::Arc, task::{Context, Poll}, }; +use DigestAlgorithm::{Sha1, Sha256, Sha384, Sha512}; use futures::future::{FutureExt, TryFutureExt}; use ring::digest; @@ -13,6 +14,10 @@ use rustls::{ClientConfig, ServerName}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_postgres::tls::{ChannelBinding, MakeTlsConnect, TlsConnect}; use tokio_rustls::{client::TlsStream, TlsConnector}; +use x509_certificate::{algorithm, DigestAlgorithm, SignatureAlgorithm, X509Certificate}; +use SignatureAlgorithm::{ + EcdsaSha256, EcdsaSha384, Ed25519, NoSignature, RsaSha1, RsaSha256, RsaSha384, RsaSha512, +}; #[derive(Clone)] pub struct MakeRustlsConnect { @@ -83,10 +88,26 @@ where fn channel_binding(&self) -> ChannelBinding { let (_, session) = self.0.get_ref(); match session.peer_certificates() { - Some(certs) if !certs.is_empty() => { - let sha256 = digest::digest(&digest::SHA256, certs[0].as_ref()); - ChannelBinding::tls_server_end_point(sha256.as_ref().into()) - } + Some(certs) if !certs.is_empty() => X509Certificate::from_der(&certs[0]) + .ok() + .and_then(|cert| cert.signature_algorithm()) + .map(|algorithm| match algorithm { + // Note: SHA1 is upgraded to SHA256 as per https://datatracker.ietf.org/doc/html/rfc5929#section-4.1 + RsaSha1 | RsaSha256 | EcdsaSha256 => &digest::SHA256, + RsaSha384 | EcdsaSha384 => &digest::SHA384, + RsaSha512 => &digest::SHA512, + Ed25519 => &digest::SHA512, + NoSignature(algo) => match algo { + Sha1 | Sha256 => &digest::SHA256, + Sha384 => &digest::SHA384, + Sha512 => &digest::SHA512, + }, + }) + .map(|algorithm| { + let hash = digest::digest(algorithm, certs[0].as_ref()); + ChannelBinding::tls_server_end_point(hash.as_ref().into()) + }) + .unwrap_or(ChannelBinding::none()), _ => ChannelBinding::none(), } } From 6ddca4101790695b6b01f1f07bc3ad5c218caebb Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Sun, 14 Jan 2024 12:26:23 +0100 Subject: [PATCH 12/24] Bump version to 0.11.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 812f937..39a4706 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tokio-postgres-rustls" description = "Rustls integration for tokio-postgres" -version = "0.10.0" +version = "0.11.0" authors = ["Jasper Hugo "] repository = "https://github.com/jbg/tokio-postgres-rustls" edition = "2018" From 91d9d03eea72395f6c6cc8fc6bdc6a8a9198414e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Sun, 14 Jan 2024 15:06:11 +0000 Subject: [PATCH 13/24] Update x509-certificate from 0.21 to 0.23 This was causing us to pull in multiple versions of ring, should probably make a 0.11.1 release --- Cargo.toml | 4 ++-- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 39a4706..fd91ba7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,10 +15,10 @@ rustls = { version = "0.22.1", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } tokio-rustls = { version = "0.25", default-features = false } -x509-certificate = {version = "0.21.0", default-features = false } +x509-certificate = {version = "0.23.0", default-features = false } [dev-dependencies] -env_logger = { version = "0.8", default-features = false } +env_logger = { version = "0.10", default-features = false } tokio = { version = "1", features = ["macros", "rt"] } tokio-postgres = "0.7" rustls = { version = "0.22" } diff --git a/src/lib.rs b/src/lib.rs index 7173ae6..148eecb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ use rustls::pki_types::ServerName; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_postgres::tls::{ChannelBinding, MakeTlsConnect, TlsConnect}; use tokio_rustls::{client::TlsStream, TlsConnector}; -use x509_certificate::{algorithm, DigestAlgorithm, SignatureAlgorithm, X509Certificate}; +use x509_certificate::{DigestAlgorithm, SignatureAlgorithm, X509Certificate}; use SignatureAlgorithm::{ EcdsaSha256, EcdsaSha384, Ed25519, NoSignature, RsaSha1, RsaSha256, RsaSha384, RsaSha512, }; From 2c6cfad957ae5f537cc519ff1493a82237d6da49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Sun, 14 Jan 2024 17:00:15 +0000 Subject: [PATCH 14/24] Fix MakeTlsConnect error to be rustls::pki_types::InvalidDnsNameError --- src/lib.rs | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7173ae6..eca5f2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,12 +10,12 @@ use DigestAlgorithm::{Sha1, Sha256, Sha384, Sha512}; use futures::future::{FutureExt, TryFutureExt}; use ring::digest; -use rustls::ClientConfig; use rustls::pki_types::ServerName; +use rustls::ClientConfig; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_postgres::tls::{ChannelBinding, MakeTlsConnect, TlsConnect}; use tokio_rustls::{client::TlsStream, TlsConnector}; -use x509_certificate::{algorithm, DigestAlgorithm, SignatureAlgorithm, X509Certificate}; +use x509_certificate::{DigestAlgorithm, SignatureAlgorithm, X509Certificate}; use SignatureAlgorithm::{ EcdsaSha256, EcdsaSha384, Ed25519, NoSignature, RsaSha1, RsaSha256, RsaSha384, RsaSha512, }; @@ -39,21 +39,19 @@ where { type Stream = RustlsStream; type TlsConnect = RustlsConnect; - type Error = io::Error; + type Error = rustls::pki_types::InvalidDnsNameError; - fn make_tls_connect(&mut self, hostname: &str) -> io::Result { - ServerName::try_from(hostname) - .map(|dns_name| { - RustlsConnect(Some(RustlsConnectData { - hostname: dns_name.to_owned(), - connector: Arc::clone(&self.config).into(), - })) + fn make_tls_connect(&mut self, hostname: &str) -> Result { + ServerName::try_from(hostname).map(|dns_name| { + RustlsConnect(RustlsConnectData { + hostname: dns_name.to_owned(), + connector: Arc::clone(&self.config).into(), }) - .or(Ok(RustlsConnect(None))) + }) } } -pub struct RustlsConnect(Option); +pub struct RustlsConnect(RustlsConnectData); struct RustlsConnectData { hostname: ServerName<'static>, @@ -69,14 +67,11 @@ where type Future = Pin>> + Send>>; fn connect(self, stream: S) -> Self::Future { - match self.0 { - None => Box::pin(core::future::ready(Err(io::ErrorKind::InvalidInput.into()))), - Some(c) => c - .connector - .connect(c.hostname, stream) - .map_ok(|s| RustlsStream(Box::pin(s))) - .boxed(), - } + self.0 + .connector + .connect(self.0.hostname, stream) + .map_ok(|s| RustlsStream(Box::pin(s))) + .boxed() } } @@ -152,12 +147,12 @@ where mod tests { use super::*; use futures::future::TryFutureExt; + use rustls::pki_types::{CertificateDer, UnixTime}; use rustls::{ client::danger::ServerCertVerifier, client::danger::{HandshakeSignatureValid, ServerCertVerified}, Error, SignatureScheme, }; - use rustls::pki_types::{CertificateDer, UnixTime}; #[derive(Debug)] struct AcceptAllVerifier {} From 8c611e63f139c9088e5ee5e0f541baf63f6298c9 Mon Sep 17 00:00:00 2001 From: asonix Date: Mon, 15 Jan 2024 13:19:48 -0500 Subject: [PATCH 15/24] Use async blocks to remove dependency on FutureExt and TryFutureExt --- Cargo.toml | 1 - src/lib.rs | 19 +++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fd91ba7..5a5b403 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ license = "MIT" readme = "README.md" [dependencies] -futures = { version = "0.3", default-features = false } ring = { version = "0.17", default-features = false } rustls = { version = "0.22.1", default-features = false } tokio = { version = "1", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index 148eecb..b4f9d9d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,10 +8,9 @@ use std::{ }; use DigestAlgorithm::{Sha1, Sha256, Sha384, Sha512}; -use futures::future::{FutureExt, TryFutureExt}; use ring::digest; -use rustls::ClientConfig; use rustls::pki_types::ServerName; +use rustls::ClientConfig; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_postgres::tls::{ChannelBinding, MakeTlsConnect, TlsConnect}; use tokio_rustls::{client::TlsStream, TlsConnector}; @@ -71,11 +70,12 @@ where fn connect(self, stream: S) -> Self::Future { match self.0 { None => Box::pin(core::future::ready(Err(io::ErrorKind::InvalidInput.into()))), - Some(c) => c - .connector - .connect(c.hostname, stream) - .map_ok(|s| RustlsStream(Box::pin(s))) - .boxed(), + Some(c) => Box::pin(async move { + c.connector + .connect(c.hostname, stream) + .await + .map(|s| RustlsStream(Box::pin(s))) + }), } } } @@ -151,13 +151,12 @@ where #[cfg(test)] mod tests { use super::*; - use futures::future::TryFutureExt; + use rustls::pki_types::{CertificateDer, UnixTime}; use rustls::{ client::danger::ServerCertVerifier, client::danger::{HandshakeSignatureValid, ServerCertVerified}, Error, SignatureScheme, }; - use rustls::pki_types::{CertificateDer, UnixTime}; #[derive(Debug)] struct AcceptAllVerifier {} @@ -220,7 +219,7 @@ mod tests { ) .await .expect("connect"); - tokio::spawn(conn.map_err(|e| panic!("{:?}", e))); + tokio::spawn(async move { conn.await.map_err(|e| panic!("{:?}", e)) }); let stmt = client.prepare("SELECT 1").await.expect("prepare"); let _ = client.query(&stmt, &[]).await.expect("query"); } From a588474bf0ea7fa76fd0404469546092138cf771 Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Thu, 18 Jan 2024 22:03:19 +0100 Subject: [PATCH 16/24] Bump version to 0.11.1 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fd91ba7..0e7e15d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tokio-postgres-rustls" description = "Rustls integration for tokio-postgres" -version = "0.11.0" +version = "0.11.1" authors = ["Jasper Hugo "] repository = "https://github.com/jbg/tokio-postgres-rustls" edition = "2018" @@ -15,7 +15,7 @@ rustls = { version = "0.22.1", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } tokio-rustls = { version = "0.25", default-features = false } -x509-certificate = {version = "0.23.0", default-features = false } +x509-certificate = {version = "0.23", default-features = false } [dev-dependencies] env_logger = { version = "0.10", default-features = false } From 6f1b88f88edf743a1dd821951bcc3d804efc7b62 Mon Sep 17 00:00:00 2001 From: aumetra Date: Sat, 2 Mar 2024 14:32:26 +0100 Subject: [PATCH 17/24] Bump to rustls v0.23 --- Cargo.toml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 64a5b7f..9aa0a45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,14 +10,17 @@ readme = "README.md" [dependencies] ring = { version = "0.17", default-features = false } -rustls = { version = "0.22.1", default-features = false } +rustls = { version = "0.23.1", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } tokio-rustls = { version = "0.25", default-features = false } x509-certificate = {version = "0.23", default-features = false } [dev-dependencies] -env_logger = { version = "0.10", default-features = false } +env_logger = { version = "0.11", default-features = false } tokio = { version = "1", features = ["macros", "rt"] } tokio-postgres = "0.7" -rustls = { version = "0.22" } +rustls = { version = "0.23" } + +[patch.crates-io] +tokio-rustls = { git = "https://github.com/rustls/tokio-rustls", rev = "b3a2b143239d66253ba09f8ac4bfc4b7ab00cfac" } From b3b59ac2fa1b5823f2426fef78a0fb74c004ec38 Mon Sep 17 00:00:00 2001 From: Aumetra Weisman Date: Fri, 22 Mar 2024 14:59:36 +0100 Subject: [PATCH 18/24] Bump to released `tokio-rustls` version --- Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9aa0a45..83d854a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ ring = { version = "0.17", default-features = false } rustls = { version = "0.23.1", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } -tokio-rustls = { version = "0.25", default-features = false } +tokio-rustls = { version = "0.26", default-features = false } x509-certificate = {version = "0.23", default-features = false } [dev-dependencies] @@ -21,6 +21,3 @@ env_logger = { version = "0.11", default-features = false } tokio = { version = "1", features = ["macros", "rt"] } tokio-postgres = "0.7" rustls = { version = "0.23" } - -[patch.crates-io] -tokio-rustls = { git = "https://github.com/rustls/tokio-rustls", rev = "b3a2b143239d66253ba09f8ac4bfc4b7ab00cfac" } From 0a3308ec1839d1c0a1edb15a62ce6134f244a09c Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Wed, 3 Apr 2024 00:18:52 +0200 Subject: [PATCH 19/24] use ring for rustls in dev-dependencies too, disable default-features --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 83d854a..f08bd87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" [dependencies] ring = { version = "0.17", default-features = false } -rustls = { version = "0.23.1", default-features = false } +rustls = { version = "0.23", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } tokio-rustls = { version = "0.26", default-features = false } @@ -18,6 +18,6 @@ x509-certificate = {version = "0.23", default-features = false } [dev-dependencies] env_logger = { version = "0.11", default-features = false } -tokio = { version = "1", features = ["macros", "rt"] } -tokio-postgres = "0.7" -rustls = { version = "0.23" } +tokio = { version = "1", default-features = false, features = ["macros", "rt"] } +tokio-postgres = { version = "0.7", default-features = false, features = ["runtime"] } +rustls = { version = "0.23", default-features = false, features = ["std", "logging", "tls12", "ring"] } From 21f4d0eaae8b4d4be335ec0767e7891f38bd0cc9 Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Wed, 3 Apr 2024 00:19:18 +0200 Subject: [PATCH 20/24] Release 0.12.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f08bd87..93cc952 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tokio-postgres-rustls" description = "Rustls integration for tokio-postgres" -version = "0.11.1" +version = "0.12.0" authors = ["Jasper Hugo "] repository = "https://github.com/jbg/tokio-postgres-rustls" edition = "2018" From 6148818b92849676a75092764115823a7dc41064 Mon Sep 17 00:00:00 2001 From: Aumetra Weisman Date: Mon, 14 Oct 2024 16:39:20 +0200 Subject: [PATCH 21/24] Migrate to `x509-cert` --- Cargo.toml | 14 +++++++++++--- src/lib.rs | 44 ++++++++++++++++++++++++++------------------ 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 93cc952..4b0d36a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,15 +9,23 @@ license = "MIT" readme = "README.md" [dependencies] +const-oid = { version = "0.9.6", default-features = false, features = ["db"] } ring = { version = "0.17", default-features = false } rustls = { version = "0.23", default-features = false } tokio = { version = "1", default-features = false } tokio-postgres = { version = "0.7", default-features = false } tokio-rustls = { version = "0.26", default-features = false } -x509-certificate = {version = "0.23", default-features = false } +x509-cert = { version = "0.2.5", default-features = false, features = ["std"] } [dev-dependencies] env_logger = { version = "0.11", default-features = false } tokio = { version = "1", default-features = false, features = ["macros", "rt"] } -tokio-postgres = { version = "0.7", default-features = false, features = ["runtime"] } -rustls = { version = "0.23", default-features = false, features = ["std", "logging", "tls12", "ring"] } +tokio-postgres = { version = "0.7", default-features = false, features = [ + "runtime", +] } +rustls = { version = "0.23", default-features = false, features = [ + "std", + "logging", + "tls12", + "ring", +] } diff --git a/src/lib.rs b/src/lib.rs index 5fd02ce..17fea41 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,18 +6,22 @@ use std::{ sync::Arc, task::{Context, Poll}, }; -use DigestAlgorithm::{Sha1, Sha256, Sha384, Sha512}; +use const_oid::db::{ + rfc5912::{ + ECDSA_WITH_SHA_256, ECDSA_WITH_SHA_384, ID_SHA_1, ID_SHA_256, ID_SHA_384, ID_SHA_512, + SHA_1_WITH_RSA_ENCRYPTION, SHA_256_WITH_RSA_ENCRYPTION, SHA_384_WITH_RSA_ENCRYPTION, + SHA_512_WITH_RSA_ENCRYPTION, + }, + rfc8410::ID_ED_25519, +}; use ring::digest; use rustls::pki_types::ServerName; use rustls::ClientConfig; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_postgres::tls::{ChannelBinding, MakeTlsConnect, TlsConnect}; use tokio_rustls::{client::TlsStream, TlsConnector}; -use x509_certificate::{DigestAlgorithm, SignatureAlgorithm, X509Certificate}; -use SignatureAlgorithm::{ - EcdsaSha256, EcdsaSha384, Ed25519, NoSignature, RsaSha1, RsaSha256, RsaSha384, RsaSha512, -}; +use x509_cert::{der::Decode, TbsCertificate}; #[derive(Clone)] pub struct MakeRustlsConnect { @@ -85,20 +89,24 @@ where fn channel_binding(&self) -> ChannelBinding { let (_, session) = self.0.get_ref(); match session.peer_certificates() { - Some(certs) if !certs.is_empty() => X509Certificate::from_der(&certs[0]) + Some(certs) if !certs.is_empty() => TbsCertificate::from_der(&certs[0]) .ok() - .and_then(|cert| cert.signature_algorithm()) - .map(|algorithm| match algorithm { - // Note: SHA1 is upgraded to SHA256 as per https://datatracker.ietf.org/doc/html/rfc5929#section-4.1 - RsaSha1 | RsaSha256 | EcdsaSha256 => &digest::SHA256, - RsaSha384 | EcdsaSha384 => &digest::SHA384, - RsaSha512 => &digest::SHA512, - Ed25519 => &digest::SHA512, - NoSignature(algo) => match algo { - Sha1 | Sha256 => &digest::SHA256, - Sha384 => &digest::SHA384, - Sha512 => &digest::SHA512, - }, + .and_then(|cert| { + let digest = match cert.signature.oid { + // Note: SHA1 is upgraded to SHA256 as per https://datatracker.ietf.org/doc/html/rfc5929#section-4.1 + ID_SHA_1 + | ID_SHA_256 + | SHA_1_WITH_RSA_ENCRYPTION + | SHA_256_WITH_RSA_ENCRYPTION + | ECDSA_WITH_SHA_256 => &digest::SHA256, + ID_SHA_384 | SHA_384_WITH_RSA_ENCRYPTION | ECDSA_WITH_SHA_384 => { + &digest::SHA384 + } + ID_SHA_512 | SHA_512_WITH_RSA_ENCRYPTION | ID_ED_25519 => &digest::SHA512, + _ => return None, + }; + + Some(digest) }) .map(|algorithm| { let hash = digest::digest(algorithm, certs[0].as_ref()); From 0a99a3cb4dd1ac6696a5a0601f645b6a6214a7da Mon Sep 17 00:00:00 2001 From: Aumetra Weisman Date: Mon, 14 Oct 2024 16:50:29 +0200 Subject: [PATCH 22/24] Remove allocations --- src/lib.rs | 58 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5fd02ce..ef6a190 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,27 @@ use SignatureAlgorithm::{ EcdsaSha256, EcdsaSha384, Ed25519, NoSignature, RsaSha1, RsaSha256, RsaSha384, RsaSha512, }; +mod private { + use super::*; + + pub struct TlsConnectFuture { + pub inner: tokio_rustls::Connect, + } + + impl Future for TlsConnectFuture + where + S: AsyncRead + AsyncWrite + Unpin, + { + type Output = io::Result>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + // SAFETY: If `self` is pinned, so is `inner`. + let fut = unsafe { self.map_unchecked_mut(|this| &mut this.inner) }; + fut.poll(cx).map_ok(RustlsStream) + } + } +} + #[derive(Clone)] pub struct MakeRustlsConnect { config: Arc, @@ -63,20 +84,23 @@ where { type Stream = RustlsStream; type Error = io::Error; - type Future = Pin>> + Send>>; + type Future = private::TlsConnectFuture; fn connect(self, stream: S) -> Self::Future { - Box::pin(async move { - self.0 - .connector - .connect(self.0.hostname, stream) - .await - .map(|s| RustlsStream(Box::pin(s))) - }) + private::TlsConnectFuture { + inner: self.0.connector.connect(self.0.hostname, stream), + } } } -pub struct RustlsStream(Pin>>); +pub struct RustlsStream(TlsStream); + +impl RustlsStream { + pub fn project_stream(self: Pin<&mut Self>) -> Pin<&mut TlsStream> { + // SAFETY: When `Self` is pinned, so is the inner `TlsStream`. + unsafe { self.map_unchecked_mut(|this| &mut this.0) } + } +} impl tokio_postgres::tls::TlsStream for RustlsStream where @@ -115,11 +139,11 @@ where S: AsyncRead + AsyncWrite + Unpin, { fn poll_read( - mut self: Pin<&mut Self>, + self: Pin<&mut Self>, cx: &mut Context, buf: &mut ReadBuf<'_>, ) -> Poll> { - self.0.as_mut().poll_read(cx, buf) + self.project_stream().poll_read(cx, buf) } } @@ -128,19 +152,19 @@ where S: AsyncRead + AsyncWrite + Unpin, { fn poll_write( - mut self: Pin<&mut Self>, + self: Pin<&mut Self>, cx: &mut Context, buf: &[u8], ) -> Poll> { - self.0.as_mut().poll_write(cx, buf) + self.project_stream().poll_write(cx, buf) } - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - self.0.as_mut().poll_flush(cx) + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { + self.project_stream().poll_flush(cx) } - fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - self.0.as_mut().poll_shutdown(cx) + fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { + self.project_stream().poll_shutdown(cx) } } From d29076ca1a1a7b00ebd9144709dd5d084e5f8d53 Mon Sep 17 00:00:00 2001 From: Aumetra Weisman Date: Wed, 16 Oct 2024 11:59:35 +0200 Subject: [PATCH 23/24] Minimize API and add some documentation --- .clippy.toml | 1 + src/lib.rs | 281 +++++++++++++++++++++++++++------------------------ 2 files changed, 151 insertions(+), 131 deletions(-) create mode 100644 .clippy.toml diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 0000000..f357307 --- /dev/null +++ b/.clippy.toml @@ -0,0 +1 @@ +doc-valid-idents = ["PostgreSQL"] diff --git a/src/lib.rs b/src/lib.rs index 0959781..eccd1ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,30 +1,36 @@ -use std::{ - convert::TryFrom, - future::Future, - io, - pin::Pin, - sync::Arc, - task::{Context, Poll}, -}; - -use const_oid::db::{ - rfc5912::{ - ECDSA_WITH_SHA_256, ECDSA_WITH_SHA_384, ID_SHA_1, ID_SHA_256, ID_SHA_384, ID_SHA_512, - SHA_1_WITH_RSA_ENCRYPTION, SHA_256_WITH_RSA_ENCRYPTION, SHA_384_WITH_RSA_ENCRYPTION, - SHA_512_WITH_RSA_ENCRYPTION, - }, - rfc8410::ID_ED_25519, -}; -use ring::digest; -use rustls::pki_types::ServerName; -use rustls::ClientConfig; -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; -use tokio_postgres::tls::{ChannelBinding, MakeTlsConnect, TlsConnect}; -use tokio_rustls::{client::TlsStream, TlsConnector}; -use x509_cert::{der::Decode, TbsCertificate}; +#![doc = include_str!("../README.md")] +#![forbid(rust_2018_idioms)] +#![deny(missing_docs, unsafe_code)] +#![warn(clippy::all, clippy::pedantic)] + +use std::{convert::TryFrom, sync::Arc}; + +use rustls::{pki_types::ServerName, ClientConfig}; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio_postgres::tls::MakeTlsConnect; mod private { - use super::*; + use std::{ + future::Future, + io, + pin::Pin, + task::{Context, Poll}, + }; + + use const_oid::db::{ + rfc5912::{ + ECDSA_WITH_SHA_256, ECDSA_WITH_SHA_384, ID_SHA_1, ID_SHA_256, ID_SHA_384, ID_SHA_512, + SHA_1_WITH_RSA_ENCRYPTION, SHA_256_WITH_RSA_ENCRYPTION, SHA_384_WITH_RSA_ENCRYPTION, + SHA_512_WITH_RSA_ENCRYPTION, + }, + rfc8410::ID_ED_25519, + }; + use ring::digest; + use rustls::pki_types::ServerName; + use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; + use tokio_postgres::tls::{ChannelBinding, TlsConnect}; + use tokio_rustls::{client::TlsStream, TlsConnector}; + use x509_cert::{der::Decode, TbsCertificate}; pub struct TlsConnectFuture { pub inner: tokio_rustls::Connect, @@ -36,20 +42,134 @@ mod private { { type Output = io::Result>; - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // SAFETY: If `self` is pinned, so is `inner`. + #[allow(unsafe_code)] let fut = unsafe { self.map_unchecked_mut(|this| &mut this.inner) }; fut.poll(cx).map_ok(RustlsStream) } } + + pub struct RustlsConnect(pub RustlsConnectData); + + pub struct RustlsConnectData { + pub hostname: ServerName<'static>, + pub connector: TlsConnector, + } + + impl TlsConnect for RustlsConnect + where + S: AsyncRead + AsyncWrite + Unpin + Send + 'static, + { + type Stream = RustlsStream; + type Error = io::Error; + type Future = TlsConnectFuture; + + fn connect(self, stream: S) -> Self::Future { + TlsConnectFuture { + inner: self.0.connector.connect(self.0.hostname, stream), + } + } + } + + pub struct RustlsStream(TlsStream); + + impl RustlsStream { + pub fn project_stream(self: Pin<&mut Self>) -> Pin<&mut TlsStream> { + // SAFETY: When `Self` is pinned, so is the inner `TlsStream`. + #[allow(unsafe_code)] + unsafe { + self.map_unchecked_mut(|this| &mut this.0) + } + } + } + + impl tokio_postgres::tls::TlsStream for RustlsStream + where + S: AsyncRead + AsyncWrite + Unpin, + { + fn channel_binding(&self) -> ChannelBinding { + let (_, session) = self.0.get_ref(); + match session.peer_certificates() { + Some(certs) if !certs.is_empty() => TbsCertificate::from_der(&certs[0]) + .ok() + .and_then(|cert| { + let digest = match cert.signature.oid { + // Note: SHA1 is upgraded to SHA256 as per https://datatracker.ietf.org/doc/html/rfc5929#section-4.1 + ID_SHA_1 + | ID_SHA_256 + | SHA_1_WITH_RSA_ENCRYPTION + | SHA_256_WITH_RSA_ENCRYPTION + | ECDSA_WITH_SHA_256 => &digest::SHA256, + ID_SHA_384 | SHA_384_WITH_RSA_ENCRYPTION | ECDSA_WITH_SHA_384 => { + &digest::SHA384 + } + ID_SHA_512 | SHA_512_WITH_RSA_ENCRYPTION | ID_ED_25519 => { + &digest::SHA512 + } + _ => return None, + }; + + Some(digest) + }) + .map_or_else(ChannelBinding::none, |algorithm| { + let hash = digest::digest(algorithm, certs[0].as_ref()); + ChannelBinding::tls_server_end_point(hash.as_ref().into()) + }), + _ => ChannelBinding::none(), + } + } + } + + impl AsyncRead for RustlsStream + where + S: AsyncRead + AsyncWrite + Unpin, + { + fn poll_read( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + self.project_stream().poll_read(cx, buf) + } + } + + impl AsyncWrite for RustlsStream + where + S: AsyncRead + AsyncWrite + Unpin, + { + fn poll_write( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + self.project_stream().poll_write(cx, buf) + } + + fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + self.project_stream().poll_flush(cx) + } + + fn poll_shutdown( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + self.project_stream().poll_shutdown(cx) + } + } } +/// A `MakeTlsConnect` implementation using `rustls`. +/// +/// That way you can connect to PostgreSQL using `rustls` as the TLS stack. #[derive(Clone)] pub struct MakeRustlsConnect { config: Arc, } impl MakeRustlsConnect { + /// Creates a new `MakeRustlsConnect` from the provided `ClientConfig`. + #[must_use] pub fn new(config: ClientConfig) -> Self { Self { config: Arc::new(config), @@ -61,13 +181,13 @@ impl MakeTlsConnect for MakeRustlsConnect where S: AsyncRead + AsyncWrite + Unpin + Send + 'static, { - type Stream = RustlsStream; - type TlsConnect = RustlsConnect; + type Stream = private::RustlsStream; + type TlsConnect = private::RustlsConnect; type Error = rustls::pki_types::InvalidDnsNameError; - fn make_tls_connect(&mut self, hostname: &str) -> Result { + fn make_tls_connect(&mut self, hostname: &str) -> Result { ServerName::try_from(hostname).map(|dns_name| { - RustlsConnect(RustlsConnectData { + private::RustlsConnect(private::RustlsConnectData { hostname: dns_name.to_owned(), connector: Arc::clone(&self.config).into(), }) @@ -75,107 +195,6 @@ where } } -pub struct RustlsConnect(RustlsConnectData); - -struct RustlsConnectData { - hostname: ServerName<'static>, - connector: TlsConnector, -} - -impl TlsConnect for RustlsConnect -where - S: AsyncRead + AsyncWrite + Unpin + Send + 'static, -{ - type Stream = RustlsStream; - type Error = io::Error; - type Future = private::TlsConnectFuture; - - fn connect(self, stream: S) -> Self::Future { - private::TlsConnectFuture { - inner: self.0.connector.connect(self.0.hostname, stream), - } - } -} - -pub struct RustlsStream(TlsStream); - -impl RustlsStream { - pub fn project_stream(self: Pin<&mut Self>) -> Pin<&mut TlsStream> { - // SAFETY: When `Self` is pinned, so is the inner `TlsStream`. - unsafe { self.map_unchecked_mut(|this| &mut this.0) } - } -} - -impl tokio_postgres::tls::TlsStream for RustlsStream -where - S: AsyncRead + AsyncWrite + Unpin, -{ - fn channel_binding(&self) -> ChannelBinding { - let (_, session) = self.0.get_ref(); - match session.peer_certificates() { - Some(certs) if !certs.is_empty() => TbsCertificate::from_der(&certs[0]) - .ok() - .and_then(|cert| { - let digest = match cert.signature.oid { - // Note: SHA1 is upgraded to SHA256 as per https://datatracker.ietf.org/doc/html/rfc5929#section-4.1 - ID_SHA_1 - | ID_SHA_256 - | SHA_1_WITH_RSA_ENCRYPTION - | SHA_256_WITH_RSA_ENCRYPTION - | ECDSA_WITH_SHA_256 => &digest::SHA256, - ID_SHA_384 | SHA_384_WITH_RSA_ENCRYPTION | ECDSA_WITH_SHA_384 => { - &digest::SHA384 - } - ID_SHA_512 | SHA_512_WITH_RSA_ENCRYPTION | ID_ED_25519 => &digest::SHA512, - _ => return None, - }; - - Some(digest) - }) - .map(|algorithm| { - let hash = digest::digest(algorithm, certs[0].as_ref()); - ChannelBinding::tls_server_end_point(hash.as_ref().into()) - }) - .unwrap_or(ChannelBinding::none()), - _ => ChannelBinding::none(), - } - } -} - -impl AsyncRead for RustlsStream -where - S: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_read( - self: Pin<&mut Self>, - cx: &mut Context, - buf: &mut ReadBuf<'_>, - ) -> Poll> { - self.project_stream().poll_read(cx, buf) - } -} - -impl AsyncWrite for RustlsStream -where - S: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_write( - self: Pin<&mut Self>, - cx: &mut Context, - buf: &[u8], - ) -> Poll> { - self.project_stream().poll_write(cx, buf) - } - - fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - self.project_stream().poll_flush(cx) - } - - fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { - self.project_stream().poll_shutdown(cx) - } -} - #[cfg(test)] mod tests { use super::*; From dcf96d899863a50957b47534c90ac72a2b37b87e Mon Sep 17 00:00:00 2001 From: Jasper Hugo Date: Sun, 20 Oct 2024 00:19:43 +0200 Subject: [PATCH 24/24] Release 0.13.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4b0d36a..8b83023 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tokio-postgres-rustls" description = "Rustls integration for tokio-postgres" -version = "0.12.0" +version = "0.13.0" authors = ["Jasper Hugo "] repository = "https://github.com/jbg/tokio-postgres-rustls" edition = "2018"