use crate::error::Error;
use crate::kx::{SupportedKxGroup, ALL_KX_GROUPS};
use crate::suites::{SupportedCipherSuite, DEFAULT_CIPHER_SUITES};
use crate::versions;
use std::fmt;
use std::marker::PhantomData;
#[derive(Clone)]
pub struct ConfigBuilder<Side: ConfigSide, State> {
pub(crate) state: State,
pub(crate) side: PhantomData<Side>,
}
impl<Side: ConfigSide, State> fmt::Debug for ConfigBuilder<Side, State> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ConfigBuilder")
.field("side", &format_args!("{}", &std::any::type_name::<Side>()))
.field(
"state",
&format_args!("{}", &std::any::type_name::<State>()),
)
.finish()
}
}
#[derive(Clone)]
pub struct WantsCipherSuites(pub(crate) ());
impl<S: ConfigSide> ConfigBuilder<S, WantsCipherSuites> {
pub fn with_safe_defaults(self) -> ConfigBuilder<S, WantsVerifier> {
ConfigBuilder {
state: WantsVerifier {
cipher_suites: DEFAULT_CIPHER_SUITES.to_vec(),
kx_groups: ALL_KX_GROUPS.to_vec(),
versions: versions::EnabledVersions::new(versions::DEFAULT_VERSIONS),
},
side: self.side,
}
}
pub fn with_cipher_suites(
self,
cipher_suites: &[SupportedCipherSuite],
) -> ConfigBuilder<S, WantsKxGroups> {
ConfigBuilder {
state: WantsKxGroups {
cipher_suites: cipher_suites.to_vec(),
},
side: self.side,
}
}
pub fn with_safe_default_cipher_suites(self) -> ConfigBuilder<S, WantsKxGroups> {
self.with_cipher_suites(DEFAULT_CIPHER_SUITES)
}
}
#[derive(Clone)]
pub struct WantsKxGroups {
cipher_suites: Vec<SupportedCipherSuite>,
}
impl<S: ConfigSide> ConfigBuilder<S, WantsKxGroups> {
pub fn with_kx_groups(
self,
kx_groups: &[&'static SupportedKxGroup],
) -> ConfigBuilder<S, WantsVersions> {
ConfigBuilder {
state: WantsVersions {
cipher_suites: self.state.cipher_suites,
kx_groups: kx_groups.to_vec(),
},
side: self.side,
}
}
pub fn with_safe_default_kx_groups(self) -> ConfigBuilder<S, WantsVersions> {
self.with_kx_groups(&ALL_KX_GROUPS)
}
}
pub struct WantsVersions {
cipher_suites: Vec<SupportedCipherSuite>,
kx_groups: Vec<&'static SupportedKxGroup>,
}
impl<S: ConfigSide> ConfigBuilder<S, WantsVersions> {
pub fn with_safe_default_protocol_versions(
self,
) -> Result<ConfigBuilder<S, WantsVerifier>, Error> {
self.with_protocol_versions(versions::DEFAULT_VERSIONS)
}
pub fn with_protocol_versions(
self,
versions: &[&'static versions::SupportedProtocolVersion],
) -> Result<ConfigBuilder<S, WantsVerifier>, Error> {
let mut any_usable_suite = false;
for suite in &self.state.cipher_suites {
if versions.contains(&suite.version()) {
any_usable_suite = true;
break;
}
}
if !any_usable_suite {
return Err(Error::General("no usable cipher suites configured".into()));
}
if self.state.kx_groups.is_empty() {
return Err(Error::General("no kx groups configured".into()));
}
Ok(ConfigBuilder {
state: WantsVerifier {
cipher_suites: self.state.cipher_suites,
kx_groups: self.state.kx_groups,
versions: versions::EnabledVersions::new(versions),
},
side: self.side,
})
}
}
pub struct WantsVerifier {
pub(crate) cipher_suites: Vec<SupportedCipherSuite>,
pub(crate) kx_groups: Vec<&'static SupportedKxGroup>,
pub(crate) versions: versions::EnabledVersions,
}
pub trait ConfigSide: sealed::Sealed {}
impl ConfigSide for crate::ClientConfig {}
impl ConfigSide for crate::ServerConfig {}
mod sealed {
pub trait Sealed {}
impl Sealed for crate::ClientConfig {}
impl Sealed for crate::ServerConfig {}
}