use std::fmt;
use crate::cfg::{cfg_rustls, cfg_s2n_tls};
use crate::HttpClientError;
#[derive(Debug, PartialEq, Clone)]
#[non_exhaustive]
pub enum Provider {
#[cfg(feature = "__rustls")]
Rustls(rustls_provider::CryptoMode),
#[cfg(feature = "s2n-tls")]
S2nTls,
}
#[cfg(not(all(aws_sdk_unstable, feature = "__rustls")))]
impl Eq for Provider {}
#[derive(Debug, Clone)]
pub struct TlsContext {
#[allow(unused)]
trust_store: TrustStore,
#[allow(unused)]
additional_server_names: Vec<ServerName>,
}
impl TlsContext {
pub fn builder() -> TlsContextBuilder {
TlsContextBuilder::new()
}
}
impl Default for TlsContext {
fn default() -> Self {
TlsContext::builder().build().expect("valid default config")
}
}
#[derive(Debug)]
pub struct TlsContextBuilder {
trust_store: TrustStore,
additional_server_names: Vec<ServerName>,
}
impl TlsContextBuilder {
fn new() -> Self {
TlsContextBuilder {
trust_store: TrustStore::default(),
additional_server_names: Vec::default(),
}
}
pub fn with_trust_store(mut self, trust_store: TrustStore) -> Self {
self.trust_store = trust_store;
self
}
pub fn with_additional_server_names(
mut self,
additional_server_names: Vec<ServerName>,
) -> Self {
self.additional_server_names = additional_server_names;
self
}
pub fn build(self) -> Result<TlsContext, HttpClientError> {
Ok(TlsContext {
trust_store: self.trust_store,
additional_server_names: self.additional_server_names,
})
}
}
#[allow(unused)]
#[derive(Debug, Clone)]
struct CertificatePEM(Vec<u8>);
impl From<&[u8]> for CertificatePEM {
fn from(value: &[u8]) -> Self {
CertificatePEM(value.to_vec())
}
}
#[derive(Debug, Clone)]
pub struct TrustStore {
enable_native_roots: bool,
custom_certs: Vec<CertificatePEM>,
}
impl TrustStore {
pub fn empty() -> Self {
Self {
enable_native_roots: false,
custom_certs: Vec::new(),
}
}
pub fn with_native_roots(mut self, enable_native_roots: bool) -> Self {
self.enable_native_roots = enable_native_roots;
self
}
pub fn with_pem_certificate(mut self, pem_bytes: impl Into<Vec<u8>>) -> Self {
self.custom_certs.push(CertificatePEM(pem_bytes.into()));
self
}
pub fn add_pem_certificate(&mut self, pem_bytes: impl Into<Vec<u8>>) -> &mut Self {
self.custom_certs.push(CertificatePEM(pem_bytes.into()));
self
}
}
impl Default for TrustStore {
fn default() -> Self {
Self {
enable_native_roots: true,
custom_certs: Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ServerName(rustls_pki_types::ServerName<'static>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InvalidServerName {
name: String,
}
impl fmt::Display for InvalidServerName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "invalid server name: {:?}", self.name)
}
}
impl std::error::Error for InvalidServerName {}
impl TryFrom<String> for ServerName {
type Error = InvalidServerName;
fn try_from(name: String) -> Result<Self, Self::Error> {
match rustls_pki_types::ServerName::try_from(name.as_str()) {
Ok(sn) => Ok(ServerName(sn.to_owned())),
Err(_) => Err(InvalidServerName { name }),
}
}
}
impl TryFrom<&str> for ServerName {
type Error = InvalidServerName;
fn try_from(name: &str) -> Result<Self, Self::Error> {
match rustls_pki_types::ServerName::try_from(name) {
Ok(sn) => Ok(ServerName(sn.to_owned())),
Err(_) => Err(InvalidServerName {
name: name.to_owned(),
}),
}
}
}
cfg_rustls! {
pub mod rustls_provider;
}
cfg_s2n_tls! {
pub(crate) mod s2n_tls_provider;
}