1 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 2 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 3 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 4 // option. This file may not be copied, modified, or distributed 5 // except according to those terms. 6 7 // This file implements functions necessary for address validation. 8 9 use neqo_common::{qinfo, qtrace, Decoder, Encoder, Role}; 10 use neqo_crypto::{ 11 constants::{TLS_AES_128_GCM_SHA256, TLS_VERSION_1_3}, 12 selfencrypt::SelfEncrypt, 13 }; 14 15 use crate::cid::ConnectionId; 16 use crate::packet::PacketBuilder; 17 use crate::recovery::RecoveryToken; 18 use crate::stats::FrameStats; 19 use crate::{Error, Res}; 20 21 use smallvec::SmallVec; 22 use std::convert::TryFrom; 23 use std::net::{IpAddr, SocketAddr}; 24 use std::time::{Duration, Instant}; 25 26 /// A prefix we add to Retry tokens to distinguish them from NEW_TOKEN tokens. 27 const TOKEN_IDENTIFIER_RETRY: &[u8] = &[0x52, 0x65, 0x74, 0x72, 0x79]; 28 /// A prefix on NEW_TOKEN tokens, that is maximally Hamming distant from NEW_TOKEN. 29 /// Together, these need to have a low probability of collision, even if there is 30 /// corruption of individual bits in transit. 31 const TOKEN_IDENTIFIER_NEW_TOKEN: &[u8] = &[0xad, 0x9a, 0x8b, 0x8d, 0x86]; 32 33 /// The maximum number of tokens we'll save from NEW_TOKEN frames. 34 /// This should be the same as the value of MAX_TICKETS in neqo-crypto. 35 const MAX_NEW_TOKEN: usize = 4; 36 /// The number of tokens we'll track for the purposes of looking for duplicates. 37 /// This is based on how many might be received over a period where could be 38 /// retransmissions. It should be at least `MAX_NEW_TOKEN`. 39 const MAX_SAVED_TOKENS: usize = 8; 40 41 /// `ValidateAddress` determines what sort of address validation is performed. 42 /// In short, this determines when a Retry packet is sent. 43 #[derive(Debug, PartialEq, Eq)] 44 pub enum ValidateAddress { 45 /// Require address validation never. 46 Never, 47 /// Require address validation unless a NEW_TOKEN token is provided. 48 NoToken, 49 /// Require address validation even if a NEW_TOKEN token is provided. 50 Always, 51 } 52 53 pub enum AddressValidationResult { 54 Pass, 55 ValidRetry(ConnectionId), 56 Validate, 57 Invalid, 58 } 59 60 pub struct AddressValidation { 61 /// What sort of validation is performed. 62 validation: ValidateAddress, 63 /// A self-encryption object used for protecting Retry tokens. 64 self_encrypt: SelfEncrypt, 65 /// When this object was created. 66 start_time: Instant, 67 } 68 69 impl AddressValidation { new(now: Instant, validation: ValidateAddress) -> Res<Self>70 pub fn new(now: Instant, validation: ValidateAddress) -> Res<Self> { 71 Ok(Self { 72 validation, 73 self_encrypt: SelfEncrypt::new(TLS_VERSION_1_3, TLS_AES_128_GCM_SHA256)?, 74 start_time: now, 75 }) 76 } 77 encode_aad(peer_address: SocketAddr, retry: bool) -> Encoder78 fn encode_aad(peer_address: SocketAddr, retry: bool) -> Encoder { 79 // Let's be "clever" by putting the peer's address in the AAD. 80 // We don't need to encode these into the token as they should be 81 // available when we need to check the token. 82 let mut aad = Encoder::default(); 83 if retry { 84 aad.encode(TOKEN_IDENTIFIER_RETRY); 85 } else { 86 aad.encode(TOKEN_IDENTIFIER_NEW_TOKEN); 87 } 88 match peer_address.ip() { 89 IpAddr::V4(a) => { 90 aad.encode_byte(4); 91 aad.encode(&a.octets()); 92 } 93 IpAddr::V6(a) => { 94 aad.encode_byte(6); 95 aad.encode(&a.octets()); 96 } 97 } 98 if retry { 99 aad.encode_uint(2, peer_address.port()); 100 } 101 aad 102 } 103 generate_token( &self, dcid: Option<&ConnectionId>, peer_address: SocketAddr, now: Instant, ) -> Res<Vec<u8>>104 pub fn generate_token( 105 &self, 106 dcid: Option<&ConnectionId>, 107 peer_address: SocketAddr, 108 now: Instant, 109 ) -> Res<Vec<u8>> { 110 const EXPIRATION_RETRY: Duration = Duration::from_secs(5); 111 const EXPIRATION_NEW_TOKEN: Duration = Duration::from_secs(60 * 60 * 24); 112 113 // TODO(mt) rotate keys on a fixed schedule. 114 let retry = dcid.is_some(); 115 let mut data = Encoder::default(); 116 let end = now 117 + if retry { 118 EXPIRATION_RETRY 119 } else { 120 EXPIRATION_NEW_TOKEN 121 }; 122 let end_millis = u32::try_from(end.duration_since(self.start_time).as_millis())?; 123 data.encode_uint(4, end_millis); 124 if let Some(dcid) = dcid { 125 data.encode(dcid); 126 } 127 128 // Include the token identifier ("Retry"/~) in the AAD, then keep it for plaintext. 129 let mut buf = Self::encode_aad(peer_address, retry); 130 let encrypted = self.self_encrypt.seal(&buf, &data)?; 131 buf.truncate(TOKEN_IDENTIFIER_RETRY.len()); 132 buf.encode(&encrypted); 133 Ok(buf.into()) 134 } 135 136 /// This generates a token for use with Retry. generate_retry_token( &self, dcid: &ConnectionId, peer_address: SocketAddr, now: Instant, ) -> Res<Vec<u8>>137 pub fn generate_retry_token( 138 &self, 139 dcid: &ConnectionId, 140 peer_address: SocketAddr, 141 now: Instant, 142 ) -> Res<Vec<u8>> { 143 self.generate_token(Some(dcid), peer_address, now) 144 } 145 146 /// This generates a token for use with NEW_TOKEN. generate_new_token(&self, peer_address: SocketAddr, now: Instant) -> Res<Vec<u8>>147 pub fn generate_new_token(&self, peer_address: SocketAddr, now: Instant) -> Res<Vec<u8>> { 148 self.generate_token(None, peer_address, now) 149 } 150 set_validation(&mut self, validation: ValidateAddress)151 pub fn set_validation(&mut self, validation: ValidateAddress) { 152 qtrace!("AddressValidation {:p}: set to {:?}", self, validation); 153 self.validation = validation; 154 } 155 156 /// Decrypts `token` and returns the connection ID it contains. 157 /// Returns a tuple with a boolean indicating whether this thinks 158 /// that the token was a Retry token, and a connection ID, that is 159 /// None if the token wasn't successfully decrypted. decrypt_token( &self, token: &[u8], peer_address: SocketAddr, retry: bool, now: Instant, ) -> Option<ConnectionId>160 fn decrypt_token( 161 &self, 162 token: &[u8], 163 peer_address: SocketAddr, 164 retry: bool, 165 now: Instant, 166 ) -> Option<ConnectionId> { 167 let peer_addr = Self::encode_aad(peer_address, retry); 168 let data = if let Ok(d) = self.self_encrypt.open(&peer_addr, token) { 169 d 170 } else { 171 return None; 172 }; 173 let mut dec = Decoder::new(&data); 174 match dec.decode_uint(4) { 175 Some(d) => { 176 let end = self.start_time + Duration::from_millis(d); 177 if end < now { 178 qtrace!("Expired token: {:?} vs. {:?}", end, now); 179 return None; 180 } 181 } 182 _ => return None, 183 } 184 Some(ConnectionId::from(dec.decode_remainder())) 185 } 186 187 /// Calculate the Hamming difference between our identifier and the target. 188 /// Less than one difference per byte indicates that it is likely not a Retry. 189 /// This generous interpretation allows for a lot of damage in transit. 190 /// Note that if this check fails, then the token will be treated like it came 191 /// from NEW_TOKEN instead. If there truly is corruption of packets that causes 192 /// validation failure, it will be a failure that we try to recover from. is_likely_retry(token: &[u8]) -> bool193 fn is_likely_retry(token: &[u8]) -> bool { 194 let mut difference = 0; 195 for i in 0..TOKEN_IDENTIFIER_RETRY.len() { 196 difference += (token[i] ^ TOKEN_IDENTIFIER_RETRY[i]).count_ones(); 197 } 198 usize::try_from(difference).unwrap() < TOKEN_IDENTIFIER_RETRY.len() 199 } 200 validate( &self, token: &[u8], peer_address: SocketAddr, now: Instant, ) -> AddressValidationResult201 pub fn validate( 202 &self, 203 token: &[u8], 204 peer_address: SocketAddr, 205 now: Instant, 206 ) -> AddressValidationResult { 207 qtrace!( 208 "AddressValidation {:p}: validate {:?}", 209 self, 210 self.validation 211 ); 212 213 if token.is_empty() { 214 if self.validation == ValidateAddress::Never { 215 qinfo!("AddressValidation: no token; accepting"); 216 return AddressValidationResult::Pass; 217 } else { 218 qinfo!("AddressValidation: no token; validating"); 219 return AddressValidationResult::Validate; 220 } 221 } 222 if token.len() <= TOKEN_IDENTIFIER_RETRY.len() { 223 // Treat bad tokens strictly. 224 qinfo!("AddressValidation: too short token"); 225 return AddressValidationResult::Invalid; 226 } 227 let retry = Self::is_likely_retry(token); 228 let enc = &token[TOKEN_IDENTIFIER_RETRY.len()..]; 229 // Note that this allows the token identifier part to be corrupted. 230 // That's OK here as we don't depend on that being authenticated. 231 if let Some(cid) = self.decrypt_token(enc, peer_address, retry, now) { 232 if retry { 233 // This is from Retry, so we should have an ODCID >= 8. 234 if cid.len() >= 8 { 235 qinfo!("AddressValidation: valid Retry token for {}", cid); 236 AddressValidationResult::ValidRetry(cid) 237 } else { 238 panic!("AddressValidation: Retry token with small CID {}", cid); 239 } 240 } else if cid.is_empty() { 241 // An empty connection ID means NEW_TOKEN. 242 if self.validation == ValidateAddress::Always { 243 qinfo!("AddressValidation: valid NEW_TOKEN token; validating again"); 244 AddressValidationResult::Validate 245 } else { 246 qinfo!("AddressValidation: valid NEW_TOKEN token; accepting"); 247 AddressValidationResult::Pass 248 } 249 } else { 250 panic!("AddressValidation: NEW_TOKEN token with CID {}", cid); 251 } 252 } else { 253 // From here on, we have a token that we couldn't decrypt. 254 // We've either lost the keys or we've received junk. 255 if retry { 256 // If this looked like a Retry, treat it as being bad. 257 qinfo!("AddressValidation: invalid Retry token; rejecting"); 258 AddressValidationResult::Invalid 259 } else if self.validation == ValidateAddress::Never { 260 // We don't require validation, so OK. 261 qinfo!("AddressValidation: invalid NEW_TOKEN token; accepting"); 262 AddressValidationResult::Pass 263 } else { 264 // This might be an invalid NEW_TOKEN token, or a valid one 265 // for which we have since lost the keys. Check again. 266 qinfo!("AddressValidation: invalid NEW_TOKEN token; validating again"); 267 AddressValidationResult::Validate 268 } 269 } 270 } 271 } 272 273 // Note: these lint override can be removed in later versions where the lints 274 // either don't trip a false positive or don't apply. rustc 1.46 is fine. 275 #[allow(dead_code, clippy::large_enum_variant)] 276 pub enum NewTokenState { 277 Client { 278 /// Tokens that haven't been taken yet. 279 pending: SmallVec<[Vec<u8>; MAX_NEW_TOKEN]>, 280 /// Tokens that have been taken, saved so that we can discard duplicates. 281 old: SmallVec<[Vec<u8>; MAX_SAVED_TOKENS]>, 282 }, 283 Server(NewTokenSender), 284 } 285 286 impl NewTokenState { new(role: Role) -> Self287 pub fn new(role: Role) -> Self { 288 match role { 289 Role::Client => Self::Client { 290 pending: SmallVec::<[_; MAX_NEW_TOKEN]>::new(), 291 old: SmallVec::<[_; MAX_SAVED_TOKENS]>::new(), 292 }, 293 Role::Server => Self::Server(NewTokenSender::default()), 294 } 295 } 296 297 /// Is there a token available? has_token(&self) -> bool298 pub fn has_token(&self) -> bool { 299 match self { 300 Self::Client { ref pending, .. } => !pending.is_empty(), 301 Self::Server(..) => false, 302 } 303 } 304 305 /// If this is a client, take a token if there is one. 306 /// If this is a server, panic. take_token(&mut self) -> Option<&[u8]>307 pub fn take_token(&mut self) -> Option<&[u8]> { 308 if let Self::Client { 309 ref mut pending, 310 ref mut old, 311 } = self 312 { 313 if let Some(t) = pending.pop() { 314 if old.len() >= MAX_SAVED_TOKENS { 315 old.remove(0); 316 } 317 old.push(t); 318 Some(&old[old.len() - 1]) 319 } else { 320 None 321 } 322 } else { 323 unreachable!(); 324 } 325 } 326 327 /// If this is a client, save a token. 328 /// If this is a server, panic. save_token(&mut self, token: Vec<u8>)329 pub fn save_token(&mut self, token: Vec<u8>) { 330 if let Self::Client { 331 ref mut pending, 332 ref old, 333 } = self 334 { 335 for t in old.iter().rev().chain(pending.iter().rev()) { 336 if t == &token { 337 qinfo!("NewTokenState discarding duplicate NEW_TOKEN"); 338 return; 339 } 340 } 341 342 if pending.len() >= MAX_NEW_TOKEN { 343 pending.remove(0); 344 } 345 pending.push(token); 346 } else { 347 unreachable!(); 348 } 349 } 350 351 /// If this is a server, maybe send a frame. 352 /// If this is a client, do nothing. write_frames( &mut self, builder: &mut PacketBuilder, tokens: &mut Vec<RecoveryToken>, stats: &mut FrameStats, ) -> Res<()>353 pub fn write_frames( 354 &mut self, 355 builder: &mut PacketBuilder, 356 tokens: &mut Vec<RecoveryToken>, 357 stats: &mut FrameStats, 358 ) -> Res<()> { 359 if let Self::Server(ref mut sender) = self { 360 sender.write_frames(builder, tokens, stats)?; 361 } 362 Ok(()) 363 } 364 365 /// If this a server, buffer a NEW_TOKEN for sending. 366 /// If this is a client, panic. send_new_token(&mut self, token: Vec<u8>)367 pub fn send_new_token(&mut self, token: Vec<u8>) { 368 if let Self::Server(ref mut sender) = self { 369 sender.send_new_token(token); 370 } else { 371 unreachable!(); 372 } 373 } 374 375 /// If this a server, process a lost signal for a NEW_TOKEN frame. 376 /// If this is a client, panic. lost(&mut self, seqno: usize)377 pub fn lost(&mut self, seqno: usize) { 378 if let Self::Server(ref mut sender) = self { 379 sender.lost(seqno); 380 } else { 381 unreachable!(); 382 } 383 } 384 385 /// If this a server, process remove the acknowledged NEW_TOKEN frame. 386 /// If this is a client, panic. acked(&mut self, seqno: usize)387 pub fn acked(&mut self, seqno: usize) { 388 if let Self::Server(ref mut sender) = self { 389 sender.acked(seqno); 390 } else { 391 unreachable!(); 392 } 393 } 394 } 395 396 struct NewTokenFrameStatus { 397 seqno: usize, 398 token: Vec<u8>, 399 needs_sending: bool, 400 } 401 402 impl NewTokenFrameStatus { len(&self) -> usize403 fn len(&self) -> usize { 404 1 + Encoder::vvec_len(self.token.len()) 405 } 406 } 407 408 #[derive(Default)] 409 pub struct NewTokenSender { 410 /// The unacknowledged NEW_TOKEN frames we are yet to send. 411 tokens: Vec<NewTokenFrameStatus>, 412 /// A sequence number that is used to track individual tokens 413 /// by reference (so that recovery tokens can be simple). 414 next_seqno: usize, 415 } 416 417 impl NewTokenSender { 418 /// Add a token to be sent. send_new_token(&mut self, token: Vec<u8>)419 pub fn send_new_token(&mut self, token: Vec<u8>) { 420 self.tokens.push(NewTokenFrameStatus { 421 seqno: self.next_seqno, 422 token, 423 needs_sending: true, 424 }); 425 self.next_seqno += 1; 426 } 427 write_frames( &mut self, builder: &mut PacketBuilder, tokens: &mut Vec<RecoveryToken>, stats: &mut FrameStats, ) -> Res<()>428 pub fn write_frames( 429 &mut self, 430 builder: &mut PacketBuilder, 431 tokens: &mut Vec<RecoveryToken>, 432 stats: &mut FrameStats, 433 ) -> Res<()> { 434 for t in self.tokens.iter_mut() { 435 if t.needs_sending && t.len() <= builder.remaining() { 436 t.needs_sending = false; 437 438 builder.encode_varint(crate::frame::FRAME_TYPE_NEW_TOKEN); 439 builder.encode_vvec(&t.token); 440 if builder.len() > builder.limit() { 441 return Err(Error::InternalError(7)); 442 } 443 444 tokens.push(RecoveryToken::NewToken(t.seqno)); 445 stats.new_token += 1; 446 } 447 } 448 Ok(()) 449 } 450 lost(&mut self, seqno: usize)451 pub fn lost(&mut self, seqno: usize) { 452 for t in self.tokens.iter_mut() { 453 if t.seqno == seqno { 454 t.needs_sending = true; 455 break; 456 } 457 } 458 } 459 acked(&mut self, seqno: usize)460 pub fn acked(&mut self, seqno: usize) { 461 self.tokens.retain(|i| i.seqno != seqno); 462 } 463 } 464 465 #[cfg(test)] 466 mod tests { 467 use super::NewTokenState; 468 use neqo_common::Role; 469 470 const ONE: &[u8] = &[1, 2, 3]; 471 const TWO: &[u8] = &[4, 5]; 472 473 #[test] duplicate_saved()474 fn duplicate_saved() { 475 let mut tokens = NewTokenState::new(Role::Client); 476 tokens.save_token(ONE.to_vec()); 477 tokens.save_token(TWO.to_vec()); 478 tokens.save_token(ONE.to_vec()); 479 assert!(tokens.has_token()); 480 assert!(tokens.take_token().is_some()); // probably TWO 481 assert!(tokens.has_token()); 482 assert!(tokens.take_token().is_some()); // probably ONE 483 assert!(!tokens.has_token()); 484 assert!(tokens.take_token().is_none()); 485 } 486 487 #[test] duplicate_after_take()488 fn duplicate_after_take() { 489 let mut tokens = NewTokenState::new(Role::Client); 490 tokens.save_token(ONE.to_vec()); 491 tokens.save_token(TWO.to_vec()); 492 assert!(tokens.has_token()); 493 assert!(tokens.take_token().is_some()); // probably TWO 494 tokens.save_token(ONE.to_vec()); 495 assert!(tokens.has_token()); 496 assert!(tokens.take_token().is_some()); // probably ONE 497 assert!(!tokens.has_token()); 498 assert!(tokens.take_token().is_none()); 499 } 500 501 #[test] duplicate_after_empty()502 fn duplicate_after_empty() { 503 let mut tokens = NewTokenState::new(Role::Client); 504 tokens.save_token(ONE.to_vec()); 505 tokens.save_token(TWO.to_vec()); 506 assert!(tokens.has_token()); 507 assert!(tokens.take_token().is_some()); // probably TWO 508 assert!(tokens.has_token()); 509 assert!(tokens.take_token().is_some()); // probably ONE 510 tokens.save_token(ONE.to_vec()); 511 assert!(!tokens.has_token()); 512 assert!(tokens.take_token().is_none()); 513 } 514 } 515