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