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