summaryrefslogtreecommitdiffstats
path: root/NetworkPkg/IpSecDxe/Ikev2/Sa.c
diff options
context:
space:
mode:
authorqianouyang <qianouyang@6f19259b-4bc3-4df7-8a09-765794883524>2010-12-31 10:43:54 +0000
committerqianouyang <qianouyang@6f19259b-4bc3-4df7-8a09-765794883524>2010-12-31 10:43:54 +0000
commit9166f840d2a70b924b0ff66528f056515443e4e8 (patch)
treeba1f372f4e1165be3c06dd19758d151714ad77ca /NetworkPkg/IpSecDxe/Ikev2/Sa.c
parent4a8266f570ef411c21d7991f129e29aac817aa96 (diff)
downloadedk2-9166f840d2a70b924b0ff66528f056515443e4e8.tar.gz
edk2-9166f840d2a70b924b0ff66528f056515443e4e8.tar.bz2
edk2-9166f840d2a70b924b0ff66528f056515443e4e8.zip
Add IPsec/Ikev2 support.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11219 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'NetworkPkg/IpSecDxe/Ikev2/Sa.c')
-rw-r--r--NetworkPkg/IpSecDxe/Ikev2/Sa.c1949
1 files changed, 1949 insertions, 0 deletions
diff --git a/NetworkPkg/IpSecDxe/Ikev2/Sa.c b/NetworkPkg/IpSecDxe/Ikev2/Sa.c
new file mode 100644
index 0000000000..7265ca8c6c
--- /dev/null
+++ b/NetworkPkg/IpSecDxe/Ikev2/Sa.c
@@ -0,0 +1,1949 @@
+/** @file
+ The operations for IKEv2 SA.
+
+ 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 "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 ();
+ ASSERT (IkePacket != NULL);
+
+ //
+ // 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);
+ ASSERT (IkeSaSession->NiBlock != NULL);
+ }
+
+ 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);
+ ASSERT (NonceBuffer != NULL);
+ 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_EFI_ERROR (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));
+
+ CpPayload = NULL;
+ NotifyPayload = NULL;
+
+ //
+ // 1. Allocate IKE Packet
+ //
+ IkePacket= IkePacketAlloc ();
+ ASSERT (IkePacket != 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
+ );
+
+ //
+ // 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
+ );
+ }
+ }
+
+ //
+ // 4. Generate SA Payload according to the SA Data in ChildSaSession
+ //
+ SaPayload = Ikev2GenerateSaPayload (
+ ChildSaSession->SaData,
+ IKEV2_PAYLOAD_TYPE_TS_INIT,
+ IkeSessionTypeChildSa
+ );
+
+ 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
+ );
+ } else {
+ //
+ // Generate Tsr for Tunnel mode.
+ //
+ TsiPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_TS_RSP,
+ TRUE
+ );
+ TsrPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ FALSE
+ );
+ }
+
+ 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;
+}
+
+/**
+ 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;
+ Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);
+ }
+ } 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.
+ //
+ Ikev2GenerateChildSaKeys (ChildSaSession, NULL);
+ 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 (PcdIpsecCertiifcateEnabled)) {
+ 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(UefiCaFile),
+ PcdGet32(UefiCaFileSize),
+ 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 (PcdIpsecCertiifcateEnabled)) {
+ 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 (PcdIpsecCertiifcateEnabled)) {
+ return NULL;
+ }
+
+ IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
+ ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
+
+ CpPayload = NULL;
+ NotifyPayload = NULL;
+ CertPayload = NULL;
+ CertReqPayload = NULL;
+
+ //
+ // 1. Allocate IKE Packet
+ //
+ IkePacket= IkePacketAlloc ();
+ ASSERT (IkePacket != 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 (UefiCertificate),
+ PcdGet32 (UefiCertificateSize)
+ );
+
+ //
+ // 3. Generate Certificate Payload
+ //
+ CertPayload = Ikev2GenerateCertificatePayload (
+ IkeSaSession,
+ (UINT8)(IkeSaSession->SessionCommon.IsInitiator ? IKEV2_PAYLOAD_TYPE_CERTREQ : IKEV2_PAYLOAD_TYPE_AUTH),
+ (UINT8 *)PcdGetPtr (UefiCertificate),
+ PcdGet32 (UefiCertificateSize),
+ IKEV2_CERT_ENCODEING_X509_CERT_SIGN,
+ FALSE
+ );
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ CertReqPayload = Ikev2GenerateCertificatePayload (
+ IkeSaSession,
+ IKEV2_PAYLOAD_TYPE_AUTH,
+ (UINT8 *)PcdGetPtr (UefiCertificate),
+ PcdGet32 (UefiCertificateSize),
+ IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT,
+ TRUE
+ );
+ }
+
+ //
+ // 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 (UefiCertificateKey),
+ PcdGet32 (UefiCertificateKeySize),
+ ChildSaSession->IkeSaSession->Pad->Data->AuthData,
+ ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize
+ );
+ } else {
+ AuthPayload = Ikev2CertGenerateAuthPayload (
+ ChildSaSession->IkeSaSession,
+ IdPayload,
+ IKEV2_PAYLOAD_TYPE_CP,
+ FALSE,
+ (UINT8 *)PcdGetPtr (UefiCertificateKey),
+ PcdGet32 (UefiCertificateKeySize),
+ 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
+ );
+ }
+ }
+
+ //
+ // 5. Generate SA Payload according to the Sa Data in ChildSaSession
+ //
+ SaPayload = Ikev2GenerateSaPayload (
+ ChildSaSession->SaData,
+ IKEV2_PAYLOAD_TYPE_TS_INIT,
+ IkeSessionTypeChildSa
+ );
+
+ 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
+ );
+ } else {
+ //
+ // Generate Tsr for Tunnel mode.
+ //
+ TsiPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_TS_RSP,
+ TRUE
+ );
+ TsrPayload = Ikev2GenerateTsPayload (
+ ChildSaSession,
+ IKEV2_PAYLOAD_TYPE_NONE,
+ FALSE
+ );
+ }
+
+ 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;
+}
+
+/**
+ 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 *CertReqPayload;
+ IKE_PAYLOAD *VerifiedAuthPayload;
+ LIST_ENTRY *Entry;
+ EFI_STATUS Status;
+
+ if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) {
+ 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;
+ CertReqPayload = 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 (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERTREQ) {
+ CertReqPayload = 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 (UefiCaFile),
+ PcdGet32 (UefiCaFileSize),
+ 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;
+ Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);
+ }
+ } 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.
+ //
+ Ikev2GenerateChildSaKeys (ChildSaSession, NULL);
+ 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));
+ ASSERT (IkeSaSession->IkeKeys != NULL);
+ IkeKeys = IkeSaSession->IkeKeys;
+ IkeKeys->DhBuffer = AllocateZeroPool (sizeof (IKEV2_DH_BUFFER));
+ ASSERT (IkeKeys->DhBuffer != NULL);
+
+ //
+ // 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);
+ ASSERT (IkeKeys->DhBuffer->GxBuffer != NULL);
+
+ //
+ // 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));
+ 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);
+ ASSERT (DhBuffer->GxyBuffer != NULL);
+
+ //
+ // 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));
+ return Status;
+ }
+
+ //
+ // Create GxyBuf.
+ //
+ DhBuffer->GySize = PubKeySize;
+ DhBuffer->GyBuffer = AllocateZeroPool (DhBuffer->GySize);
+ ASSERT (DhBuffer->GyBuffer != NULL);
+ 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;
+ IPSEC_PAD_ENTRY *Pad;
+ 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;
+
+ //
+ // Generate Gxy
+ //
+ Ikev2GenerateSaDhComputeKey (IkeSaSession->IkeKeys->DhBuffer, KePayload);
+
+ Pad = IkeSaSession->Pad;
+
+ //
+ // 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);
+ ASSERT (KeyBuffer != NULL);
+
+ 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);
+
+ //
+ // 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ }
+
+ 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;
+
+ if (KePayload != NULL) {
+ //
+ // Generate Gxy
+ //
+ Ikev2GenerateSaDhComputeKey (ChildSaSession->DhBuffer, KePayload);
+ 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)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ //
+ // 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);
+
+ //
+ // 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)) {
+ FreePool (OutputKey);
+ return Status;
+ }
+
+ //
+ // 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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
+ );
+
+ 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
+ },
+ },
+};