1use super::super::*;
2use crate::err::ip_auth::IcvLenError;
3use arrayvec::ArrayVec;
4use core::fmt::{Debug, Formatter};
5
6#[deprecated(since = "0.10.1", note = "Please use the type IpAuthHeader instead")]
8pub type IPv6AuthenticationHeader = IpAuthHeader;
9
10#[deprecated(since = "0.14.0", note = "Please use the type IpAuthHeader instead")]
12pub type IpAuthenticationHeader = IpAuthHeader;
13
14#[derive(Clone)]
16pub struct IpAuthHeader {
17 pub next_header: IpNumber,
21 pub spi: u32,
23 pub sequence_number: u32,
26 raw_icv_len: u8,
29 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 pub const MIN_LEN: usize = 4 + 4 + 4;
71
72 pub const MAX_LEN: usize = 4 * (0xff + 2);
79
80 pub const MAX_ICV_LEN: usize = 0xfe * 4;
83
84 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 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 #[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 if payload_len < 1 {
146 Err(Content(ZeroPayloadLen))
147 } else {
148 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 #[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 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 if payload_len < 1 {
200 Err(Content(ZeroPayloadLen))
201 } else {
202 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 pub fn raw_icv(&self) -> &[u8] {
221 &self.raw_icv_buffer[..usize::from(self.raw_icv_len) * 4]
222 }
223
224 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 #[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 pub fn header_len(&self) -> usize {
271 12 + usize::from(self.raw_icv_len) * 4
272 }
273
274 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 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 assert!(a == IpAuthHeader::new(0.into(), 0, 0, &[0; 4]));
358
359 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 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 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 Test {
418 icv: &[0; 0xff * 4],
419 err: Some(TooBig(0xff * 4)),
420 },
421 ];
422
423 for test in tests.iter() {
424 {
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 {
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 {
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 {
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 {
495 let mut bytes = header.to_bytes();
496 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 {
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 {
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 {
532 let mut bytes = header.to_bytes();
533 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 {
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 {
563 let bytes = header.to_bytes();
564 for len in 0..header.header_len() {
565 {
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 {
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 {
616 let mut bytes = header.to_bytes();
617 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 {
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 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}