Skip to content

Commit d065bb1

Browse files
committed
better rustls error messages
1 parent 74823b5 commit d065bb1

File tree

1 file changed

+102
-19
lines changed

1 file changed

+102
-19
lines changed

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

Lines changed: 102 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
2-
use rustls::client::WebPkiServerVerifier;
2+
use rustls::client::{VerifierBuilderError, WebPkiServerVerifier};
33
use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName, UnixTime};
44
use rustls::{
55
CertificateError, ClientConfig, DigitallySignedStruct, Error as TlsError, KeyLogFile,
@@ -12,6 +12,56 @@ use crate::error::Error;
1212

1313
use super::TlsConfig;
1414

15+
#[derive(Debug, thiserror::Error)]
16+
pub enum RustlsError {
17+
#[error("failed to add root certificate from {path_desc} to trust store: {source}")]
18+
AddRootCert {
19+
path_desc: String,
20+
#[source]
21+
source: rustls::Error,
22+
},
23+
#[error("failed to parse PEM certificate from {file_description}: {source}")]
24+
ParsePemCert {
25+
file_description: String,
26+
#[source]
27+
source: std::io::Error,
28+
},
29+
#[error("failed to build TLS verifier, ensure CA certificates are valid and correctly configured: {source}")]
30+
BuildVerifier {
31+
#[source]
32+
source: VerifierBuilderError,
33+
},
34+
#[error("failed to parse client certificate from {file_description}: {source}")]
35+
ParseClientCert {
36+
file_description: String,
37+
#[source]
38+
source: std::io::Error,
39+
},
40+
#[error("failed to parse client private key from {file_description}: {source}")]
41+
ParseClientKey {
42+
file_description: String,
43+
#[source]
44+
source: std::io::Error,
45+
},
46+
#[error("failed to set client authentication using certificate from {cert_path_desc} and private key from {key_path_desc}; ensure the certificate and key are valid: {source}")]
47+
ClientAuthCert {
48+
cert_path_desc: String,
49+
key_path_desc: String,
50+
#[source]
51+
source: TlsError,
52+
},
53+
#[error("no supported private keys (Sec1, Pkcs8, Pkcs1) found in the provided PEM data for the client private key")]
54+
NoKeysFound,
55+
#[error("TLS configuration error: {0}. Please check your TLS settings, including paths to certificates and keys, and ensure they are correctly specified.")]
56+
Configuration(String),
57+
}
58+
59+
impl From<RustlsError> for Error {
60+
fn from(err: RustlsError) -> Self {
61+
Error::Tls(Box::new(err))
62+
}
63+
}
64+
1565
pub async fn configure_tls_connector(
1666
tls_config: TlsConfig<'_>,
1767
) -> Result<sqlx_rt::TlsConnector, Error> {
@@ -26,20 +76,29 @@ pub async fn configure_tls_connector(
2676
};
2777

2878
if let Some(ca) = tls_config.root_cert_path {
29-
let data = ca.data().await?;
79+
let path_description = ca.to_string();
80+
let data = ca.data().await.map_err(|e| RustlsError::ParsePemCert {
81+
file_description: path_description.clone(),
82+
source: std::io::Error::new(std::io::ErrorKind::Other, e),
83+
})?;
3084
let mut cursor = Cursor::new(data);
3185

32-
for cert in rustls_pemfile::certs(&mut cursor) {
33-
cert_store
34-
.add(cert.map_err(|err| Error::Tls(err.into()))?)
35-
.map_err(|err| Error::Tls(err.into()))?;
86+
for cert_result in rustls_pemfile::certs(&mut cursor) {
87+
let cert = cert_result.map_err(|e| RustlsError::ParsePemCert {
88+
file_description: path_description.clone(),
89+
source: e,
90+
})?;
91+
cert_store.add(cert).map_err(|e| RustlsError::AddRootCert {
92+
path_desc: path_description.clone(),
93+
source: e,
94+
})?;
3695
}
3796
}
3897

3998
if tls_config.accept_invalid_hostnames {
4099
let verifier = WebPkiServerVerifier::builder(Arc::new(cert_store))
41100
.build()
42-
.map_err(|err| Error::Tls(err.into()))?;
101+
.map_err(|e| RustlsError::BuildVerifier { source: e })?;
43102

44103
config
45104
.dangerous()
@@ -49,41 +108,65 @@ pub async fn configure_tls_connector(
49108
}
50109
};
51110

52-
// authentication using user's key and its associated certificate
53111
let mut config = match (tls_config.client_cert_path, tls_config.client_key_path) {
54112
(Some(cert_path), Some(key_path)) => {
55-
let cert_chain = certs_from_pem(cert_path.data().await?)?;
56-
let key_der = private_key_from_pem(key_path.data().await?)?;
113+
let cert_file_desc = cert_path.to_string();
114+
let key_file_desc = key_path.to_string();
115+
116+
let cert_chain = certs_from_pem(cert_path.data().await.map_err(|e| {
117+
RustlsError::ParseClientCert {
118+
file_description: cert_file_desc.clone(),
119+
source: std::io::Error::new(std::io::ErrorKind::Other, e),
120+
}
121+
})?)?;
122+
let key_der = private_key_from_pem(key_path.data().await.map_err(|e| {
123+
RustlsError::ParseClientKey {
124+
file_description: key_file_desc.clone(),
125+
source: std::io::Error::new(std::io::ErrorKind::Other, e),
126+
}
127+
})?)?;
57128
config
58129
.with_client_auth_cert(cert_chain, key_der)
59-
.map_err(Error::tls)?
130+
.map_err(|e| RustlsError::ClientAuthCert {
131+
cert_path_desc: cert_file_desc,
132+
key_path_desc: key_file_desc,
133+
source: e,
134+
})?
60135
}
61136
(None, None) => config.with_no_client_auth(),
62137
(_, _) => {
63-
return Err(Error::Configuration(
138+
return Err(RustlsError::Configuration(
64139
"user auth key and certs must be given together".into(),
65-
))
140+
)
141+
.into())
66142
}
67143
};
68144

69-
// When SSLKEYLOGFILE is set, write the TLS keys to a file for use with Wireshark
70145
config.key_log = Arc::new(KeyLogFile::new());
71146

72147
Ok(Arc::new(config).into())
73148
}
74149

75-
fn certs_from_pem(pem: Vec<u8>) -> std::io::Result<Vec<CertificateDer<'static>>> {
150+
fn certs_from_pem(pem: Vec<u8>) -> Result<Vec<CertificateDer<'static>>, RustlsError> {
76151
let cur = Cursor::new(pem);
77152
let mut reader = BufReader::new(cur);
78-
rustls_pemfile::certs(&mut reader).collect()
153+
rustls_pemfile::certs(&mut reader)
154+
.collect::<Result<Vec<_>, _>>()
155+
.map_err(|e| RustlsError::ParsePemCert {
156+
file_description: String::from("PEM data"),
157+
source: e,
158+
})
79159
}
80160

81-
fn private_key_from_pem(pem: Vec<u8>) -> Result<PrivateKeyDer<'static>, Error> {
161+
fn private_key_from_pem(pem: Vec<u8>) -> Result<PrivateKeyDer<'static>, RustlsError> {
82162
let cur = Cursor::new(pem);
83163
let mut reader = BufReader::new(cur);
84164

85165
loop {
86-
match rustls_pemfile::read_one(&mut reader)? {
166+
match rustls_pemfile::read_one(&mut reader).map_err(|e| RustlsError::ParseClientKey {
167+
file_description: String::from("PEM data"),
168+
source: e,
169+
})? {
87170
Some(rustls_pemfile::Item::Sec1Key(key)) => return Ok(PrivateKeyDer::Sec1(key)),
88171
Some(rustls_pemfile::Item::Pkcs8Key(key)) => return Ok(PrivateKeyDer::Pkcs8(key)),
89172
Some(rustls_pemfile::Item::Pkcs1Key(key)) => return Ok(PrivateKeyDer::Pkcs1(key)),
@@ -92,7 +175,7 @@ fn private_key_from_pem(pem: Vec<u8>) -> Result<PrivateKeyDer<'static>, Error> {
92175
}
93176
}
94177

95-
Err(Error::Configuration("no keys found pem file".into()))
178+
Err(RustlsError::NoKeysFound)
96179
}
97180

98181
#[derive(Debug)]

0 commit comments

Comments
 (0)