diff --git a/quinn-proto/src/token.rs b/quinn-proto/src/token.rs index 59dcc5575..5a2b8c224 100644 --- a/quinn-proto/src/token.rs +++ b/quinn-proto/src/token.rs @@ -13,6 +13,59 @@ use crate::{ Duration, ServerConfig, SystemTime, RESET_TOKEN_SIZE, UNIX_EPOCH, }; +/// State in an `Incoming` determined by a token or lack thereof +#[derive(Debug)] +pub(crate) struct IncomingToken { + pub(crate) retry_src_cid: Option, + pub(crate) orig_dst_cid: ConnectionId, +} + +impl IncomingToken { + /// Construct for an `Incoming` given the first packet header, or error if the connection + /// cannot be established + pub(crate) fn from_header( + header: &InitialHeader, + server_config: &ServerConfig, + remote_address: SocketAddr, + ) -> Result { + let unvalidated = Self { + retry_src_cid: None, + orig_dst_cid: header.dst_cid, + }; + + if header.token.is_empty() { + return Ok(unvalidated); + } + + let result = RetryToken::from_bytes( + &*server_config.token_key, + &remote_address, + &header.dst_cid, + &header.token, + ); + + let retry = match result { + Ok(retry) => retry, + Err(ValidationError::Unusable) => return Ok(unvalidated), + Err(ValidationError::InvalidRetry) => return Err(InvalidRetryTokenError), + }; + + if retry.issued + server_config.retry_token_lifetime < server_config.time_source.now() { + return Err(InvalidRetryTokenError); + } + + Ok(Self { + retry_src_cid: Some(header.dst_cid), + orig_dst_cid: retry.orig_dst_cid, + }) + } +} + +/// Error for a token being unambiguously from a Retry packet, and not valid +/// +/// The connection cannot be established. +pub(crate) struct InvalidRetryTokenError; + pub(crate) struct RetryToken { /// The destination connection ID set in the very first packet from the client pub(crate) orig_dst_cid: ConnectionId, @@ -72,22 +125,6 @@ impl RetryToken { issued, }) } - - /// Ensure that this token validates an `Incoming`, and construct its token state - fn validate( - &self, - header: &InitialHeader, - server_config: &ServerConfig, - ) -> Result { - if self.issued + server_config.retry_token_lifetime < server_config.time_source.now() { - return Err(ValidationError::InvalidRetry); - } - - Ok(IncomingToken { - retry_src_cid: Some(header.dst_cid), - orig_dst_cid: self.orig_dst_cid, - }) - } } fn encode_addr(buf: &mut Vec, address: &SocketAddr) { @@ -195,52 +232,6 @@ impl fmt::Display for ResetToken { } } -/// State in an `Incoming` determined by a token or lack thereof -#[derive(Debug)] -pub(crate) struct IncomingToken { - pub(crate) retry_src_cid: Option, - pub(crate) orig_dst_cid: ConnectionId, -} - -impl IncomingToken { - /// Construct for an `Incoming` which is not validated by a token - fn unvalidated(header: &InitialHeader) -> Self { - Self { - retry_src_cid: None, - orig_dst_cid: header.dst_cid, - } - } - - /// Construct for an `Incoming` given the first packet header, or error if the connection - /// cannot be established - pub(crate) fn from_header( - header: &InitialHeader, - server_config: &ServerConfig, - remote_address: SocketAddr, - ) -> Result { - if header.token.is_empty() { - return Ok(Self::unvalidated(header)); - } - - RetryToken::from_bytes( - &*server_config.token_key, - &remote_address, - &header.dst_cid, - &header.token, - ) - .and_then(|token| token.validate(header, server_config)) - .or_else(|e| match e { - ValidationError::Unusable => Ok(Self::unvalidated(header)), - ValidationError::InvalidRetry => Err(InvalidRetryTokenError), - }) - } -} - -/// Error for a token being unambiguously from a Retry packet, and not valid -/// -/// The connection cannot be established. -pub(crate) struct InvalidRetryTokenError; - #[cfg(all(test, any(feature = "aws-lc-rs", feature = "ring")))] mod test { #[cfg(all(feature = "aws-lc-rs", not(feature = "ring")))]