Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge whole history of tokio-postgres-rustls as a crate #962

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1bd0f00
Initial implementation
jbg Jul 12, 2019
06c58e1
added description and license to Cargo.toml
jbg Jul 12, 2019
514ac75
added README
jbg Jul 12, 2019
051d5b8
added example to README
jbg Jul 12, 2019
b9531bb
fixed typo
jbg Jul 12, 2019
c9f53c0
added Send bound on the underlying stream, added test
jbg Jul 12, 2019
567bec7
updated README
jbg Jul 12, 2019
567ffa5
Added license file
jbg Jul 12, 2019
55449c7
Updated to support tokio 0.2 and latest versions of all other deps
jbg Dec 26, 2019
3bba705
removed impl_trait_type_alias, implemented ChannelBinding
jbg Dec 26, 2019
2b2965e
rustfmt, logging in tests to see rustls errors
jbg Dec 26, 2019
5c90d16
added repository key to Cargo.toml
jbg Dec 26, 2019
34dfbd4
made MakeRustlsConnect Clone
jbg Dec 30, 2019
7f7e379
Updated deps
jbg Apr 9, 2020
13fd950
indicate that future of TlsConnect is Send
dvic Jan 24, 2020
9b7241e
0.4.1
jbg Apr 9, 2020
6a7a5d6
Upgrade rustls to 0.18
djc Jul 6, 2020
73eb495
update to new tokio
godofdream Dec 1, 2020
84e6860
update deps && tokio 0.3
godofdream Dec 1, 2020
ba8c5ac
Update to tokio 1
tl-alex-butler2 Jan 14, 2021
a841a3e
bumped version to 0.7.0
jbg Jan 22, 2021
f910c04
Add support for UDS connections
mahkoh Dec 9, 2020
debd547
0.8.0
jbg Feb 10, 2021
4139951
updated dependencies rustls and tokio-rustls
UjOwtuc Oct 31, 2021
32b245a
unit test only: trust any certificate
UjOwtuc Oct 31, 2021
76334a6
Update minor version due to breaking API change
UjOwtuc Nov 16, 2021
4c9f505
Moved all code to /postgres-rustls dir
nyurik Nov 1, 2022
80668d1
Merge remote-tracking branch 'postgres-rustls/master' into rustls
nyurik Nov 1, 2022
dad5bca
bump rustls dep, include new member
nyurik Nov 1, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"postgres-native-tls",
"postgres-openssl",
"postgres-protocol",
"postgres-rustls",
"postgres-types",
"tokio-postgres",
]
Expand Down
3 changes: 3 additions & 0 deletions postgres-rustls/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock
22 changes: 22 additions & 0 deletions postgres-rustls/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "tokio-postgres-rustls"
description = "Rustls integration for tokio-postgres"
version = "0.9.0"
authors = ["Jasper Hugo <[email protected]>"]
repository = "https://github.com/jbg/tokio-postgres-rustls"
edition = "2018"
license = "MIT"
readme = "README.md"

[dependencies]
futures = "0.3"
ring = "0.16"
rustls = "0.20"
tokio = "1"
tokio-postgres = "0.7"
tokio-rustls = "0.23"

[dev-dependencies]
env_logger = { version = "0.9", default-features = false }
tokio = { version = "1", features = ["macros", "rt"] }
rustls = { version = "0.20", features = ["dangerous_configuration"] }
21 changes: 21 additions & 0 deletions postgres-rustls/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 Jasper Hugo

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
22 changes: 22 additions & 0 deletions postgres-rustls/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# tokio-postgres-rustls
This is an integration between the [rustls TLS stack](https://github.com/ctz/rustls)
and the [tokio-postgres asynchronous PostgreSQL client library](https://github.com/sfackler/rust-postgres).

[![Crate](https://img.shields.io/crates/v/tokio-postgres-rustls.svg)](https://crates.io/crates/tokio-postgres-rustls)

[API Documentation](https://docs.rs/tokio-postgres-rustls/)

# Example

```
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);
let connect_fut = tokio_postgres::connect("sslmode=require host=localhost user=postgres", tls);
// ...
```

# License
tokio-postgres-rustls is distributed under the MIT license.
173 changes: 173 additions & 0 deletions postgres-rustls/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
use std::{
convert::TryFrom,
future::Future,
io,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};

use futures::future::{FutureExt, TryFutureExt};
use ring::digest;
use rustls::{ClientConfig, ServerName};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tokio_postgres::tls::{ChannelBinding, MakeTlsConnect, TlsConnect};
use tokio_rustls::{client::TlsStream, TlsConnector};

#[derive(Clone)]
pub struct MakeRustlsConnect {
config: Arc<ClientConfig>,
}

impl MakeRustlsConnect {
pub fn new(config: ClientConfig) -> Self {
Self {
config: Arc::new(config),
}
}
}

impl<S> MakeTlsConnect<S> for MakeRustlsConnect
where
S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
type Stream = RustlsStream<S>;
type TlsConnect = RustlsConnect;
type Error = io::Error;

fn make_tls_connect(&mut self, hostname: &str) -> io::Result<RustlsConnect> {
ServerName::try_from(hostname)
.map(|dns_name| {
RustlsConnect(Some(RustlsConnectData {
hostname: dns_name,
connector: Arc::clone(&self.config).into(),
}))
})
.or(Ok(RustlsConnect(None)))
}
}

pub struct RustlsConnect(Option<RustlsConnectData>);

struct RustlsConnectData {
hostname: ServerName,
connector: TlsConnector,
}

impl<S> TlsConnect<S> for RustlsConnect
where
S: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
type Stream = RustlsStream<S>;
type Error = io::Error;
type Future = Pin<Box<dyn Future<Output = io::Result<RustlsStream<S>>> + 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(),
}
}
}

pub struct RustlsStream<S>(Pin<Box<TlsStream<S>>>);

impl<S> tokio_postgres::tls::TlsStream for RustlsStream<S>
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() => {
let sha256 = digest::digest(&digest::SHA256, certs[0].as_ref());
ChannelBinding::tls_server_end_point(sha256.as_ref().into())
}
_ => ChannelBinding::none(),
}
}
}

impl<S> AsyncRead for RustlsStream<S>
where
S: AsyncRead + AsyncWrite + Unpin,
{
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context,
buf: &mut ReadBuf<'_>,
) -> Poll<tokio::io::Result<()>> {
self.0.as_mut().poll_read(cx, buf)
}
}

impl<S> AsyncWrite for RustlsStream<S>
where
S: AsyncRead + AsyncWrite + Unpin,
{
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context,
buf: &[u8],
) -> Poll<tokio::io::Result<usize>> {
self.0.as_mut().poll_write(cx, buf)
}

fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<tokio::io::Result<()>> {
self.0.as_mut().poll_flush(cx)
}

fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<tokio::io::Result<()>> {
self.0.as_mut().poll_shutdown(cx)
}
}

#[cfg(test)]
mod tests {
use super::*;
use futures::future::TryFutureExt;
use rustls::{client::ServerCertVerified, client::ServerCertVerifier, Certificate, Error};
use std::time::SystemTime;

struct AcceptAllVerifier {}
impl ServerCertVerifier for AcceptAllVerifier {
fn verify_server_cert(
&self,
_end_entity: &Certificate,
_intermediates: &[Certificate],
_server_name: &ServerName,
_scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp_response: &[u8],
_now: SystemTime,
) -> Result<ServerCertVerified, Error> {
Ok(ServerCertVerified::assertion())
}
}

#[tokio::test]
async fn it_works() {
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
.dangerous()
.set_certificate_verifier(Arc::new(AcceptAllVerifier {}));
let tls = super::MakeRustlsConnect::new(config);
let (client, conn) = tokio_postgres::connect(
"sslmode=require host=localhost port=5432 user=postgres",
tls,
)
.await
.expect("connect");
tokio::spawn(conn.map_err(|e| panic!("{:?}", e)));
let stmt = client.prepare("SELECT 1").await.expect("prepare");
let _ = client.query(&stmt, &[]).await.expect("query");
}
}