summaryrefslogtreecommitdiff
path: root/Core/NetworkPkg/IpSecDxe
diff options
context:
space:
mode:
Diffstat (limited to 'Core/NetworkPkg/IpSecDxe')
-rw-r--r--Core/NetworkPkg/IpSecDxe/ComponentName.c351
-rw-r--r--Core/NetworkPkg/IpSecDxe/IetfConstants.c388
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ike.h266
-rw-r--r--Core/NetworkPkg/IpSecDxe/IkeCommon.c254
-rw-r--r--Core/NetworkPkg/IpSecDxe/IkeCommon.h189
-rw-r--r--Core/NetworkPkg/IpSecDxe/IkePacket.c265
-rw-r--r--Core/NetworkPkg/IpSecDxe/IkePacket.h82
-rw-r--r--Core/NetworkPkg/IpSecDxe/IkeService.c794
-rw-r--r--Core/NetworkPkg/IpSecDxe/IkeService.h262
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c199
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Exchange.c809
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Ikev2.h258
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Info.c402
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Payload.c3369
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Payload.h438
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Sa.c2262
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Utility.c2787
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Utility.h1134
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecConfigImpl.c3138
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecConfigImpl.h955
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecCryptIo.c1021
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecCryptIo.h827
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecDebug.c334
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecDebug.h107
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecDriver.c665
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecDxe.inf110
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecDxe.unibin0 -> 2676 bytes
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecDxeExtra.unibin0 -> 1318 bytes
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecImpl.c2184
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecImpl.h390
-rw-r--r--Core/NetworkPkg/IpSecDxe/IpSecMain.c242
31 files changed, 24482 insertions, 0 deletions
diff --git a/Core/NetworkPkg/IpSecDxe/ComponentName.c b/Core/NetworkPkg/IpSecDxe/ComponentName.c
new file mode 100644
index 0000000000..d68b175cc1
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/ComponentName.c
@@ -0,0 +1,351 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for IPsec driver.
+
+ Copyright (c) 2009 - 2012, 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"
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user-readable name of the driver.
+
+ This function retrieves the user-readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user-readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param[in] Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param[out] DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user-readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user-readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param[in] ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param[in] ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param[in] Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param[out] ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user-readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIpSecComponentName = {
+ IpSecComponentNameGetDriverName,
+ IpSecComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIpSecComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IpSecComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IpSecComponentNameGetControllerName,
+ "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIpSecDriverNameTable[] = {
+ {
+ "eng;en",
+ L"IpSec Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIpSecControllerNameTable[] = {
+ {
+ "eng;en",
+ L"IPsec Controller"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the driver.
+
+ This function retrieves the user-readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user-readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param[in] Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param[out] DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This, and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mIpSecDriverNameTable,
+ DriverName,
+ (BOOLEAN) (This == &gIpSecComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user-readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user-readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user-readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param[in] ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param[in] ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param[in] Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param[out] ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user-readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // ChildHandle must be NULL for a Device Driver
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiIpSec2ProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mIpSecControllerNameTable,
+ ControllerName,
+ (BOOLEAN) (This == &gIpSecComponentName)
+ );
+}
diff --git a/Core/NetworkPkg/IpSecDxe/IetfConstants.c b/Core/NetworkPkg/IpSecDxe/IetfConstants.c
new file mode 100644
index 0000000000..7bd5c81da8
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IetfConstants.c
@@ -0,0 +1,388 @@
+/** @file
+ Cryptographic Parameter Constant Definitions from IETF;
+
+ Copyright (c) 2010, 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 "Ike.h"
+
+//
+// "First Oakley Default Group" from RFC2409, section 6.1.
+//
+// The prime is: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp768Modulus[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+ 0xA6, 0x3A, 0x36, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+
+//
+// "Second Oakley Default Group" from RFC2409, section 6.2.
+//
+// The prime is: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp1024Modulus[] = {
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE6,0x53,0x81,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ };
+
+//
+// "1536-bit MODP Group" from RFC3526, Section 2.
+//
+// The prime is: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp1536Modulus[]={
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+ 0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ };
+
+//
+// "2048-bit MODP Group" from RFC3526, Section 3.
+//
+// The prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp2048Modulus[]={
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+ 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,
+ 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,
+ 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,
+ 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAC,0xAA,0x68,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,
+ };
+
+//
+// "3072-bit MODP Group" from RFC3526, Section 4.
+//
+// The prime is: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp3072Modulus[]={
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+ 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,
+ 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,
+ 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,
+ 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,
+ 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,
+ 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,
+ 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,
+ 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,
+ 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,
+ 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,
+ 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,
+ 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,
+ 0xA9,0x3A,0xD2,0xCA,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ };
+
+//
+// "4096-bit MODP Group" from RFC3526, Section 5.
+//
+// The prime is: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp4096Modulus[]={
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+ 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,
+ 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,
+ 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,
+ 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,
+ 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,
+ 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,
+ 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,
+ 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,
+ 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,
+ 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,
+ 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,
+ 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,
+ 0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
+ 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,
+ 0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,
+ 0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB,
+ 0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
+ 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,
+ 0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,
+ 0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76,
+ 0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
+ 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,
+ 0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x06,0x31,0x99,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ };
+
+//
+// "6144-bit MODP Group" from RFC3526, Section 6.
+//
+// The prime is: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp6144Modulus[]={
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+ 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,
+ 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,
+ 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,
+ 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,
+ 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,
+ 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,
+ 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,
+ 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,
+ 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,
+ 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,
+ 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,
+ 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,
+ 0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
+ 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,
+ 0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,
+ 0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB,
+ 0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
+ 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,
+ 0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,
+ 0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76,
+ 0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
+ 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,
+ 0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,
+ 0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,0xC1,0xD4,0xDC,0xB2,
+ 0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD,
+ 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,
+ 0x41,0x30,0x01,0xAE,0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,
+ 0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,0xDA,0x3E,0xDB,0xEB,
+ 0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B,
+ 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,
+ 0x2B,0xD7,0xAF,0x42,0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,
+ 0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,0xF0,0x32,0xEA,0x15,
+ 0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6,
+ 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,
+ 0x90,0x0B,0x1C,0x9E,0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,
+ 0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,0x0F,0x1D,0x45,0xB7,
+ 0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA,
+ 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,
+ 0x0F,0x80,0x37,0xE0,0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,
+ 0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,0xF5,0x50,0xAA,0x3D,
+ 0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,
+ 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,
+ 0x6E,0x3C,0x04,0x68,0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,
+ 0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,0xE6,0x94,0xF9,0x1E,
+ 0x6D,0xCC,0x40,0x24,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ };
+
+//
+// "8192-bit MODP Group" from RFC3526, Section 7.
+//
+// The prime is: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }
+//
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 Modp8192Modulus[]={
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+ 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+ 0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+ 0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+ 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+ 0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+ 0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+ 0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+ 0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+ 0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+ 0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+ 0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+ 0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+ 0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+ 0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+ 0xCA,0x18,0x21,0x7C,0x32,0x90,0x5E,0x46,0x2E,0x36,0xCE,0x3B,
+ 0xE3,0x9E,0x77,0x2C,0x18,0x0E,0x86,0x03,0x9B,0x27,0x83,0xA2,
+ 0xEC,0x07,0xA2,0x8F,0xB5,0xC5,0x5D,0xF0,0x6F,0x4C,0x52,0xC9,
+ 0xDE,0x2B,0xCB,0xF6,0x95,0x58,0x17,0x18,0x39,0x95,0x49,0x7C,
+ 0xEA,0x95,0x6A,0xE5,0x15,0xD2,0x26,0x18,0x98,0xFA,0x05,0x10,
+ 0x15,0x72,0x8E,0x5A,0x8A,0xAA,0xC4,0x2D,0xAD,0x33,0x17,0x0D,
+ 0x04,0x50,0x7A,0x33,0xA8,0x55,0x21,0xAB,0xDF,0x1C,0xBA,0x64,
+ 0xEC,0xFB,0x85,0x04,0x58,0xDB,0xEF,0x0A,0x8A,0xEA,0x71,0x57,
+ 0x5D,0x06,0x0C,0x7D,0xB3,0x97,0x0F,0x85,0xA6,0xE1,0xE4,0xC7,
+ 0xAB,0xF5,0xAE,0x8C,0xDB,0x09,0x33,0xD7,0x1E,0x8C,0x94,0xE0,
+ 0x4A,0x25,0x61,0x9D,0xCE,0xE3,0xD2,0x26,0x1A,0xD2,0xEE,0x6B,
+ 0xF1,0x2F,0xFA,0x06,0xD9,0x8A,0x08,0x64,0xD8,0x76,0x02,0x73,
+ 0x3E,0xC8,0x6A,0x64,0x52,0x1F,0x2B,0x18,0x17,0x7B,0x20,0x0C,
+ 0xBB,0xE1,0x17,0x57,0x7A,0x61,0x5D,0x6C,0x77,0x09,0x88,0xC0,
+ 0xBA,0xD9,0x46,0xE2,0x08,0xE2,0x4F,0xA0,0x74,0xE5,0xAB,0x31,
+ 0x43,0xDB,0x5B,0xFC,0xE0,0xFD,0x10,0x8E,0x4B,0x82,0xD1,0x20,
+ 0xA9,0x21,0x08,0x01,0x1A,0x72,0x3C,0x12,0xA7,0x87,0xE6,0xD7,
+ 0x88,0x71,0x9A,0x10,0xBD,0xBA,0x5B,0x26,0x99,0xC3,0x27,0x18,
+ 0x6A,0xF4,0xE2,0x3C,0x1A,0x94,0x68,0x34,0xB6,0x15,0x0B,0xDA,
+ 0x25,0x83,0xE9,0xCA,0x2A,0xD4,0x4C,0xE8,0xDB,0xBB,0xC2,0xDB,
+ 0x04,0xDE,0x8E,0xF9,0x2E,0x8E,0xFC,0x14,0x1F,0xBE,0xCA,0xA6,
+ 0x28,0x7C,0x59,0x47,0x4E,0x6B,0xC0,0x5D,0x99,0xB2,0x96,0x4F,
+ 0xA0,0x90,0xC3,0xA2,0x23,0x3B,0xA1,0x86,0x51,0x5B,0xE7,0xED,
+ 0x1F,0x61,0x29,0x70,0xCE,0xE2,0xD7,0xAF,0xB8,0x1B,0xDD,0x76,
+ 0x21,0x70,0x48,0x1C,0xD0,0x06,0x91,0x27,0xD5,0xB0,0x5A,0xA9,
+ 0x93,0xB4,0xEA,0x98,0x8D,0x8F,0xDD,0xC1,0x86,0xFF,0xB7,0xDC,
+ 0x90,0xA6,0xC0,0x8F,0x4D,0xF4,0x35,0xC9,0x34,0x02,0x84,0x92,
+ 0x36,0xC3,0xFA,0xB4,0xD2,0x7C,0x70,0x26,0xC1,0xD4,0xDC,0xB2,
+ 0x60,0x26,0x46,0xDE,0xC9,0x75,0x1E,0x76,0x3D,0xBA,0x37,0xBD,
+ 0xF8,0xFF,0x94,0x06,0xAD,0x9E,0x53,0x0E,0xE5,0xDB,0x38,0x2F,
+ 0x41,0x30,0x01,0xAE,0xB0,0x6A,0x53,0xED,0x90,0x27,0xD8,0x31,
+ 0x17,0x97,0x27,0xB0,0x86,0x5A,0x89,0x18,0xDA,0x3E,0xDB,0xEB,
+ 0xCF,0x9B,0x14,0xED,0x44,0xCE,0x6C,0xBA,0xCE,0xD4,0xBB,0x1B,
+ 0xDB,0x7F,0x14,0x47,0xE6,0xCC,0x25,0x4B,0x33,0x20,0x51,0x51,
+ 0x2B,0xD7,0xAF,0x42,0x6F,0xB8,0xF4,0x01,0x37,0x8C,0xD2,0xBF,
+ 0x59,0x83,0xCA,0x01,0xC6,0x4B,0x92,0xEC,0xF0,0x32,0xEA,0x15,
+ 0xD1,0x72,0x1D,0x03,0xF4,0x82,0xD7,0xCE,0x6E,0x74,0xFE,0xF6,
+ 0xD5,0x5E,0x70,0x2F,0x46,0x98,0x0C,0x82,0xB5,0xA8,0x40,0x31,
+ 0x90,0x0B,0x1C,0x9E,0x59,0xE7,0xC9,0x7F,0xBE,0xC7,0xE8,0xF3,
+ 0x23,0xA9,0x7A,0x7E,0x36,0xCC,0x88,0xBE,0x0F,0x1D,0x45,0xB7,
+ 0xFF,0x58,0x5A,0xC5,0x4B,0xD4,0x07,0xB2,0x2B,0x41,0x54,0xAA,
+ 0xCC,0x8F,0x6D,0x7E,0xBF,0x48,0xE1,0xD8,0x14,0xCC,0x5E,0xD2,
+ 0x0F,0x80,0x37,0xE0,0xA7,0x97,0x15,0xEE,0xF2,0x9B,0xE3,0x28,
+ 0x06,0xA1,0xD5,0x8B,0xB7,0xC5,0xDA,0x76,0xF5,0x50,0xAA,0x3D,
+ 0x8A,0x1F,0xBF,0xF0,0xEB,0x19,0xCC,0xB1,0xA3,0x13,0xD5,0x5C,
+ 0xDA,0x56,0xC9,0xEC,0x2E,0xF2,0x96,0x32,0x38,0x7F,0xE8,0xD7,
+ 0x6E,0x3C,0x04,0x68,0x04,0x3E,0x8F,0x66,0x3F,0x48,0x60,0xEE,
+ 0x12,0xBF,0x2D,0x5B,0x0B,0x74,0x74,0xD6,0xE6,0x94,0xF9,0x1E,
+ 0x6D,0xBE,0x11,0x59,0x74,0xA3,0x92,0x6F,0x12,0xFE,0xE5,0xE4,
+ 0x38,0x77,0x7C,0xB6,0xA9,0x32,0xDF,0x8C,0xD8,0xBE,0xC4,0xD0,
+ 0x73,0xB9,0x31,0xBA,0x3B,0xC8,0x32,0xB6,0x8D,0x9D,0xD3,0x00,
+ 0x74,0x1F,0xA7,0xBF,0x8A,0xFC,0x47,0xED,0x25,0x76,0xF6,0x93,
+ 0x6B,0xA4,0x24,0x66,0x3A,0xAB,0x63,0x9C,0x5A,0xE4,0xF5,0x68,
+ 0x34,0x23,0xB4,0x74,0x2B,0xF1,0xC9,0x78,0x23,0x8F,0x16,0xCB,
+ 0xE3,0x9D,0x65,0x2D,0xE3,0xFD,0xB8,0xBE,0xFC,0x84,0x8A,0xD9,
+ 0x22,0x22,0x2E,0x04,0xA4,0x03,0x7C,0x07,0x13,0xEB,0x57,0xA8,
+ 0x1A,0x23,0xF0,0xC7,0x34,0x73,0xFC,0x64,0x6C,0xEA,0x30,0x6B,
+ 0x4B,0xCB,0xC8,0x86,0x2F,0x83,0x85,0xDD,0xFA,0x9D,0x4B,0x7F,
+ 0xA2,0xC0,0x87,0xE8,0x79,0x68,0x33,0x03,0xED,0x5B,0xDD,0x3A,
+ 0x06,0x2B,0x3C,0xF5,0xB3,0xA2,0x78,0xA6,0x6D,0x2A,0x13,0xF8,
+ 0x3F,0x44,0xF8,0x2D,0xDF,0x31,0x0E,0xE0,0x74,0xAB,0x6A,0x36,
+ 0x45,0x97,0xE8,0x99,0xA0,0x25,0x5D,0xC1,0x64,0xF3,0x1C,0xC5,
+ 0x08,0x46,0x85,0x1D,0xF9,0xAB,0x48,0x19,0x5D,0xED,0x7E,0xA1,
+ 0xB1,0xD5,0x10,0xBD,0x7E,0xE7,0x4D,0x73,0xFA,0xF3,0x6B,0xC3,
+ 0x1E,0xCF,0xA2,0x68,0x35,0x90,0x46,0xF4,0xEB,0x87,0x9F,0x92,
+ 0x40,0x09,0x43,0x8B,0x48,0x1C,0x6C,0xD7,0x88,0x9A,0x00,0x2E,
+ 0xD5,0xEE,0x38,0x2B,0xC9,0x19,0x0D,0xA6,0xFC,0x02,0x6E,0x47,
+ 0x95,0x58,0xE4,0x47,0x56,0x77,0xE9,0xAA,0x9E,0x30,0x50,0xE2,
+ 0x76,0x56,0x94,0xDF,0xC8,0x1F,0x56,0xE8,0x80,0xB9,0x6E,0x71,
+ 0x60,0xC9,0x80,0xDD,0x98,0xED,0xD3,0xDF,0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF,
+ };
+
+//
+// Pre-defined Oakley MODP Groups
+//
+#define DH_GENERATOR_2 2
+GLOBAL_REMOVE_IF_UNREFERENCED CONST MODP_GROUP OakleyModpGroup[] = {
+ {0, 0, NULL, 0}, //Undefined
+ {OakleyGroupModp768, 768, Modp768Modulus, DH_GENERATOR_2},
+ {OakleyGroupModp1024, 1024, Modp1024Modulus, DH_GENERATOR_2},
+ {0, 0, NULL, 0}, // For ECC. UnSupported
+ {0, 0, NULL, 0}, // For ECC. Unsupported
+ {OakleyGroupModp1536, 1536, Modp1536Modulus, DH_GENERATOR_2},
+ {0, 0, NULL, 0}, //Undefined
+ {0, 0, NULL, 0}, //Undefined
+ {0, 0, NULL, 0}, //Undefined
+ {0, 0, NULL, 0}, //Undefined
+ {0, 0, NULL, 0}, //Undefined
+ {0, 0, NULL, 0}, //Undefined
+ {0, 0, NULL, 0}, //Undefined
+ {0, 0, NULL, 0}, //Undefined
+ {OakleyGroupModp2048, 2048, Modp2048Modulus, DH_GENERATOR_2},
+ {OakleyGroupModp3072, 3072, Modp3072Modulus, DH_GENERATOR_2},
+ {OakleyGroupModp4096, 4096, Modp4096Modulus, DH_GENERATOR_2},
+ {OakleyGroupModp6144, 6144, Modp6144Modulus, DH_GENERATOR_2},
+ {OakleyGroupModp8192, 8192, Modp8192Modulus, DH_GENERATOR_2},
+};
diff --git a/Core/NetworkPkg/IpSecDxe/Ike.h b/Core/NetworkPkg/IpSecDxe/Ike.h
new file mode 100644
index 0000000000..50c680a528
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ike.h
@@ -0,0 +1,266 @@
+/** @file
+ The common definition of IPsec Key Exchange (IKE).
+
+ Copyright (c) 2010, 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.
+
+
+**/
+
+#ifndef _IKE_H_
+#define _IKE_H_
+
+#include <Library/UdpIoLib.h>
+#include <Library/BaseCryptLib.h>
+#include "IpSecImpl.h"
+
+#define IKE_VERSION_MAJOR_MASK 0xf0
+#define IKE_VERSION_MINOR_MASK 0x0f
+
+#define IKE_MAJOR_VERSION(v) (((v) & IKE_VERSION_MAJOR_MASK) >> 4)
+#define IKE_MINOR_VERSION(v) ((v) & IKE_VERSION_MINOR_MASK)
+
+//
+// Protocol Value Use in IKEv1 and IKEv2
+//
+#define IPSEC_PROTO_ISAKMP 1
+#define IPSEC_PROTO_IPSEC_AH 2
+#define IPSEC_PROTO_IPSEC_ESP 3
+#define IPSEC_PROTO_IPCOMP 4 // For IKEv1 this value is reserved
+
+//
+// For Algorithm search in support list.Last two types are for IKEv2 only.
+//
+#define IKE_ENCRYPT_TYPE 0
+#define IKE_AUTH_TYPE 1
+#define IKE_PRF_TYPE 2
+#define IKE_DH_TYPE 3
+
+//
+// Encryption Algorithm present in IKEv1 phasrs2 and IKEv2 transform payload (Transform Type 1)
+//
+#define IPSEC_ESP_DES_IV64 1
+#define IPSEC_ESP_DES 2
+#define IPSEC_ESP_3DES 3
+#define IPSEC_ESP_RC5 4
+#define IPSEC_ESP_IDEA 5
+#define IPSEC_ESP_CAST 6
+#define IPSEC_ESP_BLOWFISH 7
+#define IPSEC_ESP_3IDEA 8
+#define IPSEC_ESP_DES_IV32 9
+#define IPSEC_ESP_RC4 10 // It's reserved in IKEv2
+#define IPSEC_ESP_NULL 11
+#define IPSEC_ESP_AES 12
+
+#define IKE_XCG_TYPE_NONE 0
+#define IKE_XCG_TYPE_BASE 1
+#define IKE_XCG_TYPE_IDENTITY_PROTECT 2
+#define IKE_XCG_TYPE_AUTH_ONLY 3
+#define IKE_XCG_TYPE_AGGR 4
+#define IKE_XCG_TYPE_INFO 5
+#define IKE_XCG_TYPE_QM 32
+#define IKE_XCG_TYPE_NGM 33
+#define IKE_XCG_TYPE_SA_INIT 34
+#define IKE_XCG_TYPE_AUTH 35
+#define IKE_XCG_TYPE_CREATE_CHILD_SA 36
+#define IKE_XCG_TYPE_INFO2 37
+
+#define IKE_LIFE_TYPE_SECONDS 1
+#define IKE_LIFE_TYPE_KILOBYTES 2
+
+//
+// Deafult IKE SA lifetime and CHILD SA lifetime
+//
+#define IKE_SA_DEFAULT_LIFETIME 1200
+#define CHILD_SA_DEFAULT_LIFETIME 3600
+
+//
+// Next payload type presented within Proposal payload
+//
+#define IKE_PROPOSAL_NEXT_PAYLOAD_MORE 2
+#define IKE_PROPOSAL_NEXT_PAYLOAD_NONE 0
+
+//
+// Next payload type presented within Transform payload
+//
+#define IKE_TRANSFORM_NEXT_PAYLOAD_MORE 3
+#define IKE_TRANSFORM_NEXT_PAYLOAD_NONE 0
+
+//
+// Max size of the SA attribute
+//
+#define MAX_SA_ATTRS_SIZE 48
+#define SA_ATTR_FORMAT_BIT 0x8000
+//
+// The definition for Information Message ID.
+//
+#define INFO_MID_SIGNATURE SIGNATURE_32 ('I', 'N', 'F', 'M')
+
+//
+// Type for the IKE SESSION COMMON
+//
+typedef enum {
+ IkeSessionTypeIkeSa,
+ IkeSessionTypeChildSa,
+ IkeSessionTypeInfo,
+ IkeSessionTypeMax
+} IKE_SESSION_TYPE;
+
+//
+// The DH Group ID defined RFC3526 and RFC 2409
+//
+typedef enum {
+ OakleyGroupModp768 = 1,
+ OakleyGroupModp1024 = 2,
+ OakleyGroupGp155 = 3, // Unsupported Now.
+ OakleyGroupGp185 = 4, // Unsupported Now.
+ OakleyGroupModp1536 = 5,
+
+ OakleyGroupModp2048 = 14,
+ OakleyGroupModp3072 = 15,
+ OakleyGroupModp4096 = 16,
+ OakleyGroupModp6144 = 17,
+ OakleyGroupModp8192 = 18,
+ OakleyGroupMax
+} OAKLEY_GROUP_ID;
+
+//
+// IKE Header
+//
+#pragma pack(1)
+typedef struct {
+ UINT64 InitiatorCookie;
+ UINT64 ResponderCookie;
+ UINT8 NextPayload;
+ UINT8 Version;
+ UINT8 ExchangeType;
+ UINT8 Flags;
+ UINT32 MessageId;
+ UINT32 Length;
+} IKE_HEADER;
+#pragma pack()
+
+typedef union {
+ UINT16 AttrLength;
+ UINT16 AttrValue;
+} IKE_SA_ATTR_UNION;
+
+//
+// SA Attribute present in Transform Payload
+//
+#pragma pack(1)
+typedef struct {
+ UINT16 AttrType;
+ IKE_SA_ATTR_UNION Attr;
+} IKE_SA_ATTRIBUTE;
+#pragma pack()
+
+//
+// Contains the IKE packet information.
+//
+typedef struct {
+ UINTN RefCount;
+ BOOLEAN IsHdrExt;
+ IKE_HEADER *Header;
+ BOOLEAN IsPayloadsBufExt;
+ UINT8 *PayloadsBuf; // The whole IkePakcet trimed the IKE header.
+ UINTN PayloadTotalSize;
+ LIST_ENTRY PayloadList;
+ EFI_IP_ADDRESS RemotePeerIp;
+ BOOLEAN IsEncoded; // whether HTON is done when sending the packet
+ UINT32 Spi; // For the Delete Information Exchange
+ BOOLEAN IsDeleteInfo; // For the Delete Information Exchange
+ IPSEC_PRIVATE_DATA *Private; // For the Delete Information Exchange
+} IKE_PACKET;
+
+//
+// The generic structure to all kinds of IKE payloads.
+//
+typedef struct {
+ UINT32 Signature;
+ BOOLEAN IsPayloadBufExt;
+ UINT8 PayloadType;
+ UINT8 *PayloadBuf;
+ UINTN PayloadSize;
+ LIST_ENTRY ByPacket;
+} IKE_PAYLOAD;
+
+//
+// Udp Service
+//
+typedef struct {
+ UINT32 Signature;
+ UINT8 IpVersion;
+ LIST_ENTRY List;
+ LIST_ENTRY *ListHead;
+ EFI_HANDLE NicHandle;
+ EFI_HANDLE ImageHandle;
+ UDP_IO *Input;
+ UDP_IO *Output;
+ EFI_IP_ADDRESS DefaultAddress;
+ BOOLEAN IsConfigured;
+} IKE_UDP_SERVICE;
+
+//
+// Each IKE session has its own Key sets for local peer and remote peer.
+//
+typedef struct {
+ EFI_IPSEC_ALGO_INFO LocalPeerInfo;
+ EFI_IPSEC_ALGO_INFO RemotePeerInfo;
+} SA_KEYMATS;
+
+//
+// Each algorithm has its own Id, Guid, BlockSize and KeyLength.
+// This struct contains these information for each algorithm. It is generic structure
+// for both encryption and authentication algorithm.
+// For authentication algorithm, the AlgSize means IcvSize. For encryption algorithm,
+// it means IvSize.
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 AlgorithmId; // Encryption or Authentication Id used by ESP/AH
+ EFI_GUID *AlgGuid;
+ UINT8 AlgSize; // IcvSize or IvSize
+ UINT8 BlockSize;
+ UINTN KeyMateLen;
+} IKE_ALG_GUID_INFO; // For IPsec Authentication and Encryption Algorithm.
+#pragma pack()
+
+//
+// Structure used to store the DH group
+//
+typedef struct {
+ UINT8 GroupId;
+ UINTN Size;
+ UINT8 *Modulus;
+ UINTN GroupGenerator;
+} MODP_GROUP;
+
+/**
+ This is prototype definition of general interface to phase the payloads
+ after/before the decode/encode.
+
+ @param[in] SessionCommon Point to the SessionCommon
+ @param[in] PayloadBuf Point to the buffer of Payload.
+ @param[in] PayloadSize The size of the PayloadBuf in bytes.
+ @param[in] PayloadType The type of Payload.
+
+**/
+typedef
+VOID
+(*IKE_ON_PAYLOAD_FROM_NET) (
+ IN UINT8 *SessionCommon,
+ IN UINT8 *PayloadBuf,
+ IN UINTN PayloadSize,
+ IN UINT8 PayloadType
+ );
+
+#endif
+
diff --git a/Core/NetworkPkg/IpSecDxe/IkeCommon.c b/Core/NetworkPkg/IpSecDxe/IkeCommon.c
new file mode 100644
index 0000000000..6fc7c06353
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IkeCommon.c
@@ -0,0 +1,254 @@
+/** @file
+ Common operation of the IKE
+
+ Copyright (c) 2010 - 2015, 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 "Ike.h"
+#include "IkeCommon.h"
+#include "IpSecConfigImpl.h"
+#include "IpSecDebug.h"
+
+//
+// Initial the SPI
+//
+UINT32 mNextSpi = IKE_SPI_BASE;
+
+/**
+ Call Crypto Lib to generate a random value with eight-octet length.
+
+ @return the 64 byte vaule.
+
+**/
+UINT64
+IkeGenerateCookie (
+ VOID
+ )
+{
+ UINT64 Cookie;
+ EFI_STATUS Status;
+
+ Status = IpSecCryptoIoGenerateRandomBytes ((UINT8 *)&Cookie, sizeof (UINT64));
+ if (EFI_ERROR (Status)) {
+ return 0;
+ } else {
+ return Cookie;
+ }
+}
+
+/**
+ Generate the random data for Nonce payload.
+
+ @param[in] NonceSize Size of the data in bytes.
+
+ @return Buffer which contains the random data of the spcified size.
+
+**/
+UINT8 *
+IkeGenerateNonce (
+ IN UINTN NonceSize
+ )
+{
+ UINT8 *Nonce;
+ EFI_STATUS Status;
+
+ Nonce = AllocateZeroPool (NonceSize);
+ if (Nonce == NULL) {
+ return NULL;
+ }
+
+ Status = IpSecCryptoIoGenerateRandomBytes (Nonce, NonceSize);
+ if (EFI_ERROR (Status)) {
+ FreePool (Nonce);
+ return NULL;
+ } else {
+ return Nonce;
+ }
+}
+
+/**
+ Convert the IKE Header from Network order to Host order.
+
+ @param[in, out] Header The pointer of the IKE_HEADER.
+
+**/
+VOID
+IkeHdrNetToHost (
+ IN OUT IKE_HEADER *Header
+ )
+{
+ Header->InitiatorCookie = NTOHLL (Header->InitiatorCookie);
+ Header->ResponderCookie = NTOHLL (Header->ResponderCookie);
+ Header->MessageId = NTOHL (Header->MessageId);
+ Header->Length = NTOHL (Header->Length);
+}
+
+/**
+ Convert the IKE Header from Host order to Network order.
+
+ @param[in, out] Header The pointer of the IKE_HEADER.
+
+**/
+VOID
+IkeHdrHostToNet (
+ IN OUT IKE_HEADER *Header
+ )
+{
+ Header->InitiatorCookie = HTONLL (Header->InitiatorCookie);
+ Header->ResponderCookie = HTONLL (Header->ResponderCookie);
+ Header->MessageId = HTONL (Header->MessageId);
+ Header->Length = HTONL (Header->Length);
+}
+
+/**
+ Allocate a buffer of IKE_PAYLOAD and set its Signature.
+
+ @return A buffer of IKE_PAYLOAD.
+
+**/
+IKE_PAYLOAD *
+IkePayloadAlloc (
+ VOID
+ )
+{
+ IKE_PAYLOAD *IkePayload;
+
+ IkePayload = (IKE_PAYLOAD *) AllocateZeroPool (sizeof (IKE_PAYLOAD));
+ if (IkePayload == NULL) {
+ return NULL;
+ }
+
+ IkePayload->Signature = IKE_PAYLOAD_SIGNATURE;
+
+ return IkePayload;
+}
+
+/**
+ Free a specified IKE_PAYLOAD buffer.
+
+ @param[in] IkePayload Pointer of IKE_PAYLOAD to be freed.
+
+**/
+VOID
+IkePayloadFree (
+ IN IKE_PAYLOAD *IkePayload
+ )
+{
+ if (IkePayload == NULL) {
+ return;
+ }
+ //
+ // If this IkePayload is not referred by others, free it.
+ //
+ if (!IkePayload->IsPayloadBufExt && (IkePayload->PayloadBuf != NULL)) {
+ FreePool (IkePayload->PayloadBuf);
+ }
+
+ FreePool (IkePayload);
+}
+
+/**
+ Generate an new SPI.
+
+ @return a SPI in 4 bytes.
+
+**/
+UINT32
+IkeGenerateSpi (
+ VOID
+ )
+{
+ //
+ // TODO: should generate SPI randomly to avoid security issue
+ //
+ return mNextSpi++;
+}
+
+/**
+ Generate a random data for IV
+
+ @param[in] IvBuffer The pointer of the IV buffer.
+ @param[in] IvSize The IV size.
+
+ @retval EFI_SUCCESS Create a random data for IV.
+ @retval otherwise Failed.
+
+**/
+EFI_STATUS
+IkeGenerateIv (
+ IN UINT8 *IvBuffer,
+ IN UINTN IvSize
+ )
+{
+ return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);
+}
+
+
+/**
+ Find SPD entry by a specified SPD selector.
+
+ @param[in] SpdSel Point to SPD Selector to be searched for.
+
+ @retval Point to SPD Entry if the SPD entry found.
+ @retval NULL if not found.
+
+**/
+IPSEC_SPD_ENTRY *
+IkeSearchSpdEntry (
+ IN EFI_IPSEC_SPD_SELECTOR *SpdSel
+ )
+{
+ IPSEC_SPD_ENTRY *SpdEntry;
+ LIST_ENTRY *SpdList;
+ LIST_ENTRY *Entry;
+
+ SpdList = &mConfigData[IPsecConfigDataTypeSpd];
+
+ NET_LIST_FOR_EACH (Entry, SpdList) {
+ SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
+
+ //
+ // Find the required SPD entry
+ //
+ if (CompareSpdSelector (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
+ )) {
+ return SpdEntry;
+ }
+
+ }
+
+ return NULL;
+}
+
+/**
+ Get the IKE Version from the IKE_SA_SESSION.
+
+ @param[in] Session Pointer of the IKE_SA_SESSION.
+
+**/
+UINT8
+IkeGetVersionFromSession (
+ IN UINT8 *Session
+ )
+{
+ if (*(UINT32 *) Session == IKEV2_SA_SESSION_SIGNATURE) {
+ return ((IKEV2_SA_SESSION *) Session)->SessionCommon.IkeVer;
+ } else {
+ //
+ // Add IKEv1 support here.
+ //
+ return 0;
+ }
+}
+
diff --git a/Core/NetworkPkg/IpSecDxe/IkeCommon.h b/Core/NetworkPkg/IpSecDxe/IkeCommon.h
new file mode 100644
index 0000000000..714ecaa8e3
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IkeCommon.h
@@ -0,0 +1,189 @@
+/** @file
+ Common operation of the IKE.
+
+ Copyright (c) 2010 - 2015, 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.
+
+**/
+
+#ifndef _IKE_COMMON_H_
+#define _IKE_COMMON_H_
+
+#include <Protocol/Udp4.h>
+#include <Protocol/Udp6.h>
+#include <Protocol/Ip4Config2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UdpIoLib.h>
+#include <Library/BaseCryptLib.h>
+
+#include "Ikev2/Ikev2.h"
+#include "IpSecImpl.h"
+#include "IkePacket.h"
+#include "IpSecCryptIo.h"
+
+
+#define IKE_DEFAULT_PORT 500
+#define IKE_DEFAULT_TIMEOUT_INTERVAL 10000 // 10s
+#define IKE_NONCE_SIZE 16
+#define IKE_MAX_RETRY 4
+#define IKE_SPI_BASE 0x10000
+#define IKE_PAYLOAD_SIGNATURE SIGNATURE_32('I','K','E','P')
+#define IKE_PAYLOAD_BY_PACKET(a) CR(a,IKE_PAYLOAD,ByPacket,IKE_PAYLOAD_SIGNATURE)
+
+
+#define IKE_PACKET_APPEND_PAYLOAD(IkePacket,IkePayload) \
+ do { \
+ InsertTailList(&(IkePacket)->PayloadList, &(IkePayload)->ByPacket); \
+ } while (0)
+
+#define IKE_PACKET_REMOVE_PAYLOAD(IkePacket,IkePayload) \
+ do { \
+ RemoveEntryList(&(IkePayload)->ByPacket); \
+ } while (0)
+
+#define IKE_PACKET_END_PAYLOAD(IkePacket, Node) \
+ Node = GetFirstNode (&(IkePacket)->PayloadList); \
+ while (!IsNodeAtEnd (&(IkePacket)->PayloadList, Node)) { \
+ Node = GetNextNode (&(IkePacket)->PayloadList, Node); \
+ } \
+
+/**
+ Call Crypto Lib to generate a random value with eight-octet length.
+
+ @return the 64 byte vaule.
+
+**/
+UINT64
+IkeGenerateCookie (
+ VOID
+ );
+
+/**
+ Generate the random data for Nonce payload.
+
+ @param[in] NonceSize Size of the data in bytes.
+
+ @return Buffer which contains the random data of the spcified size.
+
+**/
+UINT8 *
+IkeGenerateNonce (
+ IN UINTN NonceSize
+ );
+
+/**
+ Convert the IKE Header from Network order to Host order.
+
+ @param[in, out] Header The pointer of the IKE_HEADER.
+
+**/
+VOID
+IkeHdrNetToHost (
+ IN OUT IKE_HEADER *Header
+ );
+
+
+/**
+ Convert the IKE Header from Host order to Network order.
+
+ @param[in, out] Header The pointer of the IKE_HEADER.
+
+**/
+VOID
+IkeHdrHostToNet (
+ IN OUT IKE_HEADER *Header
+ );
+
+/**
+ Allocate a buffer of IKE_PAYLOAD and set its Signature.
+
+ @return A buffer of IKE_PAYLOAD.
+
+**/
+IKE_PAYLOAD *
+IkePayloadAlloc (
+ VOID
+ );
+
+/**
+ Free a specified IKE_PAYLOAD buffer.
+
+ @param[in] IkePayload Pointer of IKE_PAYLOAD to be freed.
+
+**/
+VOID
+IkePayloadFree (
+ IN IKE_PAYLOAD *IkePayload
+ );
+
+/**
+ Generate an unused SPI
+
+ @return a SPI in 4 bytes.
+
+**/
+UINT32
+IkeGenerateSpi (
+ VOID
+ );
+
+/**
+ Generate a random data for IV
+
+ @param[in] IvBuffer The pointer of the IV buffer.
+ @param[in] IvSize The IV size.
+
+ @retval EFI_SUCCESS Create a random data for IV.
+ @retval otherwise Failed.
+
+**/
+EFI_STATUS
+IkeGenerateIv (
+ IN UINT8 *IvBuffer,
+ IN UINTN IvSize
+ );
+
+/**
+ Get the IKE Version from the IKE_SA_SESSION.
+
+ @param[in] Session Pointer of the IKE_SA_SESSION.
+
+**/
+UINT8
+IkeGetVersionFromSession (
+ IN UINT8 *Session
+ );
+
+/**
+ Find SPD entry by a specified SPD selector.
+
+ @param[in] SpdSel Point to SPD Selector to be searched for.
+
+ @retval Point to Spd Entry if the SPD entry found.
+ @retval NULL if not found.
+
+**/
+IPSEC_SPD_ENTRY *
+IkeSearchSpdEntry (
+ IN EFI_IPSEC_SPD_SELECTOR *SpdSel
+ );
+
+extern MODP_GROUP OakleyModpGroup[];
+extern IKE_ALG_GUID_INFO mIPsecEncrAlgInfo[];
+extern IKE_ALG_GUID_INFO mIPsecAuthAlgInfo[];
+
+#endif
+
diff --git a/Core/NetworkPkg/IpSecDxe/IkePacket.c b/Core/NetworkPkg/IpSecDxe/IkePacket.c
new file mode 100644
index 0000000000..14dbb9d5d6
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IkePacket.c
@@ -0,0 +1,265 @@
+/** @file
+ IKE Packet related operation.
+
+ Copyright (c) 2010 - 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 "IpSecDebug.h"
+#include "Ikev2/Utility.h"
+
+/**
+ Allocate a buffer for the IKE_PACKET and intitalize its Header and payloadlist.
+
+ @return The pointer of the IKE_PACKET.
+
+**/
+IKE_PACKET *
+IkePacketAlloc (
+ VOID
+ )
+{
+ IKE_PACKET *IkePacket;
+
+ IkePacket = (IKE_PACKET *) AllocateZeroPool (sizeof (IKE_PACKET));
+ if (IkePacket == NULL) {
+ return NULL;
+ }
+
+ IkePacket->RefCount = 1;
+ InitializeListHead (&IkePacket->PayloadList);
+
+ IkePacket->Header = (IKE_HEADER *) AllocateZeroPool (sizeof (IKE_HEADER));
+ if (IkePacket->Header == NULL) {
+ FreePool (IkePacket);
+ return NULL;
+ }
+ return IkePacket;
+}
+
+/**
+ Free the IkePacket by the specified IKE_PACKET pointer.
+
+ @param[in] IkePacket The pointer of the IKE_PACKET to be freed.
+
+**/
+VOID
+IkePacketFree (
+ IN IKE_PACKET *IkePacket
+ )
+{
+ LIST_ENTRY *Entry;
+ IKE_PAYLOAD *IkePayload;
+
+ if (IkePacket == NULL) {
+ return;
+ }
+ //
+ // Check if the Packet is referred by others.
+ //
+ if (--IkePacket->RefCount == 0) {
+ //
+ // Free IkePacket header
+ //
+ if (!IkePacket->IsHdrExt && IkePacket->Header != NULL) {
+ FreePool (IkePacket->Header);
+ }
+ //
+ // Free the PayloadsBuff
+ //
+ if (!IkePacket->IsPayloadsBufExt && IkePacket->PayloadsBuf != NULL) {
+ FreePool (IkePacket->PayloadsBuf);
+ }
+ //
+ // Iterate payloadlist and free all payloads
+ //
+ for (Entry = (IkePacket)->PayloadList.ForwardLink; Entry != &(IkePacket)->PayloadList;) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+ Entry = Entry->ForwardLink;
+
+ IkePayloadFree (IkePayload);
+ }
+
+ FreePool (IkePacket);
+ }
+}
+
+/**
+ Callback funtion of NetbufFromExt()
+
+ @param[in] Arg The data passed from the NetBufFromExe().
+
+**/
+VOID
+EFIAPI
+IkePacketNetbufFree (
+ IN VOID *Arg
+ )
+{
+ //
+ // TODO: add something if need.
+ //
+}
+
+/**
+ Copy the NetBuf into a IKE_PACKET sturcture.
+
+ Create a IKE_PACKET and fill the received IKE header into the header of IKE_PACKET
+ and copy the recieved packet without IKE HEADER to the PayloadBuf of IKE_PACKET.
+
+ @param[in] Netbuf The pointer of the Netbuf which contains the whole received
+ IKE packet.
+
+ @return The pointer of the IKE_PACKET which contains the received packet.
+
+**/
+IKE_PACKET *
+IkePacketFromNetbuf (
+ IN NET_BUF *Netbuf
+ )
+{
+ IKE_PACKET *IkePacket;
+
+ IkePacket = NULL;
+ if (Netbuf->TotalSize < sizeof (IKE_HEADER)) {
+ goto Error;
+ }
+
+ IkePacket = IkePacketAlloc ();
+ if (IkePacket == NULL) {
+ return NULL;
+ }
+ //
+ // Copy the IKE header from Netbuf to IkePacket->Hdr
+ //
+ NetbufCopy (Netbuf, 0, sizeof (IKE_HEADER), (UINT8 *) IkePacket->Header);
+ //
+ // Net order to host order
+ //
+ IkeHdrNetToHost (IkePacket->Header);
+ if (IkePacket->Header->Length < Netbuf->TotalSize) {
+ goto Error;
+ }
+
+ IkePacket->PayloadTotalSize = IkePacket->Header->Length - sizeof (IKE_HEADER);
+ IkePacket->PayloadsBuf = (UINT8 *) AllocateZeroPool (IkePacket->PayloadTotalSize);
+
+ if (IkePacket->PayloadsBuf == NULL) {
+ goto Error;
+ }
+ //
+ // Copy the IKE packet without the header into the IkePacket->PayloadsBuf.
+ //
+ NetbufCopy (Netbuf, sizeof (IKE_HEADER), (UINT32) IkePacket->PayloadTotalSize, IkePacket->PayloadsBuf);
+ return IkePacket;
+
+Error:
+ if (IkePacket != NULL) {
+ IkePacketFree (IkePacket);
+ }
+
+ return NULL;
+}
+
+/**
+ Convert the format from IKE_PACKET to NetBuf.
+
+ @param[in] SessionCommon Pointer of related IKE_COMMON_SESSION
+ @param[in] IkePacket Pointer of IKE_PACKET to be copy to NetBuf
+ @param[in] IkeType The IKE type to pointer the packet is for which IKE
+ phase. Now it supports IKE_SA_TYPE, IKE_CHILDSA_TYPE,
+ IKE_INFO_TYPE.
+
+ @return a pointer of Netbuff which contains the IKE_PACKE in network order.
+
+**/
+NET_BUF *
+IkeNetbufFromPacket (
+ IN UINT8 *SessionCommon,
+ IN IKE_PACKET *IkePacket,
+ IN UINTN IkeType
+ )
+{
+ NET_BUF *Netbuf;
+ NET_FRAGMENT *Fragments;
+ UINTN Index;
+ UINTN NumPayloads;
+ LIST_ENTRY *PacketEntry;
+ LIST_ENTRY *Entry;
+ IKE_PAYLOAD *IkePayload;
+ EFI_STATUS RetStatus;
+
+ RetStatus = EFI_SUCCESS;
+
+ if (!IkePacket->IsEncoded) {
+ IkePacket->IsEncoded = TRUE;
+ //
+ // Convert Host order to Network order for IKE_PACKET header and payloads
+ // Encryption payloads if needed
+ //
+ if (((IKEV2_SESSION_COMMON *) SessionCommon)->IkeVer == 2) {
+ RetStatus = Ikev2EncodePacket ((IKEV2_SESSION_COMMON *) SessionCommon, IkePacket, IkeType);
+ if (EFI_ERROR (RetStatus)) {
+ return NULL;
+ }
+
+ } else {
+ //
+ // If IKEv1 support, check it here.
+ //
+ return NULL;
+ }
+ }
+
+ NumPayloads = 0;
+ //
+ // Get the number of the payloads
+ //
+ NET_LIST_FOR_EACH (PacketEntry, &(IkePacket)->PayloadList) {
+
+ NumPayloads++;
+ }
+ //
+ // Allocate the Framgents according to the numbers of the IkePayload
+ //
+ Fragments = (NET_FRAGMENT *) AllocateZeroPool ((1 + NumPayloads) * sizeof (NET_FRAGMENT));
+ if (Fragments == NULL) {
+ return NULL;
+ }
+
+ Fragments[0].Bulk = (UINT8 *) IkePacket->Header;
+ Fragments[0].Len = sizeof (IKE_HEADER);
+ Index = 0;
+
+ //
+ // Set payloads to the Framgments.
+ //
+ NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+
+ Fragments[Index + 1].Bulk = IkePayload->PayloadBuf;
+ Fragments[Index + 1].Len = (UINT32) IkePayload->PayloadSize;
+ Index++;
+ }
+
+ Netbuf = NetbufFromExt (
+ Fragments,
+ (UINT32) (NumPayloads + 1),
+ 0,
+ 0,
+ IkePacketNetbufFree,
+ NULL
+ );
+
+ FreePool (Fragments);
+ return Netbuf;
+}
+
diff --git a/Core/NetworkPkg/IpSecDxe/IkePacket.h b/Core/NetworkPkg/IpSecDxe/IkePacket.h
new file mode 100644
index 0000000000..053d659d9c
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IkePacket.h
@@ -0,0 +1,82 @@
+/** @file
+ IKE Packet related definitions and function declarations.
+
+ Copyright (c) 2010, 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.
+
+**/
+
+#ifndef _IKE_V1_PACKET_H_
+#define _IKE_V1_PACKET_H_
+
+#include "Ike.h"
+
+#define IKE_PACKET_REF(p) ((p)->RefCount++)
+
+/**
+ Allocate a buffer for the IKE_PACKET and intitalize its Header and payloadlist.
+
+ @return The pointer of the IKE_PACKET.
+
+**/
+IKE_PACKET *
+IkePacketAlloc (
+ VOID
+ );
+
+
+/**
+ Free the IkePacket by the specified IKE_PACKET pointer.
+
+ @param[in] IkePacket The pointer of the IKE_PACKET to be freed.
+
+**/
+VOID
+IkePacketFree (
+ IN IKE_PACKET *IkePacket
+ );
+
+
+/**
+ Copy the NetBuf into a IKE_PACKET sturcture.
+
+ Create a IKE_PACKET and fill the received IKE header into the header of IKE_PACKET
+ and copy the recieved packet without IKE HEADER to the PayloadBuf of IKE_PACKET.
+
+ @param[in] Netbuf The pointer of the Netbuf which contains the whole received
+ IKE packet.
+
+ @return The pointer of the IKE_PACKET which contains the received packet.
+
+**/
+IKE_PACKET *
+IkePacketFromNetbuf (
+ IN NET_BUF *Netbuf
+ );
+
+/**
+ Convert the format from IKE_PACKET to NetBuf.
+
+ @param[in] SessionCommon Pointer of related IKE_COMMON_SESSION
+ @param[in] IkePacket Pointer of IKE_PACKET to be copy to NetBuf
+ @param[in] IkeType The IKE type to pointer the packet is for which IKE
+ phase. Now it supports IKE_SA_TYPE, IKE_CHILDSA_TYPE,
+ IKE_INFO_TYPE.
+
+ @return A pointer of Netbuff which contains the contents of the IKE_PACKE in network order.
+**/
+NET_BUF *
+IkeNetbufFromPacket (
+ IN UINT8 *SessionCommon,
+ IN IKE_PACKET *IkePacket,
+ IN UINTN IkeType
+ );
+
+#endif
diff --git a/Core/NetworkPkg/IpSecDxe/IkeService.c b/Core/NetworkPkg/IpSecDxe/IkeService.c
new file mode 100644
index 0000000000..d8571960a0
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IkeService.c
@@ -0,0 +1,794 @@
+/** @file
+ Provide IPsec Key Exchange (IKE) service general interfaces.
+
+ Copyright (c) 2010 - 2015, 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 "IkeService.h"
+#include "IpSecConfigImpl.h"
+
+IKE_EXCHANGE_INTERFACE *mIkeExchange[] = {
+ &mIkev1Exchange,
+ &mIkev2Exchange
+};
+
+EFI_UDP4_CONFIG_DATA mUdp4Conf = {
+ FALSE,
+ FALSE,
+ FALSE,
+ TRUE,
+ //
+ // IO parameters
+ //
+ 0,
+ 64,
+ FALSE,
+ 0,
+ 1000000,
+ FALSE,
+ {{0,0,0,0}},
+ {{0,0,0,0}},
+ IKE_DEFAULT_PORT,
+ {{0,0,0,0}},
+ 0
+};
+
+EFI_UDP6_CONFIG_DATA mUdp6Conf = {
+ FALSE,
+ FALSE,
+ TRUE,
+ //
+ // IO parameters
+ //
+ 0,
+ 128,
+ 0,
+ 1000000,
+ //Access Point
+ {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
+ IKE_DEFAULT_PORT,
+ {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
+ 0
+};
+
+/**
+ Check if the NIC handle is binded to a Udp service.
+
+ @param[in] Private Pointer of IPSEC_PRIVATE_DATA.
+ @param[in] Handle The Handle of the NIC card.
+ @param[in] IpVersion The version of the IP stack.
+
+ @return a pointer of IKE_UDP_SERVICE.
+
+**/
+IKE_UDP_SERVICE *
+IkeLookupUdp (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN EFI_HANDLE Handle,
+ IN UINT8 IpVersion
+ )
+{
+ LIST_ENTRY *Head;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ IKE_UDP_SERVICE *Udp;
+
+ Udp = NULL;
+ Head = (IpVersion == IP_VERSION_4) ? &Private->Udp4List : &Private->Udp6List;
+
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, Head) {
+
+ Udp = IPSEC_UDP_SERVICE_FROM_LIST (Entry);
+ //
+ // Find the right udp service which installed on the appointed NIC handle.
+ //
+ if (Handle == Udp->NicHandle) {
+ break;
+ } else {
+ Udp = NULL;
+ }
+ }
+
+ return Udp;
+}
+
+/**
+ Configure a UDPIO's UDP4 instance.
+
+ This fuction is called by the UdpIoCreateIo() to configures a
+ UDP4 instance.
+
+ @param[in] UdpIo The UDP_IO to be configured.
+ @param[in] Context User-defined data when calling UdpIoCreateIo().
+
+ @retval EFI_SUCCESS The configuration succeeded.
+ @retval Others The UDP4 instance fails to configure.
+
+**/
+EFI_STATUS
+EFIAPI
+IkeConfigUdp4 (
+ IN UDP_IO *UdpIo,
+ IN VOID *Context
+ )
+{
+ EFI_UDP4_CONFIG_DATA Udp4Cfg;
+ EFI_UDP4_PROTOCOL *Udp4;
+
+ ZeroMem (&Udp4Cfg, sizeof (EFI_UDP4_CONFIG_DATA));
+
+ Udp4 = UdpIo->Protocol.Udp4;
+ CopyMem (
+ &Udp4Cfg,
+ &mUdp4Conf,
+ sizeof (EFI_UDP4_CONFIG_DATA)
+ );
+
+ if (Context != NULL) {
+ //
+ // Configure udp4 io with local default address.
+ //
+ Udp4Cfg.UseDefaultAddress = TRUE;
+ }
+
+ return Udp4->Configure (Udp4, &Udp4Cfg);
+}
+
+/**
+ Configure a UDPIO's UDP6 instance.
+
+ This fuction is called by the UdpIoCreateIo()to configure a
+ UDP6 instance.
+
+ @param[in] UdpIo The UDP_IO to be configured.
+ @param[in] Context User-defined data when calling UdpIoCreateIo().
+
+ @retval EFI_SUCCESS The configuration succeeded.
+ @retval Others The configuration fails.
+
+**/
+EFI_STATUS
+EFIAPI
+IkeConfigUdp6 (
+ IN UDP_IO *UdpIo,
+ IN VOID *Context
+ )
+{
+ EFI_UDP6_PROTOCOL *Udp6;
+ EFI_UDP6_CONFIG_DATA Udp6Cfg;
+
+ ZeroMem (&Udp6Cfg, sizeof (EFI_UDP6_CONFIG_DATA));
+
+ Udp6 = UdpIo->Protocol.Udp6;
+ CopyMem (
+ &Udp6Cfg,
+ &mUdp6Conf,
+ sizeof (EFI_UDP6_CONFIG_DATA)
+ );
+
+ if (Context != NULL) {
+ //
+ // Configure instance with a destination address to start source address
+ // selection, and then get the configure data from the mode data to store
+ // the source address.
+ //
+ CopyMem (
+ &Udp6Cfg.RemoteAddress,
+ Context,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+ }
+
+ return Udp6->Configure (Udp6, &Udp6Cfg);
+}
+
+/**
+ Open and configure the related output UDPIO for IKE packet sending.
+
+ If the UdpService is not configured, this fuction calls UdpIoCreatIo() to
+ create UDPIO to bind this UdpService for IKE packet sending. If the UdpService
+ has already been configured, then return.
+
+ @param[in] UdpService The UDP_IO to be configured.
+ @param[in] RemoteIp User-defined data when calling UdpIoCreateIo().
+
+ @retval EFI_SUCCESS The configuration is successful.
+ @retval Others The configuration fails.
+
+**/
+EFI_STATUS
+IkeOpenOutputUdp (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN EFI_IP_ADDRESS *RemoteIp
+ )
+{
+ EFI_STATUS Status;
+ EFI_IP4_CONFIG2_PROTOCOL *Ip4Cfg2;
+ EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo;
+ UINTN BufSize;
+ EFI_IP6_MODE_DATA Ip6ModeData;
+ EFI_UDP6_PROTOCOL *Udp6;
+
+ Status = EFI_SUCCESS;
+ IfInfo = NULL;
+ BufSize = 0;
+
+ //
+ // Check whether the input and output udp io are both configured.
+ //
+ if (UdpService->IsConfigured) {
+ goto ON_EXIT;
+ }
+
+ if (UdpService->IpVersion == UDP_IO_UDP4_VERSION) {
+ //
+ // Handle ip4config protocol to get local default address.
+ //
+ Status = gBS->HandleProtocol (
+ UdpService->NicHandle,
+ &gEfiIp4Config2ProtocolGuid,
+ (VOID **) &Ip4Cfg2
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Get the interface information size.
+ //
+ Status = Ip4Cfg2->GetData (
+ Ip4Cfg2,
+ Ip4Config2DataTypeInterfaceInfo,
+ &BufSize,
+ NULL
+ );
+
+ if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ goto ON_EXIT;
+ }
+
+ IfInfo = AllocateZeroPool (BufSize);
+
+ if (IfInfo == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Get the interface info.
+ //
+ Status = Ip4Cfg2->GetData (
+ Ip4Cfg2,
+ Ip4Config2DataTypeInterfaceInfo,
+ &BufSize,
+ IfInfo
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ CopyMem (
+ &UdpService->DefaultAddress.v4,
+ &IfInfo->StationAddress,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+
+ //
+ // Create udp4 io for output with local default address.
+ //
+ UdpService->Output = UdpIoCreateIo (
+ UdpService->NicHandle,
+ UdpService->ImageHandle,
+ IkeConfigUdp4,
+ UDP_IO_UDP4_VERSION,
+ &UdpService->DefaultAddress
+ );
+
+ if (UdpService->Output == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ } else {
+ //
+ // Create udp6 io for output with remote address.
+ //
+ UdpService->Output = UdpIoCreateIo (
+ UdpService->NicHandle,
+ UdpService->ImageHandle,
+ IkeConfigUdp6,
+ UDP_IO_UDP6_VERSION,
+ RemoteIp
+ );
+
+ if (UdpService->Output == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ //
+ // Get ip6 mode data to get the result of source address selection.
+ //
+ ZeroMem (&Ip6ModeData, sizeof (EFI_IP6_MODE_DATA));
+
+ Udp6 = UdpService->Output->Protocol.Udp6;
+ Status = Udp6->GetModeData (Udp6, NULL, &Ip6ModeData, NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ UdpIoFreeIo (UdpService->Output);
+ goto ON_EXIT;
+ }
+ //
+ // Reconfigure udp6 io without remote address.
+ //
+ Udp6->Configure (Udp6, NULL);
+ Status = IkeConfigUdp6 (UdpService->Output, NULL);
+
+ //
+ // Record the selected source address for ipsec process later.
+ //
+ CopyMem (
+ &UdpService->DefaultAddress.v6,
+ &Ip6ModeData.ConfigData.StationAddress,
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+ }
+
+ UdpService->IsConfigured = TRUE;
+
+ON_EXIT:
+ if (IfInfo != NULL) {
+ FreePool (IfInfo);
+ }
+
+ return Status;
+}
+
+/**
+ Open and configure a UDPIO of Udp4 for IKE packet receiving.
+
+ This function is called at the IPsecDriverBinding start. IPsec create a UDP4 and
+ UDP4 IO for each NIC handle.
+
+ @param[in] Private Point to IPSEC_PRIVATE_DATA
+ @param[in] Controller Handler for NIC card.
+ @param[in] ImageHandle The handle that contains the EFI_DRIVER_BINDING_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The Operation is successful.
+ @retval EFI_OUT_OF_RESOURCE The required system resource can't be allocated.
+
+**/
+EFI_STATUS
+IkeOpenInputUdp4 (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ IKE_UDP_SERVICE *Udp4Srv;
+
+ //
+ // Check whether udp4 io of the controller has already been opened.
+ //
+ Udp4Srv = IkeLookupUdp (Private, Controller, IP_VERSION_4);
+
+ if (Udp4Srv != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ Udp4Srv = AllocateZeroPool (sizeof (IKE_UDP_SERVICE));
+
+ if (Udp4Srv == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Create udp4 io for iutput.
+ //
+ Udp4Srv->Input = UdpIoCreateIo (
+ Controller,
+ ImageHandle,
+ IkeConfigUdp4,
+ UDP_IO_UDP4_VERSION,
+ NULL
+ );
+
+ if (Udp4Srv->Input == NULL) {
+ FreePool (Udp4Srv);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Udp4Srv->NicHandle = Controller;
+ Udp4Srv->ImageHandle = ImageHandle;
+ Udp4Srv->ListHead = &(Private->Udp4List);
+ Udp4Srv->IpVersion = UDP_IO_UDP4_VERSION;
+ Udp4Srv->IsConfigured = FALSE;
+
+ ZeroMem (&Udp4Srv->DefaultAddress, sizeof (EFI_IP_ADDRESS));
+
+ //
+ // Insert the udp4 io into the list and increase the count.
+ //
+ InsertTailList (&Private->Udp4List, &Udp4Srv->List);
+
+ Private->Udp4Num++;
+
+ UdpIoRecvDatagram (Udp4Srv->Input, IkeDispatch, Udp4Srv, 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Open and configure a UDPIO of Udp6 for IKE packet receiving.
+
+ This function is called at the IPsecDriverBinding start. IPsec create a UDP6 and UDP6
+ IO for each NIC handle.
+
+ @param[in] Private Point to IPSEC_PRIVATE_DATA
+ @param[in] Controller Handler for NIC card.
+ @param[in] ImageHandle The handle that contains the EFI_DRIVER_BINDING_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The Operation is successful.
+ @retval EFI_OUT_OF_RESOURCE The required system resource can't be allocated.
+
+**/
+EFI_STATUS
+IkeOpenInputUdp6 (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ IKE_UDP_SERVICE *Udp6Srv;
+
+ Udp6Srv = IkeLookupUdp (Private, Controller, IP_VERSION_6);
+
+ if (Udp6Srv != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ Udp6Srv = AllocateZeroPool (sizeof (IKE_UDP_SERVICE));
+
+ if (Udp6Srv == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Create udp6 io for input.
+ //
+ Udp6Srv->Input = UdpIoCreateIo (
+ Controller,
+ ImageHandle,
+ IkeConfigUdp6,
+ UDP_IO_UDP6_VERSION,
+ NULL
+ );
+
+ if (Udp6Srv->Input == NULL) {
+ FreePool (Udp6Srv);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Udp6Srv->NicHandle = Controller;
+ Udp6Srv->ImageHandle = ImageHandle;
+ Udp6Srv->ListHead = &(Private->Udp6List);
+ Udp6Srv->IpVersion = UDP_IO_UDP6_VERSION;
+ Udp6Srv->IsConfigured = FALSE;
+
+ ZeroMem (&Udp6Srv->DefaultAddress, sizeof (EFI_IP_ADDRESS));
+
+ //
+ // Insert the udp6 io into the list and increase the count.
+ //
+ InsertTailList (&Private->Udp6List, &Udp6Srv->List);
+
+ Private->Udp6Num++;
+
+ UdpIoRecvDatagram (Udp6Srv->Input, IkeDispatch, Udp6Srv, 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The general interface of starting IPsec Key Exchange.
+
+ This function is called when a IKE negotiation to start getting a Key.
+
+ @param[in] UdpService Point to IKE_UDP_SERVICE which will be used for
+ IKE packet sending.
+ @param[in] SpdEntry Point to the SPD entry related to the IKE negotiation.
+ @param[in] RemoteIp Point to EFI_IP_ADDRESS related to the IKE negotiation.
+
+ @retval EFI_SUCCESS The Operation is successful.
+ @retval EFI_ACCESS_DENIED No related PAD entry was found.
+ @retval EFI_INVALID_PARAMETER The IKE version is not supported.
+
+**/
+EFI_STATUS
+IkeNegotiate (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IPSEC_SPD_ENTRY *SpdEntry,
+ IN EFI_IP_ADDRESS *RemoteIp
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *IkeSaSession;
+ IKE_EXCHANGE_INTERFACE *Exchange;
+ IPSEC_PRIVATE_DATA *Private;
+ IPSEC_PAD_ENTRY *PadEntry;
+ UINT8 IkeVersion;
+
+ Private = (UdpService->IpVersion == IP_VERSION_4) ?
+ IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :
+ IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
+
+ //
+ // Try to open udp io for output if it hasn't.
+ //
+ Status = IkeOpenOutputUdp (UdpService, RemoteIp);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Try to find the IKE SA session in the IKEv1 and IKEv2 established SA session list.
+ //
+ IkeSaSession = (UINT8 *) Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, RemoteIp);
+
+
+ if (IkeSaSession == NULL) {
+ //
+ // Find the pad entry by the remote ip address.
+ //
+ PadEntry = IpSecLookupPadEntry (UdpService->IpVersion, RemoteIp);
+ if (PadEntry == NULL) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Determine the IKE exchange instance by the auth protocol in pad entry.
+ //
+ ASSERT (PadEntry->Data->AuthProtocol < EfiIPsecAuthProtocolMaximum);
+ if (PadEntry->Data->AuthProtocol == EfiIPsecAuthProtocolIKEv1) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Exchange = mIkeExchange[PadEntry->Data->AuthProtocol];
+ //
+ // Start the main mode stage to negotiate IKE SA.
+ //
+ Status = Exchange->NegotiateSa (UdpService, SpdEntry, PadEntry, RemoteIp);
+ } else {
+ //
+ // Determine the IKE exchange instance by the IKE version in IKE SA session.
+ //
+ IkeVersion = IkeGetVersionFromSession (IkeSaSession);
+ if (IkeVersion != 2) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Exchange = mIkeExchange[IkeVersion - 1];
+ //
+ // Start the quick mode stage to negotiate child SA.
+ //
+ Status = Exchange->NegotiateChildSa (IkeSaSession, SpdEntry, NULL);
+ }
+
+ return Status;
+}
+
+/**
+ The generic interface when receive a IKE packet.
+
+ This function is called when UDP IO receives a IKE packet.
+
+ @param[in] Packet Point to received IKE packet.
+ @param[in] EndPoint Point to UDP_END_POINT which contains the information of
+ Remote IP and Port.
+ @param[in] IoStatus The Status of Recieve Token.
+ @param[in] Context Point to data passed from the caller.
+
+**/
+VOID
+EFIAPI
+IkeDispatch (
+ IN NET_BUF *Packet,
+ IN UDP_END_POINT *EndPoint,
+ IN EFI_STATUS IoStatus,
+ IN VOID *Context
+ )
+{
+ IPSEC_PRIVATE_DATA *Private;
+ IKE_PACKET *IkePacket;
+ IKE_HEADER *IkeHdr;
+ IKE_UDP_SERVICE *UdpService;
+ IKE_EXCHANGE_INTERFACE *Exchange;
+ EFI_STATUS Status;
+
+ UdpService = (IKE_UDP_SERVICE *) Context;
+ IkePacket = NULL;
+ Private = (UdpService->IpVersion == IP_VERSION_4) ?
+ IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :
+ IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
+
+ if (EFI_ERROR (IoStatus)) {
+ goto ON_EXIT;
+ }
+ //
+ // Check whether the ipsec is enabled or not.
+ //
+ if (Private->IpSec.DisabledFlag == TRUE) {
+ goto ON_EXIT;
+ }
+
+ if (EndPoint->RemotePort != IKE_DEFAULT_PORT) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Build IKE packet from the received netbuf.
+ //
+ IkePacket = IkePacketFromNetbuf (Packet);
+
+ if (IkePacket == NULL) {
+ goto ON_EXIT;
+ }
+ //
+ // Get the remote address from the IKE packet.
+ //
+ if (UdpService->IpVersion == IP_VERSION_4) {
+ *(UINT32 *) IkePacket->RemotePeerIp.Addr = HTONL ((*(UINT32 *) EndPoint->RemoteAddr.Addr));
+ } else {
+ CopyMem (
+ &IkePacket->RemotePeerIp,
+ NTOHLLL (&EndPoint->RemoteAddr.v6),
+ sizeof (EFI_IPv6_ADDRESS)
+ );
+ }
+ //
+ // Try to open udp io for output if hasn't.
+ //
+ Status = IkeOpenOutputUdp (UdpService, &IkePacket->RemotePeerIp);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ IkeHdr = IkePacket->Header;
+
+ //
+ // Determine the IKE exchange instance by the IKE version in IKE header.
+ //
+ if (IKE_MAJOR_VERSION (IkeHdr->Version) == 2) {
+ Exchange = mIkeExchange[IKE_MAJOR_VERSION (IkeHdr->Version) - 1];
+ } else {
+ goto ON_EXIT;
+ }
+
+ switch (IkeHdr->ExchangeType) {
+ case IKE_XCG_TYPE_IDENTITY_PROTECT:
+ case IKE_XCG_TYPE_SA_INIT:
+ case IKE_XCG_TYPE_AUTH:
+ Exchange->HandleSa (UdpService, IkePacket);
+ break;
+
+ case IKE_XCG_TYPE_QM:
+ case IKE_XCG_TYPE_CREATE_CHILD_SA:
+ Exchange->HandleChildSa (UdpService, IkePacket);
+ break;
+
+ case IKE_XCG_TYPE_INFO:
+ case IKE_XCG_TYPE_INFO2:
+ Exchange->HandleInfo (UdpService, IkePacket);
+ break;
+
+ default:
+ break;
+ }
+
+ON_EXIT:
+ if (IkePacket != NULL) {
+ IkePacketFree (IkePacket);
+ }
+
+ if (Packet != NULL) {
+ NetbufFree (Packet);
+ }
+
+ UdpIoRecvDatagram (UdpService->Input, IkeDispatch, UdpService, 0);
+
+ return ;
+}
+
+/**
+ Delete all established IKE SAs and related Child SAs.
+
+ This function is the subfunction of the IpSecCleanupAllSa(). It first calls
+ IkeDeleteChildSa() to delete all Child SAs then send out the related
+ Information packet.
+
+ @param[in] Private Pointer of the IPSEC_PRIVATE_DATA
+ @param[in] IsDisableIpsec Indicate whether needs to disable IPsec.
+
+**/
+VOID
+IkeDeleteAllSas (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN BOOLEAN IsDisableIpsec
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+ IKEV2_SA_SESSION *Ikev2SaSession;
+ UINT8 Value;
+ EFI_STATUS Status;
+ IKE_EXCHANGE_INTERFACE *Exchange;
+ UINT8 IkeVersion;
+
+ Exchange = NULL;
+
+ //
+ // If the IKEv1 is supported, first deal with the Ikev1Estatblished list.
+ //
+
+ //
+ // If IKEv2 SAs are under establishing, delete it directly.
+ //
+ if (!IsListEmpty (&Private->Ikev2SessionList)) {
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Private->Ikev2SessionList) {
+ Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);
+ RemoveEntryList (Entry);
+ Ikev2SaSessionFree (Ikev2SaSession);
+ }
+ }
+
+ //
+ // If there is no existing established IKE SA, set the Ipsec DisableFlag to TRUE
+ // and turn off the IsIPsecDisabling flag.
+ //
+ if (IsListEmpty (&Private->Ikev2EstablishedList) && IsDisableIpsec) {
+ Value = IPSEC_STATUS_DISABLED;
+ Status = gRT->SetVariable (
+ IPSECCONFIG_STATUS_NAME,
+ &gEfiIpSecConfigProtocolGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (Value),
+ &Value
+ );
+ if (!EFI_ERROR (Status)) {
+ Private->IpSec.DisabledFlag = TRUE;
+ Private->IsIPsecDisabling = FALSE;
+ return ;
+ }
+ }
+
+ //
+ // Delete established IKEv2 SAs.
+ //
+ if (!IsListEmpty (&Private->Ikev2EstablishedList)) {
+ for (Entry = Private->Ikev2EstablishedList.ForwardLink; Entry != &Private->Ikev2EstablishedList;) {
+ Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);
+ Entry = Entry->ForwardLink;
+
+ Ikev2SaSession->SessionCommon.State = IkeStateSaDeleting;
+
+ //
+ // Call for Information Exchange.
+ //
+ IkeVersion = IkeGetVersionFromSession ((UINT8*)Ikev2SaSession);
+ if (IkeVersion == 2) {
+ Exchange = mIkeExchange[IkeVersion - 1];
+ Exchange->NegotiateInfo((UINT8*)Ikev2SaSession, NULL);
+ }
+ }
+ }
+
+}
+
+
+
diff --git a/Core/NetworkPkg/IpSecDxe/IkeService.h b/Core/NetworkPkg/IpSecDxe/IkeService.h
new file mode 100644
index 0000000000..0e05dfe976
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IkeService.h
@@ -0,0 +1,262 @@
+/** @file
+ Prototypes definitions of IKE service.
+
+ Copyright (c) 2010 - 2015, 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.
+
+**/
+
+#ifndef _IKE_SERVICE_H_
+#define _IKE_SERVICE_H_
+
+#include "Ike.h"
+#include "IpSecImpl.h"
+#include "IkeCommon.h"
+#include "Ikev2/Utility.h"
+
+#define IPSEC_CRYPTO_LIB_MEMORY 128 * 1024
+
+/**
+ This is prototype definition of general interface to intialize a IKE negotiation.
+
+ @param[in] UdpService Point to Udp Servcie used for the IKE packet sending.
+ @param[in] SpdEntry Point to SPD entry related to this IKE negotiation.
+ @param[in] PadEntry Point to PAD entry related to this IKE negotiation.
+ @param[in] RemoteIp Point to IP Address which the remote peer to negnotiate.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @return Otherwise The operation is failed.
+
+**/
+typedef
+EFI_STATUS
+(*IKE_NEGOTIATE_SA) (
+ IN IKE_UDP_SERVICE * UdpService,
+ IN IPSEC_SPD_ENTRY * SpdEntry,
+ IN IPSEC_PAD_ENTRY * PadEntry,
+ IN EFI_IP_ADDRESS * RemoteIp
+ );
+
+/**
+ This is prototype definition fo general interface to start a IKE negotiation at Quick Mode.
+
+ This function will be called when the related IKE SA is existed and start to
+ create a Child SA.
+
+ @param[in] IkeSaSession Point to IKE SA Session related to this Negotiation.
+ @param[in] SpdEntry Point to SPD entry related to this Negotiation.
+ @param[in] Context Point to data passed from the caller.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval Otherwise The operation is failed.
+
+**/
+typedef
+EFI_STATUS
+(*IKE_NEGOTIATE_CHILD_SA) (
+ IN UINT8 *IkeSaSession,
+ IN IPSEC_SPD_ENTRY *SpdEntry,
+ IN UINT8 *Context
+ );
+
+/**
+ This is prototype definition of the general interface when initialize a Inforamtion
+ Exchange.
+
+ @param[in] IkeSaSession Point to IKE SA Session related to.
+ @param[in] Context Point to data passed from caller.
+
+**/
+typedef
+EFI_STATUS
+(*IKE_NEGOTIATE_INFO) (
+ IN UINT8 *IkeSaSession,
+ IN UINT8 *Context
+ );
+
+/**
+ This is prototype definition of the general interface when recived a IKE Pakcet
+ for the IKE SA establishing.
+
+ @param[in] UdpService Point to UDP service used to send IKE Packet.
+ @param[in] IkePacket Point to received IKE packet.
+
+**/
+typedef
+VOID
+(*IKE_HANDLE_SA) (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IKE_PACKET *IkePacket
+ );
+
+/**
+ This is prototyp definition of the general interface when recived a IKE Packet
+ xfor the Child SA establishing.
+
+ @param[in] UdpService Point to UDP service used to send IKE packet.
+ @param[in] IkePacket Point to received IKE packet.
+
+**/
+typedef
+VOID
+(*IKE_HANDLE_CHILD_SA) (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IKE_PACKET *IkePacket
+ );
+
+/**
+ This is prototype definition of the general interface when received a IKE
+ information Packet.
+
+ @param[in] UdpService Point to UDP service used to send IKE packet.
+ @param[in] IkePacket Point to received IKE packet.
+
+**/
+typedef
+VOID
+(*IKE_HANDLE_INFO) (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IKE_PACKET *IkePacket
+ );
+
+typedef struct _IKE_EXCHANGE_INTERFACE {
+ UINT8 IkeVer;
+ IKE_NEGOTIATE_SA NegotiateSa;
+ IKE_NEGOTIATE_CHILD_SA NegotiateChildSa;
+ IKE_NEGOTIATE_INFO NegotiateInfo;
+ IKE_HANDLE_SA HandleSa;
+ IKE_HANDLE_CHILD_SA HandleChildSa;
+ IKE_HANDLE_INFO HandleInfo;
+} IKE_EXCHANGE_INTERFACE;
+
+/**
+ Open and configure a UDPIO of Udp4 for IKE packet receiving.
+
+ This function is called at the IPsecDriverBinding start. IPsec create a UDP4 and
+ a UDP4 IO for each NIC handle.
+
+ @param[in] Private Point to IPSEC_PRIVATE_DATA
+ @param[in] Controller Handler for NIC card.
+ @param[in] ImageHandle The handle that contains the EFI_DRIVER_BINDING_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The Operation is successful.
+ @retval EFI_OUT_OF_RESOURCE The required system resource can't be allocated.
+
+**/
+EFI_STATUS
+IkeOpenInputUdp4 (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ Open and configure a UDPIO of Udp6 for IKE packet receiving.
+
+ This function is called at the IPsecDriverBinding start. IPsec create a UDP6 and UDP6
+ IO for each NIC handle.
+
+ @param[in] Private Point to IPSEC_PRIVATE_DATA
+ @param[in] Controller Handler for NIC card.
+ @param[in] ImageHandle The handle that contains the EFI_DRIVER_BINDING_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The Operation is successful.
+ @retval EFI_OUT_OF_RESOURCE The required system resource can't be allocated.
+
+**/
+EFI_STATUS
+IkeOpenInputUdp6 (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ The general interface of starting IPsec Key Exchange.
+
+ This function is called when start a IKE negotiation to get a Key.
+
+ @param[in] UdpService Point to IKE_UDP_SERVICE which will be used for
+ IKE packet sending.
+ @param[in] SpdEntry Point to the SPD entry related to the IKE negotiation.
+ @param[in] RemoteIp Point to EFI_IP_ADDRESS related to the IKE negotiation.
+
+ @retval EFI_SUCCESS The Operation is successful.
+ @retval EFI_ACCESS_DENIED No related PAD entry was found.
+
+**/
+EFI_STATUS
+IkeNegotiate (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IPSEC_SPD_ENTRY *SpdEntry,
+ IN EFI_IP_ADDRESS *RemoteIp
+ );
+
+/**
+ The general interface when receive a IKE packet.
+
+ This function is called when UDP IO receives a IKE packet.
+
+ @param[in] Packet Point to received IKE packet.
+ @param[in] EndPoint Point to UDP_END_POINT which contains the information of
+ Remote IP and Port.
+ @param[in] IoStatus The Status of Recieve Token.
+ @param[in] Context Point to data passed from the caller.
+
+**/
+VOID
+EFIAPI
+IkeDispatch (
+ IN NET_BUF *Packet,
+ IN UDP_END_POINT *EndPoint,
+ IN EFI_STATUS IoStatus,
+ IN VOID *Context
+ );
+
+/**
+ Check if the NIC handle is binded to a Udp service.
+
+ @param[in] Private Pointer of IPSEC_PRIVATE_DATA
+ @param[in] Handle The Handle of the NIC card
+ @param[in] IpVersion The version of the IP stack.
+
+ @return a pointer of IKE_UDP_SERVICE.
+
+**/
+IKE_UDP_SERVICE *
+IkeLookupUdp (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN EFI_HANDLE Handle,
+ IN UINT8 IpVersion
+ );
+
+
+/**
+ Delete all established IKE SAs and related Child SAs.
+
+ This function is the subfunction of the IpSecCleanupAllSa(). It first calls
+ IkeDeleteChildSa() to delete all Child SAs then send out the related
+ Information packet.
+
+ @param[in] Private Pointer of the IPSEC_PRIVATE_DATA.
+ @param[in] IsDisableIpsec Indicate whether needs to disable IPsec.
+
+**/
+VOID
+IkeDeleteAllSas (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN BOOLEAN IsDisableIpsec
+ );
+
+
+extern IKE_EXCHANGE_INTERFACE mIkev1Exchange;
+extern IKE_EXCHANGE_INTERFACE mIkev2Exchange;
+
+#endif
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c b/Core/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c
new file mode 100644
index 0000000000..1f0199b22d
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c
@@ -0,0 +1,199 @@
+/** @file
+ The operations for Child SA.
+
+ Copyright (c) 2010 - 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 "Utility.h"
+
+/**
+ Generate IKE Packet for CREATE_CHILD_SA exchange.
+
+ This IKE Packet would be the packet for creating new CHILD SA, or the packet for
+ rekeying existing IKE SA, or the packet for existing CHILD SA.
+
+ @param[in] SaSession Pointer to related SA session.
+ @param[in] Context The data passed by the caller.
+
+ return a pointer of IKE packet.
+
+**/
+IKE_PACKET *
+Ikev2CreateChildGenerator (
+ IN UINT8 *SaSession,
+ IN VOID *Context
+ )
+{
+
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKE_PACKET *IkePacket;
+ IKE_PAYLOAD *NotifyPayload;
+ UINT32 *MessageId;
+
+ NotifyPayload = NULL;
+ MessageId = NULL;
+
+ ChildSaSession = (IKEV2_CHILD_SA_SESSION *) SaSession;
+ if (ChildSaSession == NULL) {
+ return NULL;
+ }
+
+ IkePacket = IkePacketAlloc();
+ if (IkePacket == NULL) {
+ return NULL;
+ }
+
+
+ if (Context != NULL) {
+ MessageId = (UINT32 *) Context;
+ }
+
+ IkePacket->Header->Version = (UINT8) (2 << 4);
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NOTIFY;
+ IkePacket->Header->ExchangeType = IKE_XCG_TYPE_CREATE_CHILD_SA;
+
+ if (ChildSaSession->SessionCommon.IkeSessionType == IkeSessionTypeChildSa) {
+ //
+ // 1.a Fill the IkePacket->Hdr
+ //
+ IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie;
+
+ if (MessageId != NULL) {
+ IkePacket->Header->MessageId = *MessageId;
+ } else {
+ IkePacket->Header->MessageId = ChildSaSession->MessageId;
+ }
+
+ if (ChildSaSession->SessionCommon.IsInitiator) {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_CHILD_INIT;
+ } else {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
+ }
+
+ } else {
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+ //
+ // 1.a Fill the IkePacket->Hdr
+ //
+ IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
+
+ if (MessageId != NULL) {
+ IkePacket->Header->MessageId = *MessageId;
+ } else {
+ IkePacket->Header->MessageId = IkeSaSession->MessageId;
+ }
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_CHILD_INIT;
+ } else {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
+ }
+ }
+
+ //
+ // According to RFC4306, Chapter 4.
+ // A minimal implementation may support the CREATE_CHILD_SA exchange only to
+ // recognize requests and reject them with a Notify payload of type NO_ADDITIONAL_SAS.
+ //
+ NotifyPayload = Ikev2GenerateNotifyPayload (
+ 0,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ 0,
+ IKEV2_NOTIFICATION_NO_ADDITIONAL_SAS,
+ NULL,
+ NULL,
+ 0
+ );
+ if (NotifyPayload == NULL) {
+ IkePacketFree (IkePacket);
+ return NULL;
+ }
+
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
+ //
+ // TODO: Support the CREATE_CHILD_SA exchange.
+ //
+ return IkePacket;
+}
+
+/**
+ Parse the IKE packet of CREATE_CHILD_SA exchange.
+
+ This function parse the IKE packet and save the related information to further
+ calculation.
+
+ @param[in] SaSession Pointer to IKEv2_CHILD_SA_SESSION related to this Exchange.
+ @param[in] IkePacket Received packet to be parsed.
+
+
+ @retval EFI_SUCCESS The IKE Packet is acceptable.
+ @retval EFI_UNSUPPORTED Not support the CREATE_CHILD_SA request.
+
+**/
+EFI_STATUS
+Ikev2CreateChildParser (
+ IN UINT8 *SaSession,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Routine process before the payload decoding.
+
+ @param[in] SessionCommon Pointer to ChildSa SessionCommon.
+ @param[in] PayloadBuf Pointer to the payload.
+ @param[in] PayloadSize Size of PayloadBuf in byte.
+ @param[in] PayloadType Type of Payload.
+
+**/
+VOID
+Ikev2ChildSaBeforeDecodePayload (
+ IN UINT8 *SessionCommon,
+ IN UINT8 *PayloadBuf,
+ IN UINTN PayloadSize,
+ IN UINT8 PayloadType
+ )
+{
+
+}
+
+/**
+ Routine Process after the payload encoding.
+
+ @param[in] SessionCommon Pointer to ChildSa SessionCommon.
+ @param[in] PayloadBuf Pointer to the payload.
+ @param[in] PayloadSize Size of PayloadBuf in byte.
+ @param[in] PayloadType Type of Payload.
+
+**/
+VOID
+Ikev2ChildSaAfterEncodePayload (
+ IN UINT8 *SessionCommon,
+ IN UINT8 *PayloadBuf,
+ IN UINTN PayloadSize,
+ IN UINT8 PayloadType
+ )
+{
+}
+
+IKEV2_PACKET_HANDLER mIkev2CreateChild = {
+ //
+ // Create Child
+ //
+ Ikev2CreateChildParser,
+ Ikev2CreateChildGenerator
+};
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/Exchange.c b/Core/NetworkPkg/IpSecDxe/Ikev2/Exchange.c
new file mode 100644
index 0000000000..1eddbfbcf1
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Exchange.c
@@ -0,0 +1,809 @@
+/** @file
+ The general interfaces of the IKEv2.
+
+ Copyright (c) 2010 - 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 "Utility.h"
+#include "IpSecDebug.h"
+#include "IkeService.h"
+#include "IpSecConfigImpl.h"
+
+/**
+ General interface to intialize a IKEv2 negotiation.
+
+ @param[in] UdpService Point to Udp Servcie used for the IKE packet sending.
+ @param[in] SpdEntry Point to SPD entry related to this IKE negotiation.
+ @param[in] PadEntry Point to PAD entry related to this IKE negotiation.
+ @param[in] RemoteIp Point to IP Address which the remote peer to negnotiate.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.
+ @retval EFI_INVALID_PARAMETER If UdpService or RemoteIp is NULL.
+ @return Others The operation is failed.
+
+**/
+EFI_STATUS
+Ikev2NegotiateSa (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IPSEC_SPD_ENTRY *SpdEntry,
+ IN IPSEC_PAD_ENTRY *PadEntry,
+ IN EFI_IP_ADDRESS *RemoteIp
+ )
+{
+ IPSEC_PRIVATE_DATA *Private;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_SESSION_COMMON *SessionCommon;
+ IKEV2_PACKET_HANDLER Handler;
+ IKE_PACKET *IkePacket;
+ EFI_STATUS Status;
+
+ if (UdpService == NULL || RemoteIp == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IkePacket = NULL;
+ Private = (UdpService->IpVersion == IP_VERSION_4) ?
+ IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :
+ IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
+
+ //
+ // Lookup the remote ip address in the processing IKE SA session list.
+ //
+ IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2SessionList, RemoteIp);
+ if (IkeSaSession != NULL) {
+ //
+ // Drop the packet if already in process.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Create a new IkeSaSession and initiate the common parameters.
+ //
+ IkeSaSession = Ikev2SaSessionAlloc (Private, UdpService);
+ if (IkeSaSession == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set the specific parameters and state(IKE_STATE_INIT).
+ //
+ IkeSaSession->Spd = SpdEntry;
+ IkeSaSession->Pad = PadEntry;
+ SessionCommon = &IkeSaSession->SessionCommon;
+ SessionCommon->IsInitiator = TRUE;
+ SessionCommon->State = IkeStateInit;
+ //
+ // TODO: Get the prefer DH Group from the IPsec Configuration, after the IPsecconfig application update
+ // to support it.
+ //
+ SessionCommon->PreferDhGroup = IKEV2_TRANSFORM_ID_DH_1024MODP;
+
+ CopyMem (
+ &SessionCommon->RemotePeerIp,
+ RemoteIp,
+ sizeof (EFI_IP_ADDRESS)
+ );
+
+ CopyMem (
+ &SessionCommon->LocalPeerIp,
+ &UdpService->DefaultAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+
+ IKEV2_DUMP_STATE (SessionCommon->State, IkeStateInit);
+
+ //
+ // Initiate the SAD data of the IkeSaSession.
+ //
+ IkeSaSession->SaData = Ikev2InitializeSaData (SessionCommon);
+ if (IkeSaSession->SaData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ //
+ // Generate an IKE request packet and send it out.
+ //
+ Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][SessionCommon->State];
+ IkePacket = Handler.Generator ((UINT8 *) IkeSaSession, NULL);
+ if (IkePacket == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ Status = Ikev2SendIkePacket (UdpService, (UINT8 *) SessionCommon, IkePacket, 0);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Insert the current IkeSaSession into the processing IKE SA list.
+ //
+ Ikev2SaSessionInsert (&Private->Ikev2SessionList, IkeSaSession, RemoteIp);
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (IkePacket != NULL) {
+ IkePacketFree (IkePacket);
+ }
+ Ikev2SaSessionFree (IkeSaSession);
+ return Status;
+}
+
+/**
+ It is general interface to negotiate the Child SA.
+
+ There are three situations which will invoke this function. First, create a CHILD
+ SA if the input Context is NULL. Second, rekeying the existing IKE SA if the Context
+ is a IKEv2_SA_SESSION. Third, rekeying the existing CHILD SA if the context is a
+ IKEv2_CHILD_SA_SESSION.
+
+ @param[in] IkeSaSession Pointer to IKEv2_SA_SESSION related to this operation.
+ @param[in] SpdEntry Pointer to IPSEC_SPD_ENTRY related to this operation.
+ @param[in] Context The data pass from the caller.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.
+ @retval EFI_UNSUPPORTED The condition is not support yet.
+ @return Others The operation is failed.
+
+**/
+EFI_STATUS
+Ikev2NegotiateChildSa (
+ IN UINT8 *IkeSaSession,
+ IN IPSEC_SPD_ENTRY *SpdEntry,
+ IN UINT8 *Context
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_SA_SESSION *SaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SESSION_COMMON *ChildSaCommon;
+ IKE_PACKET *IkePacket;
+ IKE_UDP_SERVICE *UdpService;
+
+ SaSession = (IKEV2_SA_SESSION*) IkeSaSession;
+ UdpService = SaSession->SessionCommon.UdpService;
+ IkePacket = NULL;
+
+ //
+ // 1. Create another child SA session if context is null.
+ // 2. Rekeying the IKE SA session if the context is IKE SA session.
+ // 3. Rekeying the child SA session if the context is child SA session.
+ //
+ if (Context == NULL) {
+ //
+ // Create a new ChildSaSession and initiate the common parameters.
+ //
+ ChildSaSession = Ikev2ChildSaSessionAlloc (UdpService, SaSession);
+
+ if (ChildSaSession == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set the specific parameters and state as IKE_STATE_CREATE_CHILD.
+ //
+ ChildSaSession->Spd = SpdEntry;
+ ChildSaCommon = &ChildSaSession->SessionCommon;
+ ChildSaCommon->IsInitiator = TRUE;
+ ChildSaCommon->State = IkeStateCreateChild;
+
+ IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateCreateChild);
+
+ if (SpdEntry->Selector->NextLayerProtocol != EFI_IPSEC_ANY_PROTOCOL) {
+ ChildSaSession->ProtoId = SpdEntry->Selector->NextLayerProtocol;
+ }
+
+ if (SpdEntry->Selector->LocalPort != EFI_IPSEC_ANY_PORT) {
+ ChildSaSession->LocalPort = SpdEntry->Selector->LocalPort;
+ }
+
+ if (SpdEntry->Selector->RemotePort != EFI_IPSEC_ANY_PORT) {
+ ChildSaSession->RemotePort = SpdEntry->Selector->RemotePort;
+ }
+ //
+ // Initiate the SAD data parameters of the ChildSaSession.
+ //
+ ChildSaSession->SaData = Ikev2InitializeSaData (ChildSaCommon);
+ if (ChildSaSession->SaData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+ //
+ // Generate an IKE request packet and send it out.
+ //
+ IkePacket = mIkev2CreateChild.Generator ((UINT8 *) ChildSaSession, NULL);
+
+ if (IkePacket == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ Status = Ikev2SendIkePacket (UdpService, (UINT8 *) ChildSaCommon, IkePacket, 0);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Insert the ChildSaSession into processing child SA list.
+ //
+ Ikev2ChildSaSessionInsert (&SaSession->ChildSaSessionList, ChildSaSession);
+ } else {
+ //
+ // TODO: Rekeying IkeSaSession or ChildSaSession, NOT support yet.
+ //
+ // Rekey IkeSa, set IkeSaSession->State and pass over IkeSaSession
+ // Rekey ChildSa, set ChildSaSession->State and pass over ChildSaSession
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+
+ON_ERROR:
+
+ if (ChildSaSession->SaData != NULL) {
+ FreePool (ChildSaSession->SaData);
+ }
+
+ if (ChildSaSession->SessionCommon.TimeoutEvent != NULL) {
+ gBS->CloseEvent (ChildSaSession->SessionCommon.TimeoutEvent);
+ }
+
+ if (IkePacket != NULL) {
+ IkePacketFree (IkePacket);
+ }
+
+ Ikev2ChildSaSessionFree (ChildSaSession);
+ return Status;
+}
+
+/**
+ It is general interface to start the Information Exchange.
+
+ There are three situations which will invoke this function. First, deliver a Delete Information
+ to delete the IKE SA if the input Context is NULL and the state of related IkeSaSeesion's is on
+ deleting.Second, deliver a Notify Information without the contents if the input Context is NULL.
+ Third, deliver a Notify Information if the input Context is not NULL.
+
+ @param[in] IkeSaSession Pointer to IKEv2_SA_SESSION related to this operation.
+ @param[in] Context Data passed by caller.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval EFI_OUT_OF_RESOURCES The required system resource can't be allocated.
+ @retval EFI_UNSUPPORTED The condition is not support yet.
+ @return Otherwise The operation is failed.
+
+**/
+EFI_STATUS
+Ikev2NegotiateInfo (
+ IN UINT8 *IkeSaSession,
+ IN UINT8 *Context
+ )
+{
+
+ EFI_STATUS Status;
+ IKEV2_SA_SESSION *Ikev2SaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SESSION_COMMON *SaCommon;
+ IKE_PACKET *IkePacket;
+ IKE_UDP_SERVICE *UdpService;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+
+ Ikev2SaSession = (IKEV2_SA_SESSION *) IkeSaSession;
+ UdpService = Ikev2SaSession->SessionCommon.UdpService;
+ SaCommon = &Ikev2SaSession->SessionCommon;
+ IkePacket = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Delete the IKE SA.
+ //
+ if (Ikev2SaSession->SessionCommon.State == IkeStateSaDeleting && Context == NULL) {
+
+ //
+ // Generate Information Packet which contains the Delete Payload.
+ //
+ IkePacket = mIkev2Info.Generator ((UINT8 *) Ikev2SaSession, NULL);
+ if (IkePacket == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ //
+ // Send out the Packet
+ //
+ if (UdpService != NULL && UdpService->Output != NULL) {
+ Status = Ikev2SendIkePacket (UdpService, (UINT8 *) SaCommon, IkePacket, 0);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+ } else if (!IsListEmpty (&Ikev2SaSession->DeleteSaList)) {
+ //
+ // Iterate all Deleting Child SAs.
+ //
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Ikev2SaSession->DeleteSaList) {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_DEL_SA (Entry);
+ ChildSaSession->SessionCommon.State = IkeStateSaDeleting;
+
+ //
+ // Generate Information Packet which contains the Child SA Delete Payload.
+ //
+ IkePacket = mIkev2Info.Generator ((UINT8 *) ChildSaSession, NULL);
+ if (IkePacket == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_ERROR;
+ }
+
+ //
+ // Send out the Packet
+ //
+ if (UdpService != NULL && UdpService->Output != NULL) {
+ Status = Ikev2SendIkePacket (UdpService, (UINT8 *) &ChildSaSession->SessionCommon, IkePacket, 0);
+
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ }
+ }
+ } else if (Context == NULL) {
+ //
+ // TODO: Deliver null notification message.
+ //
+ } else if (Context != NULL) {
+ //
+ // TODO: Send out the Information Exchange which contains the Notify Payload.
+ //
+ }
+ON_ERROR:
+ if (IkePacket != NULL) {
+ IkePacketFree (IkePacket);
+ }
+ return Status;
+
+}
+
+/**
+ The general interface when received a IKEv2 packet for the IKE SA establishing.
+
+ This function first find the related IKE SA Session according to the IKE packet's
+ remote IP. Then call the corresponding function to handle this IKE packet according
+ to the related IKE SA Session's State.
+
+ @param[in] UdpService Pointer of related UDP Service.
+ @param[in] IkePacket Data passed by caller.
+
+**/
+VOID
+Ikev2HandleSa (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SESSION_COMMON *IkeSaCommon;
+ IKEV2_SESSION_COMMON *ChildSaCommon;
+ IKEV2_PACKET_HANDLER Handler;
+ IKE_PACKET *Reply;
+ IPSEC_PAD_ENTRY *PadEntry;
+ IPSEC_PRIVATE_DATA *Private;
+ BOOLEAN IsNewSession;
+
+ Private = (UdpService->IpVersion == IP_VERSION_4) ?
+ IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :
+ IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
+
+ ChildSaSession = NULL;
+ ChildSaCommon = NULL;
+
+ //
+ // Lookup the remote ip address in the processing IKE SA session list.
+ //
+ IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2SessionList, &IkePacket->RemotePeerIp);
+ IsNewSession = FALSE;
+
+ if (IkeSaSession == NULL) {
+ //
+ // Lookup the remote ip address in the pad.
+ //
+ PadEntry = IpSecLookupPadEntry (UdpService->IpVersion, &IkePacket->RemotePeerIp);
+ if (PadEntry == NULL) {
+ //
+ // Drop the packet if no pad entry matched, this is the request from RFC 4301.
+ //
+ return ;
+ }
+
+ //
+ // Create a new IkeSaSession and initiate the common parameters.
+ //
+ IkeSaSession = Ikev2SaSessionAlloc (Private, UdpService);
+ if (IkeSaSession == NULL) {
+ return;
+ }
+ IkeSaSession->Pad = PadEntry;
+ IkeSaCommon = &IkeSaSession->SessionCommon;
+ IkeSaCommon->IsInitiator = FALSE;
+ IkeSaCommon->State = IkeStateInit;
+
+ IKEV2_DUMP_STATE (IkeSaCommon->State, IkeStateInit);
+
+ CopyMem (
+ &IkeSaCommon->RemotePeerIp,
+ &IkePacket->RemotePeerIp,
+ sizeof (EFI_IP_ADDRESS)
+ );
+
+ CopyMem (
+ &IkeSaCommon->LocalPeerIp,
+ &UdpService->DefaultAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+
+ IsNewSession = TRUE;
+ }
+
+ //
+ // Validate the IKE packet header.
+ //
+ if (!Ikev2ValidateHeader (IkeSaSession, IkePacket->Header)) {
+ //
+ // Drop the packet if invalid IKE header.
+ //
+ goto ON_ERROR;
+ }
+
+ //
+ // Decode all the payloads in the IKE packet.
+ //
+ IkeSaCommon = &IkeSaSession->SessionCommon;
+ Status = Ikev2DecodePacket (IkeSaCommon, IkePacket, IkeSessionTypeIkeSa);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Try to reate the first ChildSa Session of that IkeSaSession.
+ // If the IkeSaSession is responder, here will create the first ChildSaSession.
+ //
+ if (IkeSaCommon->State == IkeStateAuth && IsListEmpty(&IkeSaSession->ChildSaSessionList)) {
+ //
+ // Generate a piggyback child SA in IKE_STATE_AUTH state.
+ //
+ ASSERT (IsListEmpty (&IkeSaSession->ChildSaSessionList) &&
+ IsListEmpty (&IkeSaSession->ChildSaEstablishSessionList));
+
+ ChildSaSession = Ikev2ChildSaSessionCreate (IkeSaSession, UdpService);
+ if (ChildSaSession == NULL) {
+ goto ON_ERROR;
+ }
+
+ ChildSaCommon = &ChildSaSession->SessionCommon;
+ }
+
+ //
+ // Parse the IKE request packet according to the auth method and current state.
+ //
+ Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][IkeSaCommon->State];
+ Status = Handler.Parser ((UINT8 *)IkeSaSession, IkePacket);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+
+ //
+ // Try to reate the first ChildSa Session of that IkeSaSession.
+ // If the IkeSaSession is initiator, here will create the first ChildSaSession.
+ //
+ if (IkeSaCommon->State == IkeStateAuth && IsListEmpty(&IkeSaSession->ChildSaSessionList)) {
+ //
+ // Generate a piggyback child SA in IKE_STATE_AUTH state.
+ //
+ ASSERT (IsListEmpty (&IkeSaSession->ChildSaSessionList) &&
+ IsListEmpty (&IkeSaSession->ChildSaEstablishSessionList));
+
+ ChildSaSession = Ikev2ChildSaSessionCreate (IkeSaSession, UdpService);
+ if (ChildSaSession == NULL) {
+ goto ON_ERROR;
+ }
+
+ ChildSaCommon = &ChildSaSession->SessionCommon;
+
+ //
+ // Initialize the SA data for Child SA.
+ //
+ ChildSaSession->SaData = Ikev2InitializeSaData (ChildSaCommon);
+ }
+
+ //
+ // Generate the IKE response packet and send it out if not established.
+ //
+ if (IkeSaCommon->State != IkeStateIkeSaEstablished) {
+ Handler = mIkev2Initial[IkeSaSession->Pad->Data->AuthMethod][IkeSaCommon->State];
+ Reply = Handler.Generator ((UINT8 *) IkeSaSession, NULL);
+ if (Reply == NULL) {
+ goto ON_ERROR;
+ }
+
+ Status = Ikev2SendIkePacket (UdpService, (UINT8 *) IkeSaCommon, Reply, 0);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
+ if (!IkeSaCommon->IsInitiator) {
+ IkeSaCommon->State ++;
+ IKEV2_DUMP_STATE (IkeSaCommon->State - 1, IkeSaCommon->State);
+ }
+ }
+
+ //
+ // Insert the new IkeSaSession into the Private processing IkeSaSession List.
+ //
+ if (IsNewSession) {
+ Ikev2SaSessionInsert (&Private->Ikev2SessionList, IkeSaSession, &IkePacket->RemotePeerIp);
+ }
+
+ //
+ // Register the IkeSaSession and remove it from processing list.
+ //
+ if (IkeSaCommon->State == IkeStateIkeSaEstablished) {
+
+ //
+ // Remove the Established IKE SA Session from the IKE SA Session Negotiating list
+ // and insert it into IKE SA Session Established list.
+ //
+ Ikev2SaSessionRemove (&Private->Ikev2SessionList, &IkePacket->RemotePeerIp);
+ Ikev2SaSessionReg (IkeSaSession, Private);
+
+ //
+ // Remove the Established Child SA Session from the IkeSaSession->ChildSaSessionList
+ // ,insert it into IkeSaSession->ChildSaEstablishSessionList and save this Child SA
+ // into SAD.
+ //
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (IkeSaSession->ChildSaSessionList.BackLink);
+ Ikev2ChildSaSessionRemove (
+ &IkeSaSession->ChildSaSessionList,
+ ChildSaSession->LocalPeerSpi,
+ IKEV2_ESTABLISHING_CHILDSA_LIST
+ );
+ Ikev2ChildSaSessionReg (ChildSaSession, Private);
+ }
+
+ return ;
+
+ON_ERROR:
+ if (ChildSaSession != NULL) {
+ //
+ // Remove the ChildSa from the list (Established list or Negotiating list).
+ //
+ RemoveEntryList (&ChildSaSession->ByIkeSa);
+ Ikev2ChildSaSessionFree (ChildSaSession);
+ }
+
+ if (IsNewSession && IkeSaSession != NULL) {
+ //
+ // Remove the IkeSa from the list (Established list or Negotiating list).
+ //
+ if ((&IkeSaSession->BySessionTable)->ForwardLink != NULL &&
+ !IsListEmpty (&IkeSaSession->BySessionTable
+ )){
+ RemoveEntryList (&IkeSaSession->BySessionTable);
+ }
+ Ikev2SaSessionFree (IkeSaSession);
+ }
+
+ return ;
+}
+
+/**
+
+ The general interface when received a IKEv2 packet for the IKE Child SA establishing
+ or IKE SA/CHILD SA rekeying.
+
+ This function first find the related IKE SA Session according to the IKE packet's
+ remote IP. Then call the corresponding function to handle this IKE packet according
+ to the related IKE Child Session's State.
+
+ @param[in] UdpService Pointer of related UDP Service.
+ @param[in] IkePacket Data passed by caller.
+
+**/
+VOID
+Ikev2HandleChildSa (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_CREATE_CHILD_REQUEST_TYPE RequestType;
+ IKE_PACKET *Reply;
+ IPSEC_PRIVATE_DATA *Private;
+
+ Private = (UdpService->IpVersion == IP_VERSION_4) ?
+ IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :
+ IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
+
+ Reply = NULL;
+
+ //
+ // Lookup the remote ip address in the processing IKE SA session list.
+ //
+ IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, &IkePacket->RemotePeerIp);
+
+ if (IkeSaSession == NULL) {
+ //
+ // Drop the packet if no IKE SA associated.
+ //
+ return ;
+ }
+
+ //
+ // Validate the IKE packet header.
+ //
+ if (!Ikev2ValidateHeader (IkeSaSession, IkePacket->Header)) {
+ //
+ // Drop the packet if invalid IKE header.
+ //
+ return;
+ }
+
+ //
+ // Decode all the payloads in the IKE packet.
+ //
+ Status = Ikev2DecodePacket (&IkeSaSession->SessionCommon, IkePacket, IkeSessionTypeIkeSa);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Get the request type: CreateChildSa/RekeyChildSa/RekeyIkeSa.
+ //
+ RequestType = Ikev2ChildExchangeRequestType (IkePacket);
+
+ switch (RequestType) {
+ case IkeRequestTypeCreateChildSa:
+ case IkeRequestTypeRekeyChildSa:
+ case IkeRequestTypeRekeyIkeSa:
+ //
+ // Parse the IKE request packet. Not support CREATE_CHILD_SA exchange yet, so
+ // only EFI_UNSUPPORTED will be returned and that will trigger a reply with a
+ // Notify payload of type NO_ADDITIONAL_SAS.
+ //
+ Status = mIkev2CreateChild.Parser ((UINT8 *) IkeSaSession, IkePacket);
+ if (EFI_ERROR (Status)) {
+ goto ON_REPLY;
+ }
+
+ default:
+ //
+ // No support.
+ //
+ return ;
+ }
+
+ON_REPLY:
+ //
+ // Generate the reply packet if needed and send it out.
+ //
+ if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) {
+ Reply = mIkev2CreateChild.Generator ((UINT8 *) IkeSaSession, &IkePacket->Header->MessageId);
+ if (Reply != NULL) {
+ Status = Ikev2SendIkePacket (UdpService, (UINT8 *) &(IkeSaSession->SessionCommon), Reply, 0);
+ if (EFI_ERROR (Status)) {
+ //
+ // Delete Reply payload.
+ //
+ if (Reply != NULL) {
+ IkePacketFree (Reply);
+ }
+ }
+ }
+ }
+ return ;
+}
+
+/**
+
+ It is general interface to handle IKEv2 information Exchange.
+
+ @param[in] UdpService Point to IKE UPD Service related to this information exchange.
+ @param[in] IkePacket The IKE packet to be parsed.
+
+**/
+VOID
+Ikev2HandleInfo (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_SESSION_COMMON *SessionCommon;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IPSEC_PRIVATE_DATA *Private;
+
+ Private = (UdpService->IpVersion == IP_VERSION_4) ?
+ IPSEC_PRIVATE_DATA_FROM_UDP4LIST(UdpService->ListHead) :
+ IPSEC_PRIVATE_DATA_FROM_UDP6LIST(UdpService->ListHead);
+
+ //
+ // Lookup the remote ip address in the processing IKE SA session list.
+ //
+ IkeSaSession = Ikev2SaSessionLookup (&Private->Ikev2EstablishedList, &IkePacket->RemotePeerIp);
+
+ if (IkeSaSession == NULL) {
+ //
+ // Drop the packet if no IKE SA associated.
+ //
+ return ;
+ }
+ //
+ // Validate the IKE packet header.
+ //
+ if (!Ikev2ValidateHeader (IkeSaSession, IkePacket->Header)) {
+
+ //
+ // Drop the packet if invalid IKE header.
+ //
+ return;
+ }
+
+ SessionCommon = &IkeSaSession->SessionCommon;
+
+ //
+ // Decode all the payloads in the IKE packet.
+ //
+ Status = Ikev2DecodePacket (SessionCommon, IkePacket, IkeSessionTypeIkeSa);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = mIkev2Info.Parser ((UINT8 *)IkeSaSession, IkePacket);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Drop the packet if fail to parse.
+ //
+ return;
+ }
+}
+
+IKE_EXCHANGE_INTERFACE mIkev1Exchange = {
+ 1,
+ NULL, //Ikev1NegotiateSa
+ NULL, //Ikev1NegotiateChildSa
+ NULL,
+ NULL, //Ikev1HandleSa,
+ NULL, //Ikev1HandleChildSa
+ NULL, //Ikev1HandleInfo
+};
+
+IKE_EXCHANGE_INTERFACE mIkev2Exchange = {
+ 2,
+ Ikev2NegotiateSa,
+ Ikev2NegotiateChildSa,
+ Ikev2NegotiateInfo,
+ Ikev2HandleSa,
+ Ikev2HandleChildSa,
+ Ikev2HandleInfo
+};
+
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/Ikev2.h b/Core/NetworkPkg/IpSecDxe/Ikev2/Ikev2.h
new file mode 100644
index 0000000000..a2b733a4d2
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Ikev2.h
@@ -0,0 +1,258 @@
+/** @file
+ IKEv2 related definitions.
+
+ Copyright (c) 2010, 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.
+
+**/
+#ifndef _IKE_V2_H_
+#define _IKE_V2_H_
+
+#include "Ike.h"
+#include "Payload.h"
+
+#define IKEV2_TS_ANY_PORT 0xffff
+#define IKEV2_TS_ANY_PROTOCOL 0
+
+#define IKEV2_DELET_CHILDSA_LIST 0
+#define IKEV2_ESTABLISHING_CHILDSA_LIST 1
+#define IKEV2_ESTABLISHED_CHILDSA_LIST 2
+
+#define IKEV2_SA_SESSION_SIGNATURE SIGNATURE_32 ('I', 'K', 'E', 'I')
+#define IKEV2_SA_SESSION_FROM_COMMON(a) CR (a, IKEV2_SA_SESSION, SessionCommon, IKEV2_SA_SESSION_SIGNATURE)
+#define IKEV2_SA_SESSION_BY_SESSION(a) CR (a, IKEV2_SA_SESSION, BySessionTable, IKEV2_SA_SESSION_SIGNATURE)
+#define IKEV2_SA_SESSION_BY_ESTABLISHED(a) CR (a, IKEV2_SA_SESSION, ByEstablishedTable, IKEV2_SA_SESSION_SIGNATURE)
+
+#define IKEV2_CHILD_SA_SESSION_SIGNATURE SIGNATURE_32 ('I', 'K', 'E', 'C')
+#define IKEV2_CHILD_SA_SESSION_FROM_COMMON(a) CR (a, IKEV2_CHILD_SA_SESSION, SessionCommon, IKEV2_CHILD_SA_SESSION_SIGNATURE)
+#define IKEV2_CHILD_SA_SESSION_BY_IKE_SA(a) CR (a, IKEV2_CHILD_SA_SESSION, ByIkeSa, IKEV2_CHILD_SA_SESSION_SIGNATURE)
+#define IKEV2_CHILD_SA_SESSION_BY_DEL_SA(a) CR (a, IKEV2_CHILD_SA_SESSION, ByDelete, IKEV2_CHILD_SA_SESSION_SIGNATURE)
+
+#define IS_IKEV2_SA_SESSION(s) ((s)->Common.IkeSessionType == IkeSessionTypeIkeSa)
+#define IKEV2_SA_FIRST_PROPOSAL(Sa) (IKEV2_PROPOSAL *)((IKEV2_SA *)(Sa)+1)
+#define IKEV2_NEXT_TRANSFORM_WITH_SIZE(Transform,TransformSize) \
+ (IKEV2_TRANSFORM *) ((UINT8 *)(Transform) + (TransformSize))
+
+#define IKEV2_NEXT_PROPOSAL_WITH_SIZE(Proposal, ProposalSize) \
+ (IKEV2_PROPOSAL *) ((UINT8 *)(Proposal) + (ProposalSize))
+
+#define IKEV2_PROPOSAL_FIRST_TRANSFORM(Proposal) \
+ (IKEV2_TRANSFORM *)((UINT8 *)((IKEV2_PROPOSAL *)(Proposal)+1) + \
+ (((IKEV2_PROPOSAL *)(Proposal))->SpiSize))
+#define IKEV2_PROPOSAL_FIRST_TRANSFORM(Proposal) \
+ (IKEV2_TRANSFORM *)((UINT8 *)((IKEV2_PROPOSAL *)(Proposal)+1) + \
+ (((IKEV2_PROPOSAL *)(Proposal))->SpiSize))
+
+typedef enum {
+ IkeStateInit,
+ IkeStateAuth,
+ IkeStateIkeSaEstablished,
+ IkeStateCreateChild,
+ IkeStateSaRekeying,
+ IkeStateChildSaEstablished,
+ IkeStateSaDeleting,
+ IkeStateMaximum
+} IKEV2_SESSION_STATE;
+
+typedef enum {
+ IkeRequestTypeCreateChildSa,
+ IkeRequestTypeRekeyChildSa,
+ IkeRequestTypeRekeyIkeSa,
+ IkeRequestTypeMaximum
+} IKEV2_CREATE_CHILD_REQUEST_TYPE;
+
+typedef struct {
+ UINT8 *GxBuffer;
+ UINTN GxSize;
+ UINT8 *GyBuffer;
+ UINTN GySize;
+ UINT8 *GxyBuffer;
+ UINTN GxySize;
+ UINT8 *DhContext;
+} IKEV2_DH_BUFFER;
+
+typedef struct {
+ IKEV2_DH_BUFFER *DhBuffer;
+ UINT8 *SkdKey;
+ UINTN SkdKeySize;
+ UINT8 *SkAiKey;
+ UINTN SkAiKeySize;
+ UINT8 *SkArKey;
+ UINTN SkArKeySize;
+ UINT8 *SkEiKey;
+ UINTN SkEiKeySize;
+ UINT8 *SkErKey;
+ UINTN SkErKeySize;
+ UINT8 *SkPiKey;
+ UINTN SkPiKeySize;
+ UINT8 *SkPrKey;
+ UINTN SkPrKeySize;
+} IKEV2_SESSION_KEYS;
+
+typedef struct {
+ UINT16 LifeType;
+ UINT64 LifeDuration;
+ UINT16 EncAlgId;
+ UINTN EnckeyLen;
+ UINT16 Prf;
+ UINT16 IntegAlgId;
+ UINTN IntegKeyLen;
+ UINT16 DhGroup;
+ UINT8 ExtSeq;
+} IKEV2_SA_PARAMS;
+
+//
+// Internal Payload
+//
+typedef struct {
+ IKEV2_SA SaHeader;
+ UINTN NumProposals;
+ //
+ // IKE_PROPOSAL_DATA Proposals[1];
+ //
+} IKEV2_SA_DATA;
+
+typedef struct {
+ UINT8 ProposalIndex;
+ UINT8 ProtocolId;
+ UINT8 *Spi;
+ UINT8 NumTransforms;
+ //
+ // IKE_TRANSFORM_DATA Transforms[1];
+ //
+} IKEV2_PROPOSAL_DATA;
+
+typedef struct {
+ UINT8 TransformIndex;
+ UINT8 TransformType;
+ UINT16 TransformId;
+ IKE_SA_ATTRIBUTE Attribute;
+} IKEV2_TRANSFORM_DATA;
+
+typedef struct {
+ UINT8 IkeVer;
+ IKE_SESSION_TYPE IkeSessionType;
+ BOOLEAN IsInitiator;
+ BOOLEAN IsOnDeleting; // Flag to indicate whether the SA is on deleting.
+ IKEV2_SESSION_STATE State;
+ EFI_EVENT TimeoutEvent;
+ UINT64 TimeoutInterval;
+ UINTN RetryCount;
+ IKE_PACKET *LastSentPacket;
+ IKEV2_SA_PARAMS *SaParams;
+ UINT16 PreferDhGroup;
+ EFI_IP_ADDRESS RemotePeerIp;
+ EFI_IP_ADDRESS LocalPeerIp;
+ IKE_ON_PAYLOAD_FROM_NET BeforeDecodePayload;
+ IKE_ON_PAYLOAD_FROM_NET AfterEncodePayload;
+ IKE_UDP_SERVICE *UdpService;
+ IPSEC_PRIVATE_DATA *Private;
+} IKEV2_SESSION_COMMON;
+
+typedef struct {
+ UINT32 Signature;
+ IKEV2_SESSION_COMMON SessionCommon;
+ UINT64 InitiatorCookie;
+ UINT64 ResponderCookie;
+ //
+ // Initiator: SA proposals to be sent
+ // Responder: SA proposals to be matched
+ //
+ IKEV2_SA_DATA *SaData; // SA Private struct used for SA payload generation
+ IKEV2_SESSION_KEYS *IkeKeys;
+ UINT8 *NiBlock;
+ UINTN NiBlkSize;
+ UINT8 *NrBlock;
+ UINTN NrBlkSize;
+ UINT8 *NCookie; // Buffer Contains the Notify Cookie
+ UINTN NCookieSize; // Size of NCookie
+ IPSEC_PAD_ENTRY *Pad;
+ IPSEC_SPD_ENTRY *Spd; // SPD that requested the negotiation, TODO: better use SPD selector
+ LIST_ENTRY ChildSaSessionList;
+ LIST_ENTRY ChildSaEstablishSessionList; // For Establish Child SA.
+ LIST_ENTRY InfoMIDList; // For Information MID
+ LIST_ENTRY DeleteSaList; // For deteling Child SA.
+ UINT8 *InitPacket;
+ UINTN InitPacketSize;
+ UINT8 *RespPacket;
+ UINTN RespPacketSize;
+ UINT32 MessageId;
+ LIST_ENTRY BySessionTable; // Use for all IkeSaSession Links
+} IKEV2_SA_SESSION;
+
+typedef struct {
+ UINT32 Signature;
+ IKEV2_SESSION_COMMON SessionCommon;
+ IKEV2_SA_SESSION *IkeSaSession;
+ UINT32 MessageId;
+ IKEV2_SA_DATA *SaData;
+ UINT8 IpsecProtocol;
+ UINT32 LocalPeerSpi;
+ UINT32 RemotePeerSpi;
+ UINT8 *NiBlock;
+ UINTN NiBlkSize;
+ UINT8 *NrBlock;
+ UINTN NrBlkSize;
+ SA_KEYMATS ChildKeymats;
+ IKEV2_DH_BUFFER *DhBuffer; //New DH exchnaged by CREATE_CHILD_SA
+ IPSEC_SPD_ENTRY *Spd;
+ EFI_IPSEC_SPD_SELECTOR *SpdSelector;
+ UINT16 ProtoId;
+ UINT16 RemotePort;
+ UINT16 LocalPort;
+ LIST_ENTRY ByIkeSa;
+ LIST_ENTRY ByDelete;
+} IKEV2_CHILD_SA_SESSION;
+
+typedef enum {
+ Ikev2InfoNotify,
+ Ikev2InfoDelete,
+ Ikev2InfoLiveCheck
+} IKEV2_INFO_TYPE;
+
+//
+// This struct is used to pass the detail infromation to the InfoGenerator() for
+// the response Information Exchange Message creatation.
+//
+typedef struct {
+ UINT32 MessageId;
+ IKEV2_INFO_TYPE InfoType;
+} IKEV2_INFO_EXCHANGE_CONTEXT;
+
+typedef struct {
+ UINTN DataSize;
+ UINT8 *Data;
+} PRF_DATA_FRAGMENT;
+
+typedef
+IKE_PACKET *
+(*IKEV2_PACKET_GENERATOR) (
+ IN UINT8 *SaSession,
+ IN VOID *Context
+);
+
+typedef
+EFI_STATUS
+(*IKEV2_PACKET_PARSER) (
+ IN UINT8 *SaSession,
+ IN IKE_PACKET *IkePacket
+);
+
+typedef struct {
+ IKEV2_PACKET_PARSER Parser;
+ IKEV2_PACKET_GENERATOR Generator;
+} IKEV2_PACKET_HANDLER;
+
+extern IKEV2_PACKET_HANDLER mIkev2Initial[][2];
+extern IKEV2_PACKET_HANDLER mIkev2CreateChild;
+extern IKEV2_PACKET_HANDLER mIkev2Info;
+
+#endif
+
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/Info.c b/Core/NetworkPkg/IpSecDxe/Ikev2/Info.c
new file mode 100644
index 0000000000..23e47ceea8
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Info.c
@@ -0,0 +1,402 @@
+/** @file
+ The Implementations for Information Exchange.
+
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2010 - 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 "Utility.h"
+#include "IpSecDebug.h"
+#include "IpSecConfigImpl.h"
+
+/**
+ Generate Information Packet.
+
+ The information Packet may contain one Delete Payload, or Notify Payload, which
+ dependes on the Context's parameters.
+
+ @param[in] SaSession Pointer to IKE SA Session or Child SA Session which is
+ related to the information Exchange.
+ @param[in] Context The Data passed from the caller. If the Context is not NULL
+ it should contain the information for Notification Data.
+
+ @retval Pointer of IKE_PACKET generated.
+
+**/
+IKE_PACKET *
+Ikev2InfoGenerator (
+ IN UINT8 *SaSession,
+ IN VOID *Context
+ )
+{
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKE_PACKET *IkePacket;
+ IKE_PAYLOAD *IkePayload;
+ IKEV2_INFO_EXCHANGE_CONTEXT *InfoContext;
+
+ InfoContext = NULL;
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+ IkePacket = IkePacketAlloc ();
+ if (IkePacket == NULL) {
+ return NULL;
+ }
+
+ //
+ // Fill IkePacket Header.
+ //
+ IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_INFO;
+ IkePacket->Header->Version = (UINT8) (2 << 4);
+
+ if (Context != NULL) {
+ InfoContext = (IKEV2_INFO_EXCHANGE_CONTEXT *) Context;
+ }
+
+ //
+ // For Liveness Check
+ //
+ if (InfoContext != NULL &&
+ (InfoContext->InfoType == Ikev2InfoLiveCheck || InfoContext->InfoType == Ikev2InfoNotify)
+ ) {
+ IkePacket->Header->MessageId = InfoContext->MessageId;
+ IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NONE;
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
+ //
+ // TODO: add Notify Payload for Notification Information.
+ //
+ return IkePacket;
+ }
+
+ //
+ // For delete SAs
+ //
+ if (IkeSaSession->SessionCommon.IkeSessionType == IkeSessionTypeIkeSa) {
+
+ IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
+
+ //
+ // If the information message is response message,the MessageId should
+ // be same as the request MessageId which passed through the Context.
+ //
+ if (InfoContext != NULL) {
+ IkePacket->Header->MessageId = InfoContext->MessageId;
+ } else {
+ IkePacket->Header->MessageId = IkeSaSession->MessageId;
+ Ikev2SaSessionIncreaseMessageId (IkeSaSession);
+ }
+ //
+ // If the state is on deleting generate a Delete Payload for it.
+ //
+ if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting ) {
+ IkePayload = Ikev2GenerateDeletePayload (
+ IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ 0,
+ 0,
+ NULL
+ );
+ if (IkePayload == NULL) {
+ goto ERROR_EXIT;
+ }
+ //
+ // Fill the next payload in IkePacket's Header.
+ //
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_DELETE;
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
+ IkePacket->Private = IkeSaSession->SessionCommon.Private;
+ IkePacket->Spi = 0;
+ IkePacket->IsDeleteInfo = TRUE;
+
+ } else if (Context != NULL) {
+ //
+ // TODO: If contest is not NULL Generate a Notify Payload.
+ //
+ } else {
+ //
+ // The input parameter is not correct.
+ //
+ goto ERROR_EXIT;
+ }
+ } else {
+ //
+ // Delete the Child SA Information Exchagne
+ //
+ ChildSaSession = (IKEV2_CHILD_SA_SESSION *) SaSession;
+ IkeSaSession = ChildSaSession->IkeSaSession;
+ IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie;
+
+ //
+ // If the information message is response message,the MessageId should
+ // be same as the request MessageId which passed through the Context.
+ //
+ if (InfoContext != NULL && InfoContext->MessageId != 0) {
+ IkePacket->Header->MessageId = InfoContext->MessageId;
+ } else {
+ IkePacket->Header->MessageId = ChildSaSession->IkeSaSession->MessageId;
+ Ikev2SaSessionIncreaseMessageId (IkeSaSession);
+ }
+
+ IkePayload = Ikev2GenerateDeletePayload (
+ ChildSaSession->IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_DELETE,
+ 4,
+ 1,
+ (UINT8 *)&ChildSaSession->LocalPeerSpi
+ );
+ if (IkePayload == NULL) {
+ goto ERROR_EXIT;
+ }
+ //
+ // Fill the Next Payload in IkePacket's Header.
+ //
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_DELETE;
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
+
+ IkePacket->Private = IkeSaSession->SessionCommon.Private;
+ IkePacket->Spi = ChildSaSession->LocalPeerSpi;
+ IkePacket->IsDeleteInfo = TRUE;
+
+ if (!ChildSaSession->SessionCommon.IsInitiator) {
+ //
+ // If responder, use the MessageId fromt the initiator.
+ //
+ IkePacket->Header->MessageId = ChildSaSession->MessageId;
+ }
+
+ //
+ // Change the IsOnDeleting Flag
+ //
+ ChildSaSession->SessionCommon.IsOnDeleting = TRUE;
+ }
+
+ if (InfoContext == NULL) {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
+ } else {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
+ }
+ return IkePacket;
+
+ERROR_EXIT:
+ if (IkePacket != NULL) {
+ FreePool (IkePacket);
+ }
+ return NULL;
+
+}
+
+/**
+ Parse the Info Exchange.
+
+ @param[in] SaSession Pointer to IKEV2_SA_SESSION.
+ @param[in] IkePacket Pointer to IkePacket related to the Information Exchange.
+
+ @retval EFI_SUCCESS The operation finised successed.
+
+**/
+EFI_STATUS
+Ikev2InfoParser (
+ IN UINT8 *SaSession,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKE_PAYLOAD *DeletePayload;
+ IKE_PAYLOAD *IkePayload;
+ IKEV2_DELETE *Delete;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *ListEntry;
+ UINT8 Index;
+ UINT32 Spi;
+ UINT8 *SpiBuffer;
+ IPSEC_PRIVATE_DATA *Private;
+ UINT8 Value;
+ EFI_STATUS Status;
+ IKE_PACKET *RespondPacket;
+
+ IKEV2_INFO_EXCHANGE_CONTEXT Context;
+
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+
+ DeletePayload = NULL;
+ Private = NULL;
+ RespondPacket = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // For Liveness Check
+ //
+ if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE &&
+ (IkePacket->PayloadTotalSize == 0)
+ ) {
+ if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) {
+ //
+ // If it is Liveness check request, reply it.
+ //
+ Context.InfoType = Ikev2InfoLiveCheck;
+ Context.MessageId = IkePacket->Header->MessageId;
+ RespondPacket = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);
+
+ if (RespondPacket == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+ Status = Ikev2SendIkePacket (
+ IkeSaSession->SessionCommon.UdpService,
+ (UINT8 *)(&IkeSaSession->SessionCommon),
+ RespondPacket,
+ 0
+ );
+
+ } else {
+ //
+ // Todo: verify the liveness check response packet.
+ //
+ }
+ return Status;
+ }
+
+ //
+ // For SA Delete
+ //
+ NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
+
+ //
+ // Iterate payloads to find the Delete/Notify Payload.
+ //
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_DELETE) {
+ DeletePayload = IkePayload;
+ Delete = (IKEV2_DELETE *)DeletePayload->PayloadBuf;
+
+ if (Delete->SpiSize == 0) {
+ //
+ // Delete IKE SA.
+ //
+ if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) {
+ RemoveEntryList (&IkeSaSession->BySessionTable);
+ Ikev2SaSessionFree (IkeSaSession);
+ //
+ // Checking the Private status.
+ //
+ //
+ // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec
+ // status should be changed.
+ //
+ Private = IkeSaSession->SessionCommon.Private;
+ if (Private != NULL && Private->IsIPsecDisabling) {
+ //
+ // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in
+ // IPsec status variable.
+ //
+ if (IsListEmpty (&Private->Ikev1EstablishedList) &&
+ (IsListEmpty (&Private->Ikev2EstablishedList))
+ ) {
+ Value = IPSEC_STATUS_DISABLED;
+ Status = gRT->SetVariable (
+ IPSECCONFIG_STATUS_NAME,
+ &gEfiIpSecConfigProtocolGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (Value),
+ &Value
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set the DisabledFlag in Private data.
+ //
+ Private->IpSec.DisabledFlag = TRUE;
+ Private->IsIPsecDisabling = FALSE;
+ }
+ }
+ }
+ } else {
+ IkeSaSession->SessionCommon.State = IkeStateSaDeleting;
+ Context.InfoType = Ikev2InfoDelete;
+ Context.MessageId = IkePacket->Header->MessageId;
+
+ RespondPacket = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);
+ if (RespondPacket == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+ Status = Ikev2SendIkePacket (
+ IkeSaSession->SessionCommon.UdpService,
+ (UINT8 *)(&IkeSaSession->SessionCommon),
+ RespondPacket,
+ 0
+ );
+ }
+ } else if (Delete->SpiSize == 4) {
+ //
+ // Move the Child SAs to DeleteList
+ //
+ SpiBuffer = (UINT8 *)(Delete + 1);
+ for (Index = 0; Index < Delete->NumSpis; Index++) {
+ Spi = ReadUnaligned32 ((UINT32 *)SpiBuffer);
+ for (ListEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;
+ ListEntry != &IkeSaSession->ChildSaEstablishSessionList;
+ ) {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ListEntry);
+ ListEntry = ListEntry->ForwardLink;
+
+ if (ChildSaSession->RemotePeerSpi == HTONL(Spi)) {
+ if (ChildSaSession->SessionCommon.State != IkeStateSaDeleting) {
+
+ //
+ // Insert the ChildSa Session into Delete List.
+ //
+ InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete);
+ ChildSaSession->SessionCommon.State = IkeStateSaDeleting;
+ ChildSaSession->SessionCommon.IsInitiator = FALSE;
+ ChildSaSession->MessageId = IkePacket->Header->MessageId;
+
+ Context.InfoType = Ikev2InfoDelete;
+ Context.MessageId = IkePacket->Header->MessageId;
+
+ RespondPacket = Ikev2InfoGenerator ((UINT8 *)ChildSaSession, &Context);
+ if (RespondPacket == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ return Status;
+ }
+ Status = Ikev2SendIkePacket (
+ ChildSaSession->SessionCommon.UdpService,
+ (UINT8 *)(&ChildSaSession->SessionCommon),
+ RespondPacket,
+ 0
+ );
+ } else {
+ //
+ // Delete the Child SA.
+ //
+ Ikev2ChildSaSilentDelete (IkeSaSession, Spi);
+ RemoveEntryList (&ChildSaSession->ByDelete);
+ }
+ }
+ }
+ SpiBuffer = SpiBuffer + sizeof (Spi);
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER mIkev2Info = {
+ Ikev2InfoParser,
+ Ikev2InfoGenerator
+};
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/Payload.c b/Core/NetworkPkg/IpSecDxe/Ikev2/Payload.c
new file mode 100644
index 0000000000..675ecf6f74
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Payload.c
@@ -0,0 +1,3369 @@
+/** @file
+ The implementation of Payloads Creation.
+
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2010 - 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 "Utility.h"
+#include "IpSecDebug.h"
+#include "IpSecConfigImpl.h"
+#include "IpSecCryptIo.h"
+
+//
+// The Constant String of "Key Pad for IKEv2" for Authentication Payload generation.
+//
+#define CONSTANT_KEY_SIZE 17
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mConstantKey[CONSTANT_KEY_SIZE] =
+{
+ 'K', 'e', 'y', ' ', 'P', 'a', 'd', ' ', 'f', 'o', 'r', ' ', 'I', 'K', 'E', 'v', '2'
+};
+
+/**
+ Generate Ikev2 SA payload according to SessionSaData
+
+ @param[in] SessionSaData The data used in SA payload.
+ @param[in] NextPayload The payload type presented in NextPayload field of
+ SA Payload header.
+ @param[in] Type The SA type. It MUST be neither (1) for IKE_SA or
+ (2) for CHILD_SA or (3) for INFO.
+
+ @retval a Pointer to SA IKE payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateSaPayload (
+ IN IKEV2_SA_DATA *SessionSaData,
+ IN UINT8 NextPayload,
+ IN IKE_SESSION_TYPE Type
+ )
+{
+ IKE_PAYLOAD *SaPayload;
+ IKEV2_SA_DATA *SaData;
+ UINTN SaDataSize;
+
+ SaPayload = IkePayloadAlloc ();
+ if (SaPayload == NULL) {
+ return NULL;
+ }
+
+ //
+ // TODO: Get the Proposal Number and Transform Number from IPsec Config,
+ // after the Ipsecconfig Application is support it.
+ //
+
+ if (Type == IkeSessionTypeIkeSa) {
+ SaDataSize = sizeof (IKEV2_SA_DATA) +
+ SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) +
+ sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 4;
+ } else {
+ SaDataSize = sizeof (IKEV2_SA_DATA) +
+ SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) +
+ sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 3;
+
+ }
+
+ SaData = AllocateZeroPool (SaDataSize);
+ if (SaData == NULL) {
+ IkePayloadFree (SaPayload);
+ return NULL;
+ }
+
+ CopyMem (SaData, SessionSaData, SaDataSize);
+ SaData->SaHeader.Header.NextPayload = NextPayload;
+ SaPayload->PayloadType = IKEV2_PAYLOAD_TYPE_SA;
+ SaPayload->PayloadBuf = (UINT8 *) SaData;
+
+ return SaPayload;
+}
+
+/**
+ Generate a Nonce payload containing the input parameter NonceBuf.
+
+ @param[in] NonceBuf The nonce buffer contains the whole Nonce payload block
+ except the payload header.
+ @param[in] NonceSize The buffer size of the NonceBuf
+ @param[in] NextPayload The payload type presented in the NextPayload field
+ of Nonce Payload header.
+
+ @retval Pointer to Nonce IKE paload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateNoncePayload (
+ IN UINT8 *NonceBuf,
+ IN UINTN NonceSize,
+ IN UINT8 NextPayload
+ )
+{
+ IKE_PAYLOAD *NoncePayload;
+ IKEV2_NONCE *Nonce;
+ UINTN Size;
+ UINT8 *NonceBlock;
+
+ // 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Nonce Data ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ Size = sizeof (IKEV2_NONCE) + NonceSize;
+ NonceBlock = NonceBuf;
+
+ Nonce = AllocateZeroPool (Size);
+ if (Nonce == NULL) {
+ return NULL;
+ }
+
+ CopyMem (Nonce + 1, NonceBlock, Size - sizeof (IKEV2_NONCE));
+
+ Nonce->Header.NextPayload = NextPayload;
+ Nonce->Header.PayloadLength = (UINT16) Size;
+ NoncePayload = IkePayloadAlloc ();
+ if (NoncePayload == NULL) {
+ FreePool (Nonce);
+ return NULL;
+ }
+
+ NoncePayload->PayloadType = IKEV2_PAYLOAD_TYPE_NONCE;
+ NoncePayload->PayloadBuf = (UINT8 *) Nonce;
+ NoncePayload->PayloadSize = Size;
+
+ return NoncePayload;
+}
+
+/**
+ Generate a Key Exchange payload according to the DH group type and save the
+ public Key into IkeSaSession IkeKey field.
+
+ @param[in, out] IkeSaSession Pointer of the IKE_SA_SESSION.
+ @param[in] NextPayload The payload type presented in the NextPayload field of Key
+ Exchange Payload header.
+
+ @retval Pointer to Key IKE payload.
+
+**/
+IKE_PAYLOAD*
+Ikev2GenerateKePayload (
+ IN OUT IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT8 NextPayload
+ )
+{
+ IKE_PAYLOAD *KePayload;
+ IKEV2_KEY_EXCHANGE *Ke;
+ UINTN KeSize;
+ IKEV2_SESSION_KEYS *IkeKeys;
+
+ //
+ // 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! DH Group # ! RESERVED !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Key Exchange Data ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ IkeKeys = IkeSaSession->IkeKeys;
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize;
+ } else {
+ KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize;
+ }
+
+ //
+ // Allocate buffer for Key Exchange
+ //
+ Ke = AllocateZeroPool (KeSize);
+ if (Ke == NULL) {
+ return NULL;
+ }
+
+ Ke->Header.NextPayload = NextPayload;
+ Ke->Header.PayloadLength = (UINT16) KeSize;
+ Ke->DhGroup = IkeSaSession->SessionCommon.PreferDhGroup;
+
+ CopyMem (Ke + 1, IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize);
+
+ //
+ // Create IKE_PAYLOAD to point to Key Exchange payload
+ //
+ KePayload = IkePayloadAlloc ();
+ if (KePayload == NULL) {
+ FreePool (Ke);
+ return NULL;
+ }
+
+ KePayload->PayloadType = IKEV2_PAYLOAD_TYPE_KE;
+ KePayload->PayloadBuf = (UINT8 *) Ke;
+ KePayload->PayloadSize = KeSize;
+ return KePayload;
+}
+
+/**
+ Generate a ID payload.
+
+ @param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload.
+ @param[in] NextPayload The payload type presented in the NextPayload field
+ of ID Payload header.
+
+ @retval Pointer to ID IKE payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateIdPayload (
+ IN IKEV2_SESSION_COMMON *CommonSession,
+ IN UINT8 NextPayload
+ )
+{
+ IKE_PAYLOAD *IdPayload;
+ IKEV2_ID *Id;
+ UINTN IdSize;
+ UINT8 IpVersion;
+ UINT8 AddrSize;
+
+ //
+ // ID payload
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload ! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! ID Type ! RESERVED !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Identification Data ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+
+ IpVersion = CommonSession->UdpService->IpVersion;
+ AddrSize = (UINT8) ((IpVersion == IP_VERSION_4) ? sizeof(EFI_IPv4_ADDRESS) : sizeof(EFI_IPv6_ADDRESS));
+ IdSize = sizeof (IKEV2_ID) + AddrSize;
+
+ Id = (IKEV2_ID *) AllocateZeroPool (IdSize);
+ if (Id == NULL) {
+ return NULL;
+ }
+
+ IdPayload = IkePayloadAlloc ();
+ if (IdPayload == NULL) {
+ FreePool (Id);
+ return NULL;
+ }
+
+ IdPayload->PayloadType = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP);
+ IdPayload->PayloadBuf = (UINT8 *) Id;
+ IdPayload->PayloadSize = IdSize;
+
+ //
+ // Set generic header of identification payload
+ //
+ Id->Header.NextPayload = NextPayload;
+ Id->Header.PayloadLength = (UINT16) IdSize;
+ Id->IdType = (UINT8) ((IpVersion == IP_VERSION_4) ? IKEV2_ID_TYPE_IPV4_ADDR : IKEV2_ID_TYPE_IPV6_ADDR);
+ CopyMem (Id + 1, &CommonSession->LocalPeerIp, AddrSize);
+
+ return IdPayload;
+}
+
+/**
+ Generate a ID payload.
+
+ @param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload.
+ @param[in] NextPayload The payload type presented in the NextPayload field
+ of ID Payload header.
+ @param[in] InCert Pointer to the Certificate which distinguished name
+ will be added into the Id payload.
+ @param[in] CertSize Size of the Certificate.
+
+ @retval Pointer to ID IKE payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateCertIdPayload (
+ IN IKEV2_SESSION_COMMON *CommonSession,
+ IN UINT8 NextPayload,
+ IN UINT8 *InCert,
+ IN UINTN CertSize
+ )
+{
+ IKE_PAYLOAD *IdPayload;
+ IKEV2_ID *Id;
+ UINTN IdSize;
+ UINTN SubjectSize;
+ UINT8 *CertSubject;
+
+ //
+ // ID payload
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload ! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! ID Type ! RESERVED !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Identification Data ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+
+ SubjectSize = 0;
+ CertSubject = NULL;
+ IpSecCryptoIoGetSubjectFromCert (
+ InCert,
+ CertSize,
+ &CertSubject,
+ &SubjectSize
+ );
+ if (SubjectSize != 0) {
+ ASSERT (CertSubject != NULL);
+ }
+
+ IdSize = sizeof (IKEV2_ID) + SubjectSize;
+
+ Id = (IKEV2_ID *) AllocateZeroPool (IdSize);
+ if (Id == NULL) {
+ return NULL;
+ }
+
+ IdPayload = IkePayloadAlloc ();
+ if (IdPayload == NULL) {
+ FreePool (Id);
+ return NULL;
+ }
+
+ IdPayload->PayloadType = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP);
+ IdPayload->PayloadBuf = (UINT8 *) Id;
+ IdPayload->PayloadSize = IdSize;
+
+ //
+ // Set generic header of identification payload
+ //
+ Id->Header.NextPayload = NextPayload;
+ Id->Header.PayloadLength = (UINT16) IdSize;
+ Id->IdType = 9;
+ CopyMem (Id + 1, CertSubject, SubjectSize);
+
+ if (CertSubject != NULL) {
+ FreePool (CertSubject);
+ }
+ return IdPayload;
+}
+
+/**
+ Generate a Authentication Payload.
+
+ This function is used for both Authentication generation and verification. When the
+ IsVerify is TRUE, it create a Auth Data for verification. This function choose the
+ related IKE_SA_INIT Message for Auth data creation according to the IKE Session's type
+ and the value of IsVerify parameter.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to.
+ @param[in] IdPayload Pointer to the ID payload to be used for Authentication
+ payload generation.
+ @param[in] NextPayload The type filled into the Authentication Payload next
+ payload field.
+ @param[in] IsVerify If it is TURE, the Authentication payload is used for
+ verification.
+
+ @return pointer to IKE Authentication payload for Pre-shared key method.
+
+**/
+IKE_PAYLOAD *
+Ikev2PskGenerateAuthPayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_PAYLOAD *IdPayload,
+ IN UINT8 NextPayload,
+ IN BOOLEAN IsVerify
+ )
+{
+ UINT8 *Digest;
+ UINTN DigestSize;
+ PRF_DATA_FRAGMENT Fragments[3];
+ UINT8 *KeyBuf;
+ UINTN KeySize;
+ IKE_PAYLOAD *AuthPayload;
+ IKEV2_AUTH *PayloadBuf;
+ EFI_STATUS Status;
+
+ //
+ // Auth = Prf(Prf(Secret,"Key Pad for IKEv2),IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
+ //
+ // 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Auth Method ! RESERVED !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Authentication Data ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+
+ KeyBuf = NULL;
+ AuthPayload = NULL;
+ Digest = NULL;
+
+ DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf);
+ Digest = AllocateZeroPool (DigestSize);
+ if (Digest == NULL) {
+ return NULL;
+ }
+
+ if (IdPayload == NULL) {
+ return NULL;
+ }
+
+ //
+ // Calcualte Prf(Seceret, "Key Pad for IKEv2");
+ //
+ Fragments[0].Data = (UINT8 *) mConstantKey;
+ Fragments[0].DataSize = CONSTANT_KEY_SIZE;
+
+ Status = IpSecCryptoIoHmac (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
+ IkeSaSession->Pad->Data->AuthData,
+ IkeSaSession->Pad->Data->AuthDataSize,
+ (HASH_DATA_FRAGMENT *)Fragments,
+ 1,
+ Digest,
+ DigestSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Store the AuthKey into KeyBuf
+ //
+ KeyBuf = AllocateZeroPool (DigestSize);
+ if (KeyBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ CopyMem (KeyBuf, Digest, DigestSize);
+ KeySize = DigestSize;
+
+ //
+ // Calculate Prf(SK_Pi/r, IDi/r)
+ //
+ Fragments[0].Data = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
+ Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
+
+ if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
+ (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
+ ) {
+ Status = IpSecCryptoIoHmac (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
+ IkeSaSession->IkeKeys->SkPrKey,
+ IkeSaSession->IkeKeys->SkPrKeySize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 1,
+ Digest,
+ DigestSize
+ );
+ } else {
+ Status = IpSecCryptoIoHmac (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
+ IkeSaSession->IkeKeys->SkPiKey,
+ IkeSaSession->IkeKeys->SkPiKeySize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 1,
+ Digest,
+ DigestSize
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Copy data to Fragments.
+ //
+ if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
+ (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
+ ) {
+ Fragments[0].Data = IkeSaSession->RespPacket;
+ Fragments[0].DataSize = IkeSaSession->RespPacketSize;
+ Fragments[1].Data = IkeSaSession->NiBlock;
+ Fragments[1].DataSize = IkeSaSession->NiBlkSize;
+ } else {
+ Fragments[0].Data = IkeSaSession->InitPacket;
+ Fragments[0].DataSize = IkeSaSession->InitPacketSize;
+ Fragments[1].Data = IkeSaSession->NrBlock;
+ Fragments[1].DataSize = IkeSaSession->NrBlkSize;
+ }
+
+ //
+ // Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2].
+ //
+ Fragments[2].Data = AllocateZeroPool (DigestSize);
+ if (Fragments[2].Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ Fragments[2].DataSize = DigestSize;
+ CopyMem (Fragments[2].Data, Digest, DigestSize);
+
+ //
+ // Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
+ //
+ Status = IpSecCryptoIoHmac (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
+ KeyBuf,
+ KeySize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 3,
+ Digest,
+ DigestSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Allocate buffer for Auth Payload
+ //
+ AuthPayload = IkePayloadAlloc ();
+ if (AuthPayload == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ AuthPayload->PayloadSize = sizeof (IKEV2_AUTH) + DigestSize;
+ PayloadBuf = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize);
+ if (PayloadBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Fill in Auth payload.
+ //
+ PayloadBuf->Header.NextPayload = NextPayload;
+ PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize);
+ if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodPreSharedSecret) {
+ //
+ // Only support Shared Key Message Integrity
+ //
+ PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_SKMI;
+ } else {
+ //
+ // Not support other Auth method.
+ //
+ Status = EFI_UNSUPPORTED;
+ goto EXIT;
+ }
+
+ //
+ // Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth
+ // payload block.
+ //
+ CopyMem (
+ PayloadBuf + 1,
+ Digest,
+ DigestSize
+ );
+
+ //
+ // Fill in IKE_PACKET
+ //
+ AuthPayload->PayloadBuf = (UINT8 *) PayloadBuf;
+ AuthPayload->PayloadType = IKEV2_PAYLOAD_TYPE_AUTH;
+
+EXIT:
+ if (KeyBuf != NULL) {
+ FreePool (KeyBuf);
+ }
+ if (Digest != NULL) {
+ FreePool (Digest);
+ }
+ if (Fragments[2].Data != NULL) {
+ //
+ // Free the buffer which contains the result of Prf(SK_Pr, IDi/r)
+ //
+ FreePool (Fragments[2].Data);
+ }
+
+ if (EFI_ERROR (Status)) {
+ if (AuthPayload != NULL) {
+ IkePayloadFree (AuthPayload);
+ }
+ return NULL;
+ } else {
+ return AuthPayload;
+ }
+}
+
+/**
+ Generate a Authentication Payload for Certificate Auth method.
+
+ This function has two functions. One is creating a local Authentication
+ Payload for sending and other is creating the remote Authentication data
+ for verification when the IsVerify is TURE.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to.
+ @param[in] IdPayload Pointer to the ID payload to be used for Authentication
+ payload generation.
+ @param[in] NextPayload The type filled into the Authentication Payload
+ next payload field.
+ @param[in] IsVerify If it is TURE, the Authentication payload is used
+ for verification.
+ @param[in] UefiPrivateKey Pointer to the UEFI private key. Ignore it when
+ verify the authenticate payload.
+ @param[in] UefiPrivateKeyLen The size of UefiPrivateKey in bytes. Ignore it
+ when verify the authenticate payload.
+ @param[in] UefiKeyPwd Pointer to the password of UEFI private key.
+ Ignore it when verify the authenticate payload.
+ @param[in] UefiKeyPwdLen The size of UefiKeyPwd in bytes.Ignore it when
+ verify the authenticate payload.
+
+ @return pointer to IKE Authentication payload for Cerifitcation method.
+
+**/
+IKE_PAYLOAD *
+Ikev2CertGenerateAuthPayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_PAYLOAD *IdPayload,
+ IN UINT8 NextPayload,
+ IN BOOLEAN IsVerify,
+ IN UINT8 *UefiPrivateKey,
+ IN UINTN UefiPrivateKeyLen,
+ IN UINT8 *UefiKeyPwd,
+ IN UINTN UefiKeyPwdLen
+ )
+{
+ UINT8 *Digest;
+ UINTN DigestSize;
+ PRF_DATA_FRAGMENT Fragments[3];
+ UINT8 *KeyBuf;
+ IKE_PAYLOAD *AuthPayload;
+ IKEV2_AUTH *PayloadBuf;
+ EFI_STATUS Status;
+ UINT8 *Signature;
+ UINTN SigSize;
+
+ //
+ // Auth = Prf(Scert,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
+ //
+ // 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Auth Method ! RESERVED !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Authentication Data ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ //
+ // Initial point
+ //
+ KeyBuf = NULL;
+ AuthPayload = NULL;
+ Digest = NULL;
+ Signature = NULL;
+ SigSize = 0;
+
+ if (IdPayload == NULL) {
+ return NULL;
+ }
+ DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf);
+ Digest = AllocateZeroPool (DigestSize);
+ if (Digest == NULL) {
+ return NULL;
+ }
+
+ //
+ // Store the AuthKey into KeyBuf
+ //
+ KeyBuf = AllocateZeroPool (DigestSize);
+ if (KeyBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ CopyMem (KeyBuf, Digest, DigestSize);
+
+ //
+ // Calculate Prf(SK_Pi/r, IDi/r)
+ //
+ Fragments[0].Data = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
+ Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
+
+ IpSecDumpBuf ("RestofIDPayload", Fragments[0].Data, Fragments[0].DataSize);
+
+ if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
+ (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
+ ) {
+ Status = IpSecCryptoIoHmac(
+ (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
+ IkeSaSession->IkeKeys->SkPrKey,
+ IkeSaSession->IkeKeys->SkPrKeySize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 1,
+ Digest,
+ DigestSize
+ );
+ IpSecDumpBuf ("MACedIDForR", Digest, DigestSize);
+ } else {
+ Status = IpSecCryptoIoHmac (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
+ IkeSaSession->IkeKeys->SkPiKey,
+ IkeSaSession->IkeKeys->SkPiKeySize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 1,
+ Digest,
+ DigestSize
+ );
+ IpSecDumpBuf ("MACedIDForI", Digest, DigestSize);
+ }
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Copy data to Fragments.
+ //
+ if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
+ (!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
+ ) {
+ Fragments[0].Data = IkeSaSession->RespPacket;
+ Fragments[0].DataSize = IkeSaSession->RespPacketSize;
+ Fragments[1].Data = IkeSaSession->NiBlock;
+ Fragments[1].DataSize = IkeSaSession->NiBlkSize;
+ IpSecDumpBuf ("RealMessage2", Fragments[0].Data, Fragments[0].DataSize);
+ IpSecDumpBuf ("NonceIDdata", Fragments[1].Data, Fragments[1].DataSize);
+ } else {
+ Fragments[0].Data = IkeSaSession->InitPacket;
+ Fragments[0].DataSize = IkeSaSession->InitPacketSize;
+ Fragments[1].Data = IkeSaSession->NrBlock;
+ Fragments[1].DataSize = IkeSaSession->NrBlkSize;
+ IpSecDumpBuf ("RealMessage1", Fragments[0].Data, Fragments[0].DataSize);
+ IpSecDumpBuf ("NonceRDdata", Fragments[1].Data, Fragments[1].DataSize);
+ }
+
+ //
+ // Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2].
+ //
+ Fragments[2].Data = AllocateZeroPool (DigestSize);
+ if (Fragments[2].Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ Fragments[2].DataSize = DigestSize;
+ CopyMem (Fragments[2].Data, Digest, DigestSize);
+
+ //
+ // Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
+ //
+ Status = IpSecCryptoIoHash (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 3,
+ Digest,
+ DigestSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ IpSecDumpBuf ("HashSignedOctects", Digest, DigestSize);
+ //
+ // Sign the data by the private Key
+ //
+ if (!IsVerify) {
+ IpSecCryptoIoAuthDataWithCertificate (
+ Digest,
+ DigestSize,
+ UefiPrivateKey,
+ UefiPrivateKeyLen,
+ UefiKeyPwd,
+ UefiKeyPwdLen,
+ &Signature,
+ &SigSize
+ );
+
+ if (SigSize == 0 || Signature == NULL) {
+ goto EXIT;
+ }
+ }
+
+ //
+ // Allocate buffer for Auth Payload
+ //
+ AuthPayload = IkePayloadAlloc ();
+ if (AuthPayload == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ if (!IsVerify) {
+ AuthPayload->PayloadSize = sizeof (IKEV2_AUTH) + SigSize;
+ } else {
+ AuthPayload->PayloadSize = sizeof (IKEV2_AUTH) + DigestSize;
+ }
+
+ PayloadBuf = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize);
+ if (PayloadBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Fill in Auth payload.
+ //
+ PayloadBuf->Header.NextPayload = NextPayload;
+ PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize);
+ if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodCertificates) {
+ PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_RSA;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ //
+ // Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth
+ // payload block.
+ //
+ if (!IsVerify) {
+ CopyMem (PayloadBuf + 1, Signature, SigSize);
+ } else {
+ CopyMem (PayloadBuf + 1, Digest, DigestSize);
+ }
+
+ //
+ // Fill in IKE_PACKET
+ //
+ AuthPayload->PayloadBuf = (UINT8 *) PayloadBuf;
+ AuthPayload->PayloadType = IKEV2_PAYLOAD_TYPE_AUTH;
+
+EXIT:
+ if (KeyBuf != NULL) {
+ FreePool (KeyBuf);
+ }
+ if (Digest != NULL) {
+ FreePool (Digest);
+ }
+ if (Signature != NULL) {
+ FreePool (Signature);
+ }
+ if (Fragments[2].Data != NULL) {
+ //
+ // Free the buffer which contains the result of Prf(SK_Pr, IDi/r)
+ //
+ FreePool (Fragments[2].Data);
+ }
+
+ if (EFI_ERROR (Status)) {
+ if (AuthPayload != NULL) {
+ IkePayloadFree (AuthPayload);
+ }
+ return NULL;
+ } else {
+ return AuthPayload;
+ }
+}
+
+/**
+ Generate TS payload.
+
+ This function generates TSi or TSr payload according to type of next payload.
+ If the next payload is Responder TS, gereate TSi Payload. Otherwise, generate
+ TSr payload.
+
+ @param[in] ChildSa Pointer to IKEV2_CHILD_SA_SESSION related to this TS payload.
+ @param[in] NextPayload The payload type presented in the NextPayload field
+ of ID Payload header.
+ @param[in] IsTunnel It indicates that if the Ts Payload is after the CP payload.
+ If yes, it means the Tsi and Tsr payload should be with
+ Max port range and address range and protocol is marked
+ as zero.
+
+ @retval Pointer to Ts IKE payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateTsPayload (
+ IN IKEV2_CHILD_SA_SESSION *ChildSa,
+ IN UINT8 NextPayload,
+ IN BOOLEAN IsTunnel
+ )
+{
+ IKE_PAYLOAD *TsPayload;
+ IKEV2_TS *TsPayloadBuf;
+ TRAFFIC_SELECTOR *TsSelector;
+ UINTN SelectorSize;
+ UINTN TsPayloadSize;
+ UINT8 IpVersion;
+ UINT8 AddrSize;
+
+ //
+ // 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Number of TSs ! RESERVED !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ <Traffic Selectors> ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+
+ TsPayload = IkePayloadAlloc();
+ if (TsPayload == NULL) {
+ return NULL;
+ }
+
+ IpVersion = ChildSa->SessionCommon.UdpService->IpVersion;
+ //
+ // The Starting Address and Ending Address is variable length depends on
+ // is IPv4 or IPv6
+ //
+ AddrSize = (UINT8)((IpVersion == IP_VERSION_4) ? sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS));
+ SelectorSize = sizeof (TRAFFIC_SELECTOR) + 2 * AddrSize;
+ TsPayloadSize = sizeof (IKEV2_TS) + SelectorSize;
+ TsPayloadBuf = AllocateZeroPool (TsPayloadSize);
+ if (TsPayloadBuf == NULL) {
+ goto ON_ERROR;
+ }
+
+ TsPayload->PayloadBuf = (UINT8 *) TsPayloadBuf;
+ TsSelector = (TRAFFIC_SELECTOR*)(TsPayloadBuf + 1);
+
+ TsSelector->TSType = (UINT8)((IpVersion == IP_VERSION_4) ? IKEV2_TS_TYPE_IPV4_ADDR_RANGE : IKEV2_TS_TYPS_IPV6_ADDR_RANGE);
+
+ //
+ // For tunnel mode
+ //
+ if (IsTunnel) {
+ TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL;
+ TsSelector->SelecorLen = (UINT16) SelectorSize;
+ TsSelector->StartPort = 0;
+ TsSelector->EndPort = IKEV2_TS_ANY_PORT;
+ ZeroMem ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR), AddrSize);
+ SetMem ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize, AddrSize, 0xff);
+
+ } else {
+ //
+ // TODO: Support port range and address range
+ //
+ if (NextPayload == IKEV2_PAYLOAD_TYPE_TS_RSP){
+ //
+ // Create initiator Traffic Selector
+ //
+ TsSelector->SelecorLen = (UINT16)SelectorSize;
+
+ //
+ // Currently only support the port range from 0~0xffff. Don't support other
+ // port range.
+ // TODO: support Port range
+ //
+ if (ChildSa->SessionCommon.IsInitiator) {
+ if (ChildSa->Spd->Selector->LocalPort != 0 &&
+ ChildSa->Spd->Selector->LocalPortRange == 0) {
+ //
+ // For not port range.
+ //
+ TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort;
+ TsSelector->EndPort = ChildSa->Spd->Selector->LocalPort;
+ } else if (ChildSa->Spd->Selector->LocalPort == 0){
+ //
+ // For port from 0~0xffff
+ //
+ TsSelector->StartPort = 0;
+ TsSelector->EndPort = IKEV2_TS_ANY_PORT;
+ } else {
+ //
+ // Not support now.
+ //
+ goto ON_ERROR;
+ }
+ } else {
+ if (ChildSa->Spd->Selector->RemotePort != 0 &&
+ ChildSa->Spd->Selector->RemotePortRange == 0) {
+ //
+ // For not port range.
+ //
+ TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort;
+ TsSelector->EndPort = ChildSa->Spd->Selector->RemotePort;
+ } else if (ChildSa->Spd->Selector->RemotePort == 0) {
+ //
+ // For port from 0~0xffff
+ //
+ TsSelector->StartPort = 0;
+ TsSelector->EndPort = IKEV2_TS_ANY_PORT;
+ } else {
+ //
+ // Not support now.
+ //
+ goto ON_ERROR;
+ }
+ }
+ //
+ // Copy Address.Currently the address range is not supported.
+ // The Starting address is same as Ending address
+ // TODO: Support Address Range.
+ //
+ CopyMem (
+ (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR),
+ ChildSa->SessionCommon.IsInitiator ?
+ ChildSa->Spd->Selector->LocalAddress :
+ ChildSa->Spd->Selector->RemoteAddress,
+ AddrSize
+ );
+ CopyMem (
+ (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize,
+ ChildSa->SessionCommon.IsInitiator ?
+ ChildSa->Spd->Selector->LocalAddress :
+ ChildSa->Spd->Selector->RemoteAddress,
+ AddrSize
+ );
+ //
+ // If the Next Payload is not TS responder, this TS payload type is the TS responder.
+ //
+ TsPayload->PayloadType = IKEV2_PAYLOAD_TYPE_TS_INIT;
+ }else{
+ //
+ // Create responder Traffic Selector
+ //
+ TsSelector->SelecorLen = (UINT16)SelectorSize;
+
+ //
+ // Currently only support the port range from 0~0xffff. Don't support other
+ // port range.
+ // TODO: support Port range
+ //
+ if (!ChildSa->SessionCommon.IsInitiator) {
+ if (ChildSa->Spd->Selector->LocalPort != 0 &&
+ ChildSa->Spd->Selector->LocalPortRange == 0) {
+ //
+ // For not port range.
+ //
+ TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort;
+ TsSelector->EndPort = ChildSa->Spd->Selector->LocalPort;
+ } else if (ChildSa->Spd->Selector->LocalPort == 0){
+ //
+ // For port from 0~0xffff
+ //
+ TsSelector->StartPort = 0;
+ TsSelector->EndPort = IKEV2_TS_ANY_PORT;
+ } else {
+ //
+ // Not support now.
+ //
+ goto ON_ERROR;
+ }
+ } else {
+ if (ChildSa->Spd->Selector->RemotePort != 0 &&
+ ChildSa->Spd->Selector->RemotePortRange == 0) {
+ //
+ // For not port range.
+ //
+ TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort;
+ TsSelector->EndPort = ChildSa->Spd->Selector->RemotePort;
+ } else if (ChildSa->Spd->Selector->RemotePort == 0){
+ //
+ // For port from 0~0xffff
+ //
+ TsSelector->StartPort = 0;
+ TsSelector->EndPort = IKEV2_TS_ANY_PORT;
+ } else {
+ //
+ // Not support now.
+ //
+ goto ON_ERROR;
+ }
+ }
+ //
+ // Copy Address.Currently the address range is not supported.
+ // The Starting address is same as Ending address
+ // TODO: Support Address Range.
+ //
+ CopyMem (
+ (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR),
+ ChildSa->SessionCommon.IsInitiator ?
+ ChildSa->Spd->Selector->RemoteAddress :
+ ChildSa->Spd->Selector->LocalAddress,
+ AddrSize
+ );
+ CopyMem (
+ (UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize,
+ ChildSa->SessionCommon.IsInitiator ?
+ ChildSa->Spd->Selector->RemoteAddress :
+ ChildSa->Spd->Selector->LocalAddress,
+ AddrSize
+ );
+ //
+ // If the Next Payload is not TS responder, this TS payload type is the TS responder.
+ //
+ TsPayload->PayloadType = IKEV2_PAYLOAD_TYPE_TS_RSP;
+ }
+ }
+
+ if (ChildSa->Spd->Selector->NextLayerProtocol != 0xffff) {
+ TsSelector->IpProtocolId = (UINT8)ChildSa->Spd->Selector->NextLayerProtocol;
+ } else {
+ TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL;
+ }
+
+ TsPayloadBuf->Header.NextPayload = NextPayload;
+ TsPayloadBuf->Header.PayloadLength = (UINT16)TsPayloadSize;
+ TsPayloadBuf->TSNumbers = 1;
+ TsPayload->PayloadSize = TsPayloadSize;
+ goto ON_EXIT;
+
+ON_ERROR:
+ if (TsPayload != NULL) {
+ IkePayloadFree (TsPayload);
+ TsPayload = NULL;
+ }
+ON_EXIT:
+ return TsPayload;
+}
+
+/**
+ Generate the Notify payload.
+
+ Since the structure of Notify payload which defined in RFC 4306 is simple, so
+ there is no internal data structure for Notify payload. This function generate
+ Notify payload defined in RFC 4306, but all the fields in this payload are still
+ in host order and need call Ikev2EncodePayload() to convert those fields from
+ the host order to network order beforing sending it.
+
+ @param[in] ProtocolId The protocol type ID. For IKE_SA it MUST be one (1).
+ For IPsec SAs it MUST be neither (2) for AH or (3)
+ for ESP.
+ @param[in] NextPayload The next paylaod type in NextPayload field of
+ the Notify payload.
+ @param[in] SpiSize Size of the SPI in SPI size field of the Notify Payload.
+ @param[in] MessageType The message type in NotifyMessageType field of the
+ Notify Payload.
+ @param[in] SpiBuf Pointer to buffer contains the SPI value.
+ @param[in] NotifyData Pointer to buffer contains the notification data.
+ @param[in] NotifyDataSize The size of NotifyData in bytes.
+
+
+ @retval Pointer to IKE Notify Payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateNotifyPayload (
+ IN UINT8 ProtocolId,
+ IN UINT8 NextPayload,
+ IN UINT8 SpiSize,
+ IN UINT16 MessageType,
+ IN UINT8 *SpiBuf,
+ IN UINT8 *NotifyData,
+ IN UINTN NotifyDataSize
+ )
+{
+ IKE_PAYLOAD *NotifyPayload;
+ IKEV2_NOTIFY *Notify;
+ UINT16 NotifyPayloadLen;
+ UINT8 *MessageData;
+
+ // 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Protocol ID ! SPI Size ! Notify Message Type !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Security Parameter Index (SPI) ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Notification Data ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ //
+ NotifyPayloadLen = (UINT16) (sizeof (IKEV2_NOTIFY) + NotifyDataSize + SpiSize);
+ Notify = (IKEV2_NOTIFY *) AllocateZeroPool (NotifyPayloadLen);
+ if (Notify == NULL) {
+ return NULL;
+ }
+
+ //
+ // Set Delete Payload's Generic Header
+ //
+ Notify->Header.NextPayload = NextPayload;
+ Notify->Header.PayloadLength = NotifyPayloadLen;
+ Notify->SpiSize = SpiSize;
+ Notify->ProtocolId = ProtocolId;
+ Notify->MessageType = MessageType;
+
+ //
+ // Copy Spi , for Cookie Notify, there is no SPI.
+ //
+ if (SpiBuf != NULL && SpiSize != 0 ) {
+ CopyMem (Notify + 1, SpiBuf, SpiSize);
+ }
+
+ MessageData = ((UINT8 *) (Notify + 1)) + SpiSize;
+
+ //
+ // Copy Notification Data
+ //
+ if (NotifyDataSize != 0) {
+ CopyMem (MessageData, NotifyData, NotifyDataSize);
+ }
+
+ //
+ // Create Payload for and set type as IKEV2_PAYLOAD_TYPE_NOTIFY
+ //
+ NotifyPayload = IkePayloadAlloc ();
+ if (NotifyPayload == NULL) {
+ FreePool (Notify);
+ return NULL;
+ }
+
+ NotifyPayload->PayloadType = IKEV2_PAYLOAD_TYPE_NOTIFY;
+ NotifyPayload->PayloadBuf = (UINT8 *) Notify;
+ NotifyPayload->PayloadSize = NotifyPayloadLen;
+ return NotifyPayload;
+}
+
+/**
+ Generate the Delete payload.
+
+ Since the structure of Delete payload which defined in RFC 4306 is simple,
+ there is no internal data structure for Delete payload. This function generate
+ Delete payload defined in RFC 4306, but all the fields in this payload are still
+ in host order and need call Ikev2EncodePayload() to convert those fields from
+ the host order to network order beforing sending it.
+
+ @param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload generation.
+ @param[in] NextPayload The next paylaod type in NextPayload field of
+ the Delete payload.
+ @param[in] SpiSize Size of the SPI in SPI size field of the Delete Payload.
+ @param[in] SpiNum Number of SPI in NumofSPIs field of the Delete Payload.
+ @param[in] SpiBuf Pointer to buffer contains the SPI value.
+
+ @retval a Pointer of IKE Delete Payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateDeletePayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT8 NextPayload,
+ IN UINT8 SpiSize,
+ IN UINT16 SpiNum,
+ IN UINT8 *SpiBuf
+
+ )
+{
+ IKE_PAYLOAD *DelPayload;
+ IKEV2_DELETE *Del;
+ UINT16 SpiBufSize;
+ UINT16 DelPayloadLen;
+
+ // 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Protocol ID ! SPI Size ! # of SPIs !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Security Parameter Index(es) (SPI) ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ SpiBufSize = (UINT16) (SpiSize * SpiNum);
+ if (SpiBufSize != 0 && SpiBuf == NULL) {
+ return NULL;
+ }
+
+ DelPayloadLen = (UINT16) (sizeof (IKEV2_DELETE) + SpiBufSize);
+
+ Del = AllocateZeroPool (DelPayloadLen);
+ if (Del == NULL) {
+ return NULL;
+ }
+
+ //
+ // Set Delete Payload's Generic Header
+ //
+ Del->Header.NextPayload = NextPayload;
+ Del->Header.PayloadLength = DelPayloadLen;
+ Del->NumSpis = SpiNum;
+ Del->SpiSize = SpiSize;
+
+ if (SpiSize == 4) {
+ //
+ // TODO: should consider the AH if needs to support.
+ //
+ Del->ProtocolId = IPSEC_PROTO_IPSEC_ESP;
+ } else {
+ Del->ProtocolId = IPSEC_PROTO_ISAKMP;
+ }
+
+ //
+ // Set Del Payload's Idntification Data
+ //
+ CopyMem (Del + 1, SpiBuf, SpiBufSize);
+ DelPayload = IkePayloadAlloc ();
+ if (DelPayload == NULL) {
+ FreePool (Del);
+ return NULL;
+ }
+
+ DelPayload->PayloadType = IKEV2_PAYLOAD_TYPE_DELETE;
+ DelPayload->PayloadBuf = (UINT8 *) Del;
+ DelPayload->PayloadSize = DelPayloadLen;
+ return DelPayload;
+}
+
+/**
+ Generate the Configuration payload.
+
+ This function generate configuration payload defined in RFC 4306, but all the
+ fields in this payload are still in host order and need call Ikev2EncodePayload()
+ to convert those fields from the host order to network order beforing sending it.
+
+ @param[in] IkeSaSession Pointer to IKE SA Session to be used for Delete payload
+ generation.
+ @param[in] NextPayload The next paylaod type in NextPayload field of
+ the Delete payload.
+ @param[in] CfgType The attribute type in the Configuration attribute.
+
+ @retval Pointer to IKE CP Payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateCpPayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT8 NextPayload,
+ IN UINT8 CfgType
+ )
+{
+ IKE_PAYLOAD *CpPayload;
+ IKEV2_CFG *Cfg;
+ UINT16 PayloadLen;
+ IKEV2_CFG_ATTRIBUTES *CfgAttributes;
+
+ //
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! CFG Type ! RESERVED !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ Configuration Attributes ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+
+ PayloadLen = (UINT16) (sizeof (IKEV2_CFG) + sizeof (IKEV2_CFG_ATTRIBUTES));
+ Cfg = (IKEV2_CFG *) AllocateZeroPool (PayloadLen);
+
+ if (Cfg == NULL) {
+ return NULL;
+ }
+
+ CfgAttributes = (IKEV2_CFG_ATTRIBUTES *)((UINT8 *)Cfg + sizeof (IKEV2_CFG));
+
+ //
+ // Only generate the configuration payload with an empty INTERNAL_IP4_ADDRESS
+ // or INTERNAL_IP6_ADDRESS.
+ //
+
+ Cfg->Header.NextPayload = NextPayload;
+ Cfg->Header.PayloadLength = PayloadLen;
+ Cfg->CfgType = IKEV2_CFG_TYPE_REQUEST;
+
+ CfgAttributes->AttritType = CfgType;
+ CfgAttributes->ValueLength = 0;
+
+ CpPayload = IkePayloadAlloc ();
+ if (CpPayload == NULL) {
+ if (Cfg != NULL) {
+ FreePool (Cfg);
+ }
+ return NULL;
+ }
+
+ CpPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CP;
+ CpPayload->PayloadBuf = (UINT8 *) Cfg;
+ CpPayload->PayloadSize = PayloadLen;
+ return CpPayload;
+}
+
+/**
+ Parser the Notify Cookie payload.
+
+ This function parses the Notify Cookie payload.If the Notify ProtocolId is not
+ IPSEC_PROTO_ISAKMP or if the SpiSize is not zero or if the MessageType is not
+ the COOKIE, return EFI_INVALID_PARAMETER.
+
+ @param[in] IkeNCookie Pointer to the IKE_PAYLOAD which contians the
+ Notify Cookie payload.
+ the Notify payload.
+ @param[in, out] IkeSaSession Pointer to the relevant IKE SA Session.
+
+ @retval EFI_SUCCESS The Notify Cookie Payload is valid.
+ @retval EFI_INVALID_PARAMETER The Notify Cookie Payload is invalid.
+ @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.
+
+**/
+EFI_STATUS
+Ikev2ParserNotifyCookiePayload (
+ IN IKE_PAYLOAD *IkeNCookie,
+ IN OUT IKEV2_SA_SESSION *IkeSaSession
+ )
+{
+ IKEV2_NOTIFY *NotifyPayload;
+ UINTN NotifyDataSize;
+
+ NotifyPayload = (IKEV2_NOTIFY *)IkeNCookie->PayloadBuf;
+
+ if ((NotifyPayload->ProtocolId != IPSEC_PROTO_ISAKMP) ||
+ (NotifyPayload->SpiSize != 0) ||
+ (NotifyPayload->MessageType != IKEV2_NOTIFICATION_COOKIE)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NotifyDataSize = NotifyPayload->Header.PayloadLength - sizeof (IKEV2_NOTIFY);
+ IkeSaSession->NCookie = AllocateZeroPool (NotifyDataSize);
+ if (IkeSaSession->NCookie == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IkeSaSession->NCookieSize = NotifyDataSize;
+
+ CopyMem (
+ IkeSaSession->NCookie,
+ (UINT8 *)NotifyPayload + sizeof (IKEV2_NOTIFY),
+ NotifyDataSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Generate the Certificate payload or Certificate Request Payload.
+
+ Since the Certificate Payload structure is same with Certificate Request Payload,
+ the only difference is that one contains the Certificate Data, other contains
+ the acceptable certificateion CA. This function generate Certificate payload
+ or Certificate Request Payload defined in RFC 4306, but all the fields
+ in the payload are still in host order and need call Ikev2EncodePayload()
+ to convert those fields from the host order to network order beforing sending it.
+
+ @param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload
+ generation.
+ @param[in] NextPayload The next paylaod type in NextPayload field of
+ the Delete payload.
+ @param[in] Certificate Pointer of buffer contains the certification data.
+ @param[in] CertificateLen The length of Certificate in byte.
+ @param[in] EncodeType Specified the Certificate Encodeing which is defined
+ in RFC 4306.
+ @param[in] IsRequest To indicate create Certificate Payload or Certificate
+ Request Payload. If it is TURE, create Certificate
+ Payload. Otherwise, create Certificate Request Payload.
+
+ @retval a Pointer to IKE Payload whose payload buffer containing the Certificate
+ payload or Certificated Request payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateCertificatePayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT8 NextPayload,
+ IN UINT8 *Certificate,
+ IN UINTN CertificateLen,
+ IN UINT8 EncodeType,
+ IN BOOLEAN IsRequest
+ )
+{
+ IKE_PAYLOAD *CertPayload;
+ IKEV2_CERT *Cert;
+ UINT16 PayloadLen;
+ UINT8 *PublicKey;
+ UINTN PublicKeyLen;
+ HASH_DATA_FRAGMENT Fragment[1];
+ UINT8 *HashData;
+ UINTN HashDataSize;
+ EFI_STATUS Status;
+
+ //
+ // 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Cert Encoding ! !
+ // +-+-+-+-+-+-+-+-+ !
+ // ~ Certificate Data/Authority ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+
+ Status = EFI_SUCCESS;
+ PublicKey = NULL;
+ PublicKeyLen = 0;
+
+ if (!IsRequest) {
+ PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + CertificateLen);
+ } else {
+ //
+ // SHA1 Hash length is 20.
+ //
+ PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + 20);
+ }
+
+ Cert = AllocateZeroPool (PayloadLen);
+ if (Cert == NULL) {
+ return NULL;
+ }
+
+ //
+ // Generate Certificate Payload or Certificate Request Payload.
+ //
+ Cert->Header.NextPayload = NextPayload;
+ Cert->Header.PayloadLength = PayloadLen;
+ Cert->CertEncoding = EncodeType;
+ if (!IsRequest) {
+ CopyMem (
+ ((UINT8 *)Cert) + sizeof (IKEV2_CERT),
+ Certificate,
+ CertificateLen
+ );
+ } else {
+ Status = IpSecCryptoIoGetPublicKeyFromCert (
+ Certificate,
+ CertificateLen,
+ &PublicKey,
+ &PublicKeyLen
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Fragment[0].Data = PublicKey;
+ Fragment[0].DataSize = PublicKeyLen;
+ HashDataSize = IpSecGetHmacDigestLength (IKE_AALG_SHA1HMAC);
+ HashData = AllocateZeroPool (HashDataSize);
+ if (HashData == NULL) {
+ goto ON_EXIT;
+ }
+
+ Status = IpSecCryptoIoHash (
+ IKE_AALG_SHA1HMAC,
+ Fragment,
+ 1,
+ HashData,
+ HashDataSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ CopyMem (
+ ((UINT8 *)Cert) + sizeof (IKEV2_CERT),
+ HashData,
+ HashDataSize
+ );
+ }
+
+ CertPayload = IkePayloadAlloc ();
+ if (CertPayload == NULL) {
+ goto ON_EXIT;
+ }
+
+ if (!IsRequest) {
+ CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERT;
+ } else {
+ CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERTREQ;
+ }
+
+ CertPayload->PayloadBuf = (UINT8 *) Cert;
+ CertPayload->PayloadSize = PayloadLen;
+ return CertPayload;
+
+ON_EXIT:
+ if (Cert != NULL) {
+ FreePool (Cert);
+ }
+ if (PublicKey != NULL) {
+ FreePool (PublicKey);
+ }
+ return NULL;
+}
+
+/**
+ Remove and free all IkePayloads in the specified IkePacket.
+
+ @param[in] IkePacket The pointer of IKE_PACKET.
+
+**/
+VOID
+ClearAllPayloads (
+ IN IKE_PACKET *IkePacket
+ )
+{
+ LIST_ENTRY *PayloadEntry;
+ IKE_PAYLOAD *IkePayload;
+ //
+ // remove all payloads from list and free each payload.
+ //
+ while (!IsListEmpty (&IkePacket->PayloadList)) {
+ PayloadEntry = IkePacket->PayloadList.ForwardLink;
+ IkePayload = IKE_PAYLOAD_BY_PACKET (PayloadEntry);
+ IKE_PACKET_REMOVE_PAYLOAD (IkePacket, IkePayload);
+ IkePayloadFree (IkePayload);
+ }
+}
+
+/**
+ Transfer the intrnal data structure IKEV2_SA_DATA to IKEV2_SA structure defined in RFC.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the SA Session.
+ @param[in] SaData Pointer to IKEV2_SA_DATA to be transfered.
+
+ @retval return the pointer of IKEV2_SA.
+
+**/
+IKEV2_SA*
+Ikev2EncodeSa (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN IKEV2_SA_DATA *SaData
+ )
+{
+ IKEV2_SA *Sa;
+ UINTN SaSize;
+ IKEV2_PROPOSAL_DATA *ProposalData;
+ IKEV2_TRANSFORM_DATA *TransformData;
+ UINTN TotalTransforms;
+ UINTN SaAttrsSize;
+ UINTN TransformsSize;
+ UINTN TransformSize;
+ UINTN ProposalsSize;
+ UINTN ProposalSize;
+ UINTN ProposalIndex;
+ UINTN TransformIndex;
+ IKE_SA_ATTRIBUTE *SaAttribute;
+ IKEV2_PROPOSAL *Proposal;
+ IKEV2_TRANSFORM *Transform;
+
+ //
+ // Transform IKE_SA_DATA structure to IKE_SA Payload.
+ // Header length is host order.
+ // The returned IKE_SA struct should be freed by caller.
+ //
+ TotalTransforms = 0;
+ //
+ // Calculate the Proposal numbers and Transform numbers.
+ //
+ for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) {
+
+ ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1) + ProposalIndex;
+ TotalTransforms += ProposalData->NumTransforms;
+
+ }
+ SaSize = sizeof (IKEV2_SA) +
+ SaData->NumProposals * sizeof (IKEV2_PROPOSAL) +
+ TotalTransforms * (sizeof (IKEV2_TRANSFORM) + MAX_SA_ATTRS_SIZE);
+ //
+ // Allocate buffer for IKE_SA.
+ //
+ Sa = AllocateZeroPool (SaSize);
+ if (Sa == NULL) {
+ return NULL;
+ }
+
+ CopyMem (Sa, SaData, sizeof (IKEV2_SA));
+ Sa->Header.PayloadLength = (UINT16) sizeof (IKEV2_SA);
+ ProposalsSize = 0;
+ Proposal = (IKEV2_PROPOSAL *) (Sa + 1);
+
+ //
+ // Set IKE_PROPOSAL
+ //
+ ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1);
+ for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) {
+ Proposal->ProposalIndex = ProposalData->ProposalIndex;
+ Proposal->ProtocolId = ProposalData->ProtocolId;
+ Proposal->NumTransforms = ProposalData->NumTransforms;
+
+ if (ProposalData->Spi == 0) {
+ Proposal->SpiSize = 0;
+ } else {
+ Proposal->SpiSize = 4;
+ *(UINT32 *) (Proposal + 1) = HTONL (*((UINT32*)ProposalData->Spi));
+ }
+
+ TransformsSize = 0;
+ Transform = (IKEV2_TRANSFORM *) ((UINT8 *) (Proposal + 1) + Proposal->SpiSize);
+
+ //
+ // Set IKE_TRANSFORM
+ //
+ for (TransformIndex = 0; TransformIndex < ProposalData->NumTransforms; TransformIndex++) {
+ TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex;
+ Transform->TransformType = TransformData->TransformType;
+ Transform->TransformId = HTONS (TransformData->TransformId);
+ SaAttrsSize = 0;
+
+ //
+ // If the Encryption Algorithm is variable key length set the key length in attribute.
+ // Note that only a single attribute type (Key Length) is defined and it is fixed length.
+ //
+ if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_ENCR && TransformData->Attribute.Attr.AttrValue != 0) {
+ SaAttribute = (IKE_SA_ATTRIBUTE *) (Transform + 1);
+ SaAttribute->AttrType = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT);
+ SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue);
+ SaAttrsSize = sizeof (IKE_SA_ATTRIBUTE);
+ }
+
+ //
+ // If the Integrity Algorithm is variable key length set the key length in attribute.
+ //
+ if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_INTEG && TransformData->Attribute.Attr.AttrValue != 0) {
+ SaAttribute = (IKE_SA_ATTRIBUTE *) (Transform + 1);
+ SaAttribute->AttrType = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT);
+ SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue);
+ SaAttrsSize = sizeof (IKE_SA_ATTRIBUTE);
+ }
+
+ TransformSize = sizeof (IKEV2_TRANSFORM) + SaAttrsSize;
+ TransformsSize += TransformSize;
+
+ Transform->Header.NextPayload = IKE_TRANSFORM_NEXT_PAYLOAD_MORE;
+ Transform->Header.PayloadLength = HTONS ((UINT16)TransformSize);
+
+ if (TransformIndex == (UINTN)(ProposalData->NumTransforms - 1)) {
+ Transform->Header.NextPayload = IKE_TRANSFORM_NEXT_PAYLOAD_NONE;
+ }
+
+ Transform = (IKEV2_TRANSFORM *)((UINT8 *) Transform + TransformSize);
+ }
+
+ //
+ // Set Proposal's Generic Header.
+ //
+ ProposalSize = sizeof (IKEV2_PROPOSAL) + Proposal->SpiSize + TransformsSize;
+ ProposalsSize += ProposalSize;
+ Proposal->Header.NextPayload = IKE_PROPOSAL_NEXT_PAYLOAD_MORE;
+ Proposal->Header.PayloadLength = HTONS ((UINT16)ProposalSize);
+
+ if (ProposalIndex == (UINTN)(SaData->NumProposals - 1)) {
+ Proposal->Header.NextPayload = IKE_PROPOSAL_NEXT_PAYLOAD_NONE;
+ }
+
+ //
+ // Point to next Proposal Payload
+ //
+ Proposal = (IKEV2_PROPOSAL *) ((UINT8 *) Proposal + ProposalSize);
+ ProposalData = (IKEV2_PROPOSAL_DATA *)(((UINT8 *)ProposalData) + sizeof (IKEV2_PROPOSAL_DATA) + (TransformIndex * sizeof (IKEV2_TRANSFORM_DATA)));
+ }
+ //
+ // Set SA's Generic Header.
+ //
+ Sa->Header.PayloadLength = (UINT16) (Sa->Header.PayloadLength + ProposalsSize);
+ return Sa;
+}
+
+/**
+ Decode SA payload.
+
+ This function converts the received SA payload to internal data structure.
+
+ @param[in] SessionCommon Pointer to IKE Common Session used to decode the SA
+ Payload.
+ @param[in] Sa Pointer to SA Payload
+
+ @return a Pointer to internal data structure for SA payload.
+
+**/
+IKEV2_SA_DATA *
+Ikev2DecodeSa (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN IKEV2_SA *Sa
+ )
+{
+ IKEV2_SA_DATA *SaData;
+ EFI_STATUS Status;
+ IKEV2_PROPOSAL *Proposal;
+ IKEV2_TRANSFORM *Transform;
+ UINTN TotalProposals;
+ UINTN TotalTransforms;
+ UINTN ProposalNextPayloadSum;
+ UINTN ProposalIndex;
+ UINTN TransformIndex;
+ UINTN SaRemaining;
+ UINT16 ProposalSize;
+ UINTN ProposalRemaining;
+ UINT16 TransformSize;
+ UINTN SaAttrRemaining;
+ IKE_SA_ATTRIBUTE *SaAttribute;
+ IKEV2_PROPOSAL_DATA *ProposalData;
+ IKEV2_TRANSFORM_DATA *TransformData;
+ UINT8 *Spi;
+
+ //
+ // Transfrom from IKE_SA payload to IKE_SA_DATA structure.
+ // Header length NTOH is already done
+ // The returned IKE_SA_DATA should be freed by caller
+ //
+ SaData = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // First round sanity check and size calculae
+ //
+ TotalProposals = 0;
+ TotalTransforms = 0;
+ ProposalNextPayloadSum = 0;
+ SaRemaining = Sa->Header.PayloadLength - sizeof (IKEV2_SA);// Point to current position in SA
+ Proposal = (IKEV2_PROPOSAL *)((IKEV2_SA *)(Sa)+1);
+
+ //
+ // Calculate the number of Proposal payload and the total numbers of
+ // Transforms payload (the transforms in all proposal payload).
+ //
+ while (SaRemaining > sizeof (IKEV2_PROPOSAL)) {
+ ProposalSize = NTOHS (Proposal->Header.PayloadLength);
+ if (SaRemaining < ProposalSize) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (Proposal->SpiSize != 0 && Proposal->SpiSize != 4) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ TotalProposals++;
+ TotalTransforms += Proposal->NumTransforms;
+ SaRemaining -= ProposalSize;
+ ProposalNextPayloadSum += Proposal->Header.NextPayload;
+ Proposal = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize);
+ }
+
+ //
+ // Check the proposal number.
+ // The proposal Substructure, the NextPayLoad field indicates : 0 (last) or 2 (more)
+ // which Specifies whether this is the last Proposal Substructure in the SA.
+ // Here suming all Proposal NextPayLoad field to check the proposal number is correct
+ // or not.
+ //
+ if (TotalProposals == 0 ||
+ (TotalProposals - 1) * IKE_PROPOSAL_NEXT_PAYLOAD_MORE != ProposalNextPayloadSum
+ ) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Second round sanity check and decode. Transform the SA payload into
+ // a IKE_SA_DATA structure.
+ //
+ SaData = (IKEV2_SA_DATA *) AllocateZeroPool (
+ sizeof (IKEV2_SA_DATA) +
+ TotalProposals * sizeof (IKEV2_PROPOSAL_DATA) +
+ TotalTransforms * sizeof (IKEV2_TRANSFORM_DATA)
+ );
+ if (SaData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (SaData, Sa, sizeof (IKEV2_SA));
+ SaData->NumProposals = TotalProposals;
+ ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1);
+
+ //
+ // Proposal Payload
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload ! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms!
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! SPI (variable) !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ for (ProposalIndex = 0, Proposal = IKEV2_SA_FIRST_PROPOSAL (Sa);
+ ProposalIndex < TotalProposals;
+ ProposalIndex++
+ ) {
+
+ //
+ // TODO: check ProposalId
+ //
+ ProposalData->ProposalIndex = Proposal->ProposalIndex;
+ ProposalData->ProtocolId = Proposal->ProtocolId;
+ if (Proposal->SpiSize == 0) {
+ ProposalData->Spi = 0;
+ } else {
+ //
+ // SpiSize == 4
+ //
+ Spi = AllocateZeroPool (Proposal->SpiSize);
+ if (Spi == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (Spi, (UINT32 *) (Proposal + 1), Proposal->SpiSize);
+ *((UINT32*) Spi) = NTOHL (*((UINT32*) Spi));
+ ProposalData->Spi = Spi;
+ }
+
+ ProposalData->NumTransforms = Proposal->NumTransforms;
+ ProposalSize = NTOHS (Proposal->Header.PayloadLength);
+ ProposalRemaining = ProposalSize;
+ //
+ // Transform Payload
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload ! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // !Transform Type ! RESERVED ! Transform ID !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! !
+ // ~ SA Attributes ~
+ // ! !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ Transform = IKEV2_PROPOSAL_FIRST_TRANSFORM (Proposal);
+ for (TransformIndex = 0; TransformIndex < Proposal->NumTransforms; TransformIndex++) {
+
+ //
+ // Transfer the IKEV2_TRANSFORM structure into internal IKEV2_TRANSFORM_DATA struture.
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex;
+ TransformData->TransformId = NTOHS (Transform->TransformId);
+ TransformData->TransformType = Transform->TransformType;
+ TransformSize = NTOHS (Transform->Header.PayloadLength);
+ //
+ // Check the Proposal Data is correct.
+ //
+ if (ProposalRemaining < TransformSize) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // Check if the Transform payload includes Attribution.
+ //
+ SaAttrRemaining = TransformSize - sizeof (IKEV2_TRANSFORM);
+
+ //
+ // According to RFC 4603, currently only the Key length attribute type is
+ // supported. For each Transform, there is only one attributeion.
+ //
+ if (SaAttrRemaining > 0) {
+ if (SaAttrRemaining != sizeof (IKE_SA_ATTRIBUTE)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ SaAttribute = (IKE_SA_ATTRIBUTE *) ((IKEV2_TRANSFORM *)(Transform) + 1);
+ TransformData->Attribute.AttrType = (UINT16)((NTOHS (SaAttribute->AttrType)) & ~SA_ATTR_FORMAT_BIT);
+ TransformData->Attribute.Attr.AttrValue = NTOHS (SaAttribute->Attr.AttrValue);
+
+ //
+ // Currently, only supports the Key Length Attribution.
+ //
+ if (TransformData->Attribute.AttrType != IKEV2_ATTRIBUTE_TYPE_KEYLEN) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ }
+
+ //
+ // Move to next Transform
+ //
+ Transform = IKEV2_NEXT_TRANSFORM_WITH_SIZE (Transform, TransformSize);
+ }
+ Proposal = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize);
+ ProposalData = (IKEV2_PROPOSAL_DATA *) ((UINT8 *)(ProposalData + 1) +
+ ProposalData->NumTransforms *
+ sizeof (IKEV2_TRANSFORM_DATA));
+ }
+
+Exit:
+ if (EFI_ERROR (Status) && SaData != NULL) {
+ FreePool (SaData);
+ SaData = NULL;
+ }
+ return SaData;
+}
+
+/**
+ General interface of payload encoding.
+
+ This function encodes the internal data structure into payload which
+ is defined in RFC 4306. The IkePayload->PayloadBuf is used to store both the input
+ payload and converted payload. Only the SA payload use the interal structure
+ to store the attribute. Other payload use structure which is same with the RFC
+ defined, for this kind payloads just do host order to network order change of
+ some fields.
+
+ @param[in] SessionCommon Pointer to IKE Session Common used to encode the payload.
+ @param[in, out] IkePayload Pointer to IKE payload to be encoded as input, and
+ store the encoded result as output.
+
+ @retval EFI_INVALID_PARAMETER Meet error when encoding the SA payload.
+ @retval EFI_SUCCESS Encoded successfully.
+
+**/
+EFI_STATUS
+Ikev2EncodePayload (
+ IN UINT8 *SessionCommon,
+ IN OUT IKE_PAYLOAD *IkePayload
+ )
+{
+ IKEV2_SA_DATA *SaData;
+ IKEV2_SA *SaPayload;
+ IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;
+ IKEV2_NOTIFY *NotifyPayload;
+ IKEV2_DELETE *DeletePayload;
+ IKEV2_KEY_EXCHANGE *KeyPayload;
+ IKEV2_TS *TsPayload;
+ IKEV2_CFG_ATTRIBUTES *CfgAttribute;
+ UINT8 *TsBuffer;
+ UINT8 Index;
+ TRAFFIC_SELECTOR *TrafficSelector;
+
+ //
+ // Transform the Internal IKE structure to IKE payload.
+ // Only the SA payload use the interal structure to store the attribute.
+ // Other payload use structure which same with the RFC defined, so there is
+ // no need to tranform them to IKE payload.
+ //
+ switch (IkePayload->PayloadType) {
+ case IKEV2_PAYLOAD_TYPE_SA:
+ //
+ // Transform IKE_SA_DATA to IK_SA payload
+ //
+ SaData = (IKEV2_SA_DATA *) IkePayload->PayloadBuf;
+ SaPayload = Ikev2EncodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, SaData);
+
+ if (SaPayload == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (!IkePayload->IsPayloadBufExt) {
+ FreePool (IkePayload->PayloadBuf);
+ }
+ IkePayload->PayloadBuf = (UINT8 *) SaPayload;
+ IkePayload->IsPayloadBufExt = FALSE;
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_NOTIFY:
+ NotifyPayload = (IKEV2_NOTIFY *) IkePayload->PayloadBuf;
+ NotifyPayload->MessageType = HTONS (NotifyPayload->MessageType);
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_DELETE:
+ DeletePayload = (IKEV2_DELETE *) IkePayload->PayloadBuf;
+ DeletePayload->NumSpis = HTONS (DeletePayload->NumSpis);
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_KE:
+ KeyPayload = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf;
+ KeyPayload->DhGroup = HTONS (KeyPayload->DhGroup);
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_TS_INIT:
+ case IKEV2_PAYLOAD_TYPE_TS_RSP:
+ TsPayload = (IKEV2_TS *) IkePayload->PayloadBuf;
+ TsBuffer = IkePayload->PayloadBuf + sizeof (IKEV2_TS);
+
+ for (Index = 0; Index < TsPayload->TSNumbers; Index++) {
+ TrafficSelector = (TRAFFIC_SELECTOR *) TsBuffer;
+ TsBuffer = TsBuffer + TrafficSelector->SelecorLen;
+ //
+ // Host order to network order
+ //
+ TrafficSelector->SelecorLen = HTONS (TrafficSelector->SelecorLen);
+ TrafficSelector->StartPort = HTONS (TrafficSelector->StartPort);
+ TrafficSelector->EndPort = HTONS (TrafficSelector->EndPort);
+
+ }
+
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_CP:
+ CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1);
+ CfgAttribute->AttritType = HTONS (CfgAttribute->AttritType);
+ CfgAttribute->ValueLength = HTONS (CfgAttribute->ValueLength);
+
+ case IKEV2_PAYLOAD_TYPE_ID_INIT:
+ case IKEV2_PAYLOAD_TYPE_ID_RSP:
+ case IKEV2_PAYLOAD_TYPE_AUTH:
+ default:
+ break;
+ }
+
+ PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf;
+ IkePayload->PayloadSize = PayloadHdr->PayloadLength;
+ PayloadHdr->PayloadLength = HTONS (PayloadHdr->PayloadLength);
+ IKEV2_DUMP_PAYLOAD (IkePayload);
+ return EFI_SUCCESS;
+}
+
+/**
+ The general interface for decoding Payload.
+
+ This function converts the received Payload into internal structure.
+
+ @param[in] SessionCommon Pointer to IKE Session Common used for decoding.
+ @param[in, out] IkePayload Pointer to IKE payload to be decoded as input, and
+ store the decoded result as output.
+
+ @retval EFI_INVALID_PARAMETER Meet error when decoding the SA payload.
+ @retval EFI_SUCCESS Decoded successfully.
+
+**/
+EFI_STATUS
+Ikev2DecodePayload (
+ IN UINT8 *SessionCommon,
+ IN OUT IKE_PAYLOAD *IkePayload
+ )
+{
+ IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;
+ UINT16 PayloadSize;
+ UINT8 PayloadType;
+ IKEV2_SA_DATA *SaData;
+ EFI_STATUS Status;
+ IKEV2_NOTIFY *NotifyPayload;
+ IKEV2_DELETE *DeletePayload;
+ UINT16 TsTotalSize;
+ TRAFFIC_SELECTOR *TsSelector;
+ IKEV2_TS *TsPayload;
+ IKEV2_KEY_EXCHANGE *KeyPayload;
+ IKEV2_CFG_ATTRIBUTES *CfgAttribute;
+ UINT8 Index;
+
+ //
+ // Transform the IKE payload to Internal IKE structure.
+ // Only the SA payload and Hash Payload use the interal
+ // structure to store the attribute. Other payloads use
+ // structure which is same with the definitions in RFC,
+ // so there is no need to tranform them to internal IKE
+ // structure.
+ //
+ Status = EFI_SUCCESS;
+ PayloadSize = (UINT16) IkePayload->PayloadSize;
+ PayloadType = IkePayload->PayloadType;
+ PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf;
+ //
+ // The PayloadSize is the size of whole payload.
+ // Replace HTONS operation to assignment statements, since the result is same.
+ //
+ PayloadHdr->PayloadLength = PayloadSize;
+
+ IKEV2_DUMP_PAYLOAD (IkePayload);
+ switch (PayloadType) {
+ case IKEV2_PAYLOAD_TYPE_SA:
+ if (PayloadSize < sizeof (IKEV2_SA)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ SaData = Ikev2DecodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, (IKEV2_SA *) PayloadHdr);
+ if (SaData == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (!IkePayload->IsPayloadBufExt) {
+ FreePool (IkePayload->PayloadBuf);
+ }
+
+ IkePayload->PayloadBuf = (UINT8 *) SaData;
+ IkePayload->IsPayloadBufExt = FALSE;
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_ID_INIT:
+ case IKEV2_PAYLOAD_TYPE_ID_RSP :
+ if (PayloadSize < sizeof (IKEV2_ID)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_NOTIFY:
+ if (PayloadSize < sizeof (IKEV2_NOTIFY)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ NotifyPayload = (IKEV2_NOTIFY *) PayloadHdr;
+ NotifyPayload->MessageType = NTOHS (NotifyPayload->MessageType);
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_DELETE:
+ if (PayloadSize < sizeof (IKEV2_DELETE)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ DeletePayload = (IKEV2_DELETE *) PayloadHdr;
+ DeletePayload->NumSpis = NTOHS (DeletePayload->NumSpis);
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_AUTH:
+ if (PayloadSize < sizeof (IKEV2_AUTH)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_KE:
+ KeyPayload = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf;
+ KeyPayload->DhGroup = HTONS (KeyPayload->DhGroup);
+ break;
+
+ case IKEV2_PAYLOAD_TYPE_TS_INIT:
+ case IKEV2_PAYLOAD_TYPE_TS_RSP :
+ TsTotalSize = 0;
+ if (PayloadSize < sizeof (IKEV2_TS)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ //
+ // Parse each traffic selector and transfer network-order to host-order
+ //
+ TsPayload = (IKEV2_TS *) IkePayload->PayloadBuf;
+ TsSelector = (TRAFFIC_SELECTOR *) (IkePayload->PayloadBuf + sizeof (IKEV2_TS));
+
+ for (Index = 0; Index < TsPayload->TSNumbers; Index++) {
+ TsSelector->SelecorLen = NTOHS (TsSelector->SelecorLen);
+ TsSelector->StartPort = NTOHS (TsSelector->StartPort);
+ TsSelector->EndPort = NTOHS (TsSelector->EndPort);
+
+ TsTotalSize = (UINT16) (TsTotalSize + TsSelector->SelecorLen);
+ TsSelector = (TRAFFIC_SELECTOR *) ((UINT8 *) TsSelector + TsSelector->SelecorLen);
+ }
+ //
+ // Check if the total size of Traffic Selectors is correct.
+ //
+ if (TsTotalSize != PayloadSize - sizeof(IKEV2_TS)) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ case IKEV2_PAYLOAD_TYPE_CP:
+ CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1);
+ CfgAttribute->AttritType = NTOHS (CfgAttribute->AttritType);
+ CfgAttribute->ValueLength = NTOHS (CfgAttribute->ValueLength);
+
+ default:
+ break;
+ }
+
+ Exit:
+ return Status;
+}
+
+/**
+ Decode the IKE packet.
+
+ This function first decrypts the IKE packet if needed , then separates the whole
+ IKE packet from the IkePacket->PayloadBuf into IkePacket payload list.
+
+ @param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON containing
+ some parameter used by IKE packet decoding.
+ @param[in, out] IkePacket The IKE Packet to be decoded on input, and
+ the decoded result on return.
+ @param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
+ IKE_CHILD_TYPE are supported.
+
+ @retval EFI_SUCCESS The IKE packet is decoded successfully.
+ @retval Otherwise The IKE packet decoding is failed.
+
+**/
+EFI_STATUS
+Ikev2DecodePacket (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN OUT IKE_PACKET *IkePacket,
+ IN UINTN IkeType
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;
+ UINT8 PayloadType;
+ UINTN RemainBytes;
+ UINT16 PayloadSize;
+ IKE_PAYLOAD *IkePayload;
+ IKE_HEADER *IkeHeader;
+ IKEV2_SA_SESSION *IkeSaSession;
+
+ IkeHeader = NULL;
+
+ //
+ // Check if the IkePacket need decrypt.
+ //
+ if (SessionCommon->State >= IkeStateAuth) {
+ Status = Ikev2DecryptPacket (SessionCommon, IkePacket, IkeType);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // If the IkePacket doesn't contain any payload return invalid parameter.
+ //
+ if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE) {
+ if ((SessionCommon->State >= IkeStateAuth) &&
+ (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INFO)
+ ) {
+ //
+ // If it is Liveness check, there will be no payload load in the encrypt payload.
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // If the PayloadTotalSize < Header length, return invalid parameter.
+ //
+ RemainBytes = IkePacket->PayloadTotalSize;
+ if (RemainBytes < sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // If the packet is first or second message, store whole message in
+ // IkeSa->InitiPacket or IkeSa->RespPacket for following Auth Payload
+ // calculate.
+ //
+ if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) {
+ IkeHeader = AllocateZeroPool (sizeof (IKE_HEADER));
+ if (IkeHeader == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (IkeHeader, IkePacket->Header, sizeof (IKE_HEADER));
+
+ //
+ // Before store the whole packet, roll back the host order to network order,
+ // since the header order was changed in the IkePacketFromNetbuf.
+ //
+ IkeHdrNetToHost (IkeHeader);
+ IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
+ if (SessionCommon->IsInitiator) {
+ IkeSaSession->RespPacket = AllocateZeroPool (IkePacket->Header->Length);
+ if (IkeSaSession->RespPacket == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ IkeSaSession->RespPacketSize = IkePacket->Header->Length;
+ CopyMem (IkeSaSession->RespPacket, IkeHeader, sizeof (IKE_HEADER));
+ CopyMem (
+ IkeSaSession->RespPacket + sizeof (IKE_HEADER),
+ IkePacket->PayloadsBuf,
+ IkePacket->Header->Length - sizeof (IKE_HEADER)
+ );
+ } else {
+ IkeSaSession->InitPacket = AllocateZeroPool (IkePacket->Header->Length);
+ if (IkeSaSession->InitPacket == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ IkeSaSession->InitPacketSize = IkePacket->Header->Length;
+ CopyMem (IkeSaSession->InitPacket, IkeHeader, sizeof (IKE_HEADER));
+ CopyMem (
+ IkeSaSession->InitPacket + sizeof (IKE_HEADER),
+ IkePacket->PayloadsBuf,
+ IkePacket->Header->Length - sizeof (IKE_HEADER)
+ );
+ }
+ }
+
+ //
+ // Point to the first Payload
+ //
+ PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePacket->PayloadsBuf;
+ PayloadType = IkePacket->Header->NextPayload;
+
+ //
+ // Parse each payload
+ //
+ while (RemainBytes >= sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) {
+ PayloadSize = NTOHS (PayloadHdr->PayloadLength);
+
+ //
+ //Check the size of the payload is correct.
+ //
+ if (RemainBytes < PayloadSize) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ //
+ // At certain states, it should save some datas before decoding.
+ //
+ if (SessionCommon->BeforeDecodePayload != NULL) {
+ SessionCommon->BeforeDecodePayload (
+ (UINT8 *) SessionCommon,
+ (UINT8 *) PayloadHdr,
+ PayloadSize,
+ PayloadType
+ );
+ }
+
+ //
+ // Initial IkePayload
+ //
+ IkePayload = IkePayloadAlloc ();
+ if (IkePayload == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ IkePayload->PayloadType = PayloadType;
+ IkePayload->PayloadBuf = (UINT8 *) PayloadHdr;
+ IkePayload->PayloadSize = PayloadSize;
+ IkePayload->IsPayloadBufExt = TRUE;
+
+ Status = Ikev2DecodePayload ((UINT8 *) SessionCommon, IkePayload);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ IPSEC_DUMP_BUF ("After Decoding Payload", IkePayload->PayloadBuf, IkePayload->PayloadSize);
+ //
+ // Add each payload into packet
+ // Notice, the IkePacket->Hdr->Lenght still recode the whole IkePacket length
+ // which is before the decoding.
+ //
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
+
+ RemainBytes -= PayloadSize;
+ PayloadType = PayloadHdr->NextPayload;
+ if (PayloadType == IKEV2_PAYLOAD_TYPE_NONE) {
+ break;
+ }
+
+ PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) ((UINT8 *) PayloadHdr + PayloadSize);
+ }
+
+ if (PayloadType != IKEV2_PAYLOAD_TYPE_NONE) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ ClearAllPayloads (IkePacket);
+ }
+
+ if (IkeHeader != NULL) {
+ FreePool (IkeHeader);
+ }
+ return Status;
+}
+
+/**
+ Encode the IKE packet.
+
+ This function puts all Payloads into one payload then encrypt it if needed.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing
+ some parameter used during IKE packet encoding.
+ @param[in, out] IkePacket Pointer to IKE_PACKET to be encoded as input,
+ and the encoded result as output.
+ @param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
+ IKE_CHILD_TYPE are supportted.
+
+ @retval EFI_SUCCESS Encode IKE packet successfully.
+ @retval Otherwise Encode IKE packet failed.
+
+**/
+EFI_STATUS
+Ikev2EncodePacket (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN OUT IKE_PACKET *IkePacket,
+ IN UINTN IkeType
+ )
+{
+ IKE_PAYLOAD *IkePayload;
+ UINTN PayloadTotalSize;
+ LIST_ENTRY *Entry;
+ EFI_STATUS Status;
+ IKEV2_SA_SESSION *IkeSaSession;
+
+ PayloadTotalSize = 0;
+ //
+ // Encode each payload
+ //
+ for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+ Entry = Entry->ForwardLink;
+ Status = Ikev2EncodePayload ((UINT8 *) SessionCommon, IkePayload);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (SessionCommon->AfterEncodePayload != NULL) {
+ //
+ // For certain states, save some payload for further calculation
+ //
+ SessionCommon->AfterEncodePayload (
+ (UINT8 *) SessionCommon,
+ IkePayload->PayloadBuf,
+ IkePayload->PayloadSize,
+ IkePayload->PayloadType
+ );
+ }
+
+ PayloadTotalSize += IkePayload->PayloadSize;
+ }
+ IkePacket->PayloadTotalSize = PayloadTotalSize;
+
+ Status = EFI_SUCCESS;
+ if (SessionCommon->State >= IkeStateAuth) {
+ //
+ // Encrypt all payload and transfer IKE packet header from Host order to Network order.
+ //
+ Status = Ikev2EncryptPacket (SessionCommon, IkePacket);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Fill in the lenght into IkePacket header and transfer Host order to Network order.
+ //
+ IkePacket->Header->Length = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize);
+ IkeHdrHostToNet (IkePacket->Header);
+ }
+
+ //
+ // If the packet is first message, store whole message in IkeSa->InitiPacket
+ // for following Auth Payload calculation.
+ //
+ if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) {
+ IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
+ if (SessionCommon->IsInitiator) {
+ IkeSaSession->InitPacketSize = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER);
+ IkeSaSession->InitPacket = AllocateZeroPool (IkeSaSession->InitPacketSize);
+ if (IkeSaSession->InitPacket == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (IkeSaSession->InitPacket, IkePacket->Header, sizeof (IKE_HEADER));
+ PayloadTotalSize = 0;
+ for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+ Entry = Entry->ForwardLink;
+ CopyMem (
+ IkeSaSession->InitPacket + sizeof (IKE_HEADER) + PayloadTotalSize,
+ IkePayload->PayloadBuf,
+ IkePayload->PayloadSize
+ );
+ PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize;
+ }
+ } else {
+ IkeSaSession->RespPacketSize = IkePacket->PayloadTotalSize + sizeof(IKE_HEADER);
+ IkeSaSession->RespPacket = AllocateZeroPool (IkeSaSession->RespPacketSize);
+ if (IkeSaSession->RespPacket == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (IkeSaSession->RespPacket, IkePacket->Header, sizeof (IKE_HEADER));
+ PayloadTotalSize = 0;
+ for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+ Entry = Entry->ForwardLink;
+
+ CopyMem (
+ IkeSaSession->RespPacket + sizeof (IKE_HEADER) + PayloadTotalSize,
+ IkePayload->PayloadBuf,
+ IkePayload->PayloadSize
+ );
+ PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Decrypt IKE packet.
+
+ This function decrypts the Encrypted IKE packet and put the result into IkePacket->PayloadBuf.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing
+ some parameter used during decrypting.
+ @param[in, out] IkePacket Pointer to IKE_PACKET to be decrypted as input,
+ and the decrypted result as output.
+ @param[in, out] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
+ IKE_CHILD_TYPE are supportted.
+
+ @retval EFI_INVALID_PARAMETER If the IKE packet length is zero or the
+ IKE packet length is not aligned with Algorithm Block Size
+ @retval EFI_SUCCESS Decrypt IKE packet successfully.
+
+**/
+EFI_STATUS
+Ikev2DecryptPacket (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN OUT IKE_PACKET *IkePacket,
+ IN OUT UINTN IkeType
+ )
+{
+ UINT8 CryptBlockSize; // Encrypt Block Size
+ UINTN DecryptedSize; // Encrypted IKE Payload Size
+ UINT8 *DecryptedBuf; // Encrypted IKE Payload buffer
+ UINTN IntegritySize;
+ UINT8 *IntegrityBuffer;
+ UINTN IvSize; // Iv Size
+ UINT8 CheckSumSize; // Integrity Check Sum Size depends on intergrity Auth
+ UINT8 *CheckSumData; // Check Sum data
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ EFI_STATUS Status;
+ UINT8 PadLen;
+ HASH_DATA_FRAGMENT Fragments[1];
+
+ IvSize = 0;
+ IkeSaSession = NULL;
+ CryptBlockSize = 0;
+ CheckSumSize = 0;
+
+ //
+ // Check if the first payload is the Encrypted payload
+ //
+ if (IkePacket->Header->NextPayload != IKEV2_PAYLOAD_TYPE_ENCRYPT) {
+ return EFI_ACCESS_DENIED;
+ }
+ CheckSumData = NULL;
+ DecryptedBuf = NULL;
+ IntegrityBuffer = NULL;
+
+ //
+ // Get the Block Size
+ //
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+
+ CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId);
+
+ CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId);
+ IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
+
+ } else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) {
+
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
+ IkeSaSession = ChildSaSession->IkeSaSession;
+ CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);
+ CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId);
+ } else {
+ //
+ // The type of SA Session would either be IkeSa or ChildSa.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CheckSumData = AllocateZeroPool (CheckSumSize);
+ if (CheckSumData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Fill in the Integrity buffer
+ //
+ IntegritySize = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER);
+ IntegrityBuffer = AllocateZeroPool (IntegritySize);
+ if (IntegrityBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ CopyMem (IntegrityBuffer, IkePacket->Header, sizeof(IKE_HEADER));
+ CopyMem (IntegrityBuffer + sizeof (IKE_HEADER), IkePacket->PayloadsBuf, IkePacket->PayloadTotalSize);
+
+ //
+ // Change Host order to Network order, since the header order was changed
+ // in the IkePacketFromNetbuf.
+ //
+ IkeHdrHostToNet ((IKE_HEADER *)IntegrityBuffer);
+
+ //
+ // Calculate the Integrity CheckSum Data
+ //
+ Fragments[0].Data = IntegrityBuffer;
+ Fragments[0].DataSize = IntegritySize - CheckSumSize;
+
+ if (SessionCommon->IsInitiator) {
+ Status = IpSecCryptoIoHmac (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
+ IkeSaSession->IkeKeys->SkArKey,
+ IkeSaSession->IkeKeys->SkArKeySize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 1,
+ CheckSumData,
+ CheckSumSize
+ );
+ } else {
+ Status = IpSecCryptoIoHmac (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
+ IkeSaSession->IkeKeys->SkAiKey,
+ IkeSaSession->IkeKeys->SkAiKeySize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 1,
+ CheckSumData,
+ CheckSumSize
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ //
+ // Compare the Integrity CheckSum Data with the one in IkePacket
+ //
+ if (CompareMem (
+ IkePacket->PayloadsBuf + IkePacket->PayloadTotalSize - CheckSumSize,
+ CheckSumData,
+ CheckSumSize
+ ) != 0) {
+ DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto ON_EXIT;
+ }
+
+ IvSize = CryptBlockSize;
+
+ //
+ // Decrypt the payload with the key.
+ //
+ DecryptedSize = IkePacket->PayloadTotalSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER) - IvSize - CheckSumSize;
+ DecryptedBuf = AllocateZeroPool (DecryptedSize);
+ if (DecryptedBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ CopyMem (
+ DecryptedBuf,
+ IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER) + IvSize,
+ DecryptedSize
+ );
+
+ if (SessionCommon->IsInitiator) {
+ Status = IpSecCryptoIoDecrypt (
+ (UINT8) SessionCommon->SaParams->EncAlgId,
+ IkeSaSession->IkeKeys->SkErKey,
+ IkeSaSession->IkeKeys->SkErKeySize << 3,
+ IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
+ DecryptedBuf,
+ DecryptedSize,
+ DecryptedBuf
+ );
+ } else {
+ Status = IpSecCryptoIoDecrypt (
+ (UINT8) SessionCommon->SaParams->EncAlgId,
+ IkeSaSession->IkeKeys->SkEiKey,
+ IkeSaSession->IkeKeys->SkEiKeySize << 3,
+ IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
+ DecryptedBuf,
+ DecryptedSize,
+ DecryptedBuf
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error decrypt buffer with %r\n", Status));
+ goto ON_EXIT;
+ }
+
+ //
+ // Get the Padding length
+ //
+ //
+ PadLen = (UINT8) (*(DecryptedBuf + DecryptedSize - sizeof (IKEV2_PAD_LEN)));
+
+ //
+ // Save the next payload of encrypted payload into IkePacket->Hdr->NextPayload
+ //
+ IkePacket->Header->NextPayload = ((IKEV2_ENCRYPTED *) IkePacket->PayloadsBuf)->Header.NextPayload;
+
+ //
+ // Free old IkePacket->PayloadBuf and point it to decrypted paylaod buffer.
+ //
+ FreePool (IkePacket->PayloadsBuf);
+ IkePacket->PayloadsBuf = DecryptedBuf;
+ IkePacket->PayloadTotalSize = DecryptedSize - PadLen;
+
+ IPSEC_DUMP_BUF ("Decrypted Buffer", DecryptedBuf, DecryptedSize);
+
+
+ON_EXIT:
+ if (CheckSumData != NULL) {
+ FreePool (CheckSumData);
+ }
+
+ if (EFI_ERROR (Status) && DecryptedBuf != NULL) {
+ FreePool (DecryptedBuf);
+ }
+
+ if (IntegrityBuffer != NULL) {
+ FreePool (IntegrityBuffer);
+ }
+
+ return Status;
+}
+
+/**
+ Encrypt IKE packet.
+
+ This function encrypt IKE packet before sending it. The Encrypted IKE packet
+ is put in to IKEV2 Encrypted Payload.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the IKE packet.
+ @param[in, out] IkePacket Pointer to IKE packet to be encrypted.
+
+ @retval EFI_SUCCESS Operation is successful.
+ @retval Others Operation is failed.
+
+**/
+EFI_STATUS
+Ikev2EncryptPacket (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN OUT IKE_PACKET *IkePacket
+ )
+{
+ UINT8 CryptBlockSize; // Encrypt Block Size
+ UINT8 CryptBlockSizeMask; // Block Mask
+ UINTN EncryptedSize; // Encrypted IKE Payload Size
+ UINT8 *EncryptedBuf; // Encrypted IKE Payload buffer
+ UINT8 *EncryptPayloadBuf; // Contain whole Encrypted Payload
+ UINTN EncryptPayloadSize; // Total size of the Encrypted payload
+ UINT8 *IntegrityBuf; // Buffer to be intergity
+ UINT8 *IvBuffer; // Initialization Vector
+ UINT8 IvSize; // Iv Size
+ UINT8 CheckSumSize; // Integrity Check Sum Size depends on intergrity Auth
+ UINT8 *CheckSumData; // Check Sum data
+ UINTN Index;
+ IKE_PAYLOAD *EncryptPayload;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ EFI_STATUS Status;
+ LIST_ENTRY *Entry;
+ IKE_PAYLOAD *IkePayload;
+ HASH_DATA_FRAGMENT Fragments[1];
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Initial all buffers to NULL.
+ //
+ EncryptedBuf = NULL;
+ EncryptPayloadBuf = NULL;
+ IvBuffer = NULL;
+ CheckSumData = NULL;
+ IkeSaSession = NULL;
+ CryptBlockSize = 0;
+ CheckSumSize = 0;
+ IntegrityBuf = NULL;
+ //
+ // Get the Block Size
+ //
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+
+ CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId);
+ CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId);
+ IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
+
+ } else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) {
+
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
+ IkeSaSession = ChildSaSession->IkeSaSession;
+ CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);
+ CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId);
+ }
+
+ //
+ // Calcualte the EncryptPayloadSize and the PAD length
+ //
+ CryptBlockSizeMask = (UINT8) (CryptBlockSize - 1);
+ EncryptedSize = (IkePacket->PayloadTotalSize + sizeof (IKEV2_PAD_LEN) + CryptBlockSizeMask) & ~CryptBlockSizeMask;
+ EncryptedBuf = (UINT8 *) AllocateZeroPool (EncryptedSize);
+ if (EncryptedBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Copy all payload into EncryptedIkePayload
+ //
+ Index = 0;
+ NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+
+ CopyMem (EncryptedBuf + Index, IkePayload->PayloadBuf, IkePayload->PayloadSize);
+ Index += IkePayload->PayloadSize;
+
+ };
+
+ //
+ // Fill in the Pading Length
+ //
+ *(EncryptedBuf + EncryptedSize - 1) = (UINT8)(EncryptedSize - IkePacket->PayloadTotalSize - 1);
+
+ //
+ // The IV size is equal with block size
+ //
+ IvSize = CryptBlockSize;
+ IvBuffer = (UINT8 *) AllocateZeroPool (IvSize);
+ if (IvBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Generate IV
+ //
+ IkeGenerateIv (IvBuffer, IvSize);
+
+ //
+ // Encrypt payload buf
+ //
+ if (SessionCommon->IsInitiator) {
+ Status = IpSecCryptoIoEncrypt (
+ (UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId,
+ IkeSaSession->IkeKeys->SkEiKey,
+ IkeSaSession->IkeKeys->SkEiKeySize << 3,
+ IvBuffer,
+ EncryptedBuf,
+ EncryptedSize,
+ EncryptedBuf
+ );
+ } else {
+ Status = IpSecCryptoIoEncrypt (
+ (UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId,
+ IkeSaSession->IkeKeys->SkErKey,
+ IkeSaSession->IkeKeys->SkErKeySize << 3,
+ IvBuffer,
+ EncryptedBuf,
+ EncryptedSize,
+ EncryptedBuf
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Allocate the buffer for the whole IKE payload (Encrypted Payload).
+ //
+ EncryptPayloadSize = sizeof(IKEV2_ENCRYPTED) + IvSize + EncryptedSize + CheckSumSize;
+ EncryptPayloadBuf = AllocateZeroPool (EncryptPayloadSize);
+ if (EncryptPayloadBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Fill in Header of Encrypted Payload
+ //
+ ((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.NextPayload = IkePacket->Header->NextPayload;
+ ((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.PayloadLength = HTONS ((UINT16)EncryptPayloadSize);
+
+ //
+ // Fill in Iv
+ //
+ CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED), IvBuffer, IvSize);
+
+ //
+ // Fill in encrypted data
+ //
+ CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED) + IvSize, EncryptedBuf, EncryptedSize);
+
+ //
+ // Fill in the IKE Packet header
+ //
+ IkePacket->PayloadTotalSize = EncryptPayloadSize;
+ IkePacket->Header->Length = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize);
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ENCRYPT;
+
+ IntegrityBuf = AllocateZeroPool (IkePacket->Header->Length);
+ if (IntegrityBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ IkeHdrHostToNet (IkePacket->Header);
+
+ CopyMem (IntegrityBuf, IkePacket->Header, sizeof (IKE_HEADER));
+ CopyMem (IntegrityBuf + sizeof (IKE_HEADER), EncryptPayloadBuf, EncryptPayloadSize);
+
+ //
+ // Calcualte Integrity CheckSum
+ //
+ Fragments[0].Data = IntegrityBuf;
+ Fragments[0].DataSize = EncryptPayloadSize + sizeof (IKE_HEADER) - CheckSumSize;
+
+ CheckSumData = AllocateZeroPool (CheckSumSize);
+ if (CheckSumData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ if (SessionCommon->IsInitiator) {
+
+ IpSecCryptoIoHmac (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
+ IkeSaSession->IkeKeys->SkAiKey,
+ IkeSaSession->IkeKeys->SkAiKeySize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 1,
+ CheckSumData,
+ CheckSumSize
+ );
+ } else {
+
+ IpSecCryptoIoHmac (
+ (UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
+ IkeSaSession->IkeKeys->SkArKey,
+ IkeSaSession->IkeKeys->SkArKeySize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 1,
+ CheckSumData,
+ CheckSumSize
+ );
+ }
+
+ //
+ // Copy CheckSum into Encrypted Payload
+ //
+ CopyMem (EncryptPayloadBuf + EncryptPayloadSize - CheckSumSize, CheckSumData, CheckSumSize);
+
+ IPSEC_DUMP_BUF ("Encrypted payload buffer", EncryptPayloadBuf, EncryptPayloadSize);
+ IPSEC_DUMP_BUF ("Integrith CheckSum Data", CheckSumData, CheckSumSize);
+
+ //
+ // Clean all payload under IkePacket->PayloadList.
+ //
+ ClearAllPayloads (IkePacket);
+
+ //
+ // Create Encrypted Payload and add into IkePacket->PayloadList
+ //
+ EncryptPayload = IkePayloadAlloc ();
+ if (EncryptPayload == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Fill the encrypted payload into the IKE_PAYLOAD structure.
+ //
+ EncryptPayload->PayloadBuf = EncryptPayloadBuf;
+ EncryptPayload->PayloadSize = EncryptPayloadSize;
+ EncryptPayload->PayloadType = IKEV2_PAYLOAD_TYPE_ENCRYPT;
+
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, EncryptPayload);
+
+ON_EXIT:
+ if (EncryptedBuf != NULL) {
+ FreePool (EncryptedBuf);
+ }
+
+ if (EFI_ERROR (Status) && EncryptPayloadBuf != NULL) {
+ FreePool (EncryptPayloadBuf);
+ }
+
+ if (IvBuffer != NULL) {
+ FreePool (IvBuffer);
+ }
+
+ if (CheckSumData != NULL) {
+ FreePool (CheckSumData);
+ }
+
+ if (IntegrityBuf != NULL) {
+ FreePool (IntegrityBuf);
+ }
+
+ return Status;
+}
+
+/**
+ Save some useful payloads after accepting the Packet.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the operation.
+ @param[in] IkePacket Pointer to received IkePacet.
+ @param[in] IkeType The type used to indicate it is in IkeSa or ChildSa or Info
+ exchange.
+
+**/
+VOID
+Ikev2OnPacketAccepted (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN IKE_PACKET *IkePacket,
+ IN UINT8 IkeType
+ )
+{
+ return;
+}
+
+/**
+
+ The notification function. It will be called when the related UDP_TX_TOKEN's event
+ is signaled.
+
+ This function frees the Net Buffer pointed to the input Packet.
+
+ @param[in] Packet Pointer to Net buffer containing the sending IKE packet.
+ @param[in] EndPoint Pointer to UDP_END_POINT containing the remote and local
+ address information.
+ @param[in] IoStatus The Status of the related UDP_TX_TOKEN.
+ @param[in] Context Pointer to data passed from the caller.
+
+**/
+VOID
+EFIAPI
+Ikev2OnPacketSent (
+ IN NET_BUF *Packet,
+ IN UDP_END_POINT *EndPoint,
+ IN EFI_STATUS IoStatus,
+ IN VOID *Context
+ )
+{
+ IKE_PACKET *IkePacket;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ UINT8 Value;
+ IPSEC_PRIVATE_DATA *Private;
+ EFI_STATUS Status;
+
+ IkePacket = (IKE_PACKET *) Context;
+ Private = NULL;
+
+ if (EFI_ERROR (IoStatus)) {
+ DEBUG ((DEBUG_ERROR, "Error send the last packet in IkeSessionTypeIkeSa with %r\n", IoStatus));
+ }
+
+ NetbufFree (Packet);
+
+ if (IkePacket->IsDeleteInfo) {
+ //
+ // For each RemotePeerIP, there are only one IKESA.
+ //
+ IkeSaSession = Ikev2SaSessionLookup (
+ &IkePacket->Private->Ikev2EstablishedList,
+ &IkePacket->RemotePeerIp
+ );
+ if (IkeSaSession == NULL) {
+ IkePacketFree (IkePacket);
+ return;
+ }
+
+ Private = IkePacket->Private;
+ if (IkePacket->Spi != 0 ) {
+ //
+ // At that time, the established Child SA still in eht ChildSaEstablishSessionList.
+ // And meanwhile, if the Child SA is in the the ChildSa in Delete list,
+ // remove it from delete list and delete it direclty.
+ //
+ ChildSaSession = Ikev2ChildSaSessionLookupBySpi (
+ &IkeSaSession->ChildSaEstablishSessionList,
+ IkePacket->Spi
+ );
+ if (ChildSaSession != NULL) {
+ Ikev2ChildSaSessionRemove (
+ &IkeSaSession->DeleteSaList,
+ ChildSaSession->LocalPeerSpi,
+ IKEV2_DELET_CHILDSA_LIST
+ );
+
+ //
+ // Delete the Child SA.
+ //
+ Ikev2ChildSaSilentDelete (
+ IkeSaSession,
+ IkePacket->Spi
+ );
+ }
+
+ } else {
+ //
+ // Delete the IKE SA
+ //
+ DEBUG (
+ (DEBUG_INFO,
+ "\n------ deleted Packet (cookie_i, cookie_r):(0x%lx, 0x%lx)------\n",
+ IkeSaSession->InitiatorCookie,
+ IkeSaSession->ResponderCookie)
+ );
+
+ RemoveEntryList (&IkeSaSession->BySessionTable);
+ Ikev2SaSessionFree (IkeSaSession);
+ }
+ }
+ IkePacketFree (IkePacket);
+
+ //
+ // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec status
+ // should be changed.
+ //
+ if (Private != NULL && Private->IsIPsecDisabling) {
+ //
+ // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in
+ // IPsec status variable.
+ //
+ if (IsListEmpty (&Private->Ikev1EstablishedList) && IsListEmpty (&Private->Ikev2EstablishedList)) {
+ Value = IPSEC_STATUS_DISABLED;
+ Status = gRT->SetVariable (
+ IPSECCONFIG_STATUS_NAME,
+ &gEfiIpSecConfigProtocolGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (Value),
+ &Value
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set the DisabledFlag in Private data.
+ //
+ Private->IpSec.DisabledFlag = TRUE;
+ Private->IsIPsecDisabling = FALSE;
+ }
+ }
+ }
+}
+
+/**
+ Send out IKEV2 packet.
+
+ @param[in] IkeUdpService Pointer to IKE_UDP_SERVICE used to send the IKE packet.
+ @param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON related to the IKE packet.
+ @param[in] IkePacket Pointer to IKE_PACKET to be sent out.
+ @param[in] IkeType The type of IKE to point what's kind of the IKE
+ packet is to be sent out. IKE_SA_TYPE, IKE_INFO_TYPE
+ and IKE_CHILD_TYPE are supportted.
+
+ @retval EFI_SUCCESS The operation complete successfully.
+ @retval Otherwise The operation is failed.
+
+**/
+EFI_STATUS
+Ikev2SendIkePacket (
+ IN IKE_UDP_SERVICE *IkeUdpService,
+ IN UINT8 *SessionCommon,
+ IN IKE_PACKET *IkePacket,
+ IN UINTN IkeType
+ )
+{
+ EFI_STATUS Status;
+ NET_BUF *IkePacketNetbuf;
+ UDP_END_POINT EndPoint;
+ IKEV2_SESSION_COMMON *Common;
+
+ Common = (IKEV2_SESSION_COMMON *) SessionCommon;
+
+ //
+ // Set the resend interval
+ //
+ if (Common->TimeoutInterval == 0) {
+ Common->TimeoutInterval = IKE_DEFAULT_TIMEOUT_INTERVAL;
+ }
+
+ //
+ // Retransfer the packet if it is initial packet.
+ //
+ if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) {
+ //
+ // Set timer for next retry, this will cancel previous timer
+ //
+ Status = gBS->SetTimer (
+ Common->TimeoutEvent,
+ TimerRelative,
+ MultU64x32 (Common->TimeoutInterval, 10000) // ms->100ns
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ IKE_PACKET_REF (IkePacket);
+ //
+ // If the last sent packet is same with this round packet, the packet is resent packet.
+ //
+ if (IkePacket != Common->LastSentPacket && Common->LastSentPacket != NULL) {
+ IkePacketFree (Common->LastSentPacket);
+ }
+
+ Common->LastSentPacket = IkePacket;
+
+ //
+ // Transform IkePacke to NetBuf
+ //
+ IkePacketNetbuf = IkeNetbufFromPacket ((UINT8 *) SessionCommon, IkePacket, IkeType);
+ if (IkePacketNetbuf == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem (&EndPoint, sizeof (UDP_END_POINT));
+ EndPoint.RemotePort = IKE_DEFAULT_PORT;
+ CopyMem (&IkePacket->RemotePeerIp, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&EndPoint.RemoteAddr, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&EndPoint.LocalAddr, &Common->LocalPeerIp, sizeof (EFI_IP_ADDRESS));
+
+ IPSEC_DUMP_PACKET (IkePacket, EfiIPsecOutBound, IkeUdpService->IpVersion);
+
+ if (IkeUdpService->IpVersion == IP_VERSION_4) {
+ EndPoint.RemoteAddr.Addr[0] = HTONL (EndPoint.RemoteAddr.Addr[0]);
+ EndPoint.LocalAddr.Addr[0] = HTONL (EndPoint.LocalAddr.Addr[0]);
+ }
+
+ //
+ // Call UDPIO to send out the IKE packet.
+ //
+ Status = UdpIoSendDatagram (
+ IkeUdpService->Output,
+ IkePacketNetbuf,
+ &EndPoint,
+ NULL,
+ Ikev2OnPacketSent,
+ (VOID*)IkePacket
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error send packet with %r\n", Status));
+ }
+
+ return Status;
+}
+
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/Payload.h b/Core/NetworkPkg/IpSecDxe/Ikev2/Payload.h
new file mode 100644
index 0000000000..6096a3ba77
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Payload.h
@@ -0,0 +1,438 @@
+/** @file
+ The Definitions related to IKEv2 payload.
+
+ Copyright (c) 2010, 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.
+
+**/
+#ifndef _IKE_V2_PAYLOAD_H_
+#define _IKE_V2_PAYLOAD_H_
+
+//
+// Payload Type for IKEv2
+//
+#define IKEV2_PAYLOAD_TYPE_NONE 0
+#define IKEV2_PAYLOAD_TYPE_SA 33
+#define IKEV2_PAYLOAD_TYPE_KE 34
+#define IKEV2_PAYLOAD_TYPE_ID_INIT 35
+#define IKEV2_PAYLOAD_TYPE_ID_RSP 36
+#define IKEV2_PAYLOAD_TYPE_CERT 37
+#define IKEV2_PAYLOAD_TYPE_CERTREQ 38
+#define IKEV2_PAYLOAD_TYPE_AUTH 39
+#define IKEV2_PAYLOAD_TYPE_NONCE 40
+#define IKEV2_PAYLOAD_TYPE_NOTIFY 41
+#define IKEV2_PAYLOAD_TYPE_DELETE 42
+#define IKEV2_PAYLOAD_TYPE_VENDOR 43
+#define IKEV2_PAYLOAD_TYPE_TS_INIT 44
+#define IKEV2_PAYLOAD_TYPE_TS_RSP 45
+#define IKEV2_PAYLOAD_TYPE_ENCRYPT 46
+#define IKEV2_PAYLOAD_TYPE_CP 47
+#define IKEV2_PAYLOAD_TYPE_EAP 48
+
+//
+// IKE header Flag for IKEv2
+//
+#define IKE_HEADER_FLAGS_INIT 0x08
+#define IKE_HEADER_FLAGS_RESPOND 0x20
+#define IKE_HEADER_FLAGS_CHILD_INIT 0
+
+//
+// IKE Header Exchange Type for IKEv2
+//
+#define IKEV2_EXCHANGE_TYPE_INIT 34
+#define IKEV2_EXCHANGE_TYPE_AUTH 35
+#define IKEV2_EXCHANGE_TYPE_CREATE_CHILD 36
+#define IKEV2_EXCHANGE_TYPE_INFO 37
+
+#pragma pack(1)
+typedef struct {
+ UINT8 NextPayload;
+ UINT8 Reserved;
+ UINT16 PayloadLength;
+} IKEV2_COMMON_PAYLOAD_HEADER;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ //
+ // Proposals
+ //
+} IKEV2_SA;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 ProposalIndex;
+ UINT8 ProtocolId;
+ UINT8 SpiSize;
+ UINT8 NumTransforms;
+} IKEV2_PROPOSAL;
+#pragma pack()
+
+//
+// IKEv2 Transform Type Values presented within Transform Payload
+//
+#define IKEV2_TRANSFORM_TYPE_ENCR 1 // Encryption Algorithm
+#define IKEV2_TRANSFORM_TYPE_PRF 2 // Pseduo-Random Func
+#define IKEV2_TRANSFORM_TYPE_INTEG 3 // Integrity Algorithm
+#define IKEV2_TRANSFORM_TYPE_DH 4 // DH Group
+#define IKEV2_TRANSFORM_TYPE_ESN 5 // Extended Sequence Number
+
+//
+// IKEv2 Transform ID for Encrypt Algorithm (ENCR)
+//
+#define IKEV2_TRANSFORM_ID_ENCR_DES_IV64 1
+#define IKEV2_TRANSFORM_ID_ENCR_DES 2
+#define IKEV2_TRANSFORM_ID_ENCR_3DES 3
+#define IKEV2_TRANSFORM_ID_ENCR_RC5 4
+#define IKEV2_TRANSFORM_ID_ENCR_IDEA 5
+#define IKEV2_TRANSFORM_ID_ENCR_CAST 6
+#define IKEV2_TRANSFORM_ID_ENCR_BLOWFISH 7
+#define IKEV2_TRANSFORM_ID_ENCR_3IDEA 8
+#define IKEV2_TRANSFORM_ID_ENCR_DES_IV32 9
+#define IKEV2_TRANSFORM_ID_ENCR_NULL 11
+#define IKEV2_TRANSFORM_ID_ENCR_AES_CBC 12
+#define IKEV2_TRANSFORM_ID_ENCR_AES_CTR 13
+
+//
+// IKEv2 Transform ID for Pseudo-Random Function (PRF)
+//
+#define IKEV2_TRANSFORM_ID_PRF_HMAC_MD5 1
+#define IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1 2
+#define IKEV2_TRANSFORM_ID_PRF_HMAC_TIGER 3
+#define IKEV2_TRANSFORM_ID_PRF_AES128_XCBC 4
+
+//
+// IKEv2 Transform ID for Integrity Algorithm (INTEG)
+//
+#define IKEV2_TRANSFORM_ID_AUTH_NONE 0
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_MD5_96 1
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96 2
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_DES_MAC 3
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_KPDK_MD5 4
+#define IKEV2_TRANSFORM_ID_AUTH_HMAC_AES_XCBC_96 5
+
+//
+// IKEv2 Transform ID for Diffie-Hellman Group (DH)
+//
+#define IKEV2_TRANSFORM_ID_DH_768MODP 1
+#define IKEV2_TRANSFORM_ID_DH_1024MODP 2
+#define IKEV2_TRANSFORM_ID_DH_2048MODP 14
+
+//
+// IKEv2 Attribute Type Values
+//
+#define IKEV2_ATTRIBUTE_TYPE_KEYLEN 14
+
+//
+// Transform Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 TransformType;
+ UINT8 Reserved;
+ UINT16 TransformId;
+ //
+ // SA Attributes
+ //
+} IKEV2_TRANSFORM;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT16 DhGroup;
+ UINT16 Reserved;
+ //
+ // Remaining part contains the key exchanged
+ //
+} IKEV2_KEY_EXCHANGE;
+#pragma pack()
+
+//
+// Identification Type Values presented within Ikev2 ID payload
+//
+#define IKEV2_ID_TYPE_IPV4_ADDR 1
+#define IKEV2_ID_TYPE_FQDN 2
+#define IKEV2_ID_TYPE_RFC822_ADDR 3
+#define IKEV2_ID_TYPE_IPV6_ADDR 5
+#define IKEV2_ID_TYPE_DER_ASN1_DN 9
+#define IKEV2_ID_TYPE_DER_ASN1_GN 10
+#define IKEV2_ID_TYPE_KEY_ID 11
+
+//
+// Identification Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 IdType;
+ UINT8 Reserver1;
+ UINT16 Reserver2;
+ //
+ // Identification Data
+ //
+} IKEV2_ID;
+#pragma pack()
+
+//
+// Encoding Type presented in IKEV2 Cert Payload
+//
+#define IKEV2_CERT_ENCODEING_RESERVED 0
+#define IKEV2_CERT_ENCODEING_X509_CERT_WRAP 1
+#define IKEV2_CERT_ENCODEING_PGP_CERT 2
+#define IKEV2_CERT_ENCODEING_DNS_SIGN_KEY 3
+#define IKEV2_CERT_ENCODEING_X509_CERT_SIGN 4
+#define IKEV2_CERT_ENCODEING_KERBEROS_TOKEN 6
+#define IKEV2_CERT_ENCODEING_REVOCATION_LIST_CERT 7
+#define IKEV2_CERT_ENCODEING_AUTH_REVOCATION_LIST 8
+#define IKEV2_CERT_ENCODEING_SPKI_CERT 9
+#define IKEV2_CERT_ENCODEING_X509_CERT_ATTRIBUTE 10
+#define IKEV2_CERT_ENCODEING_RAW_RSA_KEY 11
+#define IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT 12
+
+//
+// IKEV2 Certificate Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 CertEncoding;
+ //
+ // Cert Data
+ //
+} IKEV2_CERT;
+#pragma pack()
+
+//
+// IKEV2 Certificate Request Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 CertEncoding;
+ //
+ // Cert Authority
+ //
+} IKEV2_CERT_REQ;
+#pragma pack()
+
+//
+// Authentication Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 AuthMethod;
+ UINT8 Reserved1;
+ UINT16 Reserved2;
+ //
+ // Auth Data
+ //
+} IKEV2_AUTH;
+#pragma pack()
+
+//
+// Authmethod in Authentication Payload
+//
+#define IKEV2_AUTH_METHOD_RSA 1; // RSA Digital Signature
+#define IKEV2_AUTH_METHOD_SKMI 2; // Shared Key Message Integrity
+#define IKEV2_AUTH_METHOD_DSS 3; // DSS Digital Signature
+
+//
+// IKEv2 Nonce Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ //
+ // Nonce Data
+ //
+} IKEV2_NONCE;
+#pragma pack()
+
+//
+// Notification Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 ProtocolId;
+ UINT8 SpiSize;
+ UINT16 MessageType;
+ //
+ // SPI and Notification Data
+ //
+} IKEV2_NOTIFY;
+#pragma pack()
+
+//
+// Notify Message Types presented within IKEv2 Notify Payload
+//
+#define IKEV2_NOTIFICATION_UNSUPPORT_CRITICAL_PAYLOAD 1
+#define IKEV2_NOTIFICATION_INVALID_IKE_SPI 4
+#define IKEV2_NOTIFICATION_INVALID_MAJOR_VERSION 5
+#define IKEV2_NOTIFICATION_INVALID_SYNTAX 7
+#define IKEV2_NOTIFICATION_INVALID_MESSAGE_ID 9
+#define IKEV2_NOTIFICATION_INVALID_SPI 11
+#define IKEV2_NOTIFICATION_NO_PROPOSAL_CHOSEN 14
+#define IKEV2_NOTIFICATION_INVALID_KEY_PAYLOAD 17
+#define IKEV2_NOTIFICATION_AUTHENTICATION_FAILED 24
+#define IKEV2_NOTIFICATION_SINGLE_PAIR_REQUIRED 34
+#define IKEV2_NOTIFICATION_NO_ADDITIONAL_SAS 35
+#define IKEV2_NOTIFICATION_INTERNAL_ADDRESS_FAILURE 36
+#define IKEV2_NOTIFICATION_FAILED_CP_REQUIRED 37
+#define IKEV2_NOTIFICATION_TS_UNCCEPTABLE 38
+#define IKEV2_NOTIFICATION_INVALID_SELECTORS 39
+#define IKEV2_NOTIFICATION_COOKIE 16390
+#define IKEV2_NOTIFICATION_USE_TRANSPORT_MODE 16391
+#define IKEV2_NOTIFICATION_REKEY_SA 16393
+
+//
+// IKEv2 Protocol ID
+//
+//
+// IKEv2 Delete Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 ProtocolId;
+ UINT8 SpiSize;
+ UINT16 NumSpis;
+ //
+ // SPIs
+ //
+} IKEV2_DELETE;
+#pragma pack()
+
+//
+// Traffic Selector Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 TSNumbers;
+ UINT8 Reserved1;
+ UINT16 Reserved2;
+ //
+ // Traffic Selector
+ //
+} IKEV2_TS;
+#pragma pack()
+
+//
+// Traffic Selector
+//
+#pragma pack(1)
+typedef struct {
+ UINT8 TSType;
+ UINT8 IpProtocolId;
+ UINT16 SelecorLen;
+ UINT16 StartPort;
+ UINT16 EndPort;
+ //
+ // Starting Address && Ending Address
+ //
+} TRAFFIC_SELECTOR;
+#pragma pack()
+
+//
+// Ts Type in Traffic Selector
+//
+#define IKEV2_TS_TYPE_IPV4_ADDR_RANGE 7
+#define IKEV2_TS_TYPS_IPV6_ADDR_RANGE 8
+
+//
+// Vendor Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ //
+ // Vendor ID
+ //
+} IKEV2_VENDOR;
+#pragma pack()
+
+//
+// Encrypted Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ //
+ // IV, Encrypted IKE Payloads, Padding, PAD length, Integrity CheckSum
+ //
+} IKEV2_ENCRYPTED;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct {
+ UINT8 PadLength;
+} IKEV2_PAD_LEN;
+#pragma pack()
+
+//
+// Configuration Payload
+//
+#pragma pack(1)
+typedef struct {
+ IKEV2_COMMON_PAYLOAD_HEADER Header;
+ UINT8 CfgType;
+ UINT8 Reserve1;
+ UINT16 Reserve2;
+ //
+ // Configuration Attributes
+ //
+} IKEV2_CFG;
+#pragma pack()
+
+//
+// Configuration Payload CPG type
+//
+#define IKEV2_CFG_TYPE_REQUEST 1
+#define IKEV2_CFG_TYPE_REPLY 2
+#define IKEV2_CFG_TYPE_SET 3
+#define IKEV2_CFG_TYPE_ACK 4
+
+//
+// Configuration Attributes
+//
+#pragma pack(1)
+typedef struct {
+ UINT16 AttritType;
+ UINT16 ValueLength;
+} IKEV2_CFG_ATTRIBUTES;
+#pragma pack()
+
+//
+// Configuration Attributes
+//
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS 1
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_NBTMASK 2
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_DNS 3
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_NBNS 4
+#define IKEV2_CFG_ATTR_INTERNA_ADDRESS_BXPIRY 5
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_DHCP 6
+#define IKEV2_CFG_ATTR_APPLICATION_VERSION 7
+#define IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS 8
+#define IKEV2_CFG_ATTR_INTERNAL_IP6_DNS 10
+#define IKEV2_CFG_ATTR_INTERNAL_IP6_NBNS 11
+#define IKEV2_CFG_ATTR_INTERNAL_IP6_DHCP 12
+#define IKEV2_CFG_ATTR_INTERNAL_IP4_SUBNET 13
+#define IKEV2_CFG_ATTR_SUPPORTED_ATTRIBUTES 14
+#define IKEV2_CFG_ATTR_IP6_SUBNET 15
+
+#endif
+
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/Sa.c b/Core/NetworkPkg/IpSecDxe/Ikev2/Sa.c
new file mode 100644
index 0000000000..4cbfac33b1
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Sa.c
@@ -0,0 +1,2262 @@
+/** @file
+ The operations for IKEv2 SA.
+
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2010 - 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 "Utility.h"
+#include "IpSecDebug.h"
+#include "IkeService.h"
+#include "Ikev2.h"
+
+/**
+ Generates the DH Key.
+
+ This generates the DH local public key and store it in the IKEv2 SA Session's GxBuffer.
+
+ @param[in] IkeSaSession Pointer to related IKE SA Session.
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval Others The operation failed.
+
+**/
+EFI_STATUS
+Ikev2GenerateSaDhPublicKey (
+ IN IKEV2_SA_SESSION *IkeSaSession
+ );
+
+/**
+ Generates the IKEv2 SA key for the furthure IKEv2 exchange.
+
+ @param[in] IkeSaSession Pointer to IKEv2 SA Session.
+ @param[in] KePayload Pointer to Key payload used to generate the Key.
+
+ @retval EFI_UNSUPPORTED If the Algorithm Id is not supported.
+ @retval EFI_SUCCESS The operation succeeded.
+
+**/
+EFI_STATUS
+Ikev2GenerateSaKeys (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_PAYLOAD *KePayload
+ );
+
+/**
+ Generates the Keys for the furthure IPsec Protocol.
+
+ @param[in] ChildSaSession Pointer to IKE Child SA Session.
+ @param[in] KePayload Pointer to Key payload used to generate the Key.
+
+ @retval EFI_UNSUPPORTED If one or more Algorithm Id is unsupported.
+ @retval EFI_SUCCESS The operation succeeded.
+
+**/
+EFI_STATUS
+Ikev2GenerateChildSaKeys (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession,
+ IN IKE_PAYLOAD *KePayload
+ );
+
+/**
+ Gernerates IKEv2 packet for IKE_SA_INIT exchange.
+
+ @param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange.
+ @param[in] Context Context Data passed by caller.
+
+ @retval EFI_SUCCESS The IKEv2 packet generation succeeded.
+ @retval Others The IKEv2 packet generation failed.
+
+**/
+IKE_PACKET *
+Ikev2InitPskGenerator (
+ IN UINT8 *SaSession,
+ IN VOID *Context
+ )
+{
+ IKE_PACKET *IkePacket;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKE_PAYLOAD *SaPayload;
+ IKE_PAYLOAD *KePayload;
+ IKE_PAYLOAD *NoncePayload;
+ IKE_PAYLOAD *NotifyPayload;
+ EFI_STATUS Status;
+
+ SaPayload = NULL;
+ KePayload = NULL;
+ NoncePayload = NULL;
+ NotifyPayload = NULL;
+
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+
+ //
+ // 1. Allocate IKE packet
+ //
+ IkePacket = IkePacketAlloc ();
+ if (IkePacket == NULL) {
+ goto CheckError;
+ }
+
+ //
+ // 1.a Fill the IkePacket->Hdr
+ //
+ IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_INIT;
+ IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
+ IkePacket->Header->Version = (UINT8) (2 << 4);
+ IkePacket->Header->MessageId = 0;
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
+ } else {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
+ }
+
+ //
+ // If the NCookie is not NULL, this IKE_SA_INIT packet is resent by the NCookie
+ // and the NCookie payload should be the first payload in this packet.
+ //
+ if (IkeSaSession->NCookie != NULL) {
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NOTIFY;
+ NotifyPayload = Ikev2GenerateNotifyPayload (
+ IPSEC_PROTO_ISAKMP,
+ IKEV2_PAYLOAD_TYPE_SA,
+ 0,
+ IKEV2_NOTIFICATION_COOKIE,
+ NULL,
+ IkeSaSession->NCookie,
+ IkeSaSession->NCookieSize
+ );
+ } else {
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_SA;
+ }
+
+ //
+ // 2. Generate SA Payload according to the SaData & SaParams
+ //
+ SaPayload = Ikev2GenerateSaPayload (
+ IkeSaSession->SaData,
+ IKEV2_PAYLOAD_TYPE_KE,
+ IkeSessionTypeIkeSa
+ );
+
+ //
+ // 3. Generate DH public key.
+ // The DhPrivate Key has been generated in Ikev2InitPskParser, if the
+ // IkeSaSession is responder. If resending IKE_SA_INIT with Cookie Notify
+ // No need to recompute the Public key.
+ //
+ if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) {
+ Status = Ikev2GenerateSaDhPublicKey (IkeSaSession);
+ if (EFI_ERROR (Status)) {
+ goto CheckError;
+ }
+ }
+
+ //
+ // 4. Generate KE Payload according to SaParams->DhGroup
+ //
+ KePayload = Ikev2GenerateKePayload (
+ IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_NONCE
+ );
+
+ //
+ // 5. Generate Nonce Payload
+ // If resending IKE_SA_INIT with Cookie Notify paylaod, no need to regenerate
+ // the Nonce Payload.
+ //
+ if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) {
+ IkeSaSession->NiBlkSize = IKE_NONCE_SIZE;
+ IkeSaSession->NiBlock = IkeGenerateNonce (IKE_NONCE_SIZE);
+ if (IkeSaSession->NiBlock == NULL) {
+ goto CheckError;
+ }
+ }
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ NoncePayload = Ikev2GenerateNoncePayload (
+ IkeSaSession->NiBlock,
+ IkeSaSession->NiBlkSize,
+ IKEV2_PAYLOAD_TYPE_NONE
+ );
+ } else {
+ //
+ // The Nonce Payload has been created in Ikev2PskParser if the IkeSaSession is
+ // responder.
+ //
+ NoncePayload = Ikev2GenerateNoncePayload (
+ IkeSaSession->NrBlock,
+ IkeSaSession->NrBlkSize,
+ IKEV2_PAYLOAD_TYPE_NONE
+ );
+ }
+
+ if (NotifyPayload != NULL) {
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
+ }
+ if (SaPayload != NULL) {
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);
+ }
+ if (KePayload != NULL) {
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, KePayload);
+ }
+ if (NoncePayload != NULL) {
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, NoncePayload);
+ }
+
+ return IkePacket;
+
+CheckError:
+ if (IkePacket != NULL) {
+ IkePacketFree (IkePacket);
+ }
+ if (SaPayload != NULL) {
+ IkePayloadFree (SaPayload);
+ }
+ return NULL;
+}
+
+/**
+ Parses the IKEv2 packet for IKE_SA_INIT exchange.
+
+ @param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange.
+ @param[in] IkePacket The received IKE packet to be parsed.
+
+ @retval EFI_SUCCESS The IKEv2 packet is acceptable and the relative data is
+ saved for furthure communication.
+ @retval EFI_INVALID_PARAMETER The IKEv2 packet is malformed or the SA proposal is unacceptable.
+
+**/
+EFI_STATUS
+Ikev2InitPskParser (
+ IN UINT8 *SaSession,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKE_PAYLOAD *SaPayload;
+ IKE_PAYLOAD *KeyPayload;
+ IKE_PAYLOAD *IkePayload;
+ IKE_PAYLOAD *NoncePayload;
+ IKE_PAYLOAD *NotifyPayload;
+ UINT8 *NonceBuffer;
+ UINTN NonceSize;
+ LIST_ENTRY *Entry;
+ EFI_STATUS Status;
+
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+ KeyPayload = NULL;
+ SaPayload = NULL;
+ NoncePayload = NULL;
+ IkePayload = NULL;
+ NotifyPayload = NULL;
+
+ //
+ // Iterate payloads to find the SaPayload and KeyPayload.
+ //
+ NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {
+ SaPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_KE) {
+ KeyPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NONCE) {
+ NoncePayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NOTIFY) {
+ NotifyPayload = IkePayload;
+ }
+ }
+
+ //
+ // According to RFC 4306 - 2.6. If the responder responds with the COOKIE Notify
+ // payload with the cookie data, initiator MUST retry the IKE_SA_INIT with a
+ // Notify payload of type COOKIE containing the responder suppplied cookie data
+ // as first payload and all other payloads unchanged.
+ //
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ if (NotifyPayload != NULL) {
+ Status = Ikev2ParserNotifyCookiePayload (NotifyPayload, IkeSaSession);
+ return Status;
+ }
+ }
+
+ if ((KeyPayload == NULL) || (SaPayload == NULL) || (NoncePayload == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Store NoncePayload for SKEYID computing.
+ //
+ NonceSize = NoncePayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
+ NonceBuffer = (UINT8 *) AllocatePool (NonceSize);
+ if (NonceBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto CheckError;
+ }
+
+ CopyMem (
+ NonceBuffer,
+ NoncePayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
+ NonceSize
+ );
+
+ //
+ // Check if IkePacket Header matches the state
+ //
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ //
+ // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND
+ //
+ if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) {
+ Status = EFI_INVALID_PARAMETER;
+ goto CheckError;
+ }
+
+ //
+ // 2. Parse the SA Payload and Key Payload to find out the cryptographic
+ // suite and fill in the Sa paramse into CommonSession->SaParams
+ //
+ if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto CheckError;
+ }
+
+ //
+ // 3. If Initiator, the NoncePayload is Nr_b.
+ //
+ IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateAuth);
+ IkeSaSession->NrBlock = NonceBuffer;
+ IkeSaSession->NrBlkSize = NonceSize;
+ IkeSaSession->SessionCommon.State = IkeStateAuth;
+ IkeSaSession->ResponderCookie = IkePacket->Header->ResponderCookie;
+
+ //
+ // 4. Change the state of IkeSaSession
+ //
+ IkeSaSession->SessionCommon.State = IkeStateAuth;
+ } else {
+ //
+ // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT
+ //
+ if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) {
+ Status = EFI_INVALID_PARAMETER;
+ goto CheckError;
+ }
+
+ //
+ // 2. Parse the SA payload and find out the perfered one
+ // and fill in the SA parameters into CommonSession->SaParams and SaData into
+ // IkeSaSession for the responder SA payload generation.
+ //
+ if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto CheckError;
+ }
+
+ //
+ // 3. Generat Dh Y parivate Key
+ //
+ Status = Ikev2GenerateSaDhPublicKey (IkeSaSession);
+ if (EFI_ERROR (Status)) {
+ goto CheckError;
+ }
+
+ //
+ // 4. If Responder, the NoncePayload is Ni_b and go to generate Nr_b.
+ //
+ IkeSaSession->NiBlock = NonceBuffer;
+ IkeSaSession->NiBlkSize = NonceSize;
+
+ //
+ // 5. Generate Nr_b
+ //
+ IkeSaSession->NrBlock = IkeGenerateNonce (IKE_NONCE_SIZE);
+ ASSERT (IkeSaSession->NrBlock != NULL);
+ IkeSaSession->NrBlkSize = IKE_NONCE_SIZE;
+
+ //
+ // 6. Save the Cookies
+ //
+ IkeSaSession->InitiatorCookie = IkePacket->Header->InitiatorCookie;
+ IkeSaSession->ResponderCookie = IkeGenerateCookie ();
+ }
+
+ if (IkeSaSession->SessionCommon.PreferDhGroup != ((IKEV2_KEY_EXCHANGE *)KeyPayload->PayloadBuf)->DhGroup) {
+ Status = EFI_INVALID_PARAMETER;
+ goto CheckError;
+ }
+ //
+ // Call Ikev2GenerateSaKeys to create SKEYID, SKEYID_d, SKEYID_a, SKEYID_e.
+ //
+ Status = Ikev2GenerateSaKeys (IkeSaSession, KeyPayload);
+ if (EFI_ERROR(Status)) {
+ goto CheckError;
+ }
+ return EFI_SUCCESS;
+
+CheckError:
+ if (NonceBuffer != NULL) {
+ FreePool (NonceBuffer);
+ }
+
+ return Status;
+}
+
+/**
+ Generates the IKEv2 packet for IKE_AUTH exchange.
+
+ @param[in] SaSession Pointer to IKEV2_SA_SESSION.
+ @param[in] Context Context data passed by caller.
+
+ @retval Pointer to IKE Packet to be sent out.
+
+**/
+IKE_PACKET *
+Ikev2AuthPskGenerator (
+ IN UINT8 *SaSession,
+ IN VOID *Context
+ )
+{
+ IKE_PACKET *IkePacket;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKE_PAYLOAD *IdPayload;
+ IKE_PAYLOAD *AuthPayload;
+ IKE_PAYLOAD *SaPayload;
+ IKE_PAYLOAD *TsiPayload;
+ IKE_PAYLOAD *TsrPayload;
+ IKE_PAYLOAD *NotifyPayload;
+ IKE_PAYLOAD *CpPayload;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+
+
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
+
+ IkePacket = NULL;
+ IdPayload = NULL;
+ AuthPayload = NULL;
+ SaPayload = NULL;
+ TsiPayload = NULL;
+ TsrPayload = NULL;
+ NotifyPayload = NULL;
+ CpPayload = NULL;
+ NotifyPayload = NULL;
+
+ //
+ // 1. Allocate IKE Packet
+ //
+ IkePacket= IkePacketAlloc ();
+ if (IkePacket == NULL) {
+ return NULL;
+ }
+
+ //
+ // 1.a Fill the IkePacket Header.
+ //
+ IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_AUTH;
+ IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
+ IkePacket->Header->Version = (UINT8)(2 << 4);
+ if (ChildSaSession->SessionCommon.IsInitiator) {
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_INIT;
+ } else {
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_RSP;
+ }
+
+ //
+ // According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should
+ // be always number 0 and 1;
+ //
+ IkePacket->Header->MessageId = 1;
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
+ } else {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
+ }
+
+ //
+ // 2. Generate ID Payload according to IP version and address.
+ //
+ IdPayload = Ikev2GenerateIdPayload (
+ &IkeSaSession->SessionCommon,
+ IKEV2_PAYLOAD_TYPE_AUTH
+ );
+ if (IdPayload == NULL) {
+ goto CheckError;
+ }
+
+ //
+ // 3. Generate Auth Payload
+ // If it is tunnel mode, should create the configuration payload after the
+ // Auth payload.
+ //
+ if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
+
+ AuthPayload = Ikev2PskGenerateAuthPayload (
+ ChildSaSession->IkeSaSession,
+ IdPayload,
+ IKEV2_PAYLOAD_TYPE_SA,
+ FALSE
+ );
+ } else {
+ AuthPayload = Ikev2PskGenerateAuthPayload (
+ ChildSaSession->IkeSaSession,
+ IdPayload,
+ IKEV2_PAYLOAD_TYPE_CP,
+ FALSE
+ );
+ if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) {
+ CpPayload = Ikev2GenerateCpPayload (
+ ChildSaSession->IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_SA,
+ IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS
+ );
+ } else {
+ CpPayload = Ikev2GenerateCpPayload (
+ ChildSaSession->IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_SA,
+ IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS
+ );
+ }
+
+ if (CpPayload == NULL) {
+ goto CheckError;
+ }
+ }
+
+ if (AuthPayload == NULL) {
+ goto CheckError;
+ }
+
+ //
+ // 4. Generate SA Payload according to the SA Data in ChildSaSession
+ //
+ SaPayload = Ikev2GenerateSaPayload (
+ ChildSaSession->SaData,
+ IKEV2_PAYLOAD_TYPE_TS_INIT,
+ IkeSessionTypeChildSa
+ );
+ if (SaPayload == NULL) {
+ goto CheckError;
+ }
+
+ if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
+ //
+ // Generate Tsi and Tsr.
+ //
+ TsiPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_TS_RSP,
+ FALSE
+ );
+
+ TsrPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_NOTIFY,
+ FALSE
+ );
+
+ //
+ // Generate Notify Payload. If transport mode, there should have Notify
+ // payload with TRANSPORT_MODE notification.
+ //
+ NotifyPayload = Ikev2GenerateNotifyPayload (
+ 0,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ 0,
+ IKEV2_NOTIFICATION_USE_TRANSPORT_MODE,
+ NULL,
+ NULL,
+ 0
+ );
+ if (NotifyPayload == NULL) {
+ goto CheckError;
+ }
+ } else {
+ //
+ // Generate Tsr for Tunnel mode.
+ //
+ TsiPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_TS_RSP,
+ TRUE
+ );
+ TsrPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ FALSE
+ );
+ }
+
+ if (TsiPayload == NULL || TsrPayload == NULL) {
+ goto CheckError;
+ }
+
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload);
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload);
+ if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload);
+ }
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload);
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload);
+ if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
+ }
+
+ return IkePacket;
+
+CheckError:
+ if (IkePacket != NULL) {
+ IkePacketFree (IkePacket);
+ }
+
+ if (IdPayload != NULL) {
+ IkePayloadFree (IdPayload);
+ }
+
+ if (AuthPayload != NULL) {
+ IkePayloadFree (AuthPayload);
+ }
+
+ if (CpPayload != NULL) {
+ IkePayloadFree (CpPayload);
+ }
+
+ if (SaPayload != NULL) {
+ IkePayloadFree (SaPayload);
+ }
+
+ if (TsiPayload != NULL) {
+ IkePayloadFree (TsiPayload);
+ }
+
+ if (TsrPayload != NULL) {
+ IkePayloadFree (TsrPayload);
+ }
+
+ if (NotifyPayload != NULL) {
+ IkePayloadFree (NotifyPayload);
+ }
+
+ return NULL;
+}
+
+/**
+ Parses IKE_AUTH packet.
+
+ @param[in] SaSession Pointer to the IKE_SA_SESSION related to this packet.
+ @param[in] IkePacket Pointer to the IKE_AUTH packet to be parsered.
+
+ @retval EFI_INVALID_PARAMETER The IKE packet is malformed or the SA
+ proposal is unacceptable.
+ @retval EFI_SUCCESS The IKE packet is acceptable and the
+ relative data is saved for furthure communication.
+
+**/
+EFI_STATUS
+Ikev2AuthPskParser (
+ IN UINT8 *SaSession,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKE_PAYLOAD *IkePayload;
+ IKE_PAYLOAD *SaPayload;
+ IKE_PAYLOAD *IdiPayload;
+ IKE_PAYLOAD *IdrPayload;
+ IKE_PAYLOAD *AuthPayload;
+ IKE_PAYLOAD *TsiPayload;
+ IKE_PAYLOAD *TsrPayload;
+ IKE_PAYLOAD *VerifiedAuthPayload;
+ LIST_ENTRY *Entry;
+ EFI_STATUS Status;
+
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
+
+ SaPayload = NULL;
+ IdiPayload = NULL;
+ IdrPayload = NULL;
+ AuthPayload = NULL;
+ TsiPayload = NULL;
+ TsrPayload = NULL;
+
+ //
+ // Iterate payloads to find the SaPayload/ID/AUTH/TS Payload.
+ //
+ NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) {
+ IdiPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) {
+ IdrPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {
+ SaPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) {
+ AuthPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {
+ TsiPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) {
+ TsrPayload = IkePayload;
+ }
+ }
+
+ if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) || (TsrPayload == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((IdiPayload == NULL) && (IdrPayload == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check IkePacket Header is match the state
+ //
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+
+ //
+ // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND
+ //
+ if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) ||
+ (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ } else {
+ //
+ // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT
+ //
+ if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) ||
+ (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // 2. Parse the SA payload and Key Payload and find out the perferable one
+ // and fill in the Sa paramse into CommonSession->SaParams and SaData into
+ // IkeSaSession for the responder SA payload generation.
+ //
+ }
+
+ //
+ // Verify the Auth Payload.
+ //
+ VerifiedAuthPayload = Ikev2PskGenerateAuthPayload (
+ IkeSaSession,
+ IkeSaSession->SessionCommon.IsInitiator ? IdrPayload : IdiPayload,
+ IKEV2_PAYLOAD_TYPE_SA,
+ TRUE
+ );
+ if ((VerifiedAuthPayload != NULL) &&
+ (0 != CompareMem (
+ VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
+ AuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
+ VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER)
+ ))) {
+ return EFI_INVALID_PARAMETER;
+ };
+
+ //
+ // 3. Parse the SA Payload to find out the cryptographic suite
+ // and fill in the Sa paramse into CommonSession->SaParams. If no acceptable
+ // porposal found, return EFI_INVALID_PARAMETER.
+ //
+ if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // 4. Parse TSi, TSr payloads.
+ //
+ if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId !=
+ ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) &&
+ (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) &&
+ (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IkeSaSession->SessionCommon.IsInitiator) {
+ //
+ //TODO:check the Port range. Only support any port and one certain port here.
+ //
+ ChildSaSession->ProtoId = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId;
+ ChildSaSession->LocalPort = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
+ ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
+ //
+ // Association a SPD with this SA.
+ //
+ Status = Ikev2ChildSaAssociateSpdEntry (ChildSaSession);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Associate the IkeSaSession's SPD to the first ChildSaSession's SPD.
+ //
+ if (ChildSaSession->IkeSaSession->Spd == NULL) {
+ ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd;
+ Status = Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ } else {
+ //
+ //TODO:check the Port range.
+ //
+ if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
+ (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
+ (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector.
+ //
+ if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
+ if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) {
+ //
+ // If it is tunnel mode, the UEFI part must be the initiator.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Get the Virtual IP address from the Tsi traffic selector.
+ // TODO: check the CFG reply payload
+ //
+ CopyMem (
+ &ChildSaSession->SpdSelector->LocalAddress[0].Address,
+ TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR),
+ (ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ?
+ sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS)
+ );
+ }
+ }
+
+ //
+ // 5. Generate keymats for IPsec protocol.
+ //
+ Status = Ikev2GenerateChildSaKeys (ChildSaSession, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ //
+ // 6. Change the state of IkeSaSession
+ //
+ IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished);
+ IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Gernerates IKEv2 packet for IKE_SA_INIT exchange.
+
+ @param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange.
+ @param[in] Context Context Data passed by caller.
+
+ @retval EFI_SUCCESS The IKE packet generation succeeded.
+ @retval Others The IKE packet generation failed.
+
+**/
+IKE_PACKET*
+Ikev2InitCertGenerator (
+ IN UINT8 *SaSession,
+ IN VOID *Context
+ )
+{
+ IKE_PACKET *IkePacket;
+ IKE_PAYLOAD *CertReqPayload;
+ LIST_ENTRY *Node;
+ IKE_PAYLOAD *NoncePayload;
+
+ if (!FeaturePcdGet (PcdIpsecCertificateEnabled)) {
+ return NULL;
+ }
+
+ //
+ // The first two messages exchange is same between PSK and Cert.
+ //
+ IkePacket = Ikev2InitPskGenerator (SaSession, Context);
+
+ if ((IkePacket != NULL) && (!((IKEV2_SA_SESSION *)SaSession)->SessionCommon.IsInitiator)) {
+ //
+ // Add the Certification Request Payload
+ //
+ CertReqPayload = Ikev2GenerateCertificatePayload (
+ (IKEV2_SA_SESSION *)SaSession,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ (UINT8*)PcdGetPtr(PcdIpsecUefiCaFile),
+ PcdGet32(PcdIpsecUefiCaFileSize),
+ IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT,
+ TRUE
+ );
+ //
+ // Change Nonce Payload Next payload type.
+ //
+ IKE_PACKET_END_PAYLOAD (IkePacket, Node);
+ NoncePayload = IKE_PAYLOAD_BY_PACKET (Node);
+ ((IKEV2_NONCE *)NoncePayload->PayloadBuf)->Header.NextPayload = IKEV2_PAYLOAD_TYPE_CERTREQ;
+
+ //
+ // Add Certification Request Payload
+ //
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload);
+ }
+
+ return IkePacket;
+}
+
+/**
+ Parses the IKEv2 packet for IKE_SA_INIT exchange.
+
+ @param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange.
+ @param[in] IkePacket The received IKEv2 packet to be parsed.
+
+ @retval EFI_SUCCESS The IKEv2 packet is acceptable and the relative data is
+ saved for furthure communication.
+ @retval EFI_INVALID_PARAMETER The IKE packet is malformed or the SA proposal is unacceptable.
+ @retval EFI_UNSUPPORTED The certificate authentication is not supported.
+
+**/
+EFI_STATUS
+Ikev2InitCertParser (
+ IN UINT8 *SaSession,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ if (!FeaturePcdGet (PcdIpsecCertificateEnabled)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // The first two messages exchange is same between PSK and Cert.
+ // Todo: Parse Certificate Request from responder Initial Exchange.
+ //
+ return Ikev2InitPskParser (SaSession, IkePacket);
+}
+
+/**
+ Generates the IKEv2 packet for IKE_AUTH exchange.
+
+ @param[in] SaSession Pointer to IKEV2_SA_SESSION.
+ @param[in] Context Context data passed by caller.
+
+ @retval Pointer to IKEv2 Packet to be sent out.
+
+**/
+IKE_PACKET *
+Ikev2AuthCertGenerator (
+ IN UINT8 *SaSession,
+ IN VOID *Context
+ )
+{
+ IKE_PACKET *IkePacket;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKE_PAYLOAD *IdPayload;
+ IKE_PAYLOAD *AuthPayload;
+ IKE_PAYLOAD *SaPayload;
+ IKE_PAYLOAD *TsiPayload;
+ IKE_PAYLOAD *TsrPayload;
+ IKE_PAYLOAD *NotifyPayload;
+ IKE_PAYLOAD *CpPayload;
+ IKE_PAYLOAD *CertPayload;
+ IKE_PAYLOAD *CertReqPayload;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+
+ if (!FeaturePcdGet (PcdIpsecCertificateEnabled)) {
+ return NULL;
+ }
+
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
+
+ IkePacket = NULL;
+ IdPayload = NULL;
+ AuthPayload = NULL;
+ CpPayload = NULL;
+ SaPayload = NULL;
+ TsiPayload = NULL;
+ TsrPayload = NULL;
+ NotifyPayload = NULL;
+ CertPayload = NULL;
+ CertReqPayload = NULL;
+
+ //
+ // 1. Allocate IKE Packet
+ //
+ IkePacket= IkePacketAlloc ();
+ if (IkePacket == NULL) {
+ return NULL;
+ }
+
+ //
+ // 1.a Fill the IkePacket Header.
+ //
+ IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_AUTH;
+ IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
+ IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
+ IkePacket->Header->Version = (UINT8)(2 << 4);
+ if (ChildSaSession->SessionCommon.IsInitiator) {
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_INIT;
+ } else {
+ IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_RSP;
+ }
+
+ //
+ // According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should
+ // be always number 0 and 1;
+ //
+ IkePacket->Header->MessageId = 1;
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
+ } else {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
+ }
+
+ //
+ // 2. Generate ID Payload according to IP version and address.
+ //
+ IdPayload = Ikev2GenerateCertIdPayload (
+ &IkeSaSession->SessionCommon,
+ IKEV2_PAYLOAD_TYPE_CERT,
+ (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificate),
+ PcdGet32 (PcdIpsecUefiCertificateSize)
+ );
+ if (IdPayload == NULL) {
+ goto CheckError;
+ }
+
+ //
+ // 3. Generate Certificate Payload
+ //
+ CertPayload = Ikev2GenerateCertificatePayload (
+ IkeSaSession,
+ (UINT8)(IkeSaSession->SessionCommon.IsInitiator ? IKEV2_PAYLOAD_TYPE_CERTREQ : IKEV2_PAYLOAD_TYPE_AUTH),
+ (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificate),
+ PcdGet32 (PcdIpsecUefiCertificateSize),
+ IKEV2_CERT_ENCODEING_X509_CERT_SIGN,
+ FALSE
+ );
+ if (CertPayload == NULL) {
+ goto CheckError;
+ }
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ CertReqPayload = Ikev2GenerateCertificatePayload (
+ IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_AUTH,
+ (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificate),
+ PcdGet32 (PcdIpsecUefiCertificateSize),
+ IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT,
+ TRUE
+ );
+ if (CertReqPayload == NULL) {
+ goto CheckError;
+ }
+ }
+
+ //
+ // 4. Generate Auth Payload
+ // If it is tunnel mode, should create the configuration payload after the
+ // Auth payload.
+ //
+ if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
+ AuthPayload = Ikev2CertGenerateAuthPayload (
+ ChildSaSession->IkeSaSession,
+ IdPayload,
+ IKEV2_PAYLOAD_TYPE_SA,
+ FALSE,
+ (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificateKey),
+ PcdGet32 (PcdIpsecUefiCertificateKeySize),
+ ChildSaSession->IkeSaSession->Pad->Data->AuthData,
+ ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize
+ );
+ } else {
+ AuthPayload = Ikev2CertGenerateAuthPayload (
+ ChildSaSession->IkeSaSession,
+ IdPayload,
+ IKEV2_PAYLOAD_TYPE_CP,
+ FALSE,
+ (UINT8 *)PcdGetPtr (PcdIpsecUefiCertificateKey),
+ PcdGet32 (PcdIpsecUefiCertificateKeySize),
+ ChildSaSession->IkeSaSession->Pad->Data->AuthData,
+ ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize
+ );
+ if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) {
+ CpPayload = Ikev2GenerateCpPayload (
+ ChildSaSession->IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_SA,
+ IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS
+ );
+ } else {
+ CpPayload = Ikev2GenerateCpPayload (
+ ChildSaSession->IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_SA,
+ IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS
+ );
+ }
+
+ if (CpPayload == NULL) {
+ goto CheckError;
+ }
+ }
+
+ if (AuthPayload == NULL) {
+ goto CheckError;
+ }
+
+ //
+ // 5. Generate SA Payload according to the Sa Data in ChildSaSession
+ //
+ SaPayload = Ikev2GenerateSaPayload (
+ ChildSaSession->SaData,
+ IKEV2_PAYLOAD_TYPE_TS_INIT,
+ IkeSessionTypeChildSa
+ );
+ if (SaPayload == NULL) {
+ goto CheckError;
+ }
+
+ if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
+ //
+ // Generate Tsi and Tsr.
+ //
+ TsiPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_TS_RSP,
+ FALSE
+ );
+
+ TsrPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_NOTIFY,
+ FALSE
+ );
+
+ //
+ // Generate Notify Payload. If transport mode, there should have Notify
+ // payload with TRANSPORT_MODE notification.
+ //
+ NotifyPayload = Ikev2GenerateNotifyPayload (
+ 0,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ 0,
+ IKEV2_NOTIFICATION_USE_TRANSPORT_MODE,
+ NULL,
+ NULL,
+ 0
+ );
+ if (NotifyPayload == NULL) {
+ goto CheckError;
+ }
+ } else {
+ //
+ // Generate Tsr for Tunnel mode.
+ //
+ TsiPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_TS_RSP,
+ TRUE
+ );
+ TsrPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ FALSE
+ );
+ }
+
+ if (TsiPayload == NULL || TsrPayload == NULL) {
+ goto CheckError;
+ }
+
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload);
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertPayload);
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload);
+ }
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload);
+ if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload);
+ }
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload);
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload);
+ if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
+ IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
+ }
+
+ return IkePacket;
+
+CheckError:
+ if (IkePacket != NULL) {
+ IkePacketFree (IkePacket);
+ }
+
+ if (IdPayload != NULL) {
+ IkePayloadFree (IdPayload);
+ }
+
+ if (CertPayload != NULL) {
+ IkePayloadFree (CertPayload);
+ }
+
+ if (CertReqPayload != NULL) {
+ IkePayloadFree (CertReqPayload);
+ }
+
+ if (AuthPayload != NULL) {
+ IkePayloadFree (AuthPayload);
+ }
+
+ if (CpPayload != NULL) {
+ IkePayloadFree (CpPayload);
+ }
+
+ if (SaPayload != NULL) {
+ IkePayloadFree (SaPayload);
+ }
+
+ if (TsiPayload != NULL) {
+ IkePayloadFree (TsiPayload);
+ }
+
+ if (TsrPayload != NULL) {
+ IkePayloadFree (TsrPayload);
+ }
+
+ if (NotifyPayload != NULL) {
+ IkePayloadFree (NotifyPayload);
+ }
+
+ return NULL;
+}
+
+/**
+ Parses IKE_AUTH packet.
+
+ @param[in] SaSession Pointer to the IKE_SA_SESSION related to this packet.
+ @param[in] IkePacket Pointer to the IKE_AUTH packet to be parsered.
+
+ @retval EFI_INVALID_PARAMETER The IKEv2 packet is malformed or the SA
+ proposal is unacceptable.
+ @retval EFI_SUCCESS The IKE packet is acceptable and the
+ relative data is saved for furthure communication.
+ @retval EFI_UNSUPPORTED The certificate authentication is not supported.
+
+**/
+EFI_STATUS
+Ikev2AuthCertParser (
+ IN UINT8 *SaSession,
+ IN IKE_PACKET *IkePacket
+ )
+{
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKE_PAYLOAD *IkePayload;
+ IKE_PAYLOAD *SaPayload;
+ IKE_PAYLOAD *IdiPayload;
+ IKE_PAYLOAD *IdrPayload;
+ IKE_PAYLOAD *AuthPayload;
+ IKE_PAYLOAD *TsiPayload;
+ IKE_PAYLOAD *TsrPayload;
+ IKE_PAYLOAD *CertPayload;
+ IKE_PAYLOAD *VerifiedAuthPayload;
+ LIST_ENTRY *Entry;
+ EFI_STATUS Status;
+
+ if (!FeaturePcdGet (PcdIpsecCertificateEnabled)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
+
+ SaPayload = NULL;
+ IdiPayload = NULL;
+ IdrPayload = NULL;
+ AuthPayload = NULL;
+ TsiPayload = NULL;
+ TsrPayload = NULL;
+ CertPayload = NULL;
+ VerifiedAuthPayload = NULL;
+ Status = EFI_INVALID_PARAMETER;
+
+ //
+ // Iterate payloads to find the SaPayload/ID/AUTH/TS Payload.
+ //
+ NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) {
+ IdiPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) {
+ IdrPayload = IkePayload;
+ }
+
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {
+ SaPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) {
+ AuthPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {
+ TsiPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) {
+ TsrPayload = IkePayload;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERT) {
+ CertPayload = IkePayload;
+ }
+ }
+
+ if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) ||
+ (TsrPayload == NULL) || (CertPayload == NULL)) {
+ goto Exit;
+ }
+ if ((IdiPayload == NULL) && (IdrPayload == NULL)) {
+ goto Exit;
+ }
+
+ //
+ // Check IkePacket Header is match the state
+ //
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+
+ //
+ // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND
+ //
+ if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) ||
+ (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) {
+ goto Exit;
+ }
+ } else {
+ //
+ // 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT
+ //
+ if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) ||
+ (IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) {
+ goto Exit;
+ }
+ }
+
+ //
+ // Verify the Auth Payload.
+ //
+ VerifiedAuthPayload = Ikev2CertGenerateAuthPayload (
+ IkeSaSession,
+ IkeSaSession->SessionCommon.IsInitiator ? IdrPayload:IdiPayload,
+ IKEV2_PAYLOAD_TYPE_SA,
+ TRUE,
+ NULL,
+ 0,
+ NULL,
+ 0
+ );
+
+ if ((VerifiedAuthPayload != NULL) &&
+ (!IpSecCryptoIoVerifySignDataByCertificate (
+ CertPayload->PayloadBuf + sizeof (IKEV2_CERT),
+ CertPayload->PayloadSize - sizeof (IKEV2_CERT),
+ (UINT8 *)PcdGetPtr (PcdIpsecUefiCaFile),
+ PcdGet32 (PcdIpsecUefiCaFileSize),
+ VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_AUTH),
+ VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_AUTH),
+ AuthPayload->PayloadBuf + sizeof (IKEV2_AUTH),
+ AuthPayload->PayloadSize - sizeof (IKEV2_AUTH)
+ ))) {
+ goto Exit;
+ }
+
+ //
+ // 3. Parse the SA Payload to find out the cryptographic suite
+ // and fill in the SA paramse into CommonSession->SaParams. If no acceptable
+ // porposal found, return EFI_INVALID_PARAMETER.
+ //
+ if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) {
+ goto Exit;
+ }
+
+ //
+ // 4. Parse TSi, TSr payloads.
+ //
+ if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId !=
+ ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) &&
+ (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) &&
+ (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0)
+ ) {
+ goto Exit;
+ }
+
+ if (!IkeSaSession->SessionCommon.IsInitiator) {
+ //
+ //Todo:check the Port range. Only support any port and one certain port here.
+ //
+ ChildSaSession->ProtoId = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId;
+ ChildSaSession->LocalPort = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
+ ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
+ //
+ // Association a SPD with this SA.
+ //
+ if (EFI_ERROR (Ikev2ChildSaAssociateSpdEntry (ChildSaSession))) {
+ goto Exit;
+ }
+ //
+ // Associate the IkeSaSession's SPD to the first ChildSaSession's SPD.
+ //
+ if (ChildSaSession->IkeSaSession->Spd == NULL) {
+ ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd;
+ Status = Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+ } else {
+ //
+ // Todo:check the Port range.
+ //
+ if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
+ (((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort)
+ ) {
+ goto Exit;
+ }
+ if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
+ (((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort)
+ ) {
+ goto Exit;
+ }
+ //
+ // For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector.
+ //
+ if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
+ if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) {
+ //
+ // If it is tunnel mode, the UEFI part must be the initiator.
+ //
+ goto Exit;
+ }
+ //
+ // Get the Virtual IP address from the Tsi traffic selector.
+ // TODO: check the CFG reply payload
+ //
+ CopyMem (
+ &ChildSaSession->SpdSelector->LocalAddress[0].Address,
+ TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR),
+ (ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ?
+ sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS)
+ );
+ }
+ }
+
+ //
+ // 5. Generat keymats for IPsec protocol.
+ //
+ Status = Ikev2GenerateChildSaKeys (ChildSaSession, NULL);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ //
+ // 6. Change the state of IkeSaSession
+ //
+ IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished);
+ IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished;
+ }
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ if (VerifiedAuthPayload != NULL) {
+ IkePayloadFree (VerifiedAuthPayload);
+ }
+ return Status;
+}
+
+/**
+ Generates the DH Public Key.
+
+ This generates the DH local public key and store it in the IKE SA Session's GxBuffer.
+
+ @param[in] IkeSaSession Pointer to related IKE SA Session.
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval Others The operation failed.
+
+**/
+EFI_STATUS
+Ikev2GenerateSaDhPublicKey (
+ IN IKEV2_SA_SESSION *IkeSaSession
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_SESSION_KEYS *IkeKeys;
+
+ IkeSaSession->IkeKeys = AllocateZeroPool (sizeof (IKEV2_SESSION_KEYS));
+ if (IkeSaSession->IkeKeys == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IkeKeys = IkeSaSession->IkeKeys;
+ IkeKeys->DhBuffer = AllocateZeroPool (sizeof (IKEV2_DH_BUFFER));
+ if (IkeKeys->DhBuffer == NULL) {
+ FreePool (IkeSaSession->IkeKeys);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Init DH with the certain DH Group Description.
+ //
+ IkeKeys->DhBuffer->GxSize = OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size >> 3;
+ IkeKeys->DhBuffer->GxBuffer = AllocateZeroPool (IkeKeys->DhBuffer->GxSize);
+ if (IkeKeys->DhBuffer->GxBuffer == NULL) {
+ FreePool (IkeKeys->DhBuffer);
+ FreePool (IkeSaSession->IkeKeys);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get X PublicKey
+ //
+ Status = IpSecCryptoIoDhGetPublicKey (
+ &IkeKeys->DhBuffer->DhContext,
+ OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].GroupGenerator,
+ OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size,
+ OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Modulus,
+ IkeKeys->DhBuffer->GxBuffer,
+ &IkeKeys->DhBuffer->GxSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam X public key error Status = %r\n", Status));
+
+ FreePool (IkeKeys->DhBuffer->GxBuffer);
+
+ FreePool (IkeKeys->DhBuffer);
+
+ FreePool (IkeSaSession->IkeKeys);
+
+ return Status;
+ }
+
+ IPSEC_DUMP_BUF ("DH Public Key (g^x) Dump", IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Computes the DH Shared/Exchange Key.
+
+ Given peer's public key, this function computes the exchanged common key and
+ stores it in the IKEv2 SA Session's GxyBuffer.
+
+ @param[in] DhBuffer Pointer to buffer of peer's puliic key.
+ @param[in] KePayload Pointer to received key payload.
+
+ @retval EFI_SUCCESS The operation succeeded.
+ @retval Otherwise The operation failed.
+
+**/
+EFI_STATUS
+Ikev2GenerateSaDhComputeKey (
+ IN IKEV2_DH_BUFFER *DhBuffer,
+ IN IKE_PAYLOAD *KePayload
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_KEY_EXCHANGE *Ke;
+ UINT8 *PubKey;
+ UINTN PubKeySize;
+
+ Ke = (IKEV2_KEY_EXCHANGE *) KePayload->PayloadBuf;
+ PubKey = (UINT8 *) (Ke + 1);
+ PubKeySize = KePayload->PayloadSize - sizeof (IKEV2_KEY_EXCHANGE);
+ DhBuffer->GxySize = DhBuffer->GxSize;
+ DhBuffer->GxyBuffer = AllocateZeroPool (DhBuffer->GxySize);
+ if (DhBuffer->GxyBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get GxyBuf
+ //
+ Status = IpSecCryptoIoDhComputeKey (
+ DhBuffer->DhContext,
+ PubKey,
+ PubKeySize,
+ DhBuffer->GxyBuffer,
+ &DhBuffer->GxySize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam Y session key error Status = %r\n", Status));
+
+ FreePool (DhBuffer->GxyBuffer);
+
+ return Status;
+ }
+
+ //
+ // Create GxyBuf.
+ //
+ DhBuffer->GySize = PubKeySize;
+ DhBuffer->GyBuffer = AllocateZeroPool (DhBuffer->GySize);
+ if (DhBuffer->GyBuffer == NULL) {
+ FreePool (DhBuffer->GxyBuffer);
+
+ return Status;
+ }
+
+ CopyMem (DhBuffer->GyBuffer, PubKey, DhBuffer->GySize);
+
+ IPSEC_DUMP_BUF ("DH Public Key (g^y) Dump", DhBuffer->GyBuffer, DhBuffer->GySize);
+ IPSEC_DUMP_BUF ("DH Shared Key (g^xy) Dump", DhBuffer->GxyBuffer, DhBuffer->GxySize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generates the IKE SKEYSEED and seven other secrets. SK_d, SK_ai, SK_ar, SK_ei, SK_er,
+ SK_pi, SK_pr are keys for the furthure IKE exchange.
+
+ @param[in] IkeSaSession Pointer to IKE SA Session.
+ @param[in] KePayload Pointer to Key payload used to generate the Key.
+
+ @retval EFI_UNSUPPORTED If one or more Algorithm Id is not supported.
+ @retval EFI_OUT_OF_RESOURCES If there is no enough resource to be allocated to
+ meet the requirement.
+ @retval EFI_SUCCESS The operation succeeded.
+
+**/
+EFI_STATUS
+Ikev2GenerateSaKeys (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_PAYLOAD *KePayload
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_SA_PARAMS *SaParams;
+ PRF_DATA_FRAGMENT Fragments[4];
+ UINT64 InitiatorCookieNet;
+ UINT64 ResponderCookieNet;
+ UINT8 *KeyBuffer;
+ UINTN KeyBufferSize;
+ UINTN AuthAlgKeyLen;
+ UINTN EncryptAlgKeyLen;
+ UINTN IntegrityAlgKeyLen;
+ UINTN PrfAlgKeyLen;
+ UINT8 *OutputKey;
+ UINTN OutputKeyLength;
+ UINT8 *Digest;
+ UINTN DigestSize;
+
+ Digest = NULL;
+ OutputKey = NULL;
+ KeyBuffer = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Generate Gxy
+ //
+ Status = Ikev2GenerateSaDhComputeKey (IkeSaSession->IkeKeys->DhBuffer, KePayload);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Get the key length of Authenticaion, Encryption, PRF, and Integrity.
+ //
+ SaParams = IkeSaSession->SessionCommon.SaParams;
+ AuthAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);
+ EncryptAlgKeyLen = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId);
+ IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId);
+ PrfAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);
+
+ //
+ // If one or more algorithm is not support, return EFI_UNSUPPORTED.
+ //
+ if (AuthAlgKeyLen == 0 ||
+ EncryptAlgKeyLen == 0 ||
+ IntegrityAlgKeyLen == 0 ||
+ PrfAlgKeyLen == 0
+ ) {
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ //
+ // Compute SKEYSEED = prf(Ni | Nr, g^ir)
+ //
+ KeyBufferSize = IkeSaSession->NiBlkSize + IkeSaSession->NrBlkSize;
+ KeyBuffer = AllocateZeroPool (KeyBufferSize);
+ if (KeyBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (KeyBuffer, IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);
+ CopyMem (KeyBuffer + IkeSaSession->NiBlkSize, IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);
+
+ Fragments[0].Data = IkeSaSession->IkeKeys->DhBuffer->GxyBuffer;
+ Fragments[0].DataSize = IkeSaSession->IkeKeys->DhBuffer->GxySize;
+
+ DigestSize = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);
+ Digest = AllocateZeroPool (DigestSize);
+
+ if (Digest == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ IpSecCryptoIoHmac (
+ (UINT8)SaParams->Prf,
+ KeyBuffer,
+ KeyBufferSize,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ 1,
+ Digest,
+ DigestSize
+ );
+
+ //
+ // {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = prf+
+ // (SKEYSEED, Ni | Nr | SPIi | SPIr )
+ //
+ Fragments[0].Data = IkeSaSession->NiBlock;
+ Fragments[0].DataSize = IkeSaSession->NiBlkSize;
+ Fragments[1].Data = IkeSaSession->NrBlock;
+ Fragments[1].DataSize = IkeSaSession->NrBlkSize;
+ InitiatorCookieNet = HTONLL (IkeSaSession->InitiatorCookie);
+ ResponderCookieNet = HTONLL (IkeSaSession->ResponderCookie);
+ Fragments[2].Data = (UINT8 *)(&InitiatorCookieNet);
+ Fragments[2].DataSize = sizeof (IkeSaSession->InitiatorCookie);
+ Fragments[3].Data = (UINT8 *)(&ResponderCookieNet);
+ Fragments[3].DataSize = sizeof (IkeSaSession->ResponderCookie);
+
+ IPSEC_DUMP_BUF (">>> NiBlock", IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);
+ IPSEC_DUMP_BUF (">>> NrBlock", IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);
+ IPSEC_DUMP_BUF (">>> InitiatorCookie", (UINT8 *)&IkeSaSession->InitiatorCookie, sizeof(UINT64));
+ IPSEC_DUMP_BUF (">>> ResponderCookie", (UINT8 *)&IkeSaSession->ResponderCookie, sizeof(UINT64));
+
+ OutputKeyLength = PrfAlgKeyLen +
+ 2 * EncryptAlgKeyLen +
+ 2 * AuthAlgKeyLen +
+ 2 * IntegrityAlgKeyLen;
+ OutputKey = AllocateZeroPool (OutputKeyLength);
+ if (OutputKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Generate Seven Keymates.
+ //
+ Status = Ikev2SaGenerateKey (
+ (UINT8)SaParams->Prf,
+ Digest,
+ DigestSize,
+ OutputKey,
+ OutputKeyLength,
+ Fragments,
+ 4
+ );
+ if (EFI_ERROR(Status)) {
+ goto Exit;
+ }
+
+ //
+ // Save the seven keys into KeySession.
+ // First, SK_d
+ //
+ IkeSaSession->IkeKeys->SkdKey = AllocateZeroPool (PrfAlgKeyLen);
+ if (IkeSaSession->IkeKeys->SkdKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ IkeSaSession->IkeKeys->SkdKeySize = PrfAlgKeyLen;
+ CopyMem (IkeSaSession->IkeKeys->SkdKey, OutputKey, PrfAlgKeyLen);
+
+ IPSEC_DUMP_BUF (">>> SK_D Key", IkeSaSession->IkeKeys->SkdKey, PrfAlgKeyLen);
+
+ //
+ // Second, Sk_ai
+ //
+ IkeSaSession->IkeKeys->SkAiKey = AllocateZeroPool (IntegrityAlgKeyLen);
+ if (IkeSaSession->IkeKeys->SkAiKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ IkeSaSession->IkeKeys->SkAiKeySize = IntegrityAlgKeyLen;
+ CopyMem (IkeSaSession->IkeKeys->SkAiKey, OutputKey + PrfAlgKeyLen, IntegrityAlgKeyLen);
+
+ IPSEC_DUMP_BUF (">>> SK_Ai Key", IkeSaSession->IkeKeys->SkAiKey, IkeSaSession->IkeKeys->SkAiKeySize);
+
+ //
+ // Third, Sk_ar
+ //
+ IkeSaSession->IkeKeys->SkArKey = AllocateZeroPool (IntegrityAlgKeyLen);
+ if (IkeSaSession->IkeKeys->SkArKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ IkeSaSession->IkeKeys->SkArKeySize = IntegrityAlgKeyLen;
+ CopyMem (
+ IkeSaSession->IkeKeys->SkArKey,
+ OutputKey + PrfAlgKeyLen + IntegrityAlgKeyLen,
+ IntegrityAlgKeyLen
+ );
+
+ IPSEC_DUMP_BUF (">>> SK_Ar Key", IkeSaSession->IkeKeys->SkArKey, IkeSaSession->IkeKeys->SkArKeySize);
+
+ //
+ // Fourth, Sk_ei
+ //
+ IkeSaSession->IkeKeys->SkEiKey = AllocateZeroPool (EncryptAlgKeyLen);
+ if (IkeSaSession->IkeKeys->SkEiKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ IkeSaSession->IkeKeys->SkEiKeySize = EncryptAlgKeyLen;
+
+ CopyMem (
+ IkeSaSession->IkeKeys->SkEiKey,
+ OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen,
+ EncryptAlgKeyLen
+ );
+ IPSEC_DUMP_BUF (
+ ">>> SK_Ei Key",
+ OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen,
+ EncryptAlgKeyLen
+ );
+
+ //
+ // Fifth, Sk_er
+ //
+ IkeSaSession->IkeKeys->SkErKey = AllocateZeroPool (EncryptAlgKeyLen);
+ if (IkeSaSession->IkeKeys->SkErKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ IkeSaSession->IkeKeys->SkErKeySize = EncryptAlgKeyLen;
+
+ CopyMem (
+ IkeSaSession->IkeKeys->SkErKey,
+ OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen,
+ EncryptAlgKeyLen
+ );
+ IPSEC_DUMP_BUF (
+ ">>> SK_Er Key",
+ OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen,
+ EncryptAlgKeyLen
+ );
+
+ //
+ // Sixth, Sk_pi
+ //
+ IkeSaSession->IkeKeys->SkPiKey = AllocateZeroPool (AuthAlgKeyLen);
+ if (IkeSaSession->IkeKeys->SkPiKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ IkeSaSession->IkeKeys->SkPiKeySize = AuthAlgKeyLen;
+
+ CopyMem (
+ IkeSaSession->IkeKeys->SkPiKey,
+ OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen,
+ AuthAlgKeyLen
+ );
+ IPSEC_DUMP_BUF (
+ ">>> SK_Pi Key",
+ OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen,
+ AuthAlgKeyLen
+ );
+
+ //
+ // Seventh, Sk_pr
+ //
+ IkeSaSession->IkeKeys->SkPrKey = AllocateZeroPool (AuthAlgKeyLen);
+ if (IkeSaSession->IkeKeys->SkPrKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+ IkeSaSession->IkeKeys->SkPrKeySize = AuthAlgKeyLen;
+
+ CopyMem (
+ IkeSaSession->IkeKeys->SkPrKey,
+ OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen,
+ AuthAlgKeyLen
+ );
+ IPSEC_DUMP_BUF (
+ ">>> SK_Pr Key",
+ OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen,
+ AuthAlgKeyLen
+ );
+
+
+Exit:
+ if (Digest != NULL) {
+ FreePool (Digest);
+ }
+ if (KeyBuffer != NULL) {
+ FreePool (KeyBuffer);
+ }
+ if (OutputKey != NULL) {
+ FreePool (OutputKey);
+ }
+
+ if (EFI_ERROR(Status)) {
+ if (IkeSaSession->IkeKeys->SkdKey != NULL) {
+ FreePool (IkeSaSession->IkeKeys->SkdKey);
+ }
+ if (IkeSaSession->IkeKeys->SkAiKey != NULL) {
+ FreePool (IkeSaSession->IkeKeys->SkAiKey);
+ }
+ if (IkeSaSession->IkeKeys->SkArKey != NULL) {
+ FreePool (IkeSaSession->IkeKeys->SkArKey);
+ }
+ if (IkeSaSession->IkeKeys->SkEiKey != NULL) {
+ FreePool (IkeSaSession->IkeKeys->SkEiKey);
+ }
+ if (IkeSaSession->IkeKeys->SkErKey != NULL) {
+ FreePool (IkeSaSession->IkeKeys->SkErKey);
+ }
+ if (IkeSaSession->IkeKeys->SkPiKey != NULL) {
+ FreePool (IkeSaSession->IkeKeys->SkPiKey);
+ }
+ if (IkeSaSession->IkeKeys->SkPrKey != NULL) {
+ FreePool (IkeSaSession->IkeKeys->SkPrKey);
+ }
+ }
+
+
+ return Status;
+}
+
+/**
+ Generates the Keys for the furthure IPsec Protocol.
+
+ @param[in] ChildSaSession Pointer to IKE Child SA Session.
+ @param[in] KePayload Pointer to Key payload used to generate the Key.
+
+ @retval EFI_UNSUPPORTED If one or more Algorithm Id is not supported.
+ @retval EFI_SUCCESS The operation succeeded.
+
+**/
+EFI_STATUS
+Ikev2GenerateChildSaKeys (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession,
+ IN IKE_PAYLOAD *KePayload
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_SA_PARAMS *SaParams;
+ PRF_DATA_FRAGMENT Fragments[3];
+ UINTN EncryptAlgKeyLen;
+ UINTN IntegrityAlgKeyLen;
+ UINT8* OutputKey;
+ UINTN OutputKeyLength;
+
+ Status = EFI_SUCCESS;
+ OutputKey = NULL;
+
+ if (KePayload != NULL) {
+ //
+ // Generate Gxy
+ //
+ Status = Ikev2GenerateSaDhComputeKey (ChildSaSession->DhBuffer, KePayload);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Fragments[0].Data = ChildSaSession->DhBuffer->GxyBuffer;
+ Fragments[0].DataSize = ChildSaSession->DhBuffer->GxySize;
+ }
+
+ Fragments[1].Data = ChildSaSession->NiBlock;
+ Fragments[1].DataSize = ChildSaSession->NiBlkSize;
+ Fragments[2].Data = ChildSaSession->NrBlock;
+ Fragments[2].DataSize = ChildSaSession->NrBlkSize;
+
+ //
+ // Get the key length of Authenticaion, Encryption, PRF, and Integrity.
+ //
+ SaParams = ChildSaSession->SessionCommon.SaParams;
+ EncryptAlgKeyLen = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId);
+ IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId);
+ OutputKeyLength = 2 * EncryptAlgKeyLen + 2 * IntegrityAlgKeyLen;
+
+ if ((EncryptAlgKeyLen == 0) || (IntegrityAlgKeyLen == 0)) {
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ //
+ //
+ // If KePayload is not NULL, calculate KEYMAT = prf+(SK_d, g^ir (new) | Ni | Nr ),
+ // otherwise, KEYMAT = prf+(SK_d, Ni | Nr )
+ //
+ OutputKey = AllocateZeroPool (OutputKeyLength);
+ if (OutputKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Derive Key from the SkdKey Buffer.
+ //
+ Status = Ikev2SaGenerateKey (
+ (UINT8)ChildSaSession->IkeSaSession->SessionCommon.SaParams->Prf,
+ ChildSaSession->IkeSaSession->IkeKeys->SkdKey,
+ ChildSaSession->IkeSaSession->IkeKeys->SkdKeySize,
+ OutputKey,
+ OutputKeyLength,
+ KePayload == NULL ? &Fragments[1] : Fragments,
+ KePayload == NULL ? 2 : 3
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Copy KEYMATE (SK_ENCRYPT_i | SK_ENCRYPT_r | SK_INTEG_i | SK_INTEG_r) to
+ // ChildKeyMates.
+ //
+ if (!ChildSaSession->SessionCommon.IsInitiator) {
+
+ //
+ // Initiator Encryption Key
+ //
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId;
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen);
+ if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,
+ OutputKey,
+ EncryptAlgKeyLen
+ );
+
+ //
+ // Initiator Authentication Key
+ //
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId;
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen);
+ if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,
+ OutputKey + EncryptAlgKeyLen,
+ IntegrityAlgKeyLen
+ );
+
+ //
+ // Responder Encrypt Key
+ //
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId;
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen);
+ if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,
+ OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen,
+ EncryptAlgKeyLen
+ );
+
+ //
+ // Responder Authentication Key
+ //
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId;
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen);
+ if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,
+ OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen,
+ IntegrityAlgKeyLen
+ );
+ } else {
+ //
+ // Initiator Encryption Key
+ //
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId;
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen);
+ if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,
+ OutputKey,
+ EncryptAlgKeyLen
+ );
+
+ //
+ // Initiator Authentication Key
+ //
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId;
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen);
+ if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,
+ OutputKey + EncryptAlgKeyLen,
+ IntegrityAlgKeyLen
+ );
+
+ //
+ // Responder Encryption Key
+ //
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId;
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen);
+ if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,
+ OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen,
+ EncryptAlgKeyLen
+ );
+
+ //
+ // Responder Authentication Key
+ //
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId;
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen);
+ if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ CopyMem (
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,
+ OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen,
+ IntegrityAlgKeyLen
+ );
+ }
+
+ IPSEC_DUMP_BUF (
+ " >>> Local Encryption Key",
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,
+ EncryptAlgKeyLen
+ );
+ IPSEC_DUMP_BUF (
+ " >>> Remote Encryption Key",
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,
+ EncryptAlgKeyLen
+ );
+ IPSEC_DUMP_BUF (
+ " >>> Local Authentication Key",
+ ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,
+ IntegrityAlgKeyLen
+ );
+ IPSEC_DUMP_BUF (
+ " >>> Remote Authentication Key",
+ ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,
+ IntegrityAlgKeyLen
+ );
+
+
+
+Exit:
+ if (EFI_ERROR (Status)) {
+ if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey != NULL) {
+ FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey);
+ }
+ if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey != NULL) {
+ FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey);
+ }
+ if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey != NULL) {
+ FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey);
+ }
+ if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey != NULL) {
+ FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey);
+ }
+ }
+
+ if (OutputKey != NULL) {
+ FreePool (OutputKey);
+ }
+
+ return EFI_SUCCESS;
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER mIkev2Initial[][2] = {
+ { //PSK
+ { // IKEV2_INIT
+ Ikev2InitPskParser,
+ Ikev2InitPskGenerator
+ },
+ { //IKEV2_AUTH
+ Ikev2AuthPskParser,
+ Ikev2AuthPskGenerator
+ }
+ },
+ { // CERT
+ { // IKEV2_INIT
+ Ikev2InitCertParser,
+ Ikev2InitCertGenerator
+ },
+ { // IKEV2_AUTH
+ Ikev2AuthCertParser,
+ Ikev2AuthCertGenerator
+ },
+ },
+};
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/Utility.c b/Core/NetworkPkg/IpSecDxe/Ikev2/Utility.c
new file mode 100644
index 0000000000..5b26ba1d02
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Utility.c
@@ -0,0 +1,2787 @@
+/** @file
+ The Common operations used by IKE Exchange Process.
+
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2010 - 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 "Utility.h"
+#include "IpSecDebug.h"
+#include "IkeService.h"
+#include "IpSecConfigImpl.h"
+
+UINT16 mIkev2EncryptAlgorithmList[IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM] = {
+ IKEV2_TRANSFORM_ID_ENCR_3DES,
+ IKEV2_TRANSFORM_ID_ENCR_AES_CBC,
+};
+
+UINT16 mIkev2PrfAlgorithmList[IKEV2_SUPPORT_PRF_ALGORITHM_NUM] = {
+ IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1,
+};
+
+UINT16 mIkev2DhGroupAlgorithmList[IKEV2_SUPPORT_DH_ALGORITHM_NUM] = {
+ IKEV2_TRANSFORM_ID_DH_1024MODP,
+ IKEV2_TRANSFORM_ID_DH_2048MODP,
+};
+
+UINT16 mIkev2AuthAlgorithmList[IKEV2_SUPPORT_AUTH_ALGORITHM_NUM] = {
+ IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96,
+};
+
+/**
+ Allocate buffer for IKEV2_SA_SESSION and initialize it.
+
+ @param[in] Private Pointer to IPSEC_PRIVATE_DATA.
+ @param[in] UdpService Pointer to IKE_UDP_SERVICE related to this IKE SA Session.
+
+ @return Pointer to IKEV2_SA_SESSION or NULL.
+
+**/
+IKEV2_SA_SESSION *
+Ikev2SaSessionAlloc (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN IKE_UDP_SERVICE *UdpService
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_SESSION_COMMON *SessionCommon;
+ IKEV2_SA_SESSION *IkeSaSession;
+
+ IkeSaSession = AllocateZeroPool (sizeof (IKEV2_SA_SESSION));
+ if (IkeSaSession == NULL) {
+ return NULL;
+ }
+
+ //
+ // Initialize the fields of IkeSaSession and its SessionCommon.
+ //
+ IkeSaSession->NCookie = NULL;
+ IkeSaSession->Signature = IKEV2_SA_SESSION_SIGNATURE;
+ IkeSaSession->InitiatorCookie = IkeGenerateCookie ();
+ IkeSaSession->ResponderCookie = 0;
+ //
+ // BUGBUG: Message ID starts from 2 is to match the OpenSwan requirement, but it
+ // might not match the IPv6 Logo. In its test specification, it mentions that
+ // the Message ID should start from zero after the IKE_SA_INIT exchange.
+ //
+ IkeSaSession->MessageId = 2;
+ SessionCommon = &IkeSaSession->SessionCommon;
+ SessionCommon->UdpService = UdpService;
+ SessionCommon->Private = Private;
+ SessionCommon->IkeSessionType = IkeSessionTypeIkeSa;
+ SessionCommon->IkeVer = 2;
+ SessionCommon->AfterEncodePayload = NULL;
+ SessionCommon->BeforeDecodePayload = NULL;
+
+ //
+ // Create a resend notfiy event for retry.
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ Ikev2ResendNotify,
+ SessionCommon,
+ &SessionCommon->TimeoutEvent
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (IkeSaSession);
+ return NULL;
+ }
+
+ //
+ // Initialize the lists in IkeSaSession.
+ //
+ InitializeListHead (&IkeSaSession->ChildSaSessionList);
+ InitializeListHead (&IkeSaSession->ChildSaEstablishSessionList);
+ InitializeListHead (&IkeSaSession->InfoMIDList);
+ InitializeListHead (&IkeSaSession->DeleteSaList);
+
+ return IkeSaSession;
+}
+
+/**
+ Register the established IKEv2 SA into Private->Ikev2EstablishedList. If there is
+ IKEV2_SA_SESSION with same remote peer IP, remove the old one then register the
+ new one.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be registered.
+ @param[in] Private Pointer to IPSEC_PRAVATE_DATA.
+
+**/
+VOID
+Ikev2SaSessionReg (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IPSEC_PRIVATE_DATA *Private
+ )
+{
+ IKEV2_SESSION_COMMON *SessionCommon;
+ IKEV2_SA_SESSION *OldIkeSaSession;
+ EFI_STATUS Status;
+ UINT64 Lifetime;
+
+ //
+ // Keep IKE SA exclusive to remote ip address.
+ //
+ SessionCommon = &IkeSaSession->SessionCommon;
+ OldIkeSaSession = Ikev2SaSessionRemove (&Private->Ikev2EstablishedList, &SessionCommon->RemotePeerIp);
+ if (OldIkeSaSession != NULL) {
+ //
+ // TODO: It should delete all child SAs if rekey the IKE SA.
+ //
+ Ikev2SaSessionFree (OldIkeSaSession);
+ }
+
+ //
+ // Cleanup the fields of SessionCommon for processing.
+ //
+ Ikev2SessionCommonRefresh (SessionCommon);
+
+ //
+ // Insert the ready IKE SA session into established list.
+ //
+ Ikev2SaSessionInsert (&Private->Ikev2EstablishedList, IkeSaSession, &SessionCommon->RemotePeerIp);
+
+ //
+ // Create a notfiy event for the IKE SA life time counting.
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ Ikev2LifetimeNotify,
+ SessionCommon,
+ &SessionCommon->TimeoutEvent
+ );
+ if (EFI_ERROR(Status)){
+ //
+ // If TimerEvent creation failed, the SA will be alive untill user disable it or
+ // receiving a Delete Payload from peer.
+ //
+ return;
+ }
+
+ //
+ // Start to count the lifetime of the IKE SA.
+ //
+ if (IkeSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime == 0) {
+ Lifetime = IKE_SA_DEFAULT_LIFETIME;
+ } else {
+ Lifetime = IkeSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime;
+ }
+
+ Status = gBS->SetTimer (
+ SessionCommon->TimeoutEvent,
+ TimerRelative,
+ MultU64x32(Lifetime, 10000000) // ms->100ns
+ );
+ if (EFI_ERROR(Status)){
+ //
+ // If SetTimer failed, the SA will be alive untill user disable it or
+ // receiving a Delete Payload from peer.
+ //
+ return ;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "\n------IkeSa established and start to count down %d seconds lifetime\n",
+ Lifetime
+ ));
+
+ return ;
+}
+
+/**
+ Find a IKEV2_SA_SESSION by the remote peer IP.
+
+ @param[in] SaSessionList SaSession List to be searched.
+ @param[in] RemotePeerIp Pointer to specified IP address.
+
+ @return Pointer to IKEV2_SA_SESSION if find one or NULL.
+
+**/
+IKEV2_SA_SESSION *
+Ikev2SaSessionLookup (
+ IN LIST_ENTRY *SaSessionList,
+ IN EFI_IP_ADDRESS *RemotePeerIp
+ )
+{
+ LIST_ENTRY *Entry;
+ IKEV2_SA_SESSION *IkeSaSession;
+
+ NET_LIST_FOR_EACH (Entry, SaSessionList) {
+ IkeSaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);
+
+ if (CompareMem (
+ &IkeSaSession->SessionCommon.RemotePeerIp,
+ RemotePeerIp,
+ sizeof (EFI_IP_ADDRESS)
+ ) == 0) {
+
+ return IkeSaSession;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Insert a IKE_SA_SESSION into IkeSaSession list. The IkeSaSession list is either
+ Private->Ikev2SaSession list or Private->Ikev2EstablishedList list.
+
+ @param[in] SaSessionList Pointer to list to be inserted into.
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be inserted.
+ @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESSS to indicate the
+ unique IKEV2_SA_SESSION.
+
+**/
+VOID
+Ikev2SaSessionInsert (
+ IN LIST_ENTRY *SaSessionList,
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN EFI_IP_ADDRESS *RemotePeerIp
+ )
+{
+ Ikev2SaSessionRemove (SaSessionList, RemotePeerIp);
+ InsertTailList (SaSessionList, &IkeSaSession->BySessionTable);
+}
+
+/**
+ Remove the SA Session by Remote Peer IP.
+
+ @param[in] SaSessionList Pointer to list to be searched.
+ @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESS to use for SA Session search.
+
+ @retval Pointer to IKEV2_SA_SESSION with the specified remote IP address or NULL.
+
+**/
+IKEV2_SA_SESSION *
+Ikev2SaSessionRemove (
+ IN LIST_ENTRY *SaSessionList,
+ IN EFI_IP_ADDRESS *RemotePeerIp
+ )
+{
+ LIST_ENTRY *Entry;
+ IKEV2_SA_SESSION *IkeSaSession;
+
+ NET_LIST_FOR_EACH (Entry, SaSessionList) {
+ IkeSaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);
+
+ if (CompareMem (
+ &IkeSaSession->SessionCommon.RemotePeerIp,
+ RemotePeerIp,
+ sizeof (EFI_IP_ADDRESS)
+ ) == 0) {
+
+ RemoveEntryList (Entry);
+ return IkeSaSession;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Marking a SA session as on deleting.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION.
+
+ @retval EFI_SUCCESS Find the related SA session and marked it.
+
+**/
+EFI_STATUS
+Ikev2SaSessionOnDeleting (
+ IN IKEV2_SA_SESSION *IkeSaSession
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Free specified Seession Common. The session common would belong to a IKE SA or
+ a Child SA.
+
+ @param[in] SessionCommon Pointer to a Session Common.
+
+**/
+VOID
+Ikev2SaSessionCommonFree (
+ IN IKEV2_SESSION_COMMON *SessionCommon
+ )
+{
+
+ ASSERT (SessionCommon != NULL);
+
+ if (SessionCommon->LastSentPacket != NULL) {
+ IkePacketFree (SessionCommon->LastSentPacket);
+ }
+
+ if (SessionCommon->SaParams != NULL) {
+ FreePool (SessionCommon->SaParams);
+ }
+ if (SessionCommon->TimeoutEvent != NULL) {
+ gBS->CloseEvent (SessionCommon->TimeoutEvent);
+ }
+}
+
+/**
+ After IKE/Child SA is estiblished, close the time event and free sent packet.
+
+ @param[in] SessionCommon Pointer to a Session Common.
+
+**/
+VOID
+Ikev2SessionCommonRefresh (
+ IN IKEV2_SESSION_COMMON *SessionCommon
+ )
+{
+ ASSERT (SessionCommon != NULL);
+
+ gBS->CloseEvent (SessionCommon->TimeoutEvent);
+ SessionCommon->TimeoutEvent = NULL;
+ SessionCommon->TimeoutInterval = 0;
+ SessionCommon->RetryCount = 0;
+ if (SessionCommon->LastSentPacket != NULL) {
+ IkePacketFree (SessionCommon->LastSentPacket);
+ SessionCommon->LastSentPacket = NULL;
+ }
+
+ return ;
+}
+/**
+ Free specified IKEV2 SA Session.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be freed.
+
+**/
+VOID
+Ikev2SaSessionFree (
+ IN IKEV2_SA_SESSION *IkeSaSession
+ )
+{
+ IKEV2_SESSION_KEYS *IkeKeys;
+ LIST_ENTRY *Entry;
+ IKEV2_CHILD_SA_SESSION *ChildSa;
+ IKEV2_DH_BUFFER *DhBuffer;
+
+ ASSERT (IkeSaSession != NULL);
+
+ //
+ // Delete Common Session
+ //
+ Ikev2SaSessionCommonFree (&IkeSaSession->SessionCommon);
+
+ //
+ // Delete ChildSaEstablish List and SAD
+ //
+ for (Entry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;
+ Entry != &IkeSaSession->ChildSaEstablishSessionList;
+ ) {
+
+ ChildSa = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);
+ Entry = Entry->ForwardLink;
+ Ikev2ChildSaSilentDelete (ChildSa->IkeSaSession, ChildSa->LocalPeerSpi);
+
+ }
+
+ //
+ // Delete ChildSaSessionList
+ //
+ for ( Entry = IkeSaSession->ChildSaSessionList.ForwardLink;
+ Entry != &IkeSaSession->ChildSaSessionList;
+ ){
+ ChildSa = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);
+ Entry = Entry->ForwardLink;
+ RemoveEntryList (Entry->BackLink);
+ Ikev2ChildSaSessionFree (ChildSa);
+ }
+
+ //
+ // Delete DhBuffer and Keys
+ //
+ if (IkeSaSession->IkeKeys != NULL) {
+ IkeKeys = IkeSaSession->IkeKeys;
+ DhBuffer = IkeKeys->DhBuffer;
+
+ //
+ // Delete DhBuffer
+ //
+ Ikev2DhBufferFree (DhBuffer);
+
+ //
+ // Delete Keys
+ //
+ if (IkeKeys->SkAiKey != NULL) {
+ FreePool (IkeKeys->SkAiKey);
+ }
+ if (IkeKeys->SkArKey != NULL) {
+ FreePool (IkeKeys->SkArKey);
+ }
+ if (IkeKeys->SkdKey != NULL) {
+ FreePool (IkeKeys->SkdKey);
+ }
+ if (IkeKeys->SkEiKey != NULL) {
+ FreePool (IkeKeys->SkEiKey);
+ }
+ if (IkeKeys->SkErKey != NULL) {
+ FreePool (IkeKeys->SkErKey);
+ }
+ if (IkeKeys->SkPiKey != NULL) {
+ FreePool (IkeKeys->SkPiKey);
+ }
+ if (IkeKeys->SkPrKey != NULL) {
+ FreePool (IkeKeys->SkPrKey);
+ }
+ FreePool (IkeKeys);
+ }
+
+ if (IkeSaSession->SaData != NULL) {
+ FreePool (IkeSaSession->SaData);
+ }
+
+ if (IkeSaSession->NiBlock != NULL) {
+ FreePool (IkeSaSession->NiBlock);
+ }
+
+ if (IkeSaSession->NrBlock != NULL) {
+ FreePool (IkeSaSession->NrBlock);
+ }
+
+ if (IkeSaSession->NCookie != NULL) {
+ FreePool (IkeSaSession->NCookie);
+ }
+
+ if (IkeSaSession->InitPacket != NULL) {
+ FreePool (IkeSaSession->InitPacket);
+ }
+
+ if (IkeSaSession->RespPacket != NULL) {
+ FreePool (IkeSaSession->RespPacket);
+ }
+
+ FreePool (IkeSaSession);
+
+ return ;
+}
+
+/**
+ Increase the MessageID in IkeSaSession.
+
+ @param[in] IkeSaSession Pointer to a specified IKEV2_SA_SESSION.
+
+**/
+VOID
+Ikev2SaSessionIncreaseMessageId (
+ IN IKEV2_SA_SESSION *IkeSaSession
+ )
+{
+ if (IkeSaSession->MessageId < 0xffffffff) {
+ IkeSaSession->MessageId ++;
+ } else {
+ //
+ // TODO: Trigger Rekey process.
+ //
+ }
+}
+
+/**
+ Allocate memory for IKEV2 Child SA Session.
+
+ @param[in] UdpService Pointer to IKE_UDP_SERVICE.
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this Child SA
+ Session.
+
+ @retval Pointer of a new created IKEV2 Child SA Session or NULL.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionAlloc (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IKEV2_SA_SESSION *IkeSaSession
+ )
+{
+ EFI_STATUS Status;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SESSION_COMMON *ChildSaCommon;
+ IKEV2_SESSION_COMMON *SaCommon;
+
+ ChildSaSession = AllocateZeroPool (sizeof (IKEV2_CHILD_SA_SESSION));
+ if (ChildSaSession == NULL) {
+ return NULL;
+ }
+
+ //
+ // Initialize the fields of ChildSaSession and its SessionCommon.
+ //
+ ChildSaSession->Signature = IKEV2_CHILD_SA_SESSION_SIGNATURE;
+ ChildSaSession->IkeSaSession = IkeSaSession;
+ ChildSaSession->MessageId = IkeSaSession->MessageId;
+ ChildSaSession->LocalPeerSpi = IkeGenerateSpi ();
+ ChildSaCommon = &ChildSaSession->SessionCommon;
+ ChildSaCommon->UdpService = UdpService;
+ ChildSaCommon->Private = IkeSaSession->SessionCommon.Private;
+ ChildSaCommon->IkeSessionType = IkeSessionTypeChildSa;
+ ChildSaCommon->IkeVer = 2;
+ ChildSaCommon->AfterEncodePayload = Ikev2ChildSaAfterEncodePayload;
+ ChildSaCommon->BeforeDecodePayload = Ikev2ChildSaBeforeDecodePayload;
+ SaCommon = &ChildSaSession->IkeSaSession->SessionCommon;
+
+ //
+ // Create a resend notfiy event for retry.
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ Ikev2ResendNotify,
+ ChildSaCommon,
+ &ChildSaCommon->TimeoutEvent
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (ChildSaSession);
+ return NULL;
+ }
+
+ CopyMem (&ChildSaCommon->LocalPeerIp, &SaCommon->LocalPeerIp, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&ChildSaCommon->RemotePeerIp, &SaCommon->RemotePeerIp, sizeof (EFI_IP_ADDRESS));
+
+ return ChildSaSession;
+}
+
+/**
+ Register a established IKEv2 Child SA into IkeSaSession->ChildSaEstablishSessionList.
+ If the there is IKEV2_CHILD_SA_SESSION with same remote peer IP, remove the old one
+ then register the new one.
+
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be registered.
+ @param[in] Private Pointer to IPSEC_PRAVATE_DATA.
+
+**/
+VOID
+Ikev2ChildSaSessionReg (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession,
+ IN IPSEC_PRIVATE_DATA *Private
+ )
+{
+ IKEV2_SESSION_COMMON *SessionCommon;
+ IKEV2_CHILD_SA_SESSION *OldChildSaSession;
+ IKEV2_SA_SESSION *IkeSaSession;
+ EFI_STATUS Status;
+ UINT64 Lifetime;
+
+ //
+ // Keep the IKE SA exclusive.
+ //
+ SessionCommon = &ChildSaSession->SessionCommon;
+ IkeSaSession = ChildSaSession->IkeSaSession;
+ OldChildSaSession = Ikev2ChildSaSessionRemove (
+ &IkeSaSession->ChildSaEstablishSessionList,
+ ChildSaSession->LocalPeerSpi,
+ IKEV2_ESTABLISHED_CHILDSA_LIST
+ );
+ if (OldChildSaSession != NULL) {
+ //
+ // Free the old one.
+ //
+ Ikev2ChildSaSessionFree (OldChildSaSession);
+ }
+
+ //
+ // Store the ready child SA into SAD.
+ //
+ Ikev2StoreSaData (ChildSaSession);
+
+ //
+ // Cleanup the fields of SessionCommon for processing.
+ //
+ Ikev2SessionCommonRefresh (SessionCommon);
+
+ //
+ // Insert the ready child SA session into established list.
+ //
+ Ikev2ChildSaSessionInsert (&IkeSaSession->ChildSaEstablishSessionList, ChildSaSession);
+
+ //
+ // Create a Notify event for the IKE SA life time counting.
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ Ikev2LifetimeNotify,
+ SessionCommon,
+ &SessionCommon->TimeoutEvent
+ );
+ if (EFI_ERROR(Status)){
+ return ;
+ }
+
+ //
+ // Start to count the lifetime of the IKE SA.
+ //
+ if (ChildSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime != 0){
+ Lifetime = ChildSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime;
+ } else {
+ Lifetime = CHILD_SA_DEFAULT_LIFETIME;
+ }
+
+ Status = gBS->SetTimer (
+ SessionCommon->TimeoutEvent,
+ TimerRelative,
+ MultU64x32(Lifetime, 10000000) // ms->100ns
+ );
+ if (EFI_ERROR(Status)){
+ return ;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "\n------ChildSa established and start to count down %d seconds lifetime\n",
+ Lifetime
+ ));
+
+ return ;
+}
+
+/**
+ Find the ChildSaSession by it's MessagId.
+
+ @param[in] SaSessionList Pointer to a ChildSaSession List.
+ @param[in] Mid The messageId used to search ChildSaSession.
+
+ @return Pointer to IKEV2_CHILD_SA_SESSION or NULL.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionLookupByMid (
+ IN LIST_ENTRY *SaSessionList,
+ IN UINT32 Mid
+ )
+{
+ LIST_ENTRY *Entry;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+
+ NET_LIST_FOR_EACH (Entry, SaSessionList) {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);
+
+ if (ChildSaSession->MessageId == Mid) {
+ return ChildSaSession;
+ }
+ }
+ return NULL;
+}
+
+/**
+ This function find the Child SA by the specified SPI.
+
+ This functin find a ChildSA session by searching the ChildSaSessionlist of
+ the input IKEV2_SA_SESSION by specified MessageID.
+
+ @param[in] SaSessionList Pointer to List to be searched.
+ @param[in] Spi Specified SPI.
+
+ @return Pointer to IKEV2_CHILD_SA_SESSION or NULL.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionLookupBySpi (
+ IN LIST_ENTRY *SaSessionList,
+ IN UINT32 Spi
+ )
+{
+ LIST_ENTRY *Entry;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+
+ NET_LIST_FOR_EACH (Entry, SaSessionList) {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);
+
+ if (ChildSaSession->RemotePeerSpi == Spi || ChildSaSession->LocalPeerSpi == Spi) {
+ return ChildSaSession;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Insert a Child SA Session into the specified ChildSa list.
+
+ @param[in] SaSessionList Pointer to list to be inserted in.
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be inserted.
+
+**/
+VOID
+Ikev2ChildSaSessionInsert (
+ IN LIST_ENTRY *SaSessionList,
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession
+ )
+{
+ InsertTailList (SaSessionList, &ChildSaSession->ByIkeSa);
+}
+
+/**
+ Remove the IKEV2_CHILD_SA_SESSION from IkeSaSessionList.
+
+ @param[in] SaSessionList The SA Session List to be iterated.
+ @param[in] Spi Spi used to identified the IKEV2_CHILD_SA_SESSION.
+ @param[in] ListType The type of the List to indicate whether it is a
+ Established.
+
+ @return The point to IKEV2_CHILD_SA_SESSION or NULL.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionRemove (
+ IN LIST_ENTRY *SaSessionList,
+ IN UINT32 Spi,
+ IN UINT8 ListType
+ )
+{
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SaSessionList) {
+
+ if (ListType == IKEV2_ESTABLISHED_CHILDSA_LIST || ListType == IKEV2_ESTABLISHING_CHILDSA_LIST) {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);
+ } else if (ListType == IKEV2_DELET_CHILDSA_LIST) {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_DEL_SA (Entry);
+ } else {
+ return NULL;
+ }
+
+ if (ChildSaSession->RemotePeerSpi == Spi || ChildSaSession->LocalPeerSpi == Spi) {
+ RemoveEntryList (Entry);
+ return ChildSaSession;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Mark a specified Child SA Session as on deleting.
+
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION.
+
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+Ikev2ChildSaSessionOnDeleting (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Free the memory located for the specified IKEV2_CHILD_SA_SESSION.
+
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION.
+
+**/
+VOID
+Ikev2ChildSaSessionFree (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession
+ )
+{
+ IKEV2_SESSION_COMMON *SessionCommon;
+
+ SessionCommon = &ChildSaSession->SessionCommon;
+ if (ChildSaSession->SaData != NULL) {
+ FreePool (ChildSaSession->SaData);
+ }
+
+ if (ChildSaSession->NiBlock != NULL) {
+ FreePool (ChildSaSession->NiBlock);
+ }
+
+ if (ChildSaSession->NrBlock != NULL) {
+ FreePool (ChildSaSession->NrBlock);
+ }
+
+ if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey != NULL) {
+ FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey);
+ }
+
+ if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey != NULL) {
+ FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey);
+ }
+
+ if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey != NULL) {
+ FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey);
+ }
+
+ if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey != NULL) {
+ FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey);
+ }
+
+ //
+ // Delete DhBuffer
+ //
+ Ikev2DhBufferFree (ChildSaSession->DhBuffer);
+
+ //
+ // Delete SpdSelector
+ //
+ if (ChildSaSession->SpdSelector != NULL) {
+ if (ChildSaSession->SpdSelector->LocalAddress != NULL) {
+ FreePool (ChildSaSession->SpdSelector->LocalAddress);
+ }
+ if (ChildSaSession->SpdSelector->RemoteAddress != NULL) {
+ FreePool (ChildSaSession->SpdSelector->RemoteAddress);
+ }
+ FreePool (ChildSaSession->SpdSelector);
+ }
+ Ikev2SaSessionCommonFree (SessionCommon);
+ FreePool (ChildSaSession);
+
+ return ;
+}
+
+/**
+ Delete the specified established Child SA.
+
+ This function delete the Child SA directly and don't send the Information Packet to
+ remote peer.
+
+ @param[in] IkeSaSession Pointer to a IKE SA Session used to be searched for.
+ @param[in] Spi SPI used to find the Child SA.
+
+ @retval EFI_NOT_FOUND Pointer of IKE SA Session is NULL.
+ @retval EFI_NOT_FOUND There is no specified Child SA related with the input
+ SPI under this IKE SA Session.
+ @retval EFI_SUCCESS Delete the Child SA successfully.
+
+**/
+EFI_STATUS
+Ikev2ChildSaSilentDelete (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT32 Spi
+ )
+{
+ EFI_STATUS Status;
+ EFI_IPSEC_CONFIG_SELECTOR *Selector;
+ UINTN SelectorSize;
+ BOOLEAN IsLocalFound;
+ BOOLEAN IsRemoteFound;
+ UINT32 LocalSpi;
+ UINT32 RemoteSpi;
+ IKEV2_CHILD_SA_SESSION *ChildSession;
+ EFI_IPSEC_CONFIG_SELECTOR *LocalSelector;
+ EFI_IPSEC_CONFIG_SELECTOR *RemoteSelector;
+ IPSEC_PRIVATE_DATA *Private;
+
+ if (IkeSaSession == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ IsLocalFound = FALSE;
+ IsRemoteFound = FALSE;
+ ChildSession = NULL;
+ LocalSelector = NULL;
+ RemoteSelector = NULL;
+
+ Private = IkeSaSession->SessionCommon.Private;
+
+ //
+ // Remove the Established SA from ChildSaEstablishlist.
+ //
+ ChildSession = Ikev2ChildSaSessionRemove(
+ &(IkeSaSession->ChildSaEstablishSessionList),
+ Spi,
+ IKEV2_ESTABLISHED_CHILDSA_LIST
+ );
+ if (ChildSession == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ LocalSpi = ChildSession->LocalPeerSpi;
+ RemoteSpi = ChildSession->RemotePeerSpi;
+
+ SelectorSize = sizeof (EFI_IPSEC_CONFIG_SELECTOR);
+ Selector = AllocateZeroPool (SelectorSize);
+ if (Selector == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ while (1) {
+ Status = EfiIpSecConfigGetNextSelector (
+ &Private->IpSecConfig,
+ IPsecConfigDataTypeSad,
+ &SelectorSize,
+ Selector
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (Selector);
+
+ Selector = AllocateZeroPool (SelectorSize);
+ if (Selector == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ Status = EfiIpSecConfigGetNextSelector (
+ &Private->IpSecConfig,
+ IPsecConfigDataTypeSad,
+ &SelectorSize,
+ Selector
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Selector->SaId.Spi == RemoteSpi) {
+ //
+ // SPI is unique. There is only one SAD whose SPI is
+ // same with RemoteSpi.
+ //
+ IsRemoteFound = TRUE;
+ RemoteSelector = AllocateZeroPool (SelectorSize);
+ if (RemoteSelector == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ CopyMem (RemoteSelector, Selector, SelectorSize);
+ }
+
+ if (Selector->SaId.Spi == LocalSpi) {
+ //
+ // SPI is unique. There is only one SAD whose SPI is
+ // same with LocalSpi.
+ //
+ IsLocalFound = TRUE;
+ LocalSelector = AllocateZeroPool (SelectorSize);
+ if (LocalSelector == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ CopyMem (LocalSelector, Selector, SelectorSize);
+ }
+ }
+ //
+ // Delete SA from the Variable.
+ //
+ if (IsLocalFound) {
+ Status = EfiIpSecConfigSetData (
+ &Private->IpSecConfig,
+ IPsecConfigDataTypeSad,
+ LocalSelector,
+ NULL,
+ NULL
+ );
+ }
+
+ if (IsRemoteFound) {
+ Status = EfiIpSecConfigSetData (
+ &Private->IpSecConfig,
+ IPsecConfigDataTypeSad,
+ RemoteSelector,
+ NULL,
+ NULL
+ );
+
+ }
+
+ DEBUG (
+ (DEBUG_INFO,
+ "\n------IKEV2 deleted ChildSa(local spi, remote spi):(0x%x, 0x%x)------\n",
+ LocalSpi,
+ RemoteSpi)
+ );
+ Ikev2ChildSaSessionFree (ChildSession);
+
+ if (RemoteSelector != NULL) {
+ FreePool (RemoteSelector);
+ }
+
+ if (LocalSelector != NULL) {
+ FreePool (LocalSelector);
+ }
+
+ if (Selector != NULL) {
+ FreePool (Selector);
+ }
+
+ return Status;
+}
+
+/**
+ Free the specified DhBuffer.
+
+ @param[in] DhBuffer Pointer to IKEV2_DH_BUFFER to be freed.
+
+**/
+VOID
+Ikev2DhBufferFree (
+ IKEV2_DH_BUFFER *DhBuffer
+)
+{
+ if (DhBuffer != NULL) {
+ if (DhBuffer->GxBuffer != NULL) {
+ FreePool (DhBuffer->GxBuffer);
+ }
+ if (DhBuffer->GyBuffer != NULL) {
+ FreePool (DhBuffer->GyBuffer);
+ }
+ if (DhBuffer->GxyBuffer != NULL) {
+ FreePool (DhBuffer->GxyBuffer);
+ }
+ if (DhBuffer->DhContext != NULL) {
+ IpSecCryptoIoFreeDh (&DhBuffer->DhContext);
+ }
+ FreePool (DhBuffer);
+ }
+}
+
+/**
+ This function is to parse a request IKE packet and return its request type.
+ The request type is one of IKE CHILD SA creation, IKE SA rekeying and
+ IKE CHILD SA rekeying.
+
+ @param[in] IkePacket IKE packet to be prased.
+
+ return the type of the IKE packet.
+
+**/
+IKEV2_CREATE_CHILD_REQUEST_TYPE
+Ikev2ChildExchangeRequestType(
+ IN IKE_PACKET *IkePacket
+ )
+{
+ BOOLEAN Flag;
+ LIST_ENTRY *Entry;
+ IKE_PAYLOAD *IkePayload;
+
+ Flag = FALSE;
+
+ NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
+ IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {
+ //
+ // Packet with Ts Payload means it is for either CHILD_SA_CREATE or CHILD_SA_REKEY.
+ //
+ Flag = TRUE;
+ }
+ if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NOTIFY) {
+ if (((IKEV2_NOTIFY*)IkePayload)->MessageType == IKEV2_NOTIFICATION_REKEY_SA) {
+ //
+ // If notify payload with REKEY_SA message type, the IkePacket is for
+ // rekeying Child SA.
+ //
+ return IkeRequestTypeRekeyChildSa;
+ }
+ }
+ };
+
+ if (!Flag){
+ //
+ // The Create Child Exchange is for IKE SA rekeying.
+ //
+ return IkeRequestTypeRekeyIkeSa;
+ } else {
+ //
+ // If the Notify payloaad with transport mode message type, the IkePacket is
+ // for create Child SA.
+ //
+ return IkeRequestTypeCreateChildSa;
+ }
+}
+
+/**
+ Associate a SPD selector to the Child SA Session.
+
+ This function is called when the Child SA is not the first child SA of its
+ IKE SA. It associate a SPD to this Child SA.
+
+ @param[in, out] ChildSaSession Pointer to the Child SA Session to be associated to
+ a SPD selector.
+
+ @retval EFI_SUCCESS Associate one SPD selector to this Child SA Session successfully.
+ @retval EFI_NOT_FOUND Can't find the related SPD selector.
+
+**/
+EFI_STATUS
+Ikev2ChildSaAssociateSpdEntry (
+ IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession
+ )
+{
+ IpSecVisitConfigData (IPsecConfigDataTypeSpd, Ikev2MatchSpdEntry, ChildSaSession);
+ if (ChildSaSession->Spd != NULL) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+
+/**
+ This function finds the SPI from Create Child SA Exchange Packet.
+
+ @param[in] IkePacket Pointer to IKE_PACKET to be searched.
+
+ @retval SPI number or 0 if it is not supported.
+
+**/
+UINT32
+Ikev2ChildExchangeRekeySpi (
+ IN IKE_PACKET *IkePacket
+ )
+{
+ //
+ // Not support yet.
+ //
+ return 0;
+}
+
+/**
+ Validate the IKE header of received IKE packet.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this IKE packet.
+ @param[in] IkeHdr Pointer to IKE header of received IKE packet.
+
+ @retval TRUE If the IKE header is valid.
+ @retval FALSE If the IKE header is invalid.
+
+**/
+BOOLEAN
+Ikev2ValidateHeader (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_HEADER *IkeHdr
+ )
+{
+
+ IKEV2_SESSION_STATE State;
+
+ State = IkeSaSession->SessionCommon.State;
+ if (State == IkeStateInit) {
+ //
+ // For the IKE Initial Exchange, the MessagId should be zero.
+ //
+ if (IkeHdr->MessageId != 0) {
+ return FALSE;
+ }
+ } else {
+ if (State == IkeStateAuth) {
+ if (IkeHdr->MessageId != 1) {
+ return FALSE;
+ }
+ }
+ if (IkeHdr->InitiatorCookie != IkeSaSession->InitiatorCookie ||
+ IkeHdr->ResponderCookie != IkeSaSession->ResponderCookie
+ ) {
+ //
+ // TODO: send notification INVALID-COOKIE
+ //
+ return FALSE;
+ }
+ }
+
+ //
+ // Information Exchagne and Create Child Exchange can be started from each part.
+ //
+ if (IkeHdr->ExchangeType != IKEV2_EXCHANGE_TYPE_INFO &&
+ IkeHdr->ExchangeType != IKEV2_EXCHANGE_TYPE_CREATE_CHILD
+ ) {
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ if (IkeHdr->InitiatorCookie != IkeSaSession->InitiatorCookie) {
+ //
+ // TODO: send notification INVALID-COOKIE
+ //
+ return FALSE;
+ }
+ if (IkeHdr->Flags != IKE_HEADER_FLAGS_RESPOND) {
+ return FALSE;
+ }
+ } else {
+ if (IkeHdr->Flags != IKE_HEADER_FLAGS_INIT) {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Create and intialize IKEV2_SA_DATA for speicifed IKEV2_SESSION_COMMON.
+
+ This function will be only called by the initiator. The responder's IKEV2_SA_DATA
+ will be generated during parsed the initiator packet.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to.
+
+ @retval a Pointer to a new IKEV2_SA_DATA or NULL.
+
+**/
+IKEV2_SA_DATA *
+Ikev2InitializeSaData (
+ IN IKEV2_SESSION_COMMON *SessionCommon
+ )
+{
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SA_DATA *SaData;
+ IKEV2_PROPOSAL_DATA *ProposalData;
+ IKEV2_TRANSFORM_DATA *TransformData;
+ IKE_SA_ATTRIBUTE *Attribute;
+
+ ASSERT (SessionCommon != NULL);
+ //
+ // TODO: Remove the hard code of the support Alogrithm. Those data should be
+ // get from the SPD/PAD data.
+ //
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ SaData = AllocateZeroPool (
+ sizeof (IKEV2_SA_DATA) +
+ sizeof (IKEV2_PROPOSAL_DATA) * 2 +
+ sizeof (IKEV2_TRANSFORM_DATA) * 4 * 2
+ );
+ } else {
+ SaData = AllocateZeroPool (
+ sizeof (IKEV2_SA_DATA) +
+ sizeof (IKEV2_PROPOSAL_DATA) * 2 +
+ sizeof (IKEV2_TRANSFORM_DATA) * 3 * 2
+ );
+ }
+ if (SaData == NULL) {
+ return NULL;
+ }
+
+ //
+ // First proposal payload: 3DES + SHA1 + DH
+ //
+ SaData->NumProposals = 2;
+ ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1);
+ ProposalData->ProposalIndex = 1;
+
+ //
+ // If SA data for IKE_SA_INIT exchage, contains 4 transforms. If SA data for
+ // IKE_AUTH exchange contains 3 transforms.
+ //
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ ProposalData->NumTransforms = 4;
+ } else {
+ ProposalData->NumTransforms = 3;
+ }
+
+
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ ProposalData->ProtocolId = IPSEC_PROTO_ISAKMP;
+ } else {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
+ ProposalData->ProtocolId = IPSEC_PROTO_IPSEC_ESP;
+ ProposalData->Spi = AllocateZeroPool (sizeof (ChildSaSession->LocalPeerSpi));
+ if (ProposalData->Spi == NULL) {
+ FreePool (SaData);
+ return NULL;
+ }
+
+ CopyMem (
+ ProposalData->Spi,
+ &ChildSaSession->LocalPeerSpi,
+ sizeof(ChildSaSession->LocalPeerSpi)
+ );
+ }
+
+ //
+ // Set transform attribute for Encryption Algorithm - 3DES
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1);
+ TransformData->TransformIndex = 0;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ENCR;
+ TransformData->TransformId = IKEV2_TRANSFORM_ID_ENCR_3DES;
+
+ //
+ // Set transform attribute for Integrity Algorithm - SHA1_96
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);
+ TransformData->TransformIndex = 1;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_INTEG;
+ TransformData->TransformId = IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96;
+
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ //
+ // Set transform attribute for Pseduo-Random Function - HAMC_SHA1
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);
+ TransformData->TransformIndex = 2;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_PRF;
+ TransformData->TransformId = IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1;
+ }
+
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ //
+ // Set transform attribute for DH Group - DH 1024
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);
+ TransformData->TransformIndex = 3;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_DH;
+ TransformData->TransformId = IKEV2_TRANSFORM_ID_DH_1024MODP;
+ } else {
+ //
+ // Transform type for Extended Sequence Numbers. Currently not support Extended
+ // Sequence Number.
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);
+ TransformData->TransformIndex = 2;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ESN;
+ TransformData->TransformId = 0;
+ }
+
+ //
+ // Second proposal payload: 3DES + SHA1 + DH
+ //
+ ProposalData = (IKEV2_PROPOSAL_DATA *) (TransformData + 1);
+ ProposalData->ProposalIndex = 2;
+
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ ProposalData->ProtocolId = IPSEC_PROTO_ISAKMP;
+ ProposalData->NumTransforms = 4;
+ } else {
+
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
+ ProposalData->ProtocolId = IPSEC_PROTO_IPSEC_ESP;
+ ProposalData->NumTransforms = 3;
+ ProposalData->Spi = AllocateZeroPool (sizeof (ChildSaSession->LocalPeerSpi));
+ if (ProposalData->Spi == NULL) {
+ FreePool (((IKEV2_PROPOSAL_DATA *) (SaData + 1))->Spi);
+ FreePool (SaData);
+ return NULL;
+ }
+
+ CopyMem (
+ ProposalData->Spi,
+ &ChildSaSession->LocalPeerSpi,
+ sizeof(ChildSaSession->LocalPeerSpi)
+ );
+ }
+
+ //
+ // Set transform attribute for Encryption Algorithm - AES-CBC
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1);
+ TransformData->TransformIndex = 0;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ENCR;
+ TransformData->TransformId = IKEV2_TRANSFORM_ID_ENCR_AES_CBC;
+ Attribute = &TransformData->Attribute;
+ Attribute->AttrType = IKEV2_ATTRIBUTE_TYPE_KEYLEN;
+ Attribute->Attr.AttrLength = (UINT16) (8 * IpSecGetEncryptKeyLength (IKEV2_TRANSFORM_ID_ENCR_AES_CBC));
+
+ //
+ // Set transform attribute for Integrity Algorithm - SHA1_96
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);
+ TransformData->TransformIndex = 1;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_INTEG;
+ TransformData->TransformId = IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96;
+
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ //
+ // Set transform attribute for Pseduo-Random Function - HAMC_SHA1
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);
+ TransformData->TransformIndex = 2;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_PRF;
+ TransformData->TransformId = IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1;
+ }
+
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ //
+ // Set transform attrbiute for DH Group - DH-1024
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);
+ TransformData->TransformIndex = 3;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_DH;
+ TransformData->TransformId = IKEV2_TRANSFORM_ID_DH_1024MODP;
+ } else {
+ //
+ // Transform type for Extended Sequence Numbers. Currently not support Extended
+ // Sequence Number.
+ //
+ TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);
+ TransformData->TransformIndex = 2;
+ TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ESN;
+ TransformData->TransformId = 0;
+ }
+
+ return SaData;
+}
+
+/**
+ Store the SA into SAD.
+
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION.
+
+**/
+VOID
+Ikev2StoreSaData (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession
+ )
+{
+ EFI_STATUS Status;
+ EFI_IPSEC_SA_ID SaId;
+ EFI_IPSEC_SA_DATA2 SaData;
+ IKEV2_SESSION_COMMON *SessionCommon;
+ IPSEC_PRIVATE_DATA *Private;
+ UINT32 TempAddressCount;
+ EFI_IP_ADDRESS_INFO *TempAddressInfo;
+
+ SessionCommon = &ChildSaSession->SessionCommon;
+ Private = SessionCommon->Private;
+
+ ZeroMem (&SaId, sizeof (EFI_IPSEC_SA_ID));
+ ZeroMem (&SaData, sizeof (EFI_IPSEC_SA_DATA2));
+
+ //
+ // Create a SpdSelector. In this implementation, one SPD represents
+ // 2 direction traffic, so in here, there needs to reverse the local address
+ // and remote address for Remote Peer's SA, then reverse again for the locate
+ // SA.
+ //
+ TempAddressCount = ChildSaSession->SpdSelector->LocalAddressCount;
+ TempAddressInfo = ChildSaSession->SpdSelector->LocalAddress;
+
+ ChildSaSession->SpdSelector->LocalAddressCount = ChildSaSession->SpdSelector->RemoteAddressCount;
+ ChildSaSession->SpdSelector->LocalAddress = ChildSaSession->SpdSelector->RemoteAddress;
+
+ ChildSaSession->SpdSelector->RemoteAddress = TempAddressInfo;
+ ChildSaSession->SpdSelector->RemoteAddressCount= TempAddressCount;
+
+ //
+ // Set the SaId and SaData.
+ //
+ SaId.Spi = ChildSaSession->LocalPeerSpi;
+ SaId.Proto = EfiIPsecESP;
+ SaData.AntiReplayWindows = 16;
+ SaData.SNCount = 0;
+ SaData.Mode = ChildSaSession->Spd->Data->ProcessingPolicy->Mode;
+
+ //
+ // If it is tunnel mode, should add the TunnelDest and TunnelSource for SaData.
+ //
+ if (SaData.Mode == EfiIPsecTunnel) {
+ CopyMem (
+ &SaData.TunnelSourceAddress,
+ &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+ CopyMem (
+ &SaData.TunnelDestinationAddress,
+ &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->LocalTunnelAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+ }
+
+ CopyMem (&SaId.DestAddress, &ChildSaSession->SessionCommon.LocalPeerIp, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&SaData.AlgoInfo, &ChildSaSession->ChildKeymats.LocalPeerInfo, sizeof (EFI_IPSEC_ALGO_INFO));
+ SaData.SpdSelector = ChildSaSession->SpdSelector;
+
+ //
+ // Store the remote SA into SAD.
+ //
+ Status = EfiIpSecConfigSetData (
+ &Private->IpSecConfig,
+ IPsecConfigDataTypeSad,
+ (EFI_IPSEC_CONFIG_SELECTOR *) &SaId,
+ &SaData,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Store the local SA into SAD.
+ //
+ ChildSaSession->SpdSelector->RemoteAddressCount = ChildSaSession->SpdSelector->LocalAddressCount;
+ ChildSaSession->SpdSelector->RemoteAddress = ChildSaSession->SpdSelector->LocalAddress;
+
+ ChildSaSession->SpdSelector->LocalAddress = TempAddressInfo;
+ ChildSaSession->SpdSelector->LocalAddressCount = TempAddressCount;
+
+ SaId.Spi = ChildSaSession->RemotePeerSpi;
+
+ CopyMem (&SaId.DestAddress, &ChildSaSession->SessionCommon.RemotePeerIp, sizeof (EFI_IP_ADDRESS));
+ CopyMem (&SaData.AlgoInfo, &ChildSaSession->ChildKeymats.RemotePeerInfo, sizeof (EFI_IPSEC_ALGO_INFO));
+ SaData.SpdSelector = ChildSaSession->SpdSelector;
+
+ //
+ // If it is tunnel mode, should add the TunnelDest and TunnelSource for SaData.
+ //
+ if (SaData.Mode == EfiIPsecTunnel) {
+ CopyMem (
+ &SaData.TunnelSourceAddress,
+ &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->LocalTunnelAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+ CopyMem (
+ &SaData.TunnelDestinationAddress,
+ &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+ }
+
+ Status = EfiIpSecConfigSetData (
+ &Private->IpSecConfig,
+ IPsecConfigDataTypeSad,
+ (EFI_IPSEC_CONFIG_SELECTOR *) &SaId,
+ &SaData,
+ NULL
+ );
+
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Call back function of the IKE life time is over.
+
+ This function will mark the related IKE SA Session as deleting and trigger a
+ Information negotiation.
+
+ @param[in] Event The signaled Event.
+ @param[in] Context Pointer to data passed by caller.
+
+**/
+VOID
+EFIAPI
+Ikev2LifetimeNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SESSION_COMMON *SessionCommon;
+
+ ASSERT (Context != NULL);
+ SessionCommon = (IKEV2_SESSION_COMMON *) Context;
+
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
+ DEBUG ((
+ DEBUG_INFO,
+ "\n---IkeSa Lifetime is out(cookie_i, cookie_r):(0x%lx, 0x%lx)---\n",
+ IkeSaSession->InitiatorCookie,
+ IkeSaSession->ResponderCookie
+ ));
+
+ //
+ // Change the IKE SA Session's State to IKE_STATE_SA_DELETING.
+ //
+ IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateSaDeleting);
+ IkeSaSession->SessionCommon.State = IkeStateSaDeleting;
+
+ } else {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
+ IkeSaSession = ChildSaSession->IkeSaSession;
+
+ //
+ // Link the timeout child SA to the DeleteSaList.
+ //
+ InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete);
+
+ //
+ // Change the Child SA Session's State to IKE_STATE_SA_DELETING.
+ //
+ DEBUG ((
+ DEBUG_INFO,
+ "\n------ChildSa Lifetime is out(SPI):(0x%x)------\n",
+ ChildSaSession->LocalPeerSpi
+ ));
+ }
+
+ //
+ // TODO: Send the delete info packet or delete silently
+ //
+ mIkev2Exchange.NegotiateInfo ((UINT8 *) IkeSaSession, NULL);
+}
+
+/**
+ This function will be called if the TimeOut Event is signaled.
+
+ @param[in] Event The signaled Event.
+ @param[in] Context The data passed by caller.
+
+**/
+VOID
+EFIAPI
+Ikev2ResendNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ IPSEC_PRIVATE_DATA *Private;
+ IKEV2_SA_SESSION *IkeSaSession;
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SESSION_COMMON *SessionCommon;
+ LIST_ENTRY *ChildSaEntry;
+ UINT8 Value;
+ EFI_STATUS Status;
+
+ ASSERT (Context != NULL);
+ IkeSaSession = NULL;
+ ChildSaSession = NULL;
+ SessionCommon = (IKEV2_SESSION_COMMON *) Context;
+ Private = SessionCommon->Private;
+
+ //
+ // Remove the SA session from the processing list if exceed the max retry.
+ //
+ if (SessionCommon->RetryCount > IKE_MAX_RETRY) {
+ if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
+ IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
+ if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) {
+
+ //
+ // If the IkeSaSession is initiator, delete all its Child SAs before removing IKE SA.
+ // If the IkesaSession is responder, all ChildSa has been remove in Ikev2HandleInfo();
+ //
+ for (ChildSaEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;
+ ChildSaEntry != &IkeSaSession->ChildSaEstablishSessionList;
+ ) {
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ChildSaEntry);
+ //
+ // Move to next ChildSa Entry.
+ //
+ ChildSaEntry = ChildSaEntry->ForwardLink;
+ //
+ // Delete LocalSpi & RemoteSpi and remove the ChildSaSession from the
+ // EstablishedChildSaList.
+ //
+ Ikev2ChildSaSilentDelete (IkeSaSession, ChildSaSession->LocalPeerSpi);
+ }
+
+ //
+ // If the IKE SA Delete Payload wasn't sent out successfully, Delete it from the EstablishedList.
+ //
+ Ikev2SaSessionRemove (&Private->Ikev2EstablishedList, &SessionCommon->RemotePeerIp);
+
+ if (Private != NULL && Private->IsIPsecDisabling) {
+ //
+ // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in
+ // IPsec status variable.
+ //
+ if (IsListEmpty (&Private->Ikev1EstablishedList) && IsListEmpty (&Private->Ikev2EstablishedList)) {
+ Value = IPSEC_STATUS_DISABLED;
+ Status = gRT->SetVariable (
+ IPSECCONFIG_STATUS_NAME,
+ &gEfiIpSecConfigProtocolGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (Value),
+ &Value
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set the Disabled Flag in Private data.
+ //
+ Private->IpSec.DisabledFlag = TRUE;
+ Private->IsIPsecDisabling = FALSE;
+ }
+ }
+ }
+ } else {
+ Ikev2SaSessionRemove (&Private->Ikev2SessionList, &SessionCommon->RemotePeerIp);
+ }
+ Ikev2SaSessionFree (IkeSaSession);
+
+ } else {
+
+ //
+ // If the packet sent by Child SA.
+ //
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
+ IkeSaSession = ChildSaSession->IkeSaSession;
+ if (ChildSaSession->SessionCommon.State == IkeStateSaDeleting) {
+
+ //
+ // Established Child SA should be remove from the SAD entry and
+ // DeleteList. The function of Ikev2DeleteChildSaSilent() will remove
+ // the childSA from the IkeSaSession->ChildSaEstablishedList. So there
+ // is no need to remove it here.
+ //
+ Ikev2ChildSaSilentDelete (IkeSaSession, ChildSaSession->LocalPeerSpi);
+ Ikev2ChildSaSessionRemove (
+ &IkeSaSession->DeleteSaList,
+ ChildSaSession->LocalPeerSpi,
+ IKEV2_DELET_CHILDSA_LIST
+ );
+ } else {
+ Ikev2ChildSaSessionRemove (
+ &IkeSaSession->ChildSaSessionList,
+ ChildSaSession->LocalPeerSpi,
+ IKEV2_ESTABLISHING_CHILDSA_LIST
+ );
+ }
+
+ Ikev2ChildSaSessionFree (ChildSaSession);
+ }
+ return ;
+ }
+
+ //
+ // Increase the retry count.
+ //
+ SessionCommon->RetryCount++;
+ DEBUG ((DEBUG_INFO, ">>>Resending the last packet ...\n"));
+
+ //
+ // Resend the last packet.
+ //
+ Ikev2SendIkePacket (
+ SessionCommon->UdpService,
+ (UINT8*)SessionCommon,
+ SessionCommon->LastSentPacket,
+ 0
+ );
+}
+
+/**
+ Copy ChildSaSession->Spd->Selector to ChildSaSession->SpdSelector.
+
+ ChildSaSession->SpdSelector stores the real Spdselector for its SA. Sometime,
+ the SpdSelector in ChildSaSession is more accurated or the scope is smaller
+ than the one in ChildSaSession->Spd, especially for the tunnel mode.
+
+ @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to.
+
+ @retval EFI_SUCCESS The operation complete successfully.
+ @retval EFI_OUT_OF_RESOURCES If the required resource can't be allocated.
+
+**/
+EFI_STATUS
+Ikev2ChildSaSessionSpdSelectorCreate (
+ IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (ChildSaSession->Spd != NULL && ChildSaSession->Spd->Selector != NULL) {
+ if (ChildSaSession->SpdSelector == NULL) {
+ ChildSaSession->SpdSelector = AllocateZeroPool (sizeof (EFI_IPSEC_SPD_SELECTOR));
+ if (ChildSaSession->SpdSelector == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+ }
+ CopyMem (
+ ChildSaSession->SpdSelector,
+ ChildSaSession->Spd->Selector,
+ sizeof (EFI_IPSEC_SPD_SELECTOR)
+ );
+ ChildSaSession->SpdSelector->RemoteAddress = AllocateCopyPool (
+ ChildSaSession->Spd->Selector->RemoteAddressCount *
+ sizeof (EFI_IP_ADDRESS_INFO),
+ ChildSaSession->Spd->Selector->RemoteAddress
+ );
+ if (ChildSaSession->SpdSelector->RemoteAddress == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+
+ FreePool (ChildSaSession->SpdSelector);
+
+ return Status;
+ }
+
+ ChildSaSession->SpdSelector->LocalAddress = AllocateCopyPool (
+ ChildSaSession->Spd->Selector->LocalAddressCount *
+ sizeof (EFI_IP_ADDRESS_INFO),
+ ChildSaSession->Spd->Selector->LocalAddress
+ );
+ if (ChildSaSession->SpdSelector->LocalAddress == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+
+ FreePool (ChildSaSession->SpdSelector->RemoteAddress);
+
+ FreePool (ChildSaSession->SpdSelector);
+
+ return Status;
+ }
+
+ ChildSaSession->SpdSelector->RemoteAddressCount = ChildSaSession->Spd->Selector->RemoteAddressCount;
+ ChildSaSession->SpdSelector->LocalAddressCount = ChildSaSession->Spd->Selector->LocalAddressCount;
+ }
+
+ return Status;
+}
+
+/**
+ Generate a ChildSa Session and insert it into related IkeSaSession.
+
+ @param[in] IkeSaSession Pointer to related IKEV2_SA_SESSION.
+ @param[in] UdpService Pointer to related IKE_UDP_SERVICE.
+
+ @return pointer of IKEV2_CHILD_SA_SESSION.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionCreate (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_UDP_SERVICE *UdpService
+ )
+{
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ IKEV2_SESSION_COMMON *ChildSaCommon;
+
+ //
+ // Create a new ChildSaSession.Insert it into processing list and initiate the common parameters.
+ //
+ ChildSaSession = Ikev2ChildSaSessionAlloc (UdpService, IkeSaSession);
+ if (ChildSaSession == NULL) {
+ return NULL;
+ }
+
+ //
+ // Set the specific parameters.
+ //
+ ChildSaSession->Spd = IkeSaSession->Spd;
+ ChildSaCommon = &ChildSaSession->SessionCommon;
+ ChildSaCommon->IsInitiator = IkeSaSession->SessionCommon.IsInitiator;
+ if (IkeSaSession->SessionCommon.State == IkeStateAuth) {
+ ChildSaCommon->State = IkeStateAuth;
+ IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateAuth);
+ } else {
+ ChildSaCommon->State = IkeStateCreateChild;
+ IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateCreateChild);
+ }
+
+ //
+ // If SPD->Selector is not NULL, copy it to the ChildSaSession->SpdSelector.
+ // The ChildSaSession->SpdSelector might be changed after the traffic selector
+ // negoniation and it will be copied into the SAData after ChildSA established.
+ //
+ if (EFI_ERROR (Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession))) {
+ Ikev2ChildSaSessionFree (ChildSaSession);
+ return NULL;
+ }
+
+ //
+ // Copy first NiBlock and NrBlock to ChildSa Session
+ //
+ ChildSaSession->NiBlock = AllocateZeroPool (IkeSaSession->NiBlkSize);
+ if (ChildSaSession->NiBlock == NULL) {
+ Ikev2ChildSaSessionFree (ChildSaSession);
+ return NULL;
+ }
+
+ ChildSaSession->NiBlkSize = IkeSaSession->NiBlkSize;
+ CopyMem (ChildSaSession->NiBlock, IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);
+
+ ChildSaSession->NrBlock = AllocateZeroPool (IkeSaSession->NrBlkSize);
+ if (ChildSaSession->NrBlock == NULL) {
+ Ikev2ChildSaSessionFree (ChildSaSession);
+ return NULL;
+ }
+
+ ChildSaSession->NrBlkSize = IkeSaSession->NrBlkSize;
+ CopyMem (ChildSaSession->NrBlock, IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);
+
+ //
+ // Only if the Create Child SA is called for the IKE_INIT Exchange and
+ // IkeSaSession is initiator (Only Initiator's SPD is not NULL), Set the
+ // Traffic Selectors related information here.
+ //
+ if (IkeSaSession->SessionCommon.State == IkeStateAuth && IkeSaSession->Spd != NULL) {
+ ChildSaSession->ProtoId = IkeSaSession->Spd->Selector->NextLayerProtocol;
+ ChildSaSession->LocalPort = IkeSaSession->Spd->Selector->LocalPort;
+ ChildSaSession->RemotePort = IkeSaSession->Spd->Selector->RemotePort;
+ }
+
+ //
+ // Insert the new ChildSaSession into processing child SA list.
+ //
+ Ikev2ChildSaSessionInsert (&IkeSaSession->ChildSaSessionList, ChildSaSession);
+ return ChildSaSession;
+}
+
+/**
+ Check if the SPD is related to the input Child SA Session.
+
+ This function is the subfunction of Ikev1AssociateSpdEntry(). It is the call
+ back function of IpSecVisitConfigData().
+
+
+ @param[in] Type Type of the input Config Selector.
+ @param[in] Selector Pointer to the Configure Selector to be checked.
+ @param[in] Data Pointer to the Configure Selector's Data passed
+ from the caller.
+ @param[in] SelectorSize The buffer size of Selector.
+ @param[in] DataSize The buffer size of the Data.
+ @param[in] Context The data passed from the caller. It is a Child
+ SA Session in this context.
+
+ @retval EFI_SUCCESS The SPD Selector is not related to the Child SA Session.
+ @retval EFI_ABORTED The SPD Selector is related to the Child SA session and
+ set the ChildSaSession->Spd to point to this SPD Selector.
+
+**/
+EFI_STATUS
+Ikev2MatchSpdEntry (
+ IN EFI_IPSEC_CONFIG_DATA_TYPE Type,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN UINTN SelectorSize,
+ IN UINTN DataSize,
+ IN VOID *Context
+ )
+{
+ IKEV2_CHILD_SA_SESSION *ChildSaSession;
+ EFI_IPSEC_SPD_SELECTOR *SpdSelector;
+ EFI_IPSEC_SPD_DATA *SpdData;
+ BOOLEAN IsMatch;
+ UINT8 IpVersion;
+
+ ASSERT (Type == IPsecConfigDataTypeSpd);
+ SpdData = (EFI_IPSEC_SPD_DATA *) Data;
+ //
+ // Bypass all non-protect SPD entry first
+ //
+ if (SpdData->Action != EfiIPsecActionProtect) {
+ return EFI_SUCCESS;
+ }
+
+ ChildSaSession = (IKEV2_CHILD_SA_SESSION *) Context;
+ IpVersion = ChildSaSession->SessionCommon.UdpService->IpVersion;
+ SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) Selector;
+ IsMatch = TRUE;
+
+ if (SpdSelector->NextLayerProtocol == EFI_IP_PROTO_UDP &&
+ SpdSelector->LocalPort == IKE_DEFAULT_PORT &&
+ SpdSelector->LocalPortRange == 0 &&
+ SpdSelector->RemotePort == IKE_DEFAULT_PORT &&
+ SpdSelector->RemotePortRange == 0
+ ) {
+ //
+ // TODO: Skip IKE Policy here or set a SPD entry?
+ //
+ return EFI_SUCCESS;
+ }
+
+ if (SpdSelector->NextLayerProtocol != EFI_IPSEC_ANY_PROTOCOL &&
+ SpdSelector->NextLayerProtocol != ChildSaSession->ProtoId
+ ) {
+ IsMatch = FALSE;
+ }
+
+ if (SpdSelector->LocalPort != EFI_IPSEC_ANY_PORT && SpdSelector->LocalPort != ChildSaSession->LocalPort) {
+ IsMatch = FALSE;
+ }
+
+ if (SpdSelector->RemotePort != EFI_IPSEC_ANY_PORT && SpdSelector->RemotePort != ChildSaSession->RemotePort) {
+ IsMatch = FALSE;
+ }
+
+ IsMatch = (BOOLEAN) (IsMatch &&
+ IpSecMatchIpAddress (
+ IpVersion,
+ &ChildSaSession->SessionCommon.LocalPeerIp,
+ SpdSelector->LocalAddress,
+ SpdSelector->LocalAddressCount
+ ));
+
+ IsMatch = (BOOLEAN) (IsMatch &&
+ IpSecMatchIpAddress (
+ IpVersion,
+ &ChildSaSession->SessionCommon.RemotePeerIp,
+ SpdSelector->RemoteAddress,
+ SpdSelector->RemoteAddressCount
+ ));
+
+ if (IsMatch) {
+ ChildSaSession->Spd = IkeSearchSpdEntry (SpdSelector);
+ return EFI_ABORTED;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Check if the Algorithm ID is supported.
+
+ @param[in] AlgorithmId The specified Algorithm ID.
+ @param[in] Type The type used to indicate the Algorithm is for Encrypt or
+ Authentication.
+
+ @retval TRUE If the Algorithm ID is supported.
+ @retval FALSE If the Algorithm ID is not supported.
+
+**/
+BOOLEAN
+Ikev2IsSupportAlg (
+ IN UINT16 AlgorithmId,
+ IN UINT8 Type
+ )
+{
+ UINT8 Index;
+ switch (Type) {
+ case IKE_ENCRYPT_TYPE :
+ for (Index = 0; Index < IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM; Index++) {
+ if (mIkev2EncryptAlgorithmList[Index] == AlgorithmId) {
+ return TRUE;
+ }
+ }
+ break;
+
+ case IKE_AUTH_TYPE :
+ for (Index = 0; Index < IKEV2_SUPPORT_AUTH_ALGORITHM_NUM; Index++) {
+ if (mIkev2AuthAlgorithmList[Index] == AlgorithmId) {
+ return TRUE;
+ }
+ }
+ break;
+
+ case IKE_DH_TYPE :
+ for (Index = 0; Index < IKEV2_SUPPORT_DH_ALGORITHM_NUM; Index++) {
+ if (mIkev2DhGroupAlgorithmList[Index] == AlgorithmId) {
+ return TRUE;
+ }
+ }
+ break;
+
+ case IKE_PRF_TYPE :
+ for (Index = 0; Index < IKEV2_SUPPORT_PRF_ALGORITHM_NUM; Index++) {
+ if (mIkev2PrfAlgorithmList[Index] == AlgorithmId) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Get the preferred algorithm types from ProposalData.
+
+ @param[in] ProposalData Pointer to related IKEV2_PROPOSAL_DATA.
+ @param[out] PreferEncryptAlgorithm Output of preferred encrypt algorithm.
+ @param[out] PreferIntegrityAlgorithm Output of preferred integrity algorithm.
+ @param[out] PreferPrfAlgorithm Output of preferred PRF algorithm. Only
+ for IKE SA.
+ @param[out] PreferDhGroup Output of preferred DH group. Only for
+ IKE SA.
+ @param[out] PreferEncryptKeylength Output of preferred encrypt key length
+ in bytes.
+ @param[out] IsSupportEsn Output of value about the Extented Sequence
+ Number is support or not. Only for Child SA.
+ @param[in] IsChildSa If it is ture, the ProposalData is for IKE
+ SA. Otherwise the proposalData is for Child SA.
+
+**/
+VOID
+Ikev2ParseProposalData (
+ IN IKEV2_PROPOSAL_DATA *ProposalData,
+ OUT UINT16 *PreferEncryptAlgorithm,
+ OUT UINT16 *PreferIntegrityAlgorithm,
+ OUT UINT16 *PreferPrfAlgorithm,
+ OUT UINT16 *PreferDhGroup,
+ OUT UINTN *PreferEncryptKeylength,
+ OUT BOOLEAN *IsSupportEsn,
+ IN BOOLEAN IsChildSa
+)
+{
+ IKEV2_TRANSFORM_DATA *TransformData;
+ UINT8 TransformIndex;
+
+ //
+ // Check input parameters.
+ //
+ if (ProposalData == NULL ||
+ PreferEncryptAlgorithm == NULL ||
+ PreferIntegrityAlgorithm == NULL ||
+ PreferEncryptKeylength == NULL
+ ) {
+ return;
+ }
+
+ if (IsChildSa) {
+ if (IsSupportEsn == NULL) {
+ return;
+ }
+ } else {
+ if (PreferPrfAlgorithm == NULL || PreferDhGroup == NULL) {
+ return;
+ }
+ }
+
+ TransformData = (IKEV2_TRANSFORM_DATA *)(ProposalData + 1);
+ for (TransformIndex = 0; TransformIndex < ProposalData->NumTransforms; TransformIndex++) {
+ switch (TransformData->TransformType) {
+ //
+ // For IKE SA there are four algorithm types. Encryption Algorithm, Pseudo-random Function,
+ // Integrity Algorithm, Diffie-Hellman Group. For Child SA, there are three algorithm types.
+ // Encryption Algorithm, Integrity Algorithm, Extended Sequence Number.
+ //
+ case IKEV2_TRANSFORM_TYPE_ENCR:
+ if (*PreferEncryptAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_ENCRYPT_TYPE)) {
+ //
+ // Check the attribute value. According to RFC, only Keylength is support.
+ //
+ if (TransformData->Attribute.AttrType == IKEV2_ATTRIBUTE_TYPE_KEYLEN) {
+ //
+ // If the Keylength is not support, continue to check the next one.
+ //
+ if (IpSecGetEncryptKeyLength ((UINT8)TransformData->TransformId) != (UINTN)(TransformData->Attribute.Attr.AttrValue >> 3)){
+ break;
+ } else {
+ *PreferEncryptKeylength = TransformData->Attribute.Attr.AttrValue;
+ }
+ }
+ *PreferEncryptAlgorithm = TransformData->TransformId;
+ }
+ break;
+
+ case IKEV2_TRANSFORM_TYPE_PRF :
+ if (!IsChildSa) {
+ if (*PreferPrfAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_PRF_TYPE)) {
+ *PreferPrfAlgorithm = TransformData->TransformId;
+ }
+ }
+ break;
+
+ case IKEV2_TRANSFORM_TYPE_INTEG :
+ if (*PreferIntegrityAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_AUTH_TYPE)) {
+ *PreferIntegrityAlgorithm = TransformData->TransformId;
+ }
+ break;
+
+ case IKEV2_TRANSFORM_TYPE_DH :
+ if (!IsChildSa) {
+ if (*PreferDhGroup == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_DH_TYPE)) {
+ *PreferDhGroup = TransformData->TransformId;
+ }
+ }
+ break;
+
+ case IKEV2_TRANSFORM_TYPE_ESN :
+ if (IsChildSa) {
+ if (TransformData->TransformId != 0) {
+ *IsSupportEsn = TRUE;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ TransformData = (IKEV2_TRANSFORM_DATA *)(TransformData + 1);
+ }
+}
+
+/**
+ Parse the received Initial Exchange Packet.
+
+ This function parse the SA Payload and Key Payload to find out the cryptographic
+ suite for the further IKE negotiation and fill it into the IKE SA Session's
+ CommonSession->SaParams.
+
+ @param[in, out] IkeSaSession Pointer to related IKEV2_SA_SESSION.
+ @param[in] SaPayload The received packet.
+ @param[in] Type The received packet IKE header flag.
+
+ @retval TRUE If the SA proposal in Packet is acceptable.
+ @retval FALSE If the SA proposal in Packet is not acceptable.
+
+**/
+BOOLEAN
+Ikev2SaParseSaPayload (
+ IN OUT IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_PAYLOAD *SaPayload,
+ IN UINT8 Type
+ )
+{
+ IKEV2_PROPOSAL_DATA *ProposalData;
+ UINT8 ProposalIndex;
+ UINT16 PreferEncryptAlgorithm;
+ UINT16 PreferIntegrityAlgorithm;
+ UINT16 PreferPrfAlgorithm;
+ UINT16 PreferDhGroup;
+ UINTN PreferEncryptKeylength;
+ UINT16 EncryptAlgorithm;
+ UINT16 IntegrityAlgorithm;
+ UINT16 PrfAlgorithm;
+ UINT16 DhGroup;
+ UINTN EncryptKeylength;
+ BOOLEAN IsMatch;
+ UINTN SaDataSize;
+
+ PreferPrfAlgorithm = 0;
+ PreferIntegrityAlgorithm = 0;
+ PreferDhGroup = 0;
+ PreferEncryptAlgorithm = 0;
+ PreferEncryptKeylength = 0;
+ PrfAlgorithm = 0;
+ IntegrityAlgorithm = 0;
+ DhGroup = 0;
+ EncryptAlgorithm = 0;
+ EncryptKeylength = 0;
+ IsMatch = FALSE;
+
+ if (Type == IKE_HEADER_FLAGS_INIT) {
+ ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1);
+ for (ProposalIndex = 0; ProposalIndex < ((IKEV2_SA_DATA *)SaPayload->PayloadBuf)->NumProposals; ProposalIndex++) {
+ //
+ // Iterate each proposal to find the perfered one.
+ //
+ if (ProposalData->ProtocolId == IPSEC_PROTO_ISAKMP && ProposalData->NumTransforms >= 4) {
+ //
+ // Get the preferred algorithms.
+ //
+ Ikev2ParseProposalData (
+ ProposalData,
+ &PreferEncryptAlgorithm,
+ &PreferIntegrityAlgorithm,
+ &PreferPrfAlgorithm,
+ &PreferDhGroup,
+ &PreferEncryptKeylength,
+ NULL,
+ FALSE
+ );
+
+ if (PreferEncryptAlgorithm != 0 &&
+ PreferIntegrityAlgorithm != 0 &&
+ PreferPrfAlgorithm != 0 &&
+ PreferDhGroup != 0
+ ) {
+ //
+ // Find the matched one.
+ //
+ IkeSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));
+ if (IkeSaSession->SessionCommon.SaParams == NULL) {
+ return FALSE;
+ }
+
+ IkeSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm;
+ IkeSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength;
+ IkeSaSession->SessionCommon.SaParams->DhGroup = PreferDhGroup;
+ IkeSaSession->SessionCommon.SaParams->Prf = PreferPrfAlgorithm;
+ IkeSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;
+ IkeSaSession->SessionCommon.PreferDhGroup = PreferDhGroup;
+
+ //
+ // Save the matched one in IKEV2_SA_DATA for furthure calculation.
+ //
+ SaDataSize = sizeof (IKEV2_SA_DATA) +
+ sizeof (IKEV2_PROPOSAL_DATA) +
+ sizeof (IKEV2_TRANSFORM_DATA) * 4;
+ IkeSaSession->SaData = AllocateZeroPool (SaDataSize);
+ if (IkeSaSession->SaData == NULL) {
+ FreePool (IkeSaSession->SessionCommon.SaParams);
+ return FALSE;
+ }
+
+ IkeSaSession->SaData->NumProposals = 1;
+
+ //
+ // BUGBUG: Suppose the matched proposal only has 4 transforms. If
+ // The matched Proposal has more than 4 transforms means it contains
+ // one than one transform with same type.
+ //
+ CopyMem (
+ (IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1),
+ ProposalData,
+ SaDataSize - sizeof (IKEV2_SA_DATA)
+ );
+
+ ((IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1))->ProposalIndex = 1;
+
+ return TRUE;
+ } else {
+ PreferEncryptAlgorithm = 0;
+ PreferIntegrityAlgorithm = 0;
+ PreferPrfAlgorithm = 0;
+ PreferDhGroup = 0;
+ PreferEncryptKeylength = 0;
+ }
+ }
+ //
+ // Point to next Proposal.
+ //
+ ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) +
+ ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));
+ }
+ } else if (Type == IKE_HEADER_FLAGS_RESPOND) {
+ //
+ // First check the SA proposal's ProtoctolID and Transform Numbers. Since it is
+ // the responded SA proposal, suppose it only has one proposal and the transform Numbers
+ // is 4.
+ //
+ ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *) SaPayload->PayloadBuf + 1);
+ if (ProposalData->ProtocolId != IPSEC_PROTO_ISAKMP || ProposalData->NumTransforms != 4) {
+ return FALSE;
+ }
+ //
+ // Get the preferred algorithms.
+ //
+ Ikev2ParseProposalData (
+ ProposalData,
+ &PreferEncryptAlgorithm,
+ &PreferIntegrityAlgorithm,
+ &PreferPrfAlgorithm,
+ &PreferDhGroup,
+ &PreferEncryptKeylength,
+ NULL,
+ FALSE
+ );
+ //
+ // Check if the Sa proposal data from received packet is in the IkeSaSession->SaData.
+ //
+ ProposalData = (IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1);
+
+ for (ProposalIndex = 0; ProposalIndex < IkeSaSession->SaData->NumProposals && (!IsMatch); ProposalIndex++) {
+ Ikev2ParseProposalData (
+ ProposalData,
+ &EncryptAlgorithm,
+ &IntegrityAlgorithm,
+ &PrfAlgorithm,
+ &DhGroup,
+ &EncryptKeylength,
+ NULL,
+ FALSE
+ );
+ if (EncryptAlgorithm == PreferEncryptAlgorithm &&
+ EncryptKeylength == PreferEncryptKeylength &&
+ IntegrityAlgorithm == PreferIntegrityAlgorithm &&
+ PrfAlgorithm == PreferPrfAlgorithm &&
+ DhGroup == PreferDhGroup
+ ) {
+ IsMatch = TRUE;
+ } else {
+ EncryptAlgorithm = 0;
+ IntegrityAlgorithm = 0;
+ PrfAlgorithm = 0;
+ DhGroup = 0;
+ EncryptKeylength = 0;
+ }
+
+ ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) +
+ ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));
+ }
+
+ if (IsMatch) {
+ IkeSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));
+ if (IkeSaSession->SessionCommon.SaParams == NULL) {
+ return FALSE;
+ }
+
+ IkeSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm;
+ IkeSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength;
+ IkeSaSession->SessionCommon.SaParams->DhGroup = PreferDhGroup;
+ IkeSaSession->SessionCommon.SaParams->Prf = PreferPrfAlgorithm;
+ IkeSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;
+ IkeSaSession->SessionCommon.PreferDhGroup = PreferDhGroup;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Parse the received Authentication Exchange Packet.
+
+ This function parse the SA Payload and Key Payload to find out the cryptographic
+ suite for the ESP and fill it into the Child SA Session's CommonSession->SaParams.
+
+ @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to
+ this Authentication Exchange.
+ @param[in] SaPayload The received packet.
+ @param[in] Type The IKE header's flag of received packet .
+
+ @retval TRUE If the SA proposal in Packet is acceptable.
+ @retval FALSE If the SA proposal in Packet is not acceptable.
+
+**/
+BOOLEAN
+Ikev2ChildSaParseSaPayload (
+ IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession,
+ IN IKE_PAYLOAD *SaPayload,
+ IN UINT8 Type
+ )
+{
+ IKEV2_PROPOSAL_DATA *ProposalData;
+ UINT8 ProposalIndex;
+ UINT16 PreferEncryptAlgorithm;
+ UINT16 PreferIntegrityAlgorithm;
+ UINTN PreferEncryptKeylength;
+ BOOLEAN PreferIsSupportEsn;
+ UINT16 EncryptAlgorithm;
+ UINT16 IntegrityAlgorithm;
+ UINTN EncryptKeylength;
+ BOOLEAN IsSupportEsn;
+ BOOLEAN IsMatch;
+ UINTN SaDataSize;
+
+
+ PreferIntegrityAlgorithm = 0;
+ PreferEncryptAlgorithm = 0;
+ PreferEncryptKeylength = 0;
+ IntegrityAlgorithm = 0;
+ EncryptAlgorithm = 0;
+ EncryptKeylength = 0;
+ IsMatch = TRUE;
+ IsSupportEsn = FALSE;
+ PreferIsSupportEsn = FALSE;
+
+ if (Type == IKE_HEADER_FLAGS_INIT) {
+ ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *) SaPayload->PayloadBuf + 1);
+ for (ProposalIndex = 0; ProposalIndex < ((IKEV2_SA_DATA *) SaPayload->PayloadBuf)->NumProposals; ProposalIndex++) {
+ //
+ // Iterate each proposal to find the preferred one.
+ //
+ if (ProposalData->ProtocolId == IPSEC_PROTO_IPSEC_ESP && ProposalData->NumTransforms >= 3) {
+ //
+ // Get the preferred algorithm.
+ //
+ Ikev2ParseProposalData (
+ ProposalData,
+ &PreferEncryptAlgorithm,
+ &PreferIntegrityAlgorithm,
+ NULL,
+ NULL,
+ &PreferEncryptKeylength,
+ &IsSupportEsn,
+ TRUE
+ );
+ //
+ // Don't support the ESN now.
+ //
+ if (PreferEncryptAlgorithm != 0 &&
+ PreferIntegrityAlgorithm != 0 &&
+ !IsSupportEsn
+ ) {
+ //
+ // Find the matched one.
+ //
+ ChildSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));
+ if (ChildSaSession->SessionCommon.SaParams == NULL) {
+ return FALSE;
+ }
+
+ ChildSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm;
+ ChildSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength;
+ ChildSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;
+ CopyMem (&ChildSaSession->RemotePeerSpi, ProposalData->Spi, sizeof (ChildSaSession->RemotePeerSpi));
+
+ //
+ // Save the matched one in IKEV2_SA_DATA for furthure calculation.
+ //
+ SaDataSize = sizeof (IKEV2_SA_DATA) +
+ sizeof (IKEV2_PROPOSAL_DATA) +
+ sizeof (IKEV2_TRANSFORM_DATA) * 4;
+
+ ChildSaSession->SaData = AllocateZeroPool (SaDataSize);
+ if (ChildSaSession->SaData == NULL) {
+ FreePool (ChildSaSession->SessionCommon.SaParams);
+ return FALSE;
+ }
+
+ ChildSaSession->SaData->NumProposals = 1;
+
+ //
+ // BUGBUG: Suppose there are 4 transforms in the matched proposal. If
+ // the matched Proposal has more than 4 transforms that means there
+ // are more than one transform with same type.
+ //
+ CopyMem (
+ (IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1),
+ ProposalData,
+ SaDataSize - sizeof (IKEV2_SA_DATA)
+ );
+
+ ((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->ProposalIndex = 1;
+
+ ((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->Spi = AllocateCopyPool (
+ sizeof (ChildSaSession->LocalPeerSpi),
+ &ChildSaSession->LocalPeerSpi
+ );
+ if (((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->Spi == NULL) {
+ FreePool (ChildSaSession->SessionCommon.SaParams);
+
+ FreePool (ChildSaSession->SaData );
+
+ return FALSE;
+ }
+
+ return TRUE;
+
+ } else {
+ PreferEncryptAlgorithm = 0;
+ PreferIntegrityAlgorithm = 0;
+ IsSupportEsn = TRUE;
+ }
+ }
+ //
+ // Point to next Proposal
+ //
+ ProposalData = (IKEV2_PROPOSAL_DATA *)((UINT8 *)(ProposalData + 1) +
+ ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));
+ }
+ } else if (Type == IKE_HEADER_FLAGS_RESPOND) {
+ //
+ // First check the SA proposal's ProtoctolID and Transform Numbers. Since it is
+ // the responded SA proposal, suppose it only has one proposal and the transform Numbers
+ // is 3.
+ //
+ ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1);
+ if (ProposalData->ProtocolId != IPSEC_PROTO_IPSEC_ESP || ProposalData->NumTransforms != 3) {
+ return FALSE;
+ }
+ //
+ // Get the preferred algorithms.
+ //
+ Ikev2ParseProposalData (
+ ProposalData,
+ &PreferEncryptAlgorithm,
+ &PreferIntegrityAlgorithm,
+ NULL,
+ NULL,
+ &PreferEncryptKeylength,
+ &PreferIsSupportEsn,
+ TRUE
+ );
+
+ ProposalData = (IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1);
+
+ for (ProposalIndex = 0; ProposalIndex < ChildSaSession->SaData->NumProposals && (!IsMatch); ProposalIndex++) {
+ Ikev2ParseProposalData (
+ ProposalData,
+ &EncryptAlgorithm,
+ &IntegrityAlgorithm,
+ NULL,
+ NULL,
+ &EncryptKeylength,
+ &IsSupportEsn,
+ TRUE
+ );
+ if (EncryptAlgorithm == PreferEncryptAlgorithm &&
+ EncryptKeylength == PreferEncryptKeylength &&
+ IntegrityAlgorithm == PreferIntegrityAlgorithm &&
+ IsSupportEsn == PreferIsSupportEsn
+ ) {
+ IsMatch = TRUE;
+ } else {
+ PreferEncryptAlgorithm = 0;
+ PreferIntegrityAlgorithm = 0;
+ IsSupportEsn = TRUE;
+ }
+ ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) +
+ ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));
+ }
+
+ ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1);
+ if (IsMatch) {
+ ChildSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));
+ if (ChildSaSession->SessionCommon.SaParams == NULL) {
+ return FALSE;
+ }
+
+ ChildSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm;
+ ChildSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength;
+ ChildSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;
+ CopyMem (&ChildSaSession->RemotePeerSpi, ProposalData->Spi, sizeof (ChildSaSession->RemotePeerSpi));
+
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Generate Key buffer from fragments.
+
+ If the digest length of specified HashAlgId is larger than or equal with the
+ required output key length, derive the key directly. Otherwise, Key Material
+ needs to be PRF-based concatenation according to 2.13 of RFC 4306:
+ prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01),
+ T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04)
+ then derive the key from this key material.
+
+ @param[in] HashAlgId The Hash Algorithm ID used to generate key.
+ @param[in] HashKey Pointer to a key buffer which contains hash key.
+ @param[in] HashKeyLength The length of HashKey in bytes.
+ @param[in, out] OutputKey Pointer to buffer which is used to receive the
+ output key.
+ @param[in] OutputKeyLength The length of OutPutKey buffer.
+ @param[in] Fragments Pointer to the data to be used to generate key.
+ @param[in] NumFragments The numbers of the Fragement.
+
+ @retval EFI_SUCCESS The operation complete successfully.
+ @retval EFI_INVALID_PARAMETER If NumFragments is zero.
+ @retval EFI_OUT_OF_RESOURCES If the required resource can't be allocated.
+ @retval Others The operation is failed.
+
+**/
+EFI_STATUS
+Ikev2SaGenerateKey (
+ IN UINT8 HashAlgId,
+ IN UINT8 *HashKey,
+ IN UINTN HashKeyLength,
+ IN OUT UINT8 *OutputKey,
+ IN UINTN OutputKeyLength,
+ IN PRF_DATA_FRAGMENT *Fragments,
+ IN UINTN NumFragments
+ )
+{
+ EFI_STATUS Status;
+ PRF_DATA_FRAGMENT LocalFragments[3];
+ UINT8 *Digest;
+ UINTN DigestSize;
+ UINTN Round;
+ UINTN Index;
+ UINTN AuthKeyLength;
+ UINTN FragmentsSize;
+ UINT8 TailData;
+
+ Status = EFI_SUCCESS;
+
+ if (NumFragments == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ LocalFragments[0].Data = NULL;
+ LocalFragments[1].Data = NULL;
+ LocalFragments[2].Data = NULL;
+
+ AuthKeyLength = IpSecGetHmacDigestLength (HashAlgId);
+ DigestSize = AuthKeyLength;
+ Digest = AllocateZeroPool (AuthKeyLength);
+
+ if (Digest == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // If the required output key length is less than the digest size,
+ // copy the digest into OutputKey.
+ //
+ if (OutputKeyLength <= DigestSize) {
+ Status = IpSecCryptoIoHmac (
+ HashAlgId,
+ HashKey,
+ HashKeyLength,
+ (HASH_DATA_FRAGMENT *) Fragments,
+ NumFragments,
+ Digest,
+ DigestSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ CopyMem (OutputKey, Digest, OutputKeyLength);
+ goto Exit;
+ }
+
+ //
+ //Otherwise, Key Material need to be PRF-based concatenation according to 2.13
+ //of RFC 4306: prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01),
+ //T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04)
+ //then derive the key from this key material.
+ //
+ FragmentsSize = 0;
+ for (Index = 0; Index < NumFragments; Index++) {
+ FragmentsSize = FragmentsSize + Fragments[Index].DataSize;
+ }
+
+ LocalFragments[1].Data = AllocateZeroPool (FragmentsSize);
+ if (LocalFragments[1].Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ LocalFragments[1].DataSize = FragmentsSize;
+
+ //
+ // Copy all input fragments into LocalFragments[1];
+ //
+ FragmentsSize = 0;
+ for (Index = 0; Index < NumFragments; Index++) {
+ CopyMem (
+ LocalFragments[1].Data + FragmentsSize,
+ Fragments[Index].Data,
+ Fragments[Index].DataSize
+ );
+ FragmentsSize = FragmentsSize + Fragments[Index].DataSize;
+ }
+
+ //
+ // Prepare 0x01 as the first tail data.
+ //
+ TailData = 0x01;
+ LocalFragments[2].Data = &TailData;
+ LocalFragments[2].DataSize = sizeof (TailData);
+ //
+ // Allocate buffer for the first fragment
+ //
+ LocalFragments[0].Data = AllocateZeroPool (AuthKeyLength);
+ if (LocalFragments[0].Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ LocalFragments[0].DataSize = AuthKeyLength;
+
+ Round = (OutputKeyLength - 1) / AuthKeyLength + 1;
+ for (Index = 0; Index < Round; Index++) {
+ Status = IpSecCryptoIoHmac (
+ HashAlgId,
+ HashKey,
+ HashKeyLength,
+ (HASH_DATA_FRAGMENT *)(Index == 0 ? &LocalFragments[1] : LocalFragments),
+ Index == 0 ? 2 : 3,
+ Digest,
+ DigestSize
+ );
+ if (EFI_ERROR(Status)) {
+ goto Exit;
+ }
+ CopyMem (
+ LocalFragments[0].Data,
+ Digest,
+ DigestSize
+ );
+ if (OutputKeyLength > DigestSize * (Index + 1)) {
+ CopyMem (
+ OutputKey + Index * DigestSize,
+ Digest,
+ DigestSize
+ );
+ LocalFragments[0].DataSize = DigestSize;
+ TailData ++;
+ } else {
+ //
+ // The last round
+ //
+ CopyMem (
+ OutputKey + Index * DigestSize,
+ Digest,
+ OutputKeyLength - Index * DigestSize
+ );
+ }
+ }
+
+Exit:
+ //
+ // Only First and second Framgement Data need to be freed.
+ //
+ for (Index = 0 ; Index < 2; Index++) {
+ if (LocalFragments[Index].Data != NULL) {
+ FreePool (LocalFragments[Index].Data);
+ }
+ }
+ if (Digest != NULL) {
+ FreePool (Digest);
+ }
+ return Status;
+}
+
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/Utility.h b/Core/NetworkPkg/IpSecDxe/Ikev2/Utility.h
new file mode 100644
index 0000000000..319b6cb32c
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Utility.h
@@ -0,0 +1,1134 @@
+/** @file
+ The interfaces of IKE/Child session operations and payload related operations
+ used by IKE Exchange Process.
+
+ Copyright (c) 2010 - 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.
+
+**/
+
+#ifndef _IKE_V2_UTILITY_H_
+#define _IKE_V2_UTILITY_H_
+
+#include "Ikev2.h"
+#include "IkeCommon.h"
+#include "IpSecCryptIo.h"
+
+#include <Library/PcdLib.h>
+
+#define IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM 2
+#define IKEV2_SUPPORT_PRF_ALGORITHM_NUM 1
+#define IKEV2_SUPPORT_DH_ALGORITHM_NUM 2
+#define IKEV2_SUPPORT_AUTH_ALGORITHM_NUM 1
+
+/**
+ Allocate buffer for IKEV2_SA_SESSION and initialize it.
+
+ @param[in] Private Pointer to IPSEC_PRIVATE_DATA.
+ @param[in] UdpService Pointer to IKE_UDP_SERVICE related to this IKE SA Session.
+
+ @return Pointer to IKEV2_SA_SESSION.
+
+**/
+IKEV2_SA_SESSION *
+Ikev2SaSessionAlloc (
+ IN IPSEC_PRIVATE_DATA *Private,
+ IN IKE_UDP_SERVICE *UdpService
+ );
+
+/**
+ Register Establish IKEv2 SA into Private->Ikev2EstablishedList.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be registered.
+ @param[in] Private Pointer to IPSEC_PRAVATE_DATA.
+
+**/
+VOID
+Ikev2SaSessionReg (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IPSEC_PRIVATE_DATA *Private
+ );
+
+/**
+ Find a IKEV2_SA_SESSION by the remote peer IP.
+
+ @param[in] SaSessionList SaSession List to be searched.
+ @param[in] RemotePeerIp Pointer to specified IP address.
+
+ @return Pointer to IKEV2_SA_SESSION if find one or NULL.
+
+**/
+IKEV2_SA_SESSION *
+Ikev2SaSessionLookup (
+ IN LIST_ENTRY *SaSessionList,
+ IN EFI_IP_ADDRESS *RemotePeerIp
+ );
+
+/**
+ Insert a IKE_SA_SESSION into IkeSaSession list. The IkeSaSession list is either
+ Private->Ikev2SaSession list or Private->Ikev2EstablishedList list.
+
+ @param[in] SaSessionList Pointer to list to be inserted into.
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be inserted.
+ @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESSS to indicate the
+ unique IKEV2_SA_SESSION.
+
+**/
+VOID
+Ikev2SaSessionInsert (
+ IN LIST_ENTRY *SaSessionList,
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN EFI_IP_ADDRESS *RemotePeerIp
+ );
+
+/**
+ Remove the SA Session by Remote Peer IP.
+
+ @param[in] SaSessionList Pointer to list to be searched.
+ @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESS to use for SA Session search.
+
+ @retval Pointer to IKEV2_SA_SESSION with the specified remote IP address.
+
+**/
+IKEV2_SA_SESSION *
+Ikev2SaSessionRemove (
+ IN LIST_ENTRY *SaSessionList,
+ IN EFI_IP_ADDRESS *RemotePeerIp
+ );
+
+
+/**
+ Marking a SA session as on deleting.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION.
+
+ @retval EFI_SUCCESS Find the related SA session and marked it.
+
+**/
+EFI_STATUS
+Ikev2SaSessionOnDeleting (
+ IN IKEV2_SA_SESSION *IkeSaSession
+ );
+
+/**
+ After IKE/Child SA is estiblished, close the time event and free sent packet.
+
+ @param[in] SessionCommon Pointer to a Session Common.
+
+**/
+VOID
+Ikev2SessionCommonRefresh (
+ IN IKEV2_SESSION_COMMON *SessionCommon
+ );
+
+/**
+ Free specified IKEV2 SA Session.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be freed.
+
+**/
+VOID
+Ikev2SaSessionFree (
+ IN IKEV2_SA_SESSION *IkeSaSession
+ );
+
+/**
+ Free specified Seession Common. The session common would belong to a IKE SA or
+ a Child SA.
+
+ @param[in] SessionCommon Pointer to a Session Common.
+
+**/
+VOID
+Ikev2SaSessionCommonFree (
+ IN IKEV2_SESSION_COMMON *SessionCommon
+ );
+
+/**
+ Increase the MessageID in IkeSaSession.
+
+ @param[in] IkeSaSession Pointer to a specified IKEV2_SA_SESSION.
+
+**/
+VOID
+Ikev2SaSessionIncreaseMessageId (
+ IN IKEV2_SA_SESSION *IkeSaSession
+ );
+
+/**
+ Allocate Momery for IKEV2 Child SA Session.
+
+ @param[in] UdpService Pointer to IKE_UDP_SERVICE.
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this Child SA
+ Session.
+
+ @retval Pointer of a new created IKEV2 Child SA Session.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionAlloc (
+ IN IKE_UDP_SERVICE *UdpService,
+ IN IKEV2_SA_SESSION *IkeSaSession
+ );
+
+/**
+ Register a established IKEv2 Child SA into IkeSaSession->ChildSaEstablishSessionList.
+ If the there is IKEV2_CHILD_SA_SESSION with same remote peer IP, remove the old one
+ then register the new one.
+
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be registered.
+ @param[in] Private Pointer to IPSEC_PRAVATE_DATA.
+
+**/
+VOID
+Ikev2ChildSaSessionReg (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession,
+ IN IPSEC_PRIVATE_DATA *Private
+ );
+
+/**
+ This function find the Child SA by the specified Spi.
+
+ This functin find a ChildSA session by searching the ChildSaSessionlist of
+ the input IKEV2_SA_SESSION by specified MessageID.
+
+ @param[in] SaSessionList Pointer to List to be searched.
+ @param[in] Spi Specified SPI.
+
+ @return Pointer to IKEV2_CHILD_SA_SESSION.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionLookupBySpi (
+ IN LIST_ENTRY *SaSessionList,
+ IN UINT32 Spi
+ );
+
+/**
+ Find the ChildSaSession by it's MessagId.
+
+ @param[in] SaSessionList Pointer to a ChildSaSession List.
+ @param[in] Mid The messageId used to search ChildSaSession.
+
+ @return Pointer to IKEV2_CHILD_SA_SESSION.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionLookupByMid (
+ IN LIST_ENTRY *SaSessionList,
+ IN UINT32 Mid
+ );
+
+/**
+ Insert a Child SA Session into the specified ChildSa list..
+
+ @param[in] SaSessionList Pointer to list to be inserted in.
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be inserted.
+
+**/
+VOID
+Ikev2ChildSaSessionInsert (
+ IN LIST_ENTRY *SaSessionList,
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession
+ );
+
+/**
+ Remove the IKEV2_CHILD_SA_SESSION from IkeSaSessionList.
+
+ @param[in] SaSessionList The SA Session List to be iterated.
+ @param[in] Spi Spi used to identify the IKEV2_CHILD_SA_SESSION.
+ @param[in] ListType The type of the List to indicate whether it is a
+ Established.
+
+ @return The point to IKEV2_CHILD_SA_SESSION.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionRemove (
+ IN LIST_ENTRY *SaSessionList,
+ IN UINT32 Spi,
+ IN UINT8 ListType
+ );
+
+/**
+ Mark a specified Child SA Session as on deleting.
+
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION.
+
+ @retval EFI_SUCCESS Operation is successful.
+
+**/
+EFI_STATUS
+Ikev2ChildSaSessionOnDeleting (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession
+ );
+
+/**
+ Free the memory located for the specified IKEV2_CHILD_SA_SESSION.
+
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION.
+
+**/
+VOID
+Ikev2ChildSaSessionFree (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession
+ );
+
+/**
+ Free the specified DhBuffer.
+
+ @param[in] DhBuffer Pointer to IKEV2_DH_BUFFER to be freed.
+
+**/
+VOID
+Ikev2DhBufferFree (
+ IN IKEV2_DH_BUFFER *DhBuffer
+ );
+
+/**
+ Delete the specified established Child SA.
+
+ This function delete the Child SA directly and dont send the Information Packet to
+ remote peer.
+
+ @param[in] IkeSaSession Pointer to a IKE SA Session used to be searched for.
+ @param[in] Spi SPI used to find the Child SA.
+
+ @retval EFI_NOT_FOUND Pointer of IKE SA Session is NULL.
+ @retval EFI_NOT_FOUND There is no specified Child SA related with the input
+ SPI under this IKE SA Session.
+ @retval EFI_SUCCESS Delete the Child SA successfully.
+
+**/
+EFI_STATUS
+Ikev2ChildSaSilentDelete (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT32 Spi
+ );
+
+/**
+ This function is to parse a request IKE packet and return its request type.
+ The request type is one of IKE CHILD SA creation, IKE SA rekeying and
+ IKE CHILD SA rekeying.
+
+ @param[in] IkePacket IKE packet to be prased.
+
+ return the type of the IKE packet.
+
+**/
+IKEV2_CREATE_CHILD_REQUEST_TYPE
+Ikev2ChildExchangeRequestType(
+ IN IKE_PACKET *IkePacket
+ );
+
+/**
+ This function finds the SPI from Create Child Sa Exchange Packet.
+
+ @param[in] IkePacket Pointer to IKE_PACKET to be searched.
+
+ @retval SPI number.
+
+**/
+UINT32
+Ikev2ChildExchangeRekeySpi(
+ IN IKE_PACKET *IkePacket
+ );
+
+
+/**
+ Associate a SPD selector to the Child SA Session.
+
+ This function is called when the Child SA is not the first child SA of its
+ IKE SA. It associate a SPD to this Child SA.
+
+ @param[in, out] ChildSaSession Pointer to the Child SA Session to be associated to
+ a SPD selector.
+
+ @retval EFI_SUCCESS Associate one SPD selector to this Child SA Session successfully.
+ @retval EFI_NOT_FOUND Can't find the related SPD selector.
+
+**/
+EFI_STATUS
+Ikev2ChildSaAssociateSpdEntry (
+ IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession
+ );
+
+/**
+ Validate the IKE header of received IKE packet.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this IKE packet.
+ @param[in] IkeHdr Pointer to IKE header of received IKE packet.
+
+ @retval TRUE If the IKE header is valid.
+ @retval FALSE If the IKE header is invalid.
+
+**/
+BOOLEAN
+Ikev2ValidateHeader (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_HEADER *IkeHdr
+ );
+
+/**
+ Create and intialize IKEV2_SA_DATA for speicifed IKEV2_SESSION_COMMON.
+
+ This function will be only called by the initiator. The responder's IKEV2_SA_DATA
+ will be generated during parsed the initiator packet.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to.
+
+ @retval a Pointer to a new IKEV2_SA_DATA or NULL.
+
+**/
+IKEV2_SA_DATA *
+Ikev2InitializeSaData (
+ IN IKEV2_SESSION_COMMON *SessionCommon
+ );
+
+/**
+ Store the SA into SAD.
+
+ @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION.
+
+**/
+VOID
+Ikev2StoreSaData (
+ IN IKEV2_CHILD_SA_SESSION *ChildSaSession
+ );
+
+/**
+ Routine process before the payload decoding.
+
+ @param[in] SessionCommon Pointer to ChildSa SessionCommon.
+ @param[in] PayloadBuf Pointer to the payload.
+ @param[in] PayloadSize Size of PayloadBuf in byte.
+ @param[in] PayloadType Type of Payload.
+
+**/
+VOID
+Ikev2ChildSaBeforeDecodePayload (
+ IN UINT8 *SessionCommon,
+ IN UINT8 *PayloadBuf,
+ IN UINTN PayloadSize,
+ IN UINT8 PayloadType
+ );
+
+/**
+ Routine Process after the encode payload.
+
+ @param[in] SessionCommon Pointer to ChildSa SessionCommon.
+ @param[in] PayloadBuf Pointer to the payload.
+ @param[in] PayloadSize Size of PayloadBuf in byte.
+ @param[in] PayloadType Type of Payload.
+
+**/
+VOID
+Ikev2ChildSaAfterEncodePayload (
+ IN UINT8 *SessionCommon,
+ IN UINT8 *PayloadBuf,
+ IN UINTN PayloadSize,
+ IN UINT8 PayloadType
+ );
+
+/**
+ Generate Ikev2 SA payload according to SessionSaData
+
+ @param[in] SessionSaData The data used in SA payload.
+ @param[in] NextPayload The payload type presented in NextPayload field of
+ SA Payload header.
+ @param[in] Type The SA type. It MUST be neither (1) for IKE_SA or
+ (2) for CHILD_SA or (3) for INFO.
+
+ @retval a Pointer to SA IKE payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateSaPayload (
+ IN IKEV2_SA_DATA *SessionSaData,
+ IN UINT8 NextPayload,
+ IN IKE_SESSION_TYPE Type
+ );
+
+/**
+ Generate a ID payload.
+
+ @param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload.
+ @param[in] NextPayload The payload type presented in the NextPayload field
+ of ID Payload header.
+
+ @retval Pointer to ID IKE payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateIdPayload (
+ IN IKEV2_SESSION_COMMON *CommonSession,
+ IN UINT8 NextPayload
+ );
+
+/**
+ Generate a ID payload.
+
+ @param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload.
+ @param[in] NextPayload The payload type presented in the NextPayload field
+ of ID Payload header.
+ @param[in] InCert Pointer to the Certificate which distinguished name
+ will be added into the Id payload.
+ @param[in] CertSize Size of the Certificate.
+
+ @retval Pointer to ID IKE payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateCertIdPayload (
+ IN IKEV2_SESSION_COMMON *CommonSession,
+ IN UINT8 NextPayload,
+ IN UINT8 *InCert,
+ IN UINTN CertSize
+ );
+
+/**
+ Generate a Nonce payload contenting the input parameter NonceBuf.
+
+ @param[in] NonceBuf The nonce buffer content the whole Nonce payload block
+ except the payload header.
+ @param[in] NonceSize The buffer size of the NonceBuf
+ @param[in] NextPayload The payload type presented in the NextPayload field
+ of Nonce Payload header.
+
+ @retval Pointer to Nonce IKE paload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateNoncePayload (
+ IN UINT8 *NonceBuf,
+ IN UINTN NonceSize,
+ IN UINT8 NextPayload
+ );
+
+/**
+ Generate the Notify payload.
+
+ Since the structure of Notify payload which defined in RFC 4306 is simple, so
+ there is no internal data structure for Notify payload. This function generate
+ Notify payload defined in RFC 4306, but all the fields in this payload are still
+ in host order and need call Ikev2EncodePayload() to convert those fields from
+ the host order to network order beforing sending it.
+
+ @param[in] ProtocolId The protocol type ID. For IKE_SA it MUST be one (1).
+ For IPsec SAs it MUST be neither (2) for AH or (3)
+ for ESP.
+ @param[in] NextPayload The next paylaod type in NextPayload field of
+ the Notify payload.
+ @param[in] SpiSize Size of the SPI in SPI size field of the Notify Payload.
+ @param[in] MessageType The message type in NotifyMessageType field of the
+ Notify Payload.
+ @param[in] SpiBuf Pointer to buffer contains the SPI value.
+ @param[in] NotifyData Pointer to buffer contains the notification data.
+ @param[in] NotifyDataSize The size of NotifyData in bytes.
+
+
+ @retval Pointer to IKE Notify Payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateNotifyPayload (
+ IN UINT8 ProtocolId,
+ IN UINT8 NextPayload,
+ IN UINT8 SpiSize,
+ IN UINT16 MessageType,
+ IN UINT8 *SpiBuf,
+ IN UINT8 *NotifyData,
+ IN UINTN NotifyDataSize
+ );
+
+/**
+ Generate the Delete payload.
+
+ Since the structure of Delete payload which defined in RFC 4306 is simple,
+ there is no internal data structure for Delete payload. This function generate
+ Delete payload defined in RFC 4306, but all the fields in this payload are still
+ in host order and need call Ikev2EncodePayload() to convert those fields from
+ the host order to network order beforing sending it.
+
+ @param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload generation.
+ @param[in] NextPayload The next paylaod type in NextPayload field of
+ the Delete payload.
+ @param[in] SpiSize Size of the SPI in SPI size field of the Delete Payload.
+ @param[in] SpiNum Number of SPI in NumofSPIs field of the Delete Payload.
+ @param[in] SpiBuf Pointer to buffer contains the SPI value.
+
+ @retval Pointer to IKE Delete Payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateDeletePayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT8 NextPayload,
+ IN UINT8 SpiSize,
+ IN UINT16 SpiNum,
+ IN UINT8 *SpiBuf
+ );
+
+/**
+ Generate the Configuration payload.
+
+ This function generates a configuration payload defined in RFC 4306, but all the
+ fields in this payload are still in host order and need call Ikev2EncodePayload()
+ to convert those fields from the host order to network order beforing sending it.
+
+ @param[in] IkeSaSession Pointer to IKE SA Session to be used for Delete payload
+ generation.
+ @param[in] NextPayload The next paylaod type in NextPayload field of
+ the Delete payload.
+ @param[in] CfgType The attribute type in the Configuration attribute.
+
+ @retval Pointer to IKE CP Payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateCpPayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT8 NextPayload,
+ IN UINT8 CfgType
+ );
+
+/**
+ Generate a Authentication Payload.
+
+ This function is used for both Authentication generation and verification. When the
+ IsVerify is TRUE, it create a Auth Data for verification. This function choose the
+ related IKE_SA_INIT Message for Auth data creation according to the IKE Session's type
+ and the value of IsVerify parameter.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to.
+ @param[in] IdPayload Pointer to the ID payload to be used for Authentication
+ payload generation.
+ @param[in] NextPayload The type filled into the Authentication Payload next
+ payload field.
+ @param[in] IsVerify If it is TURE, the Authentication payload is used for
+ verification.
+
+ @return pointer to IKE Authentication payload for pre-shard key method.
+
+**/
+IKE_PAYLOAD *
+Ikev2PskGenerateAuthPayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_PAYLOAD *IdPayload,
+ IN UINT8 NextPayload,
+ IN BOOLEAN IsVerify
+ );
+
+/**
+ Generate a Authentication Payload for Certificate Auth method.
+
+ This function has two functions. One is creating a local Authentication
+ Payload for sending and other is creating the remote Authentication data
+ for verification when the IsVerify is TURE.
+
+ @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to.
+ @param[in] IdPayload Pointer to the ID payload to be used for Authentication
+ payload generation.
+ @param[in] NextPayload The type filled into the Authentication Payload
+ next payload field.
+ @param[in] IsVerify If it is TURE, the Authentication payload is used
+ for verification.
+ @param[in] UefiPrivateKey Pointer to the UEFI private key. Ignore it when
+ verify the authenticate payload.
+ @param[in] UefiPrivateKeyLen The size of UefiPrivateKey in bytes. Ignore it
+ when verify the authenticate payload.
+ @param[in] UefiKeyPwd Pointer to the password of UEFI private key.
+ Ignore it when verify the authenticate payload.
+ @param[in] UefiKeyPwdLen The size of UefiKeyPwd in bytes.Ignore it when
+ verify the authenticate payload.
+
+ @return pointer to IKE Authentication payload for certification method.
+
+**/
+IKE_PAYLOAD *
+Ikev2CertGenerateAuthPayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_PAYLOAD *IdPayload,
+ IN UINT8 NextPayload,
+ IN BOOLEAN IsVerify,
+ IN UINT8 *UefiPrivateKey,
+ IN UINTN UefiPrivateKeyLen,
+ IN UINT8 *UefiKeyPwd,
+ IN UINTN UefiKeyPwdLen
+ );
+
+/**
+ Generate TS payload.
+
+ This function generates TSi or TSr payload according to type of next payload.
+ If the next payload is Responder TS, gereate TSi Payload. Otherwise, generate
+ TSr payload
+
+ @param[in] ChildSa Pointer to IKEV2_CHILD_SA_SESSION related to this TS payload.
+ @param[in] NextPayload The payload type presented in the NextPayload field
+ of ID Payload header.
+ @param[in] IsTunnel It indicates that if the Ts Payload is after the CP payload.
+ If yes, it means the Tsi and Tsr payload should be with
+ Max port range and address range and protocol is marked
+ as zero.
+
+ @retval Pointer to Ts IKE payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateTsPayload (
+ IN IKEV2_CHILD_SA_SESSION *ChildSa,
+ IN UINT8 NextPayload,
+ IN BOOLEAN IsTunnel
+ );
+
+/**
+ Parser the Notify Cookie payload.
+
+ This function parses the Notify Cookie payload.If the Notify ProtocolId is not
+ IPSEC_PROTO_ISAKMP or if the SpiSize is not zero or if the MessageType is not
+ the COOKIE, return EFI_INVALID_PARAMETER.
+
+ @param[in] IkeNCookie Pointer to the IKE_PAYLOAD which contians the
+ Notify Cookie payload.
+ the Notify payload.
+ @param[in, out] IkeSaSession Pointer to the relevant IKE SA Session.
+
+ @retval EFI_SUCCESS The Notify Cookie Payload is valid.
+ @retval EFI_INVALID_PARAMETER The Notify Cookie Payload is invalid.
+ @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.
+
+**/
+EFI_STATUS
+Ikev2ParserNotifyCookiePayload (
+ IN IKE_PAYLOAD *IkeNCookie,
+ IN OUT IKEV2_SA_SESSION *IkeSaSession
+ );
+
+/**
+ Generate the Certificate payload or Certificate Request Payload.
+
+ Since the Certificate Payload structure is same with Certificate Request Payload,
+ the only difference is that one contains the Certificate Data, other contains
+ the acceptable certificateion CA. This function generate Certificate payload
+ or Certificate Request Payload defined in RFC 4306, but all the fields
+ in the payload are still in host order and need call Ikev2EncodePayload()
+ to convert those fields from the host order to network order beforing sending it.
+
+ @param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload
+ generation.
+ @param[in] NextPayload The next paylaod type in NextPayload field of
+ the Delete payload.
+ @param[in] Certificate Pointer of buffer contains the certification data.
+ @param[in] CertificateLen The length of Certificate in byte.
+ @param[in] EncodeType Specified the Certificate Encodeing which is defined
+ in RFC 4306.
+ @param[in] IsRequest To indicate create Certificate Payload or Certificate
+ Request Payload. If it is TURE, create Certificate
+ Request Payload. Otherwise, create Certificate Payload.
+
+ @retval a Pointer to IKE Payload whose payload buffer containing the Certificate
+ payload or Certificated Request payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateCertificatePayload (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT8 NextPayload,
+ IN UINT8 *Certificate,
+ IN UINTN CertificateLen,
+ IN UINT8 EncodeType,
+ IN BOOLEAN IsRequest
+ );
+
+/**
+ General interface of payload encoding.
+
+ This function encode the internal data structure into payload which
+ is defined in RFC 4306. The IkePayload->PayloadBuf used to store both the input
+ payload and converted payload. Only the SA payload use the interal structure
+ to store the attribute. Other payload use structure which is same with the RFC
+ defined, for this kind payloads just do host order to network order change of
+ some fields.
+
+ @param[in] SessionCommon Pointer to IKE Session Common used to encode the payload.
+ @param[in, out] IkePayload Pointer to IKE payload to be encode as input, and
+ store the encoded result as output.
+
+ @retval EFI_INVALID_PARAMETER Meet error when encode the SA payload.
+ @retval EFI_SUCCESS Encode successfully.
+
+**/
+EFI_STATUS
+Ikev2EncodePayload (
+ IN UINT8 *SessionCommon,
+ IN OUT IKE_PAYLOAD *IkePayload
+ );
+
+/**
+ The general interface of decode Payload.
+
+ This function convert the received Payload into internal structure.
+
+ @param[in] SessionCommon Pointer to IKE Session Common to use for decoding.
+ @param[in, out] IkePayload Pointer to IKE payload to be decode as input, and
+ store the decoded result as output.
+
+ @retval EFI_INVALID_PARAMETER Meet error when decode the SA payload.
+ @retval EFI_SUCCESS Decode successfully.
+
+**/
+EFI_STATUS
+Ikev2DecodePayload (
+ IN UINT8 *SessionCommon,
+ IN OUT IKE_PAYLOAD *IkePayload
+ );
+
+/**
+ Decrypt IKE packet.
+
+ This function decrpt the Encrypted IKE packet and put the result into IkePacket->PayloadBuf.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing
+ some parameter used during decrypting.
+ @param[in, out] IkePacket Point to IKE_PACKET to be decrypted as input,
+ and the decrypted reslult as output.
+ @param[in, out] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
+ IKE_CHILD_TYPE are supportted.
+
+ @retval EFI_INVALID_PARAMETER If the IKE packet length is zero or the
+ IKE packet length is not Algorithm Block Size
+ alignment.
+ @retval EFI_SUCCESS Decrypt IKE packet successfully.
+
+**/
+EFI_STATUS
+Ikev2DecryptPacket (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN OUT IKE_PACKET *IkePacket,
+ IN OUT UINTN IkeType
+ );
+
+/**
+ Encrypt IKE packet.
+
+ This function encrypt IKE packet before sending it. The Encrypted IKE packet
+ is put in to IKEV2 Encrypted Payload.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the IKE packet.
+ @param[in, out] IkePacket Pointer to IKE packet to be encrypted.
+
+ @retval EFI_SUCCESS Operation is successful.
+ @retval Others OPeration is failed.
+
+**/
+EFI_STATUS
+Ikev2EncryptPacket (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN OUT IKE_PACKET *IkePacket
+ );
+
+/**
+ Encode the IKE packet.
+
+ This function put all Payloads into one payload then encrypt it if needed.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing
+ some parameter used during IKE packet encoding.
+ @param[in, out] IkePacket Pointer to IKE_PACKET to be encoded as input,
+ and the encoded reslult as output.
+ @param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
+ IKE_CHILD_TYPE are supportted.
+
+ @retval EFI_SUCCESS Encode IKE packet successfully.
+ @retval Otherwise Encode IKE packet failed.
+
+**/
+EFI_STATUS
+Ikev2EncodePacket (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN OUT IKE_PACKET *IkePacket,
+ IN UINTN IkeType
+ );
+
+/**
+ Decode the IKE packet.
+
+ This function first decrypts the IKE packet if needed , then separats the whole
+ IKE packet from the IkePacket->PayloadBuf into IkePacket payload list.
+
+ @param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON containing
+ some parameter used by IKE packet decoding.
+ @param[in, out] IkePacket The IKE Packet to be decoded on input, and
+ the decoded result on return.
+ @param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
+ IKE_CHILD_TYPE are supportted.
+
+ @retval EFI_SUCCESS The IKE packet is decoded successfull.
+ @retval Otherwise The IKE packet decoding is failed.
+
+**/
+EFI_STATUS
+Ikev2DecodePacket (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN OUT IKE_PACKET *IkePacket,
+ IN UINTN IkeType
+ );
+
+/**
+ Save some useful payloads after accepting the Packet.
+
+ @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the operation.
+ @param[in] IkePacket Pointer to received IkePacet.
+ @param[in] IkeType The type used to indicate it is in IkeSa or ChildSa or Info
+ exchange.
+
+**/
+VOID
+Ikev2OnPacketAccepted (
+ IN IKEV2_SESSION_COMMON *SessionCommon,
+ IN IKE_PACKET *IkePacket,
+ IN UINT8 IkeType
+ );
+
+/**
+ Send out IKEV2 packet.
+
+ @param[in] IkeUdpService Pointer to IKE_UDP_SERVICE used to send the IKE packet.
+ @param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON related to the IKE packet.
+ @param[in] IkePacket Pointer to IKE_PACKET to be sent out.
+ @param[in] IkeType The type of IKE to point what's kind of the IKE
+ packet is to be sent out. IKE_SA_TYPE, IKE_INFO_TYPE
+ and IKE_CHILD_TYPE are supportted.
+
+ @retval EFI_SUCCESS The operation complete successfully.
+ @retval Otherwise The operation is failed.
+
+**/
+EFI_STATUS
+Ikev2SendIkePacket (
+ IN IKE_UDP_SERVICE *IkeUdpService,
+ IN UINT8 *SessionCommon,
+ IN IKE_PACKET *IkePacket,
+ IN UINTN IkeType
+ );
+
+/**
+ Callback function for the IKE life time is over.
+
+ This function will mark the related IKE SA Session as deleting and trigger a
+ Information negotiation.
+
+ @param[in] Event The time out event.
+ @param[in] Context Pointer to data passed by caller.
+
+**/
+VOID
+EFIAPI
+Ikev2LifetimeNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ This function will be called if the TimeOut Event is signaled.
+
+ @param[in] Event The signaled Event.
+ @param[in] Context The data passed by caller.
+
+**/
+VOID
+EFIAPI
+Ikev2ResendNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Generate a Key Exchange payload according to the DH group type and save the
+ public Key into IkeSaSession IkeKey field.
+
+ @param[in, out] IkeSaSession Pointer of the IKE_SA_SESSION.
+ @param[in] NextPayload The payload type presented in the NextPayload field of Key
+ Exchange Payload header.
+
+ @retval Pointer to Key IKE payload.
+
+**/
+IKE_PAYLOAD *
+Ikev2GenerateKePayload (
+ IN OUT IKEV2_SA_SESSION *IkeSaSession,
+ IN UINT8 NextPayload
+ );
+
+/**
+ Check if the SPD is related to the input Child SA Session.
+
+ This function is the subfunction of Ikev1AssociateSpdEntry(). It is the call
+ back function of IpSecVisitConfigData().
+
+
+ @param[in] Type Type of the input Config Selector.
+ @param[in] Selector Pointer to the Configure Selector to be checked.
+ @param[in] Data Pointer to the Configure Selector's Data passed
+ from the caller.
+ @param[in] SelectorSize The buffer size of Selector.
+ @param[in] DataSize The buffer size of the Data.
+ @param[in] Context The data passed from the caller. It is a Child
+ SA Session in this context.
+
+ @retval EFI_SUCCESS The SPD Selector is not related to the Child SA Session.
+ @retval EFI_ABORTED The SPD Selector is related to the Child SA session and
+ set the ChildSaSession->Spd to point to this SPD Selector.
+
+**/
+EFI_STATUS
+Ikev2MatchSpdEntry (
+ IN EFI_IPSEC_CONFIG_DATA_TYPE Type,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN UINTN SelectorSize,
+ IN UINTN DataSize,
+ IN VOID *Context
+ );
+
+/**
+ Check if the Algorithm ID is supported.
+
+ @param[in] AlgorithmId The specified Algorithm ID.
+ @param[in] Type The type used to indicate the Algorithm is for Encrypt or
+ Authentication.
+
+ @retval TRUE If the Algorithm ID is supported.
+ @retval FALSE If the Algorithm ID is not supported.
+
+**/
+BOOLEAN
+Ikev2IsSupportAlg (
+ IN UINT16 AlgorithmId,
+ IN UINT8 Type
+ );
+
+/**
+ Generate a ChildSa Session and insert it into related IkeSaSession.
+
+ @param[in] IkeSaSession Pointer to related IKEV2_SA_SESSION.
+ @param[in] UdpService Pointer to related IKE_UDP_SERVICE.
+
+ @return pointer of IKEV2_CHILD_SA_SESSION.
+
+**/
+IKEV2_CHILD_SA_SESSION *
+Ikev2ChildSaSessionCreate (
+ IN IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_UDP_SERVICE *UdpService
+ ) ;
+
+/**
+ Parse the received Initial Exchange Packet.
+
+ This function parse the SA Payload and Key Payload to find out the cryptographic
+ suite for the further IKE negotiation and fill it into the IKE SA Session's
+ CommonSession->SaParams.
+
+ @param[in, out] IkeSaSession Pointer to related IKEV2_SA_SESSION.
+ @param[in] SaPayload The received packet.
+ @param[in] Type The received packet IKE header flag.
+
+ @retval TRUE If the SA proposal in Packet is acceptable.
+ @retval FALSE If the SA proposal in Packet is not acceptable.
+
+**/
+BOOLEAN
+Ikev2SaParseSaPayload (
+ IN OUT IKEV2_SA_SESSION *IkeSaSession,
+ IN IKE_PAYLOAD *SaPayload,
+ IN UINT8 Type
+ );
+
+/**
+ Parse the received Authentication Exchange Packet.
+
+ This function parse the SA Payload and Key Payload to find out the cryptographic
+ suite for the ESP and fill it into the Child SA Session's CommonSession->SaParams.
+
+ @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to
+ this Authentication Exchange.
+ @param[in] SaPayload The received packet.
+ @param[in] Type The IKE header's flag of received packet .
+
+ @retval TRUE If the SA proposal in Packet is acceptable.
+ @retval FALSE If the SA proposal in Packet is not acceptable.
+
+**/
+BOOLEAN
+Ikev2ChildSaParseSaPayload (
+ IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession,
+ IN IKE_PAYLOAD *SaPayload,
+ IN UINT8 Type
+ );
+
+/**
+ Generate Key buffer from fragments.
+
+ If the digest length of specified HashAlgId is larger than or equal with the
+ required output key length, derive the key directly. Otherwise, Key Material
+ needs to be PRF-based concatenation according to 2.13 of RFC 4306:
+ prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01),
+ T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04)
+ then derive the key from this key material.
+
+ @param[in] HashAlgId The Hash Algorithm ID used to generate key.
+ @param[in] HashKey Pointer to a key buffer which contains hash key.
+ @param[in] HashKeyLength The length of HashKey in bytes.
+ @param[in, out] OutputKey Pointer to buffer which is used to receive the
+ output key.
+ @param[in] OutputKeyLength The length of OutPutKey buffer.
+ @param[in] Fragments Pointer to the data to be used to generate key.
+ @param[in] NumFragments The numbers of the Fragement.
+
+ @retval EFI_SUCCESS The operation complete successfully.
+ @retval EFI_INVALID_PARAMETER If NumFragments is zero.
+ @retval EFI_OUT_OF_RESOURCES If the required resource can't be allocated.
+ @retval Others The operation is failed.
+
+**/
+EFI_STATUS
+Ikev2SaGenerateKey (
+ IN UINT8 HashAlgId,
+ IN UINT8 *HashKey,
+ IN UINTN HashKeyLength,
+ IN OUT UINT8 *OutputKey,
+ IN UINTN OutputKeyLength,
+ IN PRF_DATA_FRAGMENT *Fragments,
+ IN UINTN NumFragments
+ );
+
+/**
+ Copy ChildSaSession->Spd->Selector to ChildSaSession->SpdSelector.
+
+ ChildSaSession->SpdSelector stores the real Spdselector for its SA. Sometime,
+ the SpdSelector in ChildSaSession is more accurated or the scope is smaller
+ than the one in ChildSaSession->Spd, especially for the tunnel mode.
+
+ @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to.
+
+ @retval EFI_SUCCESS The operation complete successfully.
+ @retval EFI_OUT_OF_RESOURCES If the required resource can't be allocated.
+
+**/
+EFI_STATUS
+Ikev2ChildSaSessionSpdSelectorCreate (
+ IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession
+ );
+
+extern IKE_ALG_GUID_INFO mIPsecEncrAlgInfo[];
+#endif
+
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecConfigImpl.c b/Core/NetworkPkg/IpSecDxe/IpSecConfigImpl.c
new file mode 100644
index 0000000000..911d3e3236
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecConfigImpl.c
@@ -0,0 +1,3138 @@
+/** @file
+ The implementation of IPSEC_CONFIG_PROTOCOL.
+
+ Copyright (c) 2009 - 2015, 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 "IpSecConfigImpl.h"
+#include "IpSecDebug.h"
+
+LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum];
+BOOLEAN mSetBySelf = FALSE;
+
+//
+// Common CompareSelector routine entry for SPD/SAD/PAD.
+//
+IPSEC_COMPARE_SELECTOR mCompareSelector[] = {
+ (IPSEC_COMPARE_SELECTOR) CompareSpdSelector,
+ (IPSEC_COMPARE_SELECTOR) CompareSaId,
+ (IPSEC_COMPARE_SELECTOR) ComparePadId
+};
+
+//
+// Common IsZeroSelector routine entry for SPD/SAD/PAD.
+//
+IPSEC_IS_ZERO_SELECTOR mIsZeroSelector[] = {
+ (IPSEC_IS_ZERO_SELECTOR) IsZeroSpdSelector,
+ (IPSEC_IS_ZERO_SELECTOR) IsZeroSaId,
+ (IPSEC_IS_ZERO_SELECTOR) IsZeroPadId
+};
+
+//
+// Common DuplicateSelector routine entry for SPD/SAD/PAD.
+//
+IPSEC_DUPLICATE_SELECTOR mDuplicateSelector[] = {
+ (IPSEC_DUPLICATE_SELECTOR) DuplicateSpdSelector,
+ (IPSEC_DUPLICATE_SELECTOR) DuplicateSaId,
+ (IPSEC_DUPLICATE_SELECTOR) DuplicatePadId
+};
+
+//
+// Common FixPolicyEntry routine entry for SPD/SAD/PAD.
+//
+IPSEC_FIX_POLICY_ENTRY mFixPolicyEntry[] = {
+ (IPSEC_FIX_POLICY_ENTRY) FixSpdEntry,
+ (IPSEC_FIX_POLICY_ENTRY) FixSadEntry,
+ (IPSEC_FIX_POLICY_ENTRY) FixPadEntry
+};
+
+//
+// Common UnfixPolicyEntry routine entry for SPD/SAD/PAD.
+//
+IPSEC_FIX_POLICY_ENTRY mUnfixPolicyEntry[] = {
+ (IPSEC_FIX_POLICY_ENTRY) UnfixSpdEntry,
+ (IPSEC_FIX_POLICY_ENTRY) UnfixSadEntry,
+ (IPSEC_FIX_POLICY_ENTRY) UnfixPadEntry
+};
+
+//
+// Common SetPolicyEntry routine entry for SPD/SAD/PAD.
+//
+IPSEC_SET_POLICY_ENTRY mSetPolicyEntry[] = {
+ (IPSEC_SET_POLICY_ENTRY) SetSpdEntry,
+ (IPSEC_SET_POLICY_ENTRY) SetSadEntry,
+ (IPSEC_SET_POLICY_ENTRY) SetPadEntry
+};
+
+//
+// Common GetPolicyEntry routine entry for SPD/SAD/PAD.
+//
+IPSEC_GET_POLICY_ENTRY mGetPolicyEntry[] = {
+ (IPSEC_GET_POLICY_ENTRY) GetSpdEntry,
+ (IPSEC_GET_POLICY_ENTRY) GetSadEntry,
+ (IPSEC_GET_POLICY_ENTRY) GetPadEntry
+};
+
+//
+// Routine entry for IpSecConfig protocol.
+//
+EFI_IPSEC_CONFIG_PROTOCOL mIpSecConfigInstance = {
+ EfiIpSecConfigSetData,
+ EfiIpSecConfigGetData,
+ EfiIpSecConfigGetNextSelector,
+ EfiIpSecConfigRegisterNotify,
+ EfiIpSecConfigUnregisterNotify
+};
+
+/**
+ Get the all IPSec configuration variables and store those variables
+ to the internal data structure.
+
+ This founction is called by IpSecConfigInitialize() that is to intialize the
+ IPsecConfiguration Protocol.
+
+ @param[in] Private Point to IPSEC_PRIVATE_DATA.
+
+ @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated.
+ @retval EFI_SUCCESS Restore the IPsec Configuration successfully.
+ @retval others Other errors is found during the variable getting.
+
+**/
+EFI_STATUS
+IpSecConfigRestore (
+ IN IPSEC_PRIVATE_DATA *Private
+ );
+
+/**
+ Check if the specified EFI_IP_ADDRESS_INFO is in EFI_IP_ADDRESS_INFO list.
+
+ @param[in] AddressInfo Pointer of IP_ADDRESS_INFO to be search in AddressInfo list.
+ @param[in] AddressInfoList A list that contains IP_ADDRESS_INFOs.
+ @param[in] AddressCount Point out how many IP_ADDRESS_INFO in the list.
+
+ @retval TRUE The specified AddressInfo is in the AddressInfoList.
+ @retval FALSE The specified AddressInfo is not in the AddressInfoList.
+
+**/
+BOOLEAN
+IsInAddressInfoList(
+ IN EFI_IP_ADDRESS_INFO *AddressInfo,
+ IN EFI_IP_ADDRESS_INFO *AddressInfoList,
+ IN UINT32 AddressCount
+ )
+{
+ UINT8 Index;
+ EFI_IP_ADDRESS ZeroAddress;
+
+ ZeroMem(&ZeroAddress, sizeof (EFI_IP_ADDRESS));
+
+ //
+ // Zero Address means any address is matched.
+ //
+ if (AddressCount == 1) {
+ if (CompareMem (
+ &AddressInfoList[0].Address,
+ &ZeroAddress,
+ sizeof (EFI_IP_ADDRESS)
+ ) == 0) {
+ return TRUE;
+ }
+ }
+ for (Index = 0; Index < AddressCount ; Index++) {
+ if (CompareMem (
+ AddressInfo,
+ &AddressInfoList[Index].Address,
+ sizeof (EFI_IP_ADDRESS)
+ ) == 0 &&
+ AddressInfo->PrefixLength == AddressInfoList[Index].PrefixLength
+ ) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Compare two SPD Selectors.
+
+ Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/
+ NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the
+ Local Addresses and remote Addresses.
+
+ @param[in] Selector1 Pointer of first SPD Selector.
+ @param[in] Selector2 Pointer of second SPD Selector.
+
+ @retval TRUE This two Selector have the same value in above fields.
+ @retval FALSE Not all above fields have the same value in these two Selectors.
+
+**/
+BOOLEAN
+CompareSpdSelector (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector1,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector2
+ )
+{
+ EFI_IPSEC_SPD_SELECTOR *SpdSel1;
+ EFI_IPSEC_SPD_SELECTOR *SpdSel2;
+ BOOLEAN IsMatch;
+ UINTN Index;
+
+ SpdSel1 = &Selector1->SpdSelector;
+ SpdSel2 = &Selector2->SpdSelector;
+ IsMatch = TRUE;
+
+ //
+ // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/
+ // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the
+ // two Spdselectors. Since the SPD supports two directions, it needs to
+ // compare two directions.
+ //
+ if ((SpdSel1->LocalAddressCount != SpdSel2->LocalAddressCount &&
+ SpdSel1->LocalAddressCount != SpdSel2->RemoteAddressCount) ||
+ (SpdSel1->RemoteAddressCount != SpdSel2->RemoteAddressCount &&
+ SpdSel1->RemoteAddressCount != SpdSel2->LocalAddressCount) ||
+ SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol ||
+ SpdSel1->LocalPort != SpdSel2->LocalPort ||
+ SpdSel1->LocalPortRange != SpdSel2->LocalPortRange ||
+ SpdSel1->RemotePort != SpdSel2->RemotePort ||
+ SpdSel1->RemotePortRange != SpdSel2->RemotePortRange
+ ) {
+ IsMatch = FALSE;
+ return IsMatch;
+ }
+
+ //
+ // Compare the all LocalAddress fields in the two Spdselectors.
+ // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare
+ // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return
+ // TRUE.
+ //
+ for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel1->LocalAddress[Index],
+ SpdSel2->LocalAddress,
+ SpdSel2->LocalAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ if (IsMatch) {
+ for (Index = 0; Index < SpdSel2->LocalAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel2->LocalAddress[Index],
+ SpdSel1->LocalAddress,
+ SpdSel1->LocalAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ }
+ if (IsMatch) {
+ for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel1->RemoteAddress[Index],
+ SpdSel2->RemoteAddress,
+ SpdSel2->RemoteAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ }
+ if (IsMatch) {
+ for (Index = 0; Index < SpdSel2->RemoteAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel2->RemoteAddress[Index],
+ SpdSel1->RemoteAddress,
+ SpdSel1->RemoteAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ }
+ //
+ // Finish the one direction compare. If it is matched, return; otherwise,
+ // compare the other direction.
+ //
+ if (IsMatch) {
+ return IsMatch;
+ }
+ //
+ // Secondly, the SpdSel1->LocalAddress doesn't equal to SpdSel2->LocalAddress and
+ // SpdSel1->RemoteAddress doesn't equal to SpdSel2->RemoteAddress. Try to compare
+ // the RemoteAddress to LocalAddress.
+ //
+ IsMatch = TRUE;
+ for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel1->RemoteAddress[Index],
+ SpdSel2->LocalAddress,
+ SpdSel2->LocalAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ if (IsMatch) {
+ for (Index = 0; Index < SpdSel2->RemoteAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel2->RemoteAddress[Index],
+ SpdSel1->LocalAddress,
+ SpdSel1->LocalAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ }
+ if (IsMatch) {
+ for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel1->LocalAddress[Index],
+ SpdSel2->RemoteAddress,
+ SpdSel2->RemoteAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ }
+ if (IsMatch) {
+ for (Index = 0; Index < SpdSel2->LocalAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel2->LocalAddress[Index],
+ SpdSel1->RemoteAddress,
+ SpdSel1->RemoteAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ }
+ return IsMatch;
+}
+
+/**
+ Find if the two SPD Selectors has subordinative.
+
+ Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/
+ NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the
+ Local Addresses and remote Addresses.
+
+ @param[in] Selector1 Pointer of first SPD Selector.
+ @param[in] Selector2 Pointer of second SPD Selector.
+
+ @retval TRUE The first SPD Selector is subordinate Selector of second SPD Selector.
+ @retval FALSE The first SPD Selector is not subordinate Selector of second
+ SPD Selector.
+
+**/
+BOOLEAN
+IsSubSpdSelector (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector1,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector2
+ )
+{
+ EFI_IPSEC_SPD_SELECTOR *SpdSel1;
+ EFI_IPSEC_SPD_SELECTOR *SpdSel2;
+ BOOLEAN IsMatch;
+ UINTN Index;
+
+ SpdSel1 = &Selector1->SpdSelector;
+ SpdSel2 = &Selector2->SpdSelector;
+ IsMatch = TRUE;
+
+ //
+ // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/
+ // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the
+ // two Spdselectors. Since the SPD supports two directions, it needs to
+ // compare two directions.
+ //
+ if (SpdSel1->LocalAddressCount > SpdSel2->LocalAddressCount ||
+ SpdSel1->RemoteAddressCount > SpdSel2->RemoteAddressCount ||
+ (SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) ||
+ (SpdSel1->LocalPort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0)||
+ (SpdSel1->LocalPortRange > SpdSel2->LocalPortRange && SpdSel1->LocalPort != 0)||
+ (SpdSel1->RemotePort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0) ||
+ (SpdSel1->RemotePortRange > SpdSel2->RemotePortRange && SpdSel2->RemotePort != 0)
+ ) {
+ IsMatch = FALSE;
+ }
+
+ //
+ // Compare the all LocalAddress fields in the two Spdselectors.
+ // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare
+ // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return
+ // TRUE.
+ //
+ if (IsMatch) {
+ for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel1->LocalAddress[Index],
+ SpdSel2->LocalAddress,
+ SpdSel2->LocalAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+
+ if (IsMatch) {
+ for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel1->RemoteAddress[Index],
+ SpdSel2->RemoteAddress,
+ SpdSel2->RemoteAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ }
+ }
+ if (IsMatch) {
+ return IsMatch;
+ }
+
+ //
+ //
+ // The SPD selector in SPD entry is two way.
+ //
+ // Compare the LocalAddressCount/RemoteAddressCount/NextLayerProtocol/
+ // LocalPort/LocalPortRange/RemotePort/RemotePortRange fields in the
+ // two Spdselectors. Since the SPD supports two directions, it needs to
+ // compare two directions.
+ //
+ IsMatch = TRUE;
+ if (SpdSel1->LocalAddressCount > SpdSel2->RemoteAddressCount ||
+ SpdSel1->RemoteAddressCount > SpdSel2->LocalAddressCount ||
+ (SpdSel1->NextLayerProtocol != SpdSel2->NextLayerProtocol && SpdSel2->NextLayerProtocol != 0xffff) ||
+ (SpdSel1->LocalPort > SpdSel2->RemotePort && SpdSel2->RemotePort != 0)||
+ (SpdSel1->LocalPortRange > SpdSel2->RemotePortRange && SpdSel1->RemotePort != 0)||
+ (SpdSel1->RemotePort > SpdSel2->LocalPort && SpdSel2->LocalPort != 0) ||
+ (SpdSel1->RemotePortRange > SpdSel2->LocalPortRange && SpdSel2->LocalPort != 0)
+ ) {
+ IsMatch = FALSE;
+ return IsMatch;
+ }
+
+ //
+ // Compare the all LocalAddress fields in the two Spdselectors.
+ // First, SpdSel1->LocalAddress to SpdSel2->LocalAddress && Compare
+ // SpdSel1->RemoteAddress to SpdSel2->RemoteAddress. If all match, return
+ // TRUE.
+ //
+ for (Index = 0; Index < SpdSel1->LocalAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel1->LocalAddress[Index],
+ SpdSel2->RemoteAddress,
+ SpdSel2->RemoteAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+
+ if (IsMatch) {
+ for (Index = 0; Index < SpdSel1->RemoteAddressCount; Index++) {
+ if (!IsInAddressInfoList (
+ &SpdSel1->RemoteAddress[Index],
+ SpdSel2->LocalAddress,
+ SpdSel2->LocalAddressCount
+ )) {
+ IsMatch = FALSE;
+ break;
+ }
+ }
+ }
+ return IsMatch;
+
+}
+
+/**
+ Compare two SA IDs.
+
+ @param[in] Selector1 Pointer of first SA ID.
+ @param[in] Selector2 Pointer of second SA ID.
+
+ @retval TRUE This two Selectors have the same SA ID.
+ @retval FALSE This two Selecotrs don't have the same SA ID.
+
+**/
+BOOLEAN
+CompareSaId (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector1,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector2
+ )
+{
+ EFI_IPSEC_SA_ID *SaId1;
+ EFI_IPSEC_SA_ID *SaId2;
+ BOOLEAN IsMatch;
+
+ SaId1 = &Selector1->SaId;
+ SaId2 = &Selector2->SaId;
+ IsMatch = TRUE;
+
+ if (CompareMem (SaId1, SaId2, sizeof (EFI_IPSEC_SA_ID)) != 0) {
+ IsMatch = FALSE;
+ }
+
+ return IsMatch;
+}
+
+/**
+ Compare two PAD IDs.
+
+ @param[in] Selector1 Pointer of first PAD ID.
+ @param[in] Selector2 Pointer of second PAD ID.
+
+ @retval TRUE This two Selectors have the same PAD ID.
+ @retval FALSE This two Selecotrs don't have the same PAD ID.
+
+**/
+BOOLEAN
+ComparePadId (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector1,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector2
+ )
+{
+ EFI_IPSEC_PAD_ID *PadId1;
+ EFI_IPSEC_PAD_ID *PadId2;
+ BOOLEAN IsMatch;
+
+ PadId1 = &Selector1->PadId;
+ PadId2 = &Selector2->PadId;
+ IsMatch = TRUE;
+
+ //
+ // Compare the PeerIdValid fields in PadId.
+ //
+ if (PadId1->PeerIdValid != PadId2->PeerIdValid) {
+ IsMatch = FALSE;
+ }
+ //
+ // Compare the PeerId fields in PadId if PeerIdValid is true.
+ //
+ if (IsMatch &&
+ PadId1->PeerIdValid &&
+ AsciiStriCmp ((CONST CHAR8 *) PadId1->Id.PeerId, (CONST CHAR8 *) PadId2->Id.PeerId) != 0
+ ) {
+ IsMatch = FALSE;
+ }
+ //
+ // Compare the IpAddress fields in PadId if PeerIdValid is false.
+ //
+ if (IsMatch &&
+ !PadId1->PeerIdValid &&
+ (PadId1->Id.IpAddress.PrefixLength != PadId2->Id.IpAddress.PrefixLength ||
+ CompareMem (&PadId1->Id.IpAddress.Address, &PadId2->Id.IpAddress.Address, sizeof (EFI_IP_ADDRESS)) != 0)
+ ) {
+ IsMatch = FALSE;
+ }
+
+ return IsMatch;
+}
+
+/**
+ Check if the SPD Selector is Zero by its LocalAddressCount and RemoteAddressCount
+ fields.
+
+ @param[in] Selector Pointer of the SPD Selector.
+
+ @retval TRUE If the SPD Selector is Zero.
+ @retval FALSE If the SPD Selector is not Zero.
+
+**/
+BOOLEAN
+IsZeroSpdSelector (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector
+ )
+{
+ EFI_IPSEC_SPD_SELECTOR *SpdSel;
+ BOOLEAN IsZero;
+
+ SpdSel = &Selector->SpdSelector;
+ IsZero = FALSE;
+
+ if (SpdSel->LocalAddressCount == 0 && SpdSel->RemoteAddressCount == 0) {
+ IsZero = TRUE;
+ }
+
+ return IsZero;
+}
+
+/**
+ Check if the SA ID is Zero by its DestAddress.
+
+ @param[in] Selector Pointer of the SA ID.
+
+ @retval TRUE If the SA ID is Zero.
+ @retval FALSE If the SA ID is not Zero.
+
+**/
+BOOLEAN
+IsZeroSaId (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector
+ )
+{
+ BOOLEAN IsZero;
+ EFI_IPSEC_CONFIG_SELECTOR ZeroSelector;
+
+ IsZero = FALSE;
+
+ ZeroMem (&ZeroSelector, sizeof (EFI_IPSEC_CONFIG_SELECTOR));
+
+ if (CompareMem (&ZeroSelector, Selector, sizeof (EFI_IPSEC_CONFIG_SELECTOR)) == 0) {
+ IsZero = TRUE;
+ }
+
+ return IsZero;
+}
+
+/**
+ Check if the PAD ID is Zero.
+
+ @param[in] Selector Pointer of the PAD ID.
+
+ @retval TRUE If the PAD ID is Zero.
+ @retval FALSE If the PAD ID is not Zero.
+
+**/
+BOOLEAN
+IsZeroPadId (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector
+ )
+{
+ EFI_IPSEC_PAD_ID *PadId;
+ EFI_IPSEC_PAD_ID ZeroId;
+ BOOLEAN IsZero;
+
+ PadId = &Selector->PadId;
+ IsZero = FALSE;
+
+ ZeroMem (&ZeroId, sizeof (EFI_IPSEC_PAD_ID));
+
+ if (CompareMem (PadId, &ZeroId, sizeof (EFI_IPSEC_PAD_ID)) == 0) {
+ IsZero = TRUE;
+ }
+
+ return IsZero;
+}
+
+/**
+ Copy Source SPD Selector to the Destination SPD Selector.
+
+ @param[in, out] DstSel Pointer of Destination SPD Selector.
+ @param[in] SrcSel Pointer of Source SPD Selector.
+ @param[in, out] Size The size of the Destination SPD Selector. If it
+ not NULL and its value less than the size of
+ Source SPD Selector, the value of Source SPD
+ Selector's size will be passed to caller by this
+ parameter.
+
+ @retval EFI_INVALID_PARAMETER If the Destination or Source SPD Selector is NULL
+ @retval EFI_BUFFER_TOO_SMALL If the input Size is less than size of the Source SPD Selector.
+ @retval EFI_SUCCESS Copy Source SPD Selector to the Destination SPD
+ Selector successfully.
+
+**/
+EFI_STATUS
+DuplicateSpdSelector (
+ IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel,
+ IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel,
+ IN OUT UINTN *Size
+ )
+{
+ EFI_IPSEC_SPD_SELECTOR *Dst;
+ EFI_IPSEC_SPD_SELECTOR *Src;
+
+ Dst = &DstSel->SpdSelector;
+ Src = &SrcSel->SpdSelector;
+
+ if (Dst == NULL || Src == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Size != NULL && (*Size) < SIZE_OF_SPD_SELECTOR (Src)) {
+ *Size = SIZE_OF_SPD_SELECTOR (Src);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // Copy the base structure of SPD selector.
+ //
+ CopyMem (Dst, Src, sizeof (EFI_IPSEC_SPD_SELECTOR));
+
+ //
+ // Copy the local address array of SPD selector.
+ //
+ Dst->LocalAddress = (EFI_IP_ADDRESS_INFO *) (Dst + 1);
+ CopyMem (
+ Dst->LocalAddress,
+ Src->LocalAddress,
+ sizeof (EFI_IP_ADDRESS_INFO) * Dst->LocalAddressCount
+ );
+
+ //
+ // Copy the remote address array of SPD selector.
+ //
+ Dst->RemoteAddress = Dst->LocalAddress + Dst->LocalAddressCount;
+ CopyMem (
+ Dst->RemoteAddress,
+ Src->RemoteAddress,
+ sizeof (EFI_IP_ADDRESS_INFO) * Dst->RemoteAddressCount
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Copy Source SA ID to the Destination SA ID.
+
+ @param[in, out] DstSel Pointer of Destination SA ID.
+ @param[in] SrcSel Pointer of Source SA ID.
+ @param[in, out] Size The size of the Destination SA ID. If it
+ not NULL and its value less than the size of
+ Source SA ID, the value of Source SA ID's size
+ will be passed to caller by this parameter.
+
+ @retval EFI_INVALID_PARAMETER If the Destination or Source SA ID is NULL.
+ @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source SA ID.
+ @retval EFI_SUCCESS Copy Source SA ID to the Destination SA ID successfully.
+
+**/
+EFI_STATUS
+DuplicateSaId (
+ IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel,
+ IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel,
+ IN OUT UINTN *Size
+ )
+{
+ EFI_IPSEC_SA_ID *Dst;
+ EFI_IPSEC_SA_ID *Src;
+
+ Dst = &DstSel->SaId;
+ Src = &SrcSel->SaId;
+
+ if (Dst == NULL || Src == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Size != NULL && *Size < sizeof (EFI_IPSEC_SA_ID)) {
+ *Size = sizeof (EFI_IPSEC_SA_ID);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem (Dst, Src, sizeof (EFI_IPSEC_SA_ID));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Copy Source PAD ID to the Destination PAD ID.
+
+ @param[in, out] DstSel Pointer of Destination PAD ID.
+ @param[in] SrcSel Pointer of Source PAD ID.
+ @param[in, out] Size The size of the Destination PAD ID. If it
+ not NULL and its value less than the size of
+ Source PAD ID, the value of Source PAD ID's size
+ will be passed to caller by this parameter.
+
+ @retval EFI_INVALID_PARAMETER If the Destination or Source PAD ID is NULL.
+ @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source PAD ID .
+ @retval EFI_SUCCESS Copy Source PAD ID to the Destination PAD ID successfully.
+
+**/
+EFI_STATUS
+DuplicatePadId (
+ IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel,
+ IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel,
+ IN OUT UINTN *Size
+ )
+{
+ EFI_IPSEC_PAD_ID *Dst;
+ EFI_IPSEC_PAD_ID *Src;
+
+ Dst = &DstSel->PadId;
+ Src = &SrcSel->PadId;
+
+ if (Dst == NULL || Src == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Size != NULL && *Size < sizeof (EFI_IPSEC_PAD_ID)) {
+ *Size = sizeof (EFI_IPSEC_PAD_ID);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem (Dst, Src, sizeof (EFI_IPSEC_PAD_ID));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fix the value of some members of SPD Selector.
+
+ This function is called by IpSecCopyPolicyEntry()which copy the Policy
+ Entry into the Variable. Since some members in SPD Selector are pointers,
+ a physical address to relative address convertion is required before copying
+ this SPD entry into the variable.
+
+ @param[in] Selector Pointer of SPD Selector.
+ @param[in, out] Data Pointer of SPD Data.
+
+**/
+VOID
+FixSpdEntry (
+ IN EFI_IPSEC_SPD_SELECTOR *Selector,
+ IN OUT EFI_IPSEC_SPD_DATA *Data
+ )
+{
+ //
+ // It assumes that all ref buffers in SPD selector and data are
+ // stored in the continous memory and close to the base structure.
+ //
+ FIX_REF_BUF_ADDR (Selector->LocalAddress, Selector);
+ FIX_REF_BUF_ADDR (Selector->RemoteAddress, Selector);
+
+ if (Data->ProcessingPolicy != NULL) {
+ if (Data->ProcessingPolicy->TunnelOption != NULL) {
+ FIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data);
+ }
+
+ FIX_REF_BUF_ADDR (Data->ProcessingPolicy, Data);
+ }
+
+}
+
+/**
+ Fix the value of some members of SA ID.
+
+ This function is called by IpSecCopyPolicyEntry()which copy the Policy
+ Entry into the Variable. Since some members in SA ID are pointers,
+ a physical address to relative address conversion is required before copying
+ this SAD into the variable.
+
+ @param[in] SaId Pointer of SA ID
+ @param[in, out] Data Pointer of SA Data.
+
+**/
+VOID
+FixSadEntry (
+ IN EFI_IPSEC_SA_ID *SaId,
+ IN OUT EFI_IPSEC_SA_DATA2 *Data
+ )
+{
+ //
+ // It assumes that all ref buffers in SAD selector and data are
+ // stored in the continous memory and close to the base structure.
+ //
+ if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
+ FIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.AuthKey, Data);
+ }
+
+ if (SaId->Proto == EfiIPsecESP && Data->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
+ FIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.EncKey, Data);
+ }
+
+ if (Data->SpdSelector != NULL) {
+ if (Data->SpdSelector->LocalAddress != NULL) {
+ FIX_REF_BUF_ADDR (Data->SpdSelector->LocalAddress, Data);
+ }
+
+ FIX_REF_BUF_ADDR (Data->SpdSelector->RemoteAddress, Data);
+ FIX_REF_BUF_ADDR (Data->SpdSelector, Data);
+ }
+
+}
+
+/**
+ Fix the value of some members of PAD ID.
+
+ This function is called by IpSecCopyPolicyEntry()which copy the Policy
+ Entry into the Variable. Since some members in PAD ID are pointers,
+ a physical address to relative address conversion is required before copying
+ this PAD into the variable.
+
+ @param[in] PadId Pointer of PAD ID.
+ @param[in, out] Data Pointer of PAD Data.
+
+**/
+VOID
+FixPadEntry (
+ IN EFI_IPSEC_PAD_ID *PadId,
+ IN OUT EFI_IPSEC_PAD_DATA *Data
+ )
+{
+ //
+ // It assumes that all ref buffers in pad selector and data are
+ // stored in the continous memory and close to the base structure.
+ //
+ if (Data->AuthData != NULL) {
+ FIX_REF_BUF_ADDR (Data->AuthData, Data);
+ }
+
+ if (Data->RevocationData != NULL) {
+ FIX_REF_BUF_ADDR (Data->RevocationData, Data);
+ }
+
+}
+
+/**
+ Recover the value of some members of SPD Selector.
+
+ This function is corresponding to FixSpdEntry(). It recovers the value of members
+ of SPD Selector that are fixed by FixSpdEntry().
+
+ @param[in, out] Selector Pointer of SPD Selector.
+ @param[in, out] Data Pointer of SPD Data.
+
+**/
+VOID
+UnfixSpdEntry (
+ IN OUT EFI_IPSEC_SPD_SELECTOR *Selector,
+ IN OUT EFI_IPSEC_SPD_DATA *Data
+ )
+{
+ //
+ // It assumes that all ref buffers in SPD selector and data are
+ // stored in the continous memory and close to the base structure.
+ //
+ UNFIX_REF_BUF_ADDR (Selector->LocalAddress, Selector);
+ UNFIX_REF_BUF_ADDR (Selector->RemoteAddress, Selector);
+
+ if (Data->ProcessingPolicy != NULL) {
+ UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy, Data);
+ if (Data->ProcessingPolicy->TunnelOption != NULL) {
+ UNFIX_REF_BUF_ADDR (Data->ProcessingPolicy->TunnelOption, Data);
+ }
+ }
+
+}
+
+/**
+ Recover the value of some members of SA ID.
+
+ This function is corresponding to FixSadEntry(). It recovers the value of members
+ of SAD ID that are fixed by FixSadEntry().
+
+ @param[in, out] SaId Pointer of SAD ID.
+ @param[in, out] Data Pointer of SAD Data.
+
+**/
+VOID
+UnfixSadEntry (
+ IN OUT EFI_IPSEC_SA_ID *SaId,
+ IN OUT EFI_IPSEC_SA_DATA2 *Data
+ )
+{
+ //
+ // It assumes that all ref buffers in SAD selector and data are
+ // stored in the continous memory and close to the base structure.
+ //
+ if (Data->AlgoInfo.EspAlgoInfo.AuthKey != NULL) {
+ UNFIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.AuthKey, Data);
+ }
+
+ if (SaId->Proto == EfiIPsecESP && Data->AlgoInfo.EspAlgoInfo.EncKey != NULL) {
+ UNFIX_REF_BUF_ADDR (Data->AlgoInfo.EspAlgoInfo.EncKey, Data);
+ }
+
+ if (Data->SpdSelector != NULL) {
+ UNFIX_REF_BUF_ADDR (Data->SpdSelector, Data);
+ if (Data->SpdSelector->LocalAddress != NULL) {
+ UNFIX_REF_BUF_ADDR (Data->SpdSelector->LocalAddress, Data);
+ }
+
+ UNFIX_REF_BUF_ADDR (Data->SpdSelector->RemoteAddress, Data);
+ }
+
+}
+
+/**
+ Recover the value of some members of PAD ID.
+
+ This function is corresponding to FixPadEntry(). It recovers the value of members
+ of PAD ID that are fixed by FixPadEntry().
+
+ @param[in] PadId Pointer of PAD ID.
+ @param[in, out] Data Pointer of PAD Data.
+
+**/
+VOID
+UnfixPadEntry (
+ IN EFI_IPSEC_PAD_ID *PadId,
+ IN OUT EFI_IPSEC_PAD_DATA *Data
+ )
+{
+ //
+ // It assumes that all ref buffers in pad selector and data are
+ // stored in the continous memory and close to the base structure.
+ //
+ if (Data->AuthData != NULL) {
+ UNFIX_REF_BUF_ADDR (Data->AuthData, Data);
+ }
+
+ if (Data->RevocationData != NULL) {
+ UNFIX_REF_BUF_ADDR (Data->RevocationData, Data);
+ }
+
+}
+
+/**
+ Set the security policy information for the EFI IPsec driver.
+
+ The IPsec configuration data has a unique selector/identifier separately to
+ identify a data entry.
+
+ @param[in] Selector Pointer to an entry selector on operated
+ configuration data specified by DataType.
+ A NULL Selector causes the entire specified-type
+ configuration information to be flushed.
+ @param[in] Data The data buffer to be set. The structure
+ of the data buffer should be EFI_IPSEC_SPD_DATA.
+ @param[in] Context Pointer to one entry selector that describes
+ the expected position the new data entry will
+ be added. If Context is NULL, the new entry will
+ be appended the end of database.
+
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
+ - Selector is not NULL and its LocalAddress
+ is NULL or its RemoteAddress is NULL.
+ - Data is not NULL and its Action is Protected
+ and its plolicy is NULL.
+ - Data is not NULL, its Action is not protected,
+ and its policy is not NULL.
+ - The Action of Data is Protected, its policy
+ mode is Tunnel, and its tunnel option is NULL.
+ - The Action of Data is protected and its policy
+ mode is not Tunnel and it tunnel option is not NULL.
+ @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated.
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+
+**/
+EFI_STATUS
+SetSpdEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN VOID *Context OPTIONAL
+ )
+{
+ EFI_IPSEC_SPD_SELECTOR *SpdSel;
+ EFI_IPSEC_SPD_DATA *SpdData;
+ EFI_IPSEC_SPD_SELECTOR *InsertBefore;
+ LIST_ENTRY *SpdList;
+ LIST_ENTRY *SadList;
+ LIST_ENTRY *SpdSas;
+ LIST_ENTRY *EntryInsertBefore;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Entry2;
+ LIST_ENTRY *NextEntry;
+ IPSEC_SPD_ENTRY *SpdEntry;
+ IPSEC_SAD_ENTRY *SadEntry;
+ UINTN SpdEntrySize;
+ UINTN Index;
+
+ SpdSel = (Selector == NULL) ? NULL : &Selector->SpdSelector;
+ SpdData = (Data == NULL) ? NULL : (EFI_IPSEC_SPD_DATA *) Data;
+ InsertBefore = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SpdSelector;
+ SpdList = &mConfigData[IPsecConfigDataTypeSpd];
+
+ if (SpdSel != NULL) {
+ if (SpdSel->LocalAddress == NULL || SpdSel->RemoteAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (SpdData != NULL) {
+ if ((SpdData->Action == EfiIPsecActionProtect && SpdData->ProcessingPolicy == NULL) ||
+ (SpdData->Action != EfiIPsecActionProtect && SpdData->ProcessingPolicy != NULL)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SpdData->Action == EfiIPsecActionProtect) {
+ if ((SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption == NULL) ||
+ (SpdData->ProcessingPolicy->Mode != EfiIPsecTunnel && SpdData->ProcessingPolicy->TunnelOption != NULL)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+ //
+ // The default behavior is to insert the node ahead of the header.
+ //
+ EntryInsertBefore = SpdList;
+
+ //
+ // Remove the existed SPD entry.
+ //
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SpdList) {
+
+ SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
+
+ if (SpdSel == NULL ||
+ CompareSpdSelector ((EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector, (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel)
+ ) {
+ //
+ // Record the existed entry position to keep the original order.
+ //
+ EntryInsertBefore = SpdEntry->List.ForwardLink;
+ RemoveEntryList (&SpdEntry->List);
+
+ //
+ // Update the reverse ref of SAD entry in the SPD.sas list.
+ //
+ SpdSas = &SpdEntry->Data->Sas;
+
+ //
+ // TODO: Deleted the related SAs.
+ //
+ NET_LIST_FOR_EACH (Entry2, SpdSas) {
+ SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry2);
+ SadEntry->Data->SpdEntry = NULL;
+ }
+
+ //
+ // Free the existed SPD entry
+ //
+ FreePool (SpdEntry);
+ }
+ }
+ //
+ // Return success here if only want to remove the SPD entry.
+ //
+ if (SpdData == NULL || SpdSel == NULL) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Search the appointed entry position if InsertBefore is not NULL.
+ //
+ if (InsertBefore != NULL) {
+
+ NET_LIST_FOR_EACH (Entry, SpdList) {
+ SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
+
+ if (CompareSpdSelector (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector,
+ (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
+ )) {
+ EntryInsertBefore = Entry;
+ break;
+ }
+ }
+ }
+
+ //
+ // Do Padding for the different Arch.
+ //
+ SpdEntrySize = ALIGN_VARIABLE (sizeof (IPSEC_SPD_ENTRY));
+ SpdEntrySize = ALIGN_VARIABLE (SpdEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SpdSel));
+ SpdEntrySize += IpSecGetSizeOfEfiSpdData (SpdData);
+
+ SpdEntry = AllocateZeroPool (SpdEntrySize);
+
+ if (SpdEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Fix the address of Selector and Data buffer and copy them, which is
+ // continous memory and close to the base structure of SPD entry.
+ //
+ SpdEntry->Selector = (EFI_IPSEC_SPD_SELECTOR *) ALIGN_POINTER ((SpdEntry + 1), sizeof (UINTN));
+ SpdEntry->Data = (IPSEC_SPD_DATA *) ALIGN_POINTER (
+ ((UINT8 *) SpdEntry->Selector + SIZE_OF_SPD_SELECTOR (SpdSel)),
+ sizeof (UINTN)
+ );
+
+ DuplicateSpdSelector (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector,
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,
+ NULL
+ );
+
+ CopyMem (
+ SpdEntry->Data->Name,
+ SpdData->Name,
+ sizeof (SpdData->Name)
+ );
+ SpdEntry->Data->PackageFlag = SpdData->PackageFlag;
+ SpdEntry->Data->TrafficDirection = SpdData->TrafficDirection;
+ SpdEntry->Data->Action = SpdData->Action;
+
+ //
+ // Fix the address of ProcessingPolicy and copy it if need, which is continous
+ // memory and close to the base structure of SAD data.
+ //
+ if (SpdData->Action != EfiIPsecActionProtect) {
+ SpdEntry->Data->ProcessingPolicy = NULL;
+ } else {
+ SpdEntry->Data->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ALIGN_POINTER (
+ SpdEntry->Data + 1,
+ sizeof (UINTN)
+ );
+ IpSecDuplicateProcessPolicy (SpdEntry->Data->ProcessingPolicy, SpdData->ProcessingPolicy);
+ }
+ //
+ // Update the sas list of the new SPD entry.
+ //
+ InitializeListHead (&SpdEntry->Data->Sas);
+
+ SadList = &mConfigData[IPsecConfigDataTypeSad];
+
+ NET_LIST_FOR_EACH (Entry, SadList) {
+ SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
+
+ for (Index = 0; Index < SpdData->SaIdCount; Index++) {
+
+ if (CompareSaId (
+ (EFI_IPSEC_CONFIG_SELECTOR *) &SpdData->SaId[Index],
+ (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id
+ )) {
+ if (SadEntry->Data->SpdEntry != NULL) {
+ RemoveEntryList (&SadEntry->BySpd);
+ }
+ InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);
+ SadEntry->Data->SpdEntry = SpdEntry;
+ }
+ }
+ }
+ //
+ // Insert the new SPD entry.
+ //
+ InsertTailList (EntryInsertBefore, &SpdEntry->List);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the security association information for the EFI IPsec driver.
+
+ The IPsec configuration data has a unique selector/identifier separately to
+ identify a data entry.
+
+ @param[in] Selector Pointer to an entry selector on operated
+ configuration data specified by DataType.
+ A NULL Selector causes the entire specified-type
+ configuration information to be flushed.
+ @param[in] Data The data buffer to be set. The structure
+ of the data buffer should be EFI_IPSEC_SA_DATA.
+ @param[in] Context Pointer to one entry selector which describes
+ the expected position the new data entry will
+ be added. If Context is NULL,the new entry will
+ be appended the end of database.
+
+ @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated.
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+
+**/
+EFI_STATUS
+SetSadEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN VOID *Context OPTIONAL
+ )
+{
+ IPSEC_SAD_ENTRY *SadEntry;
+ IPSEC_SPD_ENTRY *SpdEntry;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+ LIST_ENTRY *SadList;
+ LIST_ENTRY *SpdList;
+ EFI_IPSEC_SA_ID *SaId;
+ EFI_IPSEC_SA_DATA2 *SaData;
+ EFI_IPSEC_SA_ID *InsertBefore;
+ LIST_ENTRY *EntryInsertBefore;
+ UINTN SadEntrySize;
+
+ SaId = (Selector == NULL) ? NULL : &Selector->SaId;
+ SaData = (Data == NULL) ? NULL : (EFI_IPSEC_SA_DATA2 *) Data;
+ InsertBefore = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->SaId;
+ SadList = &mConfigData[IPsecConfigDataTypeSad];
+
+ //
+ // The default behavior is to insert the node ahead of the header.
+ //
+ EntryInsertBefore = SadList;
+
+ //
+ // Remove the existed SAD entry.
+ //
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SadList) {
+
+ SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
+
+ if (SaId == NULL ||
+ CompareSaId (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,
+ (EFI_IPSEC_CONFIG_SELECTOR *) SaId
+ )) {
+ //
+ // Record the existed entry position to keep the original order.
+ //
+ EntryInsertBefore = SadEntry->List.ForwardLink;
+
+ //
+ // Update the related SAD.byspd field.
+ //
+ if (SadEntry->Data->SpdEntry != NULL) {
+ RemoveEntryList (&SadEntry->BySpd);
+ }
+
+ RemoveEntryList (&SadEntry->List);
+ FreePool (SadEntry);
+ }
+ }
+ //
+ // Return success here if only want to remove the SAD entry
+ //
+ if (SaData == NULL || SaId == NULL) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Search the appointed entry position if InsertBefore is not NULL.
+ //
+ if (InsertBefore != NULL) {
+
+ NET_LIST_FOR_EACH (Entry, SadList) {
+ SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
+
+ if (CompareSaId (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id,
+ (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
+ )) {
+ EntryInsertBefore = Entry;
+ break;
+ }
+ }
+ }
+
+ //
+ // Do Padding for different Arch.
+ //
+ SadEntrySize = ALIGN_VARIABLE (sizeof (IPSEC_SAD_ENTRY));
+ SadEntrySize = ALIGN_VARIABLE (SadEntrySize + sizeof (EFI_IPSEC_SA_ID));
+ SadEntrySize = ALIGN_VARIABLE (SadEntrySize + sizeof (IPSEC_SAD_DATA));
+
+ if (SaId->Proto == EfiIPsecAH) {
+ SadEntrySize += SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength;
+ } else {
+ SadEntrySize = ALIGN_VARIABLE (SadEntrySize + SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength);
+ SadEntrySize += ALIGN_VARIABLE (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength);
+ }
+
+ if (SaData->SpdSelector != NULL) {
+ SadEntrySize += SadEntrySize + (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector);
+ }
+ SadEntry = AllocateZeroPool (SadEntrySize);
+
+ if (SadEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Fix the address of Id and Data buffer and copy them, which is
+ // continous memory and close to the base structure of SAD entry.
+ //
+ SadEntry->Id = (EFI_IPSEC_SA_ID *) ALIGN_POINTER ((SadEntry + 1), sizeof (UINTN));
+ SadEntry->Data = (IPSEC_SAD_DATA *) ALIGN_POINTER ((SadEntry->Id + 1), sizeof (UINTN));
+
+ CopyMem (SadEntry->Id, SaId, sizeof (EFI_IPSEC_SA_ID));
+
+ SadEntry->Data->Mode = SaData->Mode;
+ SadEntry->Data->SequenceNumber = SaData->SNCount;
+ SadEntry->Data->AntiReplayWindowSize = SaData->AntiReplayWindows;
+
+ ZeroMem (
+ &SadEntry->Data->AntiReplayBitmap,
+ sizeof (SadEntry->Data->AntiReplayBitmap)
+ );
+
+ ZeroMem (
+ &SadEntry->Data->AlgoInfo,
+ sizeof (EFI_IPSEC_ALGO_INFO)
+ );
+
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId = SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId;
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength = SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength;
+
+ if (SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) {
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SadEntry->Data + 1), sizeof (UINTN));
+ CopyMem (
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
+ SaData->AlgoInfo.EspAlgoInfo.AuthKey,
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength
+ );
+ }
+
+ if (SaId->Proto == EfiIPsecESP) {
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId = SaData->AlgoInfo.EspAlgoInfo.EncAlgoId;
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength = SaData->AlgoInfo.EspAlgoInfo.EncKeyLength;
+
+ if (SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (
+ ((UINT8 *) (SadEntry->Data + 1) +
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength),
+ sizeof (UINTN)
+ );
+ CopyMem (
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
+ SaData->AlgoInfo.EspAlgoInfo.EncKey,
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength
+ );
+ }
+ }
+
+ CopyMem (
+ &SadEntry->Data->SaLifetime,
+ &SaData->SaLifetime,
+ sizeof (EFI_IPSEC_SA_LIFETIME)
+ );
+
+ SadEntry->Data->PathMTU = SaData->PathMTU;
+ SadEntry->Data->SpdSelector = NULL;
+ SadEntry->Data->ESNEnabled = FALSE;
+ SadEntry->Data->ManualSet = SaData->ManualSet;
+
+ //
+ // Copy Tunnel Source/Destination Address
+ //
+ if (SaData->Mode == EfiIPsecTunnel) {
+ CopyMem (
+ &SadEntry->Data->TunnelDestAddress,
+ &SaData->TunnelDestinationAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+ CopyMem (
+ &SadEntry->Data->TunnelSourceAddress,
+ &SaData->TunnelSourceAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+ }
+ //
+ // Update the spd.sas list of the spd entry specified by SAD selector
+ //
+ SpdList = &mConfigData[IPsecConfigDataTypeSpd];
+
+ for (Entry = SpdList->ForwardLink; Entry != SpdList && SaData->SpdSelector != NULL; Entry = Entry->ForwardLink) {
+
+ SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
+ if (IsSubSpdSelector (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
+ ) && SpdEntry->Data->Action == EfiIPsecActionProtect) {
+ SadEntry->Data->SpdEntry = SpdEntry;
+ SadEntry->Data->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *)((UINT8 *)SadEntry +
+ SadEntrySize -
+ (UINTN)SIZE_OF_SPD_SELECTOR (SaData->SpdSelector)
+ );
+ DuplicateSpdSelector (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,
+ (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
+ NULL
+ );
+ InsertTailList (&SpdEntry->Data->Sas, &SadEntry->BySpd);
+ }
+ }
+ //
+ // Insert the new SAD entry.
+ //
+ InsertTailList (EntryInsertBefore, &SadEntry->List);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the peer authorization configuration information for the EFI IPsec driver.
+
+ The IPsec configuration data has a unique selector/identifier separately to
+ identify a data entry.
+
+ @param[in] Selector Pointer to an entry selector on operated
+ configuration data specified by DataType.
+ A NULL Selector causes the entire specified-type
+ configuration information to be flushed.
+ @param[in] Data The data buffer to be set. The structure
+ of the data buffer should be EFI_IPSEC_PAD_DATA.
+ @param[in] Context Pointer to one entry selector that describes
+ the expected position the new data entry will
+ be added. If Context is NULL, the new entry will
+ be appended the end of database.
+
+ @retval EFI_OUT_OF_RESOURCES The required system resources could not be allocated.
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+
+**/
+EFI_STATUS
+SetPadEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN VOID *Context OPTIONAL
+ )
+{
+ IPSEC_PAD_ENTRY *PadEntry;
+ EFI_IPSEC_PAD_ID *PadId;
+ EFI_IPSEC_PAD_DATA *PadData;
+ LIST_ENTRY *PadList;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *NextEntry;
+ EFI_IPSEC_PAD_ID *InsertBefore;
+ LIST_ENTRY *EntryInsertBefore;
+ UINTN PadEntrySize;
+
+ PadId = (Selector == NULL) ? NULL : &Selector->PadId;
+ PadData = (Data == NULL) ? NULL : (EFI_IPSEC_PAD_DATA *) Data;
+ InsertBefore = (Context == NULL) ? NULL : &((EFI_IPSEC_CONFIG_SELECTOR *) Context)->PadId;
+ PadList = &mConfigData[IPsecConfigDataTypePad];
+
+ //
+ // The default behavior is to insert the node ahead of the header.
+ //
+ EntryInsertBefore = PadList;
+
+ //
+ // Remove the existed pad entry.
+ //
+ NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, PadList) {
+
+ PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
+
+ if (PadId == NULL ||
+ ComparePadId ((EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id, (EFI_IPSEC_CONFIG_SELECTOR *) PadId)
+ ) {
+ //
+ // Record the existed entry position to keep the original order.
+ //
+ EntryInsertBefore = PadEntry->List.ForwardLink;
+ RemoveEntryList (&PadEntry->List);
+
+ FreePool (PadEntry);
+ }
+ }
+ //
+ // Return success here if only want to remove the pad entry
+ //
+ if (PadData == NULL || PadId == NULL) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Search the appointed entry position if InsertBefore is not NULL.
+ //
+ if (InsertBefore != NULL) {
+
+ NET_LIST_FOR_EACH (Entry, PadList) {
+ PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
+
+ if (ComparePadId (
+ (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id,
+ (EFI_IPSEC_CONFIG_SELECTOR *) InsertBefore
+ )) {
+ EntryInsertBefore = Entry;
+ break;
+ }
+ }
+ }
+
+ //
+ // Do PADDING for different arch.
+ //
+ PadEntrySize = ALIGN_VARIABLE (sizeof (IPSEC_PAD_ENTRY));
+ PadEntrySize = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_ID));
+ PadEntrySize = ALIGN_VARIABLE (PadEntrySize + sizeof (EFI_IPSEC_PAD_DATA));
+ PadEntrySize = ALIGN_VARIABLE (PadEntrySize + (PadData->AuthData != NULL ? PadData->AuthDataSize : 0));
+ PadEntrySize += PadData->RevocationData != NULL ? PadData->RevocationDataSize : 0;
+
+ PadEntry = AllocateZeroPool (PadEntrySize);
+
+ if (PadEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Fix the address of Id and Data buffer and copy them, which is
+ // continous memory and close to the base structure of pad entry.
+ //
+ PadEntry->Id = (EFI_IPSEC_PAD_ID *) ALIGN_POINTER ((PadEntry + 1), sizeof (UINTN));
+ PadEntry->Data = (EFI_IPSEC_PAD_DATA *) ALIGN_POINTER ((PadEntry->Id + 1), sizeof (UINTN));
+
+ CopyMem (PadEntry->Id, PadId, sizeof (EFI_IPSEC_PAD_ID));
+
+ PadEntry->Data->AuthProtocol = PadData->AuthProtocol;
+ PadEntry->Data->AuthMethod = PadData->AuthMethod;
+ PadEntry->Data->IkeIdFlag = PadData->IkeIdFlag;
+
+ if (PadData->AuthData != NULL) {
+ PadEntry->Data->AuthDataSize = PadData->AuthDataSize;
+ PadEntry->Data->AuthData = (VOID *) ALIGN_POINTER (PadEntry->Data + 1, sizeof (UINTN));
+ CopyMem (
+ PadEntry->Data->AuthData,
+ PadData->AuthData,
+ PadData->AuthDataSize
+ );
+ } else {
+ PadEntry->Data->AuthDataSize = 0;
+ PadEntry->Data->AuthData = NULL;
+ }
+
+ if (PadData->RevocationData != NULL) {
+ PadEntry->Data->RevocationDataSize = PadData->RevocationDataSize;
+ PadEntry->Data->RevocationData = (VOID *) ALIGN_POINTER (
+ ((UINT8 *) (PadEntry->Data + 1) + PadData->AuthDataSize),
+ sizeof (UINTN)
+ );
+ CopyMem (
+ PadEntry->Data->RevocationData,
+ PadData->RevocationData,
+ PadData->RevocationDataSize
+ );
+ } else {
+ PadEntry->Data->RevocationDataSize = 0;
+ PadEntry->Data->RevocationData = NULL;
+ }
+ //
+ // Insert the new pad entry.
+ //
+ InsertTailList (EntryInsertBefore, &PadEntry->List);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function lookup the data entry from IPsec SPD. Return the configuration
+ value of the specified SPD Entry.
+
+ @param[in] Selector Pointer to an entry selector which is an identifier
+ of the SPD entry.
+ @param[in, out] DataSize On output the size of data returned in Data.
+ @param[out] Data The buffer to return the contents of the IPsec
+ configuration data. The type of the data buffer
+ is associated with the DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero.
+ @retval EFI_NOT_FOUND The configuration data specified by Selector is not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+GetSpdEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ IPSEC_SPD_ENTRY *SpdEntry;
+ IPSEC_SAD_ENTRY *SadEntry;
+ EFI_IPSEC_SPD_SELECTOR *SpdSel;
+ EFI_IPSEC_SPD_DATA *SpdData;
+ LIST_ENTRY *SpdList;
+ LIST_ENTRY *SpdSas;
+ LIST_ENTRY *Entry;
+ UINTN RequiredSize;
+
+ SpdSel = &Selector->SpdSelector;
+ SpdData = (EFI_IPSEC_SPD_DATA *) Data;
+ SpdList = &mConfigData[IPsecConfigDataTypeSpd];
+
+ NET_LIST_FOR_EACH (Entry, SpdList) {
+ SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
+
+ //
+ // Find the required SPD entry
+ //
+ if (CompareSpdSelector (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdSel,
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
+ )) {
+
+ RequiredSize = IpSecGetSizeOfSpdData (SpdEntry->Data);
+ if (*DataSize < RequiredSize) {
+ *DataSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (SpdData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *DataSize = RequiredSize;
+
+ //
+ // Extract and fill all SaId array from the SPD.sas list
+ //
+ SpdSas = &SpdEntry->Data->Sas;
+ SpdData->SaIdCount = 0;
+
+ NET_LIST_FOR_EACH (Entry, SpdSas) {
+ SadEntry = IPSEC_SAD_ENTRY_FROM_SPD (Entry);
+ CopyMem (
+ &SpdData->SaId[SpdData->SaIdCount++],
+ SadEntry->Id,
+ sizeof (EFI_IPSEC_SA_ID)
+ );
+ }
+ //
+ // Fill the other fields in SPD data.
+ //
+ CopyMem (SpdData->Name, SpdEntry->Data->Name, sizeof (SpdData->Name));
+
+ SpdData->PackageFlag = SpdEntry->Data->PackageFlag;
+ SpdData->TrafficDirection = SpdEntry->Data->TrafficDirection;
+ SpdData->Action = SpdEntry->Data->Action;
+
+ if (SpdData->Action != EfiIPsecActionProtect) {
+ SpdData->ProcessingPolicy = NULL;
+ } else {
+ SpdData->ProcessingPolicy = (EFI_IPSEC_PROCESS_POLICY *) ((UINT8 *) SpdData + sizeof (EFI_IPSEC_SPD_DATA) + (SpdData->SaIdCount - 1) * sizeof (EFI_IPSEC_SA_ID));
+
+ IpSecDuplicateProcessPolicy (
+ SpdData->ProcessingPolicy,
+ SpdEntry->Data->ProcessingPolicy
+ );
+ }
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function lookup the data entry from IPsec SAD. Return the configuration
+ value of the specified SAD Entry.
+
+ @param[in] Selector Pointer to an entry selector which is an identifier
+ of the SAD entry.
+ @param[in, out] DataSize On output, the size of data returned in Data.
+ @param[out] Data The buffer to return the contents of the IPsec
+ configuration data. The type of the data buffer
+ is associated with the DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_NOT_FOUND The configuration data specified by Selector is not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+GetSadEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ IPSEC_SAD_ENTRY *SadEntry;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *SadList;
+ EFI_IPSEC_SA_ID *SaId;
+ EFI_IPSEC_SA_DATA2 *SaData;
+ UINTN RequiredSize;
+
+ SaId = &Selector->SaId;
+ SaData = (EFI_IPSEC_SA_DATA2 *) Data;
+ SadList = &mConfigData[IPsecConfigDataTypeSad];
+
+ NET_LIST_FOR_EACH (Entry, SadList) {
+ SadEntry = IPSEC_SAD_ENTRY_FROM_LIST (Entry);
+
+ //
+ // Find the required SAD entry.
+ //
+ if (CompareSaId (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SaId,
+ (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Id
+ )) {
+ //
+ // Calculate the required size of the SAD entry.
+ // Data Layout is follows:
+ // |EFI_IPSEC_SA_DATA
+ // |AuthKey
+ // |EncryptKey (Optional)
+ // |SpdSelector (Optional)
+ //
+ RequiredSize = ALIGN_VARIABLE (sizeof (EFI_IPSEC_SA_DATA2));
+
+ if (SaId->Proto == EfiIPsecAH) {
+ RequiredSize = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength);
+ } else {
+ RequiredSize = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength);
+ RequiredSize = ALIGN_VARIABLE (RequiredSize + SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength);
+ }
+
+ if (SadEntry->Data->SpdSelector != NULL) {
+ RequiredSize += SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector);
+ }
+
+ if (*DataSize < RequiredSize) {
+ *DataSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Fill the data fields of SAD entry.
+ //
+ *DataSize = RequiredSize;
+ SaData->Mode = SadEntry->Data->Mode;
+ SaData->SNCount = SadEntry->Data->SequenceNumber;
+ SaData->AntiReplayWindows = SadEntry->Data->AntiReplayWindowSize;
+
+ CopyMem (
+ &SaData->SaLifetime,
+ &SadEntry->Data->SaLifetime,
+ sizeof (EFI_IPSEC_SA_LIFETIME)
+ );
+
+ ZeroMem (
+ &SaData->AlgoInfo,
+ sizeof (EFI_IPSEC_ALGO_INFO)
+ );
+
+ if (SaId->Proto == EfiIPsecAH) {
+ //
+ // Copy AH alogrithm INFO to SaData
+ //
+ SaData->AlgoInfo.AhAlgoInfo.AuthAlgoId = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthAlgoId;
+ SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength = SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKeyLength;
+ if (SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength != 0) {
+ SaData->AlgoInfo.AhAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN));
+ CopyMem (
+ SaData->AlgoInfo.AhAlgoInfo.AuthKey,
+ SadEntry->Data->AlgoInfo.AhAlgoInfo.AuthKey,
+ SaData->AlgoInfo.AhAlgoInfo.AuthKeyLength
+ );
+ }
+ } else if (SaId->Proto == EfiIPsecESP) {
+ //
+ // Copy ESP alogrithem INFO to SaData
+ //
+ SaData->AlgoInfo.EspAlgoInfo.AuthAlgoId = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthAlgoId;
+ SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength = SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKeyLength;
+ if (SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength != 0) {
+ SaData->AlgoInfo.EspAlgoInfo.AuthKey = (VOID *) ALIGN_POINTER ((SaData + 1), sizeof (UINTN));
+ CopyMem (
+ SaData->AlgoInfo.EspAlgoInfo.AuthKey,
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.AuthKey,
+ SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength
+ );
+ }
+
+ SaData->AlgoInfo.EspAlgoInfo.EncAlgoId = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncAlgoId;
+ SaData->AlgoInfo.EspAlgoInfo.EncKeyLength = SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKeyLength;
+
+ if (SaData->AlgoInfo.EspAlgoInfo.EncKeyLength != 0) {
+ SaData->AlgoInfo.EspAlgoInfo.EncKey = (VOID *) ALIGN_POINTER (
+ ((UINT8 *) (SaData + 1) +
+ SaData->AlgoInfo.EspAlgoInfo.AuthKeyLength),
+ sizeof (UINTN)
+ );
+ CopyMem (
+ SaData->AlgoInfo.EspAlgoInfo.EncKey,
+ SadEntry->Data->AlgoInfo.EspAlgoInfo.EncKey,
+ SaData->AlgoInfo.EspAlgoInfo.EncKeyLength
+ );
+ }
+ }
+
+ SaData->PathMTU = SadEntry->Data->PathMTU;
+
+ //
+ // Fill Tunnel Address if it is Tunnel Mode
+ //
+ if (SadEntry->Data->Mode == EfiIPsecTunnel) {
+ CopyMem (
+ &SaData->TunnelDestinationAddress,
+ &SadEntry->Data->TunnelDestAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+ CopyMem (
+ &SaData->TunnelSourceAddress,
+ &SadEntry->Data->TunnelSourceAddress,
+ sizeof (EFI_IP_ADDRESS)
+ );
+ }
+ //
+ // Fill the spd selector field of SAD data
+ //
+ if (SadEntry->Data->SpdSelector != NULL) {
+
+ SaData->SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) (
+ (UINT8 *)SaData +
+ RequiredSize -
+ SIZE_OF_SPD_SELECTOR (SadEntry->Data->SpdSelector)
+ );
+
+ DuplicateSpdSelector (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SaData->SpdSelector,
+ (EFI_IPSEC_CONFIG_SELECTOR *) SadEntry->Data->SpdSelector,
+ NULL
+ );
+
+ } else {
+
+ SaData->SpdSelector = NULL;
+ }
+
+ SaData->ManualSet = SadEntry->Data->ManualSet;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function lookup the data entry from IPsec PAD. Return the configuration
+ value of the specified PAD Entry.
+
+ @param[in] Selector Pointer to an entry selector which is an identifier
+ of the PAD entry.
+ @param[in, out] DataSize On output the size of data returned in Data.
+ @param[out] Data The buffer to return the contents of the IPsec
+ configuration data. The type of the data buffer
+ is associated with the DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_NOT_FOUND The configuration data specified by Selector is not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+GetPadEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ IPSEC_PAD_ENTRY *PadEntry;
+ LIST_ENTRY *PadList;
+ LIST_ENTRY *Entry;
+ EFI_IPSEC_PAD_ID *PadId;
+ EFI_IPSEC_PAD_DATA *PadData;
+ UINTN RequiredSize;
+
+ PadId = &Selector->PadId;
+ PadData = (EFI_IPSEC_PAD_DATA *) Data;
+ PadList = &mConfigData[IPsecConfigDataTypePad];
+
+ NET_LIST_FOR_EACH (Entry, PadList) {
+ PadEntry = IPSEC_PAD_ENTRY_FROM_LIST (Entry);
+
+ //
+ // Find the required pad entry.
+ //
+ if (ComparePadId (
+ (EFI_IPSEC_CONFIG_SELECTOR *) PadId,
+ (EFI_IPSEC_CONFIG_SELECTOR *) PadEntry->Id
+ )) {
+ //
+ // Calculate the required size of the pad entry.
+ //
+ RequiredSize = ALIGN_VARIABLE (sizeof (EFI_IPSEC_PAD_DATA));
+ RequiredSize = ALIGN_VARIABLE (RequiredSize + PadEntry->Data->AuthDataSize);
+ RequiredSize += PadEntry->Data->RevocationDataSize;
+
+ if (*DataSize < RequiredSize) {
+ *DataSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // Fill the data fields of pad entry
+ //
+ *DataSize = RequiredSize;
+ PadData->AuthProtocol = PadEntry->Data->AuthProtocol;
+ PadData->AuthMethod = PadEntry->Data->AuthMethod;
+ PadData->IkeIdFlag = PadEntry->Data->IkeIdFlag;
+
+ //
+ // Copy Authentication data.
+ //
+ if (PadEntry->Data->AuthData != NULL) {
+
+ PadData->AuthDataSize = PadEntry->Data->AuthDataSize;
+ PadData->AuthData = (VOID *) ALIGN_POINTER ((PadData + 1), sizeof (UINTN));
+ CopyMem (
+ PadData->AuthData,
+ PadEntry->Data->AuthData,
+ PadData->AuthDataSize
+ );
+ } else {
+
+ PadData->AuthDataSize = 0;
+ PadData->AuthData = NULL;
+ }
+ //
+ // Copy Revocation Data.
+ //
+ if (PadEntry->Data->RevocationData != NULL) {
+
+ PadData->RevocationDataSize = PadEntry->Data->RevocationDataSize;
+ PadData->RevocationData = (VOID *) ALIGN_POINTER (
+ ((UINT8 *) (PadData + 1) + PadData->AuthDataSize),
+ sizeof (UINTN)
+ );
+ CopyMem (
+ PadData->RevocationData,
+ PadEntry->Data->RevocationData,
+ PadData->RevocationDataSize
+ );
+ } else {
+
+ PadData->RevocationDataSize = 0;
+ PadData->RevocationData = NULL;
+ }
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Copy Source Process Policy to the Destination Process Policy.
+
+ @param[in] Dst Pointer to the Source Process Policy.
+ @param[in] Src Pointer to the Destination Process Policy.
+
+**/
+VOID
+IpSecDuplicateProcessPolicy (
+ IN EFI_IPSEC_PROCESS_POLICY *Dst,
+ IN EFI_IPSEC_PROCESS_POLICY *Src
+ )
+{
+ //
+ // Firstly copy the structure content itself.
+ //
+ CopyMem (Dst, Src, sizeof (EFI_IPSEC_PROCESS_POLICY));
+
+ //
+ // Recursively copy the tunnel option if needed.
+ //
+ if (Dst->Mode != EfiIPsecTunnel) {
+ ASSERT (Dst->TunnelOption == NULL);
+ } else {
+ Dst->TunnelOption = (EFI_IPSEC_TUNNEL_OPTION *) ALIGN_POINTER ((Dst + 1), sizeof (UINTN));
+ CopyMem (
+ Dst->TunnelOption,
+ Src->TunnelOption,
+ sizeof (EFI_IPSEC_TUNNEL_OPTION)
+ );
+ }
+}
+
+/**
+ Calculate the a whole size of EFI_IPSEC_SPD_DATA, which includes the buffer size pointed
+ to by the pointer members.
+
+ @param[in] SpdData Pointer to a specified EFI_IPSEC_SPD_DATA.
+
+ @return the whole size the specified EFI_IPSEC_SPD_DATA.
+
+**/
+UINTN
+IpSecGetSizeOfEfiSpdData (
+ IN EFI_IPSEC_SPD_DATA *SpdData
+ )
+{
+ UINTN Size;
+
+ Size = ALIGN_VARIABLE (sizeof (IPSEC_SPD_DATA));
+
+ if (SpdData->Action == EfiIPsecActionProtect) {
+ Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_PROCESS_POLICY));
+
+ if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) {
+ Size = ALIGN_VARIABLE (Size + sizeof (EFI_IPSEC_TUNNEL_OPTION));
+ }
+ }
+
+ return Size;
+}
+
+/**
+ Calculate the a whole size of IPSEC_SPD_DATA which includes the buffer size pointed
+ to by the pointer members and the buffer size used by the Sa List.
+
+ @param[in] SpdData Pointer to the specified IPSEC_SPD_DATA.
+
+ @return the whole size of IPSEC_SPD_DATA.
+
+**/
+UINTN
+IpSecGetSizeOfSpdData (
+ IN IPSEC_SPD_DATA *SpdData
+ )
+{
+ UINTN Size;
+ LIST_ENTRY *Link;
+
+ Size = sizeof (EFI_IPSEC_SPD_DATA) - sizeof (EFI_IPSEC_SA_ID);
+
+ if (SpdData->Action == EfiIPsecActionProtect) {
+ Size += sizeof (EFI_IPSEC_PROCESS_POLICY);
+
+ if (SpdData->ProcessingPolicy->Mode == EfiIPsecTunnel) {
+ Size += sizeof (EFI_IPSEC_TUNNEL_OPTION);
+ }
+ }
+
+ NET_LIST_FOR_EACH (Link, &SpdData->Sas) {
+ Size += sizeof (EFI_IPSEC_SA_ID);
+ }
+
+ return Size;
+}
+
+/**
+ Get the IPsec Variable.
+
+ Get the all variables which start with the string contained in VaraiableName.
+ Since all IPsec related variable store in continual space, those kinds of
+ variable can be searched by the EfiGetNextVariableName. Those variables also are
+ returned in a continual buffer.
+
+ @param[in] VariableName Pointer to a specified Variable Name.
+ @param[in] VendorGuid Pointer to a specified Vendor Guid.
+ @param[in] Attributes Point to memory location to return the attributes
+ of variable. If the point is NULL, the parameter
+ would be ignored.
+ @param[in, out] DataSize As input, point to the maximum size of return
+ Data-Buffer. As output, point to the actual
+ size of the returned Data-Buffer.
+ @param[in] Data Point to return Data-Buffer.
+
+ @retval EFI_ABORTED If the Variable size which contained in the variable
+ structure doesn't match the variable size obtained
+ from the EFIGetVariable.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has
+ been updated with the size needed to complete the request.
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval others Other errors found during the variable getting.
+**/
+EFI_STATUS
+IpSecGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 *Attributes, OPTIONAL
+ IN OUT UINTN *DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID VendorGuidI;
+ UINTN VariableNameLength;
+ CHAR16 *VariableNameI;
+ UINTN VariableNameISize;
+ UINTN VariableNameISizeNew;
+ UINTN VariableIndex;
+ UINTN VariableCount;
+ IP_SEC_VARIABLE_INFO IpSecVariableInfo;
+ UINTN DataSizeI;
+
+ //
+ // The variable name constructor is "VariableName + Info/0001/0002/... + NULL".
+ // So the varialbe name is like "VariableNameInfo", "VariableName0001", ...
+ // "VariableNameNULL".
+ //
+ VariableNameLength = StrLen (VariableName);
+ VariableNameISize = (VariableNameLength + 5) * sizeof (CHAR16);
+ VariableNameI = AllocateZeroPool (VariableNameISize);
+ if (VariableNameI == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Construct the varible name of ipsecconfig meta data.
+ //
+ UnicodeSPrint (VariableNameI, VariableNameISize, L"%s%s", VariableName, L"Info");
+
+ DataSizeI = sizeof (IpSecVariableInfo);
+
+ Status = gRT->GetVariable (
+ VariableNameI,
+ VendorGuid,
+ Attributes,
+ &DataSizeI,
+ &IpSecVariableInfo
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ if (*DataSize < IpSecVariableInfo.VariableSize) {
+ *DataSize = IpSecVariableInfo.VariableSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto ON_EXIT;
+ }
+
+ VariableCount = IpSecVariableInfo.VariableCount;
+ VariableNameI[0] = L'\0';
+
+ while (VariableCount != 0) {
+ //
+ // Get the variable name one by one in the variable database.
+ //
+ VariableNameISizeNew = VariableNameISize;
+ Status = gRT->GetNextVariableName (
+ &VariableNameISizeNew,
+ VariableNameI,
+ &VendorGuidI
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ VariableNameI = ReallocatePool (
+ VariableNameISize,
+ VariableNameISizeNew,
+ VariableNameI
+ );
+ if (VariableNameI == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+ VariableNameISize = VariableNameISizeNew;
+
+ Status = gRT->GetNextVariableName (
+ &VariableNameISizeNew,
+ VariableNameI,
+ &VendorGuidI
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Check whether the current variable is the required "ipsecconfig".
+ //
+ if (StrnCmp (VariableNameI, VariableName, VariableNameLength) == 0 ||
+ CompareGuid (VendorGuid, &VendorGuidI)
+ ) {
+ //
+ // Parse the variable count of the current ipsecconfig data.
+ //
+ VariableIndex = StrDecimalToUintn (VariableNameI + VariableNameLength);
+ if (VariableIndex!= 0 && VariableIndex <= IpSecVariableInfo.VariableCount) {
+ //
+ // Get the variable size of the current ipsecconfig data.
+ //
+ DataSizeI = 0;
+ Status = gRT->GetVariable (
+ VariableNameI,
+ VendorGuid,
+ Attributes,
+ &DataSizeI,
+ NULL
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+ //
+ // Validate the variable count and variable size.
+ //
+ if (VariableIndex != IpSecVariableInfo.VariableCount) {
+ //
+ // If the varaibe is not the last one, its size should be the max
+ // size of the single variable.
+ //
+ if (DataSizeI != IpSecVariableInfo.SingleVariableSize) {
+ return EFI_ABORTED;
+ }
+ } else {
+ if (DataSizeI != IpSecVariableInfo.VariableSize % IpSecVariableInfo.SingleVariableSize) {
+ return EFI_ABORTED;
+ }
+ }
+ //
+ // Get the variable data of the current ipsecconfig data and
+ // store it into user buffer continously.
+ //
+ Status = gRT->GetVariable (
+ VariableNameI,
+ VendorGuid,
+ Attributes,
+ &DataSizeI,
+ (UINT8 *) Data + (VariableIndex - 1) * IpSecVariableInfo.SingleVariableSize
+ );
+ ASSERT_EFI_ERROR (Status);
+ VariableCount--;
+ }
+ }
+ }
+ //
+ // The VariableCount in "VariableNameInfo" varaible should have the correct
+ // numbers of variables which name starts with VariableName.
+ //
+ if (VariableCount != 0) {
+ Status = EFI_ABORTED;
+ }
+
+ON_EXIT:
+ if (VariableNameI != NULL) {
+ FreePool (VariableNameI);
+ }
+ return Status;
+}
+
+/**
+ Set the IPsec variables.
+
+ Set all IPsec variables which start with the specified variable name. Those variables
+ are set one by one.
+
+ @param[in] VariableName The name of the vendor's variable. It is a
+ Null-Terminated Unicode String.
+ @param[in] VendorGuid Unify identifier for vendor.
+ @param[in] Attributes Point to memory location to return the attributes of
+ variable. If the point is NULL, the parameter would be ignored.
+ @param[in] DataSize The size in bytes of Data-Buffer.
+ @param[in] Data Points to the content of the variable.
+
+ @retval EFI_SUCCESS The firmware successfully stored the variable and its data, as
+ defined by the Attributes.
+ @retval others Storing the variables failed.
+
+**/
+EFI_STATUS
+IpSecSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *VariableNameI;
+ UINTN VariableNameSize;
+ UINTN VariableIndex;
+ IP_SEC_VARIABLE_INFO IpSecVariableInfo;
+ UINT64 MaximumVariableStorageSize;
+ UINT64 RemainingVariableStorageSize;
+ UINT64 MaximumVariableSize;
+
+ Status = gRT->QueryVariableInfo (
+ Attributes,
+ &MaximumVariableStorageSize,
+ &RemainingVariableStorageSize,
+ &MaximumVariableSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // "VariableName + Info/0001/0002/... + NULL"
+ //
+ VariableNameSize = (StrLen (VariableName) + 5) * sizeof (CHAR16);
+ VariableNameI = AllocateZeroPool (VariableNameSize);
+
+ if (VariableNameI == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ //
+ // Construct the variable of ipsecconfig general information. Like the total
+ // numbers of the Ipsecconfig variables, the total size of all ipsecconfig variables.
+ //
+ UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%s", VariableName, L"Info");
+ MaximumVariableSize -= VariableNameSize;
+
+ IpSecVariableInfo.VariableCount = (UINT32) ((DataSize + (UINTN) MaximumVariableSize - 1) / (UINTN) MaximumVariableSize);
+ IpSecVariableInfo.VariableSize = (UINT32) DataSize;
+ IpSecVariableInfo.SingleVariableSize = (UINT32) MaximumVariableSize;
+
+ //
+ // Set the variable of ipsecconfig general information.
+ //
+ Status = gRT->SetVariable (
+ VariableNameI,
+ VendorGuid,
+ Attributes,
+ sizeof (IpSecVariableInfo),
+ &IpSecVariableInfo
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error set ipsecconfig meta data with %r\n", Status));
+ goto ON_EXIT;
+ }
+
+ for (VariableIndex = 0; VariableIndex < IpSecVariableInfo.VariableCount; VariableIndex++) {
+ //
+ // Construct and set the variable of ipsecconfig data one by one.
+ // The index of variable name begin from 0001, and the varaible name
+ // likes "VariableName0001", "VaraiableName0002"....
+ //
+ UnicodeSPrint (VariableNameI, VariableNameSize, L"%s%04d", VariableName, VariableIndex + 1);
+ Status = gRT->SetVariable (
+ VariableNameI,
+ VendorGuid,
+ Attributes,
+ (VariableIndex == IpSecVariableInfo.VariableCount - 1) ?
+ (DataSize % (UINTN) MaximumVariableSize) :
+ (UINTN) MaximumVariableSize,
+ (UINT8 *) Data + VariableIndex * (UINTN) MaximumVariableSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error set ipsecconfig variable data with %r\n", Status));
+ goto ON_EXIT;
+ }
+ }
+
+ON_EXIT:
+ if (VariableNameI != NULL) {
+ FreePool (VariableNameI);
+ }
+
+ return Status;
+}
+
+/**
+ Return the configuration value for the EFI IPsec driver.
+
+ This function lookup the data entry from IPsec database or IKEv2 configuration
+ information. The expected data type and unique identification are described in
+ DataType and Selector parameters.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The type of data to retrieve.
+ @param[in] Selector Pointer to an entry selector that is an identifier of the IPsec
+ configuration data entry.
+ @param[in, out] DataSize On output the size of data returned in Data.
+ @param[out] Data The buffer to return the contents of the IPsec configuration data.
+ The type of the data buffer associated with the DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
+ - This is NULL.
+ - Selector is NULL.
+ - DataSize is NULL.
+ - Data is NULL and *DataSize is not zero
+ @retval EFI_NOT_FOUND The configuration data specified by Selector is not found.
+ @retval EFI_UNSUPPORTED The specified DataType is not supported.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigGetData (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ if (This == NULL || Selector == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*DataSize != 0 && Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataType >= IPsecConfigDataTypeMaximum) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return mGetPolicyEntry[DataType](Selector, DataSize, Data);
+}
+
+/**
+ Set the security association, security policy and peer authorization configuration
+ information for the EFI IPsec driver.
+
+ This function is used to set the IPsec configuration information of type DataType for
+ the EFI IPsec driver.
+ The IPsec configuration data has a unique selector/identifier separately to identify
+ a data entry. The selector structure depends on DataType's definition.
+ Using SetData() with a Data of NULL causes the IPsec configuration data entry identified
+ by DataType and Selector to be deleted.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The type of data to be set.
+ @param[in] Selector Pointer to an entry selector on operated configuration data
+ specified by DataType. A NULL Selector causes the entire
+ specified-type configuration information to be flushed.
+ @param[in] Data The data buffer to be set. The structure of the data buffer is
+ associated with the DataType.
+ @param[in] InsertBefore Pointer to one entry selector which describes the expected
+ position the new data entry will be added. If InsertBefore is NULL,
+ the new entry will be appended to the end of the database.
+
+ @retval EFI_SUCCESS The specified configuration entry data was set successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
+ - This is NULL.
+ @retval EFI_UNSUPPORTED The specified DataType is not supported.
+ @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigSetData (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN EFI_IPSEC_CONFIG_SELECTOR *InsertBefore OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataType >= IPsecConfigDataTypeMaximum) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = mSetPolicyEntry[DataType](Selector, Data, InsertBefore);
+
+ if (!EFI_ERROR (Status) && !mSetBySelf) {
+ //
+ // Save the updated config data into variable.
+ //
+ IpSecConfigSave ();
+ }
+
+ return Status;
+}
+
+/**
+ Enumerates the current selector for IPsec configuration data entry.
+
+ This function is called multiple times to retrieve the entry Selector in IPsec
+ configuration database. On each call to GetNextSelector(), the next entry
+ Selector are retrieved into the output interface.
+
+ If the entire IPsec configuration database has been iterated, the error
+ EFI_NOT_FOUND is returned.
+ If the Selector buffer is too small for the next Selector copy, an
+ EFI_BUFFER_TOO_SMALL error is returned, and SelectorSize is updated to reflect
+ the size of buffer needed.
+
+ On the initial call to GetNextSelector() to start the IPsec configuration database
+ search, a pointer to the buffer with all zero value is passed in Selector. Calls
+ to SetData() between calls to GetNextSelector may produce unpredictable results.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The type of IPsec configuration data to retrieve.
+ @param[in, out] SelectorSize The size of the Selector buffer.
+ @param[in, out] Selector On input, supplies the pointer to last Selector that was
+ returned by GetNextSelector().
+ On output, returns one copy of the current entry Selector
+ of a given DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
+ - This is NULL.
+ - SelectorSize is NULL.
+ - Selector is NULL.
+ @retval EFI_NOT_FOUND The next configuration data entry was not found.
+ @retval EFI_UNSUPPORTED The specified DataType is not supported.
+ @retval EFI_BUFFER_TOO_SMALL The SelectorSize is too small for the result. This parameter
+ has been updated with the size needed to complete the search
+ request.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigGetNextSelector (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN OUT UINTN *SelectorSize,
+ IN OUT EFI_IPSEC_CONFIG_SELECTOR *Selector
+ )
+{
+ LIST_ENTRY *Link;
+ IPSEC_COMMON_POLICY_ENTRY *CommonEntry;
+ BOOLEAN IsFound;
+
+ if (This == NULL || Selector == NULL || SelectorSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataType >= IPsecConfigDataTypeMaximum) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IsFound = FALSE;
+
+ NET_LIST_FOR_EACH (Link, &mConfigData[DataType]) {
+ CommonEntry = BASE_CR (Link, IPSEC_COMMON_POLICY_ENTRY, List);
+
+ if (IsFound || (BOOLEAN)(mIsZeroSelector[DataType](Selector))) {
+ //
+ // If found the appointed entry, then duplicate the next one and return,
+ // or if the appointed entry is zero, then return the first one directly.
+ //
+ return mDuplicateSelector[DataType](Selector, CommonEntry->Selector, SelectorSize);
+ } else {
+ //
+ // Set the flag if find the appointed entry.
+ //
+ IsFound = mCompareSelector[DataType](Selector, CommonEntry->Selector);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Register an event that is to be signaled whenever a configuration process on the
+ specified IPsec configuration information is done.
+
+ The register function is not surpport now and always returns EFI_UNSUPPORTED.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The type of data to be registered the event for.
+ @param[in] Event The event to be registered.
+
+ @retval EFI_SUCCESS The event is registered successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
+ @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.
+ @retval EFI_UNSUPPORTED The notify registration is unsupported, or the specified
+ DataType is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigRegisterNotify (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN EFI_EVENT Event
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Remove the specified event that was previously registered on the specified IPsec
+ configuration data.
+
+ This function is not support now and alwasy return EFI_UNSUPPORTED.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The configuration data type to remove the registered event for.
+ @param[in] Event The event to be unregistered.
+
+ @retval EFI_SUCCESS The event was removed successfully.
+ @retval EFI_NOT_FOUND The Event specified by DataType could not be found in the
+ database.
+ @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
+ @retval EFI_UNSUPPORTED The notify registration is unsupported, or the specified
+ DataType is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigUnregisterNotify (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN EFI_EVENT Event
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Copy whole data in specified EFI_SIPEC_CONFIG_SELECTOR and the Data to a buffer.
+
+ This function is a caller defined function, and it is called by the IpSecVisitConfigData().
+ The orignal caller is IpSecConfigSave(), which calls the IpsecVisitConfigData() to
+ copy all types of IPsec Config datas into one buffer and store this buffer into firmware in
+ the form of several variables.
+
+ @param[in] Type A specified IPSEC_CONFIG_DATA_TYPE.
+ @param[in] Selector Points to a EFI_IPSEC_CONFIG_SELECTOR to be copied
+ to the buffer.
+ @param[in] Data Points to data to be copied to the buffer. The
+ Data type is related to the Type.
+ @param[in] SelectorSize The size of the Selector.
+ @param[in] DataSize The size of the Data.
+ @param[in, out] Buffer The buffer to store the Selector and Data.
+
+ @retval EFI_SUCCESS Copy the Selector and Data to a buffer successfully.
+ @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated.
+
+**/
+EFI_STATUS
+IpSecCopyPolicyEntry (
+ IN EFI_IPSEC_CONFIG_DATA_TYPE Type,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN UINTN SelectorSize,
+ IN UINTN DataSize,
+ IN OUT IPSEC_VARIABLE_BUFFER *Buffer
+ )
+{
+ IPSEC_VAR_ITEM_HEADER SelectorHeader;
+ IPSEC_VAR_ITEM_HEADER DataHeader;
+ UINTN EntrySize;
+ UINT8 *TempPoint;
+
+ if (Type == IPsecConfigDataTypeSad) {
+ //
+ // Don't save automatically-generated SA entry into variable.
+ //
+ if (((EFI_IPSEC_SA_DATA2 *) Data)->ManualSet == FALSE) {
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // Increase the capacity size of the buffer if needed.
+ //
+ EntrySize = ALIGN_VARIABLE (sizeof (SelectorHeader));
+ EntrySize = ALIGN_VARIABLE (EntrySize + SelectorSize);
+ EntrySize = ALIGN_VARIABLE (EntrySize + sizeof (SelectorHeader));
+ EntrySize = ALIGN_VARIABLE (EntrySize + DataSize);
+
+ //EntrySize = SelectorSize + DataSize + 2 * sizeof (SelectorHeader);
+ if (Buffer->Capacity - Buffer->Size < EntrySize) {
+ //
+ // Calculate the required buffer
+ //
+ Buffer->Capacity += EntrySize;
+ TempPoint = AllocatePool (Buffer->Capacity);
+
+ if (TempPoint == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Copy the old Buffer to new buffer and free the old one.
+ //
+ CopyMem (TempPoint, Buffer->Ptr, Buffer->Size);
+ FreePool (Buffer->Ptr);
+
+ Buffer->Ptr = TempPoint;
+ }
+
+ mFixPolicyEntry[Type](Selector, Data);
+
+ //
+ // Fill the selector header and copy it into buffer.
+ //
+ SelectorHeader.Type = (UINT8) (Type | IPSEC_VAR_ITEM_HEADER_LOGO_BIT);
+ SelectorHeader.Size = (UINT16) SelectorSize;
+
+ CopyMem (
+ Buffer->Ptr + Buffer->Size,
+ &SelectorHeader,
+ sizeof (SelectorHeader)
+ );
+ Buffer->Size = ALIGN_VARIABLE (Buffer->Size + sizeof (SelectorHeader));
+
+ //
+ // Copy the selector into buffer.
+ //
+ CopyMem (
+ Buffer->Ptr + Buffer->Size,
+ Selector,
+ SelectorSize
+ );
+ Buffer->Size = ALIGN_VARIABLE (Buffer->Size + SelectorSize);
+
+ //
+ // Fill the data header and copy it into buffer.
+ //
+ DataHeader.Type = (UINT8) Type;
+ DataHeader.Size = (UINT16) DataSize;
+
+ CopyMem (
+ Buffer->Ptr + Buffer->Size,
+ &DataHeader,
+ sizeof (DataHeader)
+ );
+ Buffer->Size = ALIGN_VARIABLE (Buffer->Size + sizeof (DataHeader));
+ //
+ // Copy the data into buffer.
+ //
+ CopyMem (
+ Buffer->Ptr + Buffer->Size,
+ Data,
+ DataSize
+ );
+ Buffer->Size = ALIGN_VARIABLE (Buffer->Size + DataSize);
+
+ mUnfixPolicyEntry[Type](Selector, Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Visit all IPsec Configurations of specified Type and call the caller defined
+ interface.
+
+ @param[in] DataType The specified IPsec Config Data Type.
+ @param[in] Routine The function defined by the caller.
+ @param[in] Context The data passed to the Routine.
+
+ @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated
+ @retval EFI_SUCCESS This function completed successfully.
+
+**/
+EFI_STATUS
+IpSecVisitConfigData (
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN IPSEC_COPY_POLICY_ENTRY Routine,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS GetNextStatus;
+ EFI_STATUS GetDataStatus;
+ EFI_STATUS RoutineStatus;
+ EFI_IPSEC_CONFIG_SELECTOR *Selector;
+ VOID *Data;
+ UINTN SelectorSize;
+ UINTN DataSize;
+ UINTN SelectorBufferSize;
+ UINTN DataBufferSize;
+ BOOLEAN FirstGetNext;
+
+ FirstGetNext = TRUE;
+ DataBufferSize = 0;
+ Data = NULL;
+ SelectorBufferSize = sizeof (EFI_IPSEC_CONFIG_SELECTOR);
+ Selector = AllocateZeroPool (SelectorBufferSize);
+
+ if (Selector == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ while (TRUE) {
+ //
+ // Get the real size of the selector.
+ //
+ SelectorSize = SelectorBufferSize;
+ GetNextStatus = EfiIpSecConfigGetNextSelector (
+ &mIpSecConfigInstance,
+ DataType,
+ &SelectorSize,
+ Selector
+ );
+ if (GetNextStatus == EFI_BUFFER_TOO_SMALL) {
+ FreePool (Selector);
+ SelectorBufferSize = SelectorSize;
+ //
+ // Allocate zero pool for the first selector, while store the last
+ // selector content for the other selectors.
+ //
+ if (FirstGetNext) {
+ Selector = AllocateZeroPool (SelectorBufferSize);
+ } else {
+ Selector = AllocateCopyPool (SelectorBufferSize, Selector);
+ }
+
+ if (Selector == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get the content of the selector.
+ //
+ GetNextStatus = EfiIpSecConfigGetNextSelector (
+ &mIpSecConfigInstance,
+ DataType,
+ &SelectorSize,
+ Selector
+ );
+ }
+
+ if (EFI_ERROR (GetNextStatus)) {
+ break;
+ }
+
+ FirstGetNext = FALSE;
+
+ //
+ // Get the real size of the policy entry according to the selector.
+ //
+ DataSize = DataBufferSize;
+ GetDataStatus = EfiIpSecConfigGetData (
+ &mIpSecConfigInstance,
+ DataType,
+ Selector,
+ &DataSize,
+ Data
+ );
+ if (GetDataStatus == EFI_BUFFER_TOO_SMALL) {
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ DataBufferSize = DataSize;
+ Data = AllocateZeroPool (DataBufferSize);
+
+ if (Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get the content of the policy entry according to the selector.
+ //
+ GetDataStatus = EfiIpSecConfigGetData (
+ &mIpSecConfigInstance,
+ DataType,
+ Selector,
+ &DataSize,
+ Data
+ );
+ }
+
+ if (EFI_ERROR (GetDataStatus)) {
+ break;
+ }
+ //
+ // Prepare the buffer of updated policy entry, which is stored in
+ // the continous memory, and then save into variable later.
+ //
+ RoutineStatus = Routine (
+ DataType,
+ Selector,
+ Data,
+ SelectorSize,
+ DataSize,
+ Context
+ );
+ if (EFI_ERROR (RoutineStatus)) {
+ break;
+ }
+ }
+
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ if (Selector != NULL) {
+ FreePool (Selector);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the subfunction of EFIIpSecConfigSetData.
+
+ This function call IpSecSetVaraible to set the IPsec Configuration into the firmware.
+
+ @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated.
+ @retval EFI_SUCCESS Saved the configration successfully.
+ @retval Others Other errors were found while obtaining the variable.
+
+**/
+EFI_STATUS
+IpSecConfigSave (
+ VOID
+ )
+{
+ IPSEC_VARIABLE_BUFFER Buffer;
+ EFI_STATUS Status;
+ EFI_IPSEC_CONFIG_DATA_TYPE Type;
+
+ Buffer.Size = 0;
+ Buffer.Capacity = IPSEC_DEFAULT_VARIABLE_SIZE;
+ Buffer.Ptr = AllocateZeroPool (Buffer.Capacity);
+
+ if (Buffer.Ptr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // For each policy database, prepare the contious buffer to save into variable.
+ //
+ for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) {
+ IpSecVisitConfigData (
+ Type,
+ (IPSEC_COPY_POLICY_ENTRY) IpSecCopyPolicyEntry,
+ &Buffer
+ );
+ }
+ //
+ // Save the updated policy database into variable.
+ //
+ Status = IpSecSetVariable (
+ IPSECCONFIG_VARIABLE_NAME,
+ &gEfiIpSecConfigProtocolGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ Buffer.Size,
+ Buffer.Ptr
+ );
+
+ FreePool (Buffer.Ptr);
+
+ return Status;
+}
+
+/**
+ Get the all IPSec configuration variables and store those variables
+ to the internal data structure.
+
+ This founction is called by IpSecConfigInitialize() which is to intialize the
+ IPsecConfiguration Protocol.
+
+ @param[in] Private Point to IPSEC_PRIVATE_DATA.
+
+ @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated
+ @retval EFI_SUCCESS Restore the IPsec Configuration successfully.
+ @retval others Other errors is found while obtaining the variable.
+
+**/
+EFI_STATUS
+IpSecConfigRestore (
+ IN IPSEC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ UINT8 *Buffer;
+ IPSEC_VAR_ITEM_HEADER *Header;
+ UINT8 *Ptr;
+ EFI_IPSEC_CONFIG_SELECTOR *Selector;
+ EFI_IPSEC_CONFIG_DATA_TYPE Type;
+ VOID *Data;
+ UINT8 Value;
+ UINTN Size;
+
+ Value = 0;
+ Size = sizeof (Value);
+ BufferSize = 0;
+ Buffer = NULL;
+
+ Status = gRT->GetVariable (
+ IPSECCONFIG_STATUS_NAME,
+ &gEfiIpSecConfigProtocolGuid,
+ NULL,
+ &Size,
+ &Value
+ );
+
+ if (!EFI_ERROR (Status) && Value == IPSEC_STATUS_ENABLED) {
+ Private->IpSec.DisabledFlag = FALSE;
+ }
+ //
+ // Get the real size of policy database in variable.
+ //
+ Status = IpSecGetVariable (
+ IPSECCONFIG_VARIABLE_NAME,
+ &gEfiIpSecConfigProtocolGuid,
+ NULL,
+ &BufferSize,
+ Buffer
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get the content of policy database in variable.
+ //
+ Status = IpSecGetVariable (
+ IPSECCONFIG_VARIABLE_NAME,
+ &gEfiIpSecConfigProtocolGuid,
+ NULL,
+ &BufferSize,
+ Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return Status;
+ }
+
+ for (Ptr = Buffer; Ptr < Buffer + BufferSize;) {
+
+ Header = (IPSEC_VAR_ITEM_HEADER *) Ptr;
+ Type = (EFI_IPSEC_CONFIG_DATA_TYPE) (Header->Type & IPSEC_VAR_ITEM_HEADER_CONTENT_BIT);
+ ASSERT (((Header->Type & 0x80) == IPSEC_VAR_ITEM_HEADER_LOGO_BIT) && (Type < IPsecConfigDataTypeMaximum));
+
+ Selector = (EFI_IPSEC_CONFIG_SELECTOR *) ALIGN_POINTER (Header + 1, sizeof (UINTN));
+ Header = (IPSEC_VAR_ITEM_HEADER *) ALIGN_POINTER (
+ (UINT8 *) Selector + Header->Size,
+ sizeof (UINTN)
+ );
+ ASSERT (Header->Type == Type);
+
+ Data = ALIGN_POINTER (Header + 1, sizeof (UINTN));
+
+ mUnfixPolicyEntry[Type](Selector, Data);
+
+ //
+ // Update each policy entry according to the content in variable.
+ //
+ mSetBySelf = TRUE;
+ Status = EfiIpSecConfigSetData (
+ &Private->IpSecConfig,
+ Type,
+ Selector,
+ Data,
+ NULL
+ );
+ mSetBySelf = FALSE;
+
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ return Status;
+ }
+
+ Ptr = ALIGN_POINTER ((UINT8 *) Data + Header->Size, sizeof (UINTN));
+ }
+
+ FreePool (Buffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Install and Initialize IPsecConfig protocol
+
+ @param[in, out] Private Pointer to IPSEC_PRIVATE_DATA. After this function finish,
+ the pointer of IPsecConfig Protocol implementation will copy
+ into its IPsecConfig member.
+
+ @retval EFI_SUCCESS Initialized the IPsecConfig Protocol successfully.
+ @retval Others Initializing the IPsecConfig Protocol failed.
+**/
+EFI_STATUS
+IpSecConfigInitialize (
+ IN OUT IPSEC_PRIVATE_DATA *Private
+ )
+{
+ EFI_IPSEC_CONFIG_DATA_TYPE Type;
+
+ CopyMem (
+ &Private->IpSecConfig,
+ &mIpSecConfigInstance,
+ sizeof (EFI_IPSEC_CONFIG_PROTOCOL)
+ );
+
+ //
+ // Initialize the list head of policy database.
+ //
+ for (Type = IPsecConfigDataTypeSpd; Type < IPsecConfigDataTypeMaximum; Type++) {
+ InitializeListHead (&mConfigData[Type]);
+ }
+ //
+ // Restore the content of policy database according to the variable.
+ //
+ IpSecConfigRestore (Private);
+
+ return gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiIpSecConfigProtocolGuid,
+ &Private->IpSecConfig,
+ NULL
+ );
+}
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecConfigImpl.h b/Core/NetworkPkg/IpSecDxe/IpSecConfigImpl.h
new file mode 100644
index 0000000000..3e365dae4a
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecConfigImpl.h
@@ -0,0 +1,955 @@
+/** @file
+ Definitions related to IPSEC_CONFIG_PROTOCOL implementations.
+
+ Copyright (c) 2009 - 2011, 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.
+
+**/
+
+#ifndef _IPSEC_CONFIG_IMPL_H_
+#define _IPSEC_CONFIG_IMPL_H_
+
+#include <Protocol/IpSec.h>
+#include <Protocol/IpSecConfig.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+
+#include "IpSecImpl.h"
+
+#define EFI_IPSEC_ANY_PROTOCOL 0xFFFF
+#define EFI_IPSEC_ANY_PORT 0
+
+#define IPSEC_VAR_ITEM_HEADER_LOGO_BIT 0x80
+#define IPSEC_VAR_ITEM_HEADER_CONTENT_BIT 0x7F
+
+#define IPSECCONFIG_VARIABLE_NAME L"IpSecConfig"
+#define IPSECCONFIG_STATUS_NAME L"IpSecStatus"
+
+#define SIZE_OF_SPD_SELECTOR(x) (UINTN) (sizeof (EFI_IPSEC_SPD_SELECTOR) \
+ + sizeof (EFI_IP_ADDRESS_INFO) * ((x)->LocalAddressCount + (x)->RemoteAddressCount))
+
+#define FIX_REF_BUF_ADDR(addr, base) addr = (VOID *) ((UINTN) (addr) - (UINTN) (base))
+#define UNFIX_REF_BUF_ADDR(addr, base) addr = (VOID *) ((UINTN) (addr) + (UINTN) (base))
+
+//
+// The data structure used to store the genernall information of IPsec configuration.
+//
+typedef struct {
+ UINT32 VariableCount; // the total number of the IPsecConfig variables.
+ UINT32 VariableSize; // The total size of all IpsecConfig variables.
+ UINT32 SingleVariableSize; // The max size of single variable
+} IP_SEC_VARIABLE_INFO;
+
+typedef struct {
+ EFI_IPSEC_CONFIG_SELECTOR *Selector;
+ VOID *Data;
+ LIST_ENTRY List;
+} IPSEC_COMMON_POLICY_ENTRY;
+
+typedef struct {
+ UINT8 *Ptr;
+ UINTN Size;
+ UINTN Capacity;
+} IPSEC_VARIABLE_BUFFER;
+
+#pragma pack(1)
+typedef struct {
+ UINT8 Type;
+ UINT16 Size;
+} IPSEC_VAR_ITEM_HEADER;
+#pragma pack()
+
+/**
+ The prototype of Copy Source Selector to the Destination Selector.
+
+ @param[in, out] DstSel Pointer of Destination Selector. It would be
+ SPD Selector, or SAD Selector or PAD Selector.
+ @param[in] SrcSel Pointer of Source Selector. It would be
+ SPD Selector, or SAD Selector or PAD Selector.
+ @param[in, out] Size The size of the Destination Selector. If it
+ is not NULL and its value is less than the size of
+ Source Selector, the value of Source Selector's
+ size will be passed to the caller by this parameter.
+
+ @retval EFI_INVALID_PARAMETER If the Destination or Source Selector is NULL.
+ @retval EFI_BUFFER_TOO_SMALL If the input Size is less than size of Source Selector.
+ @retval EFI_SUCCESS Copy Source Selector to the Destination
+ Selector successfully.
+
+**/
+typedef
+EFI_STATUS
+(*IPSEC_DUPLICATE_SELECTOR) (
+ IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel,
+ IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel,
+ IN OUT UINTN *Size
+ );
+
+/**
+ It is prototype of compare two Selectors. The Selector would be SPD Selector,
+ or SAD Selector, or PAD selector.
+
+ @param[in] Selector1 Pointer of the first Selector.
+ @param[in] Selector2 Pointer of the second Selector.
+
+ @retval TRUE These two Selectors have the same value in certain fields.
+ @retval FALSE Not all fields have the same value in these two Selectors.
+
+**/
+typedef
+BOOLEAN
+(*IPSEC_COMPARE_SELECTOR) (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector1,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector2
+ );
+
+/**
+ The prototype of a function to check if the Selector is Zero by its certain fields.
+
+ @param[in] Selector Pointer of the Selector.
+
+ @retval TRUE If the Selector is Zero.
+ @retval FALSE If the Selector is not Zero.
+
+**/
+typedef
+BOOLEAN
+(*IPSEC_IS_ZERO_SELECTOR) (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector
+ );
+
+/**
+ The prototype of a function to fix the value of particular members of the Selector.
+
+ @param[in] Selector Pointer of Selector.
+ @param[in] Data Pointer of Data.
+
+**/
+typedef
+VOID
+(*IPSEC_FIX_POLICY_ENTRY) (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data
+ );
+
+/**
+ It is prototype function to define a routine function by the caller of IpSecVisitConfigData().
+
+ @param[in] Type A specified IPSEC_CONFIG_DATA_TYPE.
+ @param[in] Selector Points to EFI_IPSEC_CONFIG_SELECTOR to be copied
+ to the buffer.
+ @param[in] Data Points to data to be copied to the buffer. The
+ Data type is related to the Type.
+ @param[in] SelectorSize The size of the Selector.
+ @param[in] DataSize The size of the Data.
+ @param[in, out] Buffer The buffer to store the Selector and Data.
+
+ @retval EFI_SUCCESS Copied the Selector and Data to a buffer successfully.
+ @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(*IPSEC_COPY_POLICY_ENTRY) (
+ IN EFI_IPSEC_CONFIG_DATA_TYPE Type,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN UINTN SelectorSize,
+ IN UINTN DataSize,
+ IN OUT VOID *Context
+ );
+
+/**
+ Set the security policy information for the EFI IPsec driver.
+
+ The IPsec configuration data has a unique selector/identifier separately to
+ identify a data entry.
+
+ @param[in] Selector Pointer to an entry selector on operated
+ configuration data specified by DataType.
+ A NULL Selector causes the entire specified-type
+ configuration information to be flushed.
+ @param[in] Data The data buffer to be set.
+ @param[in] Context Pointer to one entry selector that describes
+ the expected position the new data entry will
+ be added. If Context is NULL, the new entry will
+ be appended to the end of the database.
+
+ @retval EFI_INVALID_PARAMETER Certain Parameters are not correct. The Parameter
+ requiring a check depends on the Selector type.
+ @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated.
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+
+**/
+typedef
+EFI_STATUS
+(*IPSEC_SET_POLICY_ENTRY) (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN VOID *Context OPTIONAL
+ );
+
+/**
+ A prototype function definition to lookup the data entry from IPsec. Return the configuration
+ value of the specified Entry.
+
+ @param[in] Selector Pointer to an entry selector that is an identifier
+ of the entry.
+ @param[in, out] DataSize On output, the size of data returned in Data.
+ @param[out] Data The buffer to return the contents of the IPsec
+ configuration data. The type of the data buffer
+ is associated with the DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero.
+ @retval EFI_NOT_FOUND The configuration data specified by Selector is not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request.
+
+**/
+typedef
+EFI_STATUS
+(*IPSEC_GET_POLICY_ENTRY) (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN OUT UINTN *DataSize,
+ IN VOID *Data
+ );
+
+/**
+ Compare two SPD Selectors.
+
+ Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/
+ NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the
+ Local Addresses and remote Addresses.
+
+ @param[in] Selector1 Pointer of the first SPD Selector.
+ @param[in] Selector2 Pointer of the second SPD Selector.
+
+ @retval TRUE These two Selectors have the same value in above fields.
+ @retval FALSE Not all of the above fields have the same value in these two Selectors.
+
+**/
+BOOLEAN
+CompareSpdSelector (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector1,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector2
+ );
+
+
+/**
+ Visit all IPsec Configurations of specified Type and call the caller defined
+ interface.
+
+ @param[in] DataType The specified IPsec Config Data Type.
+ @param[in] Routine The function caller defined.
+ @param[in] Context The data passed to the Routine.
+
+ @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated.
+ @retval EFI_SUCCESS This function complete successfully.
+
+**/
+EFI_STATUS
+IpSecVisitConfigData (
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN IPSEC_COPY_POLICY_ENTRY Routine,
+ IN VOID *Context
+ );
+
+
+/**
+ This function is the subfunction of the EFIIpSecConfigSetData.
+
+ This function call IpSecSetVaraible to set the IPsec Configuration into the firmware.
+
+ @retval EFI_OUT_OF_RESOURCES The required system resource could not be allocated.
+ @retval EFI_SUCCESS Saved the configration successfully.
+ @retval Others Other errors were found while obtaining the variable.
+
+**/
+EFI_STATUS
+IpSecConfigSave (
+ VOID
+ );
+
+/**
+ Initialize IPsecConfig protocol
+
+ @param[in, out] Private Pointer to IPSEC_PRIVATE_DATA. After this function finish,
+ the pointer of IPsecConfig Protocol implementation will copy
+ into its IPsecConfig member.
+
+ @retval EFI_SUCCESS Initialized the IPsecConfig Protocol successfully.
+ @retval Others Initializing the IPsecConfig Protocol failed.
+
+**/
+EFI_STATUS
+IpSecConfigInitialize (
+ IN OUT IPSEC_PRIVATE_DATA *Private
+ );
+
+/**
+ Calculate the entire size of EFI_IPSEC_SPD_DATA, which includes the buffer size pointed
+ by the pointer members.
+
+ @param[in] SpdData Pointer to a specified EFI_IPSEC_SPD_DATA.
+
+ @return The entire size of the specified EFI_IPSEC_SPD_DATA.
+
+**/
+UINTN
+IpSecGetSizeOfEfiSpdData (
+ IN EFI_IPSEC_SPD_DATA *SpdData
+ );
+
+/**
+ Calculate the a entire size of IPSEC_SPD_DATA, which includes the buffer size pointed
+ by the pointer members and the buffer size used by Sa List.
+
+ @param[in] SpdData Pointer to the specified IPSEC_SPD_DATA.
+
+ @return The entire size of IPSEC_SPD_DATA.
+
+**/
+UINTN
+IpSecGetSizeOfSpdData (
+ IN IPSEC_SPD_DATA *SpdData
+ );
+
+/**
+ Copy Source Process Policy to the Destination Process Policy.
+
+ @param[in] Dst Pointer to the Source Process Policy.
+ @param[in] Src Pointer to the Destination Process Policy.
+
+**/
+VOID
+IpSecDuplicateProcessPolicy (
+ IN EFI_IPSEC_PROCESS_POLICY *Dst,
+ IN EFI_IPSEC_PROCESS_POLICY *Src
+ );
+
+/**
+ Find if the two SPD Selectors has subordinative.
+
+ Compare two SPD Selector by the fields of LocalAddressCount/RemoteAddressCount/
+ NextLayerProtocol/LocalPort/LocalPortRange/RemotePort/RemotePortRange and the
+ Local Addresses and remote Addresses.
+
+ @param[in] Selector1 Pointer of first SPD Selector.
+ @param[in] Selector2 Pointer of second SPD Selector.
+
+ @retval TRUE The first SPD Selector is subordinate Selector of second SPD Selector.
+ @retval FALSE The first SPD Selector is not subordinate Selector of second
+ SPD Selector.
+
+**/
+BOOLEAN
+IsSubSpdSelector (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector1,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector2
+ );
+
+/**
+ Compare two SA IDs.
+
+ @param[in] Selector1 Pointer of the first SA ID.
+ @param[in] Selector2 Pointer of the second SA ID.
+
+ @retval TRUE This two Selectors have the same SA ID.
+ @retval FALSE This two Selecotrs don't have the same SA ID.
+
+**/
+BOOLEAN
+CompareSaId (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector1,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector2
+ );
+
+/**
+ Compare two PAD IDs.
+
+ @param[in] Selector1 Pointer of the first PAD ID.
+ @param[in] Selector2 Pointer of the second PAD ID.
+
+ @retval TRUE This two Selectors have the same PAD ID.
+ @retval FALSE This two Selecotrs don't have the same PAD ID.
+
+**/
+BOOLEAN
+ComparePadId (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector1,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector2
+ );
+
+/**
+ Check if the SPD Selector is Zero by its LocalAddressCount and RemoteAddressCount
+ fields.
+
+ @param[in] Selector Pointer of the SPD Selector.
+
+ @retval TRUE If the SPD Selector is Zero.
+ @retval FALSE If the SPD Selector is not Zero.
+
+**/
+BOOLEAN
+IsZeroSpdSelector (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector
+ );
+
+/**
+ Check if the SA ID is Zero by its DestAddress.
+
+ @param[in] Selector Pointer of the SA ID.
+
+ @retval TRUE If the SA ID is Zero.
+ @retval FALSE If the SA ID is not Zero.
+
+**/
+BOOLEAN
+IsZeroSaId (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector
+ );
+
+/**
+ Check if the PAD ID is Zero.
+
+ @param[in] Selector Pointer of the PAD ID.
+
+ @retval TRUE If the PAD ID is Zero.
+ @retval FALSE If the PAD ID is not Zero.
+
+**/
+BOOLEAN
+IsZeroPadId (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector
+ );
+
+/**
+ Copy Source SPD Selector to the Destination SPD Selector.
+
+ @param[in, out] DstSel Pointer of Destination SPD Selector.
+ @param[in] SrcSel Pointer of Source SPD Selector.
+ @param[in, out] Size The size of the Destination SPD Selector. If
+ it is not NULL and its value is less than the
+ size of Source SPD Selector, the value of
+ Source SPD Selector's size will be passed to
+ the caller by this parameter.
+
+ @retval EFI_INVALID_PARAMETER If the Destination or Source SPD Selector is NULL.
+ @retval EFI_BUFFER_TOO_SMALL If the input Size is less than size of Source SPD Selector.
+ @retval EFI_SUCCESS Copy Source SPD Selector to the Destination SPD
+ Selector successfully.
+
+**/
+EFI_STATUS
+DuplicateSpdSelector (
+ IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel,
+ IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel,
+ IN OUT UINTN *Size
+ );
+
+/**
+ Copy Source SA ID to the Destination SA ID.
+
+ @param[in, out] DstSel Pointer of the Destination SA ID.
+ @param[in] SrcSel Pointer of the Source SA ID.
+ @param[in, out] Size The size of the Destination SA ID. If it
+ not NULL, and its value is less than the size of
+ Source SA ID, the value of Source SA ID's size
+ will be passed to the caller by this parameter.
+
+ @retval EFI_INVALID_PARAMETER If the Destination or Source SA ID is NULL.
+ @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source SA ID.
+ @retval EFI_SUCCESS Copied Source SA ID to the Destination SA ID successfully.
+
+**/
+EFI_STATUS
+DuplicateSaId (
+ IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel,
+ IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel,
+ IN OUT UINTN *Size
+ );
+
+/**
+ Copy Source PAD ID to the Destination PAD ID.
+
+ @param[in, out] DstSel Pointer of Destination PAD ID.
+ @param[in] SrcSel Pointer of Source PAD ID.
+ @param[in, out] Size The size of the Destination PAD ID. If it
+ not NULL, and its value less than the size of
+ Source PAD ID, the value of Source PAD ID's size
+ will be passed to the caller by this parameter.
+
+ @retval EFI_INVALID_PARAMETER If the Destination or Source PAD ID is NULL.
+ @retval EFI_BUFFER_TOO_SMALL If the input Size less than size of source PAD ID.
+ @retval EFI_SUCCESS Copied Source PAD ID to the Destination PAD ID successfully.
+
+**/
+EFI_STATUS
+DuplicatePadId (
+ IN OUT EFI_IPSEC_CONFIG_SELECTOR *DstSel,
+ IN EFI_IPSEC_CONFIG_SELECTOR *SrcSel,
+ IN OUT UINTN *Size
+ );
+
+/**
+ Fix the value of some members of the SPD Selector.
+
+ This function is called by IpSecCopyPolicyEntry(), which copies the Policy
+ Entry into the Variable. Since some members in SPD Selector are pointers,
+ a physical address to relative address conversion is required before copying
+ this SPD entry into the variable.
+
+ @param[in] Selector Pointer of SPD Selector.
+ @param[in, out] Data Pointer of SPD Data.
+
+**/
+VOID
+FixSpdEntry (
+ IN EFI_IPSEC_SPD_SELECTOR *Selector,
+ IN OUT EFI_IPSEC_SPD_DATA *Data
+ );
+
+/**
+ Fix the value of some members of SA ID.
+
+ This function is called by IpSecCopyPolicyEntry(), which copies the Policy
+ Entry into the Variable. Since some members in SA ID are pointers,
+ a physical address to relative address conversion is required before copying
+ this SAD into the variable.
+
+ @param[in] SaId Pointer of SA ID.
+ @param[in, out] Data Pointer of SA Data.
+
+**/
+VOID
+FixSadEntry (
+ IN EFI_IPSEC_SA_ID *SaId,
+ IN OUT EFI_IPSEC_SA_DATA2 *Data
+ );
+
+/**
+ Fix the value of some members of PAD ID.
+
+ This function is called by IpSecCopyPolicyEntry(), which copy the Policy
+ Entry into the Variable. Since some members in PAD ID are pointers,
+ a physical address to relative address conversion is required before copying
+ this PAD into the variable.
+
+ @param[in] PadId Pointer of PAD ID.
+ @param[in, out] Data Pointer of PAD Data.
+
+**/
+VOID
+FixPadEntry (
+ IN EFI_IPSEC_PAD_ID *PadId,
+ IN OUT EFI_IPSEC_PAD_DATA *Data
+ );
+
+/**
+ Recover the value of some members of SPD Selector.
+
+ This function is corresponding to FixSpdEntry(). It recovers the value of members
+ of SPD Selector which fix by the FixSpdEntry().
+
+ @param[in, out] Selector Pointer of SPD Selector.
+ @param[in, out] Data Pointer of SPD Data.
+
+**/
+VOID
+UnfixSpdEntry (
+ IN OUT EFI_IPSEC_SPD_SELECTOR *Selector,
+ IN OUT EFI_IPSEC_SPD_DATA *Data
+ );
+
+
+/**
+ Recover the value of some members of SA ID.
+
+ This function is corresponding to FixSadEntry(). It recovers the value of members
+ of SAD ID which fix by the FixSadEntry().
+
+ @param[in, out] SaId Pointer of SAD ID
+ @param[in, out] Data Pointer of SAD Data.
+
+**/
+VOID
+UnfixSadEntry (
+ IN OUT EFI_IPSEC_SA_ID *SaId,
+ IN OUT EFI_IPSEC_SA_DATA2 *Data
+ );
+
+/**
+ Recover the value of some members of PAD ID.
+
+ This function is corresponding to FixPadEntry(). It recovers the value of members
+ of PAD ID which fix by the FixPadEntry().
+
+ @param[in] PadId Pointer of PAD ID
+ @param[in, out] Data Pointer of PAD Data.
+
+**/
+VOID
+UnfixPadEntry (
+ IN EFI_IPSEC_PAD_ID *PadId,
+ IN OUT EFI_IPSEC_PAD_DATA *Data
+ );
+
+/**
+ Set the security policy information for the EFI IPsec driver.
+
+ The IPsec configuration data has a unique selector/identifier separately to
+ identify a data entry.
+
+ @param[in] Selector Pointer to an entry selector on operated
+ configuration data specified by DataType.
+ A NULL Selector causes the entire specified-type
+ configuration information to be flushed.
+ @param[in] Data The data buffer to be set. The structure
+ of the data buffer should be EFI_IPSEC_SPD_DATA.
+ @param[in] Context Pointer to one entry selector that describes
+ the expected position the new data entry will
+ be added. If Context is NULL,the new entry will
+ be appended the end of database.
+
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
+ - Selector is not NULL and its LocalAddress
+ is NULL or its RemoteAddress is NULL.
+ - Data is not NULL, its Action is Protected,
+ and its policy is NULL.
+ - Data is not NULL and its Action is not protected
+ and its policy is not NULL.
+ - The Action of Data is Protected, its policy
+ mode is Tunnel, and its tunnel option is NULL.
+ - The Action of Data is protected, its policy
+ mode is not Tunnel, and it tunnel option is not NULL.
+ @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated.
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+
+**/
+EFI_STATUS
+SetSpdEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN VOID *Context OPTIONAL
+ );
+
+/**
+ Set the security association information for the EFI IPsec driver.
+
+ The IPsec configuration data has a unique selector/identifier separately to
+ identify a data entry.
+
+ @param[in] Selector Pointer to an entry selector on operated
+ configuration data specified by DataType.
+ A NULL Selector causes the entire specified-type
+ configuration information to be flushed.
+ @param[in] Data The data buffer to be set. The structure
+ of the data buffer should be EFI_IPSEC_SA_DATA.
+ @param[in] Context Pointer to one entry selector which describes
+ the expected position the new data entry will
+ be added. If Context is NULL,the new entry will
+ be appended to the end of database.
+
+ @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated.
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+
+**/
+EFI_STATUS
+SetSadEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN VOID *Context OPTIONAL
+ );
+
+/**
+ Set the peer authorization configuration information for the EFI IPsec driver.
+
+ The IPsec configuration data has a unique selector/identifier separately to
+ identify a data entry.
+
+ @param[in] Selector Pointer to an entry selector on operated
+ configuration data specified by DataType.
+ A NULL Selector causes the entire specified-type
+ configuration information to be flushed.
+ @param[in] Data The data buffer to be set. The structure
+ of the data buffer should be EFI_IPSEC_PAD_DATA.
+ @param[in] Context Pointer to one entry selector that describes
+ the expected position where the new data entry will
+ be added. If Context is NULL, the new entry will
+ be appended the end of database.
+
+ @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated.
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+
+**/
+EFI_STATUS
+SetPadEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN VOID *Context OPTIONAL
+ );
+
+/**
+ This function looks up the data entry from IPsec SPD, and returns the configuration
+ value of the specified SPD Entry.
+
+ @param[in] Selector Pointer to an entry selector which is an identifier
+ of the SPD entry.
+ @param[in, out] DataSize On output the size of data returned in Data.
+ @param[out] Data The buffer to return the contents of the IPsec
+ configuration data. The type of the data buffer
+ is associated with the DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_INVALID_PARAMETER Data is NULL and *DataSize is not zero.
+ @retval EFI_NOT_FOUND The configuration data specified by Selector is not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+GetSpdEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ This function looks up the data entry from IPsec SAD and returns the configuration
+ value of the specified SAD Entry.
+
+ @param[in] Selector Pointer to an entry selector that is an identifier
+ of the SAD entry.
+ @param[in, out] DataSize On output, the size of data returned in Data.
+ @param[out] Data The buffer to return the contents of the IPsec
+ configuration data. This type of the data buffer
+ is associated with the DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_NOT_FOUND The configuration data specified by Selector is not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+GetSadEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ This function looks up the data entry from IPsec PADand returns the configuration
+ value of the specified PAD Entry.
+
+ @param[in] Selector Pointer to an entry selector that is an identifier
+ of the PAD entry.
+ @param[in, out] DataSize On output the size of data returned in Data.
+ @param[out] Data The buffer to return the contents of the IPsec
+ configuration data. This type of the data buffer
+ is associated with the DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_NOT_FOUND The configuration data specified by Selector is not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+GetPadEntry (
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ Return the configuration value for the EFI IPsec driver.
+
+ This function lookup the data entry from IPsec database or IKEv2 configuration
+ information. The expected data type and unique identification are described in
+ DataType and Selector parameters.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The type of data to retrieve.
+ @param[in] Selector Pointer to an entry selector that is an identifier of the IPsec
+ configuration data entry.
+ @param[in, out] DataSize On output the size of data returned in Data.
+ @param[out] Data The buffer to return the contents of the IPsec configuration data.
+ The type of the data buffer is associated with the DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
+ - This is NULL.
+ - Selector is NULL.
+ - DataSize is NULL.
+ - Data is NULL and *DataSize is not zero
+ @retval EFI_NOT_FOUND The configuration data specified by Selector is not found.
+ @retval EFI_UNSUPPORTED The specified DataType is not supported.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigGetData (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ Set the security association, security policy and peer authorization configuration
+ information for the EFI IPsec driver.
+
+ This function is used to set the IPsec configuration information of type DataType for
+ the EFI IPsec driver.
+ The IPsec configuration data has a unique selector/identifier separately to identify
+ a data entry. The selector structure depends on DataType's definition.
+ Using SetData() with a Data of NULL causes the IPsec configuration data entry identified
+ by DataType and Selector to be deleted.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The type of data to be set.
+ @param[in] Selector Pointer to an entry selector on operated configuration data
+ specified by DataType. A NULL Selector causes the entire
+ specified-type configuration information to be flushed.
+ @param[in] Data The data buffer to be set. The structure of the data buffer is
+ associated with the DataType.
+ @param[in] InsertBefore Pointer to one entry selector which describes the expected
+ position the new data entry will be added. If InsertBefore is NULL,
+ the new entry will be appended the end of database.
+
+ @retval EFI_SUCCESS The specified configuration entry data was set successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
+ - This is NULL.
+ @retval EFI_UNSUPPORTED The specified DataType is not supported.
+ @retval EFI_OUT_OF_RESOURCED The required system resource could not be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigSetData (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN EFI_IPSEC_CONFIG_SELECTOR *Selector,
+ IN VOID *Data,
+ IN EFI_IPSEC_CONFIG_SELECTOR *InsertBefore OPTIONAL
+ );
+
+/**
+ Enumerates the current selector for IPsec configuration data entry.
+
+ This function is called multiple times to retrieve the entry Selector in IPsec
+ configuration database. On each call to GetNextSelector(), the next entry
+ Selector are retrieved into the output interface.
+
+ If the entire IPsec configuration database has been iterated, the error
+ EFI_NOT_FOUND is returned.
+ If the Selector buffer is too small for the next Selector copy, an
+ EFI_BUFFER_TOO_SMALL error is returned, and SelectorSize is updated to reflect
+ the size of buffer needed.
+
+ On the initial call to GetNextSelector() to start the IPsec configuration database
+ search, a pointer to the buffer with all zero value is passed in Selector. Calls
+ to SetData() between calls to GetNextSelector may produce unpredictable results.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The type of IPsec configuration data to retrieve.
+ @param[in, out] SelectorSize The size of the Selector buffer.
+ @param[in, out] Selector On input, supplies the pointer to last Selector that was
+ returned by GetNextSelector().
+ On output, returns one copy of the current entry Selector
+ of a given DataType.
+
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
+ - This is NULL.
+ - SelectorSize is NULL.
+ - Selector is NULL.
+ @retval EFI_NOT_FOUND The next configuration data entry was not found.
+ @retval EFI_UNSUPPORTED The specified DataType is not supported.
+ @retval EFI_BUFFER_TOO_SMALL The SelectorSize is too small for the result. This parameter
+ has been updated with the size needed to complete the search
+ request.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigGetNextSelector (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN OUT UINTN *SelectorSize,
+ IN OUT EFI_IPSEC_CONFIG_SELECTOR *Selector
+ );
+
+/**
+ Register an event that is to be signaled whenever a configuration process on the
+ specified IPsec configuration information is done.
+
+ The register function is not surpport now and always returns EFI_UNSUPPORTED.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The type of data to be registered the event for.
+ @param[in] Event The event to be registered.
+
+ @retval EFI_SUCCESS The event is registered successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL, or Event is NULL.
+ @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.
+ @retval EFI_UNSUPPORTED The notify registration unsupported, or the specified
+ DataType is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigRegisterNotify (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN EFI_EVENT Event
+ );
+
+
+/**
+ Remove the specified event that was previously registered on the specified IPsec
+ configuration data.
+
+ This function is not supported now and always returns EFI_UNSUPPORTED.
+
+ @param[in] This Pointer to the EFI_IPSEC_CONFIG_PROTOCOL instance.
+ @param[in] DataType The configuration data type to remove the registered event for.
+ @param[in] Event The event to be unregistered.
+
+ @retval EFI_SUCCESS The event was removed successfully.
+ @retval EFI_NOT_FOUND The Event specified by DataType could not be found in the
+ database.
+ @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
+ @retval EFI_UNSUPPORTED The notify registration unsupported or the specified
+ DataType is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+EfiIpSecConfigUnregisterNotify (
+ IN EFI_IPSEC_CONFIG_PROTOCOL *This,
+ IN EFI_IPSEC_CONFIG_DATA_TYPE DataType,
+ IN EFI_EVENT Event
+ );
+
+extern LIST_ENTRY mConfigData[IPsecConfigDataTypeMaximum];
+
+#endif
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecCryptIo.c b/Core/NetworkPkg/IpSecDxe/IpSecCryptIo.c
new file mode 100644
index 0000000000..dca44231be
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecCryptIo.c
@@ -0,0 +1,1021 @@
+/** @file
+ Common interfaces to call Security library.
+
+ 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 "IpSecCryptIo.h"
+//
+// The informations for the supported Encrypt/Decrpt Alogrithm.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {
+ {IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL},
+ {IKE_EALG_NONE, 0, 0, 1, NULL, NULL, NULL, NULL},
+ {IKE_EALG_3DESCBC, 24, 8, 8, TdesGetContextSize, TdesInit, TdesCbcEncrypt, TdesCbcDecrypt},
+ {IKE_EALG_AESCBC, 16, 16, 16, AesGetContextSize, AesInit, AesCbcEncrypt, AesCbcDecrypt}
+};
+
+//
+// The informations for the supported Authentication algorithm
+//
+GLOBAL_REMOVE_IF_UNREFERENCED AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {
+ {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},
+ {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},
+ {IKE_AALG_SHA1HMAC, 20, 12, 64, HmacSha1GetContextSize, HmacSha1Init, HmacSha1Update, HmacSha1Final}
+};
+
+//
+// The information for the supported Hash aglorithm
+//
+GLOBAL_REMOVE_IF_UNREFERENCED HASH_ALGORITHM mIpsecHashAlgorithmList[IPSEC_HASH_ALGORITHM_LIST_SIZE] = {
+ {IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},
+ {IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},
+ {IKE_AALG_SHA1HMAC, 20, 12, 64, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final}
+};
+
+BOOLEAN mInitialRandomSeed = FALSE;
+
+/**
+ Get the block size of specified encryption alogrithm.
+
+ @param[in] AlgorithmId The encryption algorithm ID.
+
+ @return The value of block size.
+
+**/
+UINTN
+IpSecGetEncryptBlockSize (
+ IN UINT8 AlgorithmId
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
+ if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
+ return mIpsecEncryptAlgorithmList[Index].BlockSize;
+ }
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Get the key length of the specified encryption alogrithm.
+
+ @param[in] AlgorithmId The encryption algorithm ID.
+
+ @return The value of key length.
+
+**/
+UINTN
+IpSecGetEncryptKeyLength (
+ IN UINT8 AlgorithmId
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
+ if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
+ return mIpsecEncryptAlgorithmList[Index].KeyLength;
+ }
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Get the IV size of the specified encryption alogrithm.
+
+ @param[in] AlgorithmId The encryption algorithm ID.
+
+ @return The value of IV size.
+
+**/
+UINTN
+IpSecGetEncryptIvLength (
+ IN UINT8 AlgorithmId
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
+ if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
+ return mIpsecEncryptAlgorithmList[Index].IvLength;
+ }
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Get the HMAC digest length by the specified Algorithm ID.
+
+ @param[in] AlgorithmId The specified Alogrithm ID.
+
+ @return The digest length of the specified Authentication Algorithm ID.
+
+**/
+UINTN
+IpSecGetHmacDigestLength (
+ IN UINT8 AlgorithmId
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {
+ if (mIpsecAuthAlgorithmList[Index].AlgorithmId == AlgorithmId) {
+ //
+ // Return the Digest Length of the Algorithm.
+ //
+ return mIpsecAuthAlgorithmList[Index].DigestLength;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ Get the ICV size of the specified Authenticaion alogrithm.
+
+ @param[in] AlgorithmId The Authentication algorithm ID.
+
+ @return The value of ICV size.
+
+**/
+UINTN
+IpSecGetIcvLength (
+ IN UINT8 AlgorithmId
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {
+ if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {
+ return mIpsecAuthAlgorithmList[Index].IcvLength;
+ }
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Generate a random data for IV. If the IvSize is zero, not needed to create
+ IV and return EFI_SUCCESS.
+
+ @param[in] IvBuffer The pointer of the IV buffer.
+ @param[in] IvSize The IV size in bytes.
+
+ @retval EFI_SUCCESS Create a random data for IV.
+
+**/
+EFI_STATUS
+IpSecGenerateIv (
+ IN UINT8 *IvBuffer,
+ IN UINTN IvSize
+ )
+{
+ if (IvSize != 0) {
+ return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get index of the specified encryption alogrithm from the mIpsecEncryptAlgorithemList.
+
+ @param[in] AlgorithmId The encryption algorithm ID.
+
+ @return the index.
+
+**/
+UINTN
+IpSecGetIndexFromEncList (
+ IN UINT8 AlgorithmId
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
+ if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
+ return Index;
+ }
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Get index of the specified encryption alogrithm from the mIpsecAuthAlgorithemList.
+
+ @param[in] AlgorithmId The encryption algorithm ID.
+
+ @return the index.
+
+**/
+UINTN
+IpSecGetIndexFromAuthList (
+ IN UINT8 AlgorithmId
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {
+ if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {
+ //
+ // The BlockSize is same with IvSize.
+ //
+ return Index;
+ }
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Encrypt the buffer.
+
+ This function calls relevant encryption interface from CryptoLib according to
+ the input alogrithm ID. The InData should be multiple of block size. This function
+ doesn't perform the padding. If it has the Ivec data, the length of it should be
+ same with the block size. The block size is different from the different algorithm.
+
+ @param[in] AlgorithmId The Alogrithem identification defined in RFC.
+ @param[in] Key Pointer to the buffer containing encrypting key.
+ @param[in] KeyBits The length of the key in bits.
+ @param[in] Ivec Point to the buffer containning the Initializeion
+ Vector (IV) data.
+ @param[in] InData Point to the buffer containing the data to be
+ encrypted.
+ @param[in] InDataLength The length of InData in Bytes.
+ @param[out] OutData Point to the buffer that receives the encryption
+ output.
+
+ @retval EFI_UNSUPPORTED The input Algorithm is not supported.
+ @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+IpSecCryptoIoEncrypt (
+ IN CONST UINT8 AlgorithmId,
+ IN CONST UINT8 *Key,
+ IN CONST UINTN KeyBits,
+ IN CONST UINT8 *Ivec, OPTIONAL
+ IN UINT8 *InData,
+ IN UINTN InDataLength,
+ OUT UINT8 *OutData
+ )
+{
+ UINTN Index;
+ UINTN ContextSize;
+ UINT8 *Context;
+ EFI_STATUS Status;
+
+ Status = EFI_UNSUPPORTED;
+
+ switch (AlgorithmId) {
+
+ case IKE_EALG_NULL:
+ case IKE_EALG_NONE:
+ CopyMem (OutData, InData, InDataLength);
+ return EFI_SUCCESS;
+
+ case IKE_EALG_3DESCBC:
+ case IKE_EALG_AESCBC:
+ Index = IpSecGetIndexFromEncList (AlgorithmId);
+ if (Index == -1) {
+ return Status;
+ }
+ //
+ // Get Context Size
+ //
+ ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize ();
+ Context = AllocateZeroPool (ContextSize);
+
+ if (Context == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Initiate Context
+ //
+ if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {
+ if (mIpsecEncryptAlgorithmList[Index].CipherEncrypt (Context, InData, InDataLength, Ivec, OutData)) {
+ Status = EFI_SUCCESS;
+ }
+ }
+ break;
+
+ default:
+ return Status;
+
+ }
+
+ if (Context != NULL) {
+ FreePool (Context);
+ }
+
+ return Status;
+}
+
+/**
+ Decrypts the buffer.
+
+ This function calls relevant Decryption interface from CryptoLib according to
+ the input alogrithm ID. The InData should be multiple of block size. This function
+ doesn't perform the padding. If it has the Ivec data, the length of it should be
+ same with the block size. The block size is different from the different algorithm.
+
+ @param[in] AlgorithmId The Alogrithem identification defined in RFC.
+ @param[in] Key Pointer to the buffer containing encrypting key.
+ @param[in] KeyBits The length of the key in bits.
+ @param[in] Ivec Point to the buffer containning the Initializeion
+ Vector (IV) data.
+ @param[in] InData Point to the buffer containing the data to be
+ decrypted.
+ @param[in] InDataLength The length of InData in Bytes.
+ @param[out] OutData Pointer to the buffer that receives the decryption
+ output.
+
+ @retval EFI_UNSUPPORTED The input Algorithm is not supported.
+ @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+IpSecCryptoIoDecrypt (
+ IN CONST UINT8 AlgorithmId,
+ IN CONST UINT8 *Key,
+ IN CONST UINTN KeyBits,
+ IN CONST UINT8 *Ivec, OPTIONAL
+ IN UINT8 *InData,
+ IN UINTN InDataLength,
+ OUT UINT8 *OutData
+ )
+{
+ UINTN Index;
+ UINTN ContextSize;
+ UINT8 *Context;
+ EFI_STATUS Status;
+
+ Status = EFI_UNSUPPORTED;
+
+ switch (AlgorithmId) {
+
+ case IKE_EALG_NULL:
+ case IKE_EALG_NONE:
+ CopyMem (OutData, InData, InDataLength);
+ return EFI_SUCCESS;
+
+ case IKE_EALG_3DESCBC:
+ case IKE_EALG_AESCBC:
+ Index = IpSecGetIndexFromEncList(AlgorithmId);
+ if (Index == -1) {
+ return Status;
+ }
+
+ //
+ // Get Context Size
+ //
+ ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize();
+ Context = AllocateZeroPool (ContextSize);
+ if (Context == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initiate Context
+ //
+ if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {
+ if (mIpsecEncryptAlgorithmList[Index].CipherDecrypt (Context, InData, InDataLength, Ivec, OutData)) {
+ Status = EFI_SUCCESS;
+ }
+ }
+ break;
+
+ default:
+ return Status;
+ }
+
+ if (Context != NULL) {
+ FreePool (Context);
+ }
+
+ return Status;
+}
+
+/**
+ Digests the Payload with key and store the result into the OutData.
+
+ This function calls relevant Hmac interface from CryptoLib according to
+ the input alogrithm ID. It computes all datas from InDataFragment and output
+ the result into the OutData buffer. If the OutDataSize is larger than the related
+ HMAC alogrithm output size, return EFI_INVALID_PARAMETER.
+
+ @param[in] AlgorithmId The authentication Identification.
+ @param[in] Key Pointer of the authentication key.
+ @param[in] KeyLength The length of the Key in bytes.
+ @param[in] InDataFragment The list contains all data to be authenticated.
+ @param[in] FragmentCount The size of the InDataFragment.
+ @param[out] OutData For in, the buffer to receive the output data.
+ For out, the buffer contains the authenticated data.
+ @param[in] OutDataSize The size of the buffer of OutData.
+
+ @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.
+ @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size.
+ @retval EFI_SUCCESS Authenticate the payload successfully.
+ @retval otherwise Authentication of the payload fails.
+
+**/
+EFI_STATUS
+IpSecCryptoIoHmac (
+ IN CONST UINT8 AlgorithmId,
+ IN CONST UINT8 *Key,
+ IN UINTN KeyLength,
+ IN HASH_DATA_FRAGMENT *InDataFragment,
+ IN UINTN FragmentCount,
+ OUT UINT8 *OutData,
+ IN UINTN OutDataSize
+ )
+{
+ UINTN ContextSize;
+ UINTN Index;
+ UINT8 FragmentIndex;
+ UINT8 *HashContext;
+ EFI_STATUS Status;
+ UINT8 *OutHashData;
+ UINTN OutHashSize;
+
+ Status = EFI_UNSUPPORTED;
+ OutHashData = NULL;
+
+ OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);
+ //
+ // If the expected hash data size is larger than the related Hash algorithm
+ // output length, return EFI_INVALID_PARAMETER.
+ //
+ if (OutDataSize > OutHashSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ OutHashData = AllocatePool (OutHashSize);
+
+ if (OutHashData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ switch (AlgorithmId) {
+
+ case IKE_AALG_NONE :
+ case IKE_AALG_NULL :
+ return EFI_SUCCESS;
+
+ case IKE_AALG_SHA1HMAC:
+ Index = IpSecGetIndexFromAuthList (AlgorithmId);
+ if (Index == -1) {
+ return Status;
+ }
+
+ //
+ // Get Context Size
+ //
+ ContextSize = mIpsecAuthAlgorithmList[Index].HmacGetContextSize();
+ HashContext = AllocateZeroPool (ContextSize);
+
+ if (HashContext == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Initiate HMAC context and hash the input data.
+ //
+ if (mIpsecAuthAlgorithmList[Index].HmacInitiate(HashContext, Key, KeyLength)) {
+ for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {
+ if (!mIpsecAuthAlgorithmList[Index].HmacUpdate (
+ HashContext,
+ InDataFragment[FragmentIndex].Data,
+ InDataFragment[FragmentIndex].DataSize
+ )
+ ) {
+ goto Exit;
+ }
+ }
+ if (mIpsecAuthAlgorithmList[Index].HmacFinal (HashContext, OutHashData)) {
+ //
+ // In some cases, like the Icv computing, the Icv size might be less than
+ // the key length size, so copy the part of hash data to the OutData.
+ //
+ CopyMem (OutData, OutHashData, OutDataSize);
+ Status = EFI_SUCCESS;
+ }
+
+ goto Exit;
+ }
+
+ default:
+ return Status;
+ }
+
+Exit:
+ if (HashContext != NULL) {
+ FreePool (HashContext);
+ }
+ if (OutHashData != NULL) {
+ FreePool (OutHashData);
+ }
+
+ return Status;
+}
+
+/**
+ Digests the Payload and store the result into the OutData.
+
+ This function calls relevant Hash interface from CryptoLib according to
+ the input alogrithm ID. It computes all datas from InDataFragment and output
+ the result into the OutData buffer. If the OutDataSize is larger than the related
+ Hash alogrithm output size, return EFI_INVALID_PARAMETER.
+
+ @param[in] AlgorithmId The authentication Identification.
+ @param[in] InDataFragment A list contains all data to be authenticated.
+ @param[in] FragmentCount The size of the InDataFragment.
+ @param[out] OutData For in, the buffer to receive the output data.
+ For out, the buffer contains the authenticated data.
+ @param[in] OutDataSize The size of the buffer of OutData.
+
+ @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.
+ @retval EFI_SUCCESS Authenticated the payload successfully.
+ @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash
+ algorithm could handle.
+ @retval otherwise Authentication of the payload failed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoHash (
+ IN CONST UINT8 AlgorithmId,
+ IN HASH_DATA_FRAGMENT *InDataFragment,
+ IN UINTN FragmentCount,
+ OUT UINT8 *OutData,
+ IN UINTN OutDataSize
+ )
+{
+ UINTN ContextSize;
+ UINTN Index;
+ UINT8 FragmentIndex;
+ UINT8 *HashContext;
+ EFI_STATUS Status;
+ UINT8 *OutHashData;
+ UINTN OutHashSize;
+
+ Status = EFI_UNSUPPORTED;
+ OutHashData = NULL;
+
+ OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);
+ //
+ // If the expected hash data size is larger than the related Hash algorithm
+ // output length, return EFI_INVALID_PARAMETER.
+ //
+ if (OutDataSize > OutHashSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ OutHashData = AllocatePool (OutHashSize);
+ if (OutHashData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ switch (AlgorithmId) {
+
+ case IKE_AALG_NONE:
+ case IKE_AALG_NULL:
+ return EFI_SUCCESS;
+
+ case IKE_AALG_SHA1HMAC:
+ Index = IpSecGetIndexFromAuthList (AlgorithmId);
+ if (Index == -1) {
+ return Status;
+ }
+ //
+ // Get Context Size
+ //
+ ContextSize = mIpsecHashAlgorithmList[Index].HashGetContextSize();
+ HashContext = AllocateZeroPool (ContextSize);
+ if (HashContext == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Initiate Hash context and hash the input data.
+ //
+ if (mIpsecHashAlgorithmList[Index].HashInitiate(HashContext)) {
+ for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {
+ if (!mIpsecHashAlgorithmList[Index].HashUpdate (
+ HashContext,
+ InDataFragment[FragmentIndex].Data,
+ InDataFragment[FragmentIndex].DataSize
+ )
+ ) {
+ goto Exit;
+ }
+ }
+ if (mIpsecHashAlgorithmList[Index].HashFinal (HashContext, OutHashData)) {
+ //
+ // In some cases, like the Icv computing, the Icv size might be less than
+ // the key length size, so copy the part of hash data to the OutData.
+ //
+ CopyMem (OutData, OutHashData, OutDataSize);
+ Status = EFI_SUCCESS;
+ }
+
+ goto Exit;
+ }
+
+ default:
+ return Status;
+ }
+
+Exit:
+ if (HashContext != NULL) {
+ FreePool (HashContext);
+ }
+ if (OutHashData != NULL) {
+ FreePool (OutHashData);
+ }
+
+ return Status;
+}
+
+/**
+ Generates the Diffie-Hellman public key.
+
+ This function first initiate a DHContext, then call the DhSetParameter() to set
+ the prime and primelenght, at end call the DhGenerateKey() to generates random
+ secret exponent, and computes the public key. The output returned via parameter
+ PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey
+ buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned
+ and PublicKeySize is set to the required buffer size to obtain the public key.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] Generator Vlaue of generator.
+ @param[in] PrimeLength Length in bits of prime to be generated.
+ @param[in] Prime Pointer to the buffer to receive the generated
+ prime number.
+ @param[out] PublicKey Pointer to the buffer to receive generated public key.
+ @param[in, out] PublicKeySize For in, the size of PublicKey buffer in bytes.
+ For out, the size of data returned in PublicKey
+ buffer in bytes.
+
+ @retval EFI_SUCCESS The operation perfoms successfully.
+ @retval Otherwise The operation is failed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoDhGetPublicKey (
+ IN OUT UINT8 **DhContext,
+ IN UINTN Generator,
+ IN UINTN PrimeLength,
+ IN CONST UINT8 *Prime,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ )
+{
+ EFI_STATUS Status;
+
+ *DhContext = DhNew ();
+ ASSERT (*DhContext != NULL);
+ if (!DhSetParameter (*DhContext, Generator, PrimeLength, Prime)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ if (!DhGenerateKey (*DhContext, PublicKey, PublicKeySize)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Exit;
+ }
+ return EFI_SUCCESS;
+
+Exit:
+ if (*DhContext != NULL) {
+ DhFree (*DhContext);
+ DhContext = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Generates exchanged common key.
+
+ Given peer's public key, this function computes the exchanged common key, based
+ on its own context including value of prime modulus and random secret exponent.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] PeerPublicKey Pointer to the peer's Public Key.
+ @param[in] PeerPublicKeySize Size of peer's public key in bytes.
+ @param[out] Key Pointer to the buffer to receive generated key.
+ @param[in, out] KeySize For in, the size of Key buffer in bytes.
+ For out, the size of data returned in Key
+ buffer in bytes.
+
+ @retval EFI_SUCCESS The operation perfoms successfully.
+ @retval Otherwise The operation is failed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoDhComputeKey (
+ IN OUT UINT8 *DhContext,
+ IN CONST UINT8 *PeerPublicKey,
+ IN UINTN PeerPublicKeySize,
+ OUT UINT8 *Key,
+ IN OUT UINTN *KeySize
+ )
+{
+ if (!DhComputeKey (DhContext, PeerPublicKey, PeerPublicKeySize, Key, KeySize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER.
+
+ @param[in, out] DhContext Pointer to the DH context to be freed.
+
+ @retval EFI_SUCCESS The operation perfoms successfully.
+ @retval EFI_INVALID_PARAMETER The DhContext is NULL.
+
+**/
+EFI_STATUS
+IpSecCryptoIoFreeDh (
+ IN OUT UINT8 **DhContext
+ )
+{
+ if (*DhContext == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DhFree (*DhContext);
+ return EFI_SUCCESS;
+}
+
+/**
+ Generates random numbers of specified size.
+
+ If the Random Generator wasn't initiated, initiate it first, then call RandomBytes.
+
+ @param[out] OutBuffer Pointer to buffer to receive random value.
+ @param[in] Bytes Size of randome bytes to generate.
+
+ @retval EFI_SUCCESS The operation perfoms successfully.
+ @retval Otherwise The operation is failed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoGenerateRandomBytes (
+ OUT UINT8* OutBuffer,
+ IN UINTN Bytes
+ )
+{
+ if (!mInitialRandomSeed) {
+ RandomSeed (NULL, 0);
+ mInitialRandomSeed = TRUE;
+ }
+ if (RandomBytes (OutBuffer, Bytes)) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ Authenticate data with the certificate.
+
+ @param[in] InData Pointer to the Data to be signed.
+ @param[in] InDataSize InData size in bytes.
+ @param[in] PrivateKey Pointer to the private key.
+ @param[in] PrivateKeySize The size of Private Key in bytes.
+ @param[in] KeyPassWord Pointer to the password for retrieving private key.
+ @param[in] KeyPwdSize The size of Key Password in bytes.
+ @param[out] OutData The pointer to the signed data.
+ @param[in, out] OutDataSize Pointer to contain the size of out data.
+
+**/
+VOID
+IpSecCryptoIoAuthDataWithCertificate (
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN UINT8 *PrivateKey,
+ IN UINTN PrivateKeySize,
+ IN UINT8 *KeyPassWord,
+ IN UINTN KeyPwdSize,
+ OUT UINT8 **OutData,
+ IN OUT UINTN *OutDataSize
+ )
+{
+ UINT8 *RsaContext;
+ UINT8 *Signature;
+ UINTN SigSize;
+
+ SigSize = 0;
+ RsaContext = NULL;
+
+ //
+ // Retrieve RSA Private Key from password-protected PEM data
+ //
+ RsaGetPrivateKeyFromPem (
+ (CONST UINT8 *)PrivateKey,
+ PrivateKeySize,
+ (CONST CHAR8 *)KeyPassWord,
+ (VOID **) &RsaContext
+ );
+ if (RsaContext == NULL) {
+ return;
+ }
+
+ //
+ // Sign data
+ //
+ Signature = NULL;
+ if (!RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize)) {
+ Signature = AllocateZeroPool (SigSize);
+ } else {
+ return;
+ }
+
+ RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize);
+
+ *OutData = Signature;
+ *OutDataSize = SigSize;
+
+ if (RsaContext != NULL) {
+ RsaFree (RsaContext);
+ }
+}
+
+/**
+ Verify the singed data with the public key which is contained in a certificate.
+
+ @param[in] InCert Pointer to the Certificate which contains the
+ public key.
+ @param[in] CertLen The size of Certificate in bytes.
+ @param[in] InCa Pointer to the CA certificate
+ @param[in] CaLen The size of CA certificate in bytes.
+ @param[in] InData Pointer to octect message hash to be checked.
+ @param[in] InDataSize Size of the message hash in bytes.
+ @param[in] Singnature The pointer to the RSA PKCS1-V1_5 signature to be verifed.
+ @param[in] SigSize Size of signature in bytes.
+
+ @retval TRUE Valid signature encoded in PKCS1-v1_5.
+ @retval FALSE Invalid signature or invalid RSA context.
+
+**/
+BOOLEAN
+IpSecCryptoIoVerifySignDataByCertificate (
+ IN UINT8 *InCert,
+ IN UINTN CertLen,
+ IN UINT8 *InCa,
+ IN UINTN CaLen,
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN UINT8 *Singnature,
+ IN UINTN SigSize
+ )
+{
+ UINT8 *RsaContext;
+ BOOLEAN Status;
+
+ //
+ // Create the RSA Context
+ //
+ RsaContext = RsaNew ();
+ if (RsaContext == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Verify the validity of X509 Certificate
+ //
+ if (!X509VerifyCert (InCert, CertLen, InCa, CaLen)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the RSA public Key from Certificate
+ //
+ RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **)&RsaContext);
+
+ //
+ // Verify data
+ //
+ Status = RsaPkcs1Verify (RsaContext, InData, InDataSize, Singnature, SigSize);
+
+ if (RsaContext != NULL) {
+ RsaFree (RsaContext);
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves the RSA Public Key from one X509 certificate (DER format only).
+
+ @param[in] InCert Pointer to the certificate.
+ @param[in] CertLen The size of the certificate in bytes.
+ @param[out] PublicKey Pointer to the retrieved public key.
+ @param[out] PublicKeyLen Size of Public Key in bytes.
+
+ @retval EFI_SUCCESS Successfully get the public Key.
+ @retval EFI_INVALID_PARAMETER The certificate is malformed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoGetPublicKeyFromCert (
+ IN UINT8 *InCert,
+ IN UINTN CertLen,
+ OUT UINT8 **PublicKey,
+ OUT UINTN *PublicKeyLen
+ )
+{
+ UINT8 *RsaContext;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Create the RSA Context
+ //
+ RsaContext = RsaNew ();
+
+ //
+ // Retrieve the RSA public key from CA Certificate
+ //
+ if (!RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **) &RsaContext)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ *PublicKeyLen = 0;
+
+ RsaGetKey (RsaContext, RsaKeyN, NULL, PublicKeyLen);
+
+ *PublicKey = AllocateZeroPool (*PublicKeyLen);
+ if (*PublicKey == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ if (!RsaGetKey (RsaContext, RsaKeyN, *PublicKey, PublicKeyLen)) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+EXIT:
+ if (RsaContext != NULL) {
+ RsaFree (RsaContext);
+ }
+
+ return Status;
+}
+
+/**
+ Retrieves the subject name from one X509 certificate (DER format only).
+
+ @param[in] InCert Pointer to the X509 certificate.
+ @param[in] CertSize The size of the X509 certificate in bytes.
+ @param[out] CertSubject Pointer to the retrieved certificate subject.
+ @param[out] SubjectSize The size of Certificate Subject in bytes.
+
+ @retval EFI_SUCCESS Retrieved the certificate subject successfully.
+ @retval EFI_INVALID_PARAMETER The certificate is malformed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoGetSubjectFromCert (
+ IN UINT8 *InCert,
+ IN UINTN CertSize,
+ OUT UINT8 **CertSubject,
+ OUT UINTN *SubjectSize
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ *SubjectSize = 0;
+ X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize);
+
+ *CertSubject = AllocateZeroPool (*SubjectSize);
+ if (!X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize)) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ return Status;
+}
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecCryptIo.h b/Core/NetworkPkg/IpSecDxe/IpSecCryptIo.h
new file mode 100644
index 0000000000..0e106af0f0
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecCryptIo.h
@@ -0,0 +1,827 @@
+/** @file
+ Definitions related to the Cryptographic Operations in IPsec.
+
+ Copyright (c) 2009 - 2011, 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.
+
+**/
+#ifndef _EFI_IPSEC_CRYPTIO_H_
+#define _EFI_IPSEC_CRYPTIO_H_
+
+#include <Protocol/IpSecConfig.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include "IpSecImpl.h"
+#include "IkeCommon.h"
+
+#define IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE 4
+#define IPSEC_AUTH_ALGORITHM_LIST_SIZE 3
+#define IPSEC_HASH_ALGORITHM_LIST_SIZE 3
+
+///
+/// Authentication Algorithm Definition
+/// The number value definition is aligned to IANA assignment
+///
+#define IKE_AALG_NONE 0x00
+#define IKE_AALG_SHA1HMAC 0x02
+#define IKE_AALG_NULL 0xFB
+
+///
+/// Encryption Algorithm Definition
+/// The number value definition is aligned to IANA assignment
+///
+#define IKE_EALG_NONE 0x00
+#define IKE_EALG_3DESCBC 0x03
+#define IKE_EALG_NULL 0x0B
+#define IKE_EALG_AESCBC 0x0C
+
+/**
+ Prototype of HMAC GetContextSize.
+
+ Retrieves the size, in bytes, of the context buffer required.
+
+ @return The size, in bytes, of the context buffer required.
+
+**/
+typedef
+UINTN
+(EFIAPI *CRYPTO_HMAC_GETCONTEXTSIZE)(
+ VOID
+ );
+
+/**
+ Prototype of HMAC Operation Initiating.
+
+ Initialization with a new context.
+
+ @param[out] Context Input Context.
+ @param[in] Key Pointer to the key for HMAC.
+ @param[in] KeySize The length of the Key in bytes.
+
+ @retval TRUE Initialization Successfully.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CRYPTO_HMAC_INIT)(
+ OUT VOID *Context,
+ IN CONST UINT8 *Key,
+ IN UINTN KeySize
+ );
+
+/**
+ Prototype of HMAC update.
+ HMAC update operation. Continue an HMAC message digest operation, processing
+ another message block, and updating the HMAC context.
+
+ If Context is NULL, then ASSERT().
+ If Data is NULL, then ASSERT().
+
+ @param[in,out] Context The Specified Context.
+ @param[in,out] Data The Input Data to be digested.
+ @param[in] DataLength The length, in bytes, of Data.
+
+ @retval TRUE Update data successfully.
+ @retval FALSE The Context has been finalized.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CRYPTO_HMAC_UPDATE)(
+ IN OUT VOID *Context,
+ IN CONST VOID *Data,
+ IN UINTN DataLength
+ );
+
+/**
+ Prototype of HMAC finallization.
+ Terminate a HMAC message digest operation and output the message digest.
+
+ If Context is NULL, then ASSERT().
+ If HashValue is NULL, then ASSERT().
+
+ @param[in,out] Context The specified Context.
+ @param[out] HmacValue Pointer to a 16-byte message digest output buffer.
+
+ @retval TRUE Finalized successfully.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CRYPTO_HMAC_FINAL)(
+ IN OUT VOID *Context,
+ OUT UINT8 *HmacValue
+ );
+
+/**
+ Prototype of Block Cipher GetContextSize.
+
+ Retrieves the size, in bytes, of the context buffer required.
+
+ @return The size, in bytes, of the context buffer required.
+
+**/
+typedef
+UINTN
+(EFIAPI *CRYPTO_CIPHER_GETCONTEXTSIZE)(
+ VOID
+ );
+
+/**
+ Prototype of Block Cipher initiation.
+ Intializes the user-supplied key as the specifed context (key materials) for both
+ encryption and decryption operations.
+
+ If Context is NULL, then ASSERT().
+ If Key is NULL, then generate random key for usage.
+
+ @param[in,out] Context The specified Context.
+ @param[in] Key User-supplied cipher key.
+ @param[in] KeyBits Key length in bits.
+
+ @retval TRUE Block Cipher Initialization was successful.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CRYPTO_CIPHER_INIT)(
+ IN OUT VOID *Context,
+ IN CONST UINT8 *Key,
+ IN UINTN KeyBits
+ );
+
+/**
+ Prototype of Cipher encryption.
+ Encrypts plaintext message with the specified cipher.
+
+ If Context is NULL, then ASSERT().
+ if InData is NULL, then ASSERT().
+ If Size of input data is not multiple of Cipher algorithm related block size,
+ then ASSERT().
+
+ @param[in] Context The specified Context.
+ @param[in] InData The input plaintext data to be encrypted.
+ @param[in] InputSize The size of input data.
+ @param[in] Ivec Pointer to Initial Vector data for encryption.
+ @param[out] OutData The resultant encrypted ciphertext.
+
+ @retval TRUE Encryption successful.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CRYPTO_CIPHER_ENCRYPT)(
+ IN VOID *Context,
+ IN CONST UINT8 *InData,
+ IN UINTN InputSize,
+ IN CONST UINT8 *Ivec,
+ OUT UINT8 *OutData
+ );
+
+/**
+ Prototype of Cipher decryption.
+ Decrypts cipher message with specified cipher.
+
+ If Context is NULL, then ASSERT().
+ if InData is NULL, then ASSERT().
+ If Size of input data is not a multiple of a certaion block size , then ASSERT().
+
+ @param[in] Context The specified Context.
+ @param[in] InData The input ciphertext data to be decrypted.
+ @param[in] InputSize The InData size.
+ @param[in] Ivec Pointer to the Initial Vector data for decryption.
+ @param[out] OutData The resultant decrypted plaintext.
+
+ @retval TRUE Decryption successful.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CRYPTO_CIPHER_DECRYPT)(
+ IN VOID *Context,
+ IN CONST UINT8 *InData,
+ IN UINTN InputSize,
+ IN CONST UINT8 *Ivec,
+ OUT UINT8 *OutData
+ );
+
+/**
+ Prototype of Hash ContextSize.
+
+ Retrieves the size, in bytes, of the context buffer required for specified hash operations.
+
+ @return The size, in bytes, of the context buffer required for certain hash operations.
+
+**/
+typedef
+UINTN
+(EFIAPI *CRYPTO_HASH_GETCONTEXTSIZE)(
+ VOID
+ );
+
+/**
+ Prototype of Hash Initiate.
+
+ Initializes user-supplied memory pointed by Context as specified hash context for
+ subsequent use.
+
+ If Context is NULL, then ASSERT().
+
+ @param[out] Context Pointer to specified context being initialized.
+
+ @retval TRUE context initialization succeeded.
+ @retval FALSE context initialization failed.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CRYPTO_HASH_INIT)(
+ OUT VOID *Context
+ );
+
+/**
+ Prototype of Hash Update
+
+ Digests the input data and updates hash context.
+
+ This function performs digest on a data buffer of the specified size.
+ It can be called multiple times to compute the digest of long or discontinuous data streams.
+ Context should be already correctly intialized by HashInit(), and should not be finalized
+ by HashFinal(). Behavior with invalid context is undefined.
+
+ If Context is NULL, then ASSERT().
+
+ @param[in, out] Context Pointer to the specified context.
+ @param[in] Data Pointer to the buffer containing the data to be hashed.
+ @param[in] DataSize Size of Data buffer in bytes.
+
+ @retval TRUE data digest succeeded.
+ @retval FALSE data digest failed.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CRYPTO_HASH_UPDATE)(
+ IN OUT VOID *Context,
+ IN CONST VOID *Data,
+ IN UINTN DataSize
+ );
+
+/**
+ Prototype of Hash Finalization.
+
+ Completes computation of the digest value.
+
+ This function completes hash computation and retrieves the digest value into
+ the specified memory. After this function has been called, the context cannot
+ be used again.
+ context should be already correctly intialized by HashInit(), and should not be
+ finalized by HashFinal(). Behavior with invalid context is undefined.
+
+ If Context is NULL, then ASSERT().
+ If HashValue is NULL, then ASSERT().
+
+ @param[in, out] Context Pointer to the specified context.
+ @param[out] HashValue Pointer to a buffer that receives the digest
+ value.
+
+ @retval TRUE digest computation succeeded.
+ @retval FALSE digest computation failed.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CRYPTO_HASH_FINAL)(
+ IN OUT VOID *Context,
+ OUT UINT8 *HashValue
+ );
+
+//
+// The struct used to store the information and operation of Block Cipher algorithm.
+//
+typedef struct _ENCRYPT_ALGORITHM {
+ //
+ // The ID of the Algorithm
+ //
+ UINT8 AlgorithmId;
+ //
+ // The Key length of the Algorithm
+ //
+ UINTN KeyLength;
+ //
+ // Iv Size of the Algorithm
+ //
+ UINTN IvLength;
+ //
+ // The Block Size of the Algorithm
+ //
+ UINTN BlockSize;
+ //
+ // The Function pointer of GetContextSize.
+ //
+ CRYPTO_CIPHER_GETCONTEXTSIZE CipherGetContextSize;
+ //
+ // The Function pointer of Cipher initiation.
+ //
+ CRYPTO_CIPHER_INIT CipherInitiate;
+ //
+ // The Function pointer of Cipher Encryption.
+ //
+ CRYPTO_CIPHER_ENCRYPT CipherEncrypt;
+ //
+ // The Function pointer of Cipher Decrption.
+ //
+ CRYPTO_CIPHER_DECRYPT CipherDecrypt;
+} ENCRYPT_ALGORITHM;
+
+//
+// The struct used to store the information and operation of Autahentication algorithm.
+//
+typedef struct _AUTH_ALGORITHM {
+ //
+ // ID of the Algorithm
+ //
+ UINT8 AlgorithmId;
+ //
+ // The Key length of the Algorithm
+ //
+ UINTN DigestLength;
+ //
+ // The ICV length of the Algorithm
+ //
+ UINTN IcvLength;
+ //
+ // The block size of the Algorithm
+ //
+ UINTN BlockSize;
+ //
+ // The function pointer of GetContextSize.
+ //
+ CRYPTO_HMAC_GETCONTEXTSIZE HmacGetContextSize;
+ //
+ // The function pointer of Initiation
+ //
+ CRYPTO_HMAC_INIT HmacInitiate;
+ //
+ // The function pointer of HMAC Update.
+ //
+ CRYPTO_HMAC_UPDATE HmacUpdate;
+ //
+ // The fucntion pointer of HMAC Final
+ //
+ CRYPTO_HMAC_FINAL HmacFinal;
+} AUTH_ALGORITHM;
+
+//
+// The struct used to store the informatino and operation of Hash algorithm.
+//
+typedef struct _HASH_ALGORITHM {
+ //
+ // ID of the Algorithm
+ //
+ UINT8 AlgorithmId;
+ //
+ // The Key length of the Algorithm
+ //
+ UINTN DigestLength;
+ //
+ // The ICV length of the Algorithm
+ //
+ UINTN IcvLength;
+ //
+ // The block size of the Algorithm
+ //
+ UINTN BlockSize;
+ //
+ // The function pointer of GetContextSize
+ //
+ CRYPTO_HASH_GETCONTEXTSIZE HashGetContextSize;
+ //
+ // The function pointer of Initiation
+ //
+ CRYPTO_HASH_INIT HashInitiate;
+ //
+ // The function pointer of Hash Update
+ //
+ CRYPTO_HASH_UPDATE HashUpdate;
+ //
+ // The fucntion pointer of Hash Final
+ //
+ CRYPTO_HASH_FINAL HashFinal;
+} HASH_ALGORITHM;
+
+/**
+ Get the IV size of specified encryption alogrithm.
+
+ @param[in] AlgorithmId The encryption algorithm ID.
+
+ @return The value of IV size.
+
+**/
+UINTN
+IpSecGetEncryptIvLength (
+ IN UINT8 AlgorithmId
+ );
+
+/**
+ Get the block size of specified encryption alogrithm.
+
+ @param[in] AlgorithmId The encryption algorithm ID.
+
+ @return The value of block size.
+
+**/
+UINTN
+IpSecGetEncryptBlockSize (
+ IN UINT8 AlgorithmId
+ );
+
+/**
+ Get the required key length of the specified encryption alogrithm.
+
+ @param[in] AlgorithmId The encryption algorithm ID.
+
+ @return The value of key length.
+
+**/
+UINTN
+IpSecGetEncryptKeyLength (
+ IN UINT8 AlgorithmId
+ );
+
+/**
+ Get the ICV size of the specified Authenticaion alogrithm.
+
+ @param[in] AlgorithmId The Authentication algorithm ID.
+
+ @return The value of ICV size.
+
+**/
+UINTN
+IpSecGetIcvLength (
+ IN UINT8 AlgorithmId
+ );
+
+/**
+ Get the HMAC digest length by the specified Algorithm ID.
+
+ @param[in] AlgorithmId The specified Alogrithm ID.
+
+ @return The digest length of the specified Authentication Algorithm ID.
+
+**/
+UINTN
+IpSecGetHmacDigestLength (
+ IN UINT8 AlgorithmId
+ );
+
+/**
+ Generate a random data for IV. If the IvSize is zero, not needed to create
+ IV and return EFI_SUCCESS.
+
+ @param[in] IvBuffer The pointer of the IV buffer.
+ @param[in] IvSize The IV size in bytes.
+
+ @retval EFI_SUCCESS Create random data for IV.
+
+**/
+EFI_STATUS
+IpSecGenerateIv (
+ IN UINT8 *IvBuffer,
+ IN UINTN IvSize
+ );
+
+/**
+ Encrypt the buffer.
+
+ This function calls relevant encryption interface from CryptoLib according to
+ the input alogrithm ID. The InData should be multiple of block size. This function
+ doesn't perform the padding. If it has the Ivec data, the length of it should be
+ same with the block size. The block size is different from the different algorithm.
+
+ @param[in] AlgorithmId The Alogrithem identification defined in RFC.
+ @param[in] Key Pointer to the buffer containing encrypting key.
+ @param[in] KeyBits The length of the key in bits.
+ @param[in] Ivec Point to the buffer containning the Initializeion
+ Vector (IV) data.
+ @param[in] InData Point to the buffer containing the data to be
+ encrypted.
+ @param[in] InDataLength The length of InData in Bytes.
+ @param[out] OutData Point to the buffer that receives the encryption
+ output.
+
+ @retval EFI_UNSUPPORTED The input Algorithm is not supported.
+ @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+IpSecCryptoIoEncrypt (
+ IN CONST UINT8 AlgorithmId,
+ IN CONST UINT8 *Key,
+ IN CONST UINTN KeyBits,
+ IN CONST UINT8 *Ivec, OPTIONAL
+ IN UINT8 *InData,
+ IN UINTN InDataLength,
+ OUT UINT8 *OutData
+ );
+
+/**
+ Decrypts the buffer.
+
+ This function calls relevant Decryption interface from CryptoLib according to
+ the input alogrithm ID. The InData should be multiple of block size. This function
+ doesn't perform the padding. If it has the Ivec data, the length of it should be
+ same with the block size. The block size is different from the different algorithm.
+
+ @param[in] AlgorithmId The Alogrithem identification defined in RFC.
+ @param[in] Key Pointer to the buffer containing encrypting key.
+ @param[in] KeyBits The length of the key in bits.
+ @param[in] Ivec Point to the buffer containning the Initializeion
+ Vector (IV) data.
+ @param[in] InData Point to the buffer containing the data to be
+ decrypted.
+ @param[in] InDataLength The length of InData in Bytes.
+ @param[out] OutData Pointer to the buffer that receives the decryption
+ output.
+
+ @retval EFI_UNSUPPORTED The input Algorithm is not supported.
+ @retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.
+ @retval EFI_SUCCESS The operation completed successfully.
+
+**/
+EFI_STATUS
+IpSecCryptoIoDecrypt (
+ IN CONST UINT8 AlgorithmId,
+ IN CONST UINT8 *Key,
+ IN CONST UINTN KeyBits,
+ IN CONST UINT8 *Ivec, OPTIONAL
+ IN UINT8 *InData,
+ IN UINTN InDataLength,
+ OUT UINT8 *OutData
+ );
+
+/**
+ Digests the Payload with key and store the result into the OutData.
+
+ This function calls relevant Hmac interface from CryptoLib according to
+ the input alogrithm ID. It computes all datas from InDataFragment and output
+ the result into the OutData buffer. If the OutDataSize is larger than the related
+ HMAC alogrithm output size, return EFI_INVALID_PARAMETER.
+
+ @param[in] AlgorithmId The authentication Identification.
+ @param[in] Key Pointer of the authentication key.
+ @param[in] KeyLength The length of the Key in bytes.
+ @param[in] InDataFragment The list contains all data to be authenticated.
+ @param[in] FragmentCount The size of the InDataFragment.
+ @param[out] OutData For in, the buffer to receive the output data.
+ For out, the buffer contains the authenticated data.
+ @param[in] OutDataSize The size of the buffer of OutData.
+
+ @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.
+ @retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size.
+ @retval EFI_SUCCESS Authenticate the payload successfully.
+ @retval otherwise Authentication of the payload fails.
+
+**/
+EFI_STATUS
+IpSecCryptoIoHmac (
+ IN CONST UINT8 AlgorithmId,
+ IN CONST UINT8 *Key,
+ IN UINTN KeyLength,
+ IN HASH_DATA_FRAGMENT *InDataFragment,
+ IN UINTN FragmentCount,
+ OUT UINT8 *OutData,
+ IN UINTN OutDataSize
+ );
+
+/**
+ Digests the Payload and store the result into the OutData.
+
+ This function calls relevant Hash interface from CryptoLib according to
+ the input alogrithm ID. It computes all datas from InDataFragment and output
+ the result into the OutData buffer. If the OutDataSize is larger than the related
+ Hash alogrithm output size, return EFI_INVALID_PARAMETER.
+
+ @param[in] AlgorithmId The authentication Identification.
+ @param[in] InDataFragment A list contains all data to be authenticated.
+ @param[in] FragmentCount The size of the InDataFragment.
+ @param[out] OutData For in, the buffer to receive the output data.
+ For out, the buffer contains the authenticated data.
+ @param[in] OutDataSize The size of the buffer of OutData.
+
+ @retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.
+ @retval EFI_SUCCESS Authenticated the payload successfully.
+ @retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash
+ algorithm could handle.
+ @retval otherwise Authentication of the payload failed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoHash (
+ IN CONST UINT8 AlgorithmId,
+ IN HASH_DATA_FRAGMENT *InDataFragment,
+ IN UINTN FragmentCount,
+ OUT UINT8 *OutData,
+ IN UINTN OutDataSize
+ );
+
+/**
+ Generates the Diffie-Hellman public key.
+
+ This function first initiate a DHContext, then call the DhSetParameter() to set
+ the prime and primelenght, at end call the DhGenerateKey() to generates random
+ secret exponent, and computes the public key. The output returned via parameter
+ PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey
+ buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned
+ and PublicKeySize is set to the required buffer size to obtain the public key.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] Generator Vlaue of generator.
+ @param[in] PrimeLength Length in bits of prime to be generated.
+ @param[in] Prime Pointer to the buffer to receive the generated
+ prime number.
+ @param[out] PublicKey Pointer to the buffer to receive generated public key.
+ @param[in, out] PublicKeySize For in, the size of PublicKey buffer in bytes.
+ For out, the size of data returned in PublicKey
+ buffer in bytes.
+
+ @retval EFI_SUCCESS The operation perfoms successfully.
+ @retval Otherwise The operation is failed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoDhGetPublicKey (
+ IN OUT UINT8 **DhContext,
+ IN UINTN Generator,
+ IN UINTN PrimeLength,
+ IN CONST UINT8 *Prime,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ );
+
+/**
+ Generates exchanged common key.
+
+ Given peer's public key, this function computes the exchanged common key, based
+ on its own context including value of prime modulus and random secret exponent.
+
+ @param[in, out] DhContext Pointer to the DH context.
+ @param[in] PeerPublicKey Pointer to the peer's Public Key.
+ @param[in] PeerPublicKeySize Size of peer's public key in bytes.
+ @param[out] Key Pointer to the buffer to receive generated key.
+ @param[in, out] KeySize For in, the size of Key buffer in bytes.
+ For out, the size of data returned in Key
+ buffer in bytes.
+
+ @retval EFI_SUCCESS The operation perfoms successfully.
+ @retval Otherwise The operation is failed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoDhComputeKey (
+ IN OUT UINT8 *DhContext,
+ IN CONST UINT8 *PeerPublicKey,
+ IN UINTN PeerPublicKeySize,
+ OUT UINT8 *Key,
+ IN OUT UINTN *KeySize
+ );
+
+/**
+ Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER.
+
+ @param[in, out] DhContext Pointer to the DH context to be freed.
+
+ @retval EFI_SUCCESS The operation perfoms successfully.
+ @retval EFI_INVALID_PARAMETER The DhContext is NULL.
+
+**/
+EFI_STATUS
+IpSecCryptoIoFreeDh (
+ IN OUT UINT8 **DhContext
+ );
+
+/**
+ Generates random numbers of specified size.
+
+ If the Random Generator wasn't initiated, initiate it first, then call RandomBytes.
+
+ @param[out] OutBuffer Pointer to buffer to receive random value.
+ @param[in] Bytes Size of randome bytes to generate.
+
+ @retval EFI_SUCCESS The operation perfoms successfully.
+ @retval Otherwise The operation is failed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoGenerateRandomBytes (
+ OUT UINT8* OutBuffer,
+ IN UINTN Bytes
+ );
+
+/**
+ Authenticate data with the certificate.
+
+ @param[in] InData Pointer to the Data to be signed.
+ @param[in] InDataSize InData size in bytes.
+ @param[in] PrivateKey Pointer to the private key.
+ @param[in] PrivateKeySize The size of Private Key in bytes.
+ @param[in] KeyPassWord Pointer to the password for retrieving private key.
+ @param[in] KeyPwdSize The size of Key Password in bytes.
+ @param[out] OutData The pointer to the signed data.
+ @param[in, out] OutDataSize Pointer to contain the size of out data.
+
+**/
+VOID
+IpSecCryptoIoAuthDataWithCertificate (
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN UINT8 *PrivateKey,
+ IN UINTN PrivateKeySize,
+ IN UINT8 *KeyPassWord,
+ IN UINTN KeyPwdSize,
+ OUT UINT8 **OutData,
+ IN OUT UINTN *OutDataSize
+ );
+
+/**
+ Verify the singed data with the public key which is contained in a certificate.
+
+ @param[in] InCert Pointer to the Certificate which contains the
+ public key.
+ @param[in] CertLen The size of Certificate in bytes.
+ @param[in] InCa Pointer to the CA certificate
+ @param[in] CaLen The size of CA certificate in bytes.
+ @param[in] InData Pointer to octect message hash to be checked.
+ @param[in] InDataSize Size of the message hash in bytes.
+ @param[in] Singnature The pointer to the RSA PKCS1-V1_5 signature to be verifed.
+ @param[in] SigSize Size of signature in bytes.
+
+ @retval TRUE Valid signature encoded in PKCS1-v1_5.
+ @retval FALSE Invalid signature or invalid RSA context.
+
+**/
+BOOLEAN
+IpSecCryptoIoVerifySignDataByCertificate (
+ IN UINT8 *InCert,
+ IN UINTN CertLen,
+ IN UINT8 *InCa,
+ IN UINTN CaLen,
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN UINT8 *Singnature,
+ IN UINTN SigSize
+ );
+
+/**
+ Retrieves the RSA Public Key from one X509 certificate (DER format only).
+
+ @param[in] InCert Pointer to the certificate.
+ @param[in] CertLen The size of the certificate in bytes.
+ @param[out] PublicKey Pointer to the retrieved public key.
+ @param[out] PublicKeyLen Size of Public Key in bytes.
+
+ @retval EFI_SUCCESS Successfully get the public Key.
+ @retval EFI_INVALID_PARAMETER The CA certificate is malformed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoGetPublicKeyFromCert (
+ IN UINT8 *InCert,
+ IN UINTN CertLen,
+ OUT UINT8 **PublicKey,
+ OUT UINTN *PublicKeyLen
+ );
+
+/**
+ Retrieves the subject name from one X509 certificate (DER format only).
+
+ @param[in] InCert Pointer to the X509 certificate.
+ @param[in] CertSize The size of the X509 certificate in bytes.
+ @param[out] CertSubject Pointer to the retrieved certificate subject.
+ @param[out] SubjectSize The size of Certificate Subject in bytes.
+
+ @retval EFI_SUCCESS Retrieved the certificate subject successfully.
+ @retval EFI_INVALID_PARAMETER The certificate is malformed.
+
+**/
+EFI_STATUS
+IpSecCryptoIoGetSubjectFromCert (
+ IN UINT8 *InCert,
+ IN UINTN CertSize,
+ OUT UINT8 **CertSubject,
+ OUT UINTN *SubjectSize
+ );
+
+#endif
+
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecDebug.c b/Core/NetworkPkg/IpSecDxe/IpSecDebug.c
new file mode 100644
index 0000000000..636e775969
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecDebug.c
@@ -0,0 +1,334 @@
+/** @file
+ The Interfaces of IPsec debug information printing.
+
+ Copyright (c) 2009 - 2010, 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 "IpSecDebug.h"
+
+//
+// The print title for IKEv1 variety phase.
+//
+CHAR8 *mIkev1StateStr[IKE_STATE_NUM] = {
+ "IKEv1_MAIN_1",
+ "IKEv1_MAIN_2",
+ "IKEv1_MAIN_3",
+ "IKEv1_MAIN_ESTABLISHED",
+ "IKEv1_QUICK_1",
+ "IKEv1_QUICK_2",
+ "IKEv1_QUICK_ESTABLISHED"
+};
+
+//
+// The print title for IKEv2 variety phase.
+//
+CHAR8 *mIkev2StateStr[IKE_STATE_NUM] = {
+ "IKEv2_STATE_INIT",
+ "IKEv2_STATE_AUTH",
+ "IKEv2_STATE_SA_ESTABLISH",
+ "IKEv2_STATE_CREATE_CHILD",
+ "IKEv2_STATE_SA_REKEYING",
+ "IKEv2_STATE_CHILD_SA_ESTABLISHED",
+ "IKEv2_STATE_SA_DELETING"
+};
+
+//
+// The print title for IKEv1 variety Exchagne.
+//
+CHAR8 *mExchangeStr[] = {
+ "IKEv1 Main Exchange",
+ "IKEv1 Info Exchange",
+ "IKEv1 Quick Exchange",
+ "IKEv2 Initial Exchange",
+ "IKEv2 Auth Exchange",
+ "IKEv2 Create Child Exchange",
+ "IKEv2 Info Exchange",
+ "IKE Unknow Exchange"
+};
+
+//
+// The print title for IKEv1 variety Payload.
+//
+CHAR8 *mIkev1PayloadStr[] = {
+ "IKEv1 None Payload",
+ "IKEv1 SA Payload",
+ "IKEv1 Proposal Payload",
+ "IKEv1 Transform Payload",
+ "IKEv1 KE Payload",
+ "IKEv1 ID Payload",
+ "IKEv1 Certificate Payload",
+ "IKEv1 Certificate Request Payload",
+ "IKEv1 Hash Payload",
+ "IKEv1 Signature Payload",
+ "IKEv1 Nonce Payload",
+ "IKEv1 Notify Payload",
+ "IKEv1 Delete Payload",
+ "IKEv1 Vendor Payload"
+};
+
+//
+// The print title for IKEv2 variety Payload.
+//
+CHAR8* mIkev2PayloadStr[] = {
+ "IKEv2 SA Payload",
+ "IKEv2 Key Payload",
+ "IKEv2 Identity Initial Payload",
+ "IKEv2 Identity Respond Payload",
+ "IKEv2 Certificate Payload",
+ "IKEv2 Certificate Request Payload",
+ "IKEv2 Auth Payload",
+ "IKEv2 Nonce Payload",
+ "IKEv2 Notify Payload",
+ "IKEv2 Delet Payload",
+ "IKEv2 Vendor Payload",
+ "IKEv2 Traffic Selector Initiator Payload",
+ "IKEv2 Traffic Selector Respond Payload",
+ "IKEv2 Encrypt Payload",
+ "IKEv2 Configuration Payload",
+ "IKEv2 Extensible Authentication Payload"
+};
+
+/**
+ Print the IP address.
+
+ @param[in] Level Debug print error level. Pass to DEBUG().
+ @param[in] Ip Point to a specified IP address.
+ @param[in] IpVersion The IP Version.
+
+**/
+VOID
+IpSecDumpAddress (
+ IN UINTN Level,
+ IN EFI_IP_ADDRESS *Ip,
+ IN UINT8 IpVersion
+ )
+{
+ if (IpVersion == IP_VERSION_6) {
+ DEBUG (
+ (Level,
+ "%x%x:%x%x:%x%x:%x%x",
+ Ip->v6.Addr[0],
+ Ip->v6.Addr[1],
+ Ip->v6.Addr[2],
+ Ip->v6.Addr[3],
+ Ip->v6.Addr[4],
+ Ip->v6.Addr[5],
+ Ip->v6.Addr[6],
+ Ip->v6.Addr[7])
+ );
+ DEBUG (
+ (Level,
+ ":%x%x:%x%x:%x%x:%x%x\n",
+ Ip->v6.Addr[8],
+ Ip->v6.Addr[9],
+ Ip->v6.Addr[10],
+ Ip->v6.Addr[11],
+ Ip->v6.Addr[12],
+ Ip->v6.Addr[13],
+ Ip->v6.Addr[14],
+ Ip->v6.Addr[15])
+ );
+ } else {
+ DEBUG (
+ (Level,
+ "%d.%d.%d.%d\n",
+ Ip->v4.Addr[0],
+ Ip->v4.Addr[1],
+ Ip->v4.Addr[2],
+ Ip->v4.Addr[3])
+ );
+ }
+
+}
+
+/**
+ Print IKE Current states.
+
+ @param[in] Previous The Previous state of IKE.
+ @param[in] Current The current state of IKE.
+ @param[in] IkeVersion The version of IKE.
+
+**/
+VOID
+IkeDumpState (
+ IN UINT32 Previous,
+ IN UINT32 Current,
+ IN UINT8 IkeVersion
+ )
+{
+ if (Previous >= IKE_STATE_NUM || Current >= IKE_STATE_NUM) {
+ return;
+ }
+
+ if (Previous == Current) {
+ if (IkeVersion == 1) {
+ DEBUG ((DEBUG_INFO, "\n****Current state is %a\n", mIkev1StateStr[Previous]));
+ } else if (IkeVersion == 2) {
+ DEBUG ((DEBUG_INFO, "\n****Current state is %a\n", mIkev2StateStr[Previous]));
+ }
+ } else {
+ if (IkeVersion == 1) {
+ DEBUG ((DEBUG_INFO, "\n****Change state from %a to %a\n", mIkev1StateStr[Previous], mIkev1StateStr[Current]));
+ } else {
+ DEBUG ((DEBUG_INFO, "\n****Change state from %a to %a\n", mIkev2StateStr[Previous], mIkev2StateStr[Current]));
+ }
+ }
+}
+
+/**
+ Print the IKE Packet.
+
+ @param[in] Packet Point to IKE packet to be printed.
+ @param[in] Direction Point to the IKE packet is inbound or outbound.
+ @param[in] IpVersion Specified IP Version.
+
+**/
+VOID
+IpSecDumpPacket (
+ IN IKE_PACKET *Packet,
+ IN EFI_IPSEC_TRAFFIC_DIR Direction,
+ IN UINT8 IpVersion
+ )
+{
+ CHAR8 *TypeStr;
+ UINTN PacketSize;
+ UINT64 InitCookie;
+ UINT64 RespCookie;
+
+ ASSERT (Packet != NULL);
+
+ PacketSize = Packet->PayloadTotalSize + sizeof (IKE_HEADER);
+ InitCookie = (Direction == EfiIPsecOutBound) ? HTONLL (Packet->Header->InitiatorCookie) : Packet->Header->InitiatorCookie;
+ RespCookie = (Direction == EfiIPsecOutBound) ? HTONLL (Packet->Header->ResponderCookie) : Packet->Header->ResponderCookie;
+
+ switch (Packet->Header->ExchangeType) {
+ case IKE_XCG_TYPE_IDENTITY_PROTECT:
+ TypeStr = mExchangeStr[0];
+ break;
+
+ case IKE_XCG_TYPE_INFO:
+ TypeStr = mExchangeStr[1];
+ break;
+
+ case IKE_XCG_TYPE_QM:
+ TypeStr = mExchangeStr[2];
+ break;
+
+ case IKE_XCG_TYPE_SA_INIT:
+ TypeStr = mExchangeStr[3];
+ break;
+
+ case IKE_XCG_TYPE_AUTH:
+ TypeStr = mExchangeStr[4];
+ break;
+
+ case IKE_XCG_TYPE_CREATE_CHILD_SA:
+ TypeStr = mExchangeStr[5];
+ break;
+
+ case IKE_XCG_TYPE_INFO2:
+ TypeStr = mExchangeStr[6];
+ break;
+
+ default:
+ TypeStr = mExchangeStr[7];
+ break;
+ }
+
+ if (Direction == EfiIPsecOutBound) {
+ DEBUG ((DEBUG_INFO, "\n>>>Sending %d bytes %a to ", PacketSize, TypeStr));
+ } else {
+ DEBUG ((DEBUG_INFO, "\n>>>Receiving %d bytes %a from ", PacketSize, TypeStr));
+ }
+
+ IpSecDumpAddress (DEBUG_INFO, &Packet->RemotePeerIp, IpVersion);
+
+ DEBUG ((DEBUG_INFO, " InitiatorCookie:0x%lx ResponderCookie:0x%lx\n", InitCookie, RespCookie));
+ DEBUG (
+ (DEBUG_INFO,
+ " Version: 0x%x Flags:0x%x ExchangeType:0x%x\n",
+ Packet->Header->Version,
+ Packet->Header->Flags,
+ Packet->Header->ExchangeType)
+ );
+ DEBUG (
+ (DEBUG_INFO,
+ " MessageId:0x%x NextPayload:0x%x\n",
+ Packet->Header->MessageId,
+ Packet->Header->NextPayload)
+ );
+
+}
+
+/**
+ Print the IKE Paylolad.
+
+ @param[in] IkePayload Point to payload to be printed.
+ @param[in] IkeVersion The specified version of IKE.
+
+**/
+VOID
+IpSecDumpPayload (
+ IN IKE_PAYLOAD *IkePayload,
+ IN UINT8 IkeVersion
+ )
+{
+ if (IkeVersion == 1) {
+ DEBUG ((DEBUG_INFO, "+%a\n", mIkev1PayloadStr[IkePayload->PayloadType]));
+ } else {
+ //
+ // For IKEV2 the first Payload type is started from 33.
+ //
+ DEBUG ((DEBUG_INFO, "+%a\n", mIkev2PayloadStr[IkePayload->PayloadType - 33]));
+ }
+ IpSecDumpBuf ("Payload data", IkePayload->PayloadBuf, IkePayload->PayloadSize);
+}
+
+/**
+ Print the buffer in form of Hex.
+
+ @param[in] Title The strings to be printed before the data of the buffer.
+ @param[in] Data Points to buffer to be printed.
+ @param[in] DataSize The size of the buffer to be printed.
+
+**/
+VOID
+IpSecDumpBuf (
+ IN CHAR8 *Title,
+ IN UINT8 *Data,
+ IN UINTN DataSize
+ )
+{
+ UINTN Index;
+ UINTN DataIndex;
+ UINTN BytesRemaining;
+ UINTN BytesToPrint;
+
+ DataIndex = 0;
+ BytesRemaining = DataSize;
+
+ DEBUG ((DEBUG_INFO, "==%a %d bytes==\n", Title, DataSize));
+
+ while (BytesRemaining > 0) {
+
+ BytesToPrint = (BytesRemaining > IPSEC_DEBUG_BYTE_PER_LINE) ? IPSEC_DEBUG_BYTE_PER_LINE : BytesRemaining;
+
+ for (Index = 0; Index < BytesToPrint; Index++) {
+ DEBUG ((DEBUG_INFO, " 0x%02x,", Data[DataIndex++]));
+ }
+
+ DEBUG ((DEBUG_INFO, "\n"));
+ BytesRemaining -= BytesToPrint;
+ }
+
+}
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecDebug.h b/Core/NetworkPkg/IpSecDxe/IpSecDebug.h
new file mode 100644
index 0000000000..16bbcd53c6
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecDebug.h
@@ -0,0 +1,107 @@
+/** @file
+ The definition of functions and MACROs used for IPsec debug information printting.
+
+ Copyright (c) 2009 - 2010, 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.
+
+**/
+#ifndef _EFI_IPSEC_DEBUG_H_
+#define _EFI_IPSEC_DEBUG_H_
+
+#include "IkeCommon.h"
+#include "IkePacket.h"
+
+#define IPSEC_DUMP_ADDRESS(Level, Ip, Version) IpSecDumpAddress (Level, Ip, Version)
+#define IKEV1_DUMP_STATE(Previous, Current) IkeDumpState (Previous, Current, 1)
+#define IKEV2_DUMP_STATE(Previous, Current) IkeDumpState (Previous, Current, 2)
+#define IPSEC_DUMP_PACKET(Packet, Direction, IpVersion) IpSecDumpPacket (Packet, Direction, IpVersion)
+#define IPSEC_DUMP_PAYLOAD(IkePayload) IpSecDumpPayload (IkePayload, 1)
+#define IKEV2_DUMP_PAYLOAD(IkePayload) IpSecDumpPayload (IkePayload, 2)
+#define IPSEC_DUMP_BUF(Title, Data, DataSize) IpSecDumpBuf (Title, Data, DataSize)
+
+#define IPSEC_DEBUG_BYTE_PER_LINE 8
+#define IKE_STATE_NUM 7
+
+
+
+/**
+ Print the IP address.
+
+ @param[in] Level Debug print error level. Pass to DEBUG().
+ @param[in] Ip Point to specified IP address.
+ @param[in] IpVersion The IP Version.
+
+**/
+VOID
+IpSecDumpAddress (
+ IN UINTN Level,
+ IN EFI_IP_ADDRESS *Ip,
+ IN UINT8 IpVersion
+ );
+
+/**
+ Print IKE Current states.
+
+ @param[in] Previous The Previous state of IKE.
+ @param[in] Current The current state of IKE.
+ @param[in] IkeVersion The version of IKE.
+
+**/
+VOID
+IkeDumpState (
+ IN UINT32 Previous,
+ IN UINT32 Current,
+ IN UINT8 IkeVersion
+ );
+
+/**
+ Print the IKE Packet.
+
+ @param[in] Packet Point to IKE packet to be printed.
+ @param[in] Direction Point to the IKE packet is inbound or outbound.
+ @param[in] IpVersion Specified IP Version.
+
+**/
+VOID
+IpSecDumpPacket (
+ IN IKE_PACKET *Packet,
+ IN EFI_IPSEC_TRAFFIC_DIR Direction,
+ IN UINT8 IpVersion
+ );
+
+/**
+ Print the IKE Paylolad.
+
+ @param[in] IkePayload Point to payload to be printed.
+ @param[in] IkeVersion The specified version of IKE.
+
+**/
+VOID
+IpSecDumpPayload (
+ IN IKE_PAYLOAD *IkePayload,
+ IN UINT8 IkeVersion
+ );
+
+/**
+ Print the buffer in form of Hex.
+
+ @param[in] Title The strings to be printed before the data of the buffer.
+ @param[in] Data Point to buffer to be printed.
+ @param[in] DataSize The size of the buffer to be printed.
+
+**/
+VOID
+IpSecDumpBuf (
+ IN CHAR8 *Title,
+ IN UINT8 *Data,
+ IN UINTN DataSize
+ );
+
+#endif
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecDriver.c b/Core/NetworkPkg/IpSecDxe/IpSecDriver.c
new file mode 100644
index 0000000000..d8282b5e2f
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecDriver.c
@@ -0,0 +1,665 @@
+/** @file
+ Driver Binding Protocol for IPsec Driver.
+
+ Copyright (c) 2009 - 2015, 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 <Library/BaseCryptLib.h>
+
+#include "IpSecConfigImpl.h"
+#include "IkeService.h"
+#include "IpSecDebug.h"
+
+/**
+ Test to see if this driver supports ControllerHandle. This is the worker function
+ for IpSec4(6)DriverbindingSupported.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] RemainingDevicePath Optional parameter used to pick a specific child
+ device to start.
+ @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
+
+ @retval EFI_SUCCES This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN UINT8 IpVersion
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *UdpServiceBindingGuid;
+
+ if (IpVersion == IP_VERSION_4) {
+ UdpServiceBindingGuid = &gEfiUdp4ServiceBindingProtocolGuid;
+ } else {
+ UdpServiceBindingGuid = &gEfiUdp6ServiceBindingProtocolGuid;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ UdpServiceBindingGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Start this driver on ControllerHandle. This is the worker function
+ for IpSec4(6)DriverbindingStart.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to.
+ @param[in] RemainingDevicePath Optional parameter used to pick a specific child
+ device to start.
+ @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
+
+ @retval EFI_SUCCES This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
+ Currently not implemented.
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL,
+ IN UINT8 IpVersion
+ )
+{
+ EFI_IPSEC2_PROTOCOL *IpSec;
+ EFI_STATUS Status;
+ IPSEC_PRIVATE_DATA *Private;
+
+ //
+ // Ipsec protocol should be installed when load image.
+ //
+ Status = gBS->LocateProtocol (&gEfiIpSec2ProtocolGuid, NULL, (VOID **) &IpSec);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (IpSec);
+
+ if (IpVersion == IP_VERSION_4) {
+ //
+ // Try to open a udp4 io for input.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUdp4ServiceBindingProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = IkeOpenInputUdp4 (Private, ControllerHandle, This->DriverBindingHandle);
+ }
+ } else {
+ //
+ // Try to open a udp6 io for input.
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiUdp6ServiceBindingProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = IkeOpenInputUdp6 (Private, ControllerHandle, This->DriverBindingHandle);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop this driver on ControllerHandle. This is the worker function
+ for IpSec4(6)DriverbindingStop.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of a device to stop the driver on.
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If the number of
+ children is zero, stop the entire bus driver.
+ @param[in] ChildHandleBuffer List of Child Handles to Stop.
+ @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6.
+
+ @retval EFI_SUCCES This driver removed ControllerHandle.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer,
+ IN UINT8 IpVersion
+ )
+{
+ EFI_IPSEC2_PROTOCOL *IpSec;
+ EFI_STATUS Status;
+ IPSEC_PRIVATE_DATA *Private;
+ IKE_UDP_SERVICE *UdpSrv;
+ LIST_ENTRY *Entry;
+ LIST_ENTRY *Next;
+ IKEV2_SA_SESSION *Ikev2SaSession;
+
+ //
+ // Locate ipsec protocol to get private data.
+ //
+ Status = gBS->LocateProtocol (&gEfiIpSec2ProtocolGuid, NULL, (VOID **) &IpSec);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (IpSec);
+
+ //
+ // The SAs are shared by both IP4 and IP6 stack. So we skip the cleanup
+ // and leave the SAs unchanged if the other IP stack is still running.
+ //
+ if ((IpVersion == IP_VERSION_4 && Private->Udp6Num ==0) ||
+ (IpVersion == IP_VERSION_6 && Private->Udp4Num ==0)) {
+ //
+ // If IKEv2 SAs are under establishing, delete it directly.
+ //
+ if (!IsListEmpty (&Private->Ikev2SessionList)) {
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Ikev2SessionList) {
+ Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);
+ RemoveEntryList (&Ikev2SaSession->BySessionTable);
+ Ikev2SaSessionFree (Ikev2SaSession);
+ }
+ }
+
+ //
+ // Delete established IKEv2 SAs.
+ //
+ if (!IsListEmpty (&Private->Ikev2EstablishedList)) {
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Ikev2EstablishedList) {
+ Ikev2SaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);
+ RemoveEntryList (&Ikev2SaSession->BySessionTable);
+ Ikev2SaSessionFree (Ikev2SaSession);
+ }
+ }
+ }
+
+ if (IpVersion == IP_VERSION_4) {
+ //
+ // If has udp4 io opened on the controller, close and free it.
+ //
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Udp4List) {
+
+ UdpSrv = IPSEC_UDP_SERVICE_FROM_LIST (Entry);
+ //
+ // Find the right udp service which installed on the appointed nic handle.
+ //
+ if (UdpSrv->Input != NULL && ControllerHandle == UdpSrv->Input->UdpHandle) {
+ UdpIoFreeIo (UdpSrv->Input);
+ UdpSrv->Input = NULL;
+ }
+
+ if (UdpSrv->Output != NULL && ControllerHandle == UdpSrv->Output->UdpHandle) {
+ UdpIoFreeIo (UdpSrv->Output);
+ UdpSrv->Output = NULL;
+ }
+
+ if (UdpSrv->Input == NULL && UdpSrv->Output == NULL) {
+ RemoveEntryList (&UdpSrv->List);
+ FreePool (UdpSrv);
+ ASSERT (Private->Udp4Num > 0);
+ Private->Udp4Num--;
+ }
+ }
+ } else {
+ //
+ // If has udp6 io opened on the controller, close and free it.
+ //
+ NET_LIST_FOR_EACH_SAFE (Entry, Next, &Private->Udp6List) {
+
+ UdpSrv = IPSEC_UDP_SERVICE_FROM_LIST (Entry);
+ //
+ // Find the right udp service which installed on the appointed nic handle.
+ //
+ if (UdpSrv->Input != NULL && ControllerHandle == UdpSrv->Input->UdpHandle) {
+ UdpIoFreeIo (UdpSrv->Input);
+ UdpSrv->Input = NULL;
+ }
+
+ if (UdpSrv->Output != NULL && ControllerHandle == UdpSrv->Output->UdpHandle) {
+ UdpIoFreeIo (UdpSrv->Output);
+ UdpSrv->Output = NULL;
+ }
+
+ if (UdpSrv->Input == NULL && UdpSrv->Output == NULL) {
+ RemoveEntryList (&UdpSrv->List);
+ FreePool (UdpSrv);
+ ASSERT (Private->Udp6Num > 0);
+ Private->Udp6Num--;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] RemainingDevicePath Optional parameter used to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCES This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSec4DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return IpSecSupported (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ IP_VERSION_4
+ );
+}
+
+/**
+ Start this driver on ControllerHandle.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to.
+ @param[in] RemainingDevicePath Optional parameter used to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCES This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
+ Currently not implemented.
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+IpSec4DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return IpSecStart (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ IP_VERSION_4
+ );
+}
+
+/**
+ Stop this driver on ControllerHandle.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of a device to stop the driver on.
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If the number of
+ children is zero, stop the entire bus driver.
+ @param[in] ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCES This driver removed ControllerHandle.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSec4DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ return IpSecStop (
+ This,
+ ControllerHandle,
+ NumberOfChildren,
+ ChildHandleBuffer,
+ IP_VERSION_4
+ );
+}
+
+/**
+ Test to see if this driver supports ControllerHandle.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to test.
+ @param[in] RemainingDevicePath Optional parameter used to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCES This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSec6DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return IpSecSupported (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ IP_VERSION_6
+ );
+}
+
+/**
+ Start this driver on ControllerHandle.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of device to bind driver to.
+ @param[in] RemainingDevicePath Optional parameter used to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCES This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
+ Currently not implemented.
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+IpSec6DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ return IpSecStart (
+ This,
+ ControllerHandle,
+ RemainingDevicePath,
+ IP_VERSION_6
+ );
+}
+
+/**
+ Stop this driver on ControllerHandle.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] ControllerHandle Handle of a device to stop the driver on.
+ @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If the number of
+ children is zero, stop the entire bus driver.
+ @param[in] ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCES This driver removed ControllerHandle.
+ @retval other This driver was not removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSec6DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ return IpSecStop (
+ This,
+ ControllerHandle,
+ NumberOfChildren,
+ ChildHandleBuffer,
+ IP_VERSION_6
+ );
+}
+
+EFI_DRIVER_BINDING_PROTOCOL gIpSec4DriverBinding = {
+ IpSec4DriverBindingSupported,
+ IpSec4DriverBindingStart,
+ IpSec4DriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+EFI_DRIVER_BINDING_PROTOCOL gIpSec6DriverBinding = {
+ IpSec6DriverBindingSupported,
+ IpSec6DriverBindingStart,
+ IpSec6DriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ This is a callback function when the mIpSecInstance.DisabledEvent is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+IpSecCleanupAllSa (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ IPSEC_PRIVATE_DATA *Private;
+ Private = (IPSEC_PRIVATE_DATA *) Context;
+ Private->IsIPsecDisabling = TRUE;
+ IkeDeleteAllSas (Private, TRUE);
+}
+
+/**
+ This is the declaration of an EFI image entry point. This entry point is
+ the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers, including
+ both device drivers and bus drivers.
+
+ The entry point for IPsec driver which installs the driver binding,
+ component name protocol, IPsec Config protcolon, and IPsec protocol in
+ its ImageHandle.
+
+ @param[in] ImageHandle The firmware allocated handle for the UEFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_ALREADY_STARTED The IPsec driver has been already loaded.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The operation is failed.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ IPSEC_PRIVATE_DATA *Private;
+ EFI_IPSEC2_PROTOCOL *IpSec;
+
+ //
+ // Check whether ipsec protocol has already been installed.
+ //
+ Status = gBS->LocateProtocol (&gEfiIpSec2ProtocolGuid, NULL, (VOID **) &IpSec);
+
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "_ModuleEntryPoint: IpSec has been already loaded\n"));
+ Status = EFI_ALREADY_STARTED;
+ goto ON_EXIT;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiDpcProtocolGuid, NULL, (VOID **) &mDpc);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "_ModuleEntryPoint: Failed to locate EfiDpcProtocol\n"));
+ goto ON_EXIT;
+ }
+
+ Private = AllocateZeroPool (sizeof (IPSEC_PRIVATE_DATA));
+
+ if (Private == NULL) {
+ DEBUG ((DEBUG_ERROR, "_ModuleEntryPoint: Failed to allocate private data\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ //
+ // Create disable event to cleanup all SA when ipsec disabled by user.
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ IpSecCleanupAllSa,
+ Private,
+ &mIpSecInstance.DisabledEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "_ModuleEntryPoint: Failed to create disable event\n"));
+ goto ON_FREE_PRIVATE;
+ }
+
+ Private->Signature = IPSEC_PRIVATE_DATA_SIGNATURE;
+ Private->ImageHandle = ImageHandle;
+ CopyMem (&Private->IpSec, &mIpSecInstance, sizeof (EFI_IPSEC2_PROTOCOL));
+
+ //
+ // Initilize Private's members. Thess members is used for IKE.
+ //
+ InitializeListHead (&Private->Udp4List);
+ InitializeListHead (&Private->Udp6List);
+ InitializeListHead (&Private->Ikev1SessionList);
+ InitializeListHead (&Private->Ikev1EstablishedList);
+ InitializeListHead (&Private->Ikev2SessionList);
+ InitializeListHead (&Private->Ikev2EstablishedList);
+
+ RandomSeed (NULL, 0);
+ //
+ // Initialize the ipsec config data and restore it from variable.
+ //
+ Status = IpSecConfigInitialize (Private);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "_ModuleEntryPoint: Failed to initialize IpSecConfig\n"));
+ goto ON_CLOSE_EVENT;
+ }
+ //
+ // Install ipsec protocol which is used by ip driver to process ipsec header.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Private->Handle,
+ &gEfiIpSec2ProtocolGuid,
+ &Private->IpSec,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_UNINSTALL_CONFIG;
+ }
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gIpSec4DriverBinding,
+ ImageHandle,
+ &gIpSecComponentName,
+ &gIpSecComponentName2
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_UNINSTALL_IPSEC;
+ }
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gIpSec6DriverBinding,
+ NULL,
+ &gIpSecComponentName,
+ &gIpSecComponentName2
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_UNINSTALL_IPSEC4_DB;
+ }
+
+ return Status;
+
+ON_UNINSTALL_IPSEC4_DB:
+ gBS->UninstallMultipleProtocolInterfaces (
+ ImageHandle,
+ &gEfiDriverBindingProtocolGuid,
+ &gIpSec4DriverBinding,
+ &gEfiComponentName2ProtocolGuid,
+ &gIpSecComponentName2,
+ &gEfiComponentNameProtocolGuid,
+ &gIpSecComponentName,
+ NULL
+ );
+
+ON_UNINSTALL_IPSEC:
+ gBS->UninstallProtocolInterface (
+ Private->Handle,
+ &gEfiIpSec2ProtocolGuid,
+ &Private->IpSec
+ );
+ON_UNINSTALL_CONFIG:
+ gBS->UninstallProtocolInterface (
+ Private->Handle,
+ &gEfiIpSecConfigProtocolGuid,
+ &Private->IpSecConfig
+ );
+ON_CLOSE_EVENT:
+ gBS->CloseEvent (mIpSecInstance.DisabledEvent);
+ mIpSecInstance.DisabledEvent = NULL;
+ON_FREE_PRIVATE:
+ FreePool (Private);
+ON_EXIT:
+ return Status;
+}
+
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecDxe.inf b/Core/NetworkPkg/IpSecDxe/IpSecDxe.inf
new file mode 100644
index 0000000000..583305b4f8
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecDxe.inf
@@ -0,0 +1,110 @@
+## @file
+# Packet-level security for IP datagram.
+#
+# This driver provides EFI IPsec2 Protocol which is used to abstract the ability
+# to deal with the individual packets sent and received by the host and provide
+# packet-level security for IP datagram. It provides the IP packet protection via
+# ESP and it supports IKEv2 for key negotiation.
+#
+# Copyright (c) 2009 - 2015, 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IpSecDxe
+ FILE_GUID = EE8367C0-A1D6-4565-8F89-EF628547B722
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = IpSecDriverEntryPoint
+ MODULE_UNI_FILE = IpSecDxe.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ IpSecConfigImpl.c
+ IpSecConfigImpl.h
+ IpSecCryptIo.h
+ IpSecCryptIo.c
+ IpSecDebug.h
+ ComponentName.c
+ IkeCommon.h
+ IpSecImpl.c
+ IkeService.c
+ Ike.h
+ IkePacket.h
+ IkePacket.c
+ IpSecDebug.c
+ IpSecMain.c
+ IpSecDriver.c
+ IkeCommon.c
+ IetfConstants.c
+ IpSecImpl.h
+ IkeService.h
+ Ikev2/Ikev2.h
+ Ikev2/Payload.h
+ Ikev2/Utility.h
+ Ikev2/Utility.c
+ Ikev2/Sa.c
+ Ikev2/ChildSa.c
+ Ikev2/Info.c
+ Ikev2/Payload.c
+ Ikev2/Exchange.c
+
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ NetworkPkg/NetworkPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ BaseCryptLib
+ DpcLib
+ UdpIoLib
+ NetLib
+ PcdLib
+
+[Protocols]
+ gEfiIp4Config2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUdp4ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUdp4ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUdp6ServiceBindingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUdp6ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIpSecConfigProtocolGuid ## PRODUCES
+ gEfiIpSec2ProtocolGuid ## PRODUCES
+
+[Pcd]
+ gEfiNetworkPkgTokenSpaceGuid.PcdIpsecCertificateEnabled ## SOMETIMES_CONSUMES
+ gEfiNetworkPkgTokenSpaceGuid.PcdIpsecUefiCaFile ## SOMETIMES_CONSUMES
+ gEfiNetworkPkgTokenSpaceGuid.PcdIpsecUefiCaFileSize ## SOMETIMES_CONSUMES
+ gEfiNetworkPkgTokenSpaceGuid.PcdIpsecUefiCertificate ## SOMETIMES_CONSUMES
+ gEfiNetworkPkgTokenSpaceGuid.PcdIpsecUefiCertificateSize ## SOMETIMES_CONSUMES
+ gEfiNetworkPkgTokenSpaceGuid.PcdIpsecUefiCertificateKey ## SOMETIMES_CONSUMES
+ gEfiNetworkPkgTokenSpaceGuid.PcdIpsecUefiCertificateKeySize ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IpSecDxeExtra.uni
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecDxe.uni b/Core/NetworkPkg/IpSecDxe/IpSecDxe.uni
new file mode 100644
index 0000000000..b3e5673d6f
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecDxe.uni
Binary files differ
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecDxeExtra.uni b/Core/NetworkPkg/IpSecDxe/IpSecDxeExtra.uni
new file mode 100644
index 0000000000..864b7f8f97
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecDxeExtra.uni
Binary files differ
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecImpl.c b/Core/NetworkPkg/IpSecDxe/IpSecImpl.c
new file mode 100644
index 0000000000..00f8ed1cb6
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecImpl.c
@@ -0,0 +1,2184 @@
+/** @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 accroding 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;
+}
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecImpl.h b/Core/NetworkPkg/IpSecDxe/IpSecImpl.h
new file mode 100644
index 0000000000..89597bdc80
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecImpl.h
@@ -0,0 +1,390 @@
+/** @file
+ The definitions related to IPsec protocol implementation.
+
+ Copyright (c) 2009 - 2011, 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.
+
+**/
+
+#ifndef _IP_SEC_IMPL_H_
+#define _IP_SEC_IMPL_H_
+
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Library/NetLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/IpSec.h>
+#include <Protocol/IpSecConfig.h>
+#include <Protocol/Dpc.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+
+typedef struct _IPSEC_PRIVATE_DATA IPSEC_PRIVATE_DATA;
+typedef struct _IPSEC_SPD_ENTRY IPSEC_SPD_ENTRY;
+typedef struct _IPSEC_PAD_ENTRY IPSEC_PAD_ENTRY;
+typedef struct _IPSEC_SPD_DATA IPSEC_SPD_DATA;
+
+#define IPSEC_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I', 'P', 'S', 'E')
+
+#define IPSEC_PRIVATE_DATA_FROM_IPSEC(a) CR (a, IPSEC_PRIVATE_DATA, IpSec, IPSEC_PRIVATE_DATA_SIGNATURE)
+#define IPSEC_PRIVATE_DATA_FROM_UDP4LIST(a) CR (a, IPSEC_PRIVATE_DATA, Udp4List, IPSEC_PRIVATE_DATA_SIGNATURE)
+#define IPSEC_PRIVATE_DATA_FROM_UDP6LIST(a) CR (a, IPSEC_PRIVATE_DATA, Udp6List, IPSEC_PRIVATE_DATA_SIGNATURE)
+#define IPSEC_UDP_SERVICE_FROM_LIST(a) BASE_CR (a, IKE_UDP_SERVICE, List)
+#define IPSEC_SPD_ENTRY_FROM_LIST(a) BASE_CR (a, IPSEC_SPD_ENTRY, List)
+#define IPSEC_SAD_ENTRY_FROM_LIST(a) BASE_CR (a, IPSEC_SAD_ENTRY, List)
+#define IPSEC_PAD_ENTRY_FROM_LIST(a) BASE_CR (a, IPSEC_PAD_ENTRY, List)
+#define IPSEC_SAD_ENTRY_FROM_SPD(a) BASE_CR (a, IPSEC_SAD_ENTRY, BySpd)
+
+#define IPSEC_STATUS_DISABLED 0
+#define IPSEC_STATUS_ENABLED 1
+#define IPSEC_ESP_PROTOCOL 50
+#define IPSEC_AH_PROTOCOL 51
+#define IPSEC_DEFAULT_VARIABLE_SIZE 0x100
+
+//
+// Internal Structure Definition
+//
+#pragma pack(1)
+typedef struct _EFI_AH_HEADER {
+ UINT8 NextHeader;
+ UINT8 PayloadLen;
+ UINT16 Reserved;
+ UINT32 Spi;
+ UINT32 SequenceNumber;
+} EFI_AH_HEADER;
+
+typedef struct _EFI_ESP_HEADER {
+ UINT32 Spi;
+ UINT32 SequenceNumber;
+} EFI_ESP_HEADER;
+
+typedef struct _EFI_ESP_TAIL {
+ UINT8 PaddingLength;
+ UINT8 NextHeader;
+} EFI_ESP_TAIL;
+#pragma pack()
+
+struct _IPSEC_SPD_DATA {
+ CHAR16 Name[100];
+ UINT32 PackageFlag;
+ EFI_IPSEC_TRAFFIC_DIR TrafficDirection;
+ EFI_IPSEC_ACTION Action;
+ EFI_IPSEC_PROCESS_POLICY *ProcessingPolicy;
+ LIST_ENTRY Sas;
+};
+
+struct _IPSEC_SPD_ENTRY {
+ EFI_IPSEC_SPD_SELECTOR *Selector;
+ IPSEC_SPD_DATA *Data;
+ LIST_ENTRY List;
+};
+
+typedef struct _IPSEC_SAD_DATA {
+ EFI_IPSEC_MODE Mode;
+ UINT64 SequenceNumber;
+ UINT8 AntiReplayWindowSize;
+ UINT64 AntiReplayBitmap[4]; // bitmap for received packet
+ EFI_IPSEC_ALGO_INFO AlgoInfo;
+ EFI_IPSEC_SA_LIFETIME SaLifetime;
+ UINT32 PathMTU;
+ IPSEC_SPD_ENTRY *SpdEntry;
+ EFI_IPSEC_SPD_SELECTOR *SpdSelector;
+ BOOLEAN ESNEnabled; // Extended (64-bit) SN enabled
+ BOOLEAN ManualSet;
+ EFI_IP_ADDRESS TunnelDestAddress;
+ EFI_IP_ADDRESS TunnelSourceAddress;
+} IPSEC_SAD_DATA;
+
+typedef struct _IPSEC_SAD_ENTRY {
+ EFI_IPSEC_SA_ID *Id;
+ IPSEC_SAD_DATA *Data;
+ LIST_ENTRY List;
+ LIST_ENTRY BySpd; // Linked on IPSEC_SPD_DATA.Sas
+} IPSEC_SAD_ENTRY;
+
+struct _IPSEC_PAD_ENTRY {
+ EFI_IPSEC_PAD_ID *Id;
+ EFI_IPSEC_PAD_DATA *Data;
+ LIST_ENTRY List;
+};
+
+typedef struct _IPSEC_RECYCLE_CONTEXT {
+ EFI_IPSEC_FRAGMENT_DATA *FragmentTable;
+ UINT8 *PayloadBuffer;
+} IPSEC_RECYCLE_CONTEXT;
+
+//
+// Struct used to store the Hash and its data.
+//
+typedef struct {
+ UINTN DataSize;
+ UINT8 *Data;
+} HASH_DATA_FRAGMENT;
+
+struct _IPSEC_PRIVATE_DATA {
+ UINT32 Signature;
+ EFI_HANDLE Handle; // Virtual handle to install private prtocol
+ EFI_HANDLE ImageHandle;
+ EFI_IPSEC2_PROTOCOL IpSec;
+ EFI_IPSEC_CONFIG_PROTOCOL IpSecConfig;
+ BOOLEAN SetBySelf;
+ LIST_ENTRY Udp4List;
+ UINTN Udp4Num;
+ LIST_ENTRY Udp6List;
+ UINTN Udp6Num;
+ LIST_ENTRY Ikev1SessionList;
+ LIST_ENTRY Ikev1EstablishedList;
+ LIST_ENTRY Ikev2SessionList;
+ LIST_ENTRY Ikev2EstablishedList;
+ BOOLEAN IsIPsecDisabling;
+};
+
+/**
+ 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
+ );
+
+
+/**
+ 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
+ );
+
+/**
+ Check if the IP Address in the address range of AddressInfos specified.
+
+ @param[in] IpVersion The IP version.
+ @param[in] IpAddr Points 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
+ );
+
+/**
+ Find a PAD entry according to remote IP address.
+
+ @param[in] IpVersion The version of IP.
+ @param[in] IpAddr Point to remote IP address.
+
+ @return The pointer of related PAD entry.
+
+**/
+IPSEC_PAD_ENTRY *
+IpSecLookupPadEntry (
+ IN UINT8 IpVersion,
+ IN EFI_IP_ADDRESS *IpAddr
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ );
+
+/**
+ 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
+ )
+;
+
+/**
+ Handles IPsec packet processing for inbound and outbound IP packets.
+
+ The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet.
+ The behavior is that it can perform one of the following actions:
+ bypass the packet, discard the packet, or protect the packet.
+
+ @param[in] This Pointer to the EFI_IPSEC2_PROTOCOL instance.
+ @param[in] NicHandle Instance of the network interface.
+ @param[in] IpVersion IPV4 or IPV6.
+ @param[in, out] IpHead Pointer to the IP Header.
+ @param[in, out] LastHead The protocol of the next layer to be processed by IPsec.
+ @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.
+ @param[in, out] FragmentCount Number of fragments.
+ @param[in] TrafficDirection Traffic direction.
+ @param[out] RecycleSignal Event for recycling of resources.
+
+ @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same.
+ @retval EFI_SUCCESS The packet was protected.
+ @retval EFI_ACCESS_DENIED The packet was discarded.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecProcess (
+ IN EFI_IPSEC2_PROTOCOL *This,
+ IN EFI_HANDLE NicHandle,
+ 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 EFI_IPSEC_TRAFFIC_DIR TrafficDirection,
+ OUT EFI_EVENT *RecycleSignal
+ );
+
+extern EFI_DPC_PROTOCOL *mDpc;
+extern EFI_IPSEC2_PROTOCOL mIpSecInstance;
+
+extern EFI_COMPONENT_NAME2_PROTOCOL gIpSecComponentName2;
+extern EFI_COMPONENT_NAME_PROTOCOL gIpSecComponentName;
+
+
+#endif
diff --git a/Core/NetworkPkg/IpSecDxe/IpSecMain.c b/Core/NetworkPkg/IpSecDxe/IpSecMain.c
new file mode 100644
index 0000000000..a2fefa70d7
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/IpSecMain.c
@@ -0,0 +1,242 @@
+/** @file
+ The mian interface of IPsec Protocol.
+
+ Copyright (c) 2009 - 2011, 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 "IpSecConfigImpl.h"
+#include "IpSecImpl.h"
+
+EFI_IPSEC2_PROTOCOL mIpSecInstance = { IpSecProcess, NULL, TRUE };
+
+/**
+ Handles IPsec packet processing for inbound and outbound IP packets.
+
+ The EFI_IPSEC_PROCESS process routine handles each inbound or outbound packet.
+ The behavior is that it can perform one of the following actions:
+ bypass the packet, discard the packet, or protect the packet.
+
+ @param[in] This Pointer to the EFI_IPSEC2_PROTOCOL instance.
+ @param[in] NicHandle Instance of the network interface.
+ @param[in] IpVersion IPV4 or IPV6.
+ @param[in, out] IpHead Pointer to the IP Header.
+ @param[in, out] LastHead The protocol of the next layer to be processed by IPsec.
+ @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.
+ @param[in, out] FragmentCount Number of fragments.
+ @param[in] TrafficDirection Traffic direction.
+ @param[out] RecycleSignal Event for recycling of resources.
+
+ @retval EFI_SUCCESS The packet was bypassed and all buffers remain the same.
+ @retval EFI_SUCCESS The packet was protected.
+ @retval EFI_ACCESS_DENIED The packet was discarded.
+
+**/
+EFI_STATUS
+EFIAPI
+IpSecProcess (
+ IN EFI_IPSEC2_PROTOCOL *This,
+ IN EFI_HANDLE NicHandle,
+ 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 EFI_IPSEC_TRAFFIC_DIR TrafficDirection,
+ OUT EFI_EVENT *RecycleSignal
+ )
+{
+ IPSEC_PRIVATE_DATA *Private;
+ IPSEC_SPD_ENTRY *SpdEntry;
+ EFI_IPSEC_SPD_SELECTOR *SpdSelector;
+ IPSEC_SAD_ENTRY *SadEntry;
+ LIST_ENTRY *SpdList;
+ LIST_ENTRY *Entry;
+ EFI_IPSEC_ACTION Action;
+ EFI_STATUS Status;
+ UINT8 *IpPayload;
+ UINT8 OldLastHead;
+ BOOLEAN IsOutbound;
+
+ if (OptionsBuffer == NULL ||
+ OptionsLength == NULL ||
+ FragmentTable == NULL ||
+ FragmentCount == NULL
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Private = IPSEC_PRIVATE_DATA_FROM_IPSEC (This);
+ IpPayload = (*FragmentTable)[0].FragmentBuffer;
+ IsOutbound = (BOOLEAN) ((TrafficDirection == EfiIPsecOutBound) ? TRUE : FALSE);
+ OldLastHead = *LastHead;
+ *RecycleSignal = NULL;
+ SpdList = &mConfigData[IPsecConfigDataTypeSpd];
+
+ if (!IsOutbound) {
+ //
+ // For inbound traffic, process the ipsec header of the packet.
+ //
+ Status = IpSecProtectInboundPacket (
+ IpVersion,
+ IpHead,
+ LastHead,
+ OptionsBuffer,
+ OptionsLength,
+ FragmentTable,
+ FragmentCount,
+ &SpdSelector,
+ RecycleSignal
+ );
+
+ if (Status == EFI_ACCESS_DENIED || Status == EFI_OUT_OF_RESOURCES) {
+ //
+ // The packet is denied to access.
+ //
+ goto ON_EXIT;
+ }
+
+ if (Status == EFI_SUCCESS) {
+
+ //
+ // Check the spd entry if the packet is accessible.
+ //
+ if (SpdSelector == NULL) {
+ Status = EFI_ACCESS_DENIED;
+ goto ON_EXIT;
+ }
+
+ Status = EFI_ACCESS_DENIED;
+ NET_LIST_FOR_EACH (Entry, SpdList) {
+ SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
+ if (IsSubSpdSelector (
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdSelector,
+ (EFI_IPSEC_CONFIG_SELECTOR *) SpdEntry->Selector
+ )) {
+ Status = EFI_SUCCESS;
+ }
+ }
+ goto ON_EXIT;
+ }
+ }
+
+ Status = EFI_ACCESS_DENIED;
+
+ NET_LIST_FOR_EACH (Entry, SpdList) {
+ //
+ // For outbound and non-ipsec Inbound traffic: check the spd entry.
+ //
+ SpdEntry = IPSEC_SPD_ENTRY_FROM_LIST (Entry);
+
+ if (EFI_ERROR (IpSecLookupSpdEntry (
+ SpdEntry,
+ IpVersion,
+ IpHead,
+ IpPayload,
+ OldLastHead,
+ IsOutbound,
+ &Action
+ ))) {
+ //
+ // If the related SPD not find
+ //
+ continue;
+ }
+
+ switch (Action) {
+
+ case EfiIPsecActionProtect:
+
+ if (IsOutbound) {
+ //
+ // For outbound traffic, lookup the sad entry.
+ //
+ Status = IpSecLookupSadEntry (
+ Private,
+ NicHandle,
+ IpVersion,
+ IpHead,
+ IpPayload,
+ OldLastHead,
+ SpdEntry,
+ &SadEntry
+ );
+
+ if (SadEntry != NULL) {
+ //
+ // Process the packet by the found sad entry.
+ //
+ Status = IpSecProtectOutboundPacket (
+ IpVersion,
+ IpHead,
+ LastHead,
+ OptionsBuffer,
+ OptionsLength,
+ FragmentTable,
+ FragmentCount,
+ SadEntry,
+ RecycleSignal
+ );
+
+ } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {
+ //
+ // TODO: if no need return not ready to upper layer, change here.
+ //
+ Status = EFI_SUCCESS;
+ }
+ } else if (OldLastHead == IP6_ICMP && *IpPayload != ICMP_V6_ECHO_REQUEST) {
+ //
+ // For inbound icmpv6 traffic except ping request, accept the packet
+ // although no sad entry associated with protect spd entry.
+ //
+ Status = IpSecLookupSadEntry (
+ Private,
+ NicHandle,
+ IpVersion,
+ IpHead,
+ IpPayload,
+ OldLastHead,
+ SpdEntry,
+ &SadEntry
+ );
+ if (SadEntry == NULL) {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ goto ON_EXIT;
+
+ case EfiIPsecActionBypass:
+ Status = EFI_SUCCESS;
+ goto ON_EXIT;
+
+ case EfiIPsecActionDiscard:
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // If don't find the related SPD entry, return the EFI_ACCESS_DENIED and discard it.
+ // But it the packet is NS/NA, it should be by passed even not find the related SPD entry.
+ //
+ if (OldLastHead == IP6_ICMP &&
+ (*IpPayload == ICMP_V6_NEIGHBOR_SOLICIT || *IpPayload == ICMP_V6_NEIGHBOR_ADVERTISE)
+ ){
+ Status = EFI_SUCCESS;
+ }
+
+ON_EXIT:
+ return Status;
+}
+