]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IpSecDxe/IpSecImpl.c
NetworkPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / NetworkPkg / IpSecDxe / IpSecImpl.c
1 /** @file
2 The implementation of IPsec.
3
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11 #include "IpSecImpl.h"
12 #include "IkeService.h"
13 #include "IpSecDebug.h"
14 #include "IpSecCryptIo.h"
15 #include "IpSecConfigImpl.h"
16
17 /**
18 Check if the specified Address is the Valid Address Range.
19
20 This function checks if the bytes after prefixed length are all Zero in this
21 Address. This Address is supposed to point to a range address. That means it
22 should gives the correct prefixed address and the bytes outside the prefixed are
23 zero.
24
25 @param[in] IpVersion The IP version.
26 @param[in] Address Points to EFI_IP_ADDRESS to be checked.
27 @param[in] PrefixLength The PrefixeLength of this address.
28
29 @retval TRUE The address is a vaild address range.
30 @retval FALSE The address is not a vaild address range.
31
32 **/
33 BOOLEAN
34 IpSecValidAddressRange (
35 IN UINT8 IpVersion,
36 IN EFI_IP_ADDRESS *Address,
37 IN UINT8 PrefixLength
38 )
39 {
40 UINT8 Div;
41 UINT8 Mod;
42 UINT8 Mask;
43 UINT8 AddrLen;
44 UINT8 *Addr;
45 EFI_IP_ADDRESS ZeroAddr;
46
47 if (PrefixLength == 0) {
48 return TRUE;
49 }
50
51 AddrLen = (UINT8) ((IpVersion == IP_VERSION_4) ? 32 : 128);
52
53 if (AddrLen <= PrefixLength) {
54 return FALSE;
55 }
56
57 Div = (UINT8) (PrefixLength / 8);
58 Mod = (UINT8) (PrefixLength % 8);
59 Addr = (UINT8 *) Address;
60 ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS));
61
62 //
63 // Check whether the mod part of host scope is zero or not.
64 //
65 if (Mod > 0) {
66 Mask = (UINT8) (0xFF << (8 - Mod));
67
68 if ((Addr[Div] | Mask) != Mask) {
69 return FALSE;
70 }
71
72 Div++;
73 }
74 //
75 // Check whether the div part of host scope is zero or not.
76 //
77 if (CompareMem (
78 &Addr[Div],
79 &ZeroAddr,
80 sizeof (EFI_IP_ADDRESS) - Div
81 ) != 0) {
82 return FALSE;
83 }
84
85 return TRUE;
86 }
87
88 /**
89 Extrct the Address Range from a Address.
90
91 This function keep the prefix address and zero other part address.
92
93 @param[in] Address Point to a specified address.
94 @param[in] PrefixLength The prefix length.
95 @param[out] Range Contain the return Address Range.
96
97 **/
98 VOID
99 IpSecExtractAddressRange (
100 IN EFI_IP_ADDRESS *Address,
101 IN UINT8 PrefixLength,
102 OUT EFI_IP_ADDRESS *Range
103 )
104 {
105 UINT8 Div;
106 UINT8 Mod;
107 UINT8 Mask;
108 UINT8 *Addr;
109
110 if (PrefixLength == 0) {
111 return ;
112 }
113
114 Div = (UINT8) (PrefixLength / 8);
115 Mod = (UINT8) (PrefixLength % 8);
116 Addr = (UINT8 *) Range;
117
118 CopyMem (Range, Address, sizeof (EFI_IP_ADDRESS));
119
120 //
121 // Zero the mod part of host scope.
122 //
123 if (Mod > 0) {
124 Mask = (UINT8) (0xFF << (8 - Mod));
125 Addr[Div] = (UINT8) (Addr[Div] & Mask);
126 Div++;
127 }
128 //
129 // Zero the div part of host scope.
130 //
131 ZeroMem (&Addr[Div], sizeof (EFI_IP_ADDRESS) - Div);
132
133 }
134
135 /**
136 Checks if the IP Address in the address range of AddressInfos specified.
137
138 @param[in] IpVersion The IP version.
139 @param[in] IpAddr Point to EFI_IP_ADDRESS to be check.
140 @param[in] AddressInfo A list of EFI_IP_ADDRESS_INFO that is used to check
141 the IP Address is matched.
142 @param[in] AddressCount The total numbers of the AddressInfo.
143
144 @retval TRUE If the Specified IP Address is in the range of the AddressInfos specified.
145 @retval FALSE If the Specified IP Address is not in the range of the AddressInfos specified.
146
147 **/
148 BOOLEAN
149 IpSecMatchIpAddress (
150 IN UINT8 IpVersion,
151 IN EFI_IP_ADDRESS *IpAddr,
152 IN EFI_IP_ADDRESS_INFO *AddressInfo,
153 IN UINT32 AddressCount
154 )
155 {
156 EFI_IP_ADDRESS Range;
157 UINT32 Index;
158 BOOLEAN IsMatch;
159
160 IsMatch = FALSE;
161
162 for (Index = 0; Index < AddressCount; Index++) {
163 //
164 // Check whether the target address is in the address range
165 // if it's a valid range of address.
166 //
167 if (IpSecValidAddressRange (
168 IpVersion,
169 &AddressInfo[Index].Address,
170 AddressInfo[Index].PrefixLength
171 )) {
172 //
173 // Get the range of the target address belongs to.
174 //
175 ZeroMem (&Range, sizeof (EFI_IP_ADDRESS));
176 IpSecExtractAddressRange (
177 IpAddr,
178 AddressInfo[Index].PrefixLength,
179 &Range
180 );
181
182 if (CompareMem (
183 &Range,
184 &AddressInfo[Index].Address,
185 sizeof (EFI_IP_ADDRESS)
186 ) == 0) {
187 //
188 // The target address is in the address range.
189 //
190 IsMatch = TRUE;
191 break;
192 }
193 }
194
195 if (CompareMem (
196 IpAddr,
197 &AddressInfo[Index].Address,
198 sizeof (EFI_IP_ADDRESS)
199 ) == 0) {
200 //
201 // The target address is exact same as the address.
202 //
203 IsMatch = TRUE;
204 break;
205 }
206 }
207 return IsMatch;
208 }
209
210 /**
211 Check if the specified Protocol and Prot is supported by the specified SPD Entry.
212
213 This function is the subfunction of IPsecLookUpSpdEntry() that is used to
214 check if the sent/received IKE packet has the related SPD entry support.
215
216 @param[in] Protocol The Protocol to be checked.
217 @param[in] IpPayload Point to IP Payload to be check.
218 @param[in] SpdProtocol The Protocol supported by SPD.
219 @param[in] SpdLocalPort The Local Port in SPD.
220 @param[in] SpdRemotePort The Remote Port in SPD.
221 @param[in] IsOutbound Flag to indicate the is for IKE Packet sending or recieving.
222
223 @retval TRUE The Protocol and Port are supported by the SPD Entry.
224 @retval FALSE The Protocol and Port are not supported by the SPD Entry.
225
226 **/
227 BOOLEAN
228 IpSecMatchNextLayerProtocol (
229 IN UINT8 Protocol,
230 IN UINT8 *IpPayload,
231 IN UINT16 SpdProtocol,
232 IN UINT16 SpdLocalPort,
233 IN UINT16 SpdRemotePort,
234 IN BOOLEAN IsOutbound
235 )
236 {
237 BOOLEAN IsMatch;
238
239 if (SpdProtocol == EFI_IPSEC_ANY_PROTOCOL) {
240 return TRUE;
241 }
242
243 IsMatch = FALSE;
244
245 if (SpdProtocol == Protocol) {
246 switch (Protocol) {
247 case EFI_IP_PROTO_UDP:
248 case EFI_IP_PROTO_TCP:
249 //
250 // For udp and tcp, (0, 0) means no need to check local and remote
251 // port. The payload is passed from upper level, which means it should
252 // be in network order.
253 //
254 IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);
255 IsMatch = (BOOLEAN) (IsMatch ||
256 (IsOutbound &&
257 (BOOLEAN)(
258 NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdLocalPort &&
259 NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdRemotePort
260 )
261 ));
262
263 IsMatch = (BOOLEAN) (IsMatch ||
264 (!IsOutbound &&
265 (BOOLEAN)(
266 NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdLocalPort &&
267 NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdRemotePort
268 )
269 ));
270 break;
271
272 case EFI_IP_PROTO_ICMP:
273 //
274 // For icmpv4, type code is replaced with local port and remote port,
275 // and (0, 0) means no need to check.
276 //
277 IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);
278 IsMatch = (BOOLEAN) (IsMatch ||
279 (BOOLEAN) (((IP4_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&
280 ((IP4_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort
281 )
282 );
283 break;
284
285 case IP6_ICMP:
286 //
287 // For icmpv6, type code is replaced with local port and remote port,
288 // and (0, 0) means no need to check.
289 //
290 IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);
291
292 IsMatch = (BOOLEAN) (IsMatch ||
293 (BOOLEAN) (((IP6_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&
294 ((IP6_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort
295 )
296 );
297 break;
298
299 default:
300 IsMatch = TRUE;
301 break;
302 }
303 }
304
305 return IsMatch;
306 }
307
308 /**
309 Find the SAD through a specified SPD's SAD list.
310
311 @param[in] SadList SAD list related to a specified SPD entry.
312 @param[in] DestAddress The destination address used to find the SAD entry.
313 @param[in] IpVersion The IP version. Ip4 or Ip6.
314
315 @return The pointer to a certain SAD entry.
316
317 **/
318 IPSEC_SAD_ENTRY *
319 IpSecLookupSadBySpd (
320 IN LIST_ENTRY *SadList,
321 IN EFI_IP_ADDRESS *DestAddress,
322 IN UINT8 IpVersion
323 )
324 {
325 LIST_ENTRY *Entry;
326 IPSEC_SAD_ENTRY *SadEntry;
327
328 NET_LIST_FOR_EACH (Entry, SadList) {
329
330 SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);
331 //
332 // Find the right SAD entry which contains the appointed dest address.
333 //
334 if (IpSecMatchIpAddress (
335 IpVersion,
336 DestAddress,
337 SadEntry->Data->SpdSelector->RemoteAddress,
338 SadEntry->Data->SpdSelector->RemoteAddressCount
339 )){
340 return SadEntry;
341 }
342 }
343
344 return NULL;
345 }
346
347 /**
348 Find the SAD through whole SAD list.
349
350 @param[in] Spi The SPI used to search the SAD entry.
351 @param[in] DestAddress The destination used to search the SAD entry.
352 @param[in] IpVersion The IP version. Ip4 or Ip6.
353
354 @return the pointer to a certain SAD entry.
355
356 **/
357 IPSEC_SAD_ENTRY *
358 IpSecLookupSadBySpi (
359 IN UINT32 Spi,
360 IN EFI_IP_ADDRESS *DestAddress,
361 IN UINT8 IpVersion
362 )
363 {
364 LIST_ENTRY *Entry;
365 LIST_ENTRY *SadList;
366 IPSEC_SAD_ENTRY *SadEntry;
367
368 SadList = &mConfigData[IPsecConfigDataTypeSad];
369
370 NET_LIST_FOR_EACH (Entry, SadList) {
371
372 SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
373
374 //
375 // Find the right SAD entry which contain the appointed spi and dest addr.
376 //
377 if (SadEntry->Id->Spi == Spi) {
378 if (SadEntry->Data->Mode == EfiIPsecTunnel) {
379 if (CompareMem (
380 &DestAddress,
381 &SadEntry->Data->TunnelDestAddress,
382 sizeof (EFI_IP_ADDRESS)
383 )) {
384 return SadEntry;
385 }
386 } else {
387 if (SadEntry->Data->SpdSelector != NULL &&
388 IpSecMatchIpAddress (
389 IpVersion,
390 DestAddress,
391 SadEntry->Data->SpdSelector->RemoteAddress,
392 SadEntry->Data->SpdSelector->RemoteAddressCount
393 )
394 ) {
395 return SadEntry;
396 }
397 }
398 }
399 }
400 return NULL;
401 }
402
403 /**
404 Look up if there is existing SAD entry for specified IP packet sending.
405
406 This function is called by the IPsecProcess when there is some IP packet needed to
407 send out. This function checks if there is an existing SAD entry that can be serviced
408 to this IP packet sending. If no existing SAD entry could be used, this
409 function will invoke an IPsec Key Exchange Negotiation.
410
411 @param[in] Private Points to private data.
412 @param[in] NicHandle Points to a NIC handle.
413 @param[in] IpVersion The version of IP.
414 @param[in] IpHead The IP Header of packet to be sent out.
415 @param[in] IpPayload The IP Payload to be sent out.
416 @param[in] OldLastHead The Last protocol of the IP packet.
417 @param[in] SpdEntry Points to a related SPD entry.
418 @param[out] SadEntry Contains the Point of a related SAD entry.
419
420 @retval EFI_DEVICE_ERROR One of following conditions is TRUE:
421 - If don't find related UDP service.
422 - Sequence Number is used up.
423 - Extension Sequence Number is used up.
424 @retval EFI_NOT_READY No existing SAD entry could be used.
425 @retval EFI_SUCCESS Find the related SAD entry.
426
427 **/
428 EFI_STATUS
429 IpSecLookupSadEntry (
430 IN IPSEC_PRIVATE_DATA *Private,
431 IN EFI_HANDLE NicHandle,
432 IN UINT8 IpVersion,
433 IN VOID *IpHead,
434 IN UINT8 *IpPayload,
435 IN UINT8 OldLastHead,
436 IN IPSEC_SPD_ENTRY *SpdEntry,
437 OUT IPSEC_SAD_ENTRY **SadEntry
438 )
439 {
440 IKE_UDP_SERVICE *UdpService;
441 IPSEC_SAD_ENTRY *Entry;
442 IPSEC_SAD_DATA *Data;
443 EFI_IP_ADDRESS DestIp;
444 UINT32 SeqNum32;
445
446 *SadEntry = NULL;
447 UdpService = IkeLookupUdp (Private, NicHandle, IpVersion);
448
449 if (UdpService == NULL) {
450 return EFI_DEVICE_ERROR;
451 }
452 //
453 // Parse the destination address from ip header.
454 //
455 ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));
456 if (IpVersion == IP_VERSION_4) {
457 CopyMem (
458 &DestIp,
459 &((IP4_HEAD *) IpHead)->Dst,
460 sizeof (IP4_ADDR)
461 );
462 } else {
463 CopyMem (
464 &DestIp,
465 &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
466 sizeof (EFI_IP_ADDRESS)
467 );
468 }
469
470 //
471 // Find the SAD entry in the spd.sas list according to the dest address.
472 //
473 Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp, IpVersion);
474
475 if (Entry == NULL) {
476 if (OldLastHead != IP6_ICMP ||
477 (OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST)
478 ) {
479 //
480 // Start ike negotiation process except the request packet of ping.
481 //
482 if (SpdEntry->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
483 IkeNegotiate (
484 UdpService,
485 SpdEntry,
486 &SpdEntry->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress
487 );
488 } else {
489 IkeNegotiate (
490 UdpService,
491 SpdEntry,
492 &DestIp
493 );
494 }
495
496 }
497
498 return EFI_NOT_READY;
499 }
500
501 Data = Entry->Data;
502
503 if (!Data->ManualSet) {
504 if (Data->ESNEnabled) {
505 //
506 // Validate the 64bit sn number if 64bit sn enabled.
507 //
508 if ((UINT64) (Data->SequenceNumber + 1) == 0) {
509 //
510 // TODO: Re-negotiate SA
511 //
512 return EFI_DEVICE_ERROR;
513 }
514 } else {
515 //
516 // Validate the 32bit sn number if 64bit sn disabled.
517 //
518 SeqNum32 = (UINT32) Data->SequenceNumber;
519 if ((UINT32) (SeqNum32 + 1) == 0) {
520 //
521 // TODO: Re-negotiate SA
522 //
523 return EFI_DEVICE_ERROR;
524 }
525 }
526 }
527
528 *SadEntry = Entry;
529
530 return EFI_SUCCESS;
531 }
532
533 /**
534 Find a PAD entry according to a remote IP address.
535
536 @param[in] IpVersion The version of IP.
537 @param[in] IpAddr Points to remote IP address.
538
539 @return the pointer of related PAD entry.
540
541 **/
542 IPSEC_PAD_ENTRY *
543 IpSecLookupPadEntry (
544 IN UINT8 IpVersion,
545 IN EFI_IP_ADDRESS *IpAddr
546 )
547 {
548 LIST_ENTRY *PadList;
549 LIST_ENTRY *Entry;
550 EFI_IP_ADDRESS_INFO *IpAddrInfo;
551 IPSEC_PAD_ENTRY *PadEntry;
552
553 PadList = &mConfigData[IPsecConfigDataTypePad];
554
555 for (Entry = PadList->ForwardLink; Entry != PadList; Entry = Entry->ForwardLink) {
556
557 PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
558 IpAddrInfo = &PadEntry->Id->Id.IpAddress;
559 //
560 // Find the right pad entry which contain the appointed dest addr.
561 //
562 if (IpSecMatchIpAddress (IpVersion, IpAddr, IpAddrInfo, 1)) {
563 return PadEntry;
564 }
565 }
566
567 return NULL;
568 }
569
570 /**
571 Check if the specified IP packet can be serviced by this SPD entry.
572
573 @param[in] SpdEntry Point to SPD entry.
574 @param[in] IpVersion Version of IP.
575 @param[in] IpHead Point to IP header.
576 @param[in] IpPayload Point to IP payload.
577 @param[in] Protocol The Last protocol of IP packet.
578 @param[in] IsOutbound Traffic direction.
579 @param[out] Action The support action of SPD entry.
580
581 @retval EFI_SUCCESS Find the related SPD.
582 @retval EFI_NOT_FOUND Not find the related SPD entry;
583
584 **/
585 EFI_STATUS
586 IpSecLookupSpdEntry (
587 IN IPSEC_SPD_ENTRY *SpdEntry,
588 IN UINT8 IpVersion,
589 IN VOID *IpHead,
590 IN UINT8 *IpPayload,
591 IN UINT8 Protocol,
592 IN BOOLEAN IsOutbound,
593 OUT EFI_IPSEC_ACTION *Action
594 )
595 {
596 EFI_IPSEC_SPD_SELECTOR *SpdSel;
597 IP4_HEAD *Ip4;
598 EFI_IP6_HEADER *Ip6;
599 EFI_IP_ADDRESS SrcAddr;
600 EFI_IP_ADDRESS DstAddr;
601 BOOLEAN SpdMatch;
602
603 ASSERT (SpdEntry != NULL);
604 SpdSel = SpdEntry->Selector;
605 Ip4 = (IP4_HEAD *) IpHead;
606 Ip6 = (EFI_IP6_HEADER *) IpHead;
607
608 ZeroMem (&SrcAddr, sizeof (EFI_IP_ADDRESS));
609 ZeroMem (&DstAddr, sizeof (EFI_IP_ADDRESS));
610
611 //
612 // Parse the source and destination address from ip header.
613 //
614 if (IpVersion == IP_VERSION_4) {
615 CopyMem (&SrcAddr, &Ip4->Src, sizeof (IP4_ADDR));
616 CopyMem (&DstAddr, &Ip4->Dst, sizeof (IP4_ADDR));
617 } else {
618 CopyMem (&SrcAddr, &Ip6->SourceAddress, sizeof (EFI_IPv6_ADDRESS));
619 CopyMem (&DstAddr, &Ip6->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));
620 }
621 //
622 // Check the local and remote addresses for outbound traffic
623 //
624 SpdMatch = (BOOLEAN)(IsOutbound &&
625 IpSecMatchIpAddress (
626 IpVersion,
627 &SrcAddr,
628 SpdSel->LocalAddress,
629 SpdSel->LocalAddressCount
630 ) &&
631 IpSecMatchIpAddress (
632 IpVersion,
633 &DstAddr,
634 SpdSel->RemoteAddress,
635 SpdSel->RemoteAddressCount
636 )
637 );
638
639 //
640 // Check the local and remote addresses for inbound traffic
641 //
642 SpdMatch = (BOOLEAN) (SpdMatch ||
643 (!IsOutbound &&
644 IpSecMatchIpAddress (
645 IpVersion,
646 &DstAddr,
647 SpdSel->LocalAddress,
648 SpdSel->LocalAddressCount
649 ) &&
650 IpSecMatchIpAddress (
651 IpVersion,
652 &SrcAddr,
653 SpdSel->RemoteAddress,
654 SpdSel->RemoteAddressCount
655 )
656 ));
657
658 //
659 // Check the next layer protocol and local and remote ports.
660 //
661 SpdMatch = (BOOLEAN) (SpdMatch &&
662 IpSecMatchNextLayerProtocol (
663 Protocol,
664 IpPayload,
665 SpdSel->NextLayerProtocol,
666 SpdSel->LocalPort,
667 SpdSel->RemotePort,
668 IsOutbound
669 )
670 );
671
672 if (SpdMatch) {
673 //
674 // Find the right SPD entry if match the 5 key elements.
675 //
676 *Action = SpdEntry->Data->Action;
677 return EFI_SUCCESS;
678 }
679
680 return EFI_NOT_FOUND;
681 }
682
683 /**
684 The call back function of NetbufFromExt.
685
686 @param[in] Arg The argument passed from the caller.
687
688 **/
689 VOID
690 EFIAPI
691 IpSecOnRecyclePacket (
692 IN VOID *Arg
693 )
694 {
695 }
696
697 /**
698 This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP
699 is released.
700
701 @param[in] Event The related event.
702 @param[in] Context The data passed by the caller.
703
704 **/
705 VOID
706 EFIAPI
707 IpSecRecycleCallback (
708 IN EFI_EVENT Event,
709 IN VOID *Context
710 )
711 {
712 IPSEC_RECYCLE_CONTEXT *RecycleContext;
713
714 RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context;
715
716 if (RecycleContext->FragmentTable != NULL) {
717 FreePool (RecycleContext->FragmentTable);
718 }
719
720 if (RecycleContext->PayloadBuffer != NULL) {
721 FreePool (RecycleContext->PayloadBuffer);
722 }
723
724 FreePool (RecycleContext);
725 gBS->CloseEvent (Event);
726
727 }
728
729 /**
730 Calculate the extension hader of IP. The return length only doesn't contain
731 the fixed IP header length.
732
733 @param[in] IpHead Points to an IP head to be calculated.
734 @param[in] LastHead Points to the last header of the IP header.
735
736 @return The length of the extension header.
737
738 **/
739 UINT16
740 IpSecGetPlainExtHeadSize (
741 IN VOID *IpHead,
742 IN UINT8 *LastHead
743 )
744 {
745 UINT16 Size;
746
747 Size = (UINT16) (LastHead - (UINT8 *) IpHead);
748
749 if (Size > sizeof (EFI_IP6_HEADER)) {
750 //
751 // * (LastHead+1) point the last header's length but not include the first
752 // 8 octers, so this formluation add 8 at the end.
753 //
754 Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8);
755 } else {
756 Size = 0;
757 }
758
759 return Size;
760 }
761
762 /**
763 Verify if the Authentication payload is correct.
764
765 @param[in] EspBuffer Points to the ESP wrapped buffer.
766 @param[in] EspSize The size of the ESP wrapped buffer.
767 @param[in] SadEntry The related SAD entry to store the authentication
768 algorithm key.
769 @param[in] IcvSize The length of ICV.
770
771 @retval EFI_SUCCESS The authentication data is correct.
772 @retval EFI_ACCESS_DENIED The authentication data is not correct.
773
774 **/
775 EFI_STATUS
776 IpSecEspAuthVerifyPayload (
777 IN UINT8 *EspBuffer,
778 IN UINTN EspSize,
779 IN IPSEC_SAD_ENTRY *SadEntry,
780 IN UINTN IcvSize
781 )
782 {
783 EFI_STATUS Status;
784 UINTN AuthSize;
785 UINT8 IcvBuffer[12];
786 HASH_DATA_FRAGMENT HashFragment[1];
787
788 //
789 // Calculate the size of authentication payload.
790 //
791 AuthSize = EspSize - IcvSize;
792
793 //
794 // Calculate the icv buffer and size of the payload.
795 //
796 HashFragment[0].Data = EspBuffer;
797 HashFragment[0].DataSize = AuthSize;
798
799 Status = IpSecCryptoIoHmac (
800 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,
801 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
802 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,
803 HashFragment,
804 1,
805 IcvBuffer,
806 IcvSize
807 );
808 if (EFI_ERROR (Status)) {
809 return Status;
810 }
811
812 //
813 // Compare the calculated icv and the appended original icv.
814 //
815 if (CompareMem (EspBuffer + AuthSize, IcvBuffer, IcvSize) == 0) {
816 return EFI_SUCCESS;
817 }
818
819 DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));
820 return EFI_ACCESS_DENIED;
821 }
822
823 /**
824 Search the related SAD entry by the input .
825
826 @param[in] IpHead The pointer to IP header.
827 @param[in] IpVersion The version of IP (IP4 or IP6).
828 @param[in] Spi The SPI used to search the related SAD entry.
829
830
831 @retval NULL Not find the related SAD entry.
832 @retval IPSEC_SAD_ENTRY Return the related SAD entry.
833
834 **/
835 IPSEC_SAD_ENTRY *
836 IpSecFoundSadFromInboundPacket (
837 UINT8 *IpHead,
838 UINT8 IpVersion,
839 UINT32 Spi
840 )
841 {
842 EFI_IP_ADDRESS DestIp;
843
844 //
845 // Parse destination address from ip header.
846 //
847 ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));
848 if (IpVersion == IP_VERSION_4) {
849 CopyMem (
850 &DestIp,
851 &((IP4_HEAD *) IpHead)->Dst,
852 sizeof (IP4_ADDR)
853 );
854 } else {
855 CopyMem (
856 &DestIp,
857 &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
858 sizeof (EFI_IPv6_ADDRESS)
859 );
860 }
861
862 //
863 // Lookup SAD entry according to the spi and dest address.
864 //
865 return IpSecLookupSadBySpi (Spi, &DestIp, IpVersion);
866 }
867
868 /**
869 Validate the IP6 extension header format for both the packets we received
870 and that we will transmit.
871
872 @param[in] NextHeader The next header field in IPv6 basic header.
873 @param[in] ExtHdrs The first bye of the option.
874 @param[in] ExtHdrsLen The length of the whole option.
875 @param[out] LastHeader The pointer of NextHeader of the last extension
876 header processed by IP6.
877 @param[out] RealExtsLen The length of extension headers processed by IP6 layer.
878 This is an optional parameter that may be NULL.
879
880 @retval TRUE The option is properly formated.
881 @retval FALSE The option is malformated.
882
883 **/
884 BOOLEAN
885 IpSecIsIp6ExtsValid (
886 IN UINT8 *NextHeader,
887 IN UINT8 *ExtHdrs,
888 IN UINT32 ExtHdrsLen,
889 OUT UINT8 **LastHeader,
890 OUT UINT32 *RealExtsLen OPTIONAL
891 )
892 {
893 UINT32 Pointer;
894 UINT8 *Option;
895 UINT8 OptionLen;
896 UINT8 CountD;
897 UINT8 CountF;
898 UINT8 CountA;
899
900 if (RealExtsLen != NULL) {
901 *RealExtsLen = 0;
902 }
903
904 *LastHeader = NextHeader;
905
906 if (ExtHdrs == NULL && ExtHdrsLen == 0) {
907 return TRUE;
908 }
909
910 if ((ExtHdrs == NULL && ExtHdrsLen != 0) || (ExtHdrs != NULL && ExtHdrsLen == 0)) {
911 return FALSE;
912 }
913
914 Pointer = 0;
915 CountD = 0;
916 CountF = 0;
917 CountA = 0;
918
919 while (Pointer <= ExtHdrsLen) {
920
921 switch (*NextHeader) {
922 case IP6_HOP_BY_HOP:
923 if (Pointer != 0) {
924 return FALSE;
925 }
926
927 //
928 // Fall through
929 //
930 case IP6_DESTINATION:
931 if (*NextHeader == IP6_DESTINATION) {
932 CountD++;
933 }
934
935 if (CountD > 2) {
936 return FALSE;
937 }
938
939 NextHeader = ExtHdrs + Pointer;
940
941 Pointer++;
942 Option = ExtHdrs + Pointer;
943 OptionLen = (UINT8) ((*Option + 1) * 8 - 2);
944 Option++;
945 Pointer++;
946
947 Pointer = Pointer + OptionLen;
948 break;
949
950 case IP6_FRAGMENT:
951 if (++CountF > 1) {
952 return FALSE;
953 }
954 //
955 // RFC2402, AH header should after fragment header.
956 //
957 if (CountA > 1) {
958 return FALSE;
959 }
960
961 NextHeader = ExtHdrs + Pointer;
962 Pointer = Pointer + 8;
963 break;
964
965 case IP6_AH:
966 if (++CountA > 1) {
967 return FALSE;
968 }
969
970 Option = ExtHdrs + Pointer;
971 NextHeader = Option;
972 Option++;
973 //
974 // RFC2402, Payload length is specified in 32-bit words, minus "2".
975 //
976 OptionLen = (UINT8) ((*Option + 2) * 4);
977 Pointer = Pointer + OptionLen;
978 break;
979
980 default:
981 *LastHeader = NextHeader;
982 if (RealExtsLen != NULL) {
983 *RealExtsLen = Pointer;
984 }
985
986 return TRUE;
987 }
988 }
989
990 *LastHeader = NextHeader;
991
992 if (RealExtsLen != NULL) {
993 *RealExtsLen = Pointer;
994 }
995
996 return TRUE;
997 }
998
999 /**
1000 The actual entry to process the tunnel header and inner header for tunnel mode
1001 outbound traffic.
1002
1003 This function is the subfunction of IpSecEspInboundPacket(). It change the destination
1004 Ip address to the station address and recalculate the uplayyer's checksum.
1005
1006
1007 @param[in, out] IpHead Points to the IP header containing the ESP header
1008 to be trimed on input, and without ESP header
1009 on return.
1010 @param[in] IpPayload The decrypted Ip payload. It start from the inner
1011 header.
1012 @param[in] IpVersion The version of IP.
1013 @param[in] SadData Pointer of the relevant SAD.
1014 @param[in, out] LastHead The Last Header in IP header on return.
1015
1016 **/
1017 VOID
1018 IpSecTunnelInboundPacket (
1019 IN OUT UINT8 *IpHead,
1020 IN UINT8 *IpPayload,
1021 IN UINT8 IpVersion,
1022 IN IPSEC_SAD_DATA *SadData,
1023 IN OUT UINT8 *LastHead
1024 )
1025 {
1026 EFI_UDP_HEADER *UdpHeader;
1027 TCP_HEAD *TcpHeader;
1028 UINT16 *Checksum;
1029 UINT16 PseudoChecksum;
1030 UINT16 PacketChecksum;
1031 UINT32 OptionLen;
1032 IP6_ICMP_HEAD *Icmp6Head;
1033
1034 Checksum = NULL;
1035
1036 if (IpVersion == IP_VERSION_4) {
1037 //
1038 // Zero OutIP header use this to indicate the input packet is under
1039 // IPsec Tunnel protected.
1040 //
1041 ZeroMem (
1042 (IP4_HEAD *)IpHead,
1043 sizeof (IP4_HEAD)
1044 );
1045 CopyMem (
1046 &((IP4_HEAD *)IpPayload)->Dst,
1047 &SadData->TunnelDestAddress.v4,
1048 sizeof (EFI_IPv4_ADDRESS)
1049 );
1050
1051 //
1052 // Recalculate IpHeader Checksum
1053 //
1054 if (((IP4_HEAD *)(IpPayload))->Checksum != 0 ) {
1055 ((IP4_HEAD *)(IpPayload))->Checksum = 0;
1056 ((IP4_HEAD *)(IpPayload))->Checksum = (UINT16) (~NetblockChecksum (
1057 (UINT8 *)IpPayload,
1058 ((IP4_HEAD *)IpPayload)->HeadLen << 2
1059 ));
1060
1061
1062 }
1063
1064 //
1065 // Recalcualte PseudoChecksum
1066 //
1067 switch (((IP4_HEAD *)IpPayload)->Protocol) {
1068 case EFI_IP_PROTO_UDP :
1069 UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));
1070 Checksum = & UdpHeader->Checksum;
1071 *Checksum = 0;
1072 break;
1073
1074 case EFI_IP_PROTO_TCP:
1075 TcpHeader = (TCP_HEAD *) ((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));
1076 Checksum = &TcpHeader->Checksum;
1077 *Checksum = 0;
1078 break;
1079
1080 default:
1081 break;
1082 }
1083 PacketChecksum = NetblockChecksum (
1084 (UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2),
1085 NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)
1086 );
1087 PseudoChecksum = NetPseudoHeadChecksum (
1088 ((IP4_HEAD *)IpPayload)->Src,
1089 ((IP4_HEAD *)IpPayload)->Dst,
1090 ((IP4_HEAD *)IpPayload)->Protocol,
1091 0
1092 );
1093
1094 if (Checksum != NULL) {
1095 *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
1096 *Checksum = (UINT16) ~(NetAddChecksum (*Checksum, HTONS((UINT16)(NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)))));
1097 }
1098 }else {
1099 //
1100 // Zero OutIP header use this to indicate the input packet is under
1101 // IPsec Tunnel protected.
1102 //
1103 ZeroMem (
1104 IpHead,
1105 sizeof (EFI_IP6_HEADER)
1106 );
1107 CopyMem (
1108 &((EFI_IP6_HEADER*)IpPayload)->DestinationAddress,
1109 &SadData->TunnelDestAddress.v6,
1110 sizeof (EFI_IPv6_ADDRESS)
1111 );
1112
1113 //
1114 // Get the Extension Header and Header length.
1115 //
1116 IpSecIsIp6ExtsValid (
1117 &((EFI_IP6_HEADER *)IpPayload)->NextHeader,
1118 IpPayload + sizeof (EFI_IP6_HEADER),
1119 ((EFI_IP6_HEADER *)IpPayload)->PayloadLength,
1120 &LastHead,
1121 &OptionLen
1122 );
1123
1124 //
1125 // Recalcualte PseudoChecksum
1126 //
1127 switch (*LastHead) {
1128 case EFI_IP_PROTO_UDP:
1129 UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
1130 Checksum = &UdpHeader->Checksum;
1131 *Checksum = 0;
1132 break;
1133
1134 case EFI_IP_PROTO_TCP:
1135 TcpHeader = (TCP_HEAD *)(IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
1136 Checksum = &TcpHeader->Checksum;
1137 *Checksum = 0;
1138 break;
1139
1140 case IP6_ICMP:
1141 Icmp6Head = (IP6_ICMP_HEAD *) (IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
1142 Checksum = &Icmp6Head->Checksum;
1143 *Checksum = 0;
1144 break;
1145 }
1146 PacketChecksum = NetblockChecksum (
1147 IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen,
1148 NTOHS(((EFI_IP6_HEADER *)IpPayload)->PayloadLength) - OptionLen
1149 );
1150 PseudoChecksum = NetIp6PseudoHeadChecksum (
1151 &((EFI_IP6_HEADER *)IpPayload)->SourceAddress,
1152 &((EFI_IP6_HEADER *)IpPayload)->DestinationAddress,
1153 *LastHead,
1154 0
1155 );
1156
1157 if (Checksum != NULL) {
1158 *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
1159 *Checksum = (UINT16) ~(NetAddChecksum (
1160 *Checksum,
1161 HTONS ((UINT16)((NTOHS (((EFI_IP6_HEADER *)(IpPayload))->PayloadLength)) - OptionLen))
1162 ));
1163 }
1164 }
1165 }
1166
1167 /**
1168 The actual entry to create inner header for tunnel mode inbound traffic.
1169
1170 This function is the subfunction of IpSecEspOutboundPacket(). It create
1171 the sending packet by encrypting its payload and inserting ESP header in the orginal
1172 IP header, then return the IpHeader and IPsec protected Fragmentable.
1173
1174 @param[in, out] IpHead Points to IP header containing the orginal IP header
1175 to be processed on input, and inserted ESP header
1176 on return.
1177 @param[in] IpVersion The version of IP.
1178 @param[in] SadData The related SAD data.
1179 @param[in, out] LastHead The Last Header in IP header.
1180 @param[in] OptionsBuffer Pointer to the options buffer.
1181 @param[in] OptionsLength Length of the options buffer.
1182 @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
1183 IPsec on input, and with IPsec protected
1184 on return.
1185 @param[in] FragmentCount The number of fragments.
1186
1187 **/
1188 UINT8 *
1189 IpSecTunnelOutboundPacket (
1190 IN OUT UINT8 *IpHead,
1191 IN UINT8 IpVersion,
1192 IN IPSEC_SAD_DATA *SadData,
1193 IN OUT UINT8 *LastHead,
1194 IN VOID **OptionsBuffer,
1195 IN UINT32 *OptionsLength,
1196 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
1197 IN UINT32 *FragmentCount
1198 )
1199 {
1200 UINT8 *InnerHead;
1201 NET_BUF *Packet;
1202 UINT16 PacketChecksum;
1203 UINT16 *Checksum;
1204 UINT16 PseudoChecksum;
1205 IP6_ICMP_HEAD *IcmpHead;
1206
1207 Checksum = NULL;
1208 if (OptionsLength == NULL) {
1209 return NULL;
1210 }
1211
1212 if (IpVersion == IP_VERSION_4) {
1213 InnerHead = AllocateZeroPool (sizeof (IP4_HEAD) + *OptionsLength);
1214 if (InnerHead == NULL) {
1215 return NULL;
1216 }
1217
1218 CopyMem (
1219 InnerHead,
1220 IpHead,
1221 sizeof (IP4_HEAD)
1222 );
1223 CopyMem (
1224 InnerHead + sizeof (IP4_HEAD),
1225 *OptionsBuffer,
1226 *OptionsLength
1227 );
1228 } else {
1229 InnerHead = AllocateZeroPool (sizeof (EFI_IP6_HEADER) + *OptionsLength);
1230 if (InnerHead == NULL) {
1231 return NULL;
1232 }
1233
1234 CopyMem (
1235 InnerHead,
1236 IpHead,
1237 sizeof (EFI_IP6_HEADER)
1238 );
1239 CopyMem (
1240 InnerHead + sizeof (EFI_IP6_HEADER),
1241 *OptionsBuffer,
1242 *OptionsLength
1243 );
1244 }
1245 if (OptionsBuffer != NULL) {
1246 if (*OptionsLength != 0) {
1247
1248 *OptionsBuffer = NULL;
1249 *OptionsLength = 0;
1250 }
1251 }
1252
1253 //
1254 // 2. Reassamlbe Fragment into Packet
1255 //
1256 Packet = NetbufFromExt (
1257 (NET_FRAGMENT *)(*FragmentTable),
1258 *FragmentCount,
1259 0,
1260 0,
1261 IpSecOnRecyclePacket,
1262 NULL
1263 );
1264 if (Packet == NULL) {
1265 FreePool (InnerHead);
1266 return NULL;
1267 }
1268
1269 //
1270 // 3. Check the Last Header, if it is TCP, UDP or ICMP recalcualate its pesudo
1271 // CheckSum.
1272 //
1273 switch (*LastHead) {
1274 case EFI_IP_PROTO_UDP:
1275 Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, 0);
1276 ASSERT (Packet->Udp != NULL);
1277 Checksum = &Packet->Udp->Checksum;
1278 *Checksum = 0;
1279 break;
1280
1281 case EFI_IP_PROTO_TCP:
1282 Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, 0);
1283 ASSERT (Packet->Tcp != NULL);
1284 Checksum = &Packet->Tcp->Checksum;
1285 *Checksum = 0;
1286 break;
1287
1288 case IP6_ICMP:
1289 IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL);
1290 ASSERT (IcmpHead != NULL);
1291 Checksum = &IcmpHead->Checksum;
1292 *Checksum = 0;
1293 break;
1294
1295 default:
1296 break;
1297 }
1298
1299 PacketChecksum = NetbufChecksum (Packet);
1300
1301 if (IpVersion == IP_VERSION_4) {
1302 //
1303 // Replace the source address of Inner Header.
1304 //
1305 CopyMem (
1306 &((IP4_HEAD *)InnerHead)->Src,
1307 &SadData->SpdSelector->LocalAddress[0].Address.v4,
1308 sizeof (EFI_IPv4_ADDRESS)
1309 );
1310
1311 PacketChecksum = NetbufChecksum (Packet);
1312 PseudoChecksum = NetPseudoHeadChecksum (
1313 ((IP4_HEAD *)InnerHead)->Src,
1314 ((IP4_HEAD *)InnerHead)->Dst,
1315 *LastHead,
1316 0
1317 );
1318
1319 } else {
1320 //
1321 // Replace the source address of Inner Header.
1322 //
1323 CopyMem (
1324 &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
1325 &(SadData->SpdSelector->LocalAddress[0].Address.v6),
1326 sizeof (EFI_IPv6_ADDRESS)
1327 );
1328 PacketChecksum = NetbufChecksum (Packet);
1329 PseudoChecksum = NetIp6PseudoHeadChecksum (
1330 &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
1331 &((EFI_IP6_HEADER *)InnerHead)->DestinationAddress,
1332 *LastHead,
1333 0
1334 );
1335
1336 }
1337 if (Checksum != NULL) {
1338 *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
1339 *Checksum = (UINT16) ~(NetAddChecksum ((UINT16)*Checksum, HTONS ((UINT16) Packet->TotalSize)));
1340 }
1341
1342 if (Packet != NULL) {
1343 NetbufFree (Packet);
1344 }
1345 return InnerHead;
1346 }
1347
1348 /**
1349 The actual entry to relative function processes the inbound traffic of ESP header.
1350
1351 This function is the subfunction of IpSecProtectInboundPacket(). It checks the
1352 received packet security property and trim the ESP header and then returns without
1353 an IPsec protected IP Header and FramgmentTable.
1354
1355 @param[in] IpVersion The version of IP.
1356 @param[in, out] IpHead Points to the IP header containing the ESP header
1357 to be trimed on input, and without ESP header
1358 on return.
1359 @param[out] LastHead The Last Header in IP header on return.
1360 @param[in, out] OptionsBuffer Pointer to the options buffer.
1361 @param[in, out] OptionsLength Length of the options buffer.
1362 @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec
1363 protected on input, and without IPsec protected
1364 on return.
1365 @param[in, out] FragmentCount The number of fragments.
1366 @param[out] SpdSelector Pointer to contain the address of SPD selector on return.
1367 @param[out] RecycleEvent The event for recycling of resources.
1368
1369 @retval EFI_SUCCESS The operation was successful.
1370 @retval EFI_ACCESS_DENIED One or more following conditions is TRUE:
1371 - ESP header was not found or mal-format.
1372 - The related SAD entry was not found.
1373 - The related SAD entry does not support the ESP protocol.
1374 @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.
1375
1376 **/
1377 EFI_STATUS
1378 IpSecEspInboundPacket (
1379 IN UINT8 IpVersion,
1380 IN OUT VOID *IpHead,
1381 OUT UINT8 *LastHead,
1382 IN OUT VOID **OptionsBuffer,
1383 IN OUT UINT32 *OptionsLength,
1384 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
1385 IN OUT UINT32 *FragmentCount,
1386 OUT EFI_IPSEC_SPD_SELECTOR **SpdSelector,
1387 OUT EFI_EVENT *RecycleEvent
1388 )
1389 {
1390 EFI_STATUS Status;
1391 NET_BUF *Payload;
1392 UINTN EspSize;
1393 UINTN IvSize;
1394 UINTN BlockSize;
1395 UINTN MiscSize;
1396 UINTN PlainPayloadSize;
1397 UINTN PaddingSize;
1398 UINTN IcvSize;
1399 UINT8 *ProcessBuffer;
1400 EFI_ESP_HEADER *EspHeader;
1401 EFI_ESP_TAIL *EspTail;
1402 EFI_IPSEC_SA_ID *SaId;
1403 IPSEC_SAD_DATA *SadData;
1404 IPSEC_SAD_ENTRY *SadEntry;
1405 IPSEC_RECYCLE_CONTEXT *RecycleContext;
1406 UINT8 NextHeader;
1407 UINT16 IpSecHeadSize;
1408 UINT8 *InnerHead;
1409
1410 Status = EFI_SUCCESS;
1411 Payload = NULL;
1412 ProcessBuffer = NULL;
1413 RecycleContext = NULL;
1414 *RecycleEvent = NULL;
1415 PlainPayloadSize = 0;
1416 NextHeader = 0;
1417
1418 //
1419 // Build netbuf from fragment table first.
1420 //
1421 Payload = NetbufFromExt (
1422 (NET_FRAGMENT *) *FragmentTable,
1423 *FragmentCount,
1424 0,
1425 sizeof (EFI_ESP_HEADER),
1426 IpSecOnRecyclePacket,
1427 NULL
1428 );
1429 if (Payload == NULL) {
1430 Status = EFI_OUT_OF_RESOURCES;
1431 goto ON_EXIT;
1432 }
1433
1434 //
1435 // Get the esp size and esp header from netbuf.
1436 //
1437 EspSize = Payload->TotalSize;
1438 EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL);
1439
1440 if (EspHeader == NULL) {
1441 Status = EFI_ACCESS_DENIED;
1442 goto ON_EXIT;
1443 }
1444
1445 //
1446 // Parse destination address from ip header and found the related SAD Entry.
1447 //
1448 SadEntry = IpSecFoundSadFromInboundPacket (
1449 IpHead,
1450 IpVersion,
1451 NTOHL (EspHeader->Spi)
1452 );
1453
1454 if (SadEntry == NULL) {
1455 Status = EFI_ACCESS_DENIED;
1456 goto ON_EXIT;
1457 }
1458
1459 SaId = SadEntry->Id;
1460 SadData = SadEntry->Data;
1461
1462 //
1463 // Only support esp protocol currently.
1464 //
1465 if (SaId->Proto != EfiIPsecESP) {
1466 Status = EFI_ACCESS_DENIED;
1467 goto ON_EXIT;
1468 }
1469
1470 if (!SadData->ManualSet) {
1471 //
1472 // TODO: Check SA lifetime and sequence number
1473 //
1474 }
1475
1476 //
1477 // Allocate buffer for decryption and authentication.
1478 //
1479 ProcessBuffer = AllocateZeroPool (EspSize);
1480 if (ProcessBuffer == NULL) {
1481 Status = EFI_OUT_OF_RESOURCES;
1482 goto ON_EXIT;
1483 }
1484
1485 NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer);
1486
1487 //
1488 // Get the IcvSize for authentication and BlockSize/IvSize for Decryption.
1489 //
1490 IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
1491 IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
1492 BlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
1493
1494 //
1495 // Make sure the ESP packet is not mal-formt.
1496 // 1. Check whether the Espsize is larger than ESP header + IvSize + EspTail + IcvSize.
1497 // 2. Check whether the left payload size is multiple of IvSize.
1498 //
1499 MiscSize = sizeof (EFI_ESP_HEADER) + IvSize + IcvSize;
1500 if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL))) {
1501 Status = EFI_ACCESS_DENIED;
1502 goto ON_EXIT;
1503 }
1504 if ((EspSize - MiscSize) % BlockSize != 0) {
1505 Status = EFI_ACCESS_DENIED;
1506 goto ON_EXIT;
1507 }
1508
1509 //
1510 // Authenticate the ESP packet.
1511 //
1512 if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
1513 Status = IpSecEspAuthVerifyPayload (
1514 ProcessBuffer,
1515 EspSize,
1516 SadEntry,
1517 IcvSize
1518 );
1519 if (EFI_ERROR (Status)) {
1520 goto ON_EXIT;
1521 }
1522 }
1523 //
1524 // Decrypt the payload by the SAD entry if it has decrypt key.
1525 //
1526 if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
1527 Status = IpSecCryptoIoDecrypt (
1528 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
1529 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
1530 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
1531 ProcessBuffer + sizeof (EFI_ESP_HEADER),
1532 ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize,
1533 EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize,
1534 ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize
1535 );
1536 if (EFI_ERROR (Status)) {
1537 goto ON_EXIT;
1538 }
1539 }
1540
1541 //
1542 // Parse EspTail and compute the plain payload size.
1543 //
1544 EspTail = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL));
1545 PaddingSize = EspTail->PaddingLength;
1546 NextHeader = EspTail->NextHeader;
1547
1548 if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL) + PaddingSize)) {
1549 Status = EFI_ACCESS_DENIED;
1550 goto ON_EXIT;
1551 }
1552 PlainPayloadSize = EspSize - MiscSize - sizeof (EFI_ESP_TAIL) - PaddingSize;
1553
1554 //
1555 // TODO: handle anti-replay window
1556 //
1557 //
1558 // Decryption and authentication with esp has been done, so it's time to
1559 // reload the new packet, create recycle event and fixup ip header.
1560 //
1561 RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
1562 if (RecycleContext == NULL) {
1563 Status = EFI_OUT_OF_RESOURCES;
1564 goto ON_EXIT;
1565 }
1566
1567 Status = gBS->CreateEvent (
1568 EVT_NOTIFY_SIGNAL,
1569 TPL_NOTIFY,
1570 IpSecRecycleCallback,
1571 RecycleContext,
1572 RecycleEvent
1573 );
1574 if (EFI_ERROR (Status)) {
1575 goto ON_EXIT;
1576 }
1577
1578 //
1579 // The caller will take responsible to handle the original fragment table
1580 //
1581 *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
1582 if (*FragmentTable == NULL) {
1583 Status = EFI_OUT_OF_RESOURCES;
1584 goto ON_EXIT;
1585 }
1586
1587 RecycleContext->PayloadBuffer = ProcessBuffer;
1588 RecycleContext->FragmentTable = *FragmentTable;
1589
1590 //
1591 // If Tunnel, recalculate upper-layyer PesudoCheckSum and trim the out
1592 //
1593 if (SadData->Mode == EfiIPsecTunnel) {
1594 InnerHead = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
1595 IpSecTunnelInboundPacket (
1596 IpHead,
1597 InnerHead,
1598 IpVersion,
1599 SadData,
1600 LastHead
1601 );
1602
1603 if (IpVersion == IP_VERSION_4) {
1604 (*FragmentTable)[0].FragmentBuffer = InnerHead ;
1605 (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;
1606
1607 }else {
1608 (*FragmentTable)[0].FragmentBuffer = InnerHead;
1609 (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;
1610 }
1611 } else {
1612 (*FragmentTable)[0].FragmentBuffer = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
1613 (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;
1614 }
1615
1616 *FragmentCount = 1;
1617
1618 //
1619 // Update the total length field in ip header since processed by esp.
1620 //
1621 if (SadData->Mode != EfiIPsecTunnel) {
1622 if (IpVersion == IP_VERSION_4) {
1623 ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + PlainPayloadSize));
1624 } else {
1625 IpSecHeadSize = IpSecGetPlainExtHeadSize (IpHead, LastHead);
1626 ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize));
1627 }
1628 //
1629 // Update the next layer field in ip header since esp header inserted.
1630 //
1631 *LastHead = NextHeader;
1632 }
1633
1634
1635 //
1636 // Update the SPD association of the SAD entry.
1637 //
1638 *SpdSelector = SadData->SpdSelector;
1639
1640 ON_EXIT:
1641 if (Payload != NULL) {
1642 NetbufFree (Payload);
1643 }
1644
1645 if (EFI_ERROR (Status)) {
1646 if (ProcessBuffer != NULL) {
1647 FreePool (ProcessBuffer);
1648 }
1649
1650 if (RecycleContext != NULL) {
1651 FreePool (RecycleContext);
1652 }
1653
1654 if (*RecycleEvent != NULL) {
1655 gBS->CloseEvent (*RecycleEvent);
1656 }
1657 }
1658
1659 return Status;
1660 }
1661
1662 /**
1663 The actual entry to the relative function processes the output traffic using the ESP protocol.
1664
1665 This function is the subfunction of IpSecProtectOutboundPacket(). It protected
1666 the sending packet by encrypting its payload and inserting ESP header in the orginal
1667 IP header, then return the IpHeader and IPsec protected Fragmentable.
1668
1669 @param[in] IpVersion The version of IP.
1670 @param[in, out] IpHead Points to IP header containing the orginal IP header
1671 to be processed on input, and inserted ESP header
1672 on return.
1673 @param[in, out] LastHead The Last Header in IP header.
1674 @param[in, out] OptionsBuffer Pointer to the options buffer.
1675 @param[in, out] OptionsLength Length of the options buffer.
1676 @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
1677 IPsec on input, and with IPsec protected
1678 on return.
1679 @param[in, out] FragmentCount The number of fragments.
1680 @param[in] SadEntry The related SAD entry.
1681 @param[out] RecycleEvent The event for recycling of resources.
1682
1683 @retval EFI_SUCCESS The operation was successful.
1684 @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated.
1685
1686 **/
1687 EFI_STATUS
1688 IpSecEspOutboundPacket (
1689 IN UINT8 IpVersion,
1690 IN OUT VOID *IpHead,
1691 IN OUT UINT8 *LastHead,
1692 IN OUT VOID **OptionsBuffer,
1693 IN OUT UINT32 *OptionsLength,
1694 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
1695 IN OUT UINT32 *FragmentCount,
1696 IN IPSEC_SAD_ENTRY *SadEntry,
1697 OUT EFI_EVENT *RecycleEvent
1698 )
1699 {
1700 EFI_STATUS Status;
1701 UINTN Index;
1702 EFI_IPSEC_SA_ID *SaId;
1703 IPSEC_SAD_DATA *SadData;
1704 IPSEC_RECYCLE_CONTEXT *RecycleContext;
1705 UINT8 *ProcessBuffer;
1706 UINTN BytesCopied;
1707 INTN EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4
1708 UINTN EspSize; // Total size of esp wrapped ip payload
1709 UINTN IvSize; // Size of IV, optional, might be 0
1710 UINTN PlainPayloadSize;// Original IP payload size
1711 UINTN PaddingSize; // Size of padding
1712 UINTN EncryptSize; // Size of data to be encrypted, start after IV and
1713 // stop before ICV
1714 UINTN IcvSize; // Size of ICV, optional, might be 0
1715 UINT8 *RestOfPayload; // Start of Payload after IV
1716 UINT8 *Padding; // Start address of padding
1717 EFI_ESP_HEADER *EspHeader; // Start address of ESP frame
1718 EFI_ESP_TAIL *EspTail; // Address behind padding
1719 UINT8 *InnerHead;
1720 HASH_DATA_FRAGMENT HashFragment[1];
1721
1722 Status = EFI_ACCESS_DENIED;
1723 SaId = SadEntry->Id;
1724 SadData = SadEntry->Data;
1725 ProcessBuffer = NULL;
1726 RecycleContext = NULL;
1727 *RecycleEvent = NULL;
1728 InnerHead = NULL;
1729
1730 if (!SadData->ManualSet &&
1731 SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL &&
1732 SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL
1733 ) {
1734 //
1735 // Invalid manual SAD entry configuration.
1736 //
1737 goto ON_EXIT;
1738 }
1739
1740 //
1741 // Create OutHeader according to Inner Header
1742 //
1743 if (SadData->Mode == EfiIPsecTunnel) {
1744 InnerHead = IpSecTunnelOutboundPacket (
1745 IpHead,
1746 IpVersion,
1747 SadData,
1748 LastHead,
1749 OptionsBuffer,
1750 OptionsLength,
1751 FragmentTable,
1752 FragmentCount
1753 );
1754
1755 if (InnerHead == NULL) {
1756 return EFI_INVALID_PARAMETER;
1757 }
1758
1759 }
1760
1761 //
1762 // Calculate enctrypt block size, need iv by default and 4 bytes alignment.
1763 //
1764 EncryptBlockSize = 4;
1765
1766 if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
1767 EncryptBlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
1768
1769 if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) {
1770 goto ON_EXIT;
1771 }
1772 }
1773
1774 //
1775 // Calculate the plain payload size according to the fragment table.
1776 //
1777 PlainPayloadSize = 0;
1778 for (Index = 0; Index < *FragmentCount; Index++) {
1779 PlainPayloadSize += (*FragmentTable)[Index].FragmentLength;
1780 }
1781
1782 //
1783 // Add IPHeader size for Tunnel Mode
1784 //
1785 if (SadData->Mode == EfiIPsecTunnel) {
1786 if (IpVersion == IP_VERSION_4) {
1787 PlainPayloadSize += sizeof (IP4_HEAD);
1788 } else {
1789 PlainPayloadSize += sizeof (EFI_IP6_HEADER);
1790 }
1791 //
1792 // OPtions should be encryption into it
1793 //
1794 PlainPayloadSize += *OptionsLength;
1795 }
1796
1797
1798 //
1799 // Calculate icv size, optional by default and 4 bytes alignment.
1800 //
1801 IcvSize = 0;
1802 if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
1803 IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
1804 if (IcvSize % 4 != 0) {
1805 goto ON_EXIT;
1806 }
1807 }
1808
1809 //
1810 // Calcuate the total size of esp wrapped ip payload.
1811 //
1812 IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
1813 EncryptSize = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize;
1814 PaddingSize = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL);
1815 EspSize = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize;
1816
1817 ProcessBuffer = AllocateZeroPool (EspSize);
1818 if (ProcessBuffer == NULL) {
1819 Status = EFI_OUT_OF_RESOURCES;
1820 goto ON_EXIT;
1821 }
1822
1823 //
1824 // Calculate esp header and esp tail including header, payload and padding.
1825 //
1826 EspHeader = (EFI_ESP_HEADER *) ProcessBuffer;
1827 RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize;
1828 Padding = RestOfPayload + PlainPayloadSize;
1829 EspTail = (EFI_ESP_TAIL *) (Padding + PaddingSize);
1830
1831 //
1832 // Fill the sn and spi fields in esp header.
1833 //
1834 EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1);
1835 //EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber);
1836 EspHeader->Spi = HTONL (SaId->Spi);
1837
1838 //
1839 // Copy the rest of payload (after iv) from the original fragment buffer.
1840 //
1841 BytesCopied = 0;
1842
1843 //
1844 // For Tunnel Mode
1845 //
1846 if (SadData->Mode == EfiIPsecTunnel) {
1847 if (IpVersion == IP_VERSION_4) {
1848 //
1849 // HeadLen, Total Length
1850 //
1851 ((IP4_HEAD *)InnerHead)->HeadLen = (UINT8) ((sizeof (IP4_HEAD) + *OptionsLength) >> 2);
1852 ((IP4_HEAD *)InnerHead)->TotalLen = HTONS ((UINT16) PlainPayloadSize);
1853 ((IP4_HEAD *)InnerHead)->Checksum = 0;
1854 ((IP4_HEAD *)InnerHead)->Checksum = (UINT16) (~NetblockChecksum (
1855 (UINT8 *)InnerHead,
1856 sizeof(IP4_HEAD)
1857 ));
1858 CopyMem (
1859 RestOfPayload + BytesCopied,
1860 InnerHead,
1861 sizeof (IP4_HEAD) + *OptionsLength
1862 );
1863 BytesCopied += sizeof (IP4_HEAD) + *OptionsLength;
1864
1865 } else {
1866 ((EFI_IP6_HEADER *)InnerHead)->PayloadLength = HTONS ((UINT16) (PlainPayloadSize - sizeof (EFI_IP6_HEADER)));
1867 CopyMem (
1868 RestOfPayload + BytesCopied,
1869 InnerHead,
1870 sizeof (EFI_IP6_HEADER) + *OptionsLength
1871 );
1872 BytesCopied += sizeof (EFI_IP6_HEADER) + *OptionsLength;
1873 }
1874 }
1875
1876 for (Index = 0; Index < *FragmentCount; Index++) {
1877 CopyMem (
1878 (RestOfPayload + BytesCopied),
1879 (*FragmentTable)[Index].FragmentBuffer,
1880 (*FragmentTable)[Index].FragmentLength
1881 );
1882 BytesCopied += (*FragmentTable)[Index].FragmentLength;
1883 }
1884 //
1885 // Fill the padding buffer by natural number sequence.
1886 //
1887 for (Index = 0; Index < PaddingSize; Index++) {
1888 Padding[Index] = (UINT8) (Index + 1);
1889 }
1890 //
1891 // Fill the padding length and next header fields in esp tail.
1892 //
1893 EspTail->PaddingLength = (UINT8) PaddingSize;
1894 EspTail->NextHeader = *LastHead;
1895
1896 //
1897 // Fill the next header for Tunnel mode.
1898 //
1899 if (SadData->Mode == EfiIPsecTunnel) {
1900 if (IpVersion == IP_VERSION_4) {
1901 EspTail->NextHeader = 4;
1902 } else {
1903 EspTail->NextHeader = 41;
1904 }
1905 }
1906
1907 //
1908 // Generate iv at random by crypt library.
1909 //
1910 Status = IpSecGenerateIv (
1911 (UINT8 *) (EspHeader + 1),
1912 IvSize
1913 );
1914
1915
1916 if (EFI_ERROR (Status)) {
1917 goto ON_EXIT;
1918 }
1919
1920 //
1921 // Encryption the payload (after iv) by the SAD entry if has encrypt key.
1922 //
1923 if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
1924 Status = IpSecCryptoIoEncrypt (
1925 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
1926 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
1927 SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
1928 (UINT8 *)(EspHeader + 1),
1929 RestOfPayload,
1930 EncryptSize,
1931 RestOfPayload
1932 );
1933
1934 if (EFI_ERROR (Status)) {
1935 goto ON_EXIT;
1936 }
1937 }
1938
1939 //
1940 // Authenticate the esp wrapped buffer by the SAD entry if it has auth key.
1941 //
1942 if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
1943
1944 HashFragment[0].Data = ProcessBuffer;
1945 HashFragment[0].DataSize = EspSize - IcvSize;
1946 Status = IpSecCryptoIoHmac (
1947 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,
1948 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
1949 SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,
1950 HashFragment,
1951 1,
1952 ProcessBuffer + EspSize - IcvSize,
1953 IcvSize
1954 );
1955 if (EFI_ERROR (Status)) {
1956 goto ON_EXIT;
1957 }
1958 }
1959
1960 //
1961 // Encryption and authentication with esp has been done, so it's time to
1962 // reload the new packet, create recycle event and fixup ip header.
1963 //
1964 RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
1965 if (RecycleContext == NULL) {
1966 Status = EFI_OUT_OF_RESOURCES;
1967 goto ON_EXIT;
1968 }
1969
1970 Status = gBS->CreateEvent (
1971 EVT_NOTIFY_SIGNAL,
1972 TPL_NOTIFY,
1973 IpSecRecycleCallback,
1974 RecycleContext,
1975 RecycleEvent
1976 );
1977 if (EFI_ERROR (Status)) {
1978 goto ON_EXIT;
1979 }
1980 //
1981 // Caller take responsible to handle the original fragment table.
1982 //
1983 *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
1984 if (*FragmentTable == NULL) {
1985 Status = EFI_OUT_OF_RESOURCES;
1986 goto ON_EXIT;
1987 }
1988
1989 RecycleContext->FragmentTable = *FragmentTable;
1990 RecycleContext->PayloadBuffer = ProcessBuffer;
1991 (*FragmentTable)[0].FragmentBuffer = ProcessBuffer;
1992 (*FragmentTable)[0].FragmentLength = (UINT32) EspSize;
1993 *FragmentCount = 1;
1994
1995 //
1996 // Update the total length field in ip header since processed by esp.
1997 //
1998 if (IpVersion == IP_VERSION_4) {
1999 ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + EspSize));
2000 } else {
2001 ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize);
2002 }
2003
2004 //
2005 // If tunnel mode, it should change the outer Ip header with tunnel source address
2006 // and destination tunnel address.
2007 //
2008 if (SadData->Mode == EfiIPsecTunnel) {
2009 if (IpVersion == IP_VERSION_4) {
2010 CopyMem (
2011 &((IP4_HEAD *) IpHead)->Src,
2012 &SadData->TunnelSourceAddress.v4,
2013 sizeof (EFI_IPv4_ADDRESS)
2014 );
2015 CopyMem (
2016 &((IP4_HEAD *) IpHead)->Dst,
2017 &SadData->TunnelDestAddress.v4,
2018 sizeof (EFI_IPv4_ADDRESS)
2019 );
2020 } else {
2021 CopyMem (
2022 &((EFI_IP6_HEADER *) IpHead)->SourceAddress,
2023 &SadData->TunnelSourceAddress.v6,
2024 sizeof (EFI_IPv6_ADDRESS)
2025 );
2026 CopyMem (
2027 &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
2028 &SadData->TunnelDestAddress.v6,
2029 sizeof (EFI_IPv6_ADDRESS)
2030 );
2031 }
2032 }
2033
2034 //
2035 // Update the next layer field in ip header since esp header inserted.
2036 //
2037 *LastHead = IPSEC_ESP_PROTOCOL;
2038
2039 //
2040 // Increase the sn number in SAD entry according to rfc4303.
2041 //
2042 SadData->SequenceNumber++;
2043
2044 ON_EXIT:
2045 if (EFI_ERROR (Status)) {
2046 if (ProcessBuffer != NULL) {
2047 FreePool (ProcessBuffer);
2048 }
2049
2050 if (RecycleContext != NULL) {
2051 FreePool (RecycleContext);
2052 }
2053
2054 if (*RecycleEvent != NULL) {
2055 gBS->CloseEvent (*RecycleEvent);
2056 }
2057 }
2058
2059 return Status;
2060 }
2061
2062 /**
2063 This function processes the inbound traffic with IPsec.
2064
2065 It checks the received packet security property, trims the ESP/AH header, and then
2066 returns without an IPsec protected IP Header and FragmentTable.
2067
2068 @param[in] IpVersion The version of IP.
2069 @param[in, out] IpHead Points to IP header containing the ESP/AH header
2070 to be trimed on input, and without ESP/AH header
2071 on return.
2072 @param[in, out] LastHead The Last Header in IP header on return.
2073 @param[in, out] OptionsBuffer Pointer to the options buffer.
2074 @param[in, out] OptionsLength Length of the options buffer.
2075 @param[in, out] FragmentTable Pointer to a list of fragments in form of IPsec
2076 protected on input, and without IPsec protected
2077 on return.
2078 @param[in, out] FragmentCount The number of fragments.
2079 @param[out] SpdEntry Pointer to contain the address of SPD entry on return.
2080 @param[out] RecycleEvent The event for recycling of resources.
2081
2082 @retval EFI_SUCCESS The operation was successful.
2083 @retval EFI_UNSUPPORTED The IPSEC protocol is not supported.
2084
2085 **/
2086 EFI_STATUS
2087 IpSecProtectInboundPacket (
2088 IN UINT8 IpVersion,
2089 IN OUT VOID *IpHead,
2090 IN OUT UINT8 *LastHead,
2091 IN OUT VOID **OptionsBuffer,
2092 IN OUT UINT32 *OptionsLength,
2093 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
2094 IN OUT UINT32 *FragmentCount,
2095 OUT EFI_IPSEC_SPD_SELECTOR **SpdEntry,
2096 OUT EFI_EVENT *RecycleEvent
2097 )
2098 {
2099 if (*LastHead == IPSEC_ESP_PROTOCOL) {
2100 //
2101 // Process the esp ipsec header of the inbound traffic.
2102 //
2103 return IpSecEspInboundPacket (
2104 IpVersion,
2105 IpHead,
2106 LastHead,
2107 OptionsBuffer,
2108 OptionsLength,
2109 FragmentTable,
2110 FragmentCount,
2111 SpdEntry,
2112 RecycleEvent
2113 );
2114 }
2115 //
2116 // The other protocols are not supported.
2117 //
2118 return EFI_UNSUPPORTED;
2119 }
2120
2121 /**
2122 This fucntion processes the output traffic with IPsec.
2123
2124 It protected the sending packet by encrypting it payload and inserting ESP/AH header
2125 in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable.
2126
2127 @param[in] IpVersion The version of IP.
2128 @param[in, out] IpHead Point to IP header containing the orginal IP header
2129 to be processed on input, and inserted ESP/AH header
2130 on return.
2131 @param[in, out] LastHead The Last Header in IP header.
2132 @param[in, out] OptionsBuffer Pointer to the options buffer.
2133 @param[in, out] OptionsLength Length of the options buffer.
2134 @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
2135 IPsec on input, and with IPsec protected
2136 on return.
2137 @param[in, out] FragmentCount Number of fragments.
2138 @param[in] SadEntry Related SAD entry.
2139 @param[out] RecycleEvent Event for recycling of resources.
2140
2141 @retval EFI_SUCCESS The operation is successful.
2142 @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported.
2143
2144 **/
2145 EFI_STATUS
2146 IpSecProtectOutboundPacket (
2147 IN UINT8 IpVersion,
2148 IN OUT VOID *IpHead,
2149 IN OUT UINT8 *LastHead,
2150 IN OUT VOID **OptionsBuffer,
2151 IN OUT UINT32 *OptionsLength,
2152 IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
2153 IN OUT UINT32 *FragmentCount,
2154 IN IPSEC_SAD_ENTRY *SadEntry,
2155 OUT EFI_EVENT *RecycleEvent
2156 )
2157 {
2158 if (SadEntry->Id->Proto == EfiIPsecESP) {
2159 //
2160 // Process the esp ipsec header of the outbound traffic.
2161 //
2162 return IpSecEspOutboundPacket (
2163 IpVersion,
2164 IpHead,
2165 LastHead,
2166 OptionsBuffer,
2167 OptionsLength,
2168 FragmentTable,
2169 FragmentCount,
2170 SadEntry,
2171 RecycleEvent
2172 );
2173 }
2174 //
2175 // The other protocols are not supported.
2176 //
2177 return EFI_UNSUPPORTED;
2178 }