s2n_quic_core/packet/
version_negotiation.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::packet::{
5    initial::ProtectedInitial,
6    long::{
7        validate_destination_connection_id_len, validate_source_connection_id_len,
8        DestinationConnectionIdLen, SourceConnectionIdLen, Version,
9    },
10    Tag,
11};
12use core::mem::size_of;
13use s2n_codec::{
14    decoder_invariant, DecoderBuffer, DecoderBufferMut, DecoderBufferMutResult, Encoder,
15    EncoderValue,
16};
17
18//= https://www.rfc-editor.org/rfc/rfc9000#section-17.2.1
19//# Version Negotiation Packet {
20//#   Header Form (1) = 1,
21//#   Unused (7),
22//#   Version (32) = 0,
23//#   Destination Connection ID Length (8),
24//#   Destination Connection ID (0..2040),
25//#   Source Connection ID Length (8),
26//#   Source Connection ID (0..2040),
27//#   Supported Version (32) ...,
28//# }
29
30//= https://www.rfc-editor.org/rfc/rfc9000#section-17.2.1
31//# The value in the Unused field is set to an arbitrary value by the
32//# server.  Clients MUST ignore the value of this field.  Where QUIC
33//# might be multiplexed with other protocols (see [RFC7983]), servers
34//# SHOULD set the most significant bit of this field (0x40) to 1 so that
35//# Version Negotiation packets appear to have the Fixed Bit field.
36
37macro_rules! version_negotiation_no_fixed_bit_tag {
38    () => {
39        0b1000u8..=0b1011u8
40    };
41}
42
43const ENCODING_TAG: u8 = 0b1100_0000;
44
45//= https://www.rfc-editor.org/rfc/rfc9000#section-17.2.1
46//# The Version field of a Version Negotiation packet MUST be set to
47//# 0x00000000.
48
49pub(crate) const VERSION: u32 = 0x0000_0000;
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
52pub struct VersionNegotiation<'a, SupportedVersions> {
53    pub tag: Tag,
54    pub destination_connection_id: &'a [u8],
55    pub source_connection_id: &'a [u8],
56    pub supported_versions: SupportedVersions,
57}
58
59pub type ProtectedVersionNegotiation<'a> = VersionNegotiation<'a, &'a [u8]>;
60pub type EncryptedVersionNegotiation<'a> = VersionNegotiation<'a, &'a [u8]>;
61pub type CleartextVersionNegotiation<'a> = VersionNegotiation<'a, &'a [u8]>;
62
63impl<'a> ProtectedVersionNegotiation<'a> {
64    #[inline]
65    pub fn decode(
66        tag: Tag,
67        _version: Version,
68        buffer: DecoderBufferMut<'_>,
69    ) -> DecoderBufferMutResult<'_, VersionNegotiation<'_, &[u8]>> {
70        let buffer = buffer
71            .skip(size_of::<Tag>() + size_of::<Version>())
72            .expect("tag and version already verified");
73
74        let (destination_connection_id, buffer) =
75            buffer.decode_slice_with_len_prefix::<DestinationConnectionIdLen>()?;
76        let destination_connection_id = destination_connection_id.into_less_safe_slice();
77        validate_destination_connection_id_len(destination_connection_id.len())?;
78
79        let (source_connection_id, buffer) =
80            buffer.decode_slice_with_len_prefix::<SourceConnectionIdLen>()?;
81        let source_connection_id = source_connection_id.into_less_safe_slice();
82        validate_source_connection_id_len(source_connection_id.len())?;
83
84        let (supported_versions, buffer) = buffer.decode::<DecoderBufferMut>()?;
85        let supported_versions: &[u8] = supported_versions.into_less_safe_slice();
86
87        // ensure at least one version is present
88        decoder_invariant!(
89            supported_versions.len() >= size_of::<u32>(),
90            "missing at least one version"
91        );
92
93        // ensure payload length can successfully decode a list of u32s
94        decoder_invariant!(
95            supported_versions.len() % size_of::<u32>() == 0,
96            "invalid payload length"
97        );
98
99        let packet = VersionNegotiation {
100            tag,
101            destination_connection_id,
102            source_connection_id,
103            supported_versions,
104        };
105
106        Ok((packet, buffer))
107    }
108
109    #[inline]
110    pub fn iter(&'a self) -> VersionNegotiationIterator<'a> {
111        self.into_iter()
112    }
113
114    #[inline]
115    pub fn destination_connection_id(&self) -> &[u8] {
116        self.destination_connection_id
117    }
118
119    #[inline]
120    pub fn source_connection_id(&self) -> &[u8] {
121        self.source_connection_id
122    }
123}
124
125impl<'a, SupportedVersions: EncoderValue> VersionNegotiation<'a, SupportedVersions> {
126    pub fn from_initial(
127        initial_packet: &'a ProtectedInitial,
128        supported_versions: SupportedVersions,
129    ) -> Self {
130        // The destination and source connection IDs are flipped because this packet is being sent
131        // back to the client.
132        Self {
133            tag: 0,
134            //= https://www.rfc-editor.org/rfc/rfc9000#section-17.2.1
135            //# The server MUST include the value from the Source Connection ID field
136            //# of the packet it receives in the Destination Connection ID field.
137            destination_connection_id: initial_packet.source_connection_id(),
138            //= https://www.rfc-editor.org/rfc/rfc9000#section-17.2.1
139            //# The value for Source Connection ID MUST be copied from the
140            //# Destination Connection ID of the received packet, which is initially
141            //# randomly selected by a client.
142            source_connection_id: initial_packet.destination_connection_id(),
143            supported_versions,
144        }
145    }
146}
147
148impl<'a> IntoIterator for ProtectedVersionNegotiation<'a> {
149    type IntoIter = VersionNegotiationIterator<'a>;
150    type Item = u32;
151
152    fn into_iter(self) -> Self::IntoIter {
153        VersionNegotiationIterator(DecoderBuffer::new(self.supported_versions))
154    }
155}
156
157#[derive(Clone, Copy, Debug)]
158pub struct VersionNegotiationIterator<'a>(DecoderBuffer<'a>);
159
160impl Iterator for VersionNegotiationIterator<'_> {
161    type Item = u32;
162
163    fn next(&mut self) -> Option<Self::Item> {
164        if let Ok((value, buffer)) = self.0.decode() {
165            self.0 = buffer;
166            Some(value)
167        } else {
168            None
169        }
170    }
171}
172
173impl<SupportedVersions: EncoderValue> EncoderValue for VersionNegotiation<'_, SupportedVersions> {
174    fn encode<E: Encoder>(&self, encoder: &mut E) {
175        (self.tag | ENCODING_TAG).encode(encoder);
176        VERSION.encode(encoder);
177        self.destination_connection_id
178            .encode_with_len_prefix::<DestinationConnectionIdLen, _>(encoder);
179        self.source_connection_id
180            .encode_with_len_prefix::<SourceConnectionIdLen, _>(encoder);
181        self.supported_versions.encode(encoder);
182    }
183}