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