• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::*;
2 use core::slice::from_raw_parts;
3 
4 /// Deprecated use [IpAuthHeaderSlice] instead.
5 #[deprecated(
6     since = "0.14.0",
7     note = "Please use the type IpAuthHeaderSlice instead"
8 )]
9 pub type IpAuthenticationHeaderSlice<'a> = IpAuthHeaderSlice<'a>;
10 
11 /// A slice containing an IP Authentication Header (rfc4302)
12 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
13 pub struct IpAuthHeaderSlice<'a> {
14     slice: &'a [u8],
15 }
16 
17 impl<'a> IpAuthHeaderSlice<'a> {
18     /// Creates a ip authentication header slice from a slice.
from_slice( slice: &'a [u8], ) -> Result<IpAuthHeaderSlice<'a>, err::ip_auth::HeaderSliceError>19     pub fn from_slice(
20         slice: &'a [u8],
21     ) -> Result<IpAuthHeaderSlice<'a>, err::ip_auth::HeaderSliceError> {
22         use err::ip_auth::{HeaderError::*, HeaderSliceError::*};
23 
24         // check slice length
25         if slice.len() < IpAuthHeader::MIN_LEN {
26             return Err(Len(err::LenError {
27                 required_len: IpAuthHeader::MIN_LEN,
28                 len: slice.len(),
29                 len_source: LenSource::Slice,
30                 layer: err::Layer::IpAuthHeader,
31                 layer_start_offset: 0,
32             }));
33         }
34 
35         // SAFETY:
36         // Safe the slice length gets checked to be at least 12 beforehand.
37         let payload_len_enc = unsafe { *slice.get_unchecked(1) };
38 
39         // check header length minimum size
40         if payload_len_enc < 1 {
41             return Err(Content(ZeroPayloadLen));
42         }
43 
44         // check length
45         // note: The unit is different then all other ipv6 extension headers.
46         //       In the other headers the length is in 8 octets, but for authentication
47         //       headers the length is in 4 octets.
48         let len = ((payload_len_enc as usize) + 2) * 4;
49         if slice.len() < len {
50             return Err(Len(err::LenError {
51                 required_len: len,
52                 len: slice.len(),
53                 len_source: LenSource::Slice,
54                 layer: err::Layer::IpAuthHeader,
55                 layer_start_offset: 0,
56             }));
57         }
58 
59         // all good
60         Ok(IpAuthHeaderSlice {
61             // SAFETY:
62             // Safe as slice len is checked to be at last len above.
63             slice: unsafe { from_raw_parts(slice.as_ptr(), len) },
64         })
65     }
66 
67     /// Creates a ip authentication header slice from a slice (assumes slice size & content was validated before).
68     ///
69     /// # Safety
70     ///
71     /// This method assumes that the slice was previously validated to contain
72     /// a valid authentication header. This means the slice length must at
73     /// least be at least 8 and `(slice[1] + 2)*4`. The data that the
74     /// slice points must also be valid (meaning no nullptr or alike allowed).
75     ///
76     /// If these preconditions are not fulfilled the behavior of this function
77     /// and the methods of the return IpAuthHeaderSlice will be undefined.
from_slice_unchecked(slice: &'a [u8]) -> IpAuthHeaderSlice<'a>78     pub unsafe fn from_slice_unchecked(slice: &'a [u8]) -> IpAuthHeaderSlice<'a> {
79         IpAuthHeaderSlice {
80             slice: from_raw_parts(slice.as_ptr(), ((*slice.get_unchecked(1) as usize) + 2) * 4),
81         }
82     }
83 
84     /// Returns the slice containing the authentication header.
85     #[inline]
slice(&self) -> &'a [u8]86     pub fn slice(&self) -> &'a [u8] {
87         self.slice
88     }
89 
90     /// Returns the IP protocol number of the next header or transport layer protocol.
91     ///
92     /// See [IpNumber] or [ip_number] for a definition of the known values.
93     #[inline]
next_header(&self) -> IpNumber94     pub fn next_header(&self) -> IpNumber {
95         // SAFETY:
96         // Safe as slice length is checked in the constructor
97         // to be at least 12.
98         IpNumber(unsafe { *self.slice.get_unchecked(0) })
99     }
100 
101     /// Read the security parameters index from the slice
102     #[inline]
spi(&self) -> u32103     pub fn spi(&self) -> u32 {
104         // SAFETY:
105         // Safe as slice length is checked in the constructor
106         // to be at least 12.
107         unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(4)) }
108     }
109 
110     /// This unsigned 32-bit field contains a counter value that
111     /// increases by one for each packet sent.
112     #[inline]
sequence_number(&self) -> u32113     pub fn sequence_number(&self) -> u32 {
114         // SAFETY:
115         // Safe as slice length is checked in the constructor
116         // to be at least 12.
117         unsafe { get_unchecked_be_u32(self.slice.as_ptr().add(8)) }
118     }
119 
120     /// Return a slice with the raw integrity check value
raw_icv(&self) -> &'a [u8]121     pub fn raw_icv(&self) -> &'a [u8] {
122         &self.slice[12..]
123     }
124 
125     /// Decode some of the fields and copy the results to a
126     /// Ipv6ExtensionHeader struct together with a slice pointing
127     /// to the non decoded parts.
to_header(&self) -> IpAuthHeader128     pub fn to_header(&self) -> IpAuthHeader {
129         IpAuthHeader::new(
130             self.next_header(),
131             self.spi(),
132             self.sequence_number(),
133             self.raw_icv(),
134         )
135         .unwrap()
136     }
137 }
138 
139 #[cfg(test)]
140 mod test {
141     use super::*;
142     use crate::test_gens::*;
143     use alloc::format;
144     use arrayvec::ArrayVec;
145     use err::ip_auth::{HeaderError::*, HeaderSliceError::*};
146     use proptest::prelude::*;
147 
148     proptest! {
149         #[test]
150         fn debug(input in ip_auth_any()) {
151             let buffer = input.to_bytes();
152             let slice = IpAuthHeaderSlice::from_slice(&buffer).unwrap();
153             assert_eq!(
154                 &format!(
155                     "IpAuthHeaderSlice {{ slice: {:?} }}",
156                     slice.slice()
157                 ),
158                 &format!("{:?}", slice)
159             );
160         }
161     }
162 
163     #[test]
clone_eq()164     fn clone_eq() {
165         let buffer = IpAuthHeader::new(0.into(), 0, 0, &[0; 4])
166             .unwrap()
167             .to_bytes();
168         let slice = IpAuthHeaderSlice::from_slice(&buffer).unwrap();
169         assert_eq!(slice.clone(), slice);
170     }
171 
172     proptest! {
173         #[test]
174         fn from_slice(header in ip_auth_any()) {
175 
176             // ok
177             {
178                 let mut bytes = ArrayVec::<u8, {IpAuthHeader::MAX_LEN + 2}>::new();
179                 bytes.extend(header.to_bytes());
180                 bytes.push(1);
181                 bytes.push(2);
182 
183                 let slice = IpAuthHeaderSlice::from_slice(&bytes).unwrap();
184                 assert_eq!(slice.slice(), &bytes[..bytes.len() - 2]);
185             }
186 
187             // length error
188             {
189                 let bytes = header.to_bytes();
190                 for len in 0..header.header_len() {
191                     assert_eq!(
192                         IpAuthHeaderSlice::from_slice(&bytes[..len]).unwrap_err(),
193                         Len(err::LenError{
194                             required_len: if len < IpAuthHeader::MIN_LEN {
195                                 IpAuthHeader::MIN_LEN
196                             } else {
197                                 header.header_len()
198                             },
199                             len: len,
200                             len_source: LenSource::Slice,
201                             layer: err::Layer::IpAuthHeader,
202                             layer_start_offset: 0,
203                         })
204                     );
205                 }
206             }
207 
208             // payload length error
209             {
210                 let mut bytes = header.to_bytes();
211                 // set payload length to 0
212                 bytes[1] = 0;
213                 assert_eq!(
214                     IpAuthHeaderSlice::from_slice(&bytes).unwrap_err(),
215                     Content(ZeroPayloadLen)
216                 );
217             }
218         }
219     }
220 
221     proptest! {
222         #[test]
223         fn from_slice_unchecked(header in ip_auth_any()) {
224             let bytes = header.to_bytes();
225             let slice = unsafe {
226                 IpAuthHeaderSlice::from_slice_unchecked(&bytes)
227             };
228             assert_eq!(slice.slice(), &bytes[..]);
229         }
230     }
231 
232     proptest! {
233         #[test]
234         fn getters(header in ip_auth_any()) {
235             let bytes = header.to_bytes();
236             let slice = IpAuthHeaderSlice::from_slice(&bytes).unwrap();
237             assert_eq!(slice.slice(), &bytes[..]);
238             assert_eq!(slice.next_header(), header.next_header);
239             assert_eq!(slice.spi(), header.spi);
240             assert_eq!(slice.sequence_number(), header.sequence_number);
241             assert_eq!(slice.raw_icv(), header.raw_icv());
242         }
243     }
244 
245     proptest! {
246         #[test]
247         fn to_header(header in ip_auth_any()) {
248             let bytes = header.to_bytes();
249             assert_eq!(
250                 header,
251                 IpAuthHeaderSlice::from_slice(&bytes)
252                     .unwrap()
253                     .to_header()
254             );
255         }
256     }
257 }
258