1use super::{CipherSuite, Error, NamedGroup, Result};
5use crate::crypto::gcm::AesGcm;
6use crate::crypto::rng;
7use crate::keys::PrivateKey;
8use crate::x509::{Certificate, RootStore};
9#[cfg(feature = "client")]
10use std::collections::{HashMap, VecDeque};
11use std::sync::{Arc, Mutex};
12
13pub trait TimeSource: Send + Sync {
16 fn unix_millis(&self) -> u64;
17}
18
19#[derive(Debug, Default, Clone, Copy)]
21pub struct SystemClock;
22
23impl TimeSource for SystemClock {
24 fn unix_millis(&self) -> u64 {
25 std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).map(|d| d.as_millis() as u64).unwrap_or(0)
26 }
27}
28
29#[derive(Clone, Debug)]
31pub struct CertifiedKey {
32 pub chain: Vec<Vec<u8>>,
33 pub key: PrivateKey,
34 names: Vec<String>,
37}
38
39impl CertifiedKey {
40 pub fn new(chain: Vec<Vec<u8>>, key: PrivateKey) -> Result<CertifiedKey> {
42 let leaf = chain.first().ok_or_else(|| Error::Config("empty certificate chain".into()))?;
43 let cert = Certificate::from_der(leaf).map_err(|e| Error::Config(format!("bad certificate: {e}")))?;
44 match &cert.public_key {
45 Some(pk) if pk.same_as(&key.public_key()) => {
46 let names = if cert.has_san { cert.dns_names } else { cert.subject.common_name().map(|s| vec![s.to_ascii_lowercase()]).unwrap_or_default() };
47 Ok(CertifiedKey { chain, key, names })
48 }
49 Some(_) => Err(Error::Config("the private key does not match the certificate".into())),
50 None => Err(Error::Config("unsupported certificate key type".into())),
51 }
52 }
53
54 pub fn from_pem(cert_pem: &[u8], key_pem: &[u8]) -> Result<CertifiedKey> {
56 let chain: Vec<Vec<u8>> = crate::pem::parse_pem(cert_pem)
57 .map_err(Error::Config)?
58 .into_iter()
59 .filter(|b| b.label == "CERTIFICATE")
60 .map(|b| b.der)
61 .collect();
62 let key = PrivateKey::from_pem(key_pem).map_err(Error::Config)?;
63 CertifiedKey::new(chain, key)
64 }
65
66 pub fn from_der(chain: Vec<Vec<u8>>, key_der: &[u8]) -> Result<CertifiedKey> {
68 let key = PrivateKey::from_der(key_der).map_err(Error::Config)?;
69 CertifiedKey::new(chain, key)
70 }
71
72 pub fn names(&self) -> &[String] {
74 &self.names
75 }
76}
77
78#[derive(Clone, Debug, Default)]
80pub enum ClientAuth {
81 #[default]
83 None,
84 Optional(RootStore),
86 Required(RootStore),
88}
89
90pub struct Ticketer {
93 keys: Mutex<TicketKeys>,
94 rotate_ms: u64,
95}
96
97struct TicketKey {
98 id: [u8; 8],
99 aead: AesGcm,
100 created_ms: u64,
101}
102
103struct TicketKeys {
104 current: Option<TicketKey>,
105 previous: Option<TicketKey>,
106}
107
108impl std::fmt::Debug for Ticketer {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 write!(f, "Ticketer(rotate every {} s)", self.rotate_ms / 1000)
111 }
112}
113
114impl Ticketer {
115 pub fn new(rotate_secs: u32) -> Ticketer {
116 Ticketer { keys: Mutex::new(TicketKeys { current: None, previous: None }), rotate_ms: rotate_secs.max(1) as u64 * 1000 }
117 }
118
119 fn fresh(now: u64) -> TicketKey {
120 let mut k = rng::array::<32>();
121 let key = TicketKey { id: rng::array(), aead: AesGcm::new(&k), created_ms: now };
122 crate::util::zeroize(&mut k);
123 key
124 }
125
126 fn rotate(&self, keys: &mut TicketKeys, now: u64) {
127 let stale = match &keys.current {
128 None => true,
129 Some(k) => now.saturating_sub(k.created_ms) >= self.rotate_ms,
130 };
131 if stale {
132 keys.previous = keys.current.take();
133 keys.current = Some(Self::fresh(now));
134 if let Some(p) = &keys.previous {
135 if now.saturating_sub(p.created_ms) >= 2 * self.rotate_ms {
136 keys.previous = None;
137 }
138 }
139 }
140 }
141
142 pub(crate) fn seal(&self, now: u64, plain: &[u8]) -> Vec<u8> {
144 let mut keys = self.keys.lock().unwrap_or_else(|e| e.into_inner());
145 self.rotate(&mut keys, now);
146 let k = keys.current.as_ref().expect("current key");
147 let nonce = rng::array::<12>();
148 let mut out = Vec::with_capacity(36 + plain.len());
149 out.extend_from_slice(&k.id);
150 out.extend_from_slice(&nonce);
151 let start = out.len();
152 out.extend_from_slice(plain);
153 let tag = k.aead.seal(&nonce, &k.id, &mut out[start..]);
154 out.extend_from_slice(&tag);
155 out
156 }
157
158 pub(crate) fn open(&self, now: u64, ticket: &[u8]) -> Option<Vec<u8>> {
159 if ticket.len() < 36 {
160 return None;
161 }
162 let mut keys = self.keys.lock().unwrap_or_else(|e| e.into_inner());
163 self.rotate(&mut keys, now);
164 let (id, rest) = ticket.split_at(8);
165 let (nonce, rest) = rest.split_at(12);
166 let (ct, tag) = rest.split_at(rest.len() - 16);
167 for k in [&keys.current, &keys.previous].into_iter().flatten() {
168 if k.id == id {
169 let mut pt = ct.to_vec();
170 return k.aead.open(nonce.try_into().unwrap(), &k.id, &mut pt, tag).then_some(pt);
171 }
172 }
173 None
174 }
175
176 pub fn rotate_now(&self, now_ms: u64) {
178 let mut keys = self.keys.lock().unwrap_or_else(|e| e.into_inner());
179 keys.previous = keys.current.take();
180 keys.current = Some(Self::fresh(now_ms));
181 }
182}
183
184#[derive(Clone)]
188pub struct ServerConfig {
189 pub(crate) default_cert: Option<Arc<CertifiedKey>>,
190 pub(crate) sni_certs: Vec<(String, Arc<CertifiedKey>)>,
191 pub alpn: Vec<Vec<u8>>,
193 pub client_auth: ClientAuth,
194 pub suites: Vec<CipherSuite>,
195 pub groups: Vec<NamedGroup>,
196 pub ticketer: Option<Arc<Ticketer>>,
198 pub ticket_lifetime_secs: u32,
200 pub ticket_count: u8,
202 pub strict_sni: bool,
205 pub max_handshake_message: usize,
207 pub time: Arc<dyn TimeSource>,
208 #[cfg(feature = "tls12")]
210 pub min_version: super::ProtocolVersion,
211 #[cfg(feature = "tls12")]
214 pub max_version: super::ProtocolVersion,
215 #[cfg(feature = "tls12")]
217 pub suites12: Vec<super::tls12::Tls12Suite>,
218 #[cfg(feature = "tls12")]
221 pub session_ids: Option<Arc<super::tls12::SessionIdCache>>,
222 #[cfg(feature = "revocation")]
225 pub ocsp_staple: Option<crate::revocation::StapleSource>,
226 #[cfg(feature = "revocation")]
228 pub client_revocation: Option<crate::revocation::RevocationPolicy>,
229}
230
231impl std::fmt::Debug for ServerConfig {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 f.debug_struct("ServerConfig").field("alpn", &self.alpn).field("suites", &self.suites).field("groups", &self.groups).finish()
234 }
235}
236
237impl ServerConfig {
238 pub fn require_tls13(&mut self) {
242 #[cfg(feature = "tls12")]
243 {
244 self.min_version = super::ProtocolVersion::Tls13;
245 }
246 }
247
248 pub fn new(cert: CertifiedKey) -> ServerConfig {
250 ServerConfig {
251 default_cert: Some(Arc::new(cert)),
252 sni_certs: Vec::new(),
253 alpn: Vec::new(),
254 client_auth: ClientAuth::None,
255 suites: CipherSuite::default_order(),
256 groups: NamedGroup::ALL.to_vec(),
257 ticketer: Some(Arc::new(Ticketer::new(6 * 3600))),
258 ticket_lifetime_secs: 6 * 3600,
259 ticket_count: 1,
260 strict_sni: false,
261 max_handshake_message: 64 * 1024,
262 time: Arc::new(SystemClock),
263 #[cfg(feature = "tls12")]
264 min_version: super::ProtocolVersion::Tls12,
265 #[cfg(feature = "tls12")]
266 max_version: super::ProtocolVersion::Tls13,
267 #[cfg(feature = "tls12")]
268 suites12: super::tls12::Tls12Suite::default_order(),
269 #[cfg(feature = "tls12")]
270 session_ids: Some(Arc::new(super::tls12::SessionIdCache::new(1024))),
271 #[cfg(feature = "revocation")]
272 ocsp_staple: None,
273 #[cfg(feature = "revocation")]
274 client_revocation: None,
275 }
276 }
277
278 pub fn from_pem(cert_pem: &[u8], key_pem: &[u8]) -> Result<ServerConfig> {
280 Ok(ServerConfig::new(CertifiedKey::from_pem(cert_pem, key_pem)?))
281 }
282
283 pub fn add_sni_cert(&mut self, cert: CertifiedKey) {
285 let cert = Arc::new(cert);
286 for n in cert.names() {
287 self.sni_certs.push((n.clone(), cert.clone()));
288 }
289 }
290
291 pub fn with_alpn(mut self, protocols: &[&[u8]]) -> ServerConfig {
292 self.alpn = protocols.iter().map(|p| p.to_vec()).collect();
293 self
294 }
295
296 pub(crate) fn resolve(&self, sni: Option<&str>) -> Option<Arc<CertifiedKey>> {
297 if let Some(name) = sni {
298 if let Some((_, c)) = self.sni_certs.iter().find(|(p, _)| crate::x509::dns_name_matches(p, name)) {
299 return Some(c.clone());
300 }
301 if self.strict_sni && !self.sni_certs.is_empty() {
302 return None;
303 }
304 }
305 self.default_cert.clone()
306 }
307}
308
309#[cfg(feature = "client")]
311#[derive(Clone, Debug)]
312pub(crate) struct StoredSession {
313 pub suite: CipherSuite,
314 pub psk: Vec<u8>,
315 pub ticket: Vec<u8>,
316 pub age_add: u32,
317 pub received_ms: u64,
318 pub lifetime_secs: u32,
319 pub alpn: Option<Vec<u8>>,
320}
321
322#[cfg(feature = "client")]
324pub struct SessionCache {
325 map: Mutex<HashMap<String, VecDeque<StoredSession>>>,
326 #[cfg(feature = "tls12")]
327 map12: Mutex<HashMap<String, super::tls12::ClientSession12>>,
328 max_servers: usize,
329 per_server: usize,
330}
331
332#[cfg(feature = "client")]
333impl std::fmt::Debug for SessionCache {
334 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
335 write!(f, "SessionCache({} servers)", self.map.lock().map(|m| m.len()).unwrap_or(0))
336 }
337}
338
339#[cfg(feature = "client")]
340impl SessionCache {
341 pub fn new(max_servers: usize) -> SessionCache {
342 SessionCache {
343 map: Mutex::new(HashMap::new()),
344 #[cfg(feature = "tls12")]
345 map12: Mutex::new(HashMap::new()),
346 max_servers: max_servers.max(1),
347 per_server: 4,
348 }
349 }
350
351 #[cfg(feature = "tls12")]
353 pub(crate) fn put12(&self, server: &str, s: super::tls12::ClientSession12) {
354 let mut m = self.map12.lock().unwrap_or_else(|e| e.into_inner());
355 if !m.contains_key(server) && m.len() >= self.max_servers {
356 if let Some(k) = m.keys().next().cloned() {
357 m.remove(&k);
358 }
359 }
360 m.insert(server.to_string(), s);
361 }
362
363 #[cfg(feature = "tls12")]
366 pub(crate) fn get12(&self, server: &str, now: u64) -> Option<super::tls12::ClientSession12> {
367 let mut m = self.map12.lock().unwrap_or_else(|e| e.into_inner());
368 match m.get(server) {
369 Some(s) if now < s.received_ms + s.lifetime_secs as u64 * 1000 => Some(s.clone()),
370 Some(_) => {
371 m.remove(server);
372 None
373 }
374 None => None,
375 }
376 }
377
378
379 pub(crate) fn put(&self, server: &str, s: StoredSession) {
380 let mut m = self.map.lock().unwrap_or_else(|e| e.into_inner());
381 if !m.contains_key(server) && m.len() >= self.max_servers {
382 if let Some(k) = m.keys().next().cloned() {
383 m.remove(&k);
384 }
385 }
386 let q = m.entry(server.to_string()).or_default();
387 if q.len() >= self.per_server {
388 q.pop_front();
389 }
390 q.push_back(s);
391 }
392
393 pub(crate) fn take(&self, server: &str, now: u64) -> Option<StoredSession> {
394 let mut m = self.map.lock().unwrap_or_else(|e| e.into_inner());
395 let q = m.get_mut(server)?;
396 while let Some(s) = q.pop_back() {
397 if now < s.received_ms + s.lifetime_secs as u64 * 1000 {
398 return Some(s);
399 }
400 }
401 None
402 }
403
404 pub fn len_for(&self, server: &str) -> usize {
406 self.map.lock().map(|m| m.get(server).map_or(0, |q| q.len())).unwrap_or(0)
407 }
408}
409
410#[cfg(feature = "client")]
412pub struct ClientConfig {
413 pub roots: RootStore,
416 pub alpn: Vec<Vec<u8>>,
417 pub suites: Vec<CipherSuite>,
418 pub groups: Vec<NamedGroup>,
420 pub client_cert: Option<CertifiedKey>,
422 pub sessions: Option<Arc<SessionCache>>,
424 pub enable_sni: bool,
426 pub max_handshake_message: usize,
427 pub time: Arc<dyn TimeSource>,
428 #[cfg(feature = "tls12")]
430 pub min_version: super::ProtocolVersion,
431 #[cfg(feature = "tls12")]
433 pub max_version: super::ProtocolVersion,
434 #[cfg(feature = "tls12")]
436 pub suites12: Vec<super::tls12::Tls12Suite>,
437 #[cfg(feature = "revocation")]
440 pub revocation: Option<crate::revocation::RevocationPolicy>,
441}
442
443#[cfg(feature = "client")]
444impl std::fmt::Debug for ClientConfig {
445 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
446 f.debug_struct("ClientConfig").field("roots", &self.roots).field("alpn", &self.alpn).finish()
447 }
448}
449
450#[cfg(feature = "client")]
451impl ClientConfig {
452 pub fn new(roots: RootStore) -> ClientConfig {
453 ClientConfig {
454 roots,
455 alpn: Vec::new(),
456 suites: CipherSuite::ALL.to_vec(),
457 groups: NamedGroup::ALL.to_vec(),
458 client_cert: None,
459 sessions: Some(Arc::new(SessionCache::new(256))),
460 enable_sni: true,
461 max_handshake_message: 64 * 1024,
462 time: Arc::new(SystemClock),
463 #[cfg(feature = "tls12")]
464 min_version: super::ProtocolVersion::Tls12,
465 #[cfg(feature = "tls12")]
466 max_version: super::ProtocolVersion::Tls13,
467 #[cfg(feature = "tls12")]
468 suites12: super::tls12::Tls12Suite::default_order(),
469 #[cfg(feature = "revocation")]
470 revocation: None,
471 }
472 }
473
474 pub fn with_alpn(mut self, protocols: &[&[u8]]) -> ClientConfig {
475 self.alpn = protocols.iter().map(|p| p.to_vec()).collect();
476 self
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483
484 #[test]
487 fn certificate_parsed_once_and_shared_by_clones() {
488 let ss = crate::certgen::self_signed_with_sans(&["a.example", "*.b.example"], 30);
489 let ck = CertifiedKey::new(vec![ss.cert_der.clone()], ss.key.clone()).unwrap();
490 assert_eq!(ck.names(), ["a.example".to_string(), "*.b.example".to_string()]);
491 let mut cfg = ServerConfig::new(ck.clone());
492 cfg.add_sni_cert(ck);
493 assert_eq!(cfg.sni_certs.len(), 2);
494 assert!(cfg.resolve(Some("x.b.example")).is_some());
495 let h3 = cfg.clone().with_alpn(&[b"h3"]);
496 assert!(Arc::ptr_eq(cfg.default_cert.as_ref().unwrap(), h3.default_cert.as_ref().unwrap()));
497 assert!(Arc::ptr_eq(cfg.ticketer.as_ref().unwrap(), h3.ticketer.as_ref().unwrap()));
498 assert!(cfg.alpn.is_empty() && h3.alpn == [b"h3".to_vec()]);
499 }
500}