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-2024 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.4.4
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  IpsecSadEntry *sa;
69  AhHeader *ahHeader;
70  IpsecSelector selector;
71  IpPseudoHeader pseudoHeader;
72 
73  //Retrieve the length of the payload
74  length = netBufferGetLength(buffer) - offset;
75 
76  //Malformed packet?
77  if(length < sizeof(AhHeader))
78  return ERROR_INVALID_HEADER;
79 
80  //Point to the AH header
81  ahHeader = netBufferAt(buffer, offset, 0);
82  //Sanity check
83  if(ahHeader == NULL)
84  return ERROR_FAILURE;
85 
86  //If a packet offered to AH for processing appears to be an IP fragment,
87  //the receiver must discard the packet (refer to RFC 4302, section 3.4.1)
88  if((ntohs(ipv4Header->fragmentOffset) & IPV4_OFFSET_MASK) != 0 ||
89  (ntohs(ipv4Header->fragmentOffset) & IPV4_FLAG_MF) != 0)
90  {
91  return ERROR_INVALID_HEADER;
92  }
93 
94  //Upon receipt of a packet containing an IP Authentication Header, the
95  //receiver determines the appropriate (unidirectional) SA via lookup in
96  //the SAD (refer to RFC 4302, section 3.4.2)
98  ntohl(ahHeader->spi));
99 
100  //If no valid Security Association exists for this packet the receiver
101  //must discard the packet. This is an auditable event
102  if(sa == NULL)
103  {
104  //Debug message
105  TRACE_WARNING("AH: No matching SA found!\r\n");
106  //Report an error
107  return ERROR_POLICY_FAILURE;
108  }
109 
110  //The Payload Length field specifies the length of AH header in 32-bit
111  //words (4-byte units), minus 2
112  n = (ahHeader->payloadLen + 2) * sizeof(uint32_t);
113 
114  //Check the length of the AH header
115  if(n > length || n != (sizeof(AhHeader) + sa->icvLen))
116  return ERROR_INVALID_HEADER;
117 
118  //Debug message
119  TRACE_INFO("Parsing AH header...\r\n");
120  //Dump AH header contents for debugging purpose
121  ahDumpHeader(ahHeader);
122 
123  //Because only the low-order 32 bits are transmitted with the packet, the
124  //receiver must deduce and track the sequence number subspace into which
125  //each packet falls
126  seq = ipsecGetSeqNum(sa, ntohl(ahHeader->seqNum));
127 
128  //For each received packet, the receiver must verify that the packet
129  //contains a Sequence Number that does not duplicate the Sequence Number of
130  //any other packets received during the life of this SA. This should be the
131  //first AH check applied to a packet after it has been matched to an SA, to
132  //speed rejection of duplicate packets (refer to RFC 4302, section 3.4.3)
133  error = ipsecCheckReplayWindow(sa, seq);
134 
135  //Duplicate packets are rejected
136  if(error)
137  {
138  //Debug message
139  TRACE_WARNING("AH: Invalid sequence number!\r\n");
140  //Report an error
142  }
143 
144  //If the received packet falls within the window and is not a duplicate, or
145  //if the packet is to the right of the window, then the receiver proceeds to
146  //ICV verification
147  error = ahVerifyIcv(sa, ipv4Header, ahHeader, buffer,
148  offset + sizeof(AhHeader) + sa->icvLen);
149 
150  //If the ICV validation fails, the receiver must discard the received IP
151  //datagram as invalid. This is is an auditable event (refer to RFC 4302,
152  //section 3.4.3)
153  if(error)
154  {
155  //Debug message
156  TRACE_WARNING("AH: ICV validation failed!\r\n");
157  //Report an error
159  }
160 
161  //The receive window is updated only if the ICV verification succeeds
162  ipsecUpdateReplayWindow(sa, seq);
163 
164  //Point to the payload
165  offset += n;
166  length -= n;
167 
168  //Match the packet against the inbound selectors identified by the SAD entry
169  //to verify that the received packet is appropriate for the SA via which it
170  //was received (refer to RFC 4301, section 5.2)
171  error = ipsecGetInboundIpv4PacketSelector(ipv4Header, ahHeader->nextHeader,
172  buffer, offset, &selector);
173  //Any error to report?
174  if(error)
175  return error;
176 
177  //If an IPsec system receives an inbound packet on an SA and the packet's
178  //header fields are not consistent with the selectors for the SA, it must
179  //discard the packet. This is an auditable event
180  if(!ipsecIsSubsetSelector(&selector, &sa->selector))
181  return ERROR_POLICY_FAILURE;
182 
183  //Form the IPv4 pseudo header
184  pseudoHeader.length = sizeof(Ipv4PseudoHeader);
185  pseudoHeader.ipv4Data.srcAddr = ipv4Header->srcAddr;
186  pseudoHeader.ipv4Data.destAddr = ipv4Header->destAddr;
187  pseudoHeader.ipv4Data.reserved = 0;
188  pseudoHeader.ipv4Data.protocol = ahHeader->nextHeader;
189  pseudoHeader.ipv4Data.length = htons(length);
190 
191  //If the computed and received ICVs match, then the datagram is valid, and
192  //it is accepted (refer to RFC 4302, section 3.4.4)
193  switch(ahHeader->nextHeader)
194  {
195  //ICMP protocol?
196  case IPV4_PROTOCOL_ICMP:
197  //Process incoming ICMP message
198  icmpProcessMessage(interface, &pseudoHeader.ipv4Data, buffer, offset);
199 
200 #if (RAW_SOCKET_SUPPORT == ENABLED)
201  //Allow raw sockets to process ICMP messages
202  rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
203  ancillary);
204 #endif
205 
206  //Continue processing
207  break;
208 
209 #if (IGMP_HOST_SUPPORT == ENABLED || IGMP_ROUTER_SUPPORT == ENABLED || \
210  IGMP_SNOOPING_SUPPORT == ENABLED)
211  //IGMP protocol?
212  case IPV4_PROTOCOL_IGMP:
213  //Process incoming IGMP message
214  igmpProcessMessage(interface, &pseudoHeader.ipv4Data, buffer, offset,
215  ancillary);
216 
217 #if (RAW_SOCKET_SUPPORT == ENABLED)
218  //Allow raw sockets to process IGMP messages
219  rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
220  ancillary);
221 #endif
222 
223  //Continue processing
224  break;
225 #endif
226 
227 #if (TCP_SUPPORT == ENABLED)
228  //TCP protocol?
229  case IPV4_PROTOCOL_TCP:
230  //Process incoming TCP segment
231  tcpProcessSegment(interface, &pseudoHeader, buffer, offset, ancillary);
232  //Continue processing
233  break;
234 #endif
235 
236 #if (UDP_SUPPORT == ENABLED)
237  //UDP protocol?
238  case IPV4_PROTOCOL_UDP:
239  //Process incoming UDP datagram
240  error = udpProcessDatagram(interface, &pseudoHeader, buffer, offset,
241  ancillary);
242  //Continue processing
243  break;
244 #endif
245 
246  //Unknown protocol?
247  default:
248 #if (RAW_SOCKET_SUPPORT == ENABLED)
249  //Allow raw sockets to process IPv4 packets
250  error = rawSocketProcessIpPacket(interface, &pseudoHeader, buffer, offset,
251  ancillary);
252 #else
253  //Report an error
255 #endif
256  //Continue processing
257  break;
258  }
259 
260  //Return status code
261  return error;
262 }
263 
264 
265 /**
266  * @brief ICV generation
267  * @param[in] sa Pointer to the SA
268  * @param[in] ipv4Header Pointer to the IPv4 header
269  * @param[in,out] ahHeader Pointer to the AH header
270  * @param[in] buffer Multi-part buffer containing the payload
271  * @param[in] offset Offset to the first byte of the payload
272  * @return Error code
273  **/
274 
276  AhHeader *ahHeader, const NetBuffer *buffer, size_t offset)
277 {
278  error_t error;
279  uint_t i;
280  size_t n;
281  uint8_t *p;
282  IpsecContext *context;
283 
284  //Point to the IPsec context
285  context = netContext.ipsecContext;
286  //Invalid IPsec context?
287  if(context == NULL)
288  return ERROR_FAILURE;
289 
290 #if (AH_HMAC_SUPPORT == ENABLED)
291  //HMAC integrity algorithm?
292  if(sa->authHashAlgo != NULL)
293  {
294  HmacContext *hmacContext;
295 
296  //Point to the HMAC context
297  hmacContext = &context->hmacContext;
298 
299  //The SAD entry specifies the algorithm employed for ICV computation
300  error = hmacInit(hmacContext, sa->authHashAlgo, sa->authKey,
301  sa->authKeyLen);
302  //Any error to report?
303  if(error)
304  return error;
305 
306  //Compute HMAC over the IP or extension header fields before the AH
307  //header that are either immutable in transit or that are predictable
308  //in value upon arrival at the endpoint for the AH SA
309  hmacUpdate(hmacContext, ipv4Header, sizeof(Ipv4Header));
310 
311  //Compute HMAC over the Next Header, Payload Length, Reserved, SPI,
312  //Sequence Number (low-order 32 bits) fields, and the ICV (which is set
313  //to zero for this computation)
314  hmacUpdate(hmacContext, ahHeader, sizeof(AhHeader) + sa->icvLen);
315 
316  //Everything after AH is assumed to be immutable in transit
317  for(i = 0; i < buffer->chunkCount; i++)
318  {
319  //Is there any data to process from the current chunk?
320  if(offset < buffer->chunk[i].length)
321  {
322  //Point to the first byte to be processed
323  p = (uint8_t *) buffer->chunk[i].address + offset;
324  //Compute the number of bytes to process at a time
325  n = buffer->chunk[i].length - offset;
326 
327  //Update HMAC calculation
328  hmacUpdate(hmacContext, p, n);
329 
330  //Process the next block from the start
331  offset = 0;
332  }
333  else
334  {
335  //Skip the current chunk
336  offset -= buffer->chunk[i].length;
337  }
338  }
339 
340  //Extended sequence numbers?
341  if(sa->esn)
342  {
343  //If the ESN option is elected for an SA, then the high-order 32 bits
344  //of the ESN must be included in the ICV computation
345  uint32_t seqh = htonl(sa->seqNum >> 32);
346 
347  //For purposes of ICV computation, these bits are appended (implicitly)
348  //immediately after the end of the payload
349  hmacUpdate(hmacContext, (uint8_t *) &seqh, 4);
350  }
351 
352  //Finalize HMAC calculation
353  hmacFinal(hmacContext, NULL);
354  //The output of the HMAC can be truncated
355  osMemcpy(ahHeader->icv, hmacContext->digest, sa->icvLen);
356  }
357  else
358 #endif
359 #if (AH_CMAC_SUPPORT == ENABLED)
360  //CMAC integrity algorithm?
361  if(sa->authCipherAlgo != NULL)
362  {
363  CmacContext *cmacContext;
364 
365  //Point to the CMAC context
366  cmacContext = &context->cmacContext;
367 
368  //The SAD entry specifies the algorithm employed for ICV computation
369  error = cmacInit(cmacContext, sa->authCipherAlgo, sa->authKey,
370  sa->authKeyLen);
371  //Any error to report?
372  if(error)
373  return error;
374 
375  //Compute CMAC over the IP or extension header fields before the AH
376  //header that are either immutable in transit or that are predictable
377  //in value upon arrival at the endpoint for the AH SA
378  cmacUpdate(cmacContext, ipv4Header, sizeof(Ipv4Header));
379 
380  //Compute HMAC over the Next Header, Payload Length, Reserved, SPI,
381  //Sequence Number (low-order 32 bits) fields, and the ICV (which is set
382  //to zero for this computation)
383  cmacUpdate(cmacContext, ahHeader, sizeof(AhHeader) + sa->icvLen);
384 
385  //Everything after AH is assumed to be immutable in transit
386  for(i = 0; i < buffer->chunkCount; i++)
387  {
388  //Is there any data to process from the current chunk?
389  if(offset < buffer->chunk[i].length)
390  {
391  //Point to the first byte to be processed
392  p = (uint8_t *) buffer->chunk[i].address + offset;
393  //Compute the number of bytes to process at a time
394  n = buffer->chunk[i].length - offset;
395 
396  //Update CMAC calculation
397  cmacUpdate(cmacContext, p, n);
398 
399  //Process the next block from the start
400  offset = 0;
401  }
402  else
403  {
404  //Skip the current chunk
405  offset -= buffer->chunk[i].length;
406  }
407  }
408 
409  //Extended sequence numbers?
410  if(sa->esn)
411  {
412  //If the ESN option is elected for an SA, then the high-order 32 bits
413  //of the ESN must be included in the ICV computation
414  uint32_t seqh = htonl(sa->seqNum >> 32);
415 
416  //For purposes of ICV computation, these bits are appended (implicitly)
417  //immediately after the end of the payload
418  cmacUpdate(cmacContext, (uint8_t *) &seqh, 4);
419  }
420 
421  //Finalize CMAC calculation
422  cmacFinal(cmacContext, ahHeader->icv, sa->icvLen);
423  }
424  else
425 #endif
426  //Unknown integrity algorithm?
427  {
428  //Report an error
429  return ERROR_FAILURE;
430  }
431 
432  //Successful processing
433  return NO_ERROR;
434 }
435 
436 
437 /**
438  * @brief ICV verification
439  * @param[in] sa Pointer to the SA
440  * @param[in] ipv4Header Pointer to the IPv4 header
441  * @param[in] ahHeader Pointer to the AH header
442  * @param[in] buffer Multi-part buffer containing the payload
443  * @param[in] offset Offset to the first byte of the payload
444  * @return Error code
445  **/
446 
448  const AhHeader *ahHeader, const NetBuffer *buffer, size_t offset)
449 {
450  error_t error;
451  uint8_t mask;
452  uint_t i;
453  size_t n;
454  uint8_t *p;
455  IpsecContext *context;
456  Ipv4Header *ipv4Header2;
457  AhHeader *ahHeader2;
458  uint8_t temp[IPV4_MAX_HEADER_LENGTH];
459 
460  //Point to the IPsec context
461  context = netContext.ipsecContext;
462  //Invalid IPsec context?
463  if(context == NULL)
464  return ERROR_FAILURE;
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_HMAC_SUPPORT == ENABLED)
484  //HMAC integrity algorithm?
485  if(sa->authHashAlgo != NULL)
486  {
487  HmacContext *hmacContext;
488 
489  //Point to the HMAC context
490  hmacContext = &context->hmacContext;
491 
492  //The SAD entry specifies the algorithm employed for ICV computation,
493  //and indicates the key required to validate the ICV
494  error = hmacInit(hmacContext, sa->authHashAlgo, sa->authKey,
495  sa->authKeyLen);
496  //Any error to report?
497  if(error)
498  return error;
499 
500  //Compute HMAC 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  hmacUpdate(hmacContext, 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) * 4;
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 for
515  //this computation (refer to RFC 4302, section 3.3.3.1)
516  osMemset(ahHeader2->icv, 0, sa->icvLen);
517 
518  //Compute HMAC over the Next Header, Payload Length, Reserved, SPI,
519  //Sequence Number (low-order 32 bits) fields, and the ICV (which is set
520  //to zero for this computation)
521  hmacUpdate(hmacContext, 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 HMAC calculation
535  hmacUpdate(hmacContext, 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 bits
551  //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 (implicitly)
558  //immediately after the end of the payload
559  hmacUpdate(hmacContext, (uint8_t *) &seqh, 4);
560  }
561 
562  //Finalize HMAC computation
563  hmacFinal(hmacContext, NULL);
564 
565  //Debug message
566  TRACE_DEBUG_ARRAY("Calculated HMAC = ", hmacContext->digest, sa->icvLen);
567 
568  //The calculated checksum is bitwise compared to the received ICV
569  for(mask = 0, i = 0; i < sa->icvLen; i++)
570  {
571  mask |= hmacContext->digest[i] ^ ahHeader->icv[i];
572  }
573  }
574  else
575 #endif
576 #if (AH_CMAC_SUPPORT == ENABLED)
577  //CMAC integrity algorithm?
578  if(sa->authCipherAlgo != NULL)
579  {
580  CmacContext *cmacContext;
581 
582  //Point to the CMAC context
583  cmacContext = &context->cmacContext;
584 
585  //The SAD entry specifies the algorithm employed for ICV computation,
586  //and indicates the key required to validate the ICV
587  error = cmacInit(cmacContext, sa->authCipherAlgo, sa->authKey,
588  sa->authKeyLen);
589  //Any error to report?
590  if(error)
591  return error;
592 
593  //Compute CMAC over the IP or extension header fields before the AH
594  //header that are either immutable in transit or that are predictable
595  //in value upon arrival at the endpoint for the AH SA
596  cmacUpdate(cmacContext, temp, n);
597 
598  //The Payload Length field specifies the length of AH header in 32-bit
599  //words (4-byte units), minus 2
600  n = (ahHeader->payloadLen + 2) * sizeof(uint32_t);
601 
602  //Copy the AH header
603  osMemcpy(temp, ahHeader, n);
604  //Point to the AH header
605  ahHeader2 = (AhHeader *) temp;
606 
607  //The Integrity Check Value field is also set to zero in preparation for
608  //this computation (refer to RFC 4302, section 3.3.3.1)
609  osMemset(ahHeader2->icv, 0, sa->icvLen);
610 
611  //Compute CMAC over the Next Header, Payload Length, Reserved, SPI,
612  //Sequence Number (low-order 32 bits) fields, and the ICV (which is set
613  //to zero for this computation)
614  cmacUpdate(cmacContext, temp, n);
615 
616  //Everything after AH is assumed to be immutable in transit
617  for(i = 0; i < buffer->chunkCount; i++)
618  {
619  //Is there any data to process from the current chunk?
620  if(offset < buffer->chunk[i].length)
621  {
622  //Point to the first byte to be processed
623  p = (uint8_t *) buffer->chunk[i].address + offset;
624  //Compute the number of bytes to process at a time
625  n = buffer->chunk[i].length - offset;
626 
627  //Update CMAC calculation
628  cmacUpdate(cmacContext, p, n);
629 
630  //Process the next block from the start
631  offset = 0;
632  }
633  else
634  {
635  //Skip the current chunk
636  offset -= buffer->chunk[i].length;
637  }
638  }
639 
640  //Extended sequence numbers?
641  if(sa->esn)
642  {
643  //If the ESN option is elected for an SA, then the high-order 32 bits
644  //of the ESN must be included in the ICV computation
645  uint32_t seqh = ipsecGetSeqNum(sa, ntohl(ahHeader->seqNum)) >> 32;
646 
647  //Convert the 32-bit value to network byte order
648  seqh = htonl(seqh);
649 
650  //For purposes of ICV computation, these bits are appended (implicitly)
651  //immediately after the end of the payload
652  cmacUpdate(cmacContext, (uint8_t *) &seqh, 4);
653  }
654 
655  //Finalize CMAC computation
656  cmacFinal(cmacContext, NULL, sa->icvLen);
657 
658  //Debug message
659  TRACE_DEBUG_ARRAY("Calculated CMAC = ", cmacContext->mac, sa->icvLen);
660 
661  //The calculated checksum is bitwise compared to the received ICV
662  for(mask = 0, i = 0; i < sa->icvLen; i++)
663  {
664  mask |= cmacContext->mac[i] ^ ahHeader->icv[i];
665  }
666  }
667  else
668 #endif
669  //Unknown integrity algorithm?
670  {
671  //Report an error
672  return ERROR_FAILURE;
673  }
674 
675  //If the ICV validation fails, the receiver must discard the received IP
676  //datagram as invalid. This is is an auditable event (refer to RFC 4302,
677  //section 3.4.3)
678  if(mask == 0)
679  {
680  return NO_ERROR;
681  }
682  else
683  {
684  return ERROR_INVALID_MAC;
685  }
686 }
687 
688 
689 /**
690  * @brief Zeroize mutable IPv4 options
691  * @param[in] header Pointer to the IPv4 header
692  **/
693 
695 {
696  size_t i;
697  size_t n;
698  size_t length;
699  Ipv4Option *option;
700 
701  //Compute the length of the options field
702  length = (header->headerLength * 4) - sizeof(TcpHeader);
703 
704  //Point to the very first option
705  i = 0;
706 
707  //Loop through the list of options
708  while(i < length)
709  {
710  //Point to the current option
711  option = (Ipv4Option *) (header->options + i);
712 
713  //Check option type
714  if(option->type == IPV4_OPTION_EEOL)
715  {
716  //This option code indicates the end of the option list
717  break;
718  }
719  else if(option->type == IPV4_OPTION_NOP)
720  {
721  //This option consists of a single octet
722  i++;
723  }
724  else
725  {
726  //Malformed option?
727  if((i + 1) >= length)
728  break;
729 
730  //The option code is followed by a one-byte length field
731  n = option->length;
732 
733  //Check the length of the option
734  if(n < sizeof(Ipv4Option) || (i + n) > length)
735  break;
736 
737  //Mutable option?
738  if(option->type != IPV4_OPTION_SEC &&
739  option->type != IPV4_OPTION_ESEC &&
740  option->type != IPV4_OPTION_CIPSO &&
741  option->type != IPV4_OPTION_RTRALT &&
742  option->type != IPV4_OPTION_SDB)
743  {
744  //The entire option is zeroed before performing the ICV calculation
745  osMemset(option, 0, n);
746  }
747 
748  //Jump to the next option
749  i += n;
750  }
751  }
752 }
753 
754 
755 /**
756  * @brief Dump AH header for debugging purpose
757  * @param[in] ahHeader Pointer to the AH header
758  **/
759 
760 void ahDumpHeader(const AhHeader *ahHeader)
761 {
762  size_t n;
763 
764  //The Payload Length field specifies the length of AH header in 32-bit
765  //words (4-byte units), minus 2
766  n = (ahHeader->payloadLen + 2) * sizeof(uint32_t);
767 
768  //Check the length of the AH header
769  if(n >= sizeof(AhHeader))
770  {
771  //Retrieve the length of the ICV tag
772  n -= sizeof(AhHeader);
773 
774  //Dump AH header contents
775  TRACE_DEBUG(" Next Header = %" PRIu8 "\r\n", ahHeader->nextHeader);
776  TRACE_DEBUG(" Payload Length = %" PRIu8 "\r\n", ahHeader->payloadLen);
777  TRACE_DEBUG(" SPI = 0x%08" PRIX32 "\r\n", ntohl(ahHeader->spi));
778  TRACE_DEBUG(" Sequence Number = 0x%08" PRIX32 "\r\n", ntohl(ahHeader->seqNum));
779  TRACE_DEBUG_ARRAY(" ICV = ", ahHeader->icv, n);
780  }
781 }
782 
783 #endif
#define htons(value)
Definition: cpu_endian.h:413
error_t ahGenerateIcv(IpsecSadEntry *sa, const Ipv4Header *ipv4Header, AhHeader *ahHeader, const NetBuffer *buffer, size_t offset)
ICV generation.
Definition: ah.c:275
error_t ahVerifyIcv(IpsecSadEntry *sa, const Ipv4Header *ipv4Header, const AhHeader *ahHeader, const NetBuffer *buffer, size_t offset)
ICV verification.
Definition: ah.c:447
HMAC algorithm context.
Definition: hmac.h:59
#define Ipv4Header
Definition: ipv4.h:36
@ IPV4_PROTOCOL_ICMP
Definition: ipv4.h:250
@ IPV4_OFFSET_MASK
Definition: ipv4.h:240
@ IPV4_OPTION_SDB
Selective Directed Broadcast.
Definition: ipv4.h:286
@ ERROR_WRONG_SEQUENCE_NUMBER
Definition: error.h:182
@ IPSEC_PROTOCOL_AH
Definition: ipsec.h:192
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:68
IPsec selector.
Definition: ipsec.h:302
uint8_t p
Definition: ndp.h:300
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:277
NetContext netContext
Definition: net.c:74
error_t udpProcessDatagram(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary)
Incoming UDP datagram processing.
Definition: udp.c:124
size_t length
Definition: ip.h:111
@ IPV4_OPTION_NOP
No Operation.
Definition: ipv4.h:266
@ 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:111
@ IPV4_PROTOCOL_TCP
Definition: ipv4.h:252
uint8_t mac[MAX_CIPHER_BLOCK_SIZE]
Definition: cmac.h:61
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:141
ICMP (Internet Control Message Protocol)
error_t
Error codes.
Definition: error.h:43
@ ERROR_PROTOCOL_UNREACHABLE
Definition: error.h:84
AhHeader
Definition: ah.h:146
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:239
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:36
uint8_t mask
Definition: web_socket.h:319
IPsec context.
Definition: ipsec.h:434
#define Ipv4PseudoHeader
Definition: ipv4.h:39
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
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
void * ipsecContext
IPsec context.
Definition: net.h:333
CMAC algorithm context.
Definition: cmac.h:54
#define IpsecSadEntry
Definition: ipsec.h:36
TCP/IP raw sockets.
@ IPV4_PROTOCOL_IGMP
Definition: ipv4.h:251
#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:85
#define TRACE_DEBUG(...)
Definition: debug.h:107
uint8_t digest[MAX_HASH_DIGEST_SIZE]
Definition: hmac.h:63
@ IPV4_OPTION_EEOL
End of Options List.
Definition: ipv4.h:265
ChunkDesc chunk[]
Definition: net_mem.h:92
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:108
IPsec (IP security)
uint8_t n
@ IPV4_PROTOCOL_UDP
Definition: ipv4.h:253
@ 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:357
CmacContext cmacContext
CMAC context.
Definition: ipsec.h:444
#define IPV4_MAX_HEADER_LENGTH
Definition: ipv4.h:104
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:285
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:275
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:278
HmacContext hmacContext
HMAC context.
Definition: ipsec.h:447
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
TcpHeader
Definition: tcp.h:358
__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:299
#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:760
void igmpProcessMessage(NetInterface *interface, const Ipv4PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary)
Process incoming IGMP message.
Definition: igmp_common.c:292
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void ahProcessMutableIpv4Options(Ipv4Header *header)
Zeroize mutable IPv4 options.
Definition: ah.c:694