1 | use crate::error::Error; |
2 | use crate::limited_cache; |
3 | use crate::msgs::handshake::CertificateChain; |
4 | use crate::server; |
5 | use crate::server::ClientHello; |
6 | use crate::sign; |
7 | use crate::webpki::{verify_server_name, ParsedCertificate}; |
8 | |
9 | use pki_types::{DnsName, ServerName}; |
10 | |
11 | use alloc::string::{String, ToString}; |
12 | use alloc::sync::Arc; |
13 | use alloc::vec::Vec; |
14 | use core::fmt::{Debug, Formatter}; |
15 | use std::collections::HashMap; |
16 | use std::sync::Mutex; |
17 | |
18 | /// Something which never stores sessions. |
19 | #[derive (Debug)] |
20 | pub struct NoServerSessionStorage {} |
21 | |
22 | impl server::StoresServerSessions for NoServerSessionStorage { |
23 | fn put(&self, _id: Vec<u8>, _sec: Vec<u8>) -> bool { |
24 | false |
25 | } |
26 | fn get(&self, _id: &[u8]) -> Option<Vec<u8>> { |
27 | None |
28 | } |
29 | fn take(&self, _id: &[u8]) -> Option<Vec<u8>> { |
30 | None |
31 | } |
32 | fn can_cache(&self) -> bool { |
33 | false |
34 | } |
35 | } |
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 | pub fn new(size: usize) -> Arc<Self> { |
49 | Arc::new(Self { |
50 | cache: Mutex::new(limited_cache::LimitedCache::new(capacity_order_of_magnitude:size)), |
51 | }) |
52 | } |
53 | } |
54 | |
55 | impl server::StoresServerSessions for ServerSessionMemoryCache { |
56 | fn put(&self, key: Vec<u8>, value: Vec<u8>) -> bool { |
57 | self.cache |
58 | .lock() |
59 | .unwrap() |
60 | .insert(key, value); |
61 | true |
62 | } |
63 | |
64 | fn get(&self, key: &[u8]) -> Option<Vec<u8>> { |
65 | self.cache |
66 | .lock() |
67 | .unwrap() |
68 | .get(key) |
69 | .cloned() |
70 | } |
71 | |
72 | fn take(&self, key: &[u8]) -> Option<Vec<u8>> { |
73 | self.cache.lock().unwrap().remove(key) |
74 | } |
75 | |
76 | fn can_cache(&self) -> bool { |
77 | true |
78 | } |
79 | } |
80 | |
81 | impl Debug for ServerSessionMemoryCache { |
82 | fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { |
83 | fDebugStruct<'_, '_>.debug_struct(name:"ServerSessionMemoryCache" ) |
84 | .finish() |
85 | } |
86 | } |
87 | |
88 | /// Something which never produces tickets. |
89 | #[derive (Debug)] |
90 | pub(super) struct NeverProducesTickets {} |
91 | |
92 | impl server::ProducesTickets for NeverProducesTickets { |
93 | fn enabled(&self) -> bool { |
94 | false |
95 | } |
96 | fn lifetime(&self) -> u32 { |
97 | 0 |
98 | } |
99 | fn encrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> { |
100 | None |
101 | } |
102 | fn decrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> { |
103 | None |
104 | } |
105 | } |
106 | |
107 | /// Something which always resolves to the same cert chain. |
108 | #[derive (Debug)] |
109 | pub(super) struct AlwaysResolvesChain(Arc<sign::CertifiedKey>); |
110 | |
111 | impl AlwaysResolvesChain { |
112 | /// Creates an `AlwaysResolvesChain`, using the supplied key and certificate chain. |
113 | pub(super) fn new(private_key: Arc<dyn sign::SigningKey>, chain: CertificateChain) -> Self { |
114 | Self(Arc::new(sign::CertifiedKey::new(chain.0, private_key))) |
115 | } |
116 | |
117 | /// Creates an `AlwaysResolvesChain`, using the supplied key, certificate chain and OCSP response. |
118 | /// |
119 | /// If non-empty, the given OCSP response is attached. |
120 | pub(super) fn new_with_extras( |
121 | private_key: Arc<dyn sign::SigningKey>, |
122 | chain: CertificateChain, |
123 | ocsp: Vec<u8>, |
124 | ) -> Self { |
125 | let mut r = Self::new(private_key, chain); |
126 | |
127 | { |
128 | let cert = Arc::make_mut(&mut r.0); |
129 | if !ocsp.is_empty() { |
130 | cert.ocsp = Some(ocsp); |
131 | } |
132 | } |
133 | |
134 | r |
135 | } |
136 | } |
137 | |
138 | impl server::ResolvesServerCert for AlwaysResolvesChain { |
139 | fn resolve(&self, _client_hello: ClientHello) -> Option<Arc<sign::CertifiedKey>> { |
140 | Some(Arc::clone(&self.0)) |
141 | } |
142 | } |
143 | |
144 | /// Something that resolves do different cert chains/keys based |
145 | /// on client-supplied server name (via SNI). |
146 | #[derive (Debug)] |
147 | pub struct ResolvesServerCertUsingSni { |
148 | by_name: HashMap<String, Arc<sign::CertifiedKey>>, |
149 | } |
150 | |
151 | impl ResolvesServerCertUsingSni { |
152 | /// Create a new and empty (i.e., knows no certificates) resolver. |
153 | pub fn new() -> Self { |
154 | Self { |
155 | by_name: HashMap::new(), |
156 | } |
157 | } |
158 | |
159 | /// Add a new `sign::CertifiedKey` to be used for the given SNI `name`. |
160 | /// |
161 | /// This function fails if `name` is not a valid DNS name, or if |
162 | /// it's not valid for the supplied certificate, or if the certificate |
163 | /// chain is syntactically faulty. |
164 | pub fn add(&mut self, name: &str, ck: sign::CertifiedKey) -> Result<(), Error> { |
165 | let server_name = { |
166 | let checked_name = DnsName::try_from(name) |
167 | .map_err(|_| Error::General("Bad DNS name" .into())) |
168 | .map(|name| name.to_lowercase_owned())?; |
169 | ServerName::DnsName(checked_name) |
170 | }; |
171 | |
172 | // Check the certificate chain for validity: |
173 | // - it should be non-empty list |
174 | // - the first certificate should be parsable as a x509v3, |
175 | // - the first certificate should quote the given server name |
176 | // (if provided) |
177 | // |
178 | // These checks are not security-sensitive. They are the |
179 | // *server* attempting to detect accidental misconfiguration. |
180 | |
181 | ck.end_entity_cert() |
182 | .and_then(ParsedCertificate::try_from) |
183 | .and_then(|cert| verify_server_name(&cert, &server_name))?; |
184 | |
185 | if let ServerName::DnsName(name) = server_name { |
186 | self.by_name |
187 | .insert(name.as_ref().to_string(), Arc::new(ck)); |
188 | } |
189 | Ok(()) |
190 | } |
191 | } |
192 | |
193 | impl server::ResolvesServerCert for ResolvesServerCertUsingSni { |
194 | fn resolve(&self, client_hello: ClientHello) -> Option<Arc<sign::CertifiedKey>> { |
195 | if let Some(name: &str) = client_hello.server_name() { |
196 | self.by_name.get(name).map(Arc::clone) |
197 | } else { |
198 | // This kind of resolver requires SNI |
199 | None |
200 | } |
201 | } |
202 | } |
203 | |
204 | #[cfg (test)] |
205 | mod tests { |
206 | use super::*; |
207 | use crate::server::ProducesTickets; |
208 | use crate::server::ResolvesServerCert; |
209 | use crate::server::StoresServerSessions; |
210 | |
211 | #[test ] |
212 | fn test_noserversessionstorage_drops_put() { |
213 | let c = NoServerSessionStorage {}; |
214 | assert!(!c.put(vec![0x01], vec![0x02])); |
215 | } |
216 | |
217 | #[test ] |
218 | fn test_noserversessionstorage_denies_gets() { |
219 | let c = NoServerSessionStorage {}; |
220 | c.put(vec![0x01], vec![0x02]); |
221 | assert_eq!(c.get(&[]), None); |
222 | assert_eq!(c.get(&[0x01]), None); |
223 | assert_eq!(c.get(&[0x02]), None); |
224 | } |
225 | |
226 | #[test ] |
227 | fn test_noserversessionstorage_denies_takes() { |
228 | let c = NoServerSessionStorage {}; |
229 | assert_eq!(c.take(&[]), None); |
230 | assert_eq!(c.take(&[0x01]), None); |
231 | assert_eq!(c.take(&[0x02]), None); |
232 | } |
233 | |
234 | #[test ] |
235 | fn test_serversessionmemorycache_accepts_put() { |
236 | let c = ServerSessionMemoryCache::new(4); |
237 | assert!(c.put(vec![0x01], vec![0x02])); |
238 | } |
239 | |
240 | #[test ] |
241 | fn test_serversessionmemorycache_persists_put() { |
242 | let c = ServerSessionMemoryCache::new(4); |
243 | assert!(c.put(vec![0x01], vec![0x02])); |
244 | assert_eq!(c.get(&[0x01]), Some(vec![0x02])); |
245 | assert_eq!(c.get(&[0x01]), Some(vec![0x02])); |
246 | } |
247 | |
248 | #[test ] |
249 | fn test_serversessionmemorycache_overwrites_put() { |
250 | let c = ServerSessionMemoryCache::new(4); |
251 | assert!(c.put(vec![0x01], vec![0x02])); |
252 | assert!(c.put(vec![0x01], vec![0x04])); |
253 | assert_eq!(c.get(&[0x01]), Some(vec![0x04])); |
254 | } |
255 | |
256 | #[test ] |
257 | fn test_serversessionmemorycache_drops_to_maintain_size_invariant() { |
258 | let c = ServerSessionMemoryCache::new(2); |
259 | assert!(c.put(vec![0x01], vec![0x02])); |
260 | assert!(c.put(vec![0x03], vec![0x04])); |
261 | assert!(c.put(vec![0x05], vec![0x06])); |
262 | assert!(c.put(vec![0x07], vec![0x08])); |
263 | assert!(c.put(vec![0x09], vec![0x0a])); |
264 | |
265 | let count = c.get(&[0x01]).iter().count() |
266 | + c.get(&[0x03]).iter().count() |
267 | + c.get(&[0x05]).iter().count() |
268 | + c.get(&[0x07]).iter().count() |
269 | + c.get(&[0x09]).iter().count(); |
270 | |
271 | assert!(count < 5); |
272 | } |
273 | |
274 | #[test ] |
275 | fn test_neverproducestickets_does_nothing() { |
276 | let npt = NeverProducesTickets {}; |
277 | assert!(!npt.enabled()); |
278 | assert_eq!(0, npt.lifetime()); |
279 | assert_eq!(None, npt.encrypt(&[])); |
280 | assert_eq!(None, npt.decrypt(&[])); |
281 | } |
282 | |
283 | #[test ] |
284 | fn test_resolvesservercertusingsni_requires_sni() { |
285 | let rscsni = ResolvesServerCertUsingSni::new(); |
286 | assert!(rscsni |
287 | .resolve(ClientHello::new(&None, &[], None, &[])) |
288 | .is_none()); |
289 | } |
290 | |
291 | #[test ] |
292 | fn test_resolvesservercertusingsni_handles_unknown_name() { |
293 | let rscsni = ResolvesServerCertUsingSni::new(); |
294 | let name = DnsName::try_from("hello.com" ) |
295 | .unwrap() |
296 | .to_owned(); |
297 | assert!(rscsni |
298 | .resolve(ClientHello::new(&Some(name), &[], None, &[])) |
299 | .is_none()); |
300 | } |
301 | } |
302 | |