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