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}