1#[cfg(feature = "tls")]
7use sqlmodel_core::Error;
8#[cfg(feature = "tls")]
9use sqlmodel_core::error::{ConnectionError, ConnectionErrorKind};
10
11#[cfg(feature = "tls")]
12use crate::config::SslMode;
13
14#[cfg(feature = "tls")]
15use std::sync::Arc;
16
17#[cfg(feature = "tls")]
18fn tls_error(message: impl Into<String>) -> Error {
19 Error::Connection(ConnectionError {
20 kind: ConnectionErrorKind::Ssl,
21 message: message.into(),
22 source: None,
23 })
24}
25
26#[allow(clippy::result_large_err)]
29#[cfg(feature = "tls")]
30pub(crate) fn server_name(host: &str) -> Result<rustls::pki_types::ServerName<'static>, Error> {
31 host.to_string()
32 .try_into()
33 .map_err(|e| tls_error(format!("Invalid server name '{host}': {e}")))
34}
35
36#[allow(clippy::result_large_err)]
43#[cfg(feature = "tls")]
44pub(crate) fn build_client_config(ssl_mode: SslMode) -> Result<rustls::ClientConfig, Error> {
45 let provider = Arc::new(rustls::crypto::ring::default_provider());
46
47 match ssl_mode {
48 SslMode::Disable => Err(tls_error("TLS config requested with SslMode::Disable")),
49 SslMode::Prefer | SslMode::Require => build_no_verify_config(&provider),
50 SslMode::VerifyCa | SslMode::VerifyFull => build_webpki_config(&provider),
51 }
52}
53
54#[allow(clippy::result_large_err)]
56#[cfg(feature = "tls")]
57fn build_no_verify_config(
58 provider: &Arc<rustls::crypto::CryptoProvider>,
59) -> Result<rustls::ClientConfig, Error> {
60 use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
61 use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
62 use rustls::{DigitallySignedStruct, Error as RustlsError, SignatureScheme};
63
64 #[derive(Debug)]
65 struct NoVerifier;
66
67 impl ServerCertVerifier for NoVerifier {
68 fn verify_server_cert(
69 &self,
70 _end_entity: &CertificateDer<'_>,
71 _intermediates: &[CertificateDer<'_>],
72 _server_name: &ServerName<'_>,
73 _ocsp_response: &[u8],
74 _now: UnixTime,
75 ) -> Result<ServerCertVerified, RustlsError> {
76 Ok(ServerCertVerified::assertion())
77 }
78
79 fn verify_tls12_signature(
80 &self,
81 _message: &[u8],
82 _cert: &CertificateDer<'_>,
83 _dss: &DigitallySignedStruct,
84 ) -> Result<HandshakeSignatureValid, RustlsError> {
85 Ok(HandshakeSignatureValid::assertion())
86 }
87
88 fn verify_tls13_signature(
89 &self,
90 _message: &[u8],
91 _cert: &CertificateDer<'_>,
92 _dss: &DigitallySignedStruct,
93 ) -> Result<HandshakeSignatureValid, RustlsError> {
94 Ok(HandshakeSignatureValid::assertion())
95 }
96
97 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
98 vec![
99 SignatureScheme::RSA_PKCS1_SHA256,
100 SignatureScheme::RSA_PKCS1_SHA384,
101 SignatureScheme::RSA_PKCS1_SHA512,
102 SignatureScheme::ECDSA_NISTP256_SHA256,
103 SignatureScheme::ECDSA_NISTP384_SHA384,
104 SignatureScheme::ECDSA_NISTP521_SHA512,
105 SignatureScheme::RSA_PSS_SHA256,
106 SignatureScheme::RSA_PSS_SHA384,
107 SignatureScheme::RSA_PSS_SHA512,
108 SignatureScheme::ED25519,
109 ]
110 }
111 }
112
113 let config = rustls::ClientConfig::builder_with_provider(provider.clone())
114 .with_protocol_versions(&[&rustls::version::TLS12, &rustls::version::TLS13])
115 .map_err(|e| tls_error(format!("Failed to set TLS versions: {e}")))?
116 .dangerous()
117 .with_custom_certificate_verifier(Arc::new(NoVerifier))
118 .with_no_client_auth();
119
120 Ok(config)
121}
122
123#[allow(clippy::result_large_err)]
125#[cfg(feature = "tls")]
126fn build_webpki_config(
127 provider: &Arc<rustls::crypto::CryptoProvider>,
128) -> Result<rustls::ClientConfig, Error> {
129 use rustls::RootCertStore;
130
131 let mut root_store = RootCertStore::empty();
132 root_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
133
134 let config = rustls::ClientConfig::builder_with_provider(provider.clone())
135 .with_protocol_versions(&[&rustls::version::TLS12, &rustls::version::TLS13])
136 .map_err(|e| tls_error(format!("Failed to set TLS versions: {e}")))?
137 .with_root_certificates(root_store)
138 .with_no_client_auth();
139
140 Ok(config)
141}