/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rustls-0.23.23/src/msgs/persist.rs
Line | Count | Source |
1 | | use alloc::vec::Vec; |
2 | | use core::cmp; |
3 | | |
4 | | use pki_types::{DnsName, UnixTime}; |
5 | | use zeroize::Zeroizing; |
6 | | |
7 | | use crate::enums::{CipherSuite, ProtocolVersion}; |
8 | | use crate::error::InvalidMessage; |
9 | | use crate::msgs::base::{PayloadU16, PayloadU8}; |
10 | | use crate::msgs::codec::{Codec, Reader}; |
11 | | use crate::msgs::handshake::CertificateChain; |
12 | | #[cfg(feature = "tls12")] |
13 | | use crate::msgs::handshake::SessionId; |
14 | | use crate::sync::Arc; |
15 | | #[cfg(feature = "tls12")] |
16 | | use crate::tls12::Tls12CipherSuite; |
17 | | use crate::tls13::Tls13CipherSuite; |
18 | | |
19 | | pub(crate) struct Retrieved<T> { |
20 | | pub(crate) value: T, |
21 | | retrieved_at: UnixTime, |
22 | | } |
23 | | |
24 | | impl<T> Retrieved<T> { |
25 | 0 | pub(crate) fn new(value: T, retrieved_at: UnixTime) -> Self { |
26 | 0 | Self { |
27 | 0 | value, |
28 | 0 | retrieved_at, |
29 | 0 | } |
30 | 0 | } |
31 | | |
32 | 0 | pub(crate) fn map<M>(&self, f: impl FnOnce(&T) -> Option<&M>) -> Option<Retrieved<&M>> { |
33 | | Some(Retrieved { |
34 | 0 | value: f(&self.value)?, |
35 | 0 | retrieved_at: self.retrieved_at, |
36 | | }) |
37 | 0 | } |
38 | | } |
39 | | |
40 | | impl Retrieved<&Tls13ClientSessionValue> { |
41 | 0 | pub(crate) fn obfuscated_ticket_age(&self) -> u32 { |
42 | 0 | let age_secs = self |
43 | 0 | .retrieved_at |
44 | 0 | .as_secs() |
45 | 0 | .saturating_sub(self.value.common.epoch); |
46 | 0 | let age_millis = age_secs as u32 * 1000; |
47 | 0 | age_millis.wrapping_add(self.value.age_add) |
48 | 0 | } |
49 | | } |
50 | | |
51 | | impl<T: core::ops::Deref<Target = ClientSessionCommon>> Retrieved<T> { |
52 | 0 | pub(crate) fn has_expired(&self) -> bool { |
53 | 0 | let common = &*self.value; |
54 | 0 | common.lifetime_secs != 0 |
55 | 0 | && common |
56 | 0 | .epoch |
57 | 0 | .saturating_add(u64::from(common.lifetime_secs)) |
58 | 0 | < self.retrieved_at.as_secs() |
59 | 0 | } |
60 | | } |
61 | | |
62 | | impl<T> core::ops::Deref for Retrieved<T> { |
63 | | type Target = T; |
64 | | |
65 | 0 | fn deref(&self) -> &Self::Target { |
66 | 0 | &self.value |
67 | 0 | } Unexecuted instantiation: <rustls::msgs::persist::Retrieved<rustls::client::hs::ClientSessionValue> as core::ops::deref::Deref>::deref Unexecuted instantiation: <rustls::msgs::persist::Retrieved<&rustls::msgs::persist::Tls13ClientSessionValue> as core::ops::deref::Deref>::deref |
68 | | } |
69 | | |
70 | | #[derive(Debug)] |
71 | | pub struct Tls13ClientSessionValue { |
72 | | suite: &'static Tls13CipherSuite, |
73 | | age_add: u32, |
74 | | max_early_data_size: u32, |
75 | | pub(crate) common: ClientSessionCommon, |
76 | | quic_params: PayloadU16, |
77 | | } |
78 | | |
79 | | impl Tls13ClientSessionValue { |
80 | 0 | pub(crate) fn new( |
81 | 0 | suite: &'static Tls13CipherSuite, |
82 | 0 | ticket: Arc<PayloadU16>, |
83 | 0 | secret: &[u8], |
84 | 0 | server_cert_chain: CertificateChain<'static>, |
85 | 0 | time_now: UnixTime, |
86 | 0 | lifetime_secs: u32, |
87 | 0 | age_add: u32, |
88 | 0 | max_early_data_size: u32, |
89 | 0 | ) -> Self { |
90 | 0 | Self { |
91 | 0 | suite, |
92 | 0 | age_add, |
93 | 0 | max_early_data_size, |
94 | 0 | common: ClientSessionCommon::new( |
95 | 0 | ticket, |
96 | 0 | secret, |
97 | 0 | time_now, |
98 | 0 | lifetime_secs, |
99 | 0 | server_cert_chain, |
100 | 0 | ), |
101 | 0 | quic_params: PayloadU16(Vec::new()), |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | 0 | pub fn max_early_data_size(&self) -> u32 { |
106 | 0 | self.max_early_data_size |
107 | 0 | } |
108 | | |
109 | 0 | pub fn suite(&self) -> &'static Tls13CipherSuite { |
110 | 0 | self.suite |
111 | 0 | } |
112 | | |
113 | | #[doc(hidden)] |
114 | | /// Test only: rewind epoch by `delta` seconds. |
115 | 0 | pub fn rewind_epoch(&mut self, delta: u32) { |
116 | 0 | self.common.epoch -= delta as u64; |
117 | 0 | } |
118 | | |
119 | | #[doc(hidden)] |
120 | | /// Test only: replace `max_early_data_size` with `new` |
121 | 0 | pub fn _private_set_max_early_data_size(&mut self, new: u32) { |
122 | 0 | self.max_early_data_size = new; |
123 | 0 | } |
124 | | |
125 | 0 | pub fn set_quic_params(&mut self, quic_params: &[u8]) { |
126 | 0 | self.quic_params = PayloadU16(quic_params.to_vec()); |
127 | 0 | } |
128 | | |
129 | 0 | pub fn quic_params(&self) -> Vec<u8> { |
130 | 0 | self.quic_params.0.clone() |
131 | 0 | } |
132 | | } |
133 | | |
134 | | impl core::ops::Deref for Tls13ClientSessionValue { |
135 | | type Target = ClientSessionCommon; |
136 | | |
137 | 0 | fn deref(&self) -> &Self::Target { |
138 | 0 | &self.common |
139 | 0 | } |
140 | | } |
141 | | |
142 | | #[derive(Debug, Clone)] |
143 | | pub struct Tls12ClientSessionValue { |
144 | | #[cfg(feature = "tls12")] |
145 | | suite: &'static Tls12CipherSuite, |
146 | | #[cfg(feature = "tls12")] |
147 | | pub(crate) session_id: SessionId, |
148 | | #[cfg(feature = "tls12")] |
149 | | extended_ms: bool, |
150 | | #[doc(hidden)] |
151 | | #[cfg(feature = "tls12")] |
152 | | pub(crate) common: ClientSessionCommon, |
153 | | } |
154 | | |
155 | | #[cfg(feature = "tls12")] |
156 | | impl Tls12ClientSessionValue { |
157 | | pub(crate) fn new( |
158 | | suite: &'static Tls12CipherSuite, |
159 | | session_id: SessionId, |
160 | | ticket: Arc<PayloadU16>, |
161 | | master_secret: &[u8], |
162 | | server_cert_chain: CertificateChain<'static>, |
163 | | time_now: UnixTime, |
164 | | lifetime_secs: u32, |
165 | | extended_ms: bool, |
166 | | ) -> Self { |
167 | | Self { |
168 | | suite, |
169 | | session_id, |
170 | | extended_ms, |
171 | | common: ClientSessionCommon::new( |
172 | | ticket, |
173 | | master_secret, |
174 | | time_now, |
175 | | lifetime_secs, |
176 | | server_cert_chain, |
177 | | ), |
178 | | } |
179 | | } |
180 | | |
181 | | pub(crate) fn ticket(&mut self) -> Arc<PayloadU16> { |
182 | | Arc::clone(&self.common.ticket) |
183 | | } |
184 | | |
185 | | pub(crate) fn extended_ms(&self) -> bool { |
186 | | self.extended_ms |
187 | | } |
188 | | |
189 | | pub(crate) fn suite(&self) -> &'static Tls12CipherSuite { |
190 | | self.suite |
191 | | } |
192 | | |
193 | | #[doc(hidden)] |
194 | | /// Test only: rewind epoch by `delta` seconds. |
195 | | pub fn rewind_epoch(&mut self, delta: u32) { |
196 | | self.common.epoch -= delta as u64; |
197 | | } |
198 | | } |
199 | | |
200 | | #[cfg(feature = "tls12")] |
201 | | impl core::ops::Deref for Tls12ClientSessionValue { |
202 | | type Target = ClientSessionCommon; |
203 | | |
204 | | fn deref(&self) -> &Self::Target { |
205 | | &self.common |
206 | | } |
207 | | } |
208 | | |
209 | | #[derive(Debug, Clone)] |
210 | | pub struct ClientSessionCommon { |
211 | | ticket: Arc<PayloadU16>, |
212 | | secret: Zeroizing<PayloadU8>, |
213 | | epoch: u64, |
214 | | lifetime_secs: u32, |
215 | | server_cert_chain: Arc<CertificateChain<'static>>, |
216 | | } |
217 | | |
218 | | impl ClientSessionCommon { |
219 | 0 | fn new( |
220 | 0 | ticket: Arc<PayloadU16>, |
221 | 0 | secret: &[u8], |
222 | 0 | time_now: UnixTime, |
223 | 0 | lifetime_secs: u32, |
224 | 0 | server_cert_chain: CertificateChain<'static>, |
225 | 0 | ) -> Self { |
226 | 0 | Self { |
227 | 0 | ticket, |
228 | 0 | secret: Zeroizing::new(PayloadU8(secret.to_vec())), |
229 | 0 | epoch: time_now.as_secs(), |
230 | 0 | lifetime_secs: cmp::min(lifetime_secs, MAX_TICKET_LIFETIME), |
231 | 0 | server_cert_chain: Arc::new(server_cert_chain), |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | 0 | pub(crate) fn server_cert_chain(&self) -> &CertificateChain<'static> { |
236 | 0 | &self.server_cert_chain |
237 | 0 | } |
238 | | |
239 | 0 | pub(crate) fn secret(&self) -> &[u8] { |
240 | 0 | self.secret.0.as_ref() |
241 | 0 | } |
242 | | |
243 | 0 | pub(crate) fn ticket(&self) -> &[u8] { |
244 | 0 | self.ticket.0.as_ref() |
245 | 0 | } |
246 | | } |
247 | | |
248 | | static MAX_TICKET_LIFETIME: u32 = 7 * 24 * 60 * 60; |
249 | | |
250 | | /// This is the maximum allowed skew between server and client clocks, over |
251 | | /// the maximum ticket lifetime period. This encompasses TCP retransmission |
252 | | /// times in case packet loss occurs when the client sends the ClientHello |
253 | | /// or receives the NewSessionTicket, _and_ actual clock skew over this period. |
254 | | static MAX_FRESHNESS_SKEW_MS: u32 = 60 * 1000; |
255 | | |
256 | | // --- Server types --- |
257 | | #[derive(Debug)] |
258 | | pub struct ServerSessionValue { |
259 | | pub(crate) sni: Option<DnsName<'static>>, |
260 | | pub(crate) version: ProtocolVersion, |
261 | | pub(crate) cipher_suite: CipherSuite, |
262 | | pub(crate) master_secret: Zeroizing<PayloadU8>, |
263 | | pub(crate) extended_ms: bool, |
264 | | pub(crate) client_cert_chain: Option<CertificateChain<'static>>, |
265 | | pub(crate) alpn: Option<PayloadU8>, |
266 | | pub(crate) application_data: PayloadU16, |
267 | | pub creation_time_sec: u64, |
268 | | pub(crate) age_obfuscation_offset: u32, |
269 | | freshness: Option<bool>, |
270 | | } |
271 | | |
272 | | impl Codec<'_> for ServerSessionValue { |
273 | 0 | fn encode(&self, bytes: &mut Vec<u8>) { |
274 | 0 | if let Some(ref sni) = self.sni { |
275 | 0 | 1u8.encode(bytes); |
276 | 0 | let sni_bytes: &str = sni.as_ref(); |
277 | 0 | PayloadU8::new(Vec::from(sni_bytes)).encode(bytes); |
278 | 0 | } else { |
279 | 0 | 0u8.encode(bytes); |
280 | 0 | } |
281 | 0 | self.version.encode(bytes); |
282 | 0 | self.cipher_suite.encode(bytes); |
283 | 0 | self.master_secret.encode(bytes); |
284 | 0 | (u8::from(self.extended_ms)).encode(bytes); |
285 | 0 | if let Some(ref chain) = self.client_cert_chain { |
286 | 0 | 1u8.encode(bytes); |
287 | 0 | chain.encode(bytes); |
288 | 0 | } else { |
289 | 0 | 0u8.encode(bytes); |
290 | 0 | } |
291 | 0 | if let Some(ref alpn) = self.alpn { |
292 | 0 | 1u8.encode(bytes); |
293 | 0 | alpn.encode(bytes); |
294 | 0 | } else { |
295 | 0 | 0u8.encode(bytes); |
296 | 0 | } |
297 | 0 | self.application_data.encode(bytes); |
298 | 0 | self.creation_time_sec.encode(bytes); |
299 | 0 | self.age_obfuscation_offset |
300 | 0 | .encode(bytes); |
301 | 0 | } |
302 | | |
303 | 0 | fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { |
304 | 0 | let has_sni = u8::read(r)?; |
305 | 0 | let sni = if has_sni == 1 { |
306 | 0 | let dns_name = PayloadU8::read(r)?; |
307 | 0 | let dns_name = match DnsName::try_from(dns_name.0.as_slice()) { |
308 | 0 | Ok(dns_name) => dns_name.to_owned(), |
309 | 0 | Err(_) => return Err(InvalidMessage::InvalidServerName), |
310 | | }; |
311 | | |
312 | 0 | Some(dns_name) |
313 | | } else { |
314 | 0 | None |
315 | | }; |
316 | | |
317 | 0 | let v = ProtocolVersion::read(r)?; |
318 | 0 | let cs = CipherSuite::read(r)?; |
319 | 0 | let ms = Zeroizing::new(PayloadU8::read(r)?); |
320 | 0 | let ems = u8::read(r)?; |
321 | 0 | let has_ccert = u8::read(r)? == 1; |
322 | 0 | let ccert = if has_ccert { |
323 | 0 | Some(CertificateChain::read(r)?.into_owned()) |
324 | | } else { |
325 | 0 | None |
326 | | }; |
327 | 0 | let has_alpn = u8::read(r)? == 1; |
328 | 0 | let alpn = if has_alpn { |
329 | 0 | Some(PayloadU8::read(r)?) |
330 | | } else { |
331 | 0 | None |
332 | | }; |
333 | 0 | let application_data = PayloadU16::read(r)?; |
334 | 0 | let creation_time_sec = u64::read(r)?; |
335 | 0 | let age_obfuscation_offset = u32::read(r)?; |
336 | | |
337 | 0 | Ok(Self { |
338 | 0 | sni, |
339 | 0 | version: v, |
340 | 0 | cipher_suite: cs, |
341 | 0 | master_secret: ms, |
342 | 0 | extended_ms: ems == 1u8, |
343 | 0 | client_cert_chain: ccert, |
344 | 0 | alpn, |
345 | 0 | application_data, |
346 | 0 | creation_time_sec, |
347 | 0 | age_obfuscation_offset, |
348 | 0 | freshness: None, |
349 | 0 | }) |
350 | 0 | } |
351 | | } |
352 | | |
353 | | impl ServerSessionValue { |
354 | 0 | pub(crate) fn new( |
355 | 0 | sni: Option<&DnsName<'_>>, |
356 | 0 | v: ProtocolVersion, |
357 | 0 | cs: CipherSuite, |
358 | 0 | ms: &[u8], |
359 | 0 | client_cert_chain: Option<CertificateChain<'static>>, |
360 | 0 | alpn: Option<Vec<u8>>, |
361 | 0 | application_data: Vec<u8>, |
362 | 0 | creation_time: UnixTime, |
363 | 0 | age_obfuscation_offset: u32, |
364 | 0 | ) -> Self { |
365 | | Self { |
366 | 0 | sni: sni.map(|dns| dns.to_owned()), |
367 | 0 | version: v, |
368 | 0 | cipher_suite: cs, |
369 | 0 | master_secret: Zeroizing::new(PayloadU8::new(ms.to_vec())), |
370 | | extended_ms: false, |
371 | 0 | client_cert_chain, |
372 | 0 | alpn: alpn.map(PayloadU8::new), |
373 | 0 | application_data: PayloadU16::new(application_data), |
374 | 0 | creation_time_sec: creation_time.as_secs(), |
375 | 0 | age_obfuscation_offset, |
376 | 0 | freshness: None, |
377 | | } |
378 | 0 | } |
379 | | |
380 | | #[cfg(feature = "tls12")] |
381 | | pub(crate) fn set_extended_ms_used(&mut self) { |
382 | | self.extended_ms = true; |
383 | | } |
384 | | |
385 | 0 | pub(crate) fn set_freshness( |
386 | 0 | mut self, |
387 | 0 | obfuscated_client_age_ms: u32, |
388 | 0 | time_now: UnixTime, |
389 | 0 | ) -> Self { |
390 | 0 | let client_age_ms = obfuscated_client_age_ms.wrapping_sub(self.age_obfuscation_offset); |
391 | 0 | let server_age_ms = (time_now |
392 | 0 | .as_secs() |
393 | 0 | .saturating_sub(self.creation_time_sec) as u32) |
394 | 0 | .saturating_mul(1000); |
395 | | |
396 | 0 | let age_difference = if client_age_ms < server_age_ms { |
397 | 0 | server_age_ms - client_age_ms |
398 | | } else { |
399 | 0 | client_age_ms - server_age_ms |
400 | | }; |
401 | | |
402 | 0 | self.freshness = Some(age_difference <= MAX_FRESHNESS_SKEW_MS); |
403 | 0 | self |
404 | 0 | } |
405 | | |
406 | 0 | pub(crate) fn is_fresh(&self) -> bool { |
407 | 0 | self.freshness.unwrap_or_default() |
408 | 0 | } |
409 | | } |
410 | | |
411 | | #[cfg(test)] |
412 | | mod tests { |
413 | | use super::*; |
414 | | |
415 | | #[cfg(feature = "std")] // for UnixTime::now |
416 | | #[test] |
417 | | fn serversessionvalue_is_debug() { |
418 | | use std::{println, vec}; |
419 | | let ssv = ServerSessionValue::new( |
420 | | None, |
421 | | ProtocolVersion::TLSv1_3, |
422 | | CipherSuite::TLS13_AES_128_GCM_SHA256, |
423 | | &[1, 2, 3], |
424 | | None, |
425 | | None, |
426 | | vec![4, 5, 6], |
427 | | UnixTime::now(), |
428 | | 0x12345678, |
429 | | ); |
430 | | println!("{:?}", ssv); |
431 | | } |
432 | | |
433 | | #[test] |
434 | | fn serversessionvalue_no_sni() { |
435 | | let bytes = [ |
436 | | 0x00, 0x03, 0x03, 0xc0, 0x23, 0x03, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, |
437 | | 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0xfe, 0xed, 0xf0, 0x0d, |
438 | | ]; |
439 | | let mut rd = Reader::init(&bytes); |
440 | | let ssv = ServerSessionValue::read(&mut rd).unwrap(); |
441 | | assert_eq!(ssv.get_encoding(), bytes); |
442 | | } |
443 | | |
444 | | #[test] |
445 | | fn serversessionvalue_with_cert() { |
446 | | let bytes = [ |
447 | | 0x00, 0x03, 0x03, 0xc0, 0x23, 0x03, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, |
448 | | 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0xfe, 0xed, 0xf0, 0x0d, |
449 | | ]; |
450 | | let mut rd = Reader::init(&bytes); |
451 | | let ssv = ServerSessionValue::read(&mut rd).unwrap(); |
452 | | assert_eq!(ssv.get_encoding(), bytes); |
453 | | } |
454 | | } |