summaryrefslogtreecommitdiff
path: root/Core/NetworkPkg/IpSecDxe/Ikev2
diff options
context:
space:
mode:
Diffstat (limited to 'Core/NetworkPkg/IpSecDxe/Ikev2')
-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.c409
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Payload.c3353
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Payload.h443
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Sa.c2261
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Utility.c2802
-rw-r--r--Core/NetworkPkg/IpSecDxe/Ikev2/Utility.h1134
9 files changed, 11668 insertions, 0 deletions
diff --git a/Core/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c b/Core/NetworkPkg/IpSecDxe/Ikev2/ChildSa.c
new file mode 100644
index 0000000000..eaccad2086
--- /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_INIT;
+ }
+
+ } 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_INIT;
+ }
+ }
+
+ if (MessageId != NULL) {
+ 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..5609964fa4
--- /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..0d2b290817
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Info.c
@@ -0,0 +1,409 @@
+/** @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;
+ }
+
+ if (IkeSaSession->SessionCommon.IsInitiator) {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT ;
+ }
+ } 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 (ChildSaSession->SessionCommon.IsInitiator) {
+ IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT ;
+ }
+ }
+
+ if (InfoContext != NULL) {
+ 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..237743b1b1
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Payload.c
@@ -0,0 +1,3353 @@
+/** @file
+ The implementation of Payloads Creation.
+
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2010 - 2017, 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];
+ 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
+ //
+ 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;
+ }
+
+ //
+ // 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 (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
+ 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
+ )
+{
+ 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 == ((UINT32)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..7a85792ed7
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Payload.h
@@ -0,0 +1,443 @@
+/** @file
+ The Definitions related to IKEv2 payload.
+
+ 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_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 (1 octet) for IKEv2, defined in RFC 4306 section 3.1
+//
+// I(nitiator) (bit 3 of Flags, 0x08) - This bit MUST be set in messages sent by the
+// original initiator of the IKE_SA
+//
+// R(esponse) (bit 5 of Flags, 0x20) - This bit indicates that this message is a response to
+// a message containing the same message ID.
+//
+#define IKE_HEADER_FLAGS_INIT 0x08
+#define IKE_HEADER_FLAGS_RESPOND 0x20
+
+//
+// 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..f9421ed4e8
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Sa.c
@@ -0,0 +1,2261 @@
+/** @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 && !EFI_ERROR(Ikev2ParserNotifyCookiePayload (NotifyPayload, IkeSaSession))) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ 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..2ca7f3c63c
--- /dev/null
+++ b/Core/NetworkPkg/IpSecDxe/Ikev2/Utility.c
@@ -0,0 +1,2802 @@
+/** @file
+ The Common operations used by IKE Exchange Process.
+
+ (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+ Copyright (c) 2010 - 2017, 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;
+
+ //
+ // Generate an new SPI.
+ //
+ Status = IkeGenerateSpi (IkeSaSession, &(ChildSaSession->LocalPeerSpi));
+ if (EFI_ERROR (Status)) {
+ FreePool (ChildSaSession);
+ return NULL;
+ }
+
+ 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.
+ If the authentication algorithm given by HashAlgId
+ cannot be found.
+ @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);
+ if (AuthKeyLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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
+