Drop Initials with invalid retry token

This commit is contained in:
Benjamin Saunders
2022-03-25 09:40:26 -07:00
committed by Dirkjan Ochtman
parent 77302c2ab6
commit e1494d348c
2 changed files with 25 additions and 3 deletions
+21 -2
View File
@@ -1595,6 +1595,15 @@ impl Connection {
debug_assert!(self.side.is_server());
let len = packet.header_data.len() + packet.payload.len();
self.path.total_recvd = len as u64;
match self.state {
State::Handshake(ref mut state) => match packet.header {
Header::Initial { ref token, .. } => {
state.token = Some(token.clone());
}
_ => unreachable!("first packet must be an Initial packet"),
},
_ => unreachable!("first packet must be delivered in Handshake state"),
}
self.on_packet_authenticated(
now,
@@ -1916,6 +1925,18 @@ impl Connection {
trace!("dropping short packet during handshake");
return;
} else {
if let Header::Initial { ref token, .. } = packet.header {
if let State::Handshake(ref hs) = self.state {
if self.side.is_server() && Some(token) != hs.token.as_ref() {
// Clients must send the same retry token in every Initial. Initial
// packets can be spoofed, so we discard rather than killing the
// connection.
warn!("discarding Initial with invalid retry token");
return;
}
}
}
if !self.state.is_closed() {
let spin = match packet.header {
Header::Short { spin, .. } => spin,
@@ -3214,8 +3235,6 @@ mod state {
/// Always set for servers
pub rem_cid_set: bool,
/// Stateless retry token, if the peer has provided one
///
/// Only set for clients
pub token: Option<Bytes>,
/// First cryptographic message
///
+4 -1
View File
@@ -39,6 +39,7 @@ impl PacketBuilder {
conn: &mut Connection,
version: u32,
) -> Option<PacketBuilder> {
let is_client = conn.side().is_client();
// Initiate key update if we're approaching the confidentiality limit
let confidentiality_limit = conn.spaces[space_id]
.crypto
@@ -107,7 +108,9 @@ impl PacketBuilder {
src_cid: conn.handshake_cid,
dst_cid: conn.rem_cids.active(),
token: match conn.state {
State::Handshake(ref state) => state.token.clone().unwrap_or_else(Bytes::new),
State::Handshake(ref state) if is_client => {
state.token.clone().unwrap_or_else(Bytes::new)
}
_ => Bytes::new(),
},
number,