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