1 use crate::msgs::handshake::SessionID;
2 use crate::msgs::enums::{CipherSuite, ProtocolVersion};
3 use crate::msgs::codec::{Reader, Codec};
4 use crate::msgs::handshake::CertificatePayload;
5 use crate::msgs::base::{PayloadU8, PayloadU16};
6 
7 use webpki;
8 
9 use std::mem;
10 use std::cmp;
11 
12 // These are the keys and values we store in session storage.
13 
14 // --- Client types ---
15 /// Keys for session resumption and tickets.
16 /// Matching value is a `ClientSessionValue`.
17 #[derive(Debug)]
18 pub struct ClientSessionKey {
19     kind: &'static [u8],
20     dns_name: PayloadU8,
21 }
22 
23 impl Codec for ClientSessionKey {
encode(&self, bytes: &mut Vec<u8>)24     fn encode(&self, bytes: &mut Vec<u8>) {
25         bytes.extend_from_slice(self.kind);
26         self.dns_name.encode(bytes);
27     }
28 
29     // Don't need to read these.
read(_r: &mut Reader) -> Option<ClientSessionKey>30     fn read(_r: &mut Reader) -> Option<ClientSessionKey> {
31         None
32     }
33 }
34 
35 impl ClientSessionKey {
session_for_dns_name(dns_name: webpki::DNSNameRef) -> ClientSessionKey36     pub fn session_for_dns_name(dns_name: webpki::DNSNameRef) -> ClientSessionKey {
37         let dns_name_str: &str = dns_name.into();
38         ClientSessionKey {
39             kind: b"session",
40             dns_name: PayloadU8::new(dns_name_str.as_bytes().to_vec()),
41         }
42     }
43 
hint_for_dns_name(dns_name: webpki::DNSNameRef) -> ClientSessionKey44     pub fn hint_for_dns_name(dns_name: webpki::DNSNameRef) -> ClientSessionKey {
45         let dns_name_str: &str = dns_name.into();
46         ClientSessionKey {
47             kind: b"kx-hint",
48             dns_name: PayloadU8::new(dns_name_str.as_bytes().to_vec()),
49         }
50     }
51 }
52 
53 #[derive(Debug)]
54 pub struct ClientSessionValue {
55     pub version: ProtocolVersion,
56     pub cipher_suite: CipherSuite,
57     pub session_id: SessionID,
58     pub ticket: PayloadU16,
59     pub master_secret: PayloadU8,
60     pub epoch: u64,
61     pub lifetime: u32,
62     pub age_add: u32,
63     pub extended_ms: bool,
64     pub max_early_data_size: u32,
65 }
66 
67 impl Codec for ClientSessionValue {
encode(&self, bytes: &mut Vec<u8>)68     fn encode(&self, bytes: &mut Vec<u8>) {
69         self.version.encode(bytes);
70         self.cipher_suite.encode(bytes);
71         self.session_id.encode(bytes);
72         self.ticket.encode(bytes);
73         self.master_secret.encode(bytes);
74         self.epoch.encode(bytes);
75         self.lifetime.encode(bytes);
76         self.age_add.encode(bytes);
77         (if self.extended_ms { 1u8 } else { 0u8 }).encode(bytes);
78         self.max_early_data_size.encode(bytes);
79     }
80 
read(r: &mut Reader) -> Option<ClientSessionValue>81     fn read(r: &mut Reader) -> Option<ClientSessionValue> {
82         let v = ProtocolVersion::read(r)?;
83         let cs = CipherSuite::read(r)?;
84         let sid = SessionID::read(r)?;
85         let ticket = PayloadU16::read(r)?;
86         let ms = PayloadU8::read(r)?;
87         let epoch = u64::read(r)?;
88         let lifetime = u32::read(r)?;
89         let age_add = u32::read(r)?;
90         let extended_ms = u8::read(r)?;
91         let max_early_data_size = u32::read(r)?;
92 
93         Some(ClientSessionValue {
94             version: v,
95             cipher_suite: cs,
96             session_id: sid,
97             ticket,
98             master_secret: ms,
99             epoch,
100             lifetime,
101             age_add,
102             extended_ms: extended_ms == 1u8,
103             max_early_data_size,
104         })
105     }
106 }
107 
108 static MAX_TICKET_LIFETIME: u32 = 7 * 24 * 60 * 60;
109 
110 impl ClientSessionValue {
new(v: ProtocolVersion, cs: CipherSuite, sessid: &SessionID, ticket: Vec<u8>, ms: Vec<u8>) -> ClientSessionValue111     pub fn new(v: ProtocolVersion,
112                cs: CipherSuite,
113                sessid: &SessionID,
114                ticket: Vec<u8>,
115                ms: Vec<u8>)
116                -> ClientSessionValue {
117         ClientSessionValue {
118             version: v,
119             cipher_suite: cs,
120             session_id: *sessid,
121             ticket: PayloadU16::new(ticket),
122             master_secret: PayloadU8::new(ms),
123             epoch: 0,
124             lifetime: 0,
125             age_add: 0,
126             extended_ms: false,
127             max_early_data_size: 0,
128         }
129     }
130 
set_extended_ms_used(&mut self)131     pub fn set_extended_ms_used(&mut self) {
132         self.extended_ms = true;
133     }
134 
set_times(&mut self, receipt_time_secs: u64, lifetime_secs: u32, age_add: u32)135     pub fn set_times(&mut self, receipt_time_secs: u64,
136                      lifetime_secs: u32, age_add: u32) {
137         self.epoch = receipt_time_secs;
138         self.lifetime = cmp::min(lifetime_secs, MAX_TICKET_LIFETIME);
139         self.age_add = age_add;
140     }
141 
has_expired(&self, time_now: u64) -> bool142     pub fn has_expired(&self, time_now: u64) -> bool {
143         self.lifetime != 0 && self.epoch + u64::from(self.lifetime) < time_now
144     }
145 
get_obfuscated_ticket_age(&self, time_now: u64) -> u32146     pub fn get_obfuscated_ticket_age(&self, time_now: u64) -> u32 {
147         let age_secs = time_now.saturating_sub(self.epoch);
148         let age_millis = age_secs as u32 * 1000;
149         age_millis.wrapping_add(self.age_add)
150     }
151 
take_ticket(&mut self) -> Vec<u8>152     pub fn take_ticket(&mut self) -> Vec<u8> {
153         let new_ticket = PayloadU16::new(Vec::new());
154         let old_ticket = mem::replace(&mut self.ticket, new_ticket);
155         old_ticket.0
156     }
157 
set_max_early_data_size(&mut self, sz: u32)158     pub fn set_max_early_data_size(&mut self, sz: u32) {
159         self.max_early_data_size = sz;
160     }
161 }
162 
163 // --- Server types ---
164 pub type ServerSessionKey = SessionID;
165 
166 #[derive(Debug)]
167 pub struct ServerSessionValue {
168     pub sni: Option<webpki::DNSName>,
169     pub version: ProtocolVersion,
170     pub cipher_suite: CipherSuite,
171     pub master_secret: PayloadU8,
172     pub extended_ms: bool,
173     pub client_cert_chain: Option<CertificatePayload>,
174     pub alpn: Option<PayloadU8>,
175     pub application_data: PayloadU16,
176 }
177 
178 impl Codec for ServerSessionValue {
encode(&self, bytes: &mut Vec<u8>)179     fn encode(&self, bytes: &mut Vec<u8>) {
180         if let Some(ref sni) = self.sni {
181             1u8.encode(bytes);
182             let sni_bytes: &str = sni.as_ref().into();
183             PayloadU8::new(Vec::from(sni_bytes)).encode(bytes);
184         } else {
185             0u8.encode(bytes);
186         }
187         self.version.encode(bytes);
188         self.cipher_suite.encode(bytes);
189         self.master_secret.encode(bytes);
190         (if self.extended_ms { 1u8 } else { 0u8 }).encode(bytes);
191         if let Some(ref chain) = self.client_cert_chain {
192             1u8.encode(bytes);
193             chain.encode(bytes);
194         } else {
195             0u8.encode(bytes);
196         }
197         if let Some(ref alpn) = self.alpn {
198             1u8.encode(bytes);
199             alpn.encode(bytes);
200         } else {
201             0u8.encode(bytes);
202         }
203         self.application_data.encode(bytes);
204     }
205 
read(r: &mut Reader) -> Option<ServerSessionValue>206     fn read(r: &mut Reader) -> Option<ServerSessionValue> {
207         let has_sni = u8::read(r)?;
208         let sni = if has_sni == 1 {
209             let dns_name = PayloadU8::read(r)?;
210             let dns_name = webpki::DNSNameRef::try_from_ascii(
211                 &dns_name.0).ok()?;
212             Some(dns_name.into())
213         } else {
214             None
215         };
216         let v = ProtocolVersion::read(r)?;
217         let cs = CipherSuite::read(r)?;
218         let ms = PayloadU8::read(r)?;
219         let ems = u8::read(r)?;
220         let has_ccert = u8::read(r)? == 1;
221         let ccert = if has_ccert {
222             Some(CertificatePayload::read(r)?)
223         } else {
224             None
225         };
226         let has_alpn = u8::read(r)? == 1;
227         let alpn = if has_alpn {
228             Some(PayloadU8::read(r)?)
229         } else {
230             None
231         };
232         let application_data = PayloadU16::read(r)?;
233 
234         Some(ServerSessionValue {
235             sni,
236             version: v,
237             cipher_suite: cs,
238             master_secret: ms,
239             extended_ms: ems == 1u8,
240             client_cert_chain: ccert,
241             alpn,
242             application_data,
243         })
244     }
245 }
246 
247 impl ServerSessionValue {
new(sni: Option<&webpki::DNSName>, v: ProtocolVersion, cs: CipherSuite, ms: Vec<u8>, cert_chain: &Option<CertificatePayload>, alpn: Option<Vec<u8>>, application_data: Vec<u8>) -> ServerSessionValue248     pub fn new(sni: Option<&webpki::DNSName>,
249                v: ProtocolVersion,
250                cs: CipherSuite,
251                ms: Vec<u8>,
252                cert_chain: &Option<CertificatePayload>,
253                alpn: Option<Vec<u8>>,
254                application_data: Vec<u8>)
255                -> ServerSessionValue {
256         ServerSessionValue {
257             sni: sni.cloned(),
258             version: v,
259             cipher_suite: cs,
260             master_secret: PayloadU8::new(ms),
261             extended_ms: false,
262             client_cert_chain: cert_chain.clone(),
263             alpn: alpn.map(PayloadU8::new),
264             application_data: PayloadU16::new(application_data),
265         }
266     }
267 
set_extended_ms_used(&mut self)268     pub fn set_extended_ms_used(&mut self) {
269         self.extended_ms = true;
270     }
271 }
272