| 1 | use alloc::vec::Vec; |
| 2 | use core::fmt::Debug; |
| 3 | |
| 4 | use crate::server::ClientHello; |
| 5 | use crate::sync::Arc; |
| 6 | use crate::{server, sign}; |
| 7 | |
| 8 | /// Something which never stores sessions. |
| 9 | #[derive (Debug)] |
| 10 | pub struct NoServerSessionStorage {} |
| 11 | |
| 12 | impl 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" ))] |
| 28 | mod 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. If 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 | #[test ] |
| 128 | fn test_serversessionmemorycache_drops_to_maintain_size_invariant() { |
| 129 | let c = ServerSessionMemoryCache::new(2); |
| 130 | assert!(c.put(vec![0x01], vec![0x02])); |
| 131 | assert!(c.put(vec![0x03], vec![0x04])); |
| 132 | assert!(c.put(vec![0x05], vec![0x06])); |
| 133 | assert!(c.put(vec![0x07], vec![0x08])); |
| 134 | assert!(c.put(vec![0x09], vec![0x0a])); |
| 135 | |
| 136 | let count = c.get(&[0x01]).iter().count() |
| 137 | + c.get(&[0x03]).iter().count() |
| 138 | + c.get(&[0x05]).iter().count() |
| 139 | + c.get(&[0x07]).iter().count() |
| 140 | + c.get(&[0x09]).iter().count(); |
| 141 | |
| 142 | assert!(count < 5); |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | #[cfg (any(feature = "std" , feature = "hashbrown" ))] |
| 148 | pub use cache::ServerSessionMemoryCache; |
| 149 | |
| 150 | /// Something which never produces tickets. |
| 151 | #[derive (Debug)] |
| 152 | pub(super) struct NeverProducesTickets {} |
| 153 | |
| 154 | impl server::ProducesTickets for NeverProducesTickets { |
| 155 | fn enabled(&self) -> bool { |
| 156 | false |
| 157 | } |
| 158 | fn lifetime(&self) -> u32 { |
| 159 | 0 |
| 160 | } |
| 161 | fn encrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> { |
| 162 | None |
| 163 | } |
| 164 | fn decrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> { |
| 165 | None |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | /// An exemplar `ResolvesServerCert` implementation that always resolves to a single |
| 170 | /// [RFC 7250] raw public key. |
| 171 | /// |
| 172 | /// [RFC 7250]: https://tools.ietf.org/html/rfc7250 |
| 173 | #[derive (Clone, Debug)] |
| 174 | pub struct AlwaysResolvesServerRawPublicKeys(Arc<sign::CertifiedKey>); |
| 175 | |
| 176 | impl AlwaysResolvesServerRawPublicKeys { |
| 177 | /// Create a new `AlwaysResolvesServerRawPublicKeys` instance. |
| 178 | pub fn new(certified_key: Arc<sign::CertifiedKey>) -> Self { |
| 179 | Self(certified_key) |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | impl server::ResolvesServerCert for AlwaysResolvesServerRawPublicKeys { |
| 184 | fn resolve(&self, _client_hello: ClientHello<'_>) -> Option<Arc<sign::CertifiedKey>> { |
| 185 | Some(Arc::clone(&self.0)) |
| 186 | } |
| 187 | |
| 188 | fn only_raw_public_keys(&self) -> bool { |
| 189 | true |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | #[cfg (any(feature = "std" , feature = "hashbrown" ))] |
| 194 | mod sni_resolver { |
| 195 | use alloc::string::{String, ToString}; |
| 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<String, 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 `name` is not a valid DNS name, or if |
| 225 | /// it's not valid for the supplied certificate, or if the certificate |
| 226 | /// chain is syntactically faulty. |
| 227 | pub fn add(&mut self, name: &str, ck: sign::CertifiedKey) -> Result<(), Error> { |
| 228 | let server_name = { |
| 229 | let checked_name = DnsName::try_from(name) |
| 230 | .map_err(|_| Error::General("Bad DNS name" .into())) |
| 231 | .map(|name| name.to_lowercase_owned())?; |
| 232 | ServerName::DnsName(checked_name) |
| 233 | }; |
| 234 | |
| 235 | // Check the certificate chain for validity: |
| 236 | // - it should be non-empty list |
| 237 | // - the first certificate should be parsable as a x509v3, |
| 238 | // - the first certificate should quote the given server name |
| 239 | // (if provided) |
| 240 | // |
| 241 | // These checks are not security-sensitive. They are the |
| 242 | // *server* attempting to detect accidental misconfiguration. |
| 243 | |
| 244 | ck.end_entity_cert() |
| 245 | .and_then(ParsedCertificate::try_from) |
| 246 | .and_then(|cert| verify_server_name(&cert, &server_name))?; |
| 247 | |
| 248 | if let ServerName::DnsName(name) = server_name { |
| 249 | self.by_name |
| 250 | .insert(name.as_ref().to_string(), Arc::new(ck)); |
| 251 | } |
| 252 | Ok(()) |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | impl server::ResolvesServerCert for ResolvesServerCertUsingSni { |
| 257 | fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<sign::CertifiedKey>> { |
| 258 | if let Some(name) = client_hello.server_name() { |
| 259 | self.by_name.get(name).cloned() |
| 260 | } else { |
| 261 | // This kind of resolver requires SNI |
| 262 | None |
| 263 | } |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | #[cfg (test)] |
| 268 | mod tests { |
| 269 | use super::*; |
| 270 | use crate::server::ResolvesServerCert; |
| 271 | |
| 272 | #[test ] |
| 273 | fn test_resolvesservercertusingsni_requires_sni() { |
| 274 | let rscsni = ResolvesServerCertUsingSni::new(); |
| 275 | assert!( |
| 276 | rscsni |
| 277 | .resolve(ClientHello { |
| 278 | server_name: &None, |
| 279 | signature_schemes: &[], |
| 280 | alpn: None, |
| 281 | server_cert_types: None, |
| 282 | client_cert_types: None, |
| 283 | cipher_suites: &[], |
| 284 | certificate_authorities: None, |
| 285 | }) |
| 286 | .is_none() |
| 287 | ); |
| 288 | } |
| 289 | |
| 290 | #[test ] |
| 291 | fn test_resolvesservercertusingsni_handles_unknown_name() { |
| 292 | let rscsni = ResolvesServerCertUsingSni::new(); |
| 293 | let name = DnsName::try_from("hello.com" ) |
| 294 | .unwrap() |
| 295 | .to_owned(); |
| 296 | assert!( |
| 297 | rscsni |
| 298 | .resolve(ClientHello { |
| 299 | server_name: &Some(name), |
| 300 | signature_schemes: &[], |
| 301 | alpn: None, |
| 302 | server_cert_types: None, |
| 303 | client_cert_types: None, |
| 304 | cipher_suites: &[], |
| 305 | certificate_authorities: None, |
| 306 | }) |
| 307 | .is_none() |
| 308 | ); |
| 309 | } |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | #[cfg (any(feature = "std" , feature = "hashbrown" ))] |
| 314 | pub use sni_resolver::ResolvesServerCertUsingSni; |
| 315 | |
| 316 | #[cfg (test)] |
| 317 | mod tests { |
| 318 | use std::vec; |
| 319 | |
| 320 | use super::*; |
| 321 | use crate::server::{ProducesTickets, StoresServerSessions}; |
| 322 | |
| 323 | #[test ] |
| 324 | fn test_noserversessionstorage_drops_put() { |
| 325 | let c = NoServerSessionStorage {}; |
| 326 | assert!(!c.put(vec![0x01], vec![0x02])); |
| 327 | } |
| 328 | |
| 329 | #[test ] |
| 330 | fn test_noserversessionstorage_denies_gets() { |
| 331 | let c = NoServerSessionStorage {}; |
| 332 | c.put(vec![0x01], vec![0x02]); |
| 333 | assert_eq!(c.get(&[]), None); |
| 334 | assert_eq!(c.get(&[0x01]), None); |
| 335 | assert_eq!(c.get(&[0x02]), None); |
| 336 | } |
| 337 | |
| 338 | #[test ] |
| 339 | fn test_noserversessionstorage_denies_takes() { |
| 340 | let c = NoServerSessionStorage {}; |
| 341 | assert_eq!(c.take(&[]), None); |
| 342 | assert_eq!(c.take(&[0x01]), None); |
| 343 | assert_eq!(c.take(&[0x02]), None); |
| 344 | } |
| 345 | |
| 346 | #[test ] |
| 347 | fn test_neverproducestickets_does_nothing() { |
| 348 | let npt = NeverProducesTickets {}; |
| 349 | assert!(!npt.enabled()); |
| 350 | assert_eq!(0, npt.lifetime()); |
| 351 | assert_eq!(None, npt.encrypt(&[])); |
| 352 | assert_eq!(None, npt.decrypt(&[])); |
| 353 | } |
| 354 | } |
| 355 | |