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::{SessionId, SizedPayload};
189 use crate::sync::Arc;
190
191 #[test]
192 fn test_noclientsessionstorage_does_nothing() {
193 let c = NoClientSessionStorage {};
194 let server_name = ServerName::try_from("example.com").unwrap();
195 let key = ClientSessionKey {
196 config_hash: Default::default(),
197 server_name,
198 };
199 let now = UnixTime::now();
200
201 c.set_kx_hint(key.clone(), NamedGroup::X25519);
202 assert_eq!(None, c.kx_hint(&key));
203
204 {
205 c.set_tls12_session(
206 key.clone(),
207 Tls12Session::new(
208 tls12_suite(CipherSuite::Unknown(0xff12), &TEST_PROVIDER),
209 SessionId::empty(),
210 Arc::new(SizedPayload::empty()),
211 &[0u8; 48],
212 Identity::X509(CertificateIdentity {
213 end_entity: CertificateDer::from(&[][..]),
214 intermediates: Vec::new(),
215 }),
216 now,
217 Duration::ZERO,
218 true,
219 ),
220 );
221 assert!(c.tls12_session(&key).is_none());
222 c.remove_tls12_session(&key);
223 }
224
225 c.insert_tls13_ticket(
226 key.clone(),
227 Tls13Session::new(
228 Tls13ClientSessionInput {
229 suite: tls13_suite(CipherSuite::Unknown(0xff13), &TEST_PROVIDER),
230 peer_identity: Identity::X509(CertificateIdentity {
231 end_entity: CertificateDer::from(&[][..]),
232 intermediates: Vec::new(),
233 }),
234 quic_params: None,
235 },
236 Arc::new(SizedPayload::empty()),
237 &[],
238 now,
239 Duration::ZERO,
240 0,
241 0,
242 ),
243 );
244
245 assert!(c.take_tls13_ticket(&key).is_none());
246 }
247}