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.  If 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        #[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    /// Something that resolves do different cert chains/keys based
165    /// on client-supplied server name (via SNI).
166    #[derive(Debug)]
167    pub struct ServerNameResolver {
168        by_name: HashMap<DnsName<'static>, Arc<Credentials>>,
169    }
170
171    impl ServerNameResolver {
172        /// Create a new and empty (i.e., knows no certificates) resolver.
173        pub fn new() -> Self {
174            Self {
175                by_name: HashMap::new(),
176            }
177        }
178
179        /// Add a new `Credentials` to be used for the given SNI `name`.
180        ///
181        /// This function fails if the `name` is not valid for the supplied certificate, or if
182        /// the certificate chain is syntactically faulty.
183        pub fn add(&mut self, name: DnsName<'static>, ck: Credentials) -> Result<(), Error> {
184            // Check the certificate chain for validity:
185            // - it should be non-empty list
186            // - the first certificate should be parsable as a x509v3,
187            // - the first certificate should quote the given server name
188            //   (if provided)
189            //
190            // These checks are not security-sensitive.  They are the
191            // *server* attempting to detect accidental misconfiguration.
192
193            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}