2 The implementation of IPsec.
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
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.
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.
16 #include "IpSecImpl.h"
17 #include "IkeService.h"
18 #include "IpSecDebug.h"
19 #include "IpSecCryptIo.h"
20 #include "IpSecConfigImpl.h"
23 Check if the specified Address is the Valid Address Range.
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
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.
34 @retval TRUE The address is a vaild address range.
35 @retval FALSE The address is not a vaild address range.
39 IpSecValidAddressRange (
41 IN EFI_IP_ADDRESS
*Address
,
50 EFI_IP_ADDRESS ZeroAddr
;
52 if (PrefixLength
== 0) {
56 AddrLen
= (UINT8
) ((IpVersion
== IP_VERSION_4
) ? 32 : 128);
58 if (AddrLen
<= PrefixLength
) {
62 Div
= (UINT8
) (PrefixLength
/ 8);
63 Mod
= (UINT8
) (PrefixLength
% 8);
64 Addr
= (UINT8
*) Address
;
65 ZeroMem (&ZeroAddr
, sizeof (EFI_IP_ADDRESS
));
68 // Check whether the mod part of host scope is zero or not.
71 Mask
= (UINT8
) (0xFF << (8 - Mod
));
73 if ((Addr
[Div
] | Mask
) != Mask
) {
80 // Check whether the div part of host scope is zero or not.
85 sizeof (EFI_IP_ADDRESS
) - Div
94 Extrct the Address Range from a Address.
96 This function keep the prefix address and zero other part address.
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.
104 IpSecExtractAddressRange (
105 IN EFI_IP_ADDRESS
*Address
,
106 IN UINT8 PrefixLength
,
107 OUT EFI_IP_ADDRESS
*Range
115 if (PrefixLength
== 0) {
119 Div
= (UINT8
) (PrefixLength
/ 8);
120 Mod
= (UINT8
) (PrefixLength
% 8);
121 Addr
= (UINT8
*) Range
;
123 CopyMem (Range
, Address
, sizeof (EFI_IP_ADDRESS
));
126 // Zero the mod part of host scope.
129 Mask
= (UINT8
) (0xFF << (8 - Mod
));
130 Addr
[Div
] = (UINT8
) (Addr
[Div
] & Mask
);
134 // Zero the div part of host scope.
136 ZeroMem (&Addr
[Div
], sizeof (EFI_IP_ADDRESS
) - Div
);
141 Checks if the IP Address in the address range of AddressInfos specified.
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.
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.
154 IpSecMatchIpAddress (
156 IN EFI_IP_ADDRESS
*IpAddr
,
157 IN EFI_IP_ADDRESS_INFO
*AddressInfo
,
158 IN UINT32 AddressCount
161 EFI_IP_ADDRESS Range
;
167 for (Index
= 0; Index
< AddressCount
; Index
++) {
169 // Check whether the target address is in the address range
170 // if it's a valid range of address.
172 if (IpSecValidAddressRange (
174 &AddressInfo
[Index
].Address
,
175 AddressInfo
[Index
].PrefixLength
178 // Get the range of the target address belongs to.
180 ZeroMem (&Range
, sizeof (EFI_IP_ADDRESS
));
181 IpSecExtractAddressRange (
183 AddressInfo
[Index
].PrefixLength
,
189 &AddressInfo
[Index
].Address
,
190 sizeof (EFI_IP_ADDRESS
)
193 // The target address is in the address range.
202 &AddressInfo
[Index
].Address
,
203 sizeof (EFI_IP_ADDRESS
)
206 // The target address is exact same as the address.
216 Check if the specified Protocol and Prot is supported by the specified SPD Entry.
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.
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.
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.
233 IpSecMatchNextLayerProtocol (
236 IN UINT16 SpdProtocol
,
237 IN UINT16 SpdLocalPort
,
238 IN UINT16 SpdRemotePort
,
239 IN BOOLEAN IsOutbound
244 if (SpdProtocol
== EFI_IPSEC_ANY_PROTOCOL
) {
250 if (SpdProtocol
== Protocol
) {
252 case EFI_IP_PROTO_UDP
:
253 case EFI_IP_PROTO_TCP
:
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.
259 IsMatch
= (BOOLEAN
) (SpdLocalPort
== 0 && SpdRemotePort
== 0);
260 IsMatch
= (BOOLEAN
) (IsMatch
||
263 NTOHS (((EFI_UDP_HEADER
*) IpPayload
)->SrcPort
) == SpdLocalPort
&&
264 NTOHS (((EFI_UDP_HEADER
*) IpPayload
)->DstPort
) == SpdRemotePort
268 IsMatch
= (BOOLEAN
) (IsMatch
||
271 NTOHS (((EFI_UDP_HEADER
*) IpPayload
)->DstPort
) == SpdLocalPort
&&
272 NTOHS (((EFI_UDP_HEADER
*) IpPayload
)->SrcPort
) == SpdRemotePort
277 case EFI_IP_PROTO_ICMP
:
279 // For icmpv4, type code is replaced with local port and remote port,
280 // and (0, 0) means no need to check.
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
292 // For icmpv6, type code is replaced with local port and remote port,
293 // and (0, 0) means no need to check.
295 IsMatch
= (BOOLEAN
) (SpdLocalPort
== 0 && SpdRemotePort
== 0);
297 IsMatch
= (BOOLEAN
) (IsMatch
||
298 (BOOLEAN
) (((IP6_ICMP_HEAD
*) IpPayload
)->Type
== SpdLocalPort
&&
299 ((IP6_ICMP_HEAD
*) IpPayload
)->Code
== SpdRemotePort
314 Find the SAD through a specified SPD's SAD list.
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.
320 @return The pointer to a certain SAD entry.
324 IpSecLookupSadBySpd (
325 IN LIST_ENTRY
*SadList
,
326 IN EFI_IP_ADDRESS
*DestAddress
,
331 IPSEC_SAD_ENTRY
*SadEntry
;
333 NET_LIST_FOR_EACH (Entry
, SadList
) {
335 SadEntry
= IPSEC_SAD_ENTRY_FROM_SPD (Entry
);
337 // Find the right SAD entry which contains the appointed dest address.
339 if (IpSecMatchIpAddress (
342 SadEntry
->Data
->SpdSelector
->RemoteAddress
,
343 SadEntry
->Data
->SpdSelector
->RemoteAddressCount
353 Find the SAD through whole SAD list.
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.
359 @return the pointer to a certain SAD entry.
363 IpSecLookupSadBySpi (
365 IN EFI_IP_ADDRESS
*DestAddress
,
371 IPSEC_SAD_ENTRY
*SadEntry
;
373 SadList
= &mConfigData
[IPsecConfigDataTypeSad
];
375 NET_LIST_FOR_EACH (Entry
, SadList
) {
377 SadEntry
= IPSEC_SAD_ENTRY_FROM_LIST (Entry
);
380 // Find the right SAD entry which contain the appointed spi and dest addr.
382 if (SadEntry
->Id
->Spi
== Spi
) {
383 if (SadEntry
->Data
->Mode
== EfiIPsecTunnel
) {
386 &SadEntry
->Data
->TunnelDestAddress
,
387 sizeof (EFI_IP_ADDRESS
)
392 if (SadEntry
->Data
->SpdSelector
!= NULL
&&
393 IpSecMatchIpAddress (
396 SadEntry
->Data
->SpdSelector
->RemoteAddress
,
397 SadEntry
->Data
->SpdSelector
->RemoteAddressCount
409 Look up if there is existing SAD entry for specified IP packet sending.
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.
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.
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.
434 IpSecLookupSadEntry (
435 IN IPSEC_PRIVATE_DATA
*Private
,
436 IN EFI_HANDLE NicHandle
,
440 IN UINT8 OldLastHead
,
441 IN IPSEC_SPD_ENTRY
*SpdEntry
,
442 OUT IPSEC_SAD_ENTRY
**SadEntry
445 IKE_UDP_SERVICE
*UdpService
;
446 IPSEC_SAD_ENTRY
*Entry
;
447 IPSEC_SAD_DATA
*Data
;
448 EFI_IP_ADDRESS DestIp
;
452 UdpService
= IkeLookupUdp (Private
, NicHandle
, IpVersion
);
454 if (UdpService
== NULL
) {
455 return EFI_DEVICE_ERROR
;
458 // Parse the destination address from ip header.
460 ZeroMem (&DestIp
, sizeof (EFI_IP_ADDRESS
));
461 if (IpVersion
== IP_VERSION_4
) {
464 &((IP4_HEAD
*) IpHead
)->Dst
,
470 &((EFI_IP6_HEADER
*) IpHead
)->DestinationAddress
,
471 sizeof (EFI_IP_ADDRESS
)
476 // Find the SAD entry in the spd.sas list according to the dest address.
478 Entry
= IpSecLookupSadBySpd (&SpdEntry
->Data
->Sas
, &DestIp
, IpVersion
);
482 if (OldLastHead
!= IP6_ICMP
||
483 (OldLastHead
== IP6_ICMP
&& *IpPayload
== ICMP_V6_ECHO_REQUEST
)
486 // Start ike negotiation process except the request packet of ping.
488 if (SpdEntry
->Data
->ProcessingPolicy
->Mode
== EfiIPsecTunnel
) {
492 &SpdEntry
->Data
->ProcessingPolicy
->TunnelOption
->RemoteTunnelAddress
504 return EFI_NOT_READY
;
509 if (!Data
->ManualSet
) {
510 if (Data
->ESNEnabled
) {
512 // Validate the 64bit sn number if 64bit sn enabled.
514 if ((UINT64
) (Data
->SequenceNumber
+ 1) == 0) {
516 // TODO: Re-negotiate SA
518 return EFI_DEVICE_ERROR
;
522 // Validate the 32bit sn number if 64bit sn disabled.
524 SeqNum32
= (UINT32
) Data
->SequenceNumber
;
525 if ((UINT32
) (SeqNum32
+ 1) == 0) {
527 // TODO: Re-negotiate SA
529 return EFI_DEVICE_ERROR
;
540 Find a PAD entry according to a remote IP address.
542 @param[in] IpVersion The version of IP.
543 @param[in] IpAddr Points to remote IP address.
545 @return the pointer of related PAD entry.
549 IpSecLookupPadEntry (
551 IN EFI_IP_ADDRESS
*IpAddr
556 EFI_IP_ADDRESS_INFO
*IpAddrInfo
;
557 IPSEC_PAD_ENTRY
*PadEntry
;
559 PadList
= &mConfigData
[IPsecConfigDataTypePad
];
561 for (Entry
= PadList
->ForwardLink
; Entry
!= PadList
; Entry
= Entry
->ForwardLink
) {
563 PadEntry
= IPSEC_PAD_ENTRY_FROM_LIST (Entry
);
564 IpAddrInfo
= &PadEntry
->Id
->Id
.IpAddress
;
566 // Find the right pad entry which contain the appointed dest addr.
568 if (IpSecMatchIpAddress (IpVersion
, IpAddr
, IpAddrInfo
, 1)) {
577 Check if the specified IP packet can be serviced by this SPD entry.
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.
587 @retval EFI_SUCCESS Find the related SPD.
588 @retval EFI_NOT_FOUND Not find the related SPD entry;
592 IpSecLookupSpdEntry (
593 IN IPSEC_SPD_ENTRY
*SpdEntry
,
598 IN BOOLEAN IsOutbound
,
599 OUT EFI_IPSEC_ACTION
*Action
602 EFI_IPSEC_SPD_SELECTOR
*SpdSel
;
605 EFI_IP_ADDRESS SrcAddr
;
606 EFI_IP_ADDRESS DstAddr
;
609 ASSERT (SpdEntry
!= NULL
);
610 SpdSel
= SpdEntry
->Selector
;
611 Ip4
= (IP4_HEAD
*) IpHead
;
612 Ip6
= (EFI_IP6_HEADER
*) IpHead
;
614 ZeroMem (&SrcAddr
, sizeof (EFI_IP_ADDRESS
));
615 ZeroMem (&DstAddr
, sizeof (EFI_IP_ADDRESS
));
618 // Parse the source and destination address from ip header.
620 if (IpVersion
== IP_VERSION_4
) {
621 CopyMem (&SrcAddr
, &Ip4
->Src
, sizeof (IP4_ADDR
));
622 CopyMem (&DstAddr
, &Ip4
->Dst
, sizeof (IP4_ADDR
));
624 CopyMem (&SrcAddr
, &Ip6
->SourceAddress
, sizeof (EFI_IPv6_ADDRESS
));
625 CopyMem (&DstAddr
, &Ip6
->DestinationAddress
, sizeof (EFI_IPv6_ADDRESS
));
628 // Check the local and remote addresses for outbound traffic
630 SpdMatch
= (BOOLEAN
)(IsOutbound
&&
631 IpSecMatchIpAddress (
634 SpdSel
->LocalAddress
,
635 SpdSel
->LocalAddressCount
637 IpSecMatchIpAddress (
640 SpdSel
->RemoteAddress
,
641 SpdSel
->RemoteAddressCount
646 // Check the local and remote addresses for inbound traffic
648 SpdMatch
= (BOOLEAN
) (SpdMatch
||
650 IpSecMatchIpAddress (
653 SpdSel
->LocalAddress
,
654 SpdSel
->LocalAddressCount
656 IpSecMatchIpAddress (
659 SpdSel
->RemoteAddress
,
660 SpdSel
->RemoteAddressCount
665 // Check the next layer protocol and local and remote ports.
667 SpdMatch
= (BOOLEAN
) (SpdMatch
&&
668 IpSecMatchNextLayerProtocol (
671 SpdSel
->NextLayerProtocol
,
680 // Find the right SPD entry if match the 5 key elements.
682 *Action
= SpdEntry
->Data
->Action
;
686 return EFI_NOT_FOUND
;
690 The call back function of NetbufFromExt.
692 @param[in] Arg The argument passed from the caller.
697 IpSecOnRecyclePacket (
704 This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP
707 @param[in] Event The related event.
708 @param[in] Context The data passed by the caller.
713 IpSecRecycleCallback (
718 IPSEC_RECYCLE_CONTEXT
*RecycleContext
;
720 RecycleContext
= (IPSEC_RECYCLE_CONTEXT
*) Context
;
722 if (RecycleContext
->FragmentTable
!= NULL
) {
723 FreePool (RecycleContext
->FragmentTable
);
726 if (RecycleContext
->PayloadBuffer
!= NULL
) {
727 FreePool (RecycleContext
->PayloadBuffer
);
730 FreePool (RecycleContext
);
731 gBS
->CloseEvent (Event
);
736 Calculate the extension hader of IP. The return length only doesn't contain
737 the fixed IP header length.
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.
742 @return The length of the extension header.
746 IpSecGetPlainExtHeadSize (
753 Size
= (UINT16
) (LastHead
- (UINT8
*) IpHead
);
755 if (Size
> sizeof (EFI_IP6_HEADER
)) {
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.
760 Size
= (UINT16
) (Size
- sizeof (EFI_IP6_HEADER
) + *(LastHead
+ 1) + 8);
769 Verify if the Authentication payload is correct.
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
775 @param[in] IcvSize The length of ICV.
777 @retval EFI_SUCCESS The authentication data is correct.
778 @retval EFI_ACCESS_DENIED The authentication data is not correct.
782 IpSecEspAuthVerifyPayload (
785 IN IPSEC_SAD_ENTRY
*SadEntry
,
792 HASH_DATA_FRAGMENT HashFragment
[1];
795 // Calculate the size of authentication payload.
797 AuthSize
= EspSize
- IcvSize
;
800 // Calculate the icv buffer and size of the payload.
802 HashFragment
[0].Data
= EspBuffer
;
803 HashFragment
[0].DataSize
= AuthSize
;
805 Status
= IpSecCryptoIoHmac (
806 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.AuthAlgoId
,
807 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.AuthKey
,
808 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.AuthKeyLength
,
814 if (EFI_ERROR (Status
)) {
819 // Compare the calculated icv and the appended original icv.
821 if (CompareMem (EspBuffer
+ AuthSize
, IcvBuffer
, IcvSize
) == 0) {
825 DEBUG ((DEBUG_ERROR
, "Error auth verify payload\n"));
826 return EFI_ACCESS_DENIED
;
830 Search the related SAD entry by the input .
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.
837 @retval NULL Not find the related SAD entry.
838 @retval IPSEC_SAD_ENTRY Return the related SAD entry.
842 IpSecFoundSadFromInboundPacket (
848 EFI_IP_ADDRESS DestIp
;
851 // Parse destination address from ip header.
853 ZeroMem (&DestIp
, sizeof (EFI_IP_ADDRESS
));
854 if (IpVersion
== IP_VERSION_4
) {
857 &((IP4_HEAD
*) IpHead
)->Dst
,
863 &((EFI_IP6_HEADER
*) IpHead
)->DestinationAddress
,
864 sizeof (EFI_IPv6_ADDRESS
)
869 // Lookup SAD entry according to the spi and dest address.
871 return IpSecLookupSadBySpi (Spi
, &DestIp
, IpVersion
);
875 Validate the IP6 extension header format for both the packets we received
876 and that we will transmit.
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.
886 @retval TRUE The option is properly formated.
887 @retval FALSE The option is malformated.
891 IpSecIsIp6ExtsValid (
892 IN UINT8
*NextHeader
,
894 IN UINT32 ExtHdrsLen
,
895 OUT UINT8
**LastHeader
,
896 OUT UINT32
*RealExtsLen OPTIONAL
907 if (RealExtsLen
!= NULL
) {
911 *LastHeader
= NextHeader
;
913 if (ExtHdrs
== NULL
&& ExtHdrsLen
== 0) {
917 if ((ExtHdrs
== NULL
&& ExtHdrsLen
!= 0) || (ExtHdrs
!= NULL
&& ExtHdrsLen
== 0)) {
927 while (Pointer
<= ExtHdrsLen
) {
929 switch (*NextHeader
) {
940 case IP6_DESTINATION
:
941 if (*NextHeader
== IP6_DESTINATION
) {
949 NextHeader
= ExtHdrs
+ Pointer
;
952 Option
= ExtHdrs
+ Pointer
;
953 OptionLen
= (UINT8
) ((*Option
+ 1) * 8 - 2);
957 Pointer
= Pointer
+ OptionLen
;
965 // RFC2402, AH header should after fragment header.
971 NextHeader
= ExtHdrs
+ Pointer
;
972 Pointer
= Pointer
+ 8;
980 Option
= ExtHdrs
+ Pointer
;
984 // RFC2402, Payload length is specified in 32-bit words, minus "2".
986 OptionLen
= (UINT8
) ((*Option
+ 2) * 4);
987 Pointer
= Pointer
+ OptionLen
;
991 *LastHeader
= NextHeader
;
992 if (RealExtsLen
!= NULL
) {
993 *RealExtsLen
= Pointer
;
1000 *LastHeader
= NextHeader
;
1002 if (RealExtsLen
!= NULL
) {
1003 *RealExtsLen
= Pointer
;
1010 The actual entry to process the tunnel header and inner header for tunnel mode
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.
1017 @param[in, out] IpHead Points to the IP header containing the ESP header
1018 to be trimed on input, and without ESP header
1020 @param[in] IpPayload The decrypted Ip payload. It start from the inner
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.
1028 IpSecTunnelInboundPacket (
1029 IN OUT UINT8
*IpHead
,
1030 IN UINT8
*IpPayload
,
1032 IN IPSEC_SAD_DATA
*SadData
,
1033 IN OUT UINT8
*LastHead
1036 EFI_UDP_HEADER
*UdpHeader
;
1037 TCP_HEAD
*TcpHeader
;
1039 UINT16 PseudoChecksum
;
1040 UINT16 PacketChecksum
;
1042 IP6_ICMP_HEAD
*Icmp6Head
;
1046 if (IpVersion
== IP_VERSION_4
) {
1048 // Zero OutIP header use this to indicate the input packet is under
1049 // IPsec Tunnel protected.
1056 &((IP4_HEAD
*)IpPayload
)->Dst
,
1057 &SadData
->TunnelDestAddress
.v4
,
1058 sizeof (EFI_IPv4_ADDRESS
)
1062 // Recalculate IpHeader Checksum
1064 if (((IP4_HEAD
*)(IpPayload
))->Checksum
!= 0 ) {
1065 ((IP4_HEAD
*)(IpPayload
))->Checksum
= 0;
1066 ((IP4_HEAD
*)(IpPayload
))->Checksum
= (UINT16
) (~NetblockChecksum (
1068 ((IP4_HEAD
*)IpPayload
)->HeadLen
<< 2
1075 // Recalcualte PseudoChecksum
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
;
1084 case EFI_IP_PROTO_TCP
:
1085 TcpHeader
= (TCP_HEAD
*) ((UINT8
*)IpPayload
+ (((IP4_HEAD
*)IpPayload
)->HeadLen
<< 2));
1086 Checksum
= &TcpHeader
->Checksum
;
1093 PacketChecksum
= NetblockChecksum (
1094 (UINT8
*)IpPayload
+ (((IP4_HEAD
*)IpPayload
)->HeadLen
<< 2),
1095 NTOHS (((IP4_HEAD
*)IpPayload
)->TotalLen
) - (((IP4_HEAD
*)IpPayload
)->HeadLen
<< 2)
1097 PseudoChecksum
= NetPseudoHeadChecksum (
1098 ((IP4_HEAD
*)IpPayload
)->Src
,
1099 ((IP4_HEAD
*)IpPayload
)->Dst
,
1100 ((IP4_HEAD
*)IpPayload
)->Protocol
,
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)))));
1110 // Zero OutIP header use this to indicate the input packet is under
1111 // IPsec Tunnel protected.
1115 sizeof (EFI_IP6_HEADER
)
1118 &((EFI_IP6_HEADER
*)IpPayload
)->DestinationAddress
,
1119 &SadData
->TunnelDestAddress
.v6
,
1120 sizeof (EFI_IPv6_ADDRESS
)
1124 // Get the Extension Header and Header length.
1126 IpSecIsIp6ExtsValid (
1127 &((EFI_IP6_HEADER
*)IpPayload
)->NextHeader
,
1128 IpPayload
+ sizeof (EFI_IP6_HEADER
),
1129 ((EFI_IP6_HEADER
*)IpPayload
)->PayloadLength
,
1135 // Recalcualte PseudoChecksum
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
;
1144 case EFI_IP_PROTO_TCP
:
1145 TcpHeader
= (TCP_HEAD
*)(IpPayload
+ sizeof (EFI_IP6_HEADER
) + OptionLen
);
1146 Checksum
= &TcpHeader
->Checksum
;
1151 Icmp6Head
= (IP6_ICMP_HEAD
*) (IpPayload
+ sizeof (EFI_IP6_HEADER
) + OptionLen
);
1152 Checksum
= &Icmp6Head
->Checksum
;
1156 PacketChecksum
= NetblockChecksum (
1157 IpPayload
+ sizeof (EFI_IP6_HEADER
) + OptionLen
,
1158 NTOHS(((EFI_IP6_HEADER
*)IpPayload
)->PayloadLength
) - OptionLen
1160 PseudoChecksum
= NetIp6PseudoHeadChecksum (
1161 &((EFI_IP6_HEADER
*)IpPayload
)->SourceAddress
,
1162 &((EFI_IP6_HEADER
*)IpPayload
)->DestinationAddress
,
1167 if (Checksum
!= NULL
) {
1168 *Checksum
= NetAddChecksum (PacketChecksum
, PseudoChecksum
);
1169 *Checksum
= (UINT16
) ~(NetAddChecksum (
1171 HTONS ((UINT16
)((NTOHS (((EFI_IP6_HEADER
*)(IpPayload
))->PayloadLength
)) - OptionLen
))
1178 The actual entry to create inner header for tunnel mode inbound traffic.
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.
1184 @param[in, out] IpHead Points to IP header containing the orginal IP header
1185 to be processed on input, and inserted ESP header
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
1195 @param[in] FragmentCount The number of fragments.
1197 @retval EFI_SUCCESS The operation was successful.
1198 @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated.
1202 IpSecTunnelOutboundPacket (
1203 IN OUT UINT8
*IpHead
,
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
1215 UINT16 PacketChecksum
;
1217 UINT16 PseudoChecksum
;
1218 IP6_ICMP_HEAD
*IcmpHead
;
1221 if (OptionsLength
== NULL
) {
1225 if (IpVersion
== IP_VERSION_4
) {
1226 InnerHead
= AllocateZeroPool (sizeof (IP4_HEAD
) + *OptionsLength
);
1227 ASSERT (InnerHead
!= NULL
);
1234 InnerHead
+ sizeof (IP4_HEAD
),
1239 InnerHead
= AllocateZeroPool (sizeof (EFI_IP6_HEADER
) + *OptionsLength
);
1243 sizeof (EFI_IP6_HEADER
)
1246 InnerHead
+ sizeof (EFI_IP6_HEADER
),
1251 if (OptionsBuffer
!= NULL
) {
1252 if (*OptionsLength
!= 0) {
1254 *OptionsBuffer
= NULL
;
1260 // 2. Reassamlbe Fragment into Packet
1262 Packet
= NetbufFromExt (
1263 (NET_FRAGMENT
*)(*FragmentTable
),
1267 IpSecOnRecyclePacket
,
1270 ASSERT (Packet
!= NULL
);
1272 // 3. Check the Last Header, if it is TCP, UDP or ICMP recalcualate its pesudo
1275 switch (*LastHead
) {
1276 case EFI_IP_PROTO_UDP
:
1277 Packet
->Udp
= (EFI_UDP_HEADER
*) NetbufGetByte (Packet
, 0, 0);
1278 ASSERT (Packet
->Udp
!= NULL
);
1279 Checksum
= &Packet
->Udp
->Checksum
;
1283 case EFI_IP_PROTO_TCP
:
1284 Packet
->Tcp
= (TCP_HEAD
*) NetbufGetByte (Packet
, 0, 0);
1285 ASSERT (Packet
->Tcp
!= NULL
);
1286 Checksum
= &Packet
->Tcp
->Checksum
;
1291 IcmpHead
= (IP6_ICMP_HEAD
*) NetbufGetByte (Packet
, 0, NULL
);
1292 ASSERT (IcmpHead
!= NULL
);
1293 Checksum
= &IcmpHead
->Checksum
;
1301 PacketChecksum
= NetbufChecksum (Packet
);
1303 if (IpVersion
== IP_VERSION_4
) {
1305 // Replace the source address of Inner Header.
1308 &((IP4_HEAD
*)InnerHead
)->Src
,
1309 &SadData
->SpdSelector
->LocalAddress
[0].Address
.v4
,
1310 sizeof (EFI_IPv4_ADDRESS
)
1313 PacketChecksum
= NetbufChecksum (Packet
);
1314 PseudoChecksum
= NetPseudoHeadChecksum (
1315 ((IP4_HEAD
*)InnerHead
)->Src
,
1316 ((IP4_HEAD
*)InnerHead
)->Dst
,
1323 // Replace the source address of Inner Header.
1326 &((EFI_IP6_HEADER
*)InnerHead
)->SourceAddress
,
1327 &(SadData
->SpdSelector
->LocalAddress
[0].Address
.v6
),
1328 sizeof (EFI_IPv6_ADDRESS
)
1330 PacketChecksum
= NetbufChecksum (Packet
);
1331 PseudoChecksum
= NetIp6PseudoHeadChecksum (
1332 &((EFI_IP6_HEADER
*)InnerHead
)->SourceAddress
,
1333 &((EFI_IP6_HEADER
*)InnerHead
)->DestinationAddress
,
1339 if (Checksum
!= NULL
) {
1340 *Checksum
= NetAddChecksum (PacketChecksum
, PseudoChecksum
);
1341 *Checksum
= (UINT16
) ~(NetAddChecksum ((UINT16
)*Checksum
, HTONS ((UINT16
) Packet
->TotalSize
)));
1344 if (Packet
!= NULL
) {
1345 NetbufFree (Packet
);
1351 The actual entry to relative function processes the inbound traffic of ESP header.
1353 This function is the subfunction of IpSecProtectInboundPacket(). It checks the
1354 received packet security property and trim the ESP header and then returns without
1355 an IPsec protected IP Header and FramgmentTable.
1357 @param[in] IpVersion The version of IP.
1358 @param[in, out] IpHead Points to the IP header containing the ESP header
1359 to be trimed on input, and without ESP header
1361 @param[out] LastHead The Last Header in IP header on return.
1362 @param[in, out] OptionsBuffer Pointer to the options buffer.
1363 @param[in, out] OptionsLength Length of the options buffer.
1364 @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec
1365 protected on input, and without IPsec protected
1367 @param[in, out] FragmentCount The number of fragments.
1368 @param[out] SpdSelector Pointer to contain the address of SPD selector on return.
1369 @param[out] RecycleEvent The event for recycling of resources.
1371 @retval EFI_SUCCESS The operation was successful.
1372 @retval EFI_ACCESS_DENIED One or more following conditions is TRUE:
1373 - ESP header was not found or mal-format.
1374 - The related SAD entry was not found.
1375 - The related SAD entry does not support the ESP protocol.
1376 @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.
1380 IpSecEspInboundPacket (
1382 IN OUT VOID
*IpHead
,
1383 OUT UINT8
*LastHead
,
1384 IN OUT VOID
**OptionsBuffer
,
1385 IN OUT UINT32
*OptionsLength
,
1386 IN OUT EFI_IPSEC_FRAGMENT_DATA
**FragmentTable
,
1387 IN OUT UINT32
*FragmentCount
,
1388 OUT EFI_IPSEC_SPD_SELECTOR
**SpdSelector
,
1389 OUT EFI_EVENT
*RecycleEvent
1398 UINTN PlainPayloadSize
;
1401 UINT8
*ProcessBuffer
;
1402 EFI_ESP_HEADER
*EspHeader
;
1403 EFI_ESP_TAIL
*EspTail
;
1404 EFI_IPSEC_SA_ID
*SaId
;
1405 IPSEC_SAD_DATA
*SadData
;
1406 IPSEC_SAD_ENTRY
*SadEntry
;
1407 IPSEC_RECYCLE_CONTEXT
*RecycleContext
;
1409 UINT16 IpSecHeadSize
;
1412 Status
= EFI_SUCCESS
;
1414 ProcessBuffer
= NULL
;
1415 RecycleContext
= NULL
;
1416 *RecycleEvent
= NULL
;
1417 PlainPayloadSize
= 0;
1421 // Build netbuf from fragment table first.
1423 Payload
= NetbufFromExt (
1424 (NET_FRAGMENT
*) *FragmentTable
,
1427 sizeof (EFI_ESP_HEADER
),
1428 IpSecOnRecyclePacket
,
1431 if (Payload
== NULL
) {
1432 Status
= EFI_OUT_OF_RESOURCES
;
1437 // Get the esp size and esp header from netbuf.
1439 EspSize
= Payload
->TotalSize
;
1440 EspHeader
= (EFI_ESP_HEADER
*) NetbufGetByte (Payload
, 0, NULL
);
1442 if (EspHeader
== NULL
) {
1443 Status
= EFI_ACCESS_DENIED
;
1448 // Parse destination address from ip header and found the related SAD Entry.
1450 SadEntry
= IpSecFoundSadFromInboundPacket (
1453 NTOHL (EspHeader
->Spi
)
1456 if (SadEntry
== NULL
) {
1457 Status
= EFI_ACCESS_DENIED
;
1461 SaId
= SadEntry
->Id
;
1462 SadData
= SadEntry
->Data
;
1465 // Only support esp protocol currently.
1467 if (SaId
->Proto
!= EfiIPsecESP
) {
1468 Status
= EFI_ACCESS_DENIED
;
1472 if (!SadData
->ManualSet
) {
1474 // TODO: Check SA lifetime and sequence number
1479 // Allocate buffer for decryption and authentication.
1481 ProcessBuffer
= AllocateZeroPool (EspSize
);
1482 if (ProcessBuffer
== NULL
) {
1483 Status
= EFI_OUT_OF_RESOURCES
;
1487 NetbufCopy (Payload
, 0, (UINT32
) EspSize
, ProcessBuffer
);
1490 // Get the IcvSize for authentication and BlockSize/IvSize for Decryption.
1492 IcvSize
= IpSecGetIcvLength (SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.AuthAlgoId
);
1493 IvSize
= IpSecGetEncryptIvLength (SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncAlgoId
);
1494 BlockSize
= IpSecGetEncryptBlockSize (SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncAlgoId
);
1497 // Make sure the ESP packet is not mal-formt.
1498 // 1. Check whether the Espsize is larger than ESP header + IvSize + EspTail + IcvSize.
1499 // 2. Check whether the left payload size is multiple of IvSize.
1501 MiscSize
= sizeof (EFI_ESP_HEADER
) + IvSize
+ IcvSize
;
1502 if (EspSize
<= (MiscSize
+ sizeof (EFI_ESP_TAIL
))) {
1503 Status
= EFI_ACCESS_DENIED
;
1506 if ((EspSize
- MiscSize
) % BlockSize
!= 0) {
1507 Status
= EFI_ACCESS_DENIED
;
1512 // Authenticate the ESP packet.
1514 if (SadData
->AlgoInfo
.EspAlgoInfo
.AuthKey
!= NULL
) {
1515 Status
= IpSecEspAuthVerifyPayload (
1521 if (EFI_ERROR (Status
)) {
1526 // Decrypt the payload by the SAD entry if it has decrypt key.
1528 if (SadData
->AlgoInfo
.EspAlgoInfo
.EncKey
!= NULL
) {
1529 Status
= IpSecCryptoIoDecrypt (
1530 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncAlgoId
,
1531 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncKey
,
1532 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncKeyLength
<< 3,
1533 ProcessBuffer
+ sizeof (EFI_ESP_HEADER
),
1534 ProcessBuffer
+ sizeof (EFI_ESP_HEADER
) + IvSize
,
1535 EspSize
- sizeof (EFI_ESP_HEADER
) - IvSize
- IcvSize
,
1536 ProcessBuffer
+ sizeof (EFI_ESP_HEADER
) + IvSize
1538 if (EFI_ERROR (Status
)) {
1544 // Parse EspTail and compute the plain payload size.
1546 EspTail
= (EFI_ESP_TAIL
*) (ProcessBuffer
+ EspSize
- IcvSize
- sizeof (EFI_ESP_TAIL
));
1547 PaddingSize
= EspTail
->PaddingLength
;
1548 NextHeader
= EspTail
->NextHeader
;
1550 if (EspSize
<= (MiscSize
+ sizeof (EFI_ESP_TAIL
) + PaddingSize
)) {
1551 Status
= EFI_ACCESS_DENIED
;
1554 PlainPayloadSize
= EspSize
- MiscSize
- sizeof (EFI_ESP_TAIL
) - PaddingSize
;
1557 // TODO: handle anti-replay window
1560 // Decryption and authentication with esp has been done, so it's time to
1561 // reload the new packet, create recycle event and fixup ip header.
1563 RecycleContext
= AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT
));
1564 if (RecycleContext
== NULL
) {
1565 Status
= EFI_OUT_OF_RESOURCES
;
1569 Status
= gBS
->CreateEvent (
1572 IpSecRecycleCallback
,
1576 if (EFI_ERROR (Status
)) {
1581 // The caller will take responsible to handle the original fragment table
1583 *FragmentTable
= AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA
));
1584 if (*FragmentTable
== NULL
) {
1585 Status
= EFI_OUT_OF_RESOURCES
;
1589 RecycleContext
->PayloadBuffer
= ProcessBuffer
;
1590 RecycleContext
->FragmentTable
= *FragmentTable
;
1593 // If Tunnel, recalculate upper-layyer PesudoCheckSum and trim the out
1595 if (SadData
->Mode
== EfiIPsecTunnel
) {
1596 InnerHead
= ProcessBuffer
+ sizeof (EFI_ESP_HEADER
) + IvSize
;
1597 IpSecTunnelInboundPacket (
1605 if (IpVersion
== IP_VERSION_4
) {
1606 (*FragmentTable
)[0].FragmentBuffer
= InnerHead
;
1607 (*FragmentTable
)[0].FragmentLength
= (UINT32
) PlainPayloadSize
;
1610 (*FragmentTable
)[0].FragmentBuffer
= InnerHead
;
1611 (*FragmentTable
)[0].FragmentLength
= (UINT32
) PlainPayloadSize
;
1614 (*FragmentTable
)[0].FragmentBuffer
= ProcessBuffer
+ sizeof (EFI_ESP_HEADER
) + IvSize
;
1615 (*FragmentTable
)[0].FragmentLength
= (UINT32
) PlainPayloadSize
;
1621 // Update the total length field in ip header since processed by esp.
1623 if (!SadData
->Mode
== EfiIPsecTunnel
) {
1624 if (IpVersion
== IP_VERSION_4
) {
1625 ((IP4_HEAD
*) IpHead
)->TotalLen
= HTONS ((UINT16
) ((((IP4_HEAD
*) IpHead
)->HeadLen
<< 2) + PlainPayloadSize
));
1627 IpSecHeadSize
= IpSecGetPlainExtHeadSize (IpHead
, LastHead
);
1628 ((EFI_IP6_HEADER
*) IpHead
)->PayloadLength
= HTONS ((UINT16
)(IpSecHeadSize
+ PlainPayloadSize
));
1631 // Update the next layer field in ip header since esp header inserted.
1633 *LastHead
= NextHeader
;
1638 // Update the SPD association of the SAD entry.
1640 *SpdSelector
= SadData
->SpdSelector
;
1643 if (Payload
!= NULL
) {
1644 NetbufFree (Payload
);
1647 if (EFI_ERROR (Status
)) {
1648 if (ProcessBuffer
!= NULL
) {
1649 FreePool (ProcessBuffer
);
1652 if (RecycleContext
!= NULL
) {
1653 FreePool (RecycleContext
);
1656 if (*RecycleEvent
!= NULL
) {
1657 gBS
->CloseEvent (*RecycleEvent
);
1665 The actual entry to the relative function processes the output traffic using the ESP protocol.
1667 This function is the subfunction of IpSecProtectOutboundPacket(). It protected
1668 the sending packet by encrypting its payload and inserting ESP header in the orginal
1669 IP header, then return the IpHeader and IPsec protected Fragmentable.
1671 @param[in] IpVersion The version of IP.
1672 @param[in, out] IpHead Points to IP header containing the orginal IP header
1673 to be processed on input, and inserted ESP header
1675 @param[in, out] LastHead The Last Header in IP header.
1676 @param[in, out] OptionsBuffer Pointer to the options buffer.
1677 @param[in, out] OptionsLength Length of the options buffer.
1678 @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
1679 IPsec on input, and with IPsec protected
1681 @param[in, out] FragmentCount The number of fragments.
1682 @param[in] SadEntry The related SAD entry.
1683 @param[out] RecycleEvent The event for recycling of resources.
1685 @retval EFI_SUCCESS The operation was successful.
1686 @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated.
1690 IpSecEspOutboundPacket (
1692 IN OUT VOID
*IpHead
,
1693 IN OUT UINT8
*LastHead
,
1694 IN OUT VOID
**OptionsBuffer
,
1695 IN OUT UINT32
*OptionsLength
,
1696 IN OUT EFI_IPSEC_FRAGMENT_DATA
**FragmentTable
,
1697 IN OUT UINT32
*FragmentCount
,
1698 IN IPSEC_SAD_ENTRY
*SadEntry
,
1699 OUT EFI_EVENT
*RecycleEvent
1704 EFI_IPSEC_SA_ID
*SaId
;
1705 IPSEC_SAD_DATA
*SadData
;
1706 IPSEC_RECYCLE_CONTEXT
*RecycleContext
;
1707 UINT8
*ProcessBuffer
;
1709 INTN EncryptBlockSize
;// Size of encryption block, 4 bytes aligned and >= 4
1710 UINTN EspSize
; // Total size of esp wrapped ip payload
1711 UINTN IvSize
; // Size of IV, optional, might be 0
1712 UINTN PlainPayloadSize
;// Original IP payload size
1713 UINTN PaddingSize
; // Size of padding
1714 UINTN EncryptSize
; // Size of data to be encrypted, start after IV and
1716 UINTN IcvSize
; // Size of ICV, optional, might be 0
1717 UINT8
*RestOfPayload
; // Start of Payload after IV
1718 UINT8
*Padding
; // Start address of padding
1719 EFI_ESP_HEADER
*EspHeader
; // Start address of ESP frame
1720 EFI_ESP_TAIL
*EspTail
; // Address behind padding
1722 HASH_DATA_FRAGMENT HashFragment
[1];
1724 Status
= EFI_ACCESS_DENIED
;
1725 SaId
= SadEntry
->Id
;
1726 SadData
= SadEntry
->Data
;
1727 ProcessBuffer
= NULL
;
1728 RecycleContext
= NULL
;
1729 *RecycleEvent
= NULL
;
1732 if (!SadData
->ManualSet
&&
1733 SadData
->AlgoInfo
.EspAlgoInfo
.EncKey
== NULL
&&
1734 SadData
->AlgoInfo
.EspAlgoInfo
.AuthKey
== NULL
1737 // Invalid manual SAD entry configuration.
1743 // Create OutHeader according to Inner Header
1745 if (SadData
->Mode
== EfiIPsecTunnel
) {
1746 InnerHead
= IpSecTunnelOutboundPacket (
1757 if (InnerHead
== NULL
) {
1758 return EFI_INVALID_PARAMETER
;
1764 // Calculate enctrypt block size, need iv by default and 4 bytes alignment.
1766 EncryptBlockSize
= 4;
1768 if (SadData
->AlgoInfo
.EspAlgoInfo
.EncKey
!= NULL
) {
1769 EncryptBlockSize
= IpSecGetEncryptBlockSize (SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncAlgoId
);
1771 if (EncryptBlockSize
< 0 || (EncryptBlockSize
!= 1 && EncryptBlockSize
% 4 != 0)) {
1777 // Calculate the plain payload size accroding to the fragment table.
1779 PlainPayloadSize
= 0;
1780 for (Index
= 0; Index
< *FragmentCount
; Index
++) {
1781 PlainPayloadSize
+= (*FragmentTable
)[Index
].FragmentLength
;
1785 // Add IPHeader size for Tunnel Mode
1787 if (SadData
->Mode
== EfiIPsecTunnel
) {
1788 if (IpVersion
== IP_VERSION_4
) {
1789 PlainPayloadSize
+= sizeof (IP4_HEAD
);
1791 PlainPayloadSize
+= sizeof (EFI_IP6_HEADER
);
1794 // OPtions should be encryption into it
1796 PlainPayloadSize
+= *OptionsLength
;
1801 // Calculate icv size, optional by default and 4 bytes alignment.
1804 if (SadData
->AlgoInfo
.EspAlgoInfo
.AuthKey
!= NULL
) {
1805 IcvSize
= IpSecGetIcvLength (SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.AuthAlgoId
);
1806 if (IcvSize
% 4 != 0) {
1812 // Calcuate the total size of esp wrapped ip payload.
1814 IvSize
= IpSecGetEncryptIvLength (SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncAlgoId
);
1815 EncryptSize
= (PlainPayloadSize
+ sizeof (EFI_ESP_TAIL
) + EncryptBlockSize
- 1) / EncryptBlockSize
* EncryptBlockSize
;
1816 PaddingSize
= EncryptSize
- PlainPayloadSize
- sizeof (EFI_ESP_TAIL
);
1817 EspSize
= sizeof (EFI_ESP_HEADER
) + IvSize
+ EncryptSize
+ IcvSize
;
1819 ProcessBuffer
= AllocateZeroPool (EspSize
);
1820 if (ProcessBuffer
== NULL
) {
1821 Status
= EFI_OUT_OF_RESOURCES
;
1826 // Calculate esp header and esp tail including header, payload and padding.
1828 EspHeader
= (EFI_ESP_HEADER
*) ProcessBuffer
;
1829 RestOfPayload
= (UINT8
*) (EspHeader
+ 1) + IvSize
;
1830 Padding
= RestOfPayload
+ PlainPayloadSize
;
1831 EspTail
= (EFI_ESP_TAIL
*) (Padding
+ PaddingSize
);
1834 // Fill the sn and spi fields in esp header.
1836 EspHeader
->SequenceNumber
= HTONL ((UINT32
) SadData
->SequenceNumber
+ 1);
1837 //EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber);
1838 EspHeader
->Spi
= HTONL (SaId
->Spi
);
1841 // Copy the rest of payload (after iv) from the original fragment buffer.
1848 if (SadData
->Mode
== EfiIPsecTunnel
) {
1849 if (IpVersion
== IP_VERSION_4
) {
1851 // HeadLen, Total Length
1853 ((IP4_HEAD
*)InnerHead
)->HeadLen
= (UINT8
) ((sizeof (IP4_HEAD
) + *OptionsLength
) >> 2);
1854 ((IP4_HEAD
*)InnerHead
)->TotalLen
= HTONS ((UINT16
) PlainPayloadSize
);
1855 ((IP4_HEAD
*)InnerHead
)->Checksum
= 0;
1856 ((IP4_HEAD
*)InnerHead
)->Checksum
= (UINT16
) (~NetblockChecksum (
1861 RestOfPayload
+ BytesCopied
,
1863 sizeof (IP4_HEAD
) + *OptionsLength
1865 BytesCopied
+= sizeof (IP4_HEAD
) + *OptionsLength
;
1868 ((EFI_IP6_HEADER
*)InnerHead
)->PayloadLength
= HTONS ((UINT16
) (PlainPayloadSize
- sizeof (EFI_IP6_HEADER
)));
1870 RestOfPayload
+ BytesCopied
,
1872 sizeof (EFI_IP6_HEADER
) + *OptionsLength
1874 BytesCopied
+= sizeof (EFI_IP6_HEADER
) + *OptionsLength
;
1878 for (Index
= 0; Index
< *FragmentCount
; Index
++) {
1880 (RestOfPayload
+ BytesCopied
),
1881 (*FragmentTable
)[Index
].FragmentBuffer
,
1882 (*FragmentTable
)[Index
].FragmentLength
1884 BytesCopied
+= (*FragmentTable
)[Index
].FragmentLength
;
1887 // Fill the padding buffer by natural number sequence.
1889 for (Index
= 0; Index
< PaddingSize
; Index
++) {
1890 Padding
[Index
] = (UINT8
) (Index
+ 1);
1893 // Fill the padding length and next header fields in esp tail.
1895 EspTail
->PaddingLength
= (UINT8
) PaddingSize
;
1896 EspTail
->NextHeader
= *LastHead
;
1899 // Fill the next header for Tunnel mode.
1901 if (SadData
->Mode
== EfiIPsecTunnel
) {
1902 if (IpVersion
== IP_VERSION_4
) {
1903 EspTail
->NextHeader
= 4;
1905 EspTail
->NextHeader
= 41;
1910 // Generate iv at random by crypt library.
1912 Status
= IpSecGenerateIv (
1913 (UINT8
*) (EspHeader
+ 1),
1918 if (EFI_ERROR (Status
)) {
1923 // Encryption the payload (after iv) by the SAD entry if has encrypt key.
1925 if (SadData
->AlgoInfo
.EspAlgoInfo
.EncKey
!= NULL
) {
1926 Status
= IpSecCryptoIoEncrypt (
1927 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncAlgoId
,
1928 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncKey
,
1929 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.EncKeyLength
<< 3,
1930 (UINT8
*)(EspHeader
+ 1),
1936 if (EFI_ERROR (Status
)) {
1942 // Authenticate the esp wrapped buffer by the SAD entry if it has auth key.
1944 if (SadData
->AlgoInfo
.EspAlgoInfo
.AuthKey
!= NULL
) {
1946 HashFragment
[0].Data
= ProcessBuffer
;
1947 HashFragment
[0].DataSize
= EspSize
- IcvSize
;
1948 Status
= IpSecCryptoIoHmac (
1949 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.AuthAlgoId
,
1950 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.AuthKey
,
1951 SadEntry
->Data
->AlgoInfo
.EspAlgoInfo
.AuthKeyLength
,
1954 ProcessBuffer
+ EspSize
- IcvSize
,
1957 if (EFI_ERROR (Status
)) {
1963 // Encryption and authentication with esp has been done, so it's time to
1964 // reload the new packet, create recycle event and fixup ip header.
1966 RecycleContext
= AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT
));
1967 if (RecycleContext
== NULL
) {
1968 Status
= EFI_OUT_OF_RESOURCES
;
1972 Status
= gBS
->CreateEvent (
1975 IpSecRecycleCallback
,
1979 if (EFI_ERROR (Status
)) {
1983 // Caller take responsible to handle the original fragment table.
1985 *FragmentTable
= AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA
));
1986 if (*FragmentTable
== NULL
) {
1987 Status
= EFI_OUT_OF_RESOURCES
;
1991 RecycleContext
->FragmentTable
= *FragmentTable
;
1992 RecycleContext
->PayloadBuffer
= ProcessBuffer
;
1993 (*FragmentTable
)[0].FragmentBuffer
= ProcessBuffer
;
1994 (*FragmentTable
)[0].FragmentLength
= (UINT32
) EspSize
;
1998 // Update the total length field in ip header since processed by esp.
2000 if (IpVersion
== IP_VERSION_4
) {
2001 ((IP4_HEAD
*) IpHead
)->TotalLen
= HTONS ((UINT16
) ((((IP4_HEAD
*) IpHead
)->HeadLen
<< 2) + EspSize
));
2003 ((EFI_IP6_HEADER
*) IpHead
)->PayloadLength
= (UINT16
) (IpSecGetPlainExtHeadSize (IpHead
, LastHead
) + EspSize
);
2007 // If tunnel mode, it should change the outer Ip header with tunnel source address
2008 // and destination tunnel address.
2010 if (SadData
->Mode
== EfiIPsecTunnel
) {
2011 if (IpVersion
== IP_VERSION_4
) {
2013 &((IP4_HEAD
*) IpHead
)->Src
,
2014 &SadData
->TunnelSourceAddress
.v4
,
2015 sizeof (EFI_IPv4_ADDRESS
)
2018 &((IP4_HEAD
*) IpHead
)->Dst
,
2019 &SadData
->TunnelDestAddress
.v4
,
2020 sizeof (EFI_IPv4_ADDRESS
)
2024 &((EFI_IP6_HEADER
*) IpHead
)->SourceAddress
,
2025 &SadData
->TunnelSourceAddress
.v6
,
2026 sizeof (EFI_IPv6_ADDRESS
)
2029 &((EFI_IP6_HEADER
*) IpHead
)->DestinationAddress
,
2030 &SadData
->TunnelDestAddress
.v6
,
2031 sizeof (EFI_IPv6_ADDRESS
)
2037 // Update the next layer field in ip header since esp header inserted.
2039 *LastHead
= IPSEC_ESP_PROTOCOL
;
2042 // Increase the sn number in SAD entry according to rfc4303.
2044 SadData
->SequenceNumber
++;
2047 if (EFI_ERROR (Status
)) {
2048 if (ProcessBuffer
!= NULL
) {
2049 FreePool (ProcessBuffer
);
2052 if (RecycleContext
!= NULL
) {
2053 FreePool (RecycleContext
);
2056 if (*RecycleEvent
!= NULL
) {
2057 gBS
->CloseEvent (*RecycleEvent
);
2065 This function processes the inbound traffic with IPsec.
2067 It checks the received packet security property, trims the ESP/AH header, and then
2068 returns without an IPsec protected IP Header and FragmentTable.
2070 @param[in] IpVersion The version of IP.
2071 @param[in, out] IpHead Points to IP header containing the ESP/AH header
2072 to be trimed on input, and without ESP/AH header
2074 @param[in, out] LastHead The Last Header in IP header on return.
2075 @param[in, out] OptionsBuffer Pointer to the options buffer.
2076 @param[in, out] OptionsLength Length of the options buffer.
2077 @param[in, out] FragmentTable Pointer to a list of fragments in form of IPsec
2078 protected on input, and without IPsec protected
2080 @param[in, out] FragmentCount The number of fragments.
2081 @param[out] SpdEntry Pointer to contain the address of SPD entry on return.
2082 @param[out] RecycleEvent The event for recycling of resources.
2084 @retval EFI_SUCCESS The operation was successful.
2085 @retval EFI_UNSUPPORTED The IPSEC protocol is not supported.
2089 IpSecProtectInboundPacket (
2091 IN OUT VOID
*IpHead
,
2092 IN OUT UINT8
*LastHead
,
2093 IN OUT VOID
**OptionsBuffer
,
2094 IN OUT UINT32
*OptionsLength
,
2095 IN OUT EFI_IPSEC_FRAGMENT_DATA
**FragmentTable
,
2096 IN OUT UINT32
*FragmentCount
,
2097 OUT EFI_IPSEC_SPD_SELECTOR
**SpdEntry
,
2098 OUT EFI_EVENT
*RecycleEvent
2101 if (*LastHead
== IPSEC_ESP_PROTOCOL
) {
2103 // Process the esp ipsec header of the inbound traffic.
2105 return IpSecEspInboundPacket (
2118 // The other protocols are not supported.
2120 return EFI_UNSUPPORTED
;
2124 This fucntion processes the output traffic with IPsec.
2126 It protected the sending packet by encrypting it payload and inserting ESP/AH header
2127 in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable.
2129 @param[in] IpVersion The version of IP.
2130 @param[in, out] IpHead Point to IP header containing the orginal IP header
2131 to be processed on input, and inserted ESP/AH header
2133 @param[in, out] LastHead The Last Header in IP header.
2134 @param[in, out] OptionsBuffer Pointer to the options buffer.
2135 @param[in, out] OptionsLength Length of the options buffer.
2136 @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
2137 IPsec on input, and with IPsec protected
2139 @param[in, out] FragmentCount Number of fragments.
2140 @param[in] SadEntry Related SAD entry.
2141 @param[out] RecycleEvent Event for recycling of resources.
2143 @retval EFI_SUCCESS The operation is successful.
2144 @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported.
2148 IpSecProtectOutboundPacket (
2150 IN OUT VOID
*IpHead
,
2151 IN OUT UINT8
*LastHead
,
2152 IN OUT VOID
**OptionsBuffer
,
2153 IN OUT UINT32
*OptionsLength
,
2154 IN OUT EFI_IPSEC_FRAGMENT_DATA
**FragmentTable
,
2155 IN OUT UINT32
*FragmentCount
,
2156 IN IPSEC_SAD_ENTRY
*SadEntry
,
2157 OUT EFI_EVENT
*RecycleEvent
2160 if (SadEntry
->Id
->Proto
== EfiIPsecESP
) {
2162 // Process the esp ipsec header of the outbound traffic.
2164 return IpSecEspOutboundPacket (
2177 // The other protocols are not supported.
2179 return EFI_UNSUPPORTED
;