1use crate::msgs::base::{PayloadU8, PayloadU16};
2use crate::msgs::codec::{Codec, Reader};
3use crate::msgs::enums::{CipherSuite, ProtocolVersion};
4use crate::msgs::handshake::CertificatePayload;
5use crate::msgs::handshake::SessionID;
6
7use webpki;
8
9use std::cmp;
10use std::mem;
11
12#[derive(Debug)]
18pub struct ClientSessionKey {
19 kind: &'static [u8],
20 dns_name: PayloadU8,
21}
22
23impl Codec for ClientSessionKey {
24 fn encode(&self, bytes: &mut Vec<u8>) {
25 bytes.extend_from_slice(self.kind);
26 self.dns_name.encode(bytes);
27 }
28
29 fn read(_r: &mut Reader) -> Option<ClientSessionKey> {
31 None
32 }
33}
34
35impl ClientSessionKey {
36 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
44 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)]
54pub 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
68impl Codec for ClientSessionValue {
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
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
112static MAX_TICKET_LIFETIME: u32 = 7 * 24 * 60 * 60;
113
114impl ClientSessionValue {
115 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
138 pub fn set_extended_ms_used(&mut self) {
139 self.extended_ms = true;
140 }
141
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
148 pub fn has_expired(&self, time_now: u64) -> bool {
149 self.lifetime != 0 && self.epoch + u64::from(self.lifetime) < time_now
150 }
151
152 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
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
164 pub fn set_max_early_data_size(&mut self, sz: u32) {
165 self.max_early_data_size = sz;
166 }
167}
168
169pub type ServerSessionKey = SessionID;
171
172#[derive(Debug)]
173pub 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
184impl Codec for ServerSessionValue {
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
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
252impl ServerSessionValue {
253 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
274 pub fn set_extended_ms_used(&mut self) {
275 self.extended_ms = true;
276 }
277}