use bytes::Bytes;
use crate::error::Error;
use crate::net::TlsConfig;
use crate::postgres::connection::stream::PgStream;
use crate::postgres::message::SslRequest;
use crate::postgres::{PgConnectOptions, PgSslMode};
pub(super) async fn maybe_upgrade(
stream: &mut PgStream,
options: &PgConnectOptions,
) -> Result<(), Error> {
match options.ssl_mode {
PgSslMode::Allow | PgSslMode::Disable => {}
PgSslMode::Prefer => {
upgrade(stream, options).await?;
}
PgSslMode::Require | PgSslMode::VerifyFull | PgSslMode::VerifyCa => {
if !upgrade(stream, options).await? {
return Err(Error::Tls("server does not support TLS".into()));
}
}
}
Ok(())
}
async fn upgrade(stream: &mut PgStream, options: &PgConnectOptions) -> Result<bool, Error> {
stream.send(SslRequest).await?;
match stream.read::<Bytes>(1).await?[0] {
b'S' => {
}
b'N' => {
return Ok(false);
}
other => {
return Err(err_protocol!(
"unexpected response from SSLRequest: 0x{:02x}",
other
));
}
}
let accept_invalid_certs = !matches!(
options.ssl_mode,
PgSslMode::VerifyCa | PgSslMode::VerifyFull
);
let accept_invalid_hostnames = !matches!(options.ssl_mode, PgSslMode::VerifyFull);
let tls_config: TlsConfig<'_> = TlsConfig {
accept_invalid_certs,
accept_invalid_hostnames,
root_cert_path: options.ssl_root_cert.as_ref(),
hostname: &options.host,
client_cert_path: options.ssl_client_cert.as_ref(),
client_key_path: options.ssl_client_key.as_ref(),
};
stream.upgrade(tls_config).await?;
Ok(true)
}