rustls/server/
handy.rs

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