Support accept_invalid_certs & accept_invalid_hostnames with rustls

Co-authored-by: BlackHoleFox <blackholefoxdev@gmail.com>
This commit is contained in:
Jonas Platte 2020-10-22 19:06:46 +02:00 committed by Ryan Leckey
parent a68872a35a
commit 1ed75ba5f0
4 changed files with 100 additions and 27 deletions

10
Cargo.lock generated
View file

@ -2249,6 +2249,7 @@ dependencies = [
"url",
"uuid",
"webpki",
"webpki-roots",
"whoami",
]
@ -2927,6 +2928,15 @@ dependencies = [
"untrusted",
]
[[package]]
name = "webpki-roots"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f20dea7535251981a9670857150d571846545088359b28e4951d350bdaf179f"
dependencies = [
"webpki",
]
[[package]]
name = "wepoll-sys"
version = "3.0.1"

View file

@ -47,7 +47,7 @@ _rt-actix = []
_rt-async-std = []
_rt-tokio = []
_tls-native-tls = []
_tls-rustls = [ "rustls", "webpki" ]
_tls-rustls = [ "rustls", "webpki", "webpki-roots" ]
# support offline/decoupled building (enables serialization of `Describe`)
offline = [ "serde", "either/serde" ]
@ -91,7 +91,7 @@ parking_lot = "0.11.0"
rand = { version = "0.7.3", default-features = false, optional = true, features = [ "std" ] }
regex = { version = "1.3.9", optional = true }
rsa = { version = "0.3.0", optional = true }
rustls = { version = "0.18.1", optional = true }
rustls = { version = "0.18.1", features = [ "dangerous_configuration" ], optional = true }
serde = { version = "1.0.106", features = [ "derive", "rc" ], optional = true }
serde_json = { version = "1.0.51", features = [ "raw_value" ], optional = true }
sha-1 = { version = "0.9.0", default-features = false, optional = true }
@ -103,6 +103,7 @@ smallvec = "1.4.0"
url = { version = "2.1.1", default-features = false }
uuid = { version = "0.8.1", default-features = false, optional = true, features = [ "std" ] }
webpki = { version = "0.21.3", optional = true }
webpki-roots = { version = "0.20.0", optional = true }
whoami = "0.9.0"
stringprep = "0.1.2"
lru-cache = "0.1.2"

View file

@ -6,11 +6,14 @@ use std::path::Path;
use std::pin::Pin;
use std::task::{Context, Poll};
use sqlx_rt::{fs, AsyncRead, AsyncWrite, TlsStream};
use sqlx_rt::{AsyncRead, AsyncWrite, TlsStream};
use crate::error::Error;
use std::mem::replace;
#[cfg(feature = "_tls-rustls")]
mod rustls;
pub enum MaybeTlsStream<S>
where
S: AsyncRead + AsyncWrite + Unpin,
@ -73,7 +76,10 @@ async fn configure_tls_connector(
accept_invalid_hostnames: bool,
root_cert_path: Option<&Path>,
) -> Result<sqlx_rt::TlsConnector, Error> {
use sqlx_rt::native_tls::{Certificate, TlsConnector};
use sqlx_rt::{
fs,
native_tls::{Certificate, TlsConnector},
};
let mut builder = TlsConnector::builder();
builder
@ -99,29 +105,7 @@ async fn configure_tls_connector(
}
#[cfg(feature = "_tls-rustls")]
async fn configure_tls_connector(
_accept_invalid_certs: bool,
_accept_invalid_hostnames: bool,
root_cert_path: Option<&Path>,
) -> Result<sqlx_rt::TlsConnector, Error> {
// FIXME: Support accept_invalid_certs / accept_invalid_hostnames
use rustls::ClientConfig;
use std::io::Cursor;
use std::sync::Arc;
let mut config = ClientConfig::new();
if let Some(ca) = root_cert_path {
let data = fs::read(ca).await?;
let mut cursor = Cursor::new(data);
config.root_store.add_pem_file(&mut cursor).map_err(|_| {
Error::Tls(format!("Invalid certificate file: {}", ca.display()).into())
})?;
}
Ok(Arc::new(config).into())
}
use self::rustls::configure_tls_connector;
impl<S> AsyncRead for MaybeTlsStream<S>
where

View file

@ -0,0 +1,78 @@
use rustls::{
Certificate, ClientConfig, RootCertStore, ServerCertVerified, ServerCertVerifier, TLSError,
WebPKIVerifier,
};
use sqlx_rt::fs;
use std::sync::Arc;
use std::{io::Cursor, path::Path};
use webpki::DNSNameRef;
use crate::error::Error;
pub async fn configure_tls_connector(
accept_invalid_certs: bool,
accept_invalid_hostnames: bool,
root_cert_path: Option<&Path>,
) -> Result<sqlx_rt::TlsConnector, Error> {
let mut config = ClientConfig::new();
if accept_invalid_certs {
config
.dangerous()
.set_certificate_verifier(Arc::new(DummyTlsVerifier));
} else {
config
.root_store
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
if let Some(ca) = root_cert_path {
let data = fs::read(ca).await?;
let mut cursor = Cursor::new(data);
config.root_store.add_pem_file(&mut cursor).map_err(|_| {
Error::Tls(format!("Invalid certificate file: {}", ca.display()).into())
})?;
}
if accept_invalid_hostnames {
config
.dangerous()
.set_certificate_verifier(Arc::new(NoHostnameTlsVerifier));
}
}
Ok(Arc::new(config).into())
}
struct DummyTlsVerifier;
impl ServerCertVerifier for DummyTlsVerifier {
fn verify_server_cert(
&self,
_roots: &RootCertStore,
_presented_certs: &[Certificate],
_dns_name: DNSNameRef<'_>,
_ocsp_response: &[u8],
) -> Result<ServerCertVerified, TLSError> {
Ok(ServerCertVerified::assertion())
}
}
pub struct NoHostnameTlsVerifier;
impl ServerCertVerifier for NoHostnameTlsVerifier {
fn verify_server_cert(
&self,
roots: &RootCertStore,
presented_certs: &[Certificate],
dns_name: DNSNameRef<'_>,
ocsp_response: &[u8],
) -> Result<ServerCertVerified, TLSError> {
let verifier = WebPKIVerifier::new();
match verifier.verify_server_cert(roots, presented_certs, dns_name, ocsp_response) {
Err(TLSError::WebPKIError(webpki::Error::CertNotValidForName)) => {
Ok(ServerCertVerified::assertion())
}
res => res,
}
}
}