Add IPsec/Ikev2 support.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11219 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
401
NetworkPkg/IpSecDxe/Ikev2/Info.c
Normal file
401
NetworkPkg/IpSecDxe/Ikev2/Info.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/** @file
|
||||
The Implementations for Information Exchange.
|
||||
|
||||
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 "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 ();
|
||||
ASSERT (IkePacket != NULL);
|
||||
|
||||
//
|
||||
// Fill IkePacket Header.
|
||||
//
|
||||
IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_INFO;
|
||||
IkePacket->Header->Version = (UINT8) (2 << 4);
|
||||
|
||||
if (Context != NULL) {
|
||||
InfoContext = (IKEV2_INFO_EXCHANGE_CONTEXT *) Context;
|
||||
}
|
||||
|
||||
//
|
||||
// For Liveness Check
|
||||
//
|
||||
if (InfoContext != NULL &&
|
||||
(InfoContext->InfoType == Ikev2InfoLiveCheck || InfoContext->InfoType == Ikev2InfoNotify)
|
||||
) {
|
||||
IkePacket->Header->MessageId = InfoContext->MessageId;
|
||||
IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
|
||||
IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
|
||||
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NONE;
|
||||
IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
|
||||
//
|
||||
// TODO: add Notify Payload for Notification Information.
|
||||
//
|
||||
return IkePacket;
|
||||
}
|
||||
|
||||
//
|
||||
// For delete SAs
|
||||
//
|
||||
if (IkeSaSession->SessionCommon.IkeSessionType == IkeSessionTypeIkeSa) {
|
||||
|
||||
IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
|
||||
IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
|
||||
|
||||
//
|
||||
// If the information message is response message,the MessageId should
|
||||
// be same as the request MessageId which passed through the Context.
|
||||
//
|
||||
if (InfoContext != NULL) {
|
||||
IkePacket->Header->MessageId = InfoContext->MessageId;
|
||||
} else {
|
||||
IkePacket->Header->MessageId = IkeSaSession->MessageId;
|
||||
Ikev2SaSessionIncreaseMessageId (IkeSaSession);
|
||||
}
|
||||
//
|
||||
// If the state is on deleting generate a Delete Payload for it.
|
||||
//
|
||||
if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting ) {
|
||||
IkePayload = Ikev2GenerateDeletePayload (
|
||||
IkeSaSession,
|
||||
IKEV2_PAYLOAD_TYPE_NONE,
|
||||
0,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
if (IkePayload == NULL) {
|
||||
goto ERROR_EXIT;
|
||||
}
|
||||
//
|
||||
// Fill the next payload in IkePacket's Header.
|
||||
//
|
||||
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_DELETE;
|
||||
IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
|
||||
IkePacket->Private = IkeSaSession->SessionCommon.Private;
|
||||
IkePacket->Spi = 0;
|
||||
IkePacket->IsDeleteInfo = TRUE;
|
||||
|
||||
} else if (Context != NULL) {
|
||||
//
|
||||
// TODO: If contest is not NULL Generate a Notify Payload.
|
||||
//
|
||||
} else {
|
||||
//
|
||||
// The input parameter is not correct.
|
||||
//
|
||||
goto ERROR_EXIT;
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// Delete the Child SA Information Exchagne
|
||||
//
|
||||
ChildSaSession = (IKEV2_CHILD_SA_SESSION *) SaSession;
|
||||
IkeSaSession = ChildSaSession->IkeSaSession;
|
||||
IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie;
|
||||
IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie;
|
||||
|
||||
//
|
||||
// If the information message is response message,the MessageId should
|
||||
// be same as the request MessageId which passed through the Context.
|
||||
//
|
||||
if (InfoContext != NULL && InfoContext->MessageId != 0) {
|
||||
IkePacket->Header->MessageId = InfoContext->MessageId;
|
||||
} else {
|
||||
IkePacket->Header->MessageId = ChildSaSession->IkeSaSession->MessageId;
|
||||
Ikev2SaSessionIncreaseMessageId (IkeSaSession);
|
||||
}
|
||||
|
||||
IkePayload = Ikev2GenerateDeletePayload (
|
||||
ChildSaSession->IkeSaSession,
|
||||
IKEV2_PAYLOAD_TYPE_DELETE,
|
||||
4,
|
||||
1,
|
||||
(UINT8 *)&ChildSaSession->LocalPeerSpi
|
||||
);
|
||||
if (IkePayload == NULL) {
|
||||
goto ERROR_EXIT;
|
||||
}
|
||||
//
|
||||
// Fill the Next Payload in IkePacket's Header.
|
||||
//
|
||||
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_DELETE;
|
||||
IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
|
||||
|
||||
IkePacket->Private = IkeSaSession->SessionCommon.Private;
|
||||
IkePacket->Spi = ChildSaSession->LocalPeerSpi;
|
||||
IkePacket->IsDeleteInfo = TRUE;
|
||||
|
||||
if (!ChildSaSession->SessionCommon.IsInitiator) {
|
||||
//
|
||||
// If responder, use the MessageId fromt the initiator.
|
||||
//
|
||||
IkePacket->Header->MessageId = ChildSaSession->MessageId;
|
||||
}
|
||||
|
||||
//
|
||||
// Change the IsOnDeleting Flag
|
||||
//
|
||||
ChildSaSession->SessionCommon.IsOnDeleting = TRUE;
|
||||
}
|
||||
|
||||
if (InfoContext == NULL) {
|
||||
IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
|
||||
} else {
|
||||
IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
|
||||
}
|
||||
return IkePacket;
|
||||
|
||||
ERROR_EXIT:
|
||||
if (IkePacket != NULL) {
|
||||
FreePool (IkePacket);
|
||||
}
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Parse the Info Exchange.
|
||||
|
||||
@param[in] SaSession Pointer to IKEV2_SA_SESSION.
|
||||
@param[in] IkePacket Pointer to IkePacket related to the Information Exchange.
|
||||
|
||||
@retval EFI_SUCCESS The operation finised successed.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
Ikev2InfoParser (
|
||||
IN UINT8 *SaSession,
|
||||
IN IKE_PACKET *IkePacket
|
||||
)
|
||||
{
|
||||
IKEV2_CHILD_SA_SESSION *ChildSaSession;
|
||||
IKEV2_SA_SESSION *IkeSaSession;
|
||||
IKE_PAYLOAD *NotifyPayload;
|
||||
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;
|
||||
|
||||
NotifyPayload = NULL;
|
||||
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
|
||||
};
|
Reference in New Issue
Block a user