Skip to content

Commit eb0bb6e

Browse files
jplatteBlackHoleFox
andcommitted
Support accept_invalid_certs & accept_invalid_hostnames with rustls
Co-authored-by: BlackHoleFox <[email protected]>
1 parent 5058091 commit eb0bb6e

File tree

4 files changed

+100
-27
lines changed

4 files changed

+100
-27
lines changed

Cargo.lock

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sqlx-core/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ _rt-actix = []
4747
_rt-async-std = []
4848
_rt-tokio = []
4949
_tls-native-tls = []
50-
_tls-rustls = [ "rustls", "webpki" ]
50+
_tls-rustls = [ "rustls", "webpki", "webpki-roots" ]
5151

5252
# support offline/decoupled building (enables serialization of `Describe`)
5353
offline = [ "serde", "either/serde" ]
@@ -91,7 +91,7 @@ parking_lot = "0.11.0"
9191
rand = { version = "0.7.3", default-features = false, optional = true, features = [ "std" ] }
9292
regex = { version = "1.3.9", optional = true }
9393
rsa = { version = "0.3.0", optional = true }
94-
rustls = { version = "0.18.1", optional = true }
94+
rustls = { version = "0.18.1", features = [ "dangerous_configuration" ], optional = true }
9595
serde = { version = "1.0.106", features = [ "derive", "rc" ], optional = true }
9696
serde_json = { version = "1.0.51", features = [ "raw_value" ], optional = true }
9797
sha-1 = { version = "0.9.0", default-features = false, optional = true }
@@ -103,6 +103,7 @@ smallvec = "1.4.0"
103103
url = { version = "2.1.1", default-features = false }
104104
uuid = { version = "0.8.1", default-features = false, optional = true, features = [ "std" ] }
105105
webpki = { version = "0.21.3", optional = true }
106+
webpki-roots = { version = "0.20.0", optional = true }
106107
whoami = "0.9.0"
107108
stringprep = "0.1.2"
108109
lru-cache = "0.1.2"

sqlx-core/src/net/tls.rs sqlx-core/src/net/tls/mod.rs

+9-25
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ use std::path::Path;
66
use std::pin::Pin;
77
use std::task::{Context, Poll};
88

9-
use sqlx_rt::{fs, AsyncRead, AsyncWrite, TlsStream};
9+
use sqlx_rt::{AsyncRead, AsyncWrite, TlsStream};
1010

1111
use crate::error::Error;
1212
use std::mem::replace;
1313

14+
#[cfg(feature = "_tls-rustls")]
15+
mod rustls;
16+
1417
pub enum MaybeTlsStream<S>
1518
where
1619
S: AsyncRead + AsyncWrite + Unpin,
@@ -73,7 +76,10 @@ async fn configure_tls_connector(
7376
accept_invalid_hostnames: bool,
7477
root_cert_path: Option<&Path>,
7578
) -> Result<sqlx_rt::TlsConnector, Error> {
76-
use sqlx_rt::native_tls::{Certificate, TlsConnector};
79+
use sqlx_rt::{
80+
fs,
81+
native_tls::{Certificate, TlsConnector},
82+
};
7783

7884
let mut builder = TlsConnector::builder();
7985
builder
@@ -99,29 +105,7 @@ async fn configure_tls_connector(
99105
}
100106

101107
#[cfg(feature = "_tls-rustls")]
102-
async fn configure_tls_connector(
103-
_accept_invalid_certs: bool,
104-
_accept_invalid_hostnames: bool,
105-
root_cert_path: Option<&Path>,
106-
) -> Result<sqlx_rt::TlsConnector, Error> {
107-
// FIXME: Support accept_invalid_certs / accept_invalid_hostnames
108-
109-
use rustls::ClientConfig;
110-
use std::io::Cursor;
111-
use std::sync::Arc;
112-
113-
let mut config = ClientConfig::new();
114-
115-
if let Some(ca) = root_cert_path {
116-
let data = fs::read(ca).await?;
117-
let mut cursor = Cursor::new(data);
118-
config.root_store.add_pem_file(&mut cursor).map_err(|_| {
119-
Error::Tls(format!("Invalid certificate file: {}", ca.display()).into())
120-
})?;
121-
}
122-
123-
Ok(Arc::new(config).into())
124-
}
108+
use self::rustls::configure_tls_connector;
125109

126110
impl<S> AsyncRead for MaybeTlsStream<S>
127111
where

sqlx-core/src/net/tls/rustls.rs

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use rustls::{
2+
Certificate, ClientConfig, RootCertStore, ServerCertVerified, ServerCertVerifier, TLSError,
3+
WebPKIVerifier,
4+
};
5+
use sqlx_rt::fs;
6+
use std::sync::Arc;
7+
use std::{io::Cursor, path::Path};
8+
use webpki::DNSNameRef;
9+
10+
use crate::error::Error;
11+
12+
pub async fn configure_tls_connector(
13+
accept_invalid_certs: bool,
14+
accept_invalid_hostnames: bool,
15+
root_cert_path: Option<&Path>,
16+
) -> Result<sqlx_rt::TlsConnector, Error> {
17+
let mut config = ClientConfig::new();
18+
19+
if accept_invalid_certs {
20+
config
21+
.dangerous()
22+
.set_certificate_verifier(Arc::new(DummyTlsVerifier));
23+
} else {
24+
config
25+
.root_store
26+
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
27+
28+
if let Some(ca) = root_cert_path {
29+
let data = fs::read(ca).await?;
30+
let mut cursor = Cursor::new(data);
31+
config.root_store.add_pem_file(&mut cursor).map_err(|_| {
32+
Error::Tls(format!("Invalid certificate file: {}", ca.display()).into())
33+
})?;
34+
}
35+
36+
if accept_invalid_hostnames {
37+
config
38+
.dangerous()
39+
.set_certificate_verifier(Arc::new(NoHostnameTlsVerifier));
40+
}
41+
}
42+
43+
Ok(Arc::new(config).into())
44+
}
45+
46+
struct DummyTlsVerifier;
47+
48+
impl ServerCertVerifier for DummyTlsVerifier {
49+
fn verify_server_cert(
50+
&self,
51+
_roots: &RootCertStore,
52+
_presented_certs: &[Certificate],
53+
_dns_name: DNSNameRef<'_>,
54+
_ocsp_response: &[u8],
55+
) -> Result<ServerCertVerified, TLSError> {
56+
Ok(ServerCertVerified::assertion())
57+
}
58+
}
59+
60+
pub struct NoHostnameTlsVerifier;
61+
62+
impl ServerCertVerifier for NoHostnameTlsVerifier {
63+
fn verify_server_cert(
64+
&self,
65+
roots: &RootCertStore,
66+
presented_certs: &[Certificate],
67+
dns_name: DNSNameRef<'_>,
68+
ocsp_response: &[u8],
69+
) -> Result<ServerCertVerified, TLSError> {
70+
let verifier = WebPKIVerifier::new();
71+
match verifier.verify_server_cert(roots, presented_certs, dns_name, ocsp_response) {
72+
Err(TLSError::WebPKIError(webpki::Error::CertNotValidForName)) => {
73+
Ok(ServerCertVerified::assertion())
74+
}
75+
res => res,
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)