mirror of https://github.com/acidanthera/audk.git
804 lines
24 KiB
C
804 lines
24 KiB
C
|
/** @file
|
||
|
The general interfaces of the IKEv2.
|
||
|
|
||
|
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
|
||
|
|
||
|
This program and the accompanying materials
|
||
|
are licensed and made available under the terms and conditions of the BSD License
|
||
|
which accompanies this distribution. The full text of the license may be found at
|
||
|
http://opensource.org/licenses/bsd-license.php.
|
||
|
|
||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include "Utility.h"
|
||
|
#include "IpSecDebug.h"
|
||
|
#include "IkeService.h"
|
||
|
#include "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) {
|
||
|
|
||
|
//
|
||
|
// The IKE SA Session should be initiator if it triggers the deleting.
|
||
|
//
|
||
|
Ikev2SaSession->SessionCommon.IsInitiator = TRUE;
|
||
|
|
||
|
//
|
||
|
// 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
|
||
|
//
|
||
|
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
|
||
|
//
|
||
|
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.
|
||
|
//
|
||
|
Status = Ikev2ValidateHeader (IkeSaSession, IkePacket->Header);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// 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);
|
||
|
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);
|
||
|
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
|
||
|
};
|
||
|
|