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