s2n_quic_core/frame/
new_connection_id.rs

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