Thanks to visit codestin.com
Credit goes to docs.rs

etherparse/net/
ip_auth_header.rs

1use super::super::*;
2use crate::err::ip_auth::IcvLenError;
3use arrayvec::ArrayVec;
4use core::fmt::{Debug, Formatter};
5
6/// Deprecated use [IpAuthHeader] instead.
7#[deprecated(since = "0.10.1", note = "Please use the type IpAuthHeader instead")]
8pub type IPv6AuthenticationHeader = IpAuthHeader;
9
10/// Deprecated use [IpAuthHeader] instead.
11#[deprecated(since = "0.14.0", note = "Please use the type IpAuthHeader instead")]
12pub type IpAuthenticationHeader = IpAuthHeader;
13
14/// IP Authentication Header (rfc4302)
15#[derive(Clone)]
16pub struct IpAuthHeader {
17    /// IP protocol number specifying the next header or transport layer protocol.
18    ///
19    /// See [IpNumber] or [ip_number] for a definition of the known values.
20    pub next_header: IpNumber,
21    /// Security Parameters Index
22    pub spi: u32,
23    /// This unsigned 32-bit field contains a counter value that
24    /// increases by one for each packet sent.
25    pub sequence_number: u32,
26    /// Length in 4-octets (maximum valid value is 0xfe) of data filled in the
27    /// `raw_icv_buffer`.
28    raw_icv_len: u8,
29    /// Buffer containing the "Encoded Integrity Check Value-ICV" (variable).
30    /// The length of the used data can be set via the `variable` (must be a multiple of 4 bytes).
31    raw_icv_buffer: [u8; 0xfe * 4],
32}
33
34impl Debug for IpAuthHeader {
35    fn fmt(&self, formatter: &mut Formatter) -> Result<(), core::fmt::Error> {
36        let mut s = formatter.debug_struct("IpAuthHeader");
37        s.field("next_header", &self.next_header);
38        s.field("spi", &self.spi);
39        s.field("sequence_number", &self.sequence_number);
40        s.field("raw_icv", &self.raw_icv());
41        s.finish()
42    }
43}
44
45impl PartialEq for IpAuthHeader {
46    fn eq(&self, other: &Self) -> bool {
47        self.next_header == other.next_header
48            && self.spi == other.spi
49            && self.sequence_number == other.sequence_number
50            && self.raw_icv() == other.raw_icv()
51    }
52}
53
54impl Eq for IpAuthHeader {}
55
56impl Default for IpAuthHeader {
57    fn default() -> Self {
58        IpAuthHeader {
59            next_header: IpNumber(255),
60            spi: 0,
61            sequence_number: 0,
62            raw_icv_len: 0,
63            raw_icv_buffer: [0; 0xfe * 4],
64        }
65    }
66}
67
68impl<'a> IpAuthHeader {
69    /// Minimum length of an IP authentication header in bytes/octets.
70    pub const MIN_LEN: usize = 4 + 4 + 4;
71
72    /// Maximum length of an IP authentication header in bytes/octets.
73    ///
74    /// This number is calculated by taking the maximum value
75    /// that the "payload length" field supports (0xff) adding 2 and
76    /// multiplying the sum by 4 as the "payload length" specifies how
77    /// many 4 bytes words are present in the header.
78    pub const MAX_LEN: usize = 4 * (0xff + 2);
79
80    /// The maximum amount of bytes/octets that can be stored in the ICV
81    /// part of an IP authentication header.
82    pub const MAX_ICV_LEN: usize = 0xfe * 4;
83
84    /// Create a new authentication header with the given parameters.
85    ///
86    /// Note: The length of the raw_icv slice must be a multiple of 4
87    /// and the maximum allowed length is 1016 bytes
88    /// (`IpAuthHeader::MAX_ICV_LEN`). If the slice length does
89    /// not fulfill these requirements the value is not copied and an
90    /// [`crate::err::ip_auth::IcvLenError`] is returned.
91    /// If successful an Ok(()) is returned.
92    pub fn new(
93        next_header: IpNumber,
94        spi: u32,
95        sequence_number: u32,
96        raw_icv: &'a [u8],
97    ) -> Result<IpAuthHeader, IcvLenError> {
98        use IcvLenError::*;
99        if raw_icv.len() > IpAuthHeader::MAX_ICV_LEN {
100            Err(TooBig(raw_icv.len()))
101        } else if 0 != raw_icv.len() % 4 {
102            Err(Unaligned(raw_icv.len()))
103        } else {
104            let mut result = IpAuthHeader {
105                next_header,
106                spi,
107                sequence_number,
108                raw_icv_len: (raw_icv.len() / 4) as u8,
109                raw_icv_buffer: [0; IpAuthHeader::MAX_ICV_LEN],
110            };
111            result.raw_icv_buffer[..raw_icv.len()].copy_from_slice(raw_icv);
112            Ok(result)
113        }
114    }
115
116    /// Read an  authentication header from a slice and return the header & unused parts of the slice.
117    pub fn from_slice(
118        slice: &'a [u8],
119    ) -> Result<(IpAuthHeader, &'a [u8]), err::ip_auth::HeaderSliceError> {
120        let s = IpAuthHeaderSlice::from_slice(slice)?;
121        let rest = &slice[s.slice().len()..];
122        let header = s.to_header();
123        Ok((header, rest))
124    }
125
126    /// Read an authentication header from the current reader position.
127    #[cfg(feature = "std")]
128    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
129    pub fn read<T: std::io::Read + Sized>(
130        reader: &mut T,
131    ) -> Result<IpAuthHeader, err::ip_auth::HeaderReadError> {
132        use err::ip_auth::HeaderError::*;
133        use err::ip_auth::HeaderReadError::*;
134
135        let start = {
136            let mut start = [0; 4 + 4 + 4];
137            reader.read_exact(&mut start).map_err(Io)?;
138            start
139        };
140
141        let next_header = IpNumber(start[0]);
142        let payload_len = start[1];
143
144        // payload len must be at least 1
145        if payload_len < 1 {
146            Err(Content(ZeroPayloadLen))
147        } else {
148            // read the rest of the header
149            Ok(IpAuthHeader {
150                next_header,
151                spi: u32::from_be_bytes([start[4], start[5], start[6], start[7]]),
152                sequence_number: u32::from_be_bytes([start[8], start[9], start[10], start[11]]),
153                raw_icv_len: payload_len - 1,
154                raw_icv_buffer: {
155                    let mut buffer = [0; 0xfe * 4];
156                    reader
157                        .read_exact(&mut buffer[..usize::from(payload_len - 1) * 4])
158                        .map_err(Io)?;
159                    buffer
160                },
161            })
162        }
163    }
164
165    /// Read an authentication header from the current reader position
166    /// with a limited reader.
167    #[cfg(feature = "std")]
168    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
169    pub fn read_limited<T: std::io::Read + Sized>(
170        reader: &mut crate::io::LimitedReader<T>,
171    ) -> Result<IpAuthHeader, err::ip_auth::HeaderLimitedReadError> {
172        use err::{
173            ip_auth::HeaderError::*,
174            ip_auth::HeaderLimitedReadError::{self, *},
175            Layer,
176        };
177
178        fn map_err(err: err::io::LimitedReadError) -> HeaderLimitedReadError {
179            use err::io::LimitedReadError as I;
180            match err {
181                I::Io(err) => Io(err),
182                I::Len(err) => Len(err),
183            }
184        }
185
186        // notify reader of layer start
187        reader.start_layer(Layer::IpAuthHeader);
188
189        let start = {
190            let mut start = [0; 4 + 4 + 4];
191            reader.read_exact(&mut start).map_err(map_err)?;
192            start
193        };
194
195        let next_header = IpNumber(start[0]);
196        let payload_len = start[1];
197
198        // payload len must be at least 1
199        if payload_len < 1 {
200            Err(Content(ZeroPayloadLen))
201        } else {
202            // read the rest of the header
203            Ok(IpAuthHeader {
204                next_header,
205                spi: u32::from_be_bytes([start[4], start[5], start[6], start[7]]),
206                sequence_number: u32::from_be_bytes([start[8], start[9], start[10], start[11]]),
207                raw_icv_len: payload_len - 1,
208                raw_icv_buffer: {
209                    let mut buffer = [0; 0xfe * 4];
210                    reader
211                        .read_exact(&mut buffer[..usize::from(payload_len - 1) * 4])
212                        .map_err(map_err)?;
213                    buffer
214                },
215            })
216        }
217    }
218
219    /// Returns a slice the raw icv value.
220    pub fn raw_icv(&self) -> &[u8] {
221        &self.raw_icv_buffer[..usize::from(self.raw_icv_len) * 4]
222    }
223
224    /// Sets the icv value to the given raw value. The length of the slice must be
225    /// a multiple of 4 and the maximum allowed length is 1016 bytes
226    /// (`IpAuthHeader::MAX_ICV_LEN`). If the slice length does
227    /// not fulfill these requirements the value is not copied and an
228    /// [`crate::err::ip_auth::IcvLenError`] is returned.
229    /// If successful an Ok(()) is returned.
230    pub fn set_raw_icv(&mut self, raw_icv: &[u8]) -> Result<(), IcvLenError> {
231        use IcvLenError::*;
232        if raw_icv.len() > IpAuthHeader::MAX_ICV_LEN {
233            Err(TooBig(raw_icv.len()))
234        } else if 0 != raw_icv.len() % 4 {
235            Err(Unaligned(raw_icv.len()))
236        } else {
237            self.raw_icv_buffer[..raw_icv.len()].copy_from_slice(raw_icv);
238            self.raw_icv_len = (raw_icv.len() / 4) as u8;
239            Ok(())
240        }
241    }
242
243    /// Writes the given authentication header to the current position.
244    #[cfg(feature = "std")]
245    #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
246    pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
247        let spi_be = self.spi.to_be_bytes();
248        let sequence_number_be = self.sequence_number.to_be_bytes();
249        debug_assert!(self.raw_icv_len != 0xff);
250
251        writer.write_all(&[
252            self.next_header.0,
253            self.raw_icv_len + 1,
254            0,
255            0,
256            spi_be[0],
257            spi_be[1],
258            spi_be[2],
259            spi_be[3],
260            sequence_number_be[0],
261            sequence_number_be[1],
262            sequence_number_be[2],
263            sequence_number_be[3],
264        ])?;
265        writer.write_all(self.raw_icv())?;
266        Ok(())
267    }
268
269    ///Length of the header in bytes.
270    pub fn header_len(&self) -> usize {
271        12 + usize::from(self.raw_icv_len) * 4
272    }
273
274    /// Returns the serialized header.
275    pub fn to_bytes(&self) -> ArrayVec<u8, { IpAuthHeader::MAX_LEN }> {
276        let spi_be = self.spi.to_be_bytes();
277        let seq_be = self.sequence_number.to_be_bytes();
278
279        let mut result = ArrayVec::<u8, { IpAuthHeader::MAX_LEN }>::new();
280        result.extend([
281            self.next_header.0,
282            self.raw_icv_len + 1,
283            0,
284            0,
285            spi_be[0],
286            spi_be[1],
287            spi_be[2],
288            spi_be[3],
289            seq_be[0],
290            seq_be[1],
291            seq_be[2],
292            seq_be[3],
293        ]);
294        result.extend(self.raw_icv_buffer);
295        // SAFETY: Safe as the header len can not exceed the maximum length
296        // of the header.
297        unsafe {
298            result.set_len(self.header_len());
299        }
300
301        result
302    }
303}
304
305#[cfg(test)]
306mod test {
307    use super::*;
308    use crate::{
309        err::{Layer, LenError},
310        io::LimitedReader,
311        test_gens::*,
312    };
313    use alloc::{format, vec::Vec};
314    use err::ip_auth::HeaderError::*;
315    use proptest::prelude::*;
316    use std::io::Cursor;
317
318    #[test]
319    fn default() {
320        let default_header = IpAuthHeader {
321            ..Default::default()
322        };
323
324        assert_eq!(default_header.next_header, IpNumber(255));
325        assert_eq!(default_header.spi, 0);
326        assert_eq!(default_header.sequence_number, 0);
327        assert_eq!(default_header.raw_icv_len, 0);
328        assert_eq!(default_header.raw_icv_buffer, [0; 0xfe * 4]);
329    }
330
331    proptest! {
332        #[test]
333        fn debug(input in ip_auth_any()) {
334            assert_eq!(
335                &format!(
336                    "IpAuthHeader {{ next_header: {:?}, spi: {}, sequence_number: {}, raw_icv: {:?} }}",
337                    input.next_header,
338                    input.spi,
339                    input.sequence_number,
340                    input.raw_icv()),
341                &format!("{:?}", input)
342            );
343        }
344    }
345
346    #[test]
347    pub fn clone() {
348        let a = IpAuthHeader::new(0.into(), 0, 0, &[0; 4]);
349        assert_eq!(a.clone(), a);
350    }
351
352    #[test]
353    pub fn partial_eq() {
354        let a = IpAuthHeader::new(0.into(), 0, 0, &[0; 4]);
355
356        //equal
357        assert!(a == IpAuthHeader::new(0.into(), 0, 0, &[0; 4]));
358
359        //not equal tests
360        assert!(a != IpAuthHeader::new(1.into(), 0, 0, &[0; 4]));
361        assert!(a != IpAuthHeader::new(0.into(), 1, 0, &[0; 4]));
362        assert!(a != IpAuthHeader::new(0.into(), 0, 1, &[0; 4]));
363        assert!(a != IpAuthHeader::new(0.into(), 0, 0, &[0, 1, 0, 0]));
364        assert!(a != IpAuthHeader::new(0.into(), 0, 1, &[]));
365        assert!(a != IpAuthHeader::new(0.into(), 0, 1, &[0; 8]));
366    }
367
368    #[test]
369    fn new_and_set_icv() {
370        use IcvLenError::*;
371
372        struct Test {
373            icv: &'static [u8],
374            err: Option<IcvLenError>,
375        }
376
377        let tests = [
378            // ok
379            Test {
380                icv: &[],
381                err: None,
382            },
383            Test {
384                icv: &[1, 2, 3, 4],
385                err: None,
386            },
387            Test {
388                icv: &[1, 2, 3, 4, 5, 6, 7, 8],
389                err: None,
390            },
391            Test {
392                icv: &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
393                err: None,
394            },
395            Test {
396                icv: &[0; 0xfe * 4],
397                err: None,
398            },
399            // unaligned
400            Test {
401                icv: &[1],
402                err: Some(Unaligned(1)),
403            },
404            Test {
405                icv: &[1, 2, 3],
406                err: Some(Unaligned(3)),
407            },
408            Test {
409                icv: &[1, 2, 3, 4, 5],
410                err: Some(Unaligned(5)),
411            },
412            Test {
413                icv: &[1, 2, 3, 4, 5, 6, 7],
414                err: Some(Unaligned(7)),
415            },
416            // too big
417            Test {
418                icv: &[0; 0xff * 4],
419                err: Some(TooBig(0xff * 4)),
420            },
421        ];
422
423        for test in tests.iter() {
424            // new
425            {
426                let a = IpAuthHeader::new(5.into(), 6, 7, test.icv);
427                if let Some(err) = &test.err {
428                    assert_eq!(Err(err.clone()), a);
429                } else {
430                    let unwrapped = a.unwrap();
431                    assert_eq!(IpNumber(5), unwrapped.next_header);
432                    assert_eq!(6, unwrapped.spi);
433                    assert_eq!(7, unwrapped.sequence_number);
434                    assert_eq!(test.icv, unwrapped.raw_icv());
435                }
436            }
437            // set_raw_icv
438            {
439                let mut header = IpAuthHeader::new(5.into(), 6, 7, &[0; 4]).unwrap();
440                let result = header.set_raw_icv(test.icv);
441                assert_eq!(IpNumber(5), header.next_header);
442                assert_eq!(6, header.spi);
443                assert_eq!(7, header.sequence_number);
444                if let Some(err) = &test.err {
445                    assert_eq!(Err(err.clone()), result);
446                    assert_eq!(&[0; 4], header.raw_icv());
447                } else {
448                    assert_eq!(Ok(()), result);
449                    assert_eq!(test.icv, header.raw_icv());
450                }
451            }
452        }
453    }
454
455    proptest! {
456        #[test]
457        fn from_slice(header in ip_auth_any()) {
458            use err::ip_auth::HeaderSliceError::*;
459
460            // ok
461            {
462                let mut bytes = ArrayVec::<u8, {IpAuthHeader::MAX_LEN + 2}>::new();
463                bytes.extend(header.to_bytes());
464                bytes.push(1);
465                bytes.push(2);
466
467                let (actual_header, actual_slice) = IpAuthHeader::from_slice(&bytes).unwrap();
468                assert_eq!(header, actual_header);
469                assert_eq!(&[1,2], actual_slice);
470            }
471
472            // length error
473            {
474                let bytes = header.to_bytes();
475                for len in 0..header.header_len() {
476                    assert_eq!(
477                        IpAuthHeader::from_slice(&bytes[..len]).unwrap_err(),
478                        Len(err::LenError{
479                            required_len: if len < IpAuthHeader::MIN_LEN {
480                                IpAuthHeader::MIN_LEN
481                            } else {
482                                header.header_len()
483                            },
484                            len: len,
485                            len_source: LenSource::Slice,
486                            layer: err::Layer::IpAuthHeader,
487                            layer_start_offset: 0,
488                        })
489                    );
490                }
491            }
492
493            // payload length error
494            {
495                let mut bytes = header.to_bytes();
496                // set payload length to 0
497                bytes[1] = 0;
498                assert_eq!(
499                    IpAuthHeader::from_slice(&bytes).unwrap_err(),
500                    Content(ZeroPayloadLen)
501                );
502            }
503        }
504    }
505
506    proptest! {
507        #[test]
508        fn read(header in ip_auth_any()) {
509            // ok
510            {
511                let bytes = header.to_bytes();
512                let mut cursor = Cursor::new(&bytes);
513                assert_eq!(header, IpAuthHeader::read(&mut cursor).unwrap());
514            }
515
516            // length error
517            {
518                let bytes = header.to_bytes();
519                for len in 0..header.header_len() {
520                    let mut cursor = Cursor::new(&bytes[..len]);
521                    assert!(
522                        IpAuthHeader::read(&mut cursor)
523                            .unwrap_err()
524                            .io()
525                            .is_some()
526                    );
527                }
528            }
529
530            // payload length error
531            {
532                let mut bytes = header.to_bytes();
533                // set payload length to 0
534                bytes[1] = 0;
535                let mut cursor = Cursor::new(&bytes);
536                assert_eq!(
537                    IpAuthHeader::read(&mut cursor).unwrap_err().content(),
538                    Some(ZeroPayloadLen)
539                );
540            }
541        }
542    }
543
544    proptest! {
545        #[test]
546        fn read_limited(header in ip_auth_any()) {
547            // ok
548            {
549                let bytes = header.to_bytes();
550                let mut cursor = Cursor::new(&bytes);
551                let mut reader = LimitedReader::new(
552                    &mut cursor,
553                    bytes.len(),
554                    LenSource::Slice,
555                    0,
556                    Layer::Ipv4Header
557                );
558                assert_eq!(header, IpAuthHeader::read_limited(&mut reader).unwrap());
559            }
560
561            // length error
562            {
563                let bytes = header.to_bytes();
564                for len in 0..header.header_len() {
565                    // io error
566                    {
567                        let mut cursor = Cursor::new(&bytes[..len]);
568                        let mut reader = LimitedReader::new(
569                            &mut cursor,
570                            bytes.len(),
571                            LenSource::Slice,
572                            0,
573                            Layer::Ipv4Header
574                        );
575                        assert!(
576                            IpAuthHeader::read_limited(&mut reader)
577                                .unwrap_err()
578                                .io()
579                                .is_some()
580                        );
581                    }
582                    // limited reader error
583                    {
584
585                        let mut cursor = Cursor::new(&bytes);
586                        let mut reader = LimitedReader::new(
587                            &mut cursor,
588                            len,
589                            LenSource::Ipv4HeaderTotalLen,
590                            0,
591                            Layer::Ipv4Header
592                        );
593                        assert_eq!(
594                            IpAuthHeader::read_limited(&mut reader)
595                                .unwrap_err()
596                                .len()
597                                .unwrap(),
598                            LenError {
599                                required_len: if len < 12 {
600                                    12
601                                } else {
602                                    bytes.len()
603                                },
604                                len,
605                                len_source: LenSource::Ipv4HeaderTotalLen,
606                                layer: Layer::IpAuthHeader,
607                                layer_start_offset: 0
608                            }
609                        );
610                    }
611                }
612            }
613
614            // payload length error
615            {
616                let mut bytes = header.to_bytes();
617                // set payload length to 0
618                bytes[1] = 0;
619                let mut cursor = Cursor::new(&bytes);
620                let mut reader = LimitedReader::new(
621                    &mut cursor,
622                    bytes.len(),
623                    LenSource::Ipv4HeaderTotalLen,
624                    0,
625                    Layer::Ipv4Header
626                );
627                assert_eq!(
628                    IpAuthHeader::read_limited(&mut reader).unwrap_err().content(),
629                    Some(ZeroPayloadLen)
630                );
631            }
632        }
633    }
634
635    proptest! {
636        #[test]
637        fn write(header in ip_auth_any()) {
638
639            // ok case
640            {
641                let mut buffer: Vec<u8> = Vec::with_capacity(header.header_len());
642                header.write(&mut buffer).unwrap();
643                assert_eq!(header, IpAuthHeader::from_slice(&buffer).unwrap().0);
644            };
645
646            // io error
647            for len in 0..header.header_len() {
648                let mut buffer = [0u8;IpAuthHeader::MAX_LEN];
649                let mut cursor = Cursor::new(&mut buffer[..len]);
650                assert!(header.write(&mut cursor).is_err());
651            }
652        }
653    }
654
655    proptest! {
656        #[test]
657        fn header_len(header in ip_auth_any()) {
658            assert_eq!(header.header_len(), header.raw_icv().len() + 12);
659        }
660    }
661
662    proptest! {
663        #[test]
664        fn to_bytes(header in ip_auth_any()) {
665            let bytes = header.to_bytes();
666
667            assert_eq!(header.next_header.0, bytes[0]);
668            assert_eq!((header.header_len()/4 - 2) as u8, bytes[1]);
669            assert_eq!(0, bytes[2]);
670            assert_eq!(0, bytes[3]);
671            {
672                let spi = u32::from_be_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
673                assert_eq!(spi, header.spi);
674            }
675            {
676                let seq_nr = u32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]);
677                assert_eq!(seq_nr, header.sequence_number);
678            }
679            assert_eq!(&bytes[12..], header.raw_icv());
680        }
681    }
682}