sqlx_postgres/connection/
tls.rsuse futures_core::future::BoxFuture;
use crate::error::Error;
use crate::net::tls::{self, TlsConfig};
use crate::net::{Socket, SocketIntoBox, WithSocket};
use crate::message::SslRequest;
use crate::{PgConnectOptions, PgSslMode};
pub struct MaybeUpgradeTls<'a>(pub &'a PgConnectOptions);
impl<'a> WithSocket for MaybeUpgradeTls<'a> {
type Output = BoxFuture<'a, crate::Result<Box<dyn Socket>>>;
fn with_socket<S: Socket>(self, socket: S) -> Self::Output {
Box::pin(maybe_upgrade(socket, self.0))
}
}
async fn maybe_upgrade<S: Socket>(
mut socket: S,
options: &PgConnectOptions,
) -> Result<Box<dyn Socket>, Error> {
match options.ssl_mode {
PgSslMode::Allow | PgSslMode::Disable => return Ok(Box::new(socket)),
PgSslMode::Prefer => {
if !tls::available() {
return Ok(Box::new(socket));
}
if !request_upgrade(&mut socket, options).await? {
return Ok(Box::new(socket));
}
}
PgSslMode::Require | PgSslMode::VerifyFull | PgSslMode::VerifyCa => {
tls::error_if_unavailable()?;
if !request_upgrade(&mut socket, options).await? {
return Err(Error::Tls("server does not support TLS".into()));
}
}
}
let accept_invalid_certs = !matches!(
options.ssl_mode,
PgSslMode::VerifyCa | PgSslMode::VerifyFull
);
let accept_invalid_hostnames = !matches!(options.ssl_mode, PgSslMode::VerifyFull);
let config = TlsConfig {
accept_invalid_certs,
accept_invalid_hostnames,
hostname: &options.host,
root_cert_path: options.ssl_root_cert.as_ref(),
client_cert_path: options.ssl_client_cert.as_ref(),
client_key_path: options.ssl_client_key.as_ref(),
};
tls::handshake(socket, config, SocketIntoBox).await
}
async fn request_upgrade(
socket: &mut impl Socket,
_options: &PgConnectOptions,
) -> Result<bool, Error> {
socket.write(SslRequest::BYTES).await?;
let mut response = [0u8];
socket.read(&mut &mut response[..]).await?;
match response[0] {
b'S' => {
Ok(true)
}
b'N' => {
Ok(false)
}
other => Err(err_protocol!(
"unexpected response from SSLRequest: 0x{:02x}",
other
)),
}
}