rustls/client/
handy.rs

1use pki_types::ServerName;
2
3use super::CredentialRequest;
4use crate::crypto::{Credentials, SelectedCredential};
5use crate::enums::CertificateType;
6use crate::msgs::persist;
7use crate::{NamedGroup, client};
8
9/// An implementer of `ClientSessionStore` which does nothing.
10#[derive(Debug)]
11pub(super) struct NoClientSessionStorage;
12
13impl client::ClientSessionStore for NoClientSessionStorage {
14    fn set_kx_hint(&self, _: ServerName<'static>, _: NamedGroup) {}
15
16    fn kx_hint(&self, _: &ServerName<'_>) -> Option<NamedGroup> {
17        None
18    }
19
20    fn set_tls12_session(&self, _: ServerName<'static>, _: persist::Tls12ClientSessionValue) {}
21
22    fn tls12_session(&self, _: &ServerName<'_>) -> Option<persist::Tls12ClientSessionValue> {
23        None
24    }
25
26    fn remove_tls12_session(&self, _: &ServerName<'_>) {}
27
28    fn insert_tls13_ticket(&self, _: ServerName<'static>, _: persist::Tls13ClientSessionValue) {}
29
30    fn take_tls13_ticket(&self, _: &ServerName<'_>) -> Option<persist::Tls13ClientSessionValue> {
31        None
32    }
33}
34
35#[cfg(any(feature = "std", feature = "hashbrown"))]
36mod cache {
37    use alloc::collections::VecDeque;
38    use core::fmt;
39
40    use pki_types::ServerName;
41
42    use crate::lock::Mutex;
43    use crate::msgs::persist;
44    use crate::{NamedGroup, limited_cache};
45
46    const MAX_TLS13_TICKETS_PER_SERVER: usize = 8;
47
48    struct ServerData {
49        kx_hint: Option<NamedGroup>,
50
51        // Zero or one TLS1.2 sessions.
52        tls12: Option<persist::Tls12ClientSessionValue>,
53
54        // Up to MAX_TLS13_TICKETS_PER_SERVER TLS1.3 tickets, oldest first.
55        tls13: VecDeque<persist::Tls13ClientSessionValue>,
56    }
57
58    impl Default for ServerData {
59        fn default() -> Self {
60            Self {
61                kx_hint: None,
62                tls12: None,
63                tls13: VecDeque::with_capacity(MAX_TLS13_TICKETS_PER_SERVER),
64            }
65        }
66    }
67
68    /// An implementer of `ClientSessionStore` that stores everything
69    /// in memory.
70    ///
71    /// It enforces a limit on the number of entries to bound memory usage.
72    pub struct ClientSessionMemoryCache {
73        servers: Mutex<limited_cache::LimitedCache<ServerName<'static>, ServerData>>,
74    }
75
76    impl ClientSessionMemoryCache {
77        /// Make a new ClientSessionMemoryCache.  `size` is the
78        /// maximum number of stored sessions.
79        #[cfg(feature = "std")]
80        pub fn new(size: usize) -> Self {
81            let max_servers = size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1)
82                / MAX_TLS13_TICKETS_PER_SERVER;
83            Self {
84                servers: Mutex::new(limited_cache::LimitedCache::new(max_servers)),
85            }
86        }
87
88        /// Make a new ClientSessionMemoryCache.  `size` is the
89        /// maximum number of stored sessions.
90        #[cfg(not(feature = "std"))]
91        pub fn new<M: crate::lock::MakeMutex>(size: usize) -> Self {
92            let max_servers = size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1)
93                / MAX_TLS13_TICKETS_PER_SERVER;
94            Self {
95                servers: Mutex::new::<M>(limited_cache::LimitedCache::new(max_servers)),
96            }
97        }
98    }
99
100    impl super::client::ClientSessionStore for ClientSessionMemoryCache {
101        fn set_kx_hint(&self, server_name: ServerName<'static>, group: NamedGroup) {
102            self.servers
103                .lock()
104                .unwrap()
105                .get_or_insert_default_and_edit(server_name, |data| data.kx_hint = Some(group));
106        }
107
108        fn kx_hint(&self, server_name: &ServerName<'_>) -> Option<NamedGroup> {
109            self.servers
110                .lock()
111                .unwrap()
112                .get(server_name)
113                .and_then(|sd| sd.kx_hint)
114        }
115
116        fn set_tls12_session(
117            &self,
118            server_name: ServerName<'static>,
119            value: persist::Tls12ClientSessionValue,
120        ) {
121            self.servers
122                .lock()
123                .unwrap()
124                .get_or_insert_default_and_edit(server_name.clone(), |data| {
125                    data.tls12 = Some(value)
126                });
127        }
128
129        fn tls12_session(
130            &self,
131            server_name: &ServerName<'_>,
132        ) -> Option<persist::Tls12ClientSessionValue> {
133            self.servers
134                .lock()
135                .unwrap()
136                .get(server_name)
137                .and_then(|sd| sd.tls12.as_ref().cloned())
138        }
139
140        fn remove_tls12_session(&self, server_name: &ServerName<'static>) {
141            self.servers
142                .lock()
143                .unwrap()
144                .get_mut(server_name)
145                .and_then(|data| data.tls12.take());
146        }
147
148        fn insert_tls13_ticket(
149            &self,
150            server_name: ServerName<'static>,
151            value: persist::Tls13ClientSessionValue,
152        ) {
153            self.servers
154                .lock()
155                .unwrap()
156                .get_or_insert_default_and_edit(server_name.clone(), |data| {
157                    if data.tls13.len() == data.tls13.capacity() {
158                        data.tls13.pop_front();
159                    }
160                    data.tls13.push_back(value);
161                });
162        }
163
164        fn take_tls13_ticket(
165            &self,
166            server_name: &ServerName<'static>,
167        ) -> Option<persist::Tls13ClientSessionValue> {
168            self.servers
169                .lock()
170                .unwrap()
171                .get_mut(server_name)
172                .and_then(|data| data.tls13.pop_back())
173        }
174    }
175
176    impl fmt::Debug for ClientSessionMemoryCache {
177        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178            // Note: we omit self.servers as it may contain sensitive data.
179            f.debug_struct("ClientSessionMemoryCache")
180                .finish()
181        }
182    }
183}
184
185#[cfg(any(feature = "std", feature = "hashbrown"))]
186pub use cache::ClientSessionMemoryCache;
187
188#[derive(Debug)]
189pub(super) struct FailResolveClientCert {}
190
191impl client::ClientCredentialResolver for FailResolveClientCert {
192    fn resolve(&self, _: &CredentialRequest<'_>) -> Option<SelectedCredential> {
193        None
194    }
195
196    fn supported_certificate_types(&self) -> &'static [CertificateType] {
197        &[]
198    }
199}
200
201/// An exemplar `ClientCredentialResolver` implementation that always resolves to a single
202/// [RFC 7250] raw public key.
203///
204/// [RFC 7250]: https://tools.ietf.org/html/rfc7250
205#[derive(Debug)]
206pub struct AlwaysResolvesClientRawPublicKeys(Credentials);
207
208impl AlwaysResolvesClientRawPublicKeys {
209    /// Create a new `AlwaysResolvesClientRawPublicKeys` instance.
210    pub fn new(credentials: Credentials) -> Self {
211        Self(credentials)
212    }
213}
214
215impl client::ClientCredentialResolver for AlwaysResolvesClientRawPublicKeys {
216    fn resolve(&self, request: &CredentialRequest<'_>) -> Option<SelectedCredential> {
217        match request.negotiated_type() {
218            CertificateType::RawPublicKey => self
219                .0
220                .signer(request.signature_schemes()),
221            _ => None,
222        }
223    }
224
225    fn supported_certificate_types(&self) -> &'static [CertificateType] {
226        &[CertificateType::RawPublicKey]
227    }
228}
229
230#[cfg(test)]
231#[macro_rules_attribute::apply(test_for_each_provider)]
232mod tests {
233    use std::prelude::v1::*;
234
235    use pki_types::{CertificateDer, ServerName, UnixTime};
236
237    use super::NoClientSessionStorage;
238    use super::provider::cipher_suite;
239    use crate::client::danger::{HandshakeSignatureValid, PeerVerified, ServerVerifier};
240    use crate::client::{ClientCredentialResolver, ClientSessionStore, CredentialRequest};
241    use crate::crypto::{CertificateIdentity, Identity, SelectedCredential};
242    use crate::enums::{CertificateType, SignatureScheme};
243    use crate::error::Error;
244    use crate::msgs::base::PayloadU16;
245    use crate::msgs::enums::NamedGroup;
246    use crate::msgs::handshake::SessionId;
247    use crate::msgs::persist::Tls13ClientSessionValue;
248    use crate::sync::Arc;
249    use crate::verify::{ServerIdentity, SignatureVerificationInput};
250
251    #[test]
252    fn test_noclientsessionstorage_does_nothing() {
253        let c = NoClientSessionStorage {};
254        let name = ServerName::try_from("example.com").unwrap();
255        let now = UnixTime::now();
256        let server_cert_verifier: Arc<dyn ServerVerifier> = Arc::new(DummyServerVerifier);
257        let resolves_client_cert: Arc<dyn ClientCredentialResolver> =
258            Arc::new(DummyClientCredentialResolver);
259
260        c.set_kx_hint(name.clone(), NamedGroup::X25519);
261        assert_eq!(None, c.kx_hint(&name));
262
263        {
264            use crate::msgs::persist::Tls12ClientSessionValue;
265
266            c.set_tls12_session(
267                name.clone(),
268                Tls12ClientSessionValue::new(
269                    cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
270                    SessionId::empty(),
271                    Arc::new(PayloadU16::empty()),
272                    &[0u8; 48],
273                    Identity::X509(CertificateIdentity {
274                        end_entity: CertificateDer::from(&[][..]),
275                        intermediates: Vec::new(),
276                    }),
277                    &server_cert_verifier,
278                    &resolves_client_cert,
279                    now,
280                    0,
281                    true,
282                ),
283            );
284            assert!(c.tls12_session(&name).is_none());
285            c.remove_tls12_session(&name);
286        }
287
288        c.insert_tls13_ticket(
289            name.clone(),
290            Tls13ClientSessionValue::new(
291                cipher_suite::TLS13_AES_256_GCM_SHA384,
292                Arc::new(PayloadU16::empty()),
293                &[],
294                Identity::X509(CertificateIdentity {
295                    end_entity: CertificateDer::from(&[][..]),
296                    intermediates: Vec::new(),
297                }),
298                &server_cert_verifier,
299                &resolves_client_cert,
300                now,
301                0,
302                0,
303                0,
304            ),
305        );
306        assert!(c.take_tls13_ticket(&name).is_none());
307    }
308
309    #[derive(Debug)]
310    struct DummyServerVerifier;
311
312    impl ServerVerifier for DummyServerVerifier {
313        #[cfg_attr(coverage_nightly, coverage(off))]
314        fn verify_identity(&self, _identity: &ServerIdentity<'_>) -> Result<PeerVerified, Error> {
315            unreachable!()
316        }
317
318        #[cfg_attr(coverage_nightly, coverage(off))]
319        fn verify_tls12_signature(
320            &self,
321            _input: &SignatureVerificationInput<'_>,
322        ) -> Result<HandshakeSignatureValid, Error> {
323            unreachable!()
324        }
325
326        #[cfg_attr(coverage_nightly, coverage(off))]
327        fn verify_tls13_signature(
328            &self,
329            _input: &SignatureVerificationInput<'_>,
330        ) -> Result<HandshakeSignatureValid, Error> {
331            unreachable!()
332        }
333
334        #[cfg_attr(coverage_nightly, coverage(off))]
335        fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
336            unreachable!()
337        }
338
339        #[cfg_attr(coverage_nightly, coverage(off))]
340        fn request_ocsp_response(&self) -> bool {
341            unreachable!()
342        }
343    }
344
345    #[derive(Debug)]
346    struct DummyClientCredentialResolver;
347
348    impl ClientCredentialResolver for DummyClientCredentialResolver {
349        #[cfg_attr(coverage_nightly, coverage(off))]
350        fn resolve(&self, _: &CredentialRequest<'_>) -> Option<SelectedCredential> {
351            unreachable!()
352        }
353
354        #[cfg_attr(coverage_nightly, coverage(off))]
355        fn supported_certificate_types(&self) -> &'static [CertificateType] {
356            unreachable!()
357        }
358    }
359}