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