1use pki_types::ServerName;
2
3use crate::enums::SignatureScheme;
4use crate::msgs::persist;
5use crate::sync::Arc;
6use crate::{NamedGroup, client, sign};
7
8#[derive(Debug)]
10pub(super) struct NoClientSessionStorage;
11
12impl client::ClientSessionStore for NoClientSessionStorage {
13 fn set_kx_hint(&self, _: ServerName<'static>, _: NamedGroup) {}
14
15 fn kx_hint(&self, _: &ServerName<'_>) -> Option<NamedGroup> {
16 None
17 }
18
19 fn set_tls12_session(&self, _: ServerName<'static>, _: persist::Tls12ClientSessionValue) {}
20
21 fn tls12_session(&self, _: &ServerName<'_>) -> Option<persist::Tls12ClientSessionValue> {
22 None
23 }
24
25 fn remove_tls12_session(&self, _: &ServerName<'_>) {}
26
27 fn insert_tls13_ticket(&self, _: ServerName<'static>, _: persist::Tls13ClientSessionValue) {}
28
29 fn take_tls13_ticket(&self, _: &ServerName<'_>) -> Option<persist::Tls13ClientSessionValue> {
30 None
31 }
32}
33
34#[cfg(any(feature = "std", feature = "hashbrown"))]
35mod cache {
36 use alloc::collections::VecDeque;
37 use core::fmt;
38
39 use pki_types::ServerName;
40
41 use crate::lock::Mutex;
42 use crate::msgs::persist;
43 use crate::{NamedGroup, limited_cache};
44
45 const MAX_TLS13_TICKETS_PER_SERVER: usize = 8;
46
47 struct ServerData {
48 kx_hint: Option<NamedGroup>,
49
50 #[cfg(feature = "tls12")]
52 tls12: Option<persist::Tls12ClientSessionValue>,
53
54 tls13: VecDeque<persist::Tls13ClientSessionValue>,
56 }
57
58 impl Default for ServerData {
59 fn default() -> Self {
60 Self {
61 kx_hint: None,
62 #[cfg(feature = "tls12")]
63 tls12: None,
64 tls13: VecDeque::with_capacity(MAX_TLS13_TICKETS_PER_SERVER),
65 }
66 }
67 }
68
69 pub struct ClientSessionMemoryCache {
74 servers: Mutex<limited_cache::LimitedCache<ServerName<'static>, ServerData>>,
75 }
76
77 impl ClientSessionMemoryCache {
78 #[cfg(feature = "std")]
89 pub fn new(size: usize) -> Self {
90 let max_servers = size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1)
92 / MAX_TLS13_TICKETS_PER_SERVER;
93 Self {
94 servers: Mutex::new(limited_cache::LimitedCache::new(max_servers)),
95 }
96 }
97
98 #[cfg(not(feature = "std"))]
109 pub fn new<M: crate::lock::MakeMutex>(size: usize) -> Self {
110 let max_servers = size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1)
112 / MAX_TLS13_TICKETS_PER_SERVER;
113 Self {
114 servers: Mutex::new::<M>(limited_cache::LimitedCache::new(max_servers)),
115 }
116 }
117 }
118
119 impl super::client::ClientSessionStore for ClientSessionMemoryCache {
120 fn set_kx_hint(&self, server_name: ServerName<'static>, group: NamedGroup) {
121 self.servers
122 .lock()
123 .unwrap()
124 .get_or_insert_default_and_edit(server_name, |data| data.kx_hint = Some(group));
125 }
126
127 fn kx_hint(&self, server_name: &ServerName<'_>) -> Option<NamedGroup> {
128 self.servers
129 .lock()
130 .unwrap()
131 .get(server_name)
132 .and_then(|sd| sd.kx_hint)
133 }
134
135 fn set_tls12_session(
136 &self,
137 _server_name: ServerName<'static>,
138 _value: persist::Tls12ClientSessionValue,
139 ) {
140 #[cfg(feature = "tls12")]
141 self.servers
142 .lock()
143 .unwrap()
144 .get_or_insert_default_and_edit(_server_name.clone(), |data| {
145 data.tls12 = Some(_value)
146 });
147 }
148
149 fn tls12_session(
150 &self,
151 _server_name: &ServerName<'_>,
152 ) -> Option<persist::Tls12ClientSessionValue> {
153 #[cfg(not(feature = "tls12"))]
154 return None;
155
156 #[cfg(feature = "tls12")]
157 self.servers
158 .lock()
159 .unwrap()
160 .get(_server_name)
161 .and_then(|sd| sd.tls12.as_ref().cloned())
162 }
163
164 fn remove_tls12_session(&self, _server_name: &ServerName<'static>) {
165 #[cfg(feature = "tls12")]
166 self.servers
167 .lock()
168 .unwrap()
169 .get_mut(_server_name)
170 .and_then(|data| data.tls12.take());
171 }
172
173 fn insert_tls13_ticket(
174 &self,
175 server_name: ServerName<'static>,
176 value: persist::Tls13ClientSessionValue,
177 ) {
178 self.servers
179 .lock()
180 .unwrap()
181 .get_or_insert_default_and_edit(server_name.clone(), |data| {
182 if data.tls13.len() == data.tls13.capacity() {
183 data.tls13.pop_front();
184 }
185 data.tls13.push_back(value);
186 });
187 }
188
189 fn take_tls13_ticket(
190 &self,
191 server_name: &ServerName<'static>,
192 ) -> Option<persist::Tls13ClientSessionValue> {
193 self.servers
194 .lock()
195 .unwrap()
196 .get_mut(server_name)
197 .and_then(|data| data.tls13.pop_back())
198 }
199 }
200
201 impl fmt::Debug for ClientSessionMemoryCache {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 f.debug_struct("ClientSessionMemoryCache")
205 .finish()
206 }
207 }
208}
209
210#[cfg(any(feature = "std", feature = "hashbrown"))]
211pub use cache::ClientSessionMemoryCache;
212
213#[derive(Debug)]
214pub(super) struct FailResolveClientCert {}
215
216impl client::ResolvesClientCert for FailResolveClientCert {
217 fn resolve(
218 &self,
219 _root_hint_subjects: &[&[u8]],
220 _sigschemes: &[SignatureScheme],
221 ) -> Option<Arc<sign::CertifiedKey>> {
222 None
223 }
224
225 fn has_certs(&self) -> bool {
226 false
227 }
228}
229
230#[derive(Clone, Debug)]
235pub struct AlwaysResolvesClientRawPublicKeys(Arc<sign::CertifiedKey>);
236impl AlwaysResolvesClientRawPublicKeys {
237 pub fn new(certified_key: Arc<sign::CertifiedKey>) -> Self {
239 Self(certified_key)
240 }
241}
242
243impl client::ResolvesClientCert for AlwaysResolvesClientRawPublicKeys {
244 fn resolve(
245 &self,
246 _root_hint_subjects: &[&[u8]],
247 _sigschemes: &[SignatureScheme],
248 ) -> Option<Arc<sign::CertifiedKey>> {
249 Some(self.0.clone())
250 }
251
252 fn only_raw_public_keys(&self) -> bool {
253 true
254 }
255
256 fn has_certs(&self) -> bool {
261 true
262 }
263}
264
265#[cfg(test)]
266#[macro_rules_attribute::apply(test_for_each_provider)]
267mod tests {
268 use core::time::Duration;
269 use std::prelude::v1::*;
270 use std::{format, vec};
271
272 use pki_types::{ServerName, UnixTime};
273
274 #[cfg(feature = "std")]
275 use super::ClientSessionMemoryCache;
276 use super::NoClientSessionStorage;
277 use super::provider::cipher_suite;
278 use crate::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
279 use crate::client::{ClientSessionStore, ResolvesClientCert};
280 use crate::msgs::base::PayloadU16;
281 use crate::msgs::enums::NamedGroup;
282 use crate::msgs::handshake::CertificateChain;
283 #[cfg(feature = "tls12")]
284 use crate::msgs::handshake::SessionId;
285 use crate::msgs::persist::Tls13ClientSessionValue;
286 use crate::pki_types::CertificateDer;
287 use crate::suites::SupportedCipherSuite;
288 use crate::sync::Arc;
289 use crate::{DigitallySignedStruct, Error, SignatureScheme, sign};
290
291 #[test]
292 fn test_noclientsessionstorage_does_nothing() {
293 let c = NoClientSessionStorage {};
294 let name = ServerName::try_from("example.com").unwrap();
295 let now = UnixTime::now();
296 let server_cert_verifier: Arc<dyn ServerCertVerifier> = Arc::new(DummyServerCertVerifier);
297 let resolves_client_cert: Arc<dyn ResolvesClientCert> = Arc::new(DummyResolvesClientCert);
298
299 c.set_kx_hint(name.clone(), NamedGroup::X25519);
300 assert_eq!(None, c.kx_hint(&name));
301
302 #[cfg(feature = "tls12")]
303 {
304 use crate::msgs::persist::Tls12ClientSessionValue;
305 let SupportedCipherSuite::Tls12(tls12_suite) =
306 cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
307 else {
308 unreachable!()
309 };
310
311 c.set_tls12_session(
312 name.clone(),
313 Tls12ClientSessionValue::new(
314 tls12_suite,
315 SessionId::empty(),
316 Arc::new(PayloadU16::empty()),
317 &[],
318 CertificateChain::default(),
319 &server_cert_verifier,
320 &resolves_client_cert,
321 now,
322 0,
323 true,
324 ),
325 );
326 assert!(c.tls12_session(&name).is_none());
327 c.remove_tls12_session(&name);
328 }
329
330 let SupportedCipherSuite::Tls13(tls13_suite) = cipher_suite::TLS13_AES_256_GCM_SHA384
331 else {
332 unreachable!();
333 };
334 c.insert_tls13_ticket(
335 name.clone(),
336 Tls13ClientSessionValue::new(
337 tls13_suite,
338 Arc::new(PayloadU16::empty()),
339 &[],
340 CertificateChain::default(),
341 &server_cert_verifier,
342 &resolves_client_cert,
343 now,
344 0,
345 0,
346 0,
347 ),
348 );
349 assert!(c.take_tls13_ticket(&name).is_none());
350 }
351
352 #[test]
353 fn debug_of_session_types() {
354 let server_cert_verifier: Arc<dyn ServerCertVerifier> = Arc::new(DummyServerCertVerifier);
355 let resolves_client_cert: Arc<dyn ResolvesClientCert> = Arc::new(DummyResolvesClientCert);
356
357 #[cfg(feature = "tls12")]
358 {
359 use crate::msgs::persist::Tls12ClientSessionValue;
360 let SupportedCipherSuite::Tls12(tls12_suite) =
361 cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
362 else {
363 unreachable!()
364 };
365
366 let tls12 = Tls12ClientSessionValue::new(
367 tls12_suite,
368 SessionId::empty(),
369 Arc::new(PayloadU16::new(vec![5])),
370 &[0xa5; 48],
371 CertificateChain::default(),
372 &server_cert_verifier,
373 &resolves_client_cert,
374 UnixTime::since_unix_epoch(Duration::from_secs(1)),
375 2,
376 true,
377 );
378 let debug = format!("{tls12:?}");
379 assert!(
380 debug.contains("ClientSessionCommon { ticket: 05, epoch: 1, lifetime_secs: 2,")
381 );
382 assert!(!debug.contains("a5a5"), "{debug}");
383 }
384
385 let SupportedCipherSuite::Tls13(tls13_suite) = cipher_suite::TLS13_AES_256_GCM_SHA384
386 else {
387 unreachable!();
388 };
389 let tls13 = Tls13ClientSessionValue::new(
390 tls13_suite,
391 Arc::new(PayloadU16::new(vec![5])),
392 &[0xa5; 32],
393 CertificateChain::default(),
394 &server_cert_verifier,
395 &resolves_client_cert,
396 UnixTime::since_unix_epoch(Duration::from_secs(1)),
397 2,
398 3,
399 0,
400 );
401 let debug = format!("{tls13:?}");
402 assert!(debug.contains("ClientSessionCommon { ticket: 05, epoch: 1, lifetime_secs: 2,"));
403 assert!(!debug.contains("a5a5"), "{debug}");
404 }
405
406 #[cfg(feature = "std")]
409 #[test]
410 fn test_clientsessionmemorycache_small_sizes_retain_server() {
411 for size in 1..=8 {
412 let c = ClientSessionMemoryCache::new(size);
413 let name = ServerName::try_from("example.com").unwrap();
414
415 c.set_kx_hint(name.clone(), NamedGroup::X25519);
416 assert_eq!(c.kx_hint(&name), Some(NamedGroup::X25519), "size {size}");
417
418 c.insert_tls13_ticket(name.clone(), tls13_session(UnixTime::now()));
419 assert!(c.take_tls13_ticket(&name).is_some(), "size {size}");
420 }
421 }
422
423 #[cfg(feature = "std")]
426 #[test]
427 fn test_clientsessionmemorycache_evicts_oldest_server() {
428 let c = ClientSessionMemoryCache::new(9);
429 let first = ServerName::try_from("first.example.com").unwrap();
430 let second = ServerName::try_from("second.example.com").unwrap();
431 let third = ServerName::try_from("third.example.com").unwrap();
432
433 c.set_kx_hint(first.clone(), NamedGroup::X25519);
434 c.set_kx_hint(second.clone(), NamedGroup::X25519);
435 c.set_kx_hint(third.clone(), NamedGroup::X25519);
436
437 assert_eq!(c.kx_hint(&first), None);
438 assert_eq!(c.kx_hint(&second), Some(NamedGroup::X25519));
439 assert_eq!(c.kx_hint(&third), Some(NamedGroup::X25519));
440 }
441
442 #[cfg(feature = "std")]
446 fn tls13_session(now: UnixTime) -> Tls13ClientSessionValue {
447 let SupportedCipherSuite::Tls13(tls13_suite) = cipher_suite::TLS13_AES_256_GCM_SHA384
448 else {
449 unreachable!();
450 };
451 let server_cert_verifier: Arc<dyn ServerCertVerifier> = Arc::new(DummyServerCertVerifier);
452 let resolves_client_cert: Arc<dyn ResolvesClientCert> = Arc::new(DummyResolvesClientCert);
453 Tls13ClientSessionValue::new(
454 tls13_suite,
455 Arc::new(PayloadU16::empty()),
456 &[],
457 CertificateChain::default(),
458 &server_cert_verifier,
459 &resolves_client_cert,
460 now,
461 0,
462 0,
463 0,
464 )
465 }
466
467 #[derive(Debug)]
468 struct DummyServerCertVerifier;
469
470 impl ServerCertVerifier for DummyServerCertVerifier {
471 #[cfg_attr(coverage_nightly, coverage(off))]
472 fn verify_server_cert(
473 &self,
474 _end_entity: &CertificateDer<'_>,
475 _intermediates: &[CertificateDer<'_>],
476 _server_name: &ServerName<'_>,
477 _ocsp_response: &[u8],
478 _now: UnixTime,
479 ) -> Result<ServerCertVerified, Error> {
480 unreachable!()
481 }
482
483 #[cfg_attr(coverage_nightly, coverage(off))]
484 fn verify_tls12_signature(
485 &self,
486 _message: &[u8],
487 _cert: &CertificateDer<'_>,
488 _dss: &DigitallySignedStruct,
489 ) -> Result<HandshakeSignatureValid, Error> {
490 unreachable!()
491 }
492
493 #[cfg_attr(coverage_nightly, coverage(off))]
494 fn verify_tls13_signature(
495 &self,
496 _message: &[u8],
497 _cert: &CertificateDer<'_>,
498 _dss: &DigitallySignedStruct,
499 ) -> Result<HandshakeSignatureValid, Error> {
500 unreachable!()
501 }
502
503 #[cfg_attr(coverage_nightly, coverage(off))]
504 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
505 unreachable!()
506 }
507 }
508
509 #[derive(Debug)]
510 struct DummyResolvesClientCert;
511
512 impl ResolvesClientCert for DummyResolvesClientCert {
513 #[cfg_attr(coverage_nightly, coverage(off))]
514 fn resolve(
515 &self,
516 _root_hint_subjects: &[&[u8]],
517 _sigschemes: &[SignatureScheme],
518 ) -> Option<Arc<sign::CertifiedKey>> {
519 unreachable!()
520 }
521
522 #[cfg_attr(coverage_nightly, coverage(off))]
523 fn has_certs(&self) -> bool {
524 unreachable!()
525 }
526 }
527}