zero_packet/network/extensions/
authentication.rs

1use core::fmt;
2
3/// The minimum length of an Authentication Header.
4pub const AUTHENTICATION_MIN_HEADER_LENGTH: usize = 12;
5
6/// Writes the Authentication Header fields.
7pub struct AuthenticationHeaderWriter<'a> {
8    pub bytes: &'a mut [u8],
9}
10
11impl<'a> AuthenticationHeaderWriter<'a> {
12    /// Creates a new `AuthenticationHeaderWriter` from the given data slice.
13    #[inline]
14    pub fn new(bytes: &'a mut [u8]) -> Result<Self, &'static str> {
15        if bytes.len() < AUTHENTICATION_MIN_HEADER_LENGTH {
16            return Err("Slice is too short to contain an Authentication extension header.");
17        }
18
19        Ok(Self { bytes })
20    }
21
22    /// Returns the total header length in bytes.
23    #[inline]
24    pub fn header_len(&self) -> usize {
25        (self.bytes[1] as usize + 2) * 4
26    }
27
28    /// Sets the next header field.
29    ///
30    /// Identifies the type of the next header.
31    #[inline]
32    pub fn set_next_header(&mut self, next_header: u8) {
33        self.bytes[0] = next_header;
34    }
35
36    /// Sets the payload length field.
37    ///
38    /// Length of this Authentication Header with scaling factor of 4, minus 2.
39    ///
40    /// E.g: Header length = (payload_len + 2) * 4.
41    #[inline]
42    pub fn set_payload_len(&mut self, payload_len: u8) {
43        self.bytes[1] = payload_len;
44    }
45
46    /// Sets the reserved field.
47    ///
48    /// Should be all zeros.
49    #[inline]
50    pub fn set_reserved(&mut self, reserved: u16) {
51        self.bytes[2] = (reserved >> 8) as u8;
52        self.bytes[3] = reserved as u8;
53    }
54
55    /// Sets the Security Parameters Index field.
56    ///
57    /// Arbitrary value which is used (together with the dest_addr) to identify the security association of the receiving party.
58    #[inline]
59    pub fn set_spi(&mut self, spi: u32) {
60        self.bytes[4] = (spi >> 24) as u8;
61        self.bytes[5] = (spi >> 16) as u8;
62        self.bytes[6] = (spi >> 8) as u8;
63        self.bytes[7] = spi as u8;
64    }
65
66    /// Sets the sequence number field.
67    ///
68    /// Monotonically increasing counter value to prevent replay attacks.
69    #[inline]
70    pub fn set_sequence_number(&mut self, sequence_number: u32) {
71        self.bytes[8] = (sequence_number >> 24) as u8;
72        self.bytes[9] = (sequence_number >> 16) as u8;
73        self.bytes[10] = (sequence_number >> 8) as u8;
74        self.bytes[11] = sequence_number as u8;
75    }
76
77    /// Sets the authentication data field.
78    ///
79    /// Padding:
80    /// - 4-octet alignment for IPv4 packets.
81    /// - 8-octet alignment for IPv6 packets.
82    #[inline]
83    pub fn set_authentication_data(&mut self, data: &[u8]) -> Result<(), &'static str> {
84        let start_offset = 12;
85        let end_offset = start_offset + data.len();
86
87        if end_offset > self.bytes.len() {
88            return Err("Authentication data exceeds the allocated header length.");
89        }
90
91        self.bytes[start_offset..end_offset].copy_from_slice(data);
92
93        Ok(())
94    }
95}
96
97/// Reads the Authentication extension header fields.
98pub struct AuthenticationHeaderReader<'a> {
99    pub bytes: &'a [u8],
100}
101
102impl<'a> AuthenticationHeaderReader<'a> {
103    /// Creates a new `AuthenticationHeaderReader` from the given data slice.
104    #[inline]
105    pub fn new(bytes: &'a [u8]) -> Result<Self, &'static str> {
106        if bytes.len() < AUTHENTICATION_MIN_HEADER_LENGTH {
107            return Err("Slice is too short to contain an Authentication extension header.");
108        }
109
110        Ok(Self { bytes })
111    }
112
113    /// Returns the next header field.
114    ///
115    /// Specifies the type of the next header.
116    #[inline]
117    pub fn next_header(&self) -> u8 {
118        self.bytes[0]
119    }
120
121    /// Returns the payload length field.
122    ///
123    /// Length of the payload in 32-bit words, minus 2.
124    #[inline]
125    pub fn payload_len(&self) -> u8 {
126        self.bytes[1]
127    }
128
129    /// Returns the reserved field.
130    ///
131    /// Should be all zeroes.
132    #[inline]
133    pub fn reserved(&self) -> u16 {
134        ((self.bytes[2] as u16) << 8) | self.bytes[3] as u16
135    }
136
137    /// Returns the Security Parameters Index field.
138    ///
139    /// Arbitrary value which is used (together with the dest_addr) to identify the security association of the receiving party.
140    #[inline]
141    pub fn spi(&self) -> u32 {
142        ((self.bytes[4] as u32) << 24)
143            | ((self.bytes[5] as u32) << 16)
144            | ((self.bytes[6] as u32) << 8)
145            | self.bytes[7] as u32
146    }
147
148    /// Returns the sequence number field.
149    ///
150    /// Monotonically increasing counter value to prevent replay attacks.
151    #[inline]
152    pub fn sequence_number(&self) -> u32 {
153        ((self.bytes[8] as u32) << 24)
154            | ((self.bytes[9] as u32) << 16)
155            | ((self.bytes[10] as u32) << 8)
156            | self.bytes[11] as u32
157    }
158
159    /// Returns the authentication data field.
160    ///
161    /// Variable-length field.
162    #[inline]
163    pub fn authentication_data(&self) -> Result<&'a [u8], &'static str> {
164        if self.bytes.len() < self.header_len() {
165            return Err("Indicated Authentication header length exceeds the allocated buffer.");
166        }
167
168        Ok(&self.bytes[12..self.header_len()])
169    }
170
171    /// Returns the total header length in bytes.
172    #[inline]
173    pub fn header_len(&self) -> usize {
174        (self.bytes[1] as usize + 2) * 4
175    }
176
177    /// Returns a reference to the header.
178    #[inline]
179    pub fn header(&self) -> Result<&'a [u8], &'static str> {
180        let end = self.header_len();
181
182        if end > self.bytes.len() {
183            return Err("Indicated Authentication header length exceeds the allocated buffer.");
184        }
185
186        Ok(&self.bytes[..end])
187    }
188
189    /// Returns a reference to the payload.
190    #[inline]
191    pub fn payload(&self) -> Result<&'a [u8], &'static str> {
192        let start = self.header_len();
193
194        if start > self.bytes.len() {
195            return Err("Indicated Authentication header length exceeds the allocated buffer.");
196        }
197
198        Ok(&self.bytes[self.header_len()..])
199    }
200}
201
202impl fmt::Debug for AuthenticationHeaderReader<'_> {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        f.debug_struct("AuthenticationHeader")
205            .field("next_header", &self.next_header())
206            .field("payload_len", &self.payload_len())
207            .field("reserved", &self.reserved())
208            .field("spi", &self.spi())
209            .field("sequence_number", &self.sequence_number())
210            .field("authentication_data", &self.authentication_data())
211            .finish()
212    }
213}
214
215#[cfg(test)]
216pub mod tests {
217    use super::*;
218
219    #[test]
220    fn getters_and_setters() {
221        // Raw packet.
222        let mut bytes = [0; 20];
223
224        // Random values.
225        let next_header = 17;
226        let payload_len = 2; // (payload_len + 2) * 4 = 16
227        let reserved = 0;
228        let spi = 305419896;
229        let sequence_number = 2271560481;
230        let auth_data = [1, 2, 3, 4];
231
232        // Write values.
233        let mut writer = AuthenticationHeaderWriter::new(&mut bytes).unwrap();
234        writer.set_next_header(next_header);
235        writer.set_payload_len(payload_len);
236        writer.set_reserved(reserved);
237        writer.set_spi(spi);
238        writer.set_sequence_number(sequence_number);
239        writer.set_authentication_data(&auth_data).unwrap();
240
241        // Read values.
242        let reader = AuthenticationHeaderReader::new(&bytes).unwrap();
243
244        assert_eq!(reader.next_header(), next_header);
245        assert_eq!(reader.payload_len(), payload_len);
246        assert_eq!(reader.reserved(), reserved);
247        assert_eq!(reader.spi(), spi);
248        assert_eq!(reader.sequence_number(), sequence_number);
249        assert_eq!(reader.authentication_data().unwrap(), &auth_data);
250    }
251}