rustls/client/
mod.rs

1use alloc::vec::Vec;
2
3use crate::compress;
4use crate::crypto::{SelectedCredential, SignatureScheme};
5use crate::enums::CertificateType;
6use crate::log::{debug, trace};
7use crate::msgs::enums::ExtensionType;
8use crate::msgs::handshake::{CertificateChain, ProtocolName, ServerExtensions};
9pub use crate::msgs::persist::{Tls12ClientSessionValue, Tls13ClientSessionValue};
10use crate::verify::DistinguishedName;
11pub use crate::webpki::{
12    ServerVerifierBuilder, VerifierBuilderError, WebPkiServerVerifier,
13    verify_identity_signed_by_trust_anchor, verify_server_name,
14};
15
16mod config;
17pub use config::{
18    ClientConfig, ClientCredentialResolver, ClientSessionKey, ClientSessionStore,
19    CredentialRequest, Resumption, Tls12Resumption, WantsClientCert,
20};
21
22mod connection;
23#[cfg(feature = "std")]
24pub use connection::{ClientConnection, WriteEarlyData};
25pub use connection::{
26    ClientConnectionData, EarlyDataError, MayEncryptEarlyData, UnbufferedClientConnection,
27};
28
29mod ech;
30pub use ech::{EchConfig, EchGreaseConfig, EchMode, EchStatus};
31
32mod handy;
33#[cfg(any(feature = "std", feature = "hashbrown"))]
34pub use handy::ClientSessionMemoryCache;
35
36mod hs;
37pub(crate) use hs::ClientHandler;
38
39mod tls12;
40pub(crate) use tls12::TLS12_HANDLER;
41
42mod tls13;
43pub(crate) use tls13::TLS13_HANDLER;
44
45/// Dangerous configuration that should be audited and used with extreme care.
46pub mod danger {
47    pub use super::config::danger::{DangerousClientConfig, DangerousClientConfigBuilder};
48    pub use crate::verify::{
49        HandshakeSignatureValid, PeerVerified, ServerIdentity, ServerVerifier,
50        SignatureVerificationInput,
51    };
52}
53
54#[cfg(test)]
55mod test;
56
57#[derive(Debug)]
58struct ServerCertDetails {
59    cert_chain: CertificateChain<'static>,
60    ocsp_response: Vec<u8>,
61}
62
63impl ServerCertDetails {
64    fn new(cert_chain: CertificateChain<'static>, ocsp_response: Vec<u8>) -> Self {
65        Self {
66            cert_chain,
67            ocsp_response,
68        }
69    }
70}
71
72struct ClientHelloDetails {
73    alpn_protocols: Vec<ProtocolName>,
74    sent_extensions: Vec<ExtensionType>,
75    extension_order_seed: u16,
76    offered_cert_compression: bool,
77}
78
79impl ClientHelloDetails {
80    fn new(alpn_protocols: Vec<ProtocolName>, extension_order_seed: u16) -> Self {
81        Self {
82            alpn_protocols,
83            sent_extensions: Vec::new(),
84            extension_order_seed,
85            offered_cert_compression: false,
86        }
87    }
88
89    fn server_sent_unsolicited_extensions(
90        &self,
91        received_exts: &ServerExtensions<'_>,
92        allowed_unsolicited: &[ExtensionType],
93    ) -> bool {
94        let mut extensions = received_exts.collect_used();
95        extensions.extend(
96            received_exts
97                .unknown_extensions
98                .iter()
99                .map(|ext| ExtensionType::from(*ext)),
100        );
101        for ext_type in extensions {
102            if !self.sent_extensions.contains(&ext_type) && !allowed_unsolicited.contains(&ext_type)
103            {
104                trace!("Unsolicited extension {ext_type:?}");
105                return true;
106            }
107        }
108
109        false
110    }
111}
112
113enum ClientAuthDetails {
114    /// Send an empty `Certificate` and no `CertificateVerify`.
115    Empty { auth_context_tls13: Option<Vec<u8>> },
116    /// Send a non-empty `Certificate` and a `CertificateVerify`.
117    Verify {
118        credentials: SelectedCredential,
119        auth_context_tls13: Option<Vec<u8>>,
120        compressor: Option<&'static dyn compress::CertCompressor>,
121    },
122}
123
124impl ClientAuthDetails {
125    fn resolve(
126        negotiated_type: CertificateType,
127        resolver: &dyn ClientCredentialResolver,
128        root_hint_subjects: Option<&[DistinguishedName]>,
129        signature_schemes: &[SignatureScheme],
130        auth_context_tls13: Option<Vec<u8>>,
131        compressor: Option<&'static dyn compress::CertCompressor>,
132    ) -> Self {
133        let server_hello = CredentialRequest {
134            negotiated_type,
135            signature_schemes,
136            root_hint_subjects: root_hint_subjects.unwrap_or_default(),
137        };
138
139        if let Some(credentials) = resolver.resolve(&server_hello) {
140            debug!("Attempting client auth");
141            return Self::Verify {
142                credentials,
143                auth_context_tls13,
144                compressor,
145            };
146        }
147
148        debug!("Client auth requested but no cert/sigscheme available");
149        Self::Empty { auth_context_tls13 }
150    }
151}