ah.c
Go to the documentation of this file.
1 /**
2  * @file ah.c
3  * @brief AH (IP Authentication Header)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2022-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneIPSEC Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL AH_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ipsec/ipsec.h"
36 #include "ipsec/ipsec_inbound.h"
38 #include "ipsec/ipsec_misc.h"
39 #include "ah/ah.h"
40 #include "core/tcp_fsm.h"
41 #include "core/raw_socket.h"
42 #include "ipv4/icmp.h"
43 #include "debug.h"
44 
45 //Check IPsec library configuration
46 #if (AH_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief Process AH protected packet
51  * @param[in] interface Underlying network interface
52  * @param[in] ipv4Header Pointer to the IPv4 header
53  * @param[in] buffer Multi-part buffer containing the AH protected packet
54  * @param[in] offset Offset to the first byte of the AH header
55  * @param[in] ancillary Additional options passed to the stack along with
56  * the packet
57  * @return Error code
58  **/
59 
61  const Ipv4Header *ipv4Header, const NetBuffer *buffer, size_t offset,
62  NetRxAncillary *ancillary)
63 {
64  error_t error;
65  size_t n;
66  size_t length;
67  uint64_t seq;
68  IpsecContext *context;
69  IpsecSadEntry *sa;
70  AhHeader *ahHeader;
71  IpsecSelector selector;
72  IpPseudoHeader pseudoHeader;
73 
74  //Point to the IPsec context
75  context = interface->netContext->ipsecContext;
76  //Sanity check
77  if(context == NULL)
78  return ERROR_FAILURE;
79 
80  //Retrieve the length of the payload
81  length = netBufferGetLength(buffer) - offset;
82 
83  //Malformed packet?
84  if(length < sizeof(AhHeader))
85  return ERROR_INVALID_HEADER;
86 
87  //Point to the AH header
88  ahHeader = netBufferAt(buffer, offset, 0);
89  //Sanity check
90  if(ahHeader == NULL)
91  return ERROR_FAILURE;
92 
93  //If a packet offered to AH for processing appears to be an IP fragment,
94  //the receiver must discard the packet (refer to RFC 4302, section 3.4.1)
95  if((ntohs(ipv4Header->fragmentOffset) & IPV4_OFFSET_MASK) != 0 ||
96  (ntohs(ipv4Header->fragmentOffset) & IPV4_FLAG_MF) != 0)
97  {
98  return ERROR_INVALID_HEADER;
99  }
100 
101  //Upon receipt of a packet containing an IP Authentication Header, the
102  //receiver determines the appropriate (unidirectional) SA via lookup in
103  //the SAD (refer to RFC 4302, section 3.4.2)
105  ntohl(ahHeader->spi));
106 
107  //If no valid Security Association exists for this packet the receiver
108  //must discard the packet. This is an auditable event
109  if(sa == NULL)
110  {
111  //Debug message
112  TRACE_WARNING("AH: No matching SA found!\r\n");
113  //Report an error
114  return ERROR_POLICY_FAILURE;
115  }
116 
117  //The Payload Length field specifies the length of AH header in 32-bit
118  //words (4-byte units), minus 2
119  n = (ahHeader->payloadLen + 2) * sizeof(uint32_t);
120 
121  //Check the length of the AH header
122  if(n > length || n != (sizeof(AhHeader) + sa->icvLen))
123  return ERROR_INVALID_HEADER;
124 
125  //Debug message
126  TRACE_INFO("Parsing AH header...\r\n");
127  //Dump AH header contents for debugging purpose
128  ahDumpHeader(ahHeader);
129 
130  //Because only the low-order 32 bits are transmitted with the packet, the
131  //receiver must deduce and track the sequence number subspace into which
132  //each packet falls
133  seq = ipsecGetSeqNum(sa, ntohl(ahHeader->seqNum));
134 
135  //For each received packet, the receiver must verify that the packet
136  //contains a Sequence Number that does not duplicate the Sequence Number of
137  //any other packets received during the life of this SA. This should be the
138  //first AH check applied to a packet after it has been matched to an SA, to
139  //speed rejection of duplicate packets (refer to RFC 4302, section 3.4.3)
140  error = ipsecCheckReplayWindow(sa, seq);
141 
142  //Duplicate packets are rejected
143  if(error)
144  {
145  //Debug message
146  TRACE_WARNING("AH: Invalid sequence number!\r\n");
147  //Report an error
149  }
150 
151  //If the received packet falls within the window and is not a duplicate, or
152  //if the packet is to the right of the window, then the receiver proceeds to
153  //ICV verification
154  error = ahVerifyIcv(context, sa, ipv4Header, ahHeader, buffer,
155  offset + sizeof(AhHeader) + sa->icvLen);
156 
157  //If the ICV validation fails, the receiver must discard the received IP
158  //datagram as invalid. This is is an auditable event (refer to RFC 4302,
159  //section 3.4.3)
160  if(error)
161  {
162  //Debug message
163  TRACE_WARNING("AH: ICV validation failed!\r\n");
164  //Report an error
166  }
167 
168  //The receive window is updated only if the ICV verification succeeds
169  ipsecUpdateReplayWindow(sa, seq);
170 
171  //Point to the payload
172  offset += n;
173  length -= n;
174 
175  //Match the packet against the inbound selectors identified by the SAD entry
176  //to verify that the received packet is appropriate for the SA via which it
177  //was received (refer to RFC 4301, section 5.2)
178  error = ipsecGetInboundIpv4PacketSelector(ipv4Header, ahHeader->nextHeader,
179  buffer, offset, &selector);
180  //Any error to report?
181  if(error)
182  return error;
183 
184  //If an IPsec system receives an inbound packet on an SA and the packet's
185  //header fields are not consistent with the selectors for the SA, it must
186  //discard the packet. This is an auditable event
187  if(!ipsecIsSubsetSelector(&selector, &sa->selector))
188  return ERROR_POLICY_FAILURE;
189 
190  //Form the IPv4 pseudo header
191  pseudoHeader.length = sizeof(Ipv4PseudoHeader);
192  pseudoHeader.ipv4Data.srcAddr = ipv4Header->srcAddr;
193  pseudoHeader.ipv4Data.destAddr = ipv4Header->destAddr;
194  pseudoHeader.ipv4Data.reserved = 0;
195  pseudoHeader.ipv4Data.protocol = ahHeader->nextHeader;
196  pseudoHeader.ipv4Data.length = htons(length);
197 
198  //If the computed and received ICVs match, then the datagram is valid, and
199  //it is accepted (refer to RFC 4302, section 3.4.4)
200  switch(ahHeader->nextHeader)
201  {
202  //ICMP protocol?
203  case IPV4_PROTOCOL_ICMP:
204  //Process incoming ICMP message
205  icmpProcessMessage(interface, &pseudoHeader.ipv4Data, buffer, offset);
206 
207 #if (RAW_SOCKET_SUPPORT == ENABLED)
208  //Allow raw sockets to process ICMP messages
209  rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
210  ancillary);
211 #endif
212 
213  //Continue processing
214  break;
215 
216 #if (IGMP_HOST_SUPPORT == ENABLED || IGMP_ROUTER_SUPPORT == ENABLED || \
217  IGMP_SNOOPING_SUPPORT == ENABLED)
218  //IGMP protocol?
219  case IPV4_PROTOCOL_IGMP:
220  //Process incoming IGMP message
221  igmpProcessMessage(interface, &pseudoHeader.ipv4Data, buffer, offset,
222  ancillary);
223 
224 #if (RAW_SOCKET_SUPPORT == ENABLED)
225  //Allow raw sockets to process IGMP messages
226  rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
227  ancillary);
228 #endif
229 
230  //Continue processing
231  break;
232 #endif
233 
234 #if (TCP_SUPPORT == ENABLED)
235  //TCP protocol?
236  case IPV4_PROTOCOL_TCP:
237  //Process incoming TCP segment
238  tcpProcessSegment(interface, &pseudoHeader, buffer, offset, ancillary);
239  //Continue processing
240  break;
241 #endif
242 
243 #if (UDP_SUPPORT == ENABLED)
244  //UDP protocol?
245  case IPV4_PROTOCOL_UDP:
246  //Process incoming UDP datagram
247  error = udpProcessDatagram(interface, &pseudoHeader, buffer, offset,
248  ancillary);
249  //Continue processing
250  break;
251 #endif
252 
253  //Unknown protocol?
254  default:
255 #if (RAW_SOCKET_SUPPORT == ENABLED)
256  //Allow raw sockets to process IPv4 packets
257  error = rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
258  ancillary);
259 #else
260  //Report an error
262 #endif
263  //Continue processing
264  break;
265  }
266 
267  //Return status code
268  return error;
269 }
270 
271 
272 /**
273  * @brief ICV generation
274  * @param[in] context Pointer to the IPsec context
275  * @param[in] sa Pointer to the SA
276  * @param[in] ipv4Header Pointer to the IPv4 header
277  * @param[in,out] ahHeader Pointer to the AH header
278  * @param[in] buffer Multi-part buffer containing the payload
279  * @param[in] offset Offset to the first byte of the payload
280  * @return Error code
281  **/
282 
284  const Ipv4Header *ipv4Header, AhHeader *ahHeader, const NetBuffer *buffer,
285  size_t offset)
286 {
287  error_t error;
288  uint_t i;
289  size_t n;
290  uint8_t *p;
291 
292 #if (AH_CMAC_SUPPORT == ENABLED)
293  //CMAC integrity algorithm?
294  if(sa->authCipherAlgo != NULL)
295  {
296  CmacContext *cmacContext;
297 
298  //Point to the CMAC context
299  cmacContext = &context->cmacContext;
300 
301  //The SAD entry specifies the algorithm employed for ICV computation
302  error = cmacInit(cmacContext, sa->authCipherAlgo, sa->authKey,
303  sa->authKeyLen);
304 
305  //Check status code
306  if(!error)
307  {
308  //Compute CMAC over the IP or extension header fields before the AH
309  //header that are either immutable in transit or that are predictable
310  //in value upon arrival at the endpoint for the AH SA
311  cmacUpdate(cmacContext, ipv4Header, sizeof(Ipv4Header));
312 
313  //Compute CMAC over the Next Header, Payload Length, Reserved, SPI,
314  //Sequence Number (low-order 32 bits) fields, and the ICV (which is
315  //set to zero for this computation)
316  cmacUpdate(cmacContext, ahHeader, sizeof(AhHeader) + sa->icvLen);
317 
318  //Everything after AH is assumed to be immutable in transit
319  for(i = 0; i < buffer->chunkCount; i++)
320  {
321  //Is there any data to process from the current chunk?
322  if(offset < buffer->chunk[i].length)
323  {
324  //Point to the first byte to be processed
325  p = (uint8_t *) buffer->chunk[i].address + offset;
326  //Compute the number of bytes to process at a time
327  n = buffer->chunk[i].length - offset;
328 
329  //Update CMAC calculation
330  cmacUpdate(cmacContext, p, n);
331 
332  //Process the next block from the start
333  offset = 0;
334  }
335  else
336  {
337  //Skip the current chunk
338  offset -= buffer->chunk[i].length;
339  }
340  }
341 
342  //Extended sequence numbers?
343  if(sa->esn)
344  {
345  //If the ESN option is elected for an SA, then the high-order 32
346  //bits of the ESN must be included in the ICV computation
347  uint32_t seqh = htonl(sa->seqNum >> 32);
348 
349  //For purposes of ICV computation, these bits are appended
350  //(implicitly) immediately after the end of the payload
351  cmacUpdate(cmacContext, (uint8_t *) &seqh, 4);
352  }
353 
354  //Finalize CMAC calculation
355  cmacFinal(cmacContext, ahHeader->icv, sa->icvLen);
356  }
357  }
358  else
359 #endif
360 #if (AH_HMAC_SUPPORT == ENABLED)
361  //HMAC integrity algorithm?
362  if(sa->authHashAlgo != NULL)
363  {
364  HmacContext *hmacContext;
365 
366  //Point to the HMAC context
367  hmacContext = &context->hmacContext;
368 
369  //The SAD entry specifies the algorithm employed for ICV computation
370  error = hmacInit(hmacContext, sa->authHashAlgo, sa->authKey,
371  sa->authKeyLen);
372 
373  //Check status code
374  if(!error)
375  {
376  //Compute HMAC over the IP or extension header fields before the AH
377  //header that are either immutable in transit or that are predictable
378  //in value upon arrival at the endpoint for the AH SA
379  hmacUpdate(hmacContext, ipv4Header, sizeof(Ipv4Header));
380 
381  //Compute HMAC over the Next Header, Payload Length, Reserved, SPI,
382  //Sequence Number (low-order 32 bits) fields, and the ICV (which is
383  //set to zero for this computation)
384  hmacUpdate(hmacContext, ahHeader, sizeof(AhHeader) + sa->icvLen);
385 
386  //Everything after AH is assumed to be immutable in transit
387  for(i = 0; i < buffer->chunkCount; i++)
388  {
389  //Is there any data to process from the current chunk?
390  if(offset < buffer->chunk[i].length)
391  {
392  //Point to the first byte to be processed
393  p = (uint8_t *) buffer->chunk[i].address + offset;
394  //Compute the number of bytes to process at a time
395  n = buffer->chunk[i].length - offset;
396 
397  //Update HMAC calculation
398  hmacUpdate(hmacContext, p, n);
399 
400  //Process the next block from the start
401  offset = 0;
402  }
403  else
404  {
405  //Skip the current chunk
406  offset -= buffer->chunk[i].length;
407  }
408  }
409 
410  //Extended sequence numbers?
411  if(sa->esn)
412  {
413  //If the ESN option is elected for an SA, then the high-order 32
414  //bits of the ESN must be included in the ICV computation
415  uint32_t seqh = htonl(sa->seqNum >> 32);
416 
417  //For purposes of ICV computation, these bits are appended
418  //(implicitly) immediately after the end of the payload
419  hmacUpdate(hmacContext, (uint8_t *) &seqh, 4);
420  }
421 
422  //Finalize HMAC calculation
423  hmacFinal(hmacContext, NULL);
424  //The output of the HMAC can be truncated
425  osMemcpy(ahHeader->icv, hmacContext->digest, sa->icvLen);
426  }
427  }
428  else
429 #endif
430  //Unknown integrity algorithm?
431  {
432  //Report an error
433  error = ERROR_FAILURE;
434  }
435 
436  //Return status code
437  return error;
438 }
439 
440 
441 /**
442  * @brief ICV verification
443  * @param[in] context Pointer to the IPsec context
444  * @param[in] sa Pointer to the SA
445  * @param[in] ipv4Header Pointer to the IPv4 header
446  * @param[in] ahHeader Pointer to the AH header
447  * @param[in] buffer Multi-part buffer containing the payload
448  * @param[in] offset Offset to the first byte of the payload
449  * @return Error code
450  **/
451 
453  const Ipv4Header *ipv4Header, const AhHeader *ahHeader,
454  const NetBuffer *buffer, size_t offset)
455 {
456  error_t error;
457  uint8_t mask;
458  uint_t i;
459  size_t n;
460  uint8_t *p;
461  Ipv4Header *ipv4Header2;
462  AhHeader *ahHeader2;
463  uint8_t temp[IPV4_MAX_HEADER_LENGTH];
464  uint8_t checksum[AH_MAX_DIGEST_SIZE];
465 
466  //Calculate the length of the IPv4 header
467  n = ipv4Header->headerLength * 4;
468  //Copy the IPv4 header
469  osMemcpy(temp, ipv4Header, n);
470  //Point to the IPv4 header
471  ipv4Header2 = (Ipv4Header *) temp;
472 
473  //If a field may be modified during transit, the value of the field is set
474  //to zero for purposes of the ICV computation
475  ipv4Header2->typeOfService = 0;
476  ipv4Header2->fragmentOffset = 0;
477  ipv4Header2->timeToLive = 0;
478  ipv4Header2->headerChecksum = 0;
479 
480  //Mutable options are zeroed before performing the ICV calculation
481  ahProcessMutableIpv4Options(ipv4Header2);
482 
483 #if (AH_CMAC_SUPPORT == ENABLED)
484  //CMAC integrity algorithm?
485  if(sa->authCipherAlgo != NULL)
486  {
487  CmacContext *cmacContext;
488 
489  //Point to the CMAC context
490  cmacContext = &context->cmacContext;
491 
492  //The SAD entry specifies the algorithm employed for ICV computation,
493  //and indicates the key required to validate the ICV
494  error = cmacInit(cmacContext, sa->authCipherAlgo, sa->authKey,
495  sa->authKeyLen);
496 
497  //Check status code
498  if(!error)
499  {
500  //Compute CMAC over the IP or extension header fields before the AH
501  //header that are either immutable in transit or that are predictable
502  //in value upon arrival at the endpoint for the AH SA
503  cmacUpdate(cmacContext, temp, n);
504 
505  //The Payload Length field specifies the length of AH header in 32-bit
506  //words (4-byte units), minus 2
507  n = (ahHeader->payloadLen + 2) * sizeof(uint32_t);
508 
509  //Copy the AH header
510  osMemcpy(temp, ahHeader, n);
511  //Point to the AH header
512  ahHeader2 = (AhHeader *) temp;
513 
514  //The Integrity Check Value field is also set to zero in preparation
515  //for this computation (refer to RFC 4302, section 3.3.3.1)
516  osMemset(ahHeader2->icv, 0, sa->icvLen);
517 
518  //Compute CMAC over the Next Header, Payload Length, Reserved, SPI,
519  //Sequence Number (low-order 32 bits) fields, and the ICV (which is
520  //set to zero for this computation)
521  cmacUpdate(cmacContext, temp, n);
522 
523  //Everything after AH is assumed to be immutable in transit
524  for(i = 0; i < buffer->chunkCount; i++)
525  {
526  //Is there any data to process from the current chunk?
527  if(offset < buffer->chunk[i].length)
528  {
529  //Point to the first byte to be processed
530  p = (uint8_t *) buffer->chunk[i].address + offset;
531  //Compute the number of bytes to process at a time
532  n = buffer->chunk[i].length - offset;
533 
534  //Update CMAC calculation
535  cmacUpdate(cmacContext, p, n);
536 
537  //Process the next block from the start
538  offset = 0;
539  }
540  else
541  {
542  //Skip the current chunk
543  offset -= buffer->chunk[i].length;
544  }
545  }
546 
547  //Extended sequence numbers?
548  if(sa->esn)
549  {
550  //If the ESN option is elected for an SA, then the high-order 32
551  //bits of the ESN must be included in the ICV computation
552  uint32_t seqh = ipsecGetSeqNum(sa, ntohl(ahHeader->seqNum)) >> 32;
553 
554  //Convert the 32-bit value to network byte order
555  seqh = htonl(seqh);
556 
557  //For purposes of ICV computation, these bits are appended
558  //(implicitly) immediately after the end of the payload
559  cmacUpdate(cmacContext, (uint8_t *) &seqh, 4);
560  }
561 
562  //Finalize CMAC computation
563  cmacFinal(cmacContext, checksum, sa->icvLen);
564  }
565  }
566  else
567 #endif
568 #if (AH_HMAC_SUPPORT == ENABLED)
569  //HMAC integrity algorithm?
570  if(sa->authHashAlgo != NULL)
571  {
572  HmacContext *hmacContext;
573 
574  //Point to the HMAC context
575  hmacContext = &context->hmacContext;
576 
577  //The SAD entry specifies the algorithm employed for ICV computation,
578  //and indicates the key required to validate the ICV
579  error = hmacInit(hmacContext, sa->authHashAlgo, sa->authKey,
580  sa->authKeyLen);
581 
582  //Check status code
583  if(!error)
584  {
585  //Compute HMAC over the IP or extension header fields before the AH
586  //header that are either immutable in transit or that are predictable
587  //in value upon arrival at the endpoint for the AH SA
588  hmacUpdate(hmacContext, temp, n);
589 
590  //The Payload Length field specifies the length of AH header in 32-bit
591  //words (4-byte units), minus 2
592  n = (ahHeader->payloadLen + 2) * 4;
593 
594  //Copy the AH header
595  osMemcpy(temp, ahHeader, n);
596  //Point to the AH header
597  ahHeader2 = (AhHeader *) temp;
598 
599  //The Integrity Check Value field is also set to zero in preparation
600  //for this computation (refer to RFC 4302, section 3.3.3.1)
601  osMemset(ahHeader2->icv, 0, sa->icvLen);
602 
603  //Compute HMAC over the Next Header, Payload Length, Reserved, SPI,
604  //Sequence Number (low-order 32 bits) fields, and the ICV (which is
605  //set to zero for this computation)
606  hmacUpdate(hmacContext, temp, n);
607 
608  //Everything after AH is assumed to be immutable in transit
609  for(i = 0; i < buffer->chunkCount; i++)
610  {
611  //Is there any data to process from the current chunk?
612  if(offset < buffer->chunk[i].length)
613  {
614  //Point to the first byte to be processed
615  p = (uint8_t *) buffer->chunk[i].address + offset;
616  //Compute the number of bytes to process at a time
617  n = buffer->chunk[i].length - offset;
618 
619  //Update HMAC calculation
620  hmacUpdate(hmacContext, p, n);
621 
622  //Process the next block from the start
623  offset = 0;
624  }
625  else
626  {
627  //Skip the current chunk
628  offset -= buffer->chunk[i].length;
629  }
630  }
631 
632  //Extended sequence numbers?
633  if(sa->esn)
634  {
635  //If the ESN option is elected for an SA, then the high-order 32
636  //bits of the ESN must be included in the ICV computation
637  uint32_t seqh = ipsecGetSeqNum(sa, ntohl(ahHeader->seqNum)) >> 32;
638 
639  //Convert the 32-bit value to network byte order
640  seqh = htonl(seqh);
641 
642  //For purposes of ICV computation, these bits are appended
643  //(implicitly) immediately after the end of the payload
644  hmacUpdate(hmacContext, (uint8_t *) &seqh, 4);
645  }
646 
647  //Finalize HMAC computation
648  hmacFinal(hmacContext, checksum);
649  }
650  }
651  else
652 #endif
653  //Unknown integrity algorithm?
654  {
655  //Report an error
656  error = ERROR_INVALID_MAC;
657  }
658 
659  //Check status code
660  if(!error)
661  {
662  //Debug message
663  TRACE_DEBUG_ARRAY("Calculated ICV = ", checksum, sa->icvLen);
664 
665  //The calculated checksum is bitwise compared to the received ICV
666  for(mask = 0, i = 0; i < sa->icvLen; i++)
667  {
668  mask |= checksum[i] ^ ahHeader->icv[i];
669  }
670 
671  //If the ICV validation fails, the receiver must discard the received IP
672  //datagram as invalid. This is is an auditable event (refer to RFC 4302,
673  //section 3.4.3)
674  error = (mask == 0) ? NO_ERROR : ERROR_INVALID_MAC;
675  }
676 
677  //Return status code
678  return error;
679 }
680 
681 
682 /**
683  * @brief Zeroize mutable IPv4 options
684  * @param[in] header Pointer to the IPv4 header
685  **/
686 
688 {
689  size_t i;
690  size_t n;
691  size_t length;
692  Ipv4Option *option;
693 
694  //Compute the length of the options field
695  length = (header->headerLength * 4) - sizeof(TcpHeader);
696 
697  //Point to the very first option
698  i = 0;
699 
700  //Loop through the list of options
701  while(i < length)
702  {
703  //Point to the current option
704  option = (Ipv4Option *) (header->options + i);
705 
706  //Check option type
707  if(option->type == IPV4_OPTION_EEOL)
708  {
709  //This option code indicates the end of the option list
710  break;
711  }
712  else if(option->type == IPV4_OPTION_NOP)
713  {
714  //This option consists of a single octet
715  i++;
716  }
717  else
718  {
719  //Malformed option?
720  if((i + 1) >= length)
721  break;
722 
723  //The option code is followed by a one-byte length field
724  n = option->length;
725 
726  //Check the length of the option
727  if(n < sizeof(Ipv4Option) || (i + n) > length)
728  break;
729 
730  //Mutable option?
731  if(option->type != IPV4_OPTION_SEC &&
732  option->type != IPV4_OPTION_ESEC &&
733  option->type != IPV4_OPTION_CIPSO &&
734  option->type != IPV4_OPTION_RTRALT &&
735  option->type != IPV4_OPTION_SDB)
736  {
737  //The entire option is zeroed before performing the ICV calculation
738  osMemset(option, 0, n);
739  }
740 
741  //Jump to the next option
742  i += n;
743  }
744  }
745 }
746 
747 
748 /**
749  * @brief Dump AH header for debugging purpose
750  * @param[in] ahHeader Pointer to the AH header
751  **/
752 
753 void ahDumpHeader(const AhHeader *ahHeader)
754 {
755  size_t n;
756 
757  //The Payload Length field specifies the length of AH header in 32-bit
758  //words (4-byte units), minus 2
759  n = (ahHeader->payloadLen + 2) * sizeof(uint32_t);
760 
761  //Check the length of the AH header
762  if(n >= sizeof(AhHeader))
763  {
764  //Retrieve the length of the ICV tag
765  n -= sizeof(AhHeader);
766 
767  //Dump AH header contents
768  TRACE_DEBUG(" Next Header = %" PRIu8 "\r\n", ahHeader->nextHeader);
769  TRACE_DEBUG(" Payload Length = %" PRIu8 "\r\n", ahHeader->payloadLen);
770  TRACE_DEBUG(" SPI = 0x%08" PRIX32 "\r\n", ntohl(ahHeader->spi));
771  TRACE_DEBUG(" Sequence Number = 0x%08" PRIX32 "\r\n", ntohl(ahHeader->seqNum));
772  TRACE_DEBUG_ARRAY(" ICV = ", ahHeader->icv, n);
773  }
774 }
775 
776 #endif
#define htons(value)
Definition: cpu_endian.h:413
HMAC algorithm context.
Definition: hmac.h:59
error_t ahGenerateIcv(IpsecContext *context, IpsecSadEntry *sa, const Ipv4Header *ipv4Header, AhHeader *ahHeader, const NetBuffer *buffer, size_t offset)
ICV generation.
Definition: ah.c:283
#define AH_MAX_DIGEST_SIZE
Definition: ah.h:151
#define Ipv4Header
Definition: ipv4.h:36
@ IPV4_PROTOCOL_ICMP
Definition: ipv4.h:275
@ IPV4_OFFSET_MASK
Definition: ipv4.h:264
@ IPV4_OPTION_SDB
Selective Directed Broadcast.
Definition: ipv4.h:311
@ ERROR_WRONG_SEQUENCE_NUMBER
Definition: error.h:183
@ IPSEC_PROTOCOL_AH
Definition: ipsec.h:196
error_t rawSocketProcessIpPacket(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary)
Process incoming IP packet.
Definition: raw_socket.c:66
IPsec selector.
Definition: ipsec.h:306
uint8_t p
Definition: ndp.h:300
uint16_t checksum
Definition: tcp.h:362
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint_t chunkCount
Definition: net_mem.h:90
@ ERROR_INVALID_HEADER
Definition: error.h:87
@ IPV4_OPTION_ESEC
Extended Security.
Definition: ipv4.h:302
error_t udpProcessDatagram(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary)
Incoming UDP datagram processing.
Definition: udp.c:123
size_t length
Definition: ip.h:111
@ IPV4_OPTION_NOP
No Operation.
Definition: ipv4.h:291
@ ERROR_INVALID_MAC
Definition: error.h:113
error_t ipsecCheckReplayWindow(const IpsecSadEntry *sa, uint64_t seqNum)
Perform replay detection.
uint64_t ipsecGetSeqNum(IpsecSadEntry *sa, uint32_t seql)
Determine the higher-order bits of the sequence number.
IP pseudo header.
Definition: ip.h:110
void icmpProcessMessage(NetInterface *interface, const Ipv4PseudoHeader *requestPseudoHeader, const NetBuffer *buffer, size_t offset)
Incoming ICMP message processing.
Definition: icmp.c:109
@ IPV4_PROTOCOL_TCP
Definition: ipv4.h:277
uint16_t length
Definition: net_mem.h:79
#define htonl(value)
Definition: cpu_endian.h:414
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
ICMP (Internet Control Message Protocol)
error_t
Error codes.
Definition: error.h:43
@ ERROR_PROTOCOL_UNREACHABLE
Definition: error.h:84
error_t ahVerifyIcv(IpsecContext *context, IpsecSadEntry *sa, const Ipv4Header *ipv4Header, const AhHeader *ahHeader, const NetBuffer *buffer, size_t offset)
ICV verification.
Definition: ah.c:452
AhHeader
Definition: ah.h:199
TCP finite state machine.
void * address
Definition: net_mem.h:78
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ IPV4_FLAG_MF
Definition: ipv4.h:263
Helper routines for IPsec.
bool_t ipsecIsSubsetSelector(const IpsecSelector *selector1, const IpsecSelector *selector2)
Test if a selector is a subset of another selector.
Definition: ipsec_misc.c:362
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:40
uint8_t mask
Definition: web_socket.h:319
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
IPsec processing of inbound IP traffic.
IpsecSadEntry * ipsecFindInboundSadEntry(IpsecContext *context, IpsecProtocol protocol, uint32_t spi)
Search the SAD database for a matching inbound entry.
Definition: ipsec_misc.c:134
Anti-replay mechanism.
AH (IP Authentication Header)
error_t ipv4ProcessAhHeader(NetInterface *interface, const Ipv4Header *ipv4Header, const NetBuffer *buffer, size_t offset, NetRxAncillary *ancillary)
Process AH protected packet.
Definition: ah.c:60
CMAC algorithm context.
Definition: cmac.h:54
#define IpsecSadEntry
Definition: ipsec.h:36
TCP/IP raw sockets.
@ IPV4_PROTOCOL_IGMP
Definition: ipv4.h:276
#define ntohs(value)
Definition: cpu_endian.h:421
__weak_func void hmacUpdate(HmacContext *context, const void *data, size_t length)
Update the HMAC context with a portion of the message being hashed.
Definition: hmac.c:201
#define TRACE_WARNING(...)
Definition: debug.h:93
#define TRACE_DEBUG(...)
Definition: debug.h:119
uint8_t digest[MAX_HASH_DIGEST_SIZE]
Definition: hmac.h:63
@ IPV4_OPTION_EEOL
End of Options List.
Definition: ipv4.h:290
ChunkDesc chunk[]
Definition: net_mem.h:92
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
IPsec (IP security)
uint8_t n
@ IPV4_PROTOCOL_UDP
Definition: ipv4.h:278
@ ERROR_AUTHENTICATION_FAILED
Definition: error.h:69
__weak_func void hmacFinal(HmacContext *context, uint8_t *digest)
Finish the HMAC calculation.
Definition: hmac.c:218
Ipv4Option
Definition: ipv4.h:382
#define IpsecContext
Definition: ipsec.h:40
#define IPV4_MAX_HEADER_LENGTH
Definition: ipv4.h:115
error_t cmacInit(CmacContext *context, const CipherAlgo *cipher, const void *key, size_t keyLen)
Initialize CMAC calculation.
Definition: cmac.c:107
void cmacUpdate(CmacContext *context, const void *data, size_t dataLen)
Update the CMAC context with a portion of the message being hashed.
Definition: cmac.c:191
@ IPV4_OPTION_RTRALT
Router Alert.
Definition: ipv4.h:310
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
@ IPV4_OPTION_SEC
Security.
Definition: ipv4.h:300
error_t ipsecGetInboundIpv4PacketSelector(const Ipv4Header *ipv4Header, uint8_t nextHeader, const NetBuffer *buffer, size_t offset, IpsecSelector *selector)
Extract packet's selector from inbound IPv4 packet.
void tcpProcessSegment(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary)
Incoming TCP segment processing.
Definition: tcp_fsm.c:73
@ IPV4_OPTION_CIPSO
Commercial Security.
Definition: ipv4.h:303
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
TcpHeader
Definition: tcp.h:365
__weak_func error_t hmacInit(HmacContext *context, const HashAlgo *hash, const void *key, size_t keyLen)
Initialize HMAC calculation.
Definition: hmac.c:140
error_t cmacFinal(CmacContext *context, uint8_t *mac, size_t macLen)
Finish the CMAC calculation.
Definition: cmac.c:237
void ipsecUpdateReplayWindow(IpsecSadEntry *sa, uint64_t seqNum)
Update sliding window.
@ ERROR_POLICY_FAILURE
Definition: error.h:300
#define ntohl(value)
Definition: cpu_endian.h:422
Ipv4PseudoHeader ipv4Data
Definition: ip.h:115
void ahDumpHeader(const AhHeader *ahHeader)
Dump AH header for debugging purpose.
Definition: ah.c:753
void igmpProcessMessage(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary)
Process incoming IGMP message.
Definition: igmp_common.c:291
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void ahProcessMutableIpv4Options(Ipv4Header *header)
Zeroize mutable IPv4 options.
Definition: ah.c:687