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