Skip to main content

rustls/server/
handy.rs

1use alloc::vec::Vec;
2use core::fmt::Debug;
3
4use crate::server::{ServerSessionKey, StoresServerSessions};
5
6/// Something which never stores sessions.
7#[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    /// An implementer of `StoresServerSessions` that stores everything
36    /// in memory.  It enforces a limit on the number of stored sessions
37    /// to bound memory usage.
38    pub struct ServerSessionMemoryCache {
39        cache: Mutex<limited_cache::LimitedCache<Vec<u8>, Vec<u8>>>,
40    }
41
42    impl ServerSessionMemoryCache {
43        /// Make a new ServerSessionMemoryCache.  `size` is the maximum
44        /// number of stored sessions, and may be rounded-up for
45        /// efficiency.
46        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        /// After five sessions are put into a cache of size 2, exactly the
119        /// two most recently added sessions remain.
120        #[test]
121        fn test_serversessionmemorycache_drops_to_maintain_size_invariant() {
122            let c = ServerSessionMemoryCache::new(2);
123            assert!(c.put(ServerSessionKey::new(&[0x01]), vec![0x02]));
124            assert!(c.put(ServerSessionKey::new(&[0x03]), vec![0x04]));
125            assert!(c.put(ServerSessionKey::new(&[0x05]), vec![0x06]));
126            assert!(c.put(ServerSessionKey::new(&[0x07]), vec![0x08]));
127            assert!(c.put(ServerSessionKey::new(&[0x09]), vec![0x0a]));
128
129            assert_eq!(c.get(ServerSessionKey::new(&[0x01])), None);
130            assert_eq!(c.get(ServerSessionKey::new(&[0x03])), None);
131            assert_eq!(c.get(ServerSessionKey::new(&[0x05])), None);
132            assert_eq!(c.get(ServerSessionKey::new(&[0x07])), Some(vec![0x08]));
133            assert_eq!(c.get(ServerSessionKey::new(&[0x09])), Some(vec![0x0a]));
134        }
135
136        /// A cache of size 1 keeps the session put into it, and a second
137        /// put replaces it.
138        #[test]
139        fn test_serversessionmemorycache_size_one_retains_session() {
140            let c = ServerSessionMemoryCache::new(1);
141            assert!(c.put(ServerSessionKey::new(&[0x01]), vec![0x02]));
142            assert_eq!(c.get(ServerSessionKey::new(&[0x01])), Some(vec![0x02]));
143
144            assert!(c.put(ServerSessionKey::new(&[0x03]), vec![0x04]));
145            assert_eq!(c.get(ServerSessionKey::new(&[0x01])), None);
146            assert_eq!(c.get(ServerSessionKey::new(&[0x03])), Some(vec![0x04]));
147        }
148    }
149}
150
151pub use cache::ServerSessionMemoryCache;
152
153#[cfg(feature = "webpki")]
154mod sni_resolver {
155    use core::fmt::Debug;
156
157    use pki_types::{DnsName, ServerName};
158
159    use crate::crypto::{CertificateIdentity, Credentials, Identity, SelectedCredential};
160    use crate::error::{Error, PeerIncompatible};
161    use crate::hash_map::HashMap;
162    use crate::server::{self, ClientHello};
163    use crate::sync::Arc;
164    use crate::webpki::{ParsedCertificate, verify_server_name};
165
166    /// Something that resolves do different cert chains/keys based
167    /// on client-supplied server name (via SNI).
168    #[derive(Debug)]
169    pub struct ServerNameResolver {
170        by_name: HashMap<DnsName<'static>, Arc<Credentials>>,
171    }
172
173    impl ServerNameResolver {
174        /// Create a new and empty (i.e., knows no certificates) resolver.
175        pub fn new() -> Self {
176            Self {
177                by_name: HashMap::new(),
178            }
179        }
180
181        /// Add a new `Credentials` to be used for the given SNI `name`.
182        ///
183        /// This function fails if the `name` is not valid for the supplied certificate, or if
184        /// the certificate chain is syntactically faulty.
185        pub fn add(&mut self, name: DnsName<'static>, ck: Credentials) -> Result<(), Error> {
186            // Check the certificate chain for validity:
187            // - it should be non-empty list
188            // - the first certificate should be parsable as a x509v3,
189            // - the first certificate should quote the given server name
190            //   (if provided)
191            //
192            // These checks are not security-sensitive.  They are the
193            // *server* attempting to detect accidental misconfiguration.
194
195            let wrapped = ServerName::DnsName(name);
196            if let Identity::X509(CertificateIdentity { end_entity, .. }) = &*ck.identity {
197                let parsed = ParsedCertificate::try_from(end_entity)?;
198                verify_server_name(&parsed, &wrapped)?;
199            }
200
201            let ServerName::DnsName(name) = wrapped else {
202                unreachable!()
203            };
204
205            self.by_name.insert(name, Arc::new(ck));
206            Ok(())
207        }
208    }
209
210    impl server::ServerCredentialResolver for ServerNameResolver {
211        fn resolve(&self, client_hello: &ClientHello<'_>) -> Result<SelectedCredential, Error> {
212            let Some(name) = client_hello.server_name() else {
213                return Err(PeerIncompatible::NoServerNameProvided.into());
214            };
215
216            let Some(credentials) = self.by_name.get(name) else {
217                return Err(Error::NoSuitableCertificate);
218            };
219
220            match credentials.signer(client_hello.signature_schemes) {
221                Some(signer) => Ok(signer),
222                None => Err(PeerIncompatible::NoSignatureSchemesInCommon.into()),
223            }
224        }
225    }
226
227    #[cfg(test)]
228    mod tests {
229        use alloc::borrow::Cow;
230
231        use super::*;
232        use crate::server::ServerCredentialResolver;
233
234        #[test]
235        fn test_server_name_resolver_requires_sni() {
236            let rscsni = ServerNameResolver::new();
237            assert!(
238                rscsni
239                    .resolve(&ClientHello::empty())
240                    .is_err()
241            );
242        }
243
244        #[test]
245        fn test_server_name_resolver_handles_unknown_name() {
246            let server_name = DnsName::try_from("hello.com")
247                .unwrap()
248                .to_owned();
249            let mut ch = ClientHello::empty();
250            ch.server_name = Some(Cow::Borrowed(&server_name));
251
252            let rscsni = ServerNameResolver::new();
253            assert!(rscsni.resolve(&ch).is_err());
254        }
255    }
256}
257
258#[cfg(feature = "webpki")]
259pub use sni_resolver::ServerNameResolver;
260
261#[cfg(test)]
262mod tests {
263    use std::vec;
264
265    use super::*;
266    use crate::server::StoresServerSessions;
267
268    #[test]
269    fn test_noserversessionstorage_drops_put() {
270        let c = NoServerSessionStorage {};
271        assert!(!c.put(ServerSessionKey::new(&[0x01]), vec![0x02]));
272    }
273
274    #[test]
275    fn test_noserversessionstorage_denies_gets() {
276        let c = NoServerSessionStorage {};
277        c.put(ServerSessionKey::new(&[0x01]), vec![0x02]);
278        assert_eq!(c.get(ServerSessionKey::new(&[])), None);
279        assert_eq!(c.get(ServerSessionKey::new(&[0x01])), None);
280        assert_eq!(c.get(ServerSessionKey::new(&[0x02])), None);
281    }
282
283    #[test]
284    fn test_noserversessionstorage_denies_takes() {
285        let c = NoServerSessionStorage {};
286        assert_eq!(c.take(ServerSessionKey::new(&[])), None);
287        assert_eq!(c.take(ServerSessionKey::new(&[0x01])), None);
288        assert_eq!(c.take(ServerSessionKey::new(&[0x02])), None);
289    }
290}