Skip to main content

rustls/server/
handy.rs

1use alloc::vec::Vec;
2use core::fmt::Debug;
3
4use crate::server::ClientHello;
5use crate::sync::Arc;
6use crate::{server, sign};
7
8/// Something which never stores sessions.
9#[derive(Debug)]
10pub struct NoServerSessionStorage {}
11
12impl server::StoresServerSessions for NoServerSessionStorage {
13    fn put(&self, _id: Vec<u8>, _sec: Vec<u8>) -> bool {
14        false
15    }
16    fn get(&self, _id: &[u8]) -> Option<Vec<u8>> {
17        None
18    }
19    fn take(&self, _id: &[u8]) -> Option<Vec<u8>> {
20        None
21    }
22    fn can_cache(&self) -> bool {
23        false
24    }
25}
26
27#[cfg(any(feature = "std", feature = "hashbrown"))]
28mod cache {
29    use alloc::vec::Vec;
30    use core::fmt::{Debug, Formatter};
31
32    use crate::lock::Mutex;
33    use crate::sync::Arc;
34    use crate::{limited_cache, server};
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        #[cfg(feature = "std")]
48        pub fn new(size: usize) -> Arc<Self> {
49            Arc::new(Self {
50                cache: Mutex::new(limited_cache::LimitedCache::new(size)),
51            })
52        }
53
54        /// Make a new ServerSessionMemoryCache.  `size` is the maximum
55        /// number of stored sessions, and may be rounded-up for
56        /// efficiency.
57        #[cfg(not(feature = "std"))]
58        pub fn new<M: crate::lock::MakeMutex>(size: usize) -> Arc<Self> {
59            Arc::new(Self {
60                cache: Mutex::new::<M>(limited_cache::LimitedCache::new(size)),
61            })
62        }
63    }
64
65    impl server::StoresServerSessions for ServerSessionMemoryCache {
66        fn put(&self, key: Vec<u8>, value: Vec<u8>) -> bool {
67            self.cache
68                .lock()
69                .unwrap()
70                .insert(key, value);
71            true
72        }
73
74        fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
75            self.cache
76                .lock()
77                .unwrap()
78                .get(key)
79                .cloned()
80        }
81
82        fn take(&self, key: &[u8]) -> Option<Vec<u8>> {
83            self.cache.lock().unwrap().remove(key)
84        }
85
86        fn can_cache(&self) -> bool {
87            true
88        }
89    }
90
91    impl Debug for ServerSessionMemoryCache {
92        fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
93            f.debug_struct("ServerSessionMemoryCache")
94                .finish()
95        }
96    }
97
98    #[cfg(test)]
99    mod tests {
100        use std::vec;
101
102        use super::*;
103        use crate::server::StoresServerSessions;
104
105        #[test]
106        fn test_serversessionmemorycache_accepts_put() {
107            let c = ServerSessionMemoryCache::new(4);
108            assert!(c.put(vec![0x01], vec![0x02]));
109        }
110
111        #[test]
112        fn test_serversessionmemorycache_persists_put() {
113            let c = ServerSessionMemoryCache::new(4);
114            assert!(c.put(vec![0x01], vec![0x02]));
115            assert_eq!(c.get(&[0x01]), Some(vec![0x02]));
116            assert_eq!(c.get(&[0x01]), Some(vec![0x02]));
117        }
118
119        #[test]
120        fn test_serversessionmemorycache_overwrites_put() {
121            let c = ServerSessionMemoryCache::new(4);
122            assert!(c.put(vec![0x01], vec![0x02]));
123            assert!(c.put(vec![0x01], vec![0x04]));
124            assert_eq!(c.get(&[0x01]), Some(vec![0x04]));
125        }
126
127        /// After five sessions are put into a cache of size 2, exactly the
128        /// two most recently added sessions remain.
129        #[test]
130        fn test_serversessionmemorycache_drops_to_maintain_size_invariant() {
131            let c = ServerSessionMemoryCache::new(2);
132            assert!(c.put(vec![0x01], vec![0x02]));
133            assert!(c.put(vec![0x03], vec![0x04]));
134            assert!(c.put(vec![0x05], vec![0x06]));
135            assert!(c.put(vec![0x07], vec![0x08]));
136            assert!(c.put(vec![0x09], vec![0x0a]));
137
138            assert_eq!(c.get(&[0x01]), None);
139            assert_eq!(c.get(&[0x03]), None);
140            assert_eq!(c.get(&[0x05]), None);
141            assert_eq!(c.get(&[0x07]), Some(vec![0x08]));
142            assert_eq!(c.get(&[0x09]), Some(vec![0x0a]));
143        }
144
145        /// A cache of size 1 keeps the session put into it, and a second
146        /// put replaces it.
147        #[test]
148        fn test_serversessionmemorycache_size_one_retains_session() {
149            let c = ServerSessionMemoryCache::new(1);
150            assert!(c.put(vec![0x01], vec![0x02]));
151            assert_eq!(c.get(&[0x01]), Some(vec![0x02]));
152
153            assert!(c.put(vec![0x03], vec![0x04]));
154            assert_eq!(c.get(&[0x01]), None);
155            assert_eq!(c.get(&[0x03]), Some(vec![0x04]));
156        }
157    }
158}
159
160#[cfg(any(feature = "std", feature = "hashbrown"))]
161pub use cache::ServerSessionMemoryCache;
162
163/// Something which never produces tickets.
164#[derive(Debug)]
165pub(super) struct NeverProducesTickets {}
166
167impl server::ProducesTickets for NeverProducesTickets {
168    fn enabled(&self) -> bool {
169        false
170    }
171    fn lifetime(&self) -> u32 {
172        0
173    }
174    fn encrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> {
175        None
176    }
177    fn decrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> {
178        None
179    }
180}
181
182/// An exemplar `ResolvesServerCert` implementation that always resolves to a single
183/// [RFC 7250] raw public key.
184///
185/// [RFC 7250]: https://tools.ietf.org/html/rfc7250
186#[derive(Clone, Debug)]
187pub struct AlwaysResolvesServerRawPublicKeys(Arc<sign::CertifiedKey>);
188
189impl AlwaysResolvesServerRawPublicKeys {
190    /// Create a new `AlwaysResolvesServerRawPublicKeys` instance.
191    pub fn new(certified_key: Arc<sign::CertifiedKey>) -> Self {
192        Self(certified_key)
193    }
194}
195
196impl server::ResolvesServerCert for AlwaysResolvesServerRawPublicKeys {
197    fn resolve(&self, _client_hello: ClientHello<'_>) -> Option<Arc<sign::CertifiedKey>> {
198        Some(self.0.clone())
199    }
200
201    fn only_raw_public_keys(&self) -> bool {
202        true
203    }
204}
205
206#[cfg(any(feature = "std", feature = "hashbrown"))]
207mod sni_resolver {
208    use alloc::string::{String, ToString};
209    use core::fmt::Debug;
210
211    use pki_types::{DnsName, ServerName};
212
213    use crate::error::Error;
214    use crate::hash_map::HashMap;
215    use crate::server::ClientHello;
216    use crate::sync::Arc;
217    use crate::webpki::{ParsedCertificate, verify_server_name};
218    use crate::{server, sign};
219
220    /// Something that resolves do different cert chains/keys based
221    /// on client-supplied server name (via SNI).
222    #[derive(Debug)]
223    pub struct ResolvesServerCertUsingSni {
224        by_name: HashMap<String, Arc<sign::CertifiedKey>>,
225    }
226
227    impl ResolvesServerCertUsingSni {
228        /// Create a new and empty (i.e., knows no certificates) resolver.
229        pub fn new() -> Self {
230            Self {
231                by_name: HashMap::new(),
232            }
233        }
234
235        /// Add a new `sign::CertifiedKey` to be used for the given SNI `name`.
236        ///
237        /// This function fails if `name` is not a valid DNS name, or if
238        /// it's not valid for the supplied certificate, or if the certificate
239        /// chain is syntactically faulty.
240        pub fn add(&mut self, name: &str, ck: sign::CertifiedKey) -> Result<(), Error> {
241            let server_name = {
242                let checked_name = DnsName::try_from(name)
243                    .map_err(|_| Error::General("Bad DNS name".into()))
244                    .map(|name| name.to_lowercase_owned())?;
245                ServerName::DnsName(checked_name)
246            };
247
248            // Check the certificate chain for validity:
249            // - it should be non-empty list
250            // - the first certificate should be parsable as a x509v3,
251            // - the first certificate should quote the given server name
252            //   (if provided)
253            //
254            // These checks are not security-sensitive.  They are the
255            // *server* attempting to detect accidental misconfiguration.
256
257            ck.end_entity_cert()
258                .and_then(ParsedCertificate::try_from)
259                .and_then(|cert| verify_server_name(&cert, &server_name))?;
260
261            if let ServerName::DnsName(name) = server_name {
262                self.by_name
263                    .insert(name.as_ref().to_string(), Arc::new(ck));
264            }
265            Ok(())
266        }
267    }
268
269    impl server::ResolvesServerCert for ResolvesServerCertUsingSni {
270        fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<sign::CertifiedKey>> {
271            if let Some(name) = client_hello.server_name() {
272                self.by_name.get(name).cloned()
273            } else {
274                // This kind of resolver requires SNI
275                None
276            }
277        }
278    }
279
280    #[cfg(test)]
281    mod tests {
282        use super::*;
283        use crate::server::ResolvesServerCert;
284
285        #[test]
286        fn test_resolvesservercertusingsni_requires_sni() {
287            let rscsni = ResolvesServerCertUsingSni::new();
288            assert!(
289                rscsni
290                    .resolve(ClientHello {
291                        server_name: &None,
292                        signature_schemes: &[],
293                        alpn: None,
294                        server_cert_types: None,
295                        client_cert_types: None,
296                        cipher_suites: &[],
297                        certificate_authorities: None,
298                        named_groups: None,
299                    })
300                    .is_none()
301            );
302        }
303
304        #[test]
305        fn test_resolvesservercertusingsni_handles_unknown_name() {
306            let rscsni = ResolvesServerCertUsingSni::new();
307            let name = DnsName::try_from("hello.com")
308                .unwrap()
309                .to_owned();
310            assert!(
311                rscsni
312                    .resolve(ClientHello {
313                        server_name: &Some(name),
314                        signature_schemes: &[],
315                        alpn: None,
316                        server_cert_types: None,
317                        client_cert_types: None,
318                        cipher_suites: &[],
319                        certificate_authorities: None,
320                        named_groups: None,
321                    })
322                    .is_none()
323            );
324        }
325    }
326}
327
328#[cfg(any(feature = "std", feature = "hashbrown"))]
329pub use sni_resolver::ResolvesServerCertUsingSni;
330
331#[cfg(test)]
332mod tests {
333    use std::vec;
334
335    use super::*;
336    use crate::server::{ProducesTickets, StoresServerSessions};
337
338    #[test]
339    fn test_noserversessionstorage_drops_put() {
340        let c = NoServerSessionStorage {};
341        assert!(!c.put(vec![0x01], vec![0x02]));
342    }
343
344    #[test]
345    fn test_noserversessionstorage_denies_gets() {
346        let c = NoServerSessionStorage {};
347        c.put(vec![0x01], vec![0x02]);
348        assert_eq!(c.get(&[]), None);
349        assert_eq!(c.get(&[0x01]), None);
350        assert_eq!(c.get(&[0x02]), None);
351    }
352
353    #[test]
354    fn test_noserversessionstorage_denies_takes() {
355        let c = NoServerSessionStorage {};
356        assert_eq!(c.take(&[]), None);
357        assert_eq!(c.take(&[0x01]), None);
358        assert_eq!(c.take(&[0x02]), None);
359    }
360
361    #[test]
362    fn test_neverproducestickets_does_nothing() {
363        let npt = NeverProducesTickets {};
364        assert!(!npt.enabled());
365        assert_eq!(0, npt.lifetime());
366        assert_eq!(None, npt.encrypt(&[]));
367        assert_eq!(None, npt.decrypt(&[]));
368    }
369}