1use alloc::vec::Vec;
2use core::fmt::Debug;
3
4use crate::server::{ServerSessionKey, StoresServerSessions};
5
6#[expect(clippy::exhaustive_structs)]
8#[derive(Debug)]
9pub struct NoServerSessionStorage {}
10
11impl StoresServerSessions for NoServerSessionStorage {
12 fn put(&self, _id: ServerSessionKey<'_>, _sec: Vec<u8>) -> bool {
13 false
14 }
15 fn get(&self, _id: ServerSessionKey<'_>) -> Option<Vec<u8>> {
16 None
17 }
18 fn take(&self, _id: ServerSessionKey<'_>) -> Option<Vec<u8>> {
19 None
20 }
21 fn can_cache(&self) -> bool {
22 false
23 }
24}
25
26mod cache {
27 use core::fmt::Formatter;
28
29 use super::*;
30 use crate::limited_cache;
31 use crate::lock::Mutex;
32 use crate::server::StoresServerSessions;
33 use crate::sync::Arc;
34
35 pub struct ServerSessionMemoryCache {
39 cache: Mutex<limited_cache::LimitedCache<Vec<u8>, Vec<u8>>>,
40 }
41
42 impl ServerSessionMemoryCache {
43 pub fn new(size: usize) -> Arc<Self> {
47 Arc::new(Self {
48 cache: Mutex::new(limited_cache::LimitedCache::new(size)),
49 })
50 }
51 }
52
53 impl StoresServerSessions for ServerSessionMemoryCache {
54 fn put(&self, key: ServerSessionKey<'_>, value: Vec<u8>) -> bool {
55 self.cache
56 .lock()
57 .unwrap()
58 .insert(key.as_ref().to_vec(), value);
59 true
60 }
61
62 fn get(&self, key: ServerSessionKey<'_>) -> Option<Vec<u8>> {
63 self.cache
64 .lock()
65 .unwrap()
66 .get(key.as_ref())
67 .cloned()
68 }
69
70 fn take(&self, key: ServerSessionKey<'_>) -> Option<Vec<u8>> {
71 self.cache
72 .lock()
73 .unwrap()
74 .remove(key.as_ref())
75 }
76
77 fn can_cache(&self) -> bool {
78 true
79 }
80 }
81
82 impl Debug for ServerSessionMemoryCache {
83 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
84 f.debug_struct("ServerSessionMemoryCache")
85 .finish_non_exhaustive()
86 }
87 }
88
89 #[cfg(test)]
90 mod tests {
91 use std::vec;
92
93 use super::*;
94 use crate::server::StoresServerSessions;
95
96 #[test]
97 fn test_serversessionmemorycache_accepts_put() {
98 let c = ServerSessionMemoryCache::new(4);
99 assert!(c.put(ServerSessionKey::new(&[0x01]), vec![0x02]));
100 }
101
102 #[test]
103 fn test_serversessionmemorycache_persists_put() {
104 let c = ServerSessionMemoryCache::new(4);
105 assert!(c.put(ServerSessionKey::new(&[0x01]), vec![0x02]));
106 assert_eq!(c.get(ServerSessionKey::new(&[0x01])), Some(vec![0x02]));
107 assert_eq!(c.get(ServerSessionKey::new(&[0x01])), Some(vec![0x02]));
108 }
109
110 #[test]
111 fn test_serversessionmemorycache_overwrites_put() {
112 let c = ServerSessionMemoryCache::new(4);
113 assert!(c.put(ServerSessionKey::new(&[0x01]), vec![0x02]));
114 assert!(c.put(ServerSessionKey::new(&[0x01]), vec![0x04]));
115 assert_eq!(c.get(ServerSessionKey::new(&[0x01])), Some(vec![0x04]));
116 }
117
118 #[test]
119 fn test_serversessionmemorycache_drops_to_maintain_size_invariant() {
120 let c = ServerSessionMemoryCache::new(2);
121 assert!(c.put(ServerSessionKey::new(&[0x01]), vec![0x02]));
122 assert!(c.put(ServerSessionKey::new(&[0x03]), vec![0x04]));
123 assert!(c.put(ServerSessionKey::new(&[0x05]), vec![0x06]));
124 assert!(c.put(ServerSessionKey::new(&[0x07]), vec![0x08]));
125 assert!(c.put(ServerSessionKey::new(&[0x09]), vec![0x0a]));
126
127 let count = c
128 .get(ServerSessionKey::new(&[0x01]))
129 .iter()
130 .count()
131 + c.get(ServerSessionKey::new(&[0x03]))
132 .iter()
133 .count()
134 + c.get(ServerSessionKey::new(&[0x05]))
135 .iter()
136 .count()
137 + c.get(ServerSessionKey::new(&[0x07]))
138 .iter()
139 .count()
140 + c.get(ServerSessionKey::new(&[0x09]))
141 .iter()
142 .count();
143
144 assert!(count < 5);
145 }
146 }
147}
148
149pub use cache::ServerSessionMemoryCache;
150
151#[cfg(feature = "webpki")]
152mod sni_resolver {
153 use core::fmt::Debug;
154
155 use pki_types::{DnsName, ServerName};
156
157 use crate::crypto::{CertificateIdentity, Credentials, Identity, SelectedCredential};
158 use crate::error::{Error, PeerIncompatible};
159 use crate::hash_map::HashMap;
160 use crate::server::{self, ClientHello};
161 use crate::sync::Arc;
162 use crate::webpki::{ParsedCertificate, verify_server_name};
163
164 #[derive(Debug)]
167 pub struct ServerNameResolver {
168 by_name: HashMap<DnsName<'static>, Arc<Credentials>>,
169 }
170
171 impl ServerNameResolver {
172 pub fn new() -> Self {
174 Self {
175 by_name: HashMap::new(),
176 }
177 }
178
179 pub fn add(&mut self, name: DnsName<'static>, ck: Credentials) -> Result<(), Error> {
184 let wrapped = ServerName::DnsName(name);
194 if let Identity::X509(CertificateIdentity { end_entity, .. }) = &*ck.identity {
195 let parsed = ParsedCertificate::try_from(end_entity)?;
196 verify_server_name(&parsed, &wrapped)?;
197 }
198
199 let ServerName::DnsName(name) = wrapped else {
200 unreachable!()
201 };
202
203 self.by_name.insert(name, Arc::new(ck));
204 Ok(())
205 }
206 }
207
208 impl server::ServerCredentialResolver for ServerNameResolver {
209 fn resolve(&self, client_hello: &ClientHello<'_>) -> Result<SelectedCredential, Error> {
210 let Some(name) = client_hello.server_name() else {
211 return Err(PeerIncompatible::NoServerNameProvided.into());
212 };
213
214 let Some(credentials) = self.by_name.get(name) else {
215 return Err(Error::NoSuitableCertificate);
216 };
217
218 match credentials.signer(client_hello.signature_schemes) {
219 Some(signer) => Ok(signer),
220 None => Err(PeerIncompatible::NoSignatureSchemesInCommon.into()),
221 }
222 }
223 }
224
225 #[cfg(test)]
226 mod tests {
227 use alloc::borrow::Cow;
228
229 use super::*;
230 use crate::server::ServerCredentialResolver;
231
232 #[test]
233 fn test_server_name_resolver_requires_sni() {
234 let rscsni = ServerNameResolver::new();
235 assert!(
236 rscsni
237 .resolve(&ClientHello {
238 server_name: None,
239 signature_schemes: &[],
240 alpn: None,
241 server_cert_types: None,
242 client_cert_types: None,
243 cipher_suites: &[],
244 certificate_authorities: None,
245 named_groups: None,
246 })
247 .is_err()
248 );
249 }
250
251 #[test]
252 fn test_server_name_resolver_handles_unknown_name() {
253 let rscsni = ServerNameResolver::new();
254 let name = DnsName::try_from("hello.com")
255 .unwrap()
256 .to_owned();
257 assert!(
258 rscsni
259 .resolve(&ClientHello {
260 server_name: Some(Cow::Borrowed(&name)),
261 signature_schemes: &[],
262 alpn: None,
263 server_cert_types: None,
264 client_cert_types: None,
265 cipher_suites: &[],
266 certificate_authorities: None,
267 named_groups: None,
268 })
269 .is_err()
270 );
271 }
272 }
273}
274
275#[cfg(feature = "webpki")]
276pub use sni_resolver::ServerNameResolver;
277
278#[cfg(test)]
279mod tests {
280 use std::vec;
281
282 use super::*;
283 use crate::server::StoresServerSessions;
284
285 #[test]
286 fn test_noserversessionstorage_drops_put() {
287 let c = NoServerSessionStorage {};
288 assert!(!c.put(ServerSessionKey::new(&[0x01]), vec![0x02]));
289 }
290
291 #[test]
292 fn test_noserversessionstorage_denies_gets() {
293 let c = NoServerSessionStorage {};
294 c.put(ServerSessionKey::new(&[0x01]), vec![0x02]);
295 assert_eq!(c.get(ServerSessionKey::new(&[])), None);
296 assert_eq!(c.get(ServerSessionKey::new(&[0x01])), None);
297 assert_eq!(c.get(ServerSessionKey::new(&[0x02])), None);
298 }
299
300 #[test]
301 fn test_noserversessionstorage_denies_takes() {
302 let c = NoServerSessionStorage {};
303 assert_eq!(c.take(ServerSessionKey::new(&[])), None);
304 assert_eq!(c.take(ServerSessionKey::new(&[0x01])), None);
305 assert_eq!(c.take(ServerSessionKey::new(&[0x02])), None);
306 }
307}