1use core::hash::Hasher;
2
3use super::config::{ClientCredentialResolver, ClientSessionStore};
4use super::{ClientSessionKey, CredentialRequest, Tls12Session, Tls13Session};
5use crate::crypto::SelectedCredential;
6use crate::crypto::kx::NamedGroup;
7use crate::enums::CertificateType;
8
9#[derive(Debug)]
11pub(super) struct NoClientSessionStorage;
12
13impl ClientSessionStore for NoClientSessionStorage {
14 fn set_kx_hint(&self, _: ClientSessionKey<'static>, _: NamedGroup) {}
15
16 fn kx_hint(&self, _: &ClientSessionKey<'_>) -> Option<NamedGroup> {
17 None
18 }
19
20 fn set_tls12_session(&self, _: ClientSessionKey<'static>, _: Tls12Session) {}
21
22 fn tls12_session(&self, _: &ClientSessionKey<'_>) -> Option<Tls12Session> {
23 None
24 }
25
26 fn remove_tls12_session(&self, _: &ClientSessionKey<'_>) {}
27
28 fn insert_tls13_ticket(&self, _: ClientSessionKey<'static>, _: Tls13Session) {}
29
30 fn take_tls13_ticket(&self, _: &ClientSessionKey<'_>) -> Option<Tls13Session> {
31 None
32 }
33}
34
35mod cache {
36 use alloc::collections::VecDeque;
37 use core::fmt;
38
39 use super::*;
40 use crate::client::Tls13Session;
41 use crate::crypto::kx::NamedGroup;
42 use crate::limited_cache;
43 use crate::lock::Mutex;
44
45 const MAX_TLS13_TICKETS_PER_SERVER: usize = 8;
46
47 struct ServerData {
48 kx_hint: Option<NamedGroup>,
49
50 tls12: Option<Tls12Session>,
52
53 tls13: VecDeque<Tls13Session>,
55 }
56
57 impl Default for ServerData {
58 fn default() -> Self {
59 Self {
60 kx_hint: None,
61 tls12: None,
62 tls13: VecDeque::with_capacity(MAX_TLS13_TICKETS_PER_SERVER),
63 }
64 }
65 }
66
67 pub struct ClientSessionMemoryCache {
72 servers: Mutex<limited_cache::LimitedCache<ClientSessionKey<'static>, ServerData>>,
73 }
74
75 impl ClientSessionMemoryCache {
76 pub fn new(size: usize) -> Self {
79 let max_servers = size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1)
80 / MAX_TLS13_TICKETS_PER_SERVER;
81 Self {
82 servers: Mutex::new(limited_cache::LimitedCache::new(max_servers)),
83 }
84 }
85 }
86
87 impl ClientSessionStore for ClientSessionMemoryCache {
88 fn set_kx_hint(&self, key: ClientSessionKey<'static>, group: NamedGroup) {
89 self.servers
90 .lock()
91 .unwrap()
92 .get_or_insert_default_and_edit(key, |data| data.kx_hint = Some(group));
93 }
94
95 fn kx_hint(&self, key: &ClientSessionKey<'_>) -> Option<NamedGroup> {
96 self.servers
97 .lock()
98 .unwrap()
99 .get(key)
100 .and_then(|sd| sd.kx_hint)
101 }
102
103 fn set_tls12_session(&self, key: ClientSessionKey<'static>, value: Tls12Session) {
104 self.servers
105 .lock()
106 .unwrap()
107 .get_or_insert_default_and_edit(key.clone(), |data| data.tls12 = Some(value));
108 }
109
110 fn tls12_session(&self, key: &ClientSessionKey<'_>) -> Option<Tls12Session> {
111 self.servers
112 .lock()
113 .unwrap()
114 .get(key)
115 .and_then(|sd| sd.tls12.as_ref().cloned())
116 }
117
118 fn remove_tls12_session(&self, key: &ClientSessionKey<'static>) {
119 self.servers
120 .lock()
121 .unwrap()
122 .get_mut(key)
123 .and_then(|data| data.tls12.take());
124 }
125
126 fn insert_tls13_ticket(&self, key: ClientSessionKey<'static>, value: Tls13Session) {
127 self.servers
128 .lock()
129 .unwrap()
130 .get_or_insert_default_and_edit(key.clone(), |data| {
131 if data.tls13.len() == data.tls13.capacity() {
132 data.tls13.pop_front();
133 }
134 data.tls13.push_back(value);
135 });
136 }
137
138 fn take_tls13_ticket(&self, key: &ClientSessionKey<'static>) -> Option<Tls13Session> {
139 self.servers
140 .lock()
141 .unwrap()
142 .get_mut(key)
143 .and_then(|data| data.tls13.pop_back())
144 }
145 }
146
147 impl fmt::Debug for ClientSessionMemoryCache {
148 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149 f.debug_struct("ClientSessionMemoryCache")
151 .finish_non_exhaustive()
152 }
153 }
154}
155
156pub use cache::ClientSessionMemoryCache;
157
158#[derive(Debug)]
159pub(super) struct FailResolveClientCert {}
160
161impl ClientCredentialResolver for FailResolveClientCert {
162 fn resolve(&self, _: &CredentialRequest<'_>) -> Option<SelectedCredential> {
163 None
164 }
165
166 fn supported_certificate_types(&self) -> &'static [CertificateType] {
167 &[]
168 }
169
170 fn hash_config(&self, _: &mut dyn Hasher) {}
171}
172
173#[cfg(test)]
174mod tests {
175 use alloc::vec::Vec;
176 use core::time::Duration;
177
178 use pki_types::{CertificateDer, ServerName, UnixTime};
179
180 use super::NoClientSessionStorage;
181 use crate::client::{
182 ClientSessionKey, ClientSessionStore, Tls12Session, Tls13ClientSessionInput, Tls13Session,
183 };
184 use crate::crypto::kx::NamedGroup;
185 use crate::crypto::{
186 CertificateIdentity, CipherSuite, Identity, TEST_PROVIDER, tls12_suite, tls13_suite,
187 };
188 use crate::msgs::{
189 NewSessionTicketExtensions, NewSessionTicketPayloadTls13, SessionId, SizedPayload,
190 };
191 use crate::sync::Arc;
192
193 #[test]
194 fn test_noclientsessionstorage_does_nothing() {
195 let c = NoClientSessionStorage {};
196 let server_name = ServerName::try_from("example.com").unwrap();
197 let key = ClientSessionKey {
198 config_hash: Default::default(),
199 server_name,
200 };
201 let now = UnixTime::now();
202
203 c.set_kx_hint(key.clone(), NamedGroup::X25519);
204 assert_eq!(None, c.kx_hint(&key));
205
206 {
207 c.set_tls12_session(
208 key.clone(),
209 Tls12Session::new(
210 tls12_suite(CipherSuite(0xff12), &TEST_PROVIDER),
211 SessionId::empty(),
212 Arc::new(SizedPayload::empty()),
213 &[0u8; 48],
214 Identity::X509(CertificateIdentity {
215 end_entity: CertificateDer::from(&[][..]),
216 intermediates: Vec::new(),
217 }),
218 now,
219 Duration::ZERO,
220 true,
221 ),
222 );
223 assert!(c.tls12_session(&key).is_none());
224 c.remove_tls12_session(&key);
225 }
226
227 c.insert_tls13_ticket(
228 key.clone(),
229 Tls13Session::new(
230 &NewSessionTicketPayloadTls13 {
231 lifetime: Duration::ZERO,
232 age_add: 0,
233 nonce: SizedPayload::empty(),
234 ticket: Arc::new(SizedPayload::empty()),
235 extensions: NewSessionTicketExtensions {
236 max_early_data_size: None,
237 },
238 },
239 Tls13ClientSessionInput {
240 suite: tls13_suite(CipherSuite(0xff13), &TEST_PROVIDER),
241 peer_identity: Identity::X509(CertificateIdentity {
242 end_entity: CertificateDer::from(&[][..]),
243 intermediates: Vec::new(),
244 }),
245 quic_params: None,
246 },
247 &[],
248 now,
249 ),
250 );
251
252 assert!(c.take_tls13_ticket(&key).is_none());
253 }
254}