1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
use crate::{frame::Tag, varint::VarInt};
use core::{convert::TryInto, mem::size_of};
use s2n_codec::{decoder_invariant, decoder_parameterized_value, Encoder, EncoderValue};
//= https://www.rfc-editor.org/rfc/rfc9000#section-19.15
//# An endpoint sends a NEW_CONNECTION_ID frame (type=0x18) to provide
//# its peer with alternative connection IDs that can be used to break
//# linkability when migrating connections; see Section 9.5.
macro_rules! new_connection_id_tag {
() => {
0x18u8
};
}
//= https://www.rfc-editor.org/rfc/rfc9000#section-19.15
//# NEW_CONNECTION_ID Frame {
//# Type (i) = 0x18,
//# Sequence Number (i),
//# Retire Prior To (i),
//# Length (8),
//# Connection ID (8..160),
//# Stateless Reset Token (128),
//# }
//= https://www.rfc-editor.org/rfc/rfc9000#section-19.15
//# NEW_CONNECTION_ID frames contain the following fields:
//#
//# Sequence Number: The sequence number assigned to the connection ID
//# by the sender, encoded as a variable-length integer; see
//# Section 5.1.1.
//#
//# Retire Prior To: A variable-length integer indicating which
//# connection IDs should be retired; see Section 5.1.2.
//#
//# Length: An 8-bit unsigned integer containing the length of the
//# connection ID. Values less than 1 and greater than 20 are invalid
//# and MUST be treated as a connection error of type
//# FRAME_ENCODING_ERROR.
//#
//# Connection ID: A connection ID of the specified length.
//#
//# Stateless Reset Token: A 128-bit value that will be used for a
//# stateless reset when the associated connection ID is used; see
//# Section 10.3.
pub const STATELESS_RESET_TOKEN_LEN: usize = size_of::<u128>();
#[derive(Debug, PartialEq, Eq)]
pub struct NewConnectionId<'a> {
/// The sequence number assigned to the connection ID by the sender
pub sequence_number: VarInt,
/// A variable-length integer indicating which connection IDs
/// should be retired
pub retire_prior_to: VarInt,
/// The new connection ID
pub connection_id: &'a [u8],
/// A 128-bit value that will be used for a stateless reset when
/// the associated connection ID is used
pub stateless_reset_token: &'a [u8; STATELESS_RESET_TOKEN_LEN],
}
impl<'a> NewConnectionId<'a> {
pub const fn tag(&self) -> u8 {
new_connection_id_tag!()
}
}
decoder_parameterized_value!(
impl<'a> NewConnectionId<'a> {
fn decode(_tag: Tag, buffer: Buffer) -> Result<Self> {
let (sequence_number, buffer) = buffer.decode()?;
let (retire_prior_to, buffer) = buffer.decode()?;
//= https://www.rfc-editor.org/rfc/rfc9000#section-19.15
//# The value in the Retire Prior To field
//# MUST be less than or equal to the value in the Sequence Number field.
//= https://www.rfc-editor.org/rfc/rfc9000#section-19.15
//# Receiving a value in the Retire Prior To field that is greater than
//# that in the Sequence Number field MUST be treated as a connection
//# error of type FRAME_ENCODING_ERROR.
decoder_invariant!(
retire_prior_to <= sequence_number,
"invalid retire prior to value"
);
let (connection_id_len, buffer) = buffer.decode::<u8>()?;
//= https://www.rfc-editor.org/rfc/rfc9000#section-19.15
//# Values less than 1 and greater than 20 are invalid
//# and MUST be treated as a connection error of type
//# FRAME_ENCODING_ERROR.
decoder_invariant!(
(1..=20).contains(&connection_id_len),
"invalid connection id length"
);
let (connection_id, buffer) = buffer.decode_slice(connection_id_len.into())?;
let connection_id = connection_id.into_less_safe_slice();
let (stateless_reset_token, buffer) = buffer.decode_slice(STATELESS_RESET_TOKEN_LEN)?;
let stateless_reset_token: &[u8] = stateless_reset_token.into_less_safe_slice();
let stateless_reset_token = stateless_reset_token
.try_into()
.expect("Length has been already verified");
let frame = NewConnectionId {
sequence_number,
retire_prior_to,
connection_id,
stateless_reset_token,
};
Ok((frame, buffer))
}
}
);
impl<'a> EncoderValue for NewConnectionId<'a> {
fn encode<E: Encoder>(&self, buffer: &mut E) {
buffer.encode(&self.tag());
buffer.encode(&self.sequence_number);
buffer.encode(&self.retire_prior_to);
buffer.encode_with_len_prefix::<u8, _>(&self.connection_id);
buffer.encode(&self.stateless_reset_token.as_ref());
}
}