use crate::{
calendar::{DateTime, Instant, Utc},
collections::{ArrayVectorCopy, ShortBoxSliceU8, ShortBoxSliceU16, SingleTypeStorage, Vector},
misc::{Lease, LeaseMut},
rng::CryptoRng,
tls::{
Alpn, CipherSuite, MaxFragmentLength, NamedGroup, PlaintextCtx, PublicKeys, ServerNameList,
TlsCtxSkInput, TlsCtxSkLoader, TrustedCtx, UnverifiedCtx,
protocol::{
signature_algorithms::SignatureAlgorithms,
signature_algorithms_cert::SignatureAlgorithmsCert, supported_groups::SupportedGroups,
},
},
x509::{Certificate, CvPolicy, CvTrustAnchor},
};
use core::{fmt::Debug, mem};
pub struct TlsConfig<TCX> {
pub(crate) inner: TlsConfigInner<ShortBoxSliceU16<u8>, TCX>,
}
impl TlsConfig<PlaintextCtx> {
#[inline]
pub fn plaintext() -> Self {
Self { inner: TlsConfigInner::new(PlaintextCtx::new(), DateTime::default()) }
}
}
impl TlsConfig<TrustedCtx> {
#[cfg(feature = "ccadb")]
#[inline]
pub fn from_ccadb() -> crate::Result<Self> {
let mut trust_anchors = Vector::new();
for elem in crate::x509::CCADB {
trust_anchors.push(CvTrustAnchor::_from_raw(*elem)?)?;
}
let mut this = Self::new(TrustedCtx::new())?;
this.inner.trust_anchors = trust_anchors.try_into()?;
Ok(this)
}
#[inline]
pub fn from_trust_anchors_pem<'bytes>(
trust_anchors: impl IntoIterator<Item = &'bytes [u8]>,
) -> crate::Result<Self> {
let mut this = Self::new(TrustedCtx::new())?;
this.set_trust_anchors_pem(trust_anchors)?;
Ok(this)
}
}
impl TlsConfig<UnverifiedCtx> {
#[inline]
pub fn unverified() -> Self {
Self { inner: TlsConfigInner::new(UnverifiedCtx::new(), DateTime::default()) }
}
}
impl<TCX> TlsConfig<TCX>
where
TCX: TlsCtxSkLoader,
{
#[inline]
pub fn from_keys_der<'pk, 'sk, RNG, SK>(
public_key: impl IntoIterator<Item = &'pk [u8]>,
rng: &mut RNG,
secret_key: SK,
) -> crate::Result<Self>
where
RNG: CryptoRng,
SK: TlsCtxSkInput<TlsCtxSk = TCX>,
TCX: TlsCtxSkLoader<SkInputDer<'sk> = SK>,
{
let mut this = Self::new(TCX::from_ders([secret_key], rng)?)?;
this.set_public_keys_der([public_key])?;
Ok(this)
}
#[inline]
pub fn from_keys_pem<'sk, RNG, SK>(
public_key: &[u8],
rng: &mut RNG,
secret_key: SK,
) -> crate::Result<Self>
where
RNG: CryptoRng,
SK: TlsCtxSkInput<TlsCtxSk = TCX>,
TCX: TlsCtxSkLoader<SkInputPem<'sk> = SK>,
{
let mut this = Self::new(TCX::from_pems([secret_key], rng)?)?;
this.set_public_keys_pem([public_key])?;
Ok(this)
}
}
impl<TCX> TlsConfig<TCX> {
#[inline]
pub fn new(ctx: TCX) -> crate::Result<Self> {
Ok(Self::from_validation_time(ctx, Instant::now_date_time()?))
}
#[inline]
pub fn from_validation_time(ctx: TCX, validation_time: DateTime<Utc>) -> Self {
Self { inner: TlsConfigInner::new(ctx, validation_time) }
}
}
impl<TCX> TlsConfig<TCX> {
#[inline]
pub const fn alpn(&self) -> &Option<Alpn> {
&self.inner.alpn
}
#[inline]
pub const fn alpn_mut(&mut self) -> &mut Option<Alpn> {
&mut self.inner.alpn
}
#[inline]
pub const fn cipher_suites(
&self,
) -> &ArrayVectorCopy<CipherSuite, { CipherSuite::PRIORITY.len() }> {
&self.inner.cipher_suites
}
#[inline]
pub const fn cipher_suites_mut(
&mut self,
) -> &mut ArrayVectorCopy<CipherSuite, { CipherSuite::PRIORITY.len() }> {
&mut self.inner.cipher_suites
}
#[inline]
pub const fn ctx(&self) -> &TCX {
&self.inner.ctx
}
#[inline]
pub const fn cv_policy(&self) -> &CvPolicy<ShortBoxSliceU16<u8>> {
&self.inner.cv_policy
}
#[inline]
pub const fn cv_policy_mut(&mut self) -> &mut CvPolicy<ShortBoxSliceU16<u8>> {
&mut self.inner.cv_policy
}
#[inline]
pub const fn max_fragment_length(&self) -> Option<MaxFragmentLength> {
self.inner.max_fragment_length
}
#[inline]
pub const fn max_fragment_length_mut(&mut self) -> &mut Option<MaxFragmentLength> {
&mut self.inner.max_fragment_length
}
#[inline]
pub const fn max_fragment_length_send(&self) -> Option<MaxFragmentLength> {
self.inner.max_fragment_length_send
}
#[inline]
pub const fn max_fragment_length_send_mut(&mut self) -> &mut Option<MaxFragmentLength> {
&mut self.inner.max_fragment_length_send
}
#[inline]
pub const fn public_keys(&self) -> &PublicKeys {
&self.inner.public_keys
}
#[inline]
pub const fn server_name(&self) -> &Option<ServerNameList> {
&self.inner.server_name
}
#[inline]
pub const fn server_name_mut(&mut self) -> &mut Option<ServerNameList> {
&mut self.inner.server_name
}
#[inline]
pub fn set_tls_mode<_TM>(self, value: _TM) -> TlsConfig<_TM> {
TlsConfig {
inner: TlsConfigInner {
alpn: self.inner.alpn,
cipher_suites: self.inner.cipher_suites,
ctx: value,
cv_policy: self.inner.cv_policy,
max_fragment_length: self.inner.max_fragment_length,
max_fragment_length_send: self.inner.max_fragment_length_send,
public_keys: self.inner.public_keys,
server_name: self.inner.server_name,
signature_algorithms: self.inner.signature_algorithms,
signature_algorithms_cert: self.inner.signature_algorithms_cert,
supported_groups: self.inner.supported_groups,
trust_anchors: self.inner.trust_anchors,
unique_signature_algorithms: self.inner.unique_signature_algorithms,
},
}
}
#[inline]
pub fn set_public_keys_der<'pkc, PKC, PKS>(&mut self, public_keys: PKS) -> crate::Result<()>
where
PKC: IntoIterator<Item = &'pkc [u8]>,
PKS: IntoIterator<Item = PKC>,
{
self.inner.public_keys.clear();
for certs in public_keys {
self.inner.public_keys.push_public_key_der(certs)?;
}
Ok(())
}
#[inline]
pub fn set_public_keys_pem<'pems>(
&mut self,
pems: impl IntoIterator<Item = &'pems [u8]>,
) -> crate::Result<()> {
let mut buffer = Vector::new();
self.inner.public_keys.clear();
for pem in pems {
self.inner.public_keys.push_public_key_pem(&mut buffer, pem)?;
buffer.clear();
}
Ok(())
}
#[inline]
pub fn set_trust_anchors_pem<'bytes>(
&mut self,
trust_anchors: impl IntoIterator<Item = &'bytes [u8]>,
) -> crate::Result<()> {
let mut buffer = Vector::new();
let mut local_trust_anchors: Vector<_> = mem::take(&mut self.inner.trust_anchors).into();
local_trust_anchors.clear();
for trust_anchor in trust_anchors {
buffer.clear();
let cert = Certificate::<&[u8]>::from_pem(&mut buffer, trust_anchor)?.0;
local_trust_anchors.push(CvTrustAnchor::from_certificate_ref(&cert)?)?;
}
self.inner.trust_anchors = local_trust_anchors.try_into()?;
Ok(())
}
#[inline]
pub const fn signature_algorithms(&self) -> &SignatureAlgorithms {
&self.inner.signature_algorithms
}
#[inline]
pub const fn signature_algorithms_mut(&mut self) -> &mut SignatureAlgorithms {
&mut self.inner.signature_algorithms
}
#[inline]
pub const fn supported_groups(&self) -> &SupportedGroups {
&self.inner.supported_groups
}
#[inline]
pub const fn supported_groups_mut(&mut self) -> &mut SupportedGroups {
&mut self.inner.supported_groups
}
#[inline]
pub fn trust_anchors(&self) -> &[CvTrustAnchor<ShortBoxSliceU16<u8>>] {
&self.inner.trust_anchors
}
#[inline]
pub const fn unique_signature_algorithms(&self) -> bool {
self.inner.unique_signature_algorithms
}
#[inline]
pub const fn unique_signature_algorithms_mut(&mut self) -> &mut bool {
&mut self.inner.unique_signature_algorithms
}
}
impl<TCX> Lease<TlsConfig<TCX>> for TlsConfig<TCX> {
#[inline]
fn lease(&self) -> &TlsConfig<TCX> {
self
}
}
impl<TCX> LeaseMut<TlsConfig<TCX>> for TlsConfig<TCX> {
#[inline]
fn lease_mut(&mut self) -> &mut TlsConfig<TCX> {
self
}
}
impl<TCX> SingleTypeStorage for TlsConfig<TCX> {
type Item = TCX;
}
impl<TCX> Debug for TlsConfig<TCX>
where
TCX: Debug,
{
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.inner.fmt(f)
}
}
#[derive(Debug)]
pub(crate) struct TlsConfigInner<B, TCX> {
pub(crate) alpn: Option<Alpn>,
pub(crate) cipher_suites: ArrayVectorCopy<CipherSuite, { CipherSuite::PRIORITY.len() }>,
pub(crate) ctx: TCX,
pub(crate) cv_policy: CvPolicy<B>,
pub(crate) max_fragment_length: Option<MaxFragmentLength>,
pub(crate) max_fragment_length_send: Option<MaxFragmentLength>,
pub(crate) public_keys: PublicKeys,
pub(crate) server_name: Option<ServerNameList>,
pub(crate) signature_algorithms: SignatureAlgorithms,
pub(crate) signature_algorithms_cert: Option<SignatureAlgorithmsCert>,
pub(crate) supported_groups: SupportedGroups,
pub(crate) trust_anchors: ShortBoxSliceU8<CvTrustAnchor<B>>,
pub(crate) unique_signature_algorithms: bool,
}
impl<B, TCX> TlsConfigInner<B, TCX>
where
B: Default,
{
#[inline]
fn new(ctx: TCX, validation_time: DateTime<Utc>) -> Self {
Self {
alpn: None,
cipher_suites: ArrayVectorCopy::from_array(CipherSuite::PRIORITY),
cv_policy: CvPolicy::new(validation_time),
ctx,
max_fragment_length: None,
max_fragment_length_send: None,
public_keys: PublicKeys::default(),
server_name: None,
signature_algorithms: SignatureAlgorithms::default(),
signature_algorithms_cert: Some(SignatureAlgorithmsCert::default()),
supported_groups: SupportedGroups::new(ArrayVectorCopy::from_array(NamedGroup::PRIORITY)),
trust_anchors: ShortBoxSliceU8::default(),
unique_signature_algorithms: false,
}
}
}