1 use crate::msgs::base::{PayloadU8, PayloadU16};
2 use crate::msgs::codec::{Codec, Reader};
3 use crate::msgs::enums::{CipherSuite, ProtocolVersion};
4 use crate::msgs::handshake::CertificatePayload;
5 use crate::msgs::handshake::SessionID;
6 
7 use webpki;
8 
9 use std::cmp;
10 use std::mem;
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     pub server_cert_chain: CertificatePayload,
66 }
67 
68 impl Codec for ClientSessionValue {
encode(&self, bytes: &mut Vec<u8>)69     fn encode(&self, bytes: &mut Vec<u8>) {
70         self.version.encode(bytes);
71         self.cipher_suite.encode(bytes);
72         self.session_id.encode(bytes);
73         self.ticket.encode(bytes);
74         self.master_secret.encode(bytes);
75         self.epoch.encode(bytes);
76         self.lifetime.encode(bytes);
77         self.age_add.encode(bytes);
78         (if self.extended_ms { 1u8 } else { 0u8 }).encode(bytes);
79         self.max_early_data_size.encode(bytes);
80         self.server_cert_chain.encode(bytes);
81     }
82 
read(r: &mut Reader) -> Option<ClientSessionValue>83     fn read(r: &mut Reader) -> Option<ClientSessionValue> {
84         let v = ProtocolVersion::read(r)?;
85         let cs = CipherSuite::read(r)?;
86         let sid = SessionID::read(r)?;
87         let ticket = PayloadU16::read(r)?;
88         let ms = PayloadU8::read(r)?;
89         let epoch = u64::read(r)?;
90         let lifetime = u32::read(r)?;
91         let age_add = u32::read(r)?;
92         let extended_ms = u8::read(r)?;
93         let max_early_data_size = u32::read(r)?;
94         let server_cert_chain = CertificatePayload::read(r)?;
95 
96         Some(ClientSessionValue {
97             version: v,
98             cipher_suite: cs,
99             session_id: sid,
100             ticket,
101             master_secret: ms,
102             epoch,
103             lifetime,
104             age_add,
105             extended_ms: extended_ms == 1u8,
106             max_early_data_size,
107             server_cert_chain,
108         })
109     }
110 }
111 
112 static MAX_TICKET_LIFETIME: u32 = 7 * 24 * 60 * 60;
113 
114 impl ClientSessionValue {
new( v: ProtocolVersion, cs: CipherSuite, sessid: &SessionID, ticket: Vec<u8>, ms: Vec<u8>, server_cert_chain: &CertificatePayload, ) -> ClientSessionValue115     pub fn new(
116         v: ProtocolVersion,
117         cs: CipherSuite,
118         sessid: &SessionID,
119         ticket: Vec<u8>,
120         ms: Vec<u8>,
121         server_cert_chain: &CertificatePayload,
122     ) -> ClientSessionValue {
123         ClientSessionValue {
124             version: v,
125             cipher_suite: cs,
126             session_id: *sessid,
127             ticket: PayloadU16::new(ticket),
128             master_secret: PayloadU8::new(ms),
129             epoch: 0,
130             lifetime: 0,
131             age_add: 0,
132             extended_ms: false,
133             max_early_data_size: 0,
134             server_cert_chain: server_cert_chain.clone(),
135         }
136     }
137 
set_extended_ms_used(&mut self)138     pub fn set_extended_ms_used(&mut self) {
139         self.extended_ms = true;
140     }
141 
set_times(&mut self, receipt_time_secs: u64, lifetime_secs: u32, age_add: u32)142     pub fn set_times(&mut self, receipt_time_secs: u64, lifetime_secs: u32, age_add: u32) {
143         self.epoch = receipt_time_secs;
144         self.lifetime = cmp::min(lifetime_secs, MAX_TICKET_LIFETIME);
145         self.age_add = age_add;
146     }
147 
has_expired(&self, time_now: u64) -> bool148     pub fn has_expired(&self, time_now: u64) -> bool {
149         self.lifetime != 0 && self.epoch + u64::from(self.lifetime) < time_now
150     }
151 
get_obfuscated_ticket_age(&self, time_now: u64) -> u32152     pub fn get_obfuscated_ticket_age(&self, time_now: u64) -> u32 {
153         let age_secs = time_now.saturating_sub(self.epoch);
154         let age_millis = age_secs as u32 * 1000;
155         age_millis.wrapping_add(self.age_add)
156     }
157 
take_ticket(&mut self) -> Vec<u8>158     pub fn take_ticket(&mut self) -> Vec<u8> {
159         let new_ticket = PayloadU16::new(Vec::new());
160         let old_ticket = mem::replace(&mut self.ticket, new_ticket);
161         old_ticket.0
162     }
163 
set_max_early_data_size(&mut self, sz: u32)164     pub fn set_max_early_data_size(&mut self, sz: u32) {
165         self.max_early_data_size = sz;
166     }
167 }
168 
169 // --- Server types ---
170 pub type ServerSessionKey = SessionID;
171 
172 #[derive(Debug)]
173 pub struct ServerSessionValue {
174     pub sni: Option<webpki::DNSName>,
175     pub version: ProtocolVersion,
176     pub cipher_suite: CipherSuite,
177     pub master_secret: PayloadU8,
178     pub extended_ms: bool,
179     pub client_cert_chain: Option<CertificatePayload>,
180     pub alpn: Option<PayloadU8>,
181     pub application_data: PayloadU16,
182 }
183 
184 impl Codec for ServerSessionValue {
encode(&self, bytes: &mut Vec<u8>)185     fn encode(&self, bytes: &mut Vec<u8>) {
186         if let Some(ref sni) = self.sni {
187             1u8.encode(bytes);
188             let sni_bytes: &str = sni.as_ref().into();
189             PayloadU8::new(Vec::from(sni_bytes)).encode(bytes);
190         } else {
191             0u8.encode(bytes);
192         }
193         self.version.encode(bytes);
194         self.cipher_suite.encode(bytes);
195         self.master_secret.encode(bytes);
196         (if self.extended_ms { 1u8 } else { 0u8 }).encode(bytes);
197         if let Some(ref chain) = self.client_cert_chain {
198             1u8.encode(bytes);
199             chain.encode(bytes);
200         } else {
201             0u8.encode(bytes);
202         }
203         if let Some(ref alpn) = self.alpn {
204             1u8.encode(bytes);
205             alpn.encode(bytes);
206         } else {
207             0u8.encode(bytes);
208         }
209         self.application_data.encode(bytes);
210     }
211 
read(r: &mut Reader) -> Option<ServerSessionValue>212     fn read(r: &mut Reader) -> Option<ServerSessionValue> {
213         let has_sni = u8::read(r)?;
214         let sni = if has_sni == 1 {
215             let dns_name = PayloadU8::read(r)?;
216             let dns_name = webpki::DNSNameRef::try_from_ascii(&dns_name.0).ok()?;
217             Some(dns_name.into())
218         } else {
219             None
220         };
221         let v = ProtocolVersion::read(r)?;
222         let cs = CipherSuite::read(r)?;
223         let ms = PayloadU8::read(r)?;
224         let ems = u8::read(r)?;
225         let has_ccert = u8::read(r)? == 1;
226         let ccert = if has_ccert {
227             Some(CertificatePayload::read(r)?)
228         } else {
229             None
230         };
231         let has_alpn = u8::read(r)? == 1;
232         let alpn = if has_alpn {
233             Some(PayloadU8::read(r)?)
234         } else {
235             None
236         };
237         let application_data = PayloadU16::read(r)?;
238 
239         Some(ServerSessionValue {
240             sni,
241             version: v,
242             cipher_suite: cs,
243             master_secret: ms,
244             extended_ms: ems == 1u8,
245             client_cert_chain: ccert,
246             alpn,
247             application_data,
248         })
249     }
250 }
251 
252 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>, ) -> ServerSessionValue253     pub fn new(
254         sni: Option<&webpki::DNSName>,
255         v: ProtocolVersion,
256         cs: CipherSuite,
257         ms: Vec<u8>,
258         cert_chain: &Option<CertificatePayload>,
259         alpn: Option<Vec<u8>>,
260         application_data: Vec<u8>,
261     ) -> ServerSessionValue {
262         ServerSessionValue {
263             sni: sni.cloned(),
264             version: v,
265             cipher_suite: cs,
266             master_secret: PayloadU8::new(ms),
267             extended_ms: false,
268             client_cert_chain: cert_chain.clone(),
269             alpn: alpn.map(PayloadU8::new),
270             application_data: PayloadU16::new(application_data),
271         }
272     }
273 
set_extended_ms_used(&mut self)274     pub fn set_extended_ms_used(&mut self) {
275         self.extended_ms = true;
276     }
277 }
278