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
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    /// An implementer of `StoresServerSessions` that stores everything
37    /// in memory.  It enforces a limit on the number of stored sessions
38    /// to bound memory usage.
39    pub struct ServerSessionMemoryCache {
40        cache: Mutex<limited_cache::LimitedCache<Vec<u8>, Vec<u8>>>,
41    }
42
43    impl ServerSessionMemoryCache {
44        /// Make a new ServerSessionMemoryCache.  `size` is the maximum
45        /// number of stored sessions, and may be rounded-up for
46        /// efficiency.
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
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        /// After five sessions are put into a cache of size 2, exactly the
120        /// two most recently added sessions remain.
121        #[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        /// A cache of size 1 keeps the session put into it, and a second
138        /// put replaces it.
139        #[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    /// Something that resolves do different cert chains/keys based
169    /// on client-supplied server name (via SNI).
170    #[derive(Debug)]
171    pub struct ServerNameResolver {
172        by_name: HashMap<DnsName<'static>, Arc<Credentials>>,
173    }
174
175    impl ServerNameResolver {
176        /// Create a new and empty (i.e., knows no certificates) resolver.
177        pub fn new() -> Self {
178            Self {
179                by_name: HashMap::new(),
180            }
181        }
182
183        /// Add a new `Credentials` to be used for the given SNI `name`.
184        ///
185        /// This function fails if the `name` is not valid for the supplied certificate, or if
186        /// the certificate chain is syntactically faulty.
187        pub fn add(&mut self, name: DnsName<'static>, ck: Credentials) -> Result<(), Error> {
188            // Check the certificate chain for validity:
189            // - it should be non-empty list
190            // - the first certificate should be parsable as a x509v3,
191            // - the first certificate should quote the given server name
192            //   (if provided)
193            //
194            // These checks are not security-sensitive.  They are the
195            // *server* attempting to detect accidental misconfiguration.
196
197            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}