summaryrefslogtreecommitdiff
path: root/NetworkPkg/IpSecDxe/IpSecImpl.c
diff options
context:
space:
mode:
Diffstat (limited to 'NetworkPkg/IpSecDxe/IpSecImpl.c')
-rw-r--r--NetworkPkg/IpSecDxe/IpSecImpl.c2184
1 files changed, 0 insertions, 2184 deletions
diff --git a/NetworkPkg/IpSecDxe/IpSecImpl.c b/NetworkPkg/IpSecDxe/IpSecImpl.c
deleted file mode 100644
index 625f154ff4..0000000000
--- a/NetworkPkg/IpSecDxe/IpSecImpl.c
+++ /dev/null
@@ -1,2184 +0,0 @@
-/** @file
- The implementation of IPsec.
-
- (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
- Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
-
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php.
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#include "IpSecImpl.h"
-#include "IkeService.h"
-#include "IpSecDebug.h"
-#include "IpSecCryptIo.h"
-#include "IpSecConfigImpl.h"
-
-/**
- Check if the specified Address is the Valid Address Range.
-
- This function checks if the bytes after prefixed length are all Zero in this
- Address. This Address is supposed to point to a range address. That means it
- should gives the correct prefixed address and the bytes outside the prefixed are
- zero.
-
- @param[in] IpVersion The IP version.
- @param[in] Address Points to EFI_IP_ADDRESS to be checked.
- @param[in] PrefixLength The PrefixeLength of this address.
-
- @retval TRUE The address is a vaild address range.
- @retval FALSE The address is not a vaild address range.
-
-**/
-BOOLEAN
-IpSecValidAddressRange (
- IN UINT8 IpVersion,
- IN EFI_IP_ADDRESS *Address,
- IN UINT8 PrefixLength
- )
-{
- UINT8 Div;
- UINT8 Mod;
- UINT8 Mask;
- UINT8 AddrLen;
- UINT8 *Addr;
- EFI_IP_ADDRESS ZeroAddr;
-
- if (PrefixLength == 0) {
- return TRUE;
- }
-
- AddrLen = (UINT8) ((IpVersion == IP_VERSION_4) ? 32 : 128);
-
- if (AddrLen <= PrefixLength) {
- return FALSE;
- }
-
- Div = (UINT8) (PrefixLength / 8);
- Mod = (UINT8) (PrefixLength % 8);
- Addr = (UINT8 *) Address;
- ZeroMem (&ZeroAddr, sizeof (EFI_IP_ADDRESS));
-
- //
- // Check whether the mod part of host scope is zero or not.
- //
- if (Mod > 0) {
- Mask = (UINT8) (0xFF << (8 - Mod));
-
- if ((Addr[Div] | Mask) != Mask) {
- return FALSE;
- }
-
- Div++;
- }
- //
- // Check whether the div part of host scope is zero or not.
- //
- if (CompareMem (
- &Addr[Div],
- &ZeroAddr,
- sizeof (EFI_IP_ADDRESS) - Div
- ) != 0) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- Extrct the Address Range from a Address.
-
- This function keep the prefix address and zero other part address.
-
- @param[in] Address Point to a specified address.
- @param[in] PrefixLength The prefix length.
- @param[out] Range Contain the return Address Range.
-
-**/
-VOID
-IpSecExtractAddressRange (
- IN EFI_IP_ADDRESS *Address,
- IN UINT8 PrefixLength,
- OUT EFI_IP_ADDRESS *Range
- )
-{
- UINT8 Div;
- UINT8 Mod;
- UINT8 Mask;
- UINT8 *Addr;
-
- if (PrefixLength == 0) {
- return ;
- }
-
- Div = (UINT8) (PrefixLength / 8);
- Mod = (UINT8) (PrefixLength % 8);
- Addr = (UINT8 *) Range;
-
- CopyMem (Range, Address, sizeof (EFI_IP_ADDRESS));
-
- //
- // Zero the mod part of host scope.
- //
- if (Mod > 0) {
- Mask = (UINT8) (0xFF << (8 - Mod));
- Addr[Div] = (UINT8) (Addr[Div] & Mask);
- Div++;
- }
- //
- // Zero the div part of host scope.
- //
- ZeroMem (&Addr[Div], sizeof (EFI_IP_ADDRESS) - Div);
-
-}
-
-/**
- Checks if the IP Address in the address range of AddressInfos specified.
-
- @param[in] IpVersion The IP version.
- @param[in] IpAddr Point to EFI_IP_ADDRESS to be check.
- @param[in] AddressInfo A list of EFI_IP_ADDRESS_INFO that is used to check
- the IP Address is matched.
- @param[in] AddressCount The total numbers of the AddressInfo.
-
- @retval TRUE If the Specified IP Address is in the range of the AddressInfos specified.
- @retval FALSE If the Specified IP Address is not in the range of the AddressInfos specified.
-
-**/
-BOOLEAN
-IpSecMatchIpAddress (
- IN UINT8 IpVersion,
- IN EFI_IP_ADDRESS *IpAddr,
- IN EFI_IP_ADDRESS_INFO *AddressInfo,
- IN UINT32 AddressCount
- )
-{
- EFI_IP_ADDRESS Range;
- UINT32 Index;
- BOOLEAN IsMatch;
-
- IsMatch = FALSE;
-
- for (Index = 0; Index < AddressCount; Index++) {
- //
- // Check whether the target address is in the address range
- // if it's a valid range of address.
- //
- if (IpSecValidAddressRange (
- IpVersion,
- &AddressInfo[Index].Address,
- AddressInfo[Index].PrefixLength
- )) {
- //
- // Get the range of the target address belongs to.
- //
- ZeroMem (&Range, sizeof (EFI_IP_ADDRESS));
- IpSecExtractAddressRange (
- IpAddr,
- AddressInfo[Index].PrefixLength,
- &Range
- );
-
- if (CompareMem (
- &Range,
- &AddressInfo[Index].Address,
- sizeof (EFI_IP_ADDRESS)
- ) == 0) {
- //
- // The target address is in the address range.
- //
- IsMatch = TRUE;
- break;
- }
- }
-
- if (CompareMem (
- IpAddr,
- &AddressInfo[Index].Address,
- sizeof (EFI_IP_ADDRESS)
- ) == 0) {
- //
- // The target address is exact same as the address.
- //
- IsMatch = TRUE;
- break;
- }
- }
- return IsMatch;
-}
-
-/**
- Check if the specified Protocol and Prot is supported by the specified SPD Entry.
-
- This function is the subfunction of IPsecLookUpSpdEntry() that is used to
- check if the sent/received IKE packet has the related SPD entry support.
-
- @param[in] Protocol The Protocol to be checked.
- @param[in] IpPayload Point to IP Payload to be check.
- @param[in] SpdProtocol The Protocol supported by SPD.
- @param[in] SpdLocalPort The Local Port in SPD.
- @param[in] SpdRemotePort The Remote Port in SPD.
- @param[in] IsOutbound Flag to indicate the is for IKE Packet sending or recieving.
-
- @retval TRUE The Protocol and Port are supported by the SPD Entry.
- @retval FALSE The Protocol and Port are not supported by the SPD Entry.
-
-**/
-BOOLEAN
-IpSecMatchNextLayerProtocol (
- IN UINT8 Protocol,
- IN UINT8 *IpPayload,
- IN UINT16 SpdProtocol,
- IN UINT16 SpdLocalPort,
- IN UINT16 SpdRemotePort,
- IN BOOLEAN IsOutbound
- )
-{
- BOOLEAN IsMatch;
-
- if (SpdProtocol == EFI_IPSEC_ANY_PROTOCOL) {
- return TRUE;
- }
-
- IsMatch = FALSE;
-
- if (SpdProtocol == Protocol) {
- switch (Protocol) {
- case EFI_IP_PROTO_UDP:
- case EFI_IP_PROTO_TCP:
- //
- // For udp and tcp, (0, 0) means no need to check local and remote
- // port. The payload is passed from upper level, which means it should
- // be in network order.
- //
- IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);
- IsMatch = (BOOLEAN) (IsMatch ||
- (IsOutbound &&
- (BOOLEAN)(
- NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdLocalPort &&
- NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdRemotePort
- )
- ));
-
- IsMatch = (BOOLEAN) (IsMatch ||
- (!IsOutbound &&
- (BOOLEAN)(
- NTOHS (((EFI_UDP_HEADER *) IpPayload)->DstPort) == SpdLocalPort &&
- NTOHS (((EFI_UDP_HEADER *) IpPayload)->SrcPort) == SpdRemotePort
- )
- ));
- break;
-
- case EFI_IP_PROTO_ICMP:
- //
- // For icmpv4, type code is replaced with local port and remote port,
- // and (0, 0) means no need to check.
- //
- IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);
- IsMatch = (BOOLEAN) (IsMatch ||
- (BOOLEAN) (((IP4_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&
- ((IP4_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort
- )
- );
- break;
-
- case IP6_ICMP:
- //
- // For icmpv6, type code is replaced with local port and remote port,
- // and (0, 0) means no need to check.
- //
- IsMatch = (BOOLEAN) (SpdLocalPort == 0 && SpdRemotePort == 0);
-
- IsMatch = (BOOLEAN) (IsMatch ||
- (BOOLEAN) (((IP6_ICMP_HEAD *) IpPayload)->Type == SpdLocalPort &&
- ((IP6_ICMP_HEAD *) IpPayload)->Code == SpdRemotePort
- )
- );
- break;
-
- default:
- IsMatch = TRUE;
- break;
- }
- }
-
- return IsMatch;
-}
-
-/**
- Find the SAD through a specified SPD's SAD list.
-
- @param[in] SadList SAD list related to a specified SPD entry.
- @param[in] DestAddress The destination address used to find the SAD entry.
- @param[in] IpVersion The IP version. Ip4 or Ip6.
-
- @return The pointer to a certain SAD entry.
-
-**/
-IPSEC_SAD_ENTRY *
-IpSecLookupSadBySpd (
- IN LIST_ENTRY *SadList,
- IN EFI_IP_ADDRESS *DestAddress,
- IN UINT8 IpVersion
- )
-{
- LIST_ENTRY *Entry;
- IPSEC_SAD_ENTRY *SadEntry;
-
- NET_LIST_FOR_EACH (Entry, SadList) {
-
- SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);
- //
- // Find the right SAD entry which contains the appointed dest address.
- //
- if (IpSecMatchIpAddress (
- IpVersion,
- DestAddress,
- SadEntry->Data->SpdSelector->RemoteAddress,
- SadEntry->Data->SpdSelector->RemoteAddressCount
- )){
- return SadEntry;
- }
- }
-
- return NULL;
-}
-
-/**
- Find the SAD through whole SAD list.
-
- @param[in] Spi The SPI used to search the SAD entry.
- @param[in] DestAddress The destination used to search the SAD entry.
- @param[in] IpVersion The IP version. Ip4 or Ip6.
-
- @return the pointer to a certain SAD entry.
-
-**/
-IPSEC_SAD_ENTRY *
-IpSecLookupSadBySpi (
- IN UINT32 Spi,
- IN EFI_IP_ADDRESS *DestAddress,
- IN UINT8 IpVersion
- )
-{
- LIST_ENTRY *Entry;
- LIST_ENTRY *SadList;
- IPSEC_SAD_ENTRY *SadEntry;
-
- SadList = &mConfigData[IPsecConfigDataTypeSad];
-
- NET_LIST_FOR_EACH (Entry, SadList) {
-
- SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
-
- //
- // Find the right SAD entry which contain the appointed spi and dest addr.
- //
- if (SadEntry->Id->Spi == Spi) {
- if (SadEntry->Data->Mode == EfiIPsecTunnel) {
- if (CompareMem (
- &DestAddress,
- &SadEntry->Data->TunnelDestAddress,
- sizeof (EFI_IP_ADDRESS)
- )) {
- return SadEntry;
- }
- } else {
- if (SadEntry->Data->SpdSelector != NULL &&
- IpSecMatchIpAddress (
- IpVersion,
- DestAddress,
- SadEntry->Data->SpdSelector->RemoteAddress,
- SadEntry->Data->SpdSelector->RemoteAddressCount
- )
- ) {
- return SadEntry;
- }
- }
- }
- }
- return NULL;
-}
-
-/**
- Look up if there is existing SAD entry for specified IP packet sending.
-
- This function is called by the IPsecProcess when there is some IP packet needed to
- send out. This function checks if there is an existing SAD entry that can be serviced
- to this IP packet sending. If no existing SAD entry could be used, this
- function will invoke an IPsec Key Exchange Negotiation.
-
- @param[in] Private Points to private data.
- @param[in] NicHandle Points to a NIC handle.
- @param[in] IpVersion The version of IP.
- @param[in] IpHead The IP Header of packet to be sent out.
- @param[in] IpPayload The IP Payload to be sent out.
- @param[in] OldLastHead The Last protocol of the IP packet.
- @param[in] SpdEntry Points to a related SPD entry.
- @param[out] SadEntry Contains the Point of a related SAD entry.
-
- @retval EFI_DEVICE_ERROR One of following conditions is TRUE:
- - If don't find related UDP service.
- - Sequence Number is used up.
- - Extension Sequence Number is used up.
- @retval EFI_NOT_READY No existing SAD entry could be used.
- @retval EFI_SUCCESS Find the related SAD entry.
-
-**/
-EFI_STATUS
-IpSecLookupSadEntry (
- IN IPSEC_PRIVATE_DATA *Private,
- IN EFI_HANDLE NicHandle,
- IN UINT8 IpVersion,
- IN VOID *IpHead,
- IN UINT8 *IpPayload,
- IN UINT8 OldLastHead,
- IN IPSEC_SPD_ENTRY *SpdEntry,
- OUT IPSEC_SAD_ENTRY **SadEntry
- )
-{
- IKE_UDP_SERVICE *UdpService;
- IPSEC_SAD_ENTRY *Entry;
- IPSEC_SAD_DATA *Data;
- EFI_IP_ADDRESS DestIp;
- UINT32 SeqNum32;
-
- *SadEntry = NULL;
- UdpService = IkeLookupUdp (Private, NicHandle, IpVersion);
-
- if (UdpService == NULL) {
- return EFI_DEVICE_ERROR;
- }
- //
- // Parse the destination address from ip header.
- //
- ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));
- if (IpVersion == IP_VERSION_4) {
- CopyMem (
- &DestIp,
- &((IP4_HEAD *) IpHead)->Dst,
- sizeof (IP4_ADDR)
- );
- } else {
- CopyMem (
- &DestIp,
- &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
- sizeof (EFI_IP_ADDRESS)
- );
- }
-
- //
- // Find the SAD entry in the spd.sas list according to the dest address.
- //
- Entry = IpSecLookupSadBySpd (&SpdEntry->Data->Sas, &DestIp, IpVersion);
-
- if (Entry == NULL) {
- if (OldLastHead != IP6_ICMP ||
- (OldLastHead == IP6_ICMP && *IpPayload == ICMP_V6_ECHO_REQUEST)
- ) {
- //
- // Start ike negotiation process except the request packet of ping.
- //
- if (SpdEntry->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
- IkeNegotiate (
- UdpService,
- SpdEntry,
- &SpdEntry->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress
- );
- } else {
- IkeNegotiate (
- UdpService,
- SpdEntry,
- &DestIp
- );
- }
-
- }
-
- return EFI_NOT_READY;
- }
-
- Data = Entry->Data;
-
- if (!Data->ManualSet) {
- if (Data->ESNEnabled) {
- //
- // Validate the 64bit sn number if 64bit sn enabled.
- //
- if ((UINT64) (Data->SequenceNumber + 1) == 0) {
- //
- // TODO: Re-negotiate SA
- //
- return EFI_DEVICE_ERROR;
- }
- } else {
- //
- // Validate the 32bit sn number if 64bit sn disabled.
- //
- SeqNum32 = (UINT32) Data->SequenceNumber;
- if ((UINT32) (SeqNum32 + 1) == 0) {
- //
- // TODO: Re-negotiate SA
- //
- return EFI_DEVICE_ERROR;
- }
- }
- }
-
- *SadEntry = Entry;
-
- return EFI_SUCCESS;
-}
-
-/**
- Find a PAD entry according to a remote IP address.
-
- @param[in] IpVersion The version of IP.
- @param[in] IpAddr Points to remote IP address.
-
- @return the pointer of related PAD entry.
-
-**/
-IPSEC_PAD_ENTRY *
-IpSecLookupPadEntry (
- IN UINT8 IpVersion,
- IN EFI_IP_ADDRESS *IpAddr
- )
-{
- LIST_ENTRY *PadList;
- LIST_ENTRY *Entry;
- EFI_IP_ADDRESS_INFO *IpAddrInfo;
- IPSEC_PAD_ENTRY *PadEntry;
-
- PadList = &mConfigData[IPsecConfigDataTypePad];
-
- for (Entry = PadList->ForwardLink; Entry != PadList; Entry = Entry->ForwardLink) {
-
- PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
- IpAddrInfo = &PadEntry->Id->Id.IpAddress;
- //
- // Find the right pad entry which contain the appointed dest addr.
- //
- if (IpSecMatchIpAddress (IpVersion, IpAddr, IpAddrInfo, 1)) {
- return PadEntry;
- }
- }
-
- return NULL;
-}
-
-/**
- Check if the specified IP packet can be serviced by this SPD entry.
-
- @param[in] SpdEntry Point to SPD entry.
- @param[in] IpVersion Version of IP.
- @param[in] IpHead Point to IP header.
- @param[in] IpPayload Point to IP payload.
- @param[in] Protocol The Last protocol of IP packet.
- @param[in] IsOutbound Traffic direction.
- @param[out] Action The support action of SPD entry.
-
- @retval EFI_SUCCESS Find the related SPD.
- @retval EFI_NOT_FOUND Not find the related SPD entry;
-
-**/
-EFI_STATUS
-IpSecLookupSpdEntry (
- IN IPSEC_SPD_ENTRY *SpdEntry,
- IN UINT8 IpVersion,
- IN VOID *IpHead,
- IN UINT8 *IpPayload,
- IN UINT8 Protocol,
- IN BOOLEAN IsOutbound,
- OUT EFI_IPSEC_ACTION *Action
- )
-{
- EFI_IPSEC_SPD_SELECTOR *SpdSel;
- IP4_HEAD *Ip4;
- EFI_IP6_HEADER *Ip6;
- EFI_IP_ADDRESS SrcAddr;
- EFI_IP_ADDRESS DstAddr;
- BOOLEAN SpdMatch;
-
- ASSERT (SpdEntry != NULL);
- SpdSel = SpdEntry->Selector;
- Ip4 = (IP4_HEAD *) IpHead;
- Ip6 = (EFI_IP6_HEADER *) IpHead;
-
- ZeroMem (&SrcAddr, sizeof (EFI_IP_ADDRESS));
- ZeroMem (&DstAddr, sizeof (EFI_IP_ADDRESS));
-
- //
- // Parse the source and destination address from ip header.
- //
- if (IpVersion == IP_VERSION_4) {
- CopyMem (&SrcAddr, &Ip4->Src, sizeof (IP4_ADDR));
- CopyMem (&DstAddr, &Ip4->Dst, sizeof (IP4_ADDR));
- } else {
- CopyMem (&SrcAddr, &Ip6->SourceAddress, sizeof (EFI_IPv6_ADDRESS));
- CopyMem (&DstAddr, &Ip6->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));
- }
- //
- // Check the local and remote addresses for outbound traffic
- //
- SpdMatch = (BOOLEAN)(IsOutbound &&
- IpSecMatchIpAddress (
- IpVersion,
- &SrcAddr,
- SpdSel->LocalAddress,
- SpdSel->LocalAddressCount
- ) &&
- IpSecMatchIpAddress (
- IpVersion,
- &DstAddr,
- SpdSel->RemoteAddress,
- SpdSel->RemoteAddressCount
- )
- );
-
- //
- // Check the local and remote addresses for inbound traffic
- //
- SpdMatch = (BOOLEAN) (SpdMatch ||
- (!IsOutbound &&
- IpSecMatchIpAddress (
- IpVersion,
- &DstAddr,
- SpdSel->LocalAddress,
- SpdSel->LocalAddressCount
- ) &&
- IpSecMatchIpAddress (
- IpVersion,
- &SrcAddr,
- SpdSel->RemoteAddress,
- SpdSel->RemoteAddressCount
- )
- ));
-
- //
- // Check the next layer protocol and local and remote ports.
- //
- SpdMatch = (BOOLEAN) (SpdMatch &&
- IpSecMatchNextLayerProtocol (
- Protocol,
- IpPayload,
- SpdSel->NextLayerProtocol,
- SpdSel->LocalPort,
- SpdSel->RemotePort,
- IsOutbound
- )
- );
-
- if (SpdMatch) {
- //
- // Find the right SPD entry if match the 5 key elements.
- //
- *Action = SpdEntry->Data->Action;
- return EFI_SUCCESS;
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- The call back function of NetbufFromExt.
-
- @param[in] Arg The argument passed from the caller.
-
-**/
-VOID
-EFIAPI
-IpSecOnRecyclePacket (
- IN VOID *Arg
- )
-{
-}
-
-/**
- This is a Notification function. It is called when the related IP6_TXTOKEN_WRAP
- is released.
-
- @param[in] Event The related event.
- @param[in] Context The data passed by the caller.
-
-**/
-VOID
-EFIAPI
-IpSecRecycleCallback (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- IPSEC_RECYCLE_CONTEXT *RecycleContext;
-
- RecycleContext = (IPSEC_RECYCLE_CONTEXT *) Context;
-
- if (RecycleContext->FragmentTable != NULL) {
- FreePool (RecycleContext->FragmentTable);
- }
-
- if (RecycleContext->PayloadBuffer != NULL) {
- FreePool (RecycleContext->PayloadBuffer);
- }
-
- FreePool (RecycleContext);
- gBS->CloseEvent (Event);
-
-}
-
-/**
- Calculate the extension hader of IP. The return length only doesn't contain
- the fixed IP header length.
-
- @param[in] IpHead Points to an IP head to be calculated.
- @param[in] LastHead Points to the last header of the IP header.
-
- @return The length of the extension header.
-
-**/
-UINT16
-IpSecGetPlainExtHeadSize (
- IN VOID *IpHead,
- IN UINT8 *LastHead
- )
-{
- UINT16 Size;
-
- Size = (UINT16) (LastHead - (UINT8 *) IpHead);
-
- if (Size > sizeof (EFI_IP6_HEADER)) {
- //
- // * (LastHead+1) point the last header's length but not include the first
- // 8 octers, so this formluation add 8 at the end.
- //
- Size = (UINT16) (Size - sizeof (EFI_IP6_HEADER) + *(LastHead + 1) + 8);
- } else {
- Size = 0;
- }
-
- return Size;
-}
-
-/**
- Verify if the Authentication payload is correct.
-
- @param[in] EspBuffer Points to the ESP wrapped buffer.
- @param[in] EspSize The size of the ESP wrapped buffer.
- @param[in] SadEntry The related SAD entry to store the authentication
- algorithm key.
- @param[in] IcvSize The length of ICV.
-
- @retval EFI_SUCCESS The authentication data is correct.
- @retval EFI_ACCESS_DENIED The authentication data is not correct.
-
-**/
-EFI_STATUS
-IpSecEspAuthVerifyPayload (
- IN UINT8 *EspBuffer,
- IN UINTN EspSize,
- IN IPSEC_SAD_ENTRY *SadEntry,
- IN UINTN IcvSize
- )
-{
- EFI_STATUS Status;
- UINTN AuthSize;
- UINT8 IcvBuffer[12];
- HASH_DATA_FRAGMENT HashFragment[1];
-
- //
- // Calculate the size of authentication payload.
- //
- AuthSize = EspSize - IcvSize;
-
- //
- // Calculate the icv buffer and size of the payload.
- //
- HashFragment[0].Data = EspBuffer;
- HashFragment[0].DataSize = AuthSize;
-
- Status = IpSecCryptoIoHmac (
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,
- HashFragment,
- 1,
- IcvBuffer,
- IcvSize
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Compare the calculated icv and the appended original icv.
- //
- if (CompareMem (EspBuffer + AuthSize, IcvBuffer, IcvSize) == 0) {
- return EFI_SUCCESS;
- }
-
- DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));
- return EFI_ACCESS_DENIED;
-}
-
-/**
- Search the related SAD entry by the input .
-
- @param[in] IpHead The pointer to IP header.
- @param[in] IpVersion The version of IP (IP4 or IP6).
- @param[in] Spi The SPI used to search the related SAD entry.
-
-
- @retval NULL Not find the related SAD entry.
- @retval IPSEC_SAD_ENTRY Return the related SAD entry.
-
-**/
-IPSEC_SAD_ENTRY *
-IpSecFoundSadFromInboundPacket (
- UINT8 *IpHead,
- UINT8 IpVersion,
- UINT32 Spi
- )
-{
- EFI_IP_ADDRESS DestIp;
-
- //
- // Parse destination address from ip header.
- //
- ZeroMem (&DestIp, sizeof (EFI_IP_ADDRESS));
- if (IpVersion == IP_VERSION_4) {
- CopyMem (
- &DestIp,
- &((IP4_HEAD *) IpHead)->Dst,
- sizeof (IP4_ADDR)
- );
- } else {
- CopyMem (
- &DestIp,
- &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
- sizeof (EFI_IPv6_ADDRESS)
- );
- }
-
- //
- // Lookup SAD entry according to the spi and dest address.
- //
- return IpSecLookupSadBySpi (Spi, &DestIp, IpVersion);
-}
-
-/**
- Validate the IP6 extension header format for both the packets we received
- and that we will transmit.
-
- @param[in] NextHeader The next header field in IPv6 basic header.
- @param[in] ExtHdrs The first bye of the option.
- @param[in] ExtHdrsLen The length of the whole option.
- @param[out] LastHeader The pointer of NextHeader of the last extension
- header processed by IP6.
- @param[out] RealExtsLen The length of extension headers processed by IP6 layer.
- This is an optional parameter that may be NULL.
-
- @retval TRUE The option is properly formated.
- @retval FALSE The option is malformated.
-
-**/
-BOOLEAN
-IpSecIsIp6ExtsValid (
- IN UINT8 *NextHeader,
- IN UINT8 *ExtHdrs,
- IN UINT32 ExtHdrsLen,
- OUT UINT8 **LastHeader,
- OUT UINT32 *RealExtsLen OPTIONAL
- )
-{
- UINT32 Pointer;
- UINT8 *Option;
- UINT8 OptionLen;
- UINT8 CountD;
- UINT8 CountF;
- UINT8 CountA;
-
- if (RealExtsLen != NULL) {
- *RealExtsLen = 0;
- }
-
- *LastHeader = NextHeader;
-
- if (ExtHdrs == NULL && ExtHdrsLen == 0) {
- return TRUE;
- }
-
- if ((ExtHdrs == NULL && ExtHdrsLen != 0) || (ExtHdrs != NULL && ExtHdrsLen == 0)) {
- return FALSE;
- }
-
- Pointer = 0;
- CountD = 0;
- CountF = 0;
- CountA = 0;
-
- while (Pointer <= ExtHdrsLen) {
-
- switch (*NextHeader) {
- case IP6_HOP_BY_HOP:
- if (Pointer != 0) {
- return FALSE;
- }
-
- //
- // Fall through
- //
- case IP6_DESTINATION:
- if (*NextHeader == IP6_DESTINATION) {
- CountD++;
- }
-
- if (CountD > 2) {
- return FALSE;
- }
-
- NextHeader = ExtHdrs + Pointer;
-
- Pointer++;
- Option = ExtHdrs + Pointer;
- OptionLen = (UINT8) ((*Option + 1) * 8 - 2);
- Option++;
- Pointer++;
-
- Pointer = Pointer + OptionLen;
- break;
-
- case IP6_FRAGMENT:
- if (++CountF > 1) {
- return FALSE;
- }
- //
- // RFC2402, AH header should after fragment header.
- //
- if (CountA > 1) {
- return FALSE;
- }
-
- NextHeader = ExtHdrs + Pointer;
- Pointer = Pointer + 8;
- break;
-
- case IP6_AH:
- if (++CountA > 1) {
- return FALSE;
- }
-
- Option = ExtHdrs + Pointer;
- NextHeader = Option;
- Option++;
- //
- // RFC2402, Payload length is specified in 32-bit words, minus "2".
- //
- OptionLen = (UINT8) ((*Option + 2) * 4);
- Pointer = Pointer + OptionLen;
- break;
-
- default:
- *LastHeader = NextHeader;
- if (RealExtsLen != NULL) {
- *RealExtsLen = Pointer;
- }
-
- return TRUE;
- }
- }
-
- *LastHeader = NextHeader;
-
- if (RealExtsLen != NULL) {
- *RealExtsLen = Pointer;
- }
-
- return TRUE;
-}
-
-/**
- The actual entry to process the tunnel header and inner header for tunnel mode
- outbound traffic.
-
- This function is the subfunction of IpSecEspInboundPacket(). It change the destination
- Ip address to the station address and recalculate the uplayyer's checksum.
-
-
- @param[in, out] IpHead Points to the IP header containing the ESP header
- to be trimed on input, and without ESP header
- on return.
- @param[in] IpPayload The decrypted Ip payload. It start from the inner
- header.
- @param[in] IpVersion The version of IP.
- @param[in] SadData Pointer of the relevant SAD.
- @param[in, out] LastHead The Last Header in IP header on return.
-
-**/
-VOID
-IpSecTunnelInboundPacket (
- IN OUT UINT8 *IpHead,
- IN UINT8 *IpPayload,
- IN UINT8 IpVersion,
- IN IPSEC_SAD_DATA *SadData,
- IN OUT UINT8 *LastHead
- )
-{
- EFI_UDP_HEADER *UdpHeader;
- TCP_HEAD *TcpHeader;
- UINT16 *Checksum;
- UINT16 PseudoChecksum;
- UINT16 PacketChecksum;
- UINT32 OptionLen;
- IP6_ICMP_HEAD *Icmp6Head;
-
- Checksum = NULL;
-
- if (IpVersion == IP_VERSION_4) {
- //
- // Zero OutIP header use this to indicate the input packet is under
- // IPsec Tunnel protected.
- //
- ZeroMem (
- (IP4_HEAD *)IpHead,
- sizeof (IP4_HEAD)
- );
- CopyMem (
- &((IP4_HEAD *)IpPayload)->Dst,
- &SadData->TunnelDestAddress.v4,
- sizeof (EFI_IPv4_ADDRESS)
- );
-
- //
- // Recalculate IpHeader Checksum
- //
- if (((IP4_HEAD *)(IpPayload))->Checksum != 0 ) {
- ((IP4_HEAD *)(IpPayload))->Checksum = 0;
- ((IP4_HEAD *)(IpPayload))->Checksum = (UINT16) (~NetblockChecksum (
- (UINT8 *)IpPayload,
- ((IP4_HEAD *)IpPayload)->HeadLen << 2
- ));
-
-
- }
-
- //
- // Recalcualte PseudoChecksum
- //
- switch (((IP4_HEAD *)IpPayload)->Protocol) {
- case EFI_IP_PROTO_UDP :
- UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));
- Checksum = & UdpHeader->Checksum;
- *Checksum = 0;
- break;
-
- case EFI_IP_PROTO_TCP:
- TcpHeader = (TCP_HEAD *) ((UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2));
- Checksum = &TcpHeader->Checksum;
- *Checksum = 0;
- break;
-
- default:
- break;
- }
- PacketChecksum = NetblockChecksum (
- (UINT8 *)IpPayload + (((IP4_HEAD *)IpPayload)->HeadLen << 2),
- NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)
- );
- PseudoChecksum = NetPseudoHeadChecksum (
- ((IP4_HEAD *)IpPayload)->Src,
- ((IP4_HEAD *)IpPayload)->Dst,
- ((IP4_HEAD *)IpPayload)->Protocol,
- 0
- );
-
- if (Checksum != NULL) {
- *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
- *Checksum = (UINT16) ~(NetAddChecksum (*Checksum, HTONS((UINT16)(NTOHS (((IP4_HEAD *)IpPayload)->TotalLen) - (((IP4_HEAD *)IpPayload)->HeadLen << 2)))));
- }
- }else {
- //
- // Zero OutIP header use this to indicate the input packet is under
- // IPsec Tunnel protected.
- //
- ZeroMem (
- IpHead,
- sizeof (EFI_IP6_HEADER)
- );
- CopyMem (
- &((EFI_IP6_HEADER*)IpPayload)->DestinationAddress,
- &SadData->TunnelDestAddress.v6,
- sizeof (EFI_IPv6_ADDRESS)
- );
-
- //
- // Get the Extension Header and Header length.
- //
- IpSecIsIp6ExtsValid (
- &((EFI_IP6_HEADER *)IpPayload)->NextHeader,
- IpPayload + sizeof (EFI_IP6_HEADER),
- ((EFI_IP6_HEADER *)IpPayload)->PayloadLength,
- &LastHead,
- &OptionLen
- );
-
- //
- // Recalcualte PseudoChecksum
- //
- switch (*LastHead) {
- case EFI_IP_PROTO_UDP:
- UdpHeader = (EFI_UDP_HEADER *)((UINT8 *)IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
- Checksum = &UdpHeader->Checksum;
- *Checksum = 0;
- break;
-
- case EFI_IP_PROTO_TCP:
- TcpHeader = (TCP_HEAD *)(IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
- Checksum = &TcpHeader->Checksum;
- *Checksum = 0;
- break;
-
- case IP6_ICMP:
- Icmp6Head = (IP6_ICMP_HEAD *) (IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen);
- Checksum = &Icmp6Head->Checksum;
- *Checksum = 0;
- break;
- }
- PacketChecksum = NetblockChecksum (
- IpPayload + sizeof (EFI_IP6_HEADER) + OptionLen,
- NTOHS(((EFI_IP6_HEADER *)IpPayload)->PayloadLength) - OptionLen
- );
- PseudoChecksum = NetIp6PseudoHeadChecksum (
- &((EFI_IP6_HEADER *)IpPayload)->SourceAddress,
- &((EFI_IP6_HEADER *)IpPayload)->DestinationAddress,
- *LastHead,
- 0
- );
-
- if (Checksum != NULL) {
- *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
- *Checksum = (UINT16) ~(NetAddChecksum (
- *Checksum,
- HTONS ((UINT16)((NTOHS (((EFI_IP6_HEADER *)(IpPayload))->PayloadLength)) - OptionLen))
- ));
- }
- }
-}
-
-/**
- The actual entry to create inner header for tunnel mode inbound traffic.
-
- This function is the subfunction of IpSecEspOutboundPacket(). It create
- the sending packet by encrypting its payload and inserting ESP header in the orginal
- IP header, then return the IpHeader and IPsec protected Fragmentable.
-
- @param[in, out] IpHead Points to IP header containing the orginal IP header
- to be processed on input, and inserted ESP header
- on return.
- @param[in] IpVersion The version of IP.
- @param[in] SadData The related SAD data.
- @param[in, out] LastHead The Last Header in IP header.
- @param[in] OptionsBuffer Pointer to the options buffer.
- @param[in] OptionsLength Length of the options buffer.
- @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
- IPsec on input, and with IPsec protected
- on return.
- @param[in] FragmentCount The number of fragments.
-
-**/
-UINT8 *
-IpSecTunnelOutboundPacket (
- IN OUT UINT8 *IpHead,
- IN UINT8 IpVersion,
- IN IPSEC_SAD_DATA *SadData,
- IN OUT UINT8 *LastHead,
- IN VOID **OptionsBuffer,
- IN UINT32 *OptionsLength,
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
- IN UINT32 *FragmentCount
- )
-{
- UINT8 *InnerHead;
- NET_BUF *Packet;
- UINT16 PacketChecksum;
- UINT16 *Checksum;
- UINT16 PseudoChecksum;
- IP6_ICMP_HEAD *IcmpHead;
-
- Checksum = NULL;
- if (OptionsLength == NULL) {
- return NULL;
- }
-
- if (IpVersion == IP_VERSION_4) {
- InnerHead = AllocateZeroPool (sizeof (IP4_HEAD) + *OptionsLength);
- if (InnerHead == NULL) {
- return NULL;
- }
-
- CopyMem (
- InnerHead,
- IpHead,
- sizeof (IP4_HEAD)
- );
- CopyMem (
- InnerHead + sizeof (IP4_HEAD),
- *OptionsBuffer,
- *OptionsLength
- );
- } else {
- InnerHead = AllocateZeroPool (sizeof (EFI_IP6_HEADER) + *OptionsLength);
- if (InnerHead == NULL) {
- return NULL;
- }
-
- CopyMem (
- InnerHead,
- IpHead,
- sizeof (EFI_IP6_HEADER)
- );
- CopyMem (
- InnerHead + sizeof (EFI_IP6_HEADER),
- *OptionsBuffer,
- *OptionsLength
- );
- }
- if (OptionsBuffer != NULL) {
- if (*OptionsLength != 0) {
-
- *OptionsBuffer = NULL;
- *OptionsLength = 0;
- }
- }
-
- //
- // 2. Reassamlbe Fragment into Packet
- //
- Packet = NetbufFromExt (
- (NET_FRAGMENT *)(*FragmentTable),
- *FragmentCount,
- 0,
- 0,
- IpSecOnRecyclePacket,
- NULL
- );
- if (Packet == NULL) {
- FreePool (InnerHead);
- return NULL;
- }
-
- //
- // 3. Check the Last Header, if it is TCP, UDP or ICMP recalcualate its pesudo
- // CheckSum.
- //
- switch (*LastHead) {
- case EFI_IP_PROTO_UDP:
- Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, 0);
- ASSERT (Packet->Udp != NULL);
- Checksum = &Packet->Udp->Checksum;
- *Checksum = 0;
- break;
-
- case EFI_IP_PROTO_TCP:
- Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, 0);
- ASSERT (Packet->Tcp != NULL);
- Checksum = &Packet->Tcp->Checksum;
- *Checksum = 0;
- break;
-
- case IP6_ICMP:
- IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL);
- ASSERT (IcmpHead != NULL);
- Checksum = &IcmpHead->Checksum;
- *Checksum = 0;
- break;
-
- default:
- break;
- }
-
- PacketChecksum = NetbufChecksum (Packet);
-
- if (IpVersion == IP_VERSION_4) {
- //
- // Replace the source address of Inner Header.
- //
- CopyMem (
- &((IP4_HEAD *)InnerHead)->Src,
- &SadData->SpdSelector->LocalAddress[0].Address.v4,
- sizeof (EFI_IPv4_ADDRESS)
- );
-
- PacketChecksum = NetbufChecksum (Packet);
- PseudoChecksum = NetPseudoHeadChecksum (
- ((IP4_HEAD *)InnerHead)->Src,
- ((IP4_HEAD *)InnerHead)->Dst,
- *LastHead,
- 0
- );
-
- } else {
- //
- // Replace the source address of Inner Header.
- //
- CopyMem (
- &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
- &(SadData->SpdSelector->LocalAddress[0].Address.v6),
- sizeof (EFI_IPv6_ADDRESS)
- );
- PacketChecksum = NetbufChecksum (Packet);
- PseudoChecksum = NetIp6PseudoHeadChecksum (
- &((EFI_IP6_HEADER *)InnerHead)->SourceAddress,
- &((EFI_IP6_HEADER *)InnerHead)->DestinationAddress,
- *LastHead,
- 0
- );
-
- }
- if (Checksum != NULL) {
- *Checksum = NetAddChecksum (PacketChecksum, PseudoChecksum);
- *Checksum = (UINT16) ~(NetAddChecksum ((UINT16)*Checksum, HTONS ((UINT16) Packet->TotalSize)));
- }
-
- if (Packet != NULL) {
- NetbufFree (Packet);
- }
- return InnerHead;
-}
-
-/**
- The actual entry to relative function processes the inbound traffic of ESP header.
-
- This function is the subfunction of IpSecProtectInboundPacket(). It checks the
- received packet security property and trim the ESP header and then returns without
- an IPsec protected IP Header and FramgmentTable.
-
- @param[in] IpVersion The version of IP.
- @param[in, out] IpHead Points to the IP header containing the ESP header
- to be trimed on input, and without ESP header
- on return.
- @param[out] LastHead The Last Header in IP header on return.
- @param[in, out] OptionsBuffer Pointer to the options buffer.
- @param[in, out] OptionsLength Length of the options buffer.
- @param[in, out] FragmentTable Pointer to a list of fragments in the form of IPsec
- protected on input, and without IPsec protected
- on return.
- @param[in, out] FragmentCount The number of fragments.
- @param[out] SpdSelector Pointer to contain the address of SPD selector on return.
- @param[out] RecycleEvent The event for recycling of resources.
-
- @retval EFI_SUCCESS The operation was successful.
- @retval EFI_ACCESS_DENIED One or more following conditions is TRUE:
- - ESP header was not found or mal-format.
- - The related SAD entry was not found.
- - The related SAD entry does not support the ESP protocol.
- @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.
-
-**/
-EFI_STATUS
-IpSecEspInboundPacket (
- IN UINT8 IpVersion,
- IN OUT VOID *IpHead,
- OUT UINT8 *LastHead,
- IN OUT VOID **OptionsBuffer,
- IN OUT UINT32 *OptionsLength,
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
- IN OUT UINT32 *FragmentCount,
- OUT EFI_IPSEC_SPD_SELECTOR **SpdSelector,
- OUT EFI_EVENT *RecycleEvent
- )
-{
- EFI_STATUS Status;
- NET_BUF *Payload;
- UINTN EspSize;
- UINTN IvSize;
- UINTN BlockSize;
- UINTN MiscSize;
- UINTN PlainPayloadSize;
- UINTN PaddingSize;
- UINTN IcvSize;
- UINT8 *ProcessBuffer;
- EFI_ESP_HEADER *EspHeader;
- EFI_ESP_TAIL *EspTail;
- EFI_IPSEC_SA_ID *SaId;
- IPSEC_SAD_DATA *SadData;
- IPSEC_SAD_ENTRY *SadEntry;
- IPSEC_RECYCLE_CONTEXT *RecycleContext;
- UINT8 NextHeader;
- UINT16 IpSecHeadSize;
- UINT8 *InnerHead;
-
- Status = EFI_SUCCESS;
- Payload = NULL;
- ProcessBuffer = NULL;
- RecycleContext = NULL;
- *RecycleEvent = NULL;
- PlainPayloadSize = 0;
- NextHeader = 0;
-
- //
- // Build netbuf from fragment table first.
- //
- Payload = NetbufFromExt (
- (NET_FRAGMENT *) *FragmentTable,
- *FragmentCount,
- 0,
- sizeof (EFI_ESP_HEADER),
- IpSecOnRecyclePacket,
- NULL
- );
- if (Payload == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
-
- //
- // Get the esp size and esp header from netbuf.
- //
- EspSize = Payload->TotalSize;
- EspHeader = (EFI_ESP_HEADER *) NetbufGetByte (Payload, 0, NULL);
-
- if (EspHeader == NULL) {
- Status = EFI_ACCESS_DENIED;
- goto ON_EXIT;
- }
-
- //
- // Parse destination address from ip header and found the related SAD Entry.
- //
- SadEntry = IpSecFoundSadFromInboundPacket (
- IpHead,
- IpVersion,
- NTOHL (EspHeader->Spi)
- );
-
- if (SadEntry == NULL) {
- Status = EFI_ACCESS_DENIED;
- goto ON_EXIT;
- }
-
- SaId = SadEntry->Id;
- SadData = SadEntry->Data;
-
- //
- // Only support esp protocol currently.
- //
- if (SaId->Proto != EfiIPsecESP) {
- Status = EFI_ACCESS_DENIED;
- goto ON_EXIT;
- }
-
- if (!SadData->ManualSet) {
- //
- // TODO: Check SA lifetime and sequence number
- //
- }
-
- //
- // Allocate buffer for decryption and authentication.
- //
- ProcessBuffer = AllocateZeroPool (EspSize);
- if (ProcessBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
-
- NetbufCopy (Payload, 0, (UINT32) EspSize, ProcessBuffer);
-
- //
- // Get the IcvSize for authentication and BlockSize/IvSize for Decryption.
- //
- IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
- IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
- BlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
-
- //
- // Make sure the ESP packet is not mal-formt.
- // 1. Check whether the Espsize is larger than ESP header + IvSize + EspTail + IcvSize.
- // 2. Check whether the left payload size is multiple of IvSize.
- //
- MiscSize = sizeof (EFI_ESP_HEADER) + IvSize + IcvSize;
- if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL))) {
- Status = EFI_ACCESS_DENIED;
- goto ON_EXIT;
- }
- if ((EspSize - MiscSize) % BlockSize != 0) {
- Status = EFI_ACCESS_DENIED;
- goto ON_EXIT;
- }
-
- //
- // Authenticate the ESP packet.
- //
- if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
- Status = IpSecEspAuthVerifyPayload (
- ProcessBuffer,
- EspSize,
- SadEntry,
- IcvSize
- );
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
- }
- //
- // Decrypt the payload by the SAD entry if it has decrypt key.
- //
- if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
- Status = IpSecCryptoIoDecrypt (
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
- ProcessBuffer + sizeof (EFI_ESP_HEADER),
- ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize,
- EspSize - sizeof (EFI_ESP_HEADER) - IvSize - IcvSize,
- ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize
- );
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
- }
-
- //
- // Parse EspTail and compute the plain payload size.
- //
- EspTail = (EFI_ESP_TAIL *) (ProcessBuffer + EspSize - IcvSize - sizeof (EFI_ESP_TAIL));
- PaddingSize = EspTail->PaddingLength;
- NextHeader = EspTail->NextHeader;
-
- if (EspSize <= (MiscSize + sizeof (EFI_ESP_TAIL) + PaddingSize)) {
- Status = EFI_ACCESS_DENIED;
- goto ON_EXIT;
- }
- PlainPayloadSize = EspSize - MiscSize - sizeof (EFI_ESP_TAIL) - PaddingSize;
-
- //
- // TODO: handle anti-replay window
- //
- //
- // Decryption and authentication with esp has been done, so it's time to
- // reload the new packet, create recycle event and fixup ip header.
- //
- RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
- if (RecycleContext == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
-
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- IpSecRecycleCallback,
- RecycleContext,
- RecycleEvent
- );
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
-
- //
- // The caller will take responsible to handle the original fragment table
- //
- *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
- if (*FragmentTable == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
-
- RecycleContext->PayloadBuffer = ProcessBuffer;
- RecycleContext->FragmentTable = *FragmentTable;
-
- //
- // If Tunnel, recalculate upper-layyer PesudoCheckSum and trim the out
- //
- if (SadData->Mode == EfiIPsecTunnel) {
- InnerHead = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
- IpSecTunnelInboundPacket (
- IpHead,
- InnerHead,
- IpVersion,
- SadData,
- LastHead
- );
-
- if (IpVersion == IP_VERSION_4) {
- (*FragmentTable)[0].FragmentBuffer = InnerHead ;
- (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;
-
- }else {
- (*FragmentTable)[0].FragmentBuffer = InnerHead;
- (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;
- }
- } else {
- (*FragmentTable)[0].FragmentBuffer = ProcessBuffer + sizeof (EFI_ESP_HEADER) + IvSize;
- (*FragmentTable)[0].FragmentLength = (UINT32) PlainPayloadSize;
- }
-
- *FragmentCount = 1;
-
- //
- // Update the total length field in ip header since processed by esp.
- //
- if (SadData->Mode != EfiIPsecTunnel) {
- if (IpVersion == IP_VERSION_4) {
- ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + PlainPayloadSize));
- } else {
- IpSecHeadSize = IpSecGetPlainExtHeadSize (IpHead, LastHead);
- ((EFI_IP6_HEADER *) IpHead)->PayloadLength = HTONS ((UINT16)(IpSecHeadSize + PlainPayloadSize));
- }
- //
- // Update the next layer field in ip header since esp header inserted.
- //
- *LastHead = NextHeader;
- }
-
-
- //
- // Update the SPD association of the SAD entry.
- //
- *SpdSelector = SadData->SpdSelector;
-
-ON_EXIT:
- if (Payload != NULL) {
- NetbufFree (Payload);
- }
-
- if (EFI_ERROR (Status)) {
- if (ProcessBuffer != NULL) {
- FreePool (ProcessBuffer);
- }
-
- if (RecycleContext != NULL) {
- FreePool (RecycleContext);
- }
-
- if (*RecycleEvent != NULL) {
- gBS->CloseEvent (*RecycleEvent);
- }
- }
-
- return Status;
-}
-
-/**
- The actual entry to the relative function processes the output traffic using the ESP protocol.
-
- This function is the subfunction of IpSecProtectOutboundPacket(). It protected
- the sending packet by encrypting its payload and inserting ESP header in the orginal
- IP header, then return the IpHeader and IPsec protected Fragmentable.
-
- @param[in] IpVersion The version of IP.
- @param[in, out] IpHead Points to IP header containing the orginal IP header
- to be processed on input, and inserted ESP header
- on return.
- @param[in, out] LastHead The Last Header in IP header.
- @param[in, out] OptionsBuffer Pointer to the options buffer.
- @param[in, out] OptionsLength Length of the options buffer.
- @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
- IPsec on input, and with IPsec protected
- on return.
- @param[in, out] FragmentCount The number of fragments.
- @param[in] SadEntry The related SAD entry.
- @param[out] RecycleEvent The event for recycling of resources.
-
- @retval EFI_SUCCESS The operation was successful.
- @retval EFI_OUT_OF_RESOURCES The required system resources can't be allocated.
-
-**/
-EFI_STATUS
-IpSecEspOutboundPacket (
- IN UINT8 IpVersion,
- IN OUT VOID *IpHead,
- IN OUT UINT8 *LastHead,
- IN OUT VOID **OptionsBuffer,
- IN OUT UINT32 *OptionsLength,
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
- IN OUT UINT32 *FragmentCount,
- IN IPSEC_SAD_ENTRY *SadEntry,
- OUT EFI_EVENT *RecycleEvent
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- EFI_IPSEC_SA_ID *SaId;
- IPSEC_SAD_DATA *SadData;
- IPSEC_RECYCLE_CONTEXT *RecycleContext;
- UINT8 *ProcessBuffer;
- UINTN BytesCopied;
- INTN EncryptBlockSize;// Size of encryption block, 4 bytes aligned and >= 4
- UINTN EspSize; // Total size of esp wrapped ip payload
- UINTN IvSize; // Size of IV, optional, might be 0
- UINTN PlainPayloadSize;// Original IP payload size
- UINTN PaddingSize; // Size of padding
- UINTN EncryptSize; // Size of data to be encrypted, start after IV and
- // stop before ICV
- UINTN IcvSize; // Size of ICV, optional, might be 0
- UINT8 *RestOfPayload; // Start of Payload after IV
- UINT8 *Padding; // Start address of padding
- EFI_ESP_HEADER *EspHeader; // Start address of ESP frame
- EFI_ESP_TAIL *EspTail; // Address behind padding
- UINT8 *InnerHead;
- HASH_DATA_FRAGMENT HashFragment[1];
-
- Status = EFI_ACCESS_DENIED;
- SaId = SadEntry->Id;
- SadData = SadEntry->Data;
- ProcessBuffer = NULL;
- RecycleContext = NULL;
- *RecycleEvent = NULL;
- InnerHead = NULL;
-
- if (!SadData->ManualSet &&
- SadData->AlgoInfo.EspAlgoInfo.EncKey == NULL &&
- SadData->AlgoInfo.EspAlgoInfo.AuthKey == NULL
- ) {
- //
- // Invalid manual SAD entry configuration.
- //
- goto ON_EXIT;
- }
-
- //
- // Create OutHeader according to Inner Header
- //
- if (SadData->Mode == EfiIPsecTunnel) {
- InnerHead = IpSecTunnelOutboundPacket (
- IpHead,
- IpVersion,
- SadData,
- LastHead,
- OptionsBuffer,
- OptionsLength,
- FragmentTable,
- FragmentCount
- );
-
- if (InnerHead == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- }
-
- //
- // Calculate enctrypt block size, need iv by default and 4 bytes alignment.
- //
- EncryptBlockSize = 4;
-
- if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
- EncryptBlockSize = IpSecGetEncryptBlockSize (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
-
- if (EncryptBlockSize < 0 || (EncryptBlockSize != 1 && EncryptBlockSize % 4 != 0)) {
- goto ON_EXIT;
- }
- }
-
- //
- // Calculate the plain payload size according to the fragment table.
- //
- PlainPayloadSize = 0;
- for (Index = 0; Index < *FragmentCount; Index++) {
- PlainPayloadSize += (*FragmentTable)[Index].FragmentLength;
- }
-
- //
- // Add IPHeader size for Tunnel Mode
- //
- if (SadData->Mode == EfiIPsecTunnel) {
- if (IpVersion == IP_VERSION_4) {
- PlainPayloadSize += sizeof (IP4_HEAD);
- } else {
- PlainPayloadSize += sizeof (EFI_IP6_HEADER);
- }
- //
- // OPtions should be encryption into it
- //
- PlainPayloadSize += *OptionsLength;
- }
-
-
- //
- // Calculate icv size, optional by default and 4 bytes alignment.
- //
- IcvSize = 0;
- if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
- IcvSize = IpSecGetIcvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId);
- if (IcvSize % 4 != 0) {
- goto ON_EXIT;
- }
- }
-
- //
- // Calcuate the total size of esp wrapped ip payload.
- //
- IvSize = IpSecGetEncryptIvLength (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId);
- EncryptSize = (PlainPayloadSize + sizeof (EFI_ESP_TAIL) + EncryptBlockSize - 1) / EncryptBlockSize * EncryptBlockSize;
- PaddingSize = EncryptSize - PlainPayloadSize - sizeof (EFI_ESP_TAIL);
- EspSize = sizeof (EFI_ESP_HEADER) + IvSize + EncryptSize + IcvSize;
-
- ProcessBuffer = AllocateZeroPool (EspSize);
- if (ProcessBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
-
- //
- // Calculate esp header and esp tail including header, payload and padding.
- //
- EspHeader = (EFI_ESP_HEADER *) ProcessBuffer;
- RestOfPayload = (UINT8 *) (EspHeader + 1) + IvSize;
- Padding = RestOfPayload + PlainPayloadSize;
- EspTail = (EFI_ESP_TAIL *) (Padding + PaddingSize);
-
- //
- // Fill the sn and spi fields in esp header.
- //
- EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber + 1);
- //EspHeader->SequenceNumber = HTONL ((UINT32) SadData->SequenceNumber);
- EspHeader->Spi = HTONL (SaId->Spi);
-
- //
- // Copy the rest of payload (after iv) from the original fragment buffer.
- //
- BytesCopied = 0;
-
- //
- // For Tunnel Mode
- //
- if (SadData->Mode == EfiIPsecTunnel) {
- if (IpVersion == IP_VERSION_4) {
- //
- // HeadLen, Total Length
- //
- ((IP4_HEAD *)InnerHead)->HeadLen = (UINT8) ((sizeof (IP4_HEAD) + *OptionsLength) >> 2);
- ((IP4_HEAD *)InnerHead)->TotalLen = HTONS ((UINT16) PlainPayloadSize);
- ((IP4_HEAD *)InnerHead)->Checksum = 0;
- ((IP4_HEAD *)InnerHead)->Checksum = (UINT16) (~NetblockChecksum (
- (UINT8 *)InnerHead,
- sizeof(IP4_HEAD)
- ));
- CopyMem (
- RestOfPayload + BytesCopied,
- InnerHead,
- sizeof (IP4_HEAD) + *OptionsLength
- );
- BytesCopied += sizeof (IP4_HEAD) + *OptionsLength;
-
- } else {
- ((EFI_IP6_HEADER *)InnerHead)->PayloadLength = HTONS ((UINT16) (PlainPayloadSize - sizeof (EFI_IP6_HEADER)));
- CopyMem (
- RestOfPayload + BytesCopied,
- InnerHead,
- sizeof (EFI_IP6_HEADER) + *OptionsLength
- );
- BytesCopied += sizeof (EFI_IP6_HEADER) + *OptionsLength;
- }
- }
-
- for (Index = 0; Index < *FragmentCount; Index++) {
- CopyMem (
- (RestOfPayload + BytesCopied),
- (*FragmentTable)[Index].FragmentBuffer,
- (*FragmentTable)[Index].FragmentLength
- );
- BytesCopied += (*FragmentTable)[Index].FragmentLength;
- }
- //
- // Fill the padding buffer by natural number sequence.
- //
- for (Index = 0; Index < PaddingSize; Index++) {
- Padding[Index] = (UINT8) (Index + 1);
- }
- //
- // Fill the padding length and next header fields in esp tail.
- //
- EspTail->PaddingLength = (UINT8) PaddingSize;
- EspTail->NextHeader = *LastHead;
-
- //
- // Fill the next header for Tunnel mode.
- //
- if (SadData->Mode == EfiIPsecTunnel) {
- if (IpVersion == IP_VERSION_4) {
- EspTail->NextHeader = 4;
- } else {
- EspTail->NextHeader = 41;
- }
- }
-
- //
- // Generate iv at random by crypt library.
- //
- Status = IpSecGenerateIv (
- (UINT8 *) (EspHeader + 1),
- IvSize
- );
-
-
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
-
- //
- // Encryption the payload (after iv) by the SAD entry if has encrypt key.
- //
- if (SadData->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
- Status = IpSecCryptoIoEncrypt (
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId,
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
- SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength << 3,
- (UINT8 *)(EspHeader + 1),
- RestOfPayload,
- EncryptSize,
- RestOfPayload
- );
-
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
- }
-
- //
- // Authenticate the esp wrapped buffer by the SAD entry if it has auth key.
- //
- if (SadData->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
-
- HashFragment[0].Data = ProcessBuffer;
- HashFragment[0].DataSize = EspSize - IcvSize;
- Status = IpSecCryptoIoHmac (
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId,
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
- SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength,
- HashFragment,
- 1,
- ProcessBuffer + EspSize - IcvSize,
- IcvSize
- );
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
- }
-
- //
- // Encryption and authentication with esp has been done, so it's time to
- // reload the new packet, create recycle event and fixup ip header.
- //
- RecycleContext = AllocateZeroPool (sizeof (IPSEC_RECYCLE_CONTEXT));
- if (RecycleContext == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
-
- Status = gBS->CreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- IpSecRecycleCallback,
- RecycleContext,
- RecycleEvent
- );
- if (EFI_ERROR (Status)) {
- goto ON_EXIT;
- }
- //
- // Caller take responsible to handle the original fragment table.
- //
- *FragmentTable = AllocateZeroPool (sizeof (EFI_IPSEC_FRAGMENT_DATA));
- if (*FragmentTable == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto ON_EXIT;
- }
-
- RecycleContext->FragmentTable = *FragmentTable;
- RecycleContext->PayloadBuffer = ProcessBuffer;
- (*FragmentTable)[0].FragmentBuffer = ProcessBuffer;
- (*FragmentTable)[0].FragmentLength = (UINT32) EspSize;
- *FragmentCount = 1;
-
- //
- // Update the total length field in ip header since processed by esp.
- //
- if (IpVersion == IP_VERSION_4) {
- ((IP4_HEAD *) IpHead)->TotalLen = HTONS ((UINT16) ((((IP4_HEAD *) IpHead)->HeadLen << 2) + EspSize));
- } else {
- ((EFI_IP6_HEADER *) IpHead)->PayloadLength = (UINT16) (IpSecGetPlainExtHeadSize (IpHead, LastHead) + EspSize);
- }
-
- //
- // If tunnel mode, it should change the outer Ip header with tunnel source address
- // and destination tunnel address.
- //
- if (SadData->Mode == EfiIPsecTunnel) {
- if (IpVersion == IP_VERSION_4) {
- CopyMem (
- &((IP4_HEAD *) IpHead)->Src,
- &SadData->TunnelSourceAddress.v4,
- sizeof (EFI_IPv4_ADDRESS)
- );
- CopyMem (
- &((IP4_HEAD *) IpHead)->Dst,
- &SadData->TunnelDestAddress.v4,
- sizeof (EFI_IPv4_ADDRESS)
- );
- } else {
- CopyMem (
- &((EFI_IP6_HEADER *) IpHead)->SourceAddress,
- &SadData->TunnelSourceAddress.v6,
- sizeof (EFI_IPv6_ADDRESS)
- );
- CopyMem (
- &((EFI_IP6_HEADER *) IpHead)->DestinationAddress,
- &SadData->TunnelDestAddress.v6,
- sizeof (EFI_IPv6_ADDRESS)
- );
- }
- }
-
- //
- // Update the next layer field in ip header since esp header inserted.
- //
- *LastHead = IPSEC_ESP_PROTOCOL;
-
- //
- // Increase the sn number in SAD entry according to rfc4303.
- //
- SadData->SequenceNumber++;
-
-ON_EXIT:
- if (EFI_ERROR (Status)) {
- if (ProcessBuffer != NULL) {
- FreePool (ProcessBuffer);
- }
-
- if (RecycleContext != NULL) {
- FreePool (RecycleContext);
- }
-
- if (*RecycleEvent != NULL) {
- gBS->CloseEvent (*RecycleEvent);
- }
- }
-
- return Status;
-}
-
-/**
- This function processes the inbound traffic with IPsec.
-
- It checks the received packet security property, trims the ESP/AH header, and then
- returns without an IPsec protected IP Header and FragmentTable.
-
- @param[in] IpVersion The version of IP.
- @param[in, out] IpHead Points to IP header containing the ESP/AH header
- to be trimed on input, and without ESP/AH header
- on return.
- @param[in, out] LastHead The Last Header in IP header on return.
- @param[in, out] OptionsBuffer Pointer to the options buffer.
- @param[in, out] OptionsLength Length of the options buffer.
- @param[in, out] FragmentTable Pointer to a list of fragments in form of IPsec
- protected on input, and without IPsec protected
- on return.
- @param[in, out] FragmentCount The number of fragments.
- @param[out] SpdEntry Pointer to contain the address of SPD entry on return.
- @param[out] RecycleEvent The event for recycling of resources.
-
- @retval EFI_SUCCESS The operation was successful.
- @retval EFI_UNSUPPORTED The IPSEC protocol is not supported.
-
-**/
-EFI_STATUS
-IpSecProtectInboundPacket (
- IN UINT8 IpVersion,
- IN OUT VOID *IpHead,
- IN OUT UINT8 *LastHead,
- IN OUT VOID **OptionsBuffer,
- IN OUT UINT32 *OptionsLength,
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
- IN OUT UINT32 *FragmentCount,
- OUT EFI_IPSEC_SPD_SELECTOR **SpdEntry,
- OUT EFI_EVENT *RecycleEvent
- )
-{
- if (*LastHead == IPSEC_ESP_PROTOCOL) {
- //
- // Process the esp ipsec header of the inbound traffic.
- //
- return IpSecEspInboundPacket (
- IpVersion,
- IpHead,
- LastHead,
- OptionsBuffer,
- OptionsLength,
- FragmentTable,
- FragmentCount,
- SpdEntry,
- RecycleEvent
- );
- }
- //
- // The other protocols are not supported.
- //
- return EFI_UNSUPPORTED;
-}
-
-/**
- This fucntion processes the output traffic with IPsec.
-
- It protected the sending packet by encrypting it payload and inserting ESP/AH header
- in the orginal IP header, then return the IpHeader and IPsec protected Fragmentable.
-
- @param[in] IpVersion The version of IP.
- @param[in, out] IpHead Point to IP header containing the orginal IP header
- to be processed on input, and inserted ESP/AH header
- on return.
- @param[in, out] LastHead The Last Header in IP header.
- @param[in, out] OptionsBuffer Pointer to the options buffer.
- @param[in, out] OptionsLength Length of the options buffer.
- @param[in, out] FragmentTable Pointer to a list of fragments to be protected by
- IPsec on input, and with IPsec protected
- on return.
- @param[in, out] FragmentCount Number of fragments.
- @param[in] SadEntry Related SAD entry.
- @param[out] RecycleEvent Event for recycling of resources.
-
- @retval EFI_SUCCESS The operation is successful.
- @retval EFI_UNSUPPORTED If the IPSEC protocol is not supported.
-
-**/
-EFI_STATUS
-IpSecProtectOutboundPacket (
- IN UINT8 IpVersion,
- IN OUT VOID *IpHead,
- IN OUT UINT8 *LastHead,
- IN OUT VOID **OptionsBuffer,
- IN OUT UINT32 *OptionsLength,
- IN OUT EFI_IPSEC_FRAGMENT_DATA **FragmentTable,
- IN OUT UINT32 *FragmentCount,
- IN IPSEC_SAD_ENTRY *SadEntry,
- OUT EFI_EVENT *RecycleEvent
- )
-{
- if (SadEntry->Id->Proto == EfiIPsecESP) {
- //
- // Process the esp ipsec header of the outbound traffic.
- //
- return IpSecEspOutboundPacket (
- IpVersion,
- IpHead,
- LastHead,
- OptionsBuffer,
- OptionsLength,
- FragmentTable,
- FragmentCount,
- SadEntry,
- RecycleEvent
- );
- }
- //
- // The other protocols are not supported.
- //
- return EFI_UNSUPPORTED;
-}