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