use alloc::boxed::Box; use alloc::vec::Vec; use super::ResolvesClientCert; use crate::log::{debug, trace}; use crate::msgs::enums::ExtensionType; use crate::msgs::handshake::{CertificateChain, DistinguishedName, ProtocolName, ServerExtensions}; use crate::sync::Arc; use crate::{SignatureScheme, compress, sign}; #[derive(Debug)] pub(super) struct ServerCertDetails<'a> { pub(super) cert_chain: CertificateChain<'a>, pub(super) ocsp_response: Vec, } impl<'a> ServerCertDetails<'a> { pub(super) fn new(cert_chain: CertificateChain<'a>, ocsp_response: Vec) -> Self { Self { cert_chain, ocsp_response, } } pub(super) fn into_owned(self) -> ServerCertDetails<'static> { let Self { cert_chain, ocsp_response, } = self; ServerCertDetails { cert_chain: cert_chain.into_owned(), ocsp_response, } } } pub(super) struct ClientHelloDetails { pub(super) alpn_protocols: Vec, pub(super) sent_extensions: Vec, pub(super) extension_order_seed: u16, pub(super) offered_cert_compression: bool, } impl ClientHelloDetails { pub(super) fn new(alpn_protocols: Vec, extension_order_seed: u16) -> Self { Self { alpn_protocols, sent_extensions: Vec::new(), extension_order_seed, offered_cert_compression: false, } } pub(super) fn server_sent_unsolicited_extensions( &self, received_exts: &ServerExtensions<'_>, allowed_unsolicited: &[ExtensionType], ) -> bool { let mut extensions = received_exts.collect_used(); extensions.extend( received_exts .unknown_extensions .iter() .map(|ext| ExtensionType::from(*ext)), ); for ext_type in extensions { if !self.sent_extensions.contains(&ext_type) && !allowed_unsolicited.contains(&ext_type) { trace!("Unsolicited extension {ext_type:?}"); return true; } } false } } pub(super) enum ClientAuthDetails { /// Send an empty `Certificate` and no `CertificateVerify`. Empty { auth_context_tls13: Option> }, /// Send a non-empty `Certificate` and a `CertificateVerify`. Verify { certkey: Arc, signer: Box, auth_context_tls13: Option>, compressor: Option<&'static dyn compress::CertCompressor>, }, } impl ClientAuthDetails { pub(super) fn resolve( resolver: &dyn ResolvesClientCert, canames: Option<&[DistinguishedName]>, sigschemes: &[SignatureScheme], auth_context_tls13: Option>, compressor: Option<&'static dyn compress::CertCompressor>, ) -> Self { let acceptable_issuers = canames .unwrap_or_default() .iter() .map(|p| p.as_ref()) .collect::>(); if let Some(certkey) = resolver.resolve(&acceptable_issuers, sigschemes) { if let Some(signer) = certkey.key.choose_scheme(sigschemes) { debug!("Attempting client auth"); return Self::Verify { certkey, signer, auth_context_tls13, compressor, }; } } debug!("Client auth requested but no cert/sigscheme available"); Self::Empty { auth_context_tls13 } } }