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