1 use super::super::*;
2 use crate::err::ip_auth::IcvLenError;
3 use arrayvec::ArrayVec;
4 use core::fmt::{Debug, Formatter};
5 
6 /// Deprecated use [IpAuthHeader] instead.
7 #[deprecated(since = "0.10.1", note = "Please use the type IpAuthHeader instead")]
8 pub type IPv6AuthenticationHeader = IpAuthHeader;
9 
10 /// Deprecated use [IpAuthHeader] instead.
11 #[deprecated(since = "0.14.0", note = "Please use the type IpAuthHeader instead")]
12 pub type IpAuthenticationHeader = IpAuthHeader;
13 
14 /// IP Authentication Header (rfc4302)
15 #[derive(Clone)]
16 pub 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 
34 impl Debug for IpAuthHeader {
fmt(&self, formatter: &mut Formatter) -> Result<(), core::fmt::Error>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 
45 impl PartialEq for IpAuthHeader {
eq(&self, other: &Self) -> bool46     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 
54 impl Eq for IpAuthHeader {}
55 
56 impl Default for IpAuthHeader {
default() -> Self57     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 
68 impl<'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.
new( next_header: IpNumber, spi: u32, sequence_number: u32, raw_icv: &'a [u8], ) -> Result<IpAuthHeader, IcvLenError>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.
from_slice( slice: &'a [u8], ) -> Result<(IpAuthHeader, &'a [u8]), err::ip_auth::HeaderSliceError>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")))]
read<T: std::io::Read + Sized>( reader: &mut T, ) -> Result<IpAuthHeader, err::ip_auth::HeaderReadError>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")))]
read_limited<T: std::io::Read + Sized>( reader: &mut crate::io::LimitedReader<T>, ) -> Result<IpAuthHeader, err::ip_auth::HeaderLimitedReadError>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.
raw_icv(&self) -> &[u8]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.
set_raw_icv(&mut self, raw_icv: &[u8]) -> Result<(), IcvLenError>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")))]
write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error>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.
header_len(&self) -> usize270     pub fn header_len(&self) -> usize {
271         12 + usize::from(self.raw_icv_len) * 4
272     }
273 
274     /// Returns the serialized header.
to_bytes(&self) -> ArrayVec<u8,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)]
306 mod 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]
default()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]
clone()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]
partial_eq()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]
new_and_set_icv()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 }
683