mirror of https://github.com/acidanthera/audk.git
1950 lines
63 KiB
C
1950 lines
63 KiB
C
/** @file
|
|
The operations for IKEv2 SA.
|
|
|
|
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php.
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "Utility.h"
|
|
#include "IpSecDebug.h"
|
|
#include "IkeService.h"
|
|
#include "Ikev2.h"
|
|
|
|
/**
|
|
Generates the DH Key.
|
|
|
|
This generates the DH local public key and store it in the IKEv2 SA Session's GxBuffer.
|
|
|
|
@param[in] IkeSaSession Pointer to related IKE SA Session.
|
|
|
|
@retval EFI_SUCCESS The operation succeeded.
|
|
@retval Others The operation failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2GenerateSaDhPublicKey (
|
|
IN IKEV2_SA_SESSION *IkeSaSession
|
|
);
|
|
|
|
/**
|
|
Generates the IKEv2 SA key for the furthure IKEv2 exchange.
|
|
|
|
@param[in] IkeSaSession Pointer to IKEv2 SA Session.
|
|
@param[in] KePayload Pointer to Key payload used to generate the Key.
|
|
|
|
@retval EFI_UNSUPPORTED If the Algorithm Id is not supported.
|
|
@retval EFI_SUCCESS The operation succeeded.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2GenerateSaKeys (
|
|
IN IKEV2_SA_SESSION *IkeSaSession,
|
|
IN IKE_PAYLOAD *KePayload
|
|
);
|
|
|
|
/**
|
|
Generates the Keys for the furthure IPsec Protocol.
|
|
|
|
@param[in] ChildSaSession Pointer to IKE Child SA Session.
|
|
@param[in] KePayload Pointer to Key payload used to generate the Key.
|
|
|
|
@retval EFI_UNSUPPORTED If one or more Algorithm Id is unsupported.
|
|
@retval EFI_SUCCESS The operation succeeded.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2GenerateChildSaKeys (
|
|
IN IKEV2_CHILD_SA_SESSION *ChildSaSession,
|
|
IN IKE_PAYLOAD *KePayload
|
|
);
|
|
|
|
/**
|
|
Gernerates IKEv2 packet for IKE_SA_INIT exchange.
|
|
|
|
@param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange.
|
|
@param[in] Context Context Data passed by caller.
|
|
|
|
@retval EFI_SUCCESS The IKEv2 packet generation succeeded.
|
|
@retval Others The IKEv2 packet generation failed.
|
|
|
|
**/
|
|
IKE_PACKET *
|
|
Ikev2InitPskGenerator (
|
|
IN UINT8 *SaSession,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
IKE_PACKET *IkePacket;
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
IKE_PAYLOAD *SaPayload;
|
|
IKE_PAYLOAD *KePayload;
|
|
IKE_PAYLOAD *NoncePayload;
|
|
IKE_PAYLOAD *NotifyPayload;
|
|
EFI_STATUS Status;
|
|
|
|
SaPayload = NULL;
|
|
KePayload = NULL;
|
|
NoncePayload = NULL;
|
|
NotifyPayload = NULL;
|
|
|
|
IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
|
|
|
|
//
|
|
// 1. Allocate IKE packet
|
|
//
|
|
IkePacket = IkePacketAlloc ();
|
|
ASSERT (IkePacket != NULL);
|
|
|
|
//
|
|
// 1.a Fill the IkePacket->Hdr
|
|
//
|
|
IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_INIT;
|
|
IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
|
|
IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
|
|
IkePacket->Header->Version = (UINT8) (2 << 4);
|
|
IkePacket->Header->MessageId = 0;
|
|
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
|
|
} else {
|
|
IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
|
|
}
|
|
|
|
//
|
|
// If the NCookie is not NULL, this IKE_SA_INIT packet is resent by the NCookie
|
|
// and the NCookie payload should be the first payload in this packet.
|
|
//
|
|
if (IkeSaSession->NCookie != NULL) {
|
|
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_NOTIFY;
|
|
NotifyPayload = Ikev2GenerateNotifyPayload (
|
|
IPSEC_PROTO_ISAKMP,
|
|
IKEV2_PAYLOAD_TYPE_SA,
|
|
0,
|
|
IKEV2_NOTIFICATION_COOKIE,
|
|
NULL,
|
|
IkeSaSession->NCookie,
|
|
IkeSaSession->NCookieSize
|
|
);
|
|
} else {
|
|
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_SA;
|
|
}
|
|
|
|
//
|
|
// 2. Generate SA Payload according to the SaData & SaParams
|
|
//
|
|
SaPayload = Ikev2GenerateSaPayload (
|
|
IkeSaSession->SaData,
|
|
IKEV2_PAYLOAD_TYPE_KE,
|
|
IkeSessionTypeIkeSa
|
|
);
|
|
|
|
//
|
|
// 3. Generate DH public key.
|
|
// The DhPrivate Key has been generated in Ikev2InitPskParser, if the
|
|
// IkeSaSession is responder. If resending IKE_SA_INIT with Cookie Notify
|
|
// No need to recompute the Public key.
|
|
//
|
|
if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) {
|
|
Status = Ikev2GenerateSaDhPublicKey (IkeSaSession);
|
|
if (EFI_ERROR (Status)) {
|
|
goto CheckError;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 4. Generate KE Payload according to SaParams->DhGroup
|
|
//
|
|
KePayload = Ikev2GenerateKePayload (
|
|
IkeSaSession,
|
|
IKEV2_PAYLOAD_TYPE_NONCE
|
|
);
|
|
|
|
//
|
|
// 5. Generate Nonce Payload
|
|
// If resending IKE_SA_INIT with Cookie Notify paylaod, no need to regenerate
|
|
// the Nonce Payload.
|
|
//
|
|
if ((IkeSaSession->SessionCommon.IsInitiator) && (IkeSaSession->NCookie == NULL)) {
|
|
IkeSaSession->NiBlkSize = IKE_NONCE_SIZE;
|
|
IkeSaSession->NiBlock = IkeGenerateNonce (IKE_NONCE_SIZE);
|
|
ASSERT (IkeSaSession->NiBlock != NULL);
|
|
}
|
|
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
NoncePayload = Ikev2GenerateNoncePayload (
|
|
IkeSaSession->NiBlock,
|
|
IkeSaSession->NiBlkSize,
|
|
IKEV2_PAYLOAD_TYPE_NONE
|
|
);
|
|
} else {
|
|
//
|
|
// The Nonce Payload has been created in Ikev2PskParser if the IkeSaSession is
|
|
// responder.
|
|
//
|
|
NoncePayload = Ikev2GenerateNoncePayload (
|
|
IkeSaSession->NrBlock,
|
|
IkeSaSession->NrBlkSize,
|
|
IKEV2_PAYLOAD_TYPE_NONE
|
|
);
|
|
}
|
|
|
|
if (NotifyPayload != NULL) {
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
|
|
}
|
|
if (SaPayload != NULL) {
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);
|
|
}
|
|
if (KePayload != NULL) {
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, KePayload);
|
|
}
|
|
if (NoncePayload != NULL) {
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, NoncePayload);
|
|
}
|
|
|
|
return IkePacket;
|
|
|
|
CheckError:
|
|
if (IkePacket != NULL) {
|
|
IkePacketFree (IkePacket);
|
|
}
|
|
if (SaPayload != NULL) {
|
|
IkePayloadFree (SaPayload);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Parses the IKEv2 packet for IKE_SA_INIT exchange.
|
|
|
|
@param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange.
|
|
@param[in] IkePacket The received IKE packet to be parsed.
|
|
|
|
@retval EFI_SUCCESS The IKEv2 packet is acceptable and the relative data is
|
|
saved for furthure communication.
|
|
@retval EFI_INVALID_PARAMETER The IKEv2 packet is malformed or the SA proposal is unacceptable.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2InitPskParser (
|
|
IN UINT8 *SaSession,
|
|
IN IKE_PACKET *IkePacket
|
|
)
|
|
{
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
IKE_PAYLOAD *SaPayload;
|
|
IKE_PAYLOAD *KeyPayload;
|
|
IKE_PAYLOAD *IkePayload;
|
|
IKE_PAYLOAD *NoncePayload;
|
|
IKE_PAYLOAD *NotifyPayload;
|
|
UINT8 *NonceBuffer;
|
|
UINTN NonceSize;
|
|
LIST_ENTRY *Entry;
|
|
EFI_STATUS Status;
|
|
|
|
IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
|
|
KeyPayload = NULL;
|
|
SaPayload = NULL;
|
|
NoncePayload = NULL;
|
|
IkePayload = NULL;
|
|
NotifyPayload = NULL;
|
|
|
|
//
|
|
// Iterate payloads to find the SaPayload and KeyPayload.
|
|
//
|
|
NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
|
|
IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {
|
|
SaPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_KE) {
|
|
KeyPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NONCE) {
|
|
NoncePayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NOTIFY) {
|
|
NotifyPayload = IkePayload;
|
|
}
|
|
}
|
|
|
|
//
|
|
// According to RFC 4306 - 2.6. If the responder responds with the COOKIE Notify
|
|
// payload with the cookie data, initiator MUST retry the IKE_SA_INIT with a
|
|
// Notify payload of type COOKIE containing the responder suppplied cookie data
|
|
// as first payload and all other payloads unchanged.
|
|
//
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
if (NotifyPayload != NULL) {
|
|
Status = Ikev2ParserNotifyCookiePayload (NotifyPayload, IkeSaSession);
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
if ((KeyPayload == NULL) || (SaPayload == NULL) || (NoncePayload == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Store NoncePayload for SKEYID computing.
|
|
//
|
|
NonceSize = NoncePayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
|
|
NonceBuffer = (UINT8 *) AllocatePool (NonceSize);
|
|
ASSERT (NonceBuffer != NULL);
|
|
CopyMem (
|
|
NonceBuffer,
|
|
NoncePayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
|
|
NonceSize
|
|
);
|
|
|
|
//
|
|
// Check if IkePacket Header matches the state
|
|
//
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
//
|
|
// 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND
|
|
//
|
|
if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto CheckError;
|
|
}
|
|
|
|
//
|
|
// 2. Parse the SA Payload and Key Payload to find out the cryptographic
|
|
// suite and fill in the Sa paramse into CommonSession->SaParams
|
|
//
|
|
if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto CheckError;
|
|
}
|
|
|
|
//
|
|
// 3. If Initiator, the NoncePayload is Nr_b.
|
|
//
|
|
IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateAuth);
|
|
IkeSaSession->NrBlock = NonceBuffer;
|
|
IkeSaSession->NrBlkSize = NonceSize;
|
|
IkeSaSession->SessionCommon.State = IkeStateAuth;
|
|
IkeSaSession->ResponderCookie = IkePacket->Header->ResponderCookie;
|
|
|
|
//
|
|
// 4. Change the state of IkeSaSession
|
|
//
|
|
IkeSaSession->SessionCommon.State = IkeStateAuth;
|
|
} else {
|
|
//
|
|
// 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT
|
|
//
|
|
if (IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto CheckError;
|
|
}
|
|
|
|
//
|
|
// 2. Parse the SA payload and find out the perfered one
|
|
// and fill in the SA parameters into CommonSession->SaParams and SaData into
|
|
// IkeSaSession for the responder SA payload generation.
|
|
//
|
|
if (!Ikev2SaParseSaPayload (IkeSaSession, SaPayload, IkePacket->Header->Flags)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto CheckError;
|
|
}
|
|
|
|
//
|
|
// 3. Generat Dh Y parivate Key
|
|
//
|
|
Status = Ikev2GenerateSaDhPublicKey (IkeSaSession);
|
|
if (EFI_ERROR (Status)) {
|
|
goto CheckError;
|
|
}
|
|
|
|
//
|
|
// 4. If Responder, the NoncePayload is Ni_b and go to generate Nr_b.
|
|
//
|
|
IkeSaSession->NiBlock = NonceBuffer;
|
|
IkeSaSession->NiBlkSize = NonceSize;
|
|
|
|
//
|
|
// 5. Generate Nr_b
|
|
//
|
|
IkeSaSession->NrBlock = IkeGenerateNonce (IKE_NONCE_SIZE);
|
|
ASSERT_EFI_ERROR (IkeSaSession->NrBlock != NULL);
|
|
IkeSaSession->NrBlkSize = IKE_NONCE_SIZE;
|
|
|
|
//
|
|
// 6. Save the Cookies
|
|
//
|
|
IkeSaSession->InitiatorCookie = IkePacket->Header->InitiatorCookie;
|
|
IkeSaSession->ResponderCookie = IkeGenerateCookie ();
|
|
}
|
|
|
|
if (IkeSaSession->SessionCommon.PreferDhGroup != ((IKEV2_KEY_EXCHANGE *)KeyPayload->PayloadBuf)->DhGroup) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto CheckError;
|
|
}
|
|
//
|
|
// Call Ikev2GenerateSaKeys to create SKEYID, SKEYID_d, SKEYID_a, SKEYID_e.
|
|
//
|
|
Status = Ikev2GenerateSaKeys (IkeSaSession, KeyPayload);
|
|
if (EFI_ERROR(Status)) {
|
|
goto CheckError;
|
|
}
|
|
return EFI_SUCCESS;
|
|
|
|
CheckError:
|
|
if (NonceBuffer != NULL) {
|
|
FreePool (NonceBuffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Generates the IKEv2 packet for IKE_AUTH exchange.
|
|
|
|
@param[in] SaSession Pointer to IKEV2_SA_SESSION.
|
|
@param[in] Context Context data passed by caller.
|
|
|
|
@retval Pointer to IKE Packet to be sent out.
|
|
|
|
**/
|
|
IKE_PACKET *
|
|
Ikev2AuthPskGenerator (
|
|
IN UINT8 *SaSession,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
IKE_PACKET *IkePacket;
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
IKE_PAYLOAD *IdPayload;
|
|
IKE_PAYLOAD *AuthPayload;
|
|
IKE_PAYLOAD *SaPayload;
|
|
IKE_PAYLOAD *TsiPayload;
|
|
IKE_PAYLOAD *TsrPayload;
|
|
IKE_PAYLOAD *NotifyPayload;
|
|
IKE_PAYLOAD *CpPayload;
|
|
IKEV2_CHILD_SA_SESSION *ChildSaSession;
|
|
|
|
|
|
IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
|
|
ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
|
|
|
|
CpPayload = NULL;
|
|
NotifyPayload = NULL;
|
|
|
|
//
|
|
// 1. Allocate IKE Packet
|
|
//
|
|
IkePacket= IkePacketAlloc ();
|
|
ASSERT (IkePacket != NULL);
|
|
|
|
//
|
|
// 1.a Fill the IkePacket Header.
|
|
//
|
|
IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_AUTH;
|
|
IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
|
|
IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
|
|
IkePacket->Header->Version = (UINT8)(2 << 4);
|
|
if (ChildSaSession->SessionCommon.IsInitiator) {
|
|
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_INIT;
|
|
} else {
|
|
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_RSP;
|
|
}
|
|
|
|
//
|
|
// According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should
|
|
// be always number 0 and 1;
|
|
//
|
|
IkePacket->Header->MessageId = 1;
|
|
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
|
|
} else {
|
|
IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
|
|
}
|
|
|
|
//
|
|
// 2. Generate ID Payload according to IP version and address.
|
|
//
|
|
IdPayload = Ikev2GenerateIdPayload (
|
|
&IkeSaSession->SessionCommon,
|
|
IKEV2_PAYLOAD_TYPE_AUTH
|
|
);
|
|
|
|
//
|
|
// 3. Generate Auth Payload
|
|
// If it is tunnel mode, should create the configuration payload after the
|
|
// Auth payload.
|
|
//
|
|
if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
|
|
|
|
AuthPayload = Ikev2PskGenerateAuthPayload (
|
|
ChildSaSession->IkeSaSession,
|
|
IdPayload,
|
|
IKEV2_PAYLOAD_TYPE_SA,
|
|
FALSE
|
|
);
|
|
} else {
|
|
AuthPayload = Ikev2PskGenerateAuthPayload (
|
|
ChildSaSession->IkeSaSession,
|
|
IdPayload,
|
|
IKEV2_PAYLOAD_TYPE_CP,
|
|
FALSE
|
|
);
|
|
if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) {
|
|
CpPayload = Ikev2GenerateCpPayload (
|
|
ChildSaSession->IkeSaSession,
|
|
IKEV2_PAYLOAD_TYPE_SA,
|
|
IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS
|
|
);
|
|
} else {
|
|
CpPayload = Ikev2GenerateCpPayload (
|
|
ChildSaSession->IkeSaSession,
|
|
IKEV2_PAYLOAD_TYPE_SA,
|
|
IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 4. Generate SA Payload according to the SA Data in ChildSaSession
|
|
//
|
|
SaPayload = Ikev2GenerateSaPayload (
|
|
ChildSaSession->SaData,
|
|
IKEV2_PAYLOAD_TYPE_TS_INIT,
|
|
IkeSessionTypeChildSa
|
|
);
|
|
|
|
if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
|
|
//
|
|
// Generate Tsi and Tsr.
|
|
//
|
|
TsiPayload = Ikev2GenerateTsPayload (
|
|
ChildSaSession,
|
|
IKEV2_PAYLOAD_TYPE_TS_RSP,
|
|
FALSE
|
|
);
|
|
|
|
TsrPayload = Ikev2GenerateTsPayload (
|
|
ChildSaSession,
|
|
IKEV2_PAYLOAD_TYPE_NOTIFY,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Generate Notify Payload. If transport mode, there should have Notify
|
|
// payload with TRANSPORT_MODE notification.
|
|
//
|
|
NotifyPayload = Ikev2GenerateNotifyPayload (
|
|
0,
|
|
IKEV2_PAYLOAD_TYPE_NONE,
|
|
0,
|
|
IKEV2_NOTIFICATION_USE_TRANSPORT_MODE,
|
|
NULL,
|
|
NULL,
|
|
0
|
|
);
|
|
} else {
|
|
//
|
|
// Generate Tsr for Tunnel mode.
|
|
//
|
|
TsiPayload = Ikev2GenerateTsPayload (
|
|
ChildSaSession,
|
|
IKEV2_PAYLOAD_TYPE_TS_RSP,
|
|
TRUE
|
|
);
|
|
TsrPayload = Ikev2GenerateTsPayload (
|
|
ChildSaSession,
|
|
IKEV2_PAYLOAD_TYPE_NONE,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload);
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload);
|
|
if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload);
|
|
}
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload);
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload);
|
|
if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
|
|
}
|
|
|
|
return IkePacket;
|
|
}
|
|
|
|
/**
|
|
Parses IKE_AUTH packet.
|
|
|
|
@param[in] SaSession Pointer to the IKE_SA_SESSION related to this packet.
|
|
@param[in] IkePacket Pointer to the IKE_AUTH packet to be parsered.
|
|
|
|
@retval EFI_INVALID_PARAMETER The IKE packet is malformed or the SA
|
|
proposal is unacceptable.
|
|
@retval EFI_SUCCESS The IKE packet is acceptable and the
|
|
relative data is saved for furthure communication.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2AuthPskParser (
|
|
IN UINT8 *SaSession,
|
|
IN IKE_PACKET *IkePacket
|
|
)
|
|
{
|
|
IKEV2_CHILD_SA_SESSION *ChildSaSession;
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
IKE_PAYLOAD *IkePayload;
|
|
IKE_PAYLOAD *SaPayload;
|
|
IKE_PAYLOAD *IdiPayload;
|
|
IKE_PAYLOAD *IdrPayload;
|
|
IKE_PAYLOAD *AuthPayload;
|
|
IKE_PAYLOAD *TsiPayload;
|
|
IKE_PAYLOAD *TsrPayload;
|
|
IKE_PAYLOAD *VerifiedAuthPayload;
|
|
LIST_ENTRY *Entry;
|
|
EFI_STATUS Status;
|
|
|
|
IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
|
|
ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
|
|
|
|
SaPayload = NULL;
|
|
IdiPayload = NULL;
|
|
IdrPayload = NULL;
|
|
AuthPayload = NULL;
|
|
TsiPayload = NULL;
|
|
TsrPayload = NULL;
|
|
|
|
//
|
|
// Iterate payloads to find the SaPayload/ID/AUTH/TS Payload.
|
|
//
|
|
NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
|
|
IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
|
|
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) {
|
|
IdiPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) {
|
|
IdrPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {
|
|
SaPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) {
|
|
AuthPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {
|
|
TsiPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) {
|
|
TsrPayload = IkePayload;
|
|
}
|
|
}
|
|
|
|
if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) || (TsrPayload == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if ((IdiPayload == NULL) && (IdrPayload == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Check IkePacket Header is match the state
|
|
//
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
|
|
//
|
|
// 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND
|
|
//
|
|
if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) ||
|
|
(IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)
|
|
) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT
|
|
//
|
|
if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) ||
|
|
(IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)
|
|
) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// 2. Parse the SA payload and Key Payload and find out the perferable one
|
|
// and fill in the Sa paramse into CommonSession->SaParams and SaData into
|
|
// IkeSaSession for the responder SA payload generation.
|
|
//
|
|
}
|
|
|
|
//
|
|
// Verify the Auth Payload.
|
|
//
|
|
VerifiedAuthPayload = Ikev2PskGenerateAuthPayload (
|
|
IkeSaSession,
|
|
IkeSaSession->SessionCommon.IsInitiator ? IdrPayload : IdiPayload,
|
|
IKEV2_PAYLOAD_TYPE_SA,
|
|
TRUE
|
|
);
|
|
if ((VerifiedAuthPayload != NULL) &&
|
|
(0 != CompareMem (
|
|
VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
|
|
AuthPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
|
|
VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER)
|
|
))) {
|
|
return EFI_INVALID_PARAMETER;
|
|
};
|
|
|
|
//
|
|
// 3. Parse the SA Payload to find out the cryptographic suite
|
|
// and fill in the Sa paramse into CommonSession->SaParams. If no acceptable
|
|
// porposal found, return EFI_INVALID_PARAMETER.
|
|
//
|
|
if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// 4. Parse TSi, TSr payloads.
|
|
//
|
|
if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId !=
|
|
((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) &&
|
|
(((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) &&
|
|
(((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0)
|
|
) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (!IkeSaSession->SessionCommon.IsInitiator) {
|
|
//
|
|
//TODO:check the Port range. Only support any port and one certain port here.
|
|
//
|
|
ChildSaSession->ProtoId = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId;
|
|
ChildSaSession->LocalPort = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
|
|
ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
|
|
//
|
|
// Association a SPD with this SA.
|
|
//
|
|
Status = Ikev2ChildSaAssociateSpdEntry (ChildSaSession);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Associate the IkeSaSession's SPD to the first ChildSaSession's SPD.
|
|
//
|
|
if (ChildSaSession->IkeSaSession->Spd == NULL) {
|
|
ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd;
|
|
Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);
|
|
}
|
|
} else {
|
|
//
|
|
//TODO:check the Port range.
|
|
//
|
|
if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
|
|
(((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort)
|
|
) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
|
|
(((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort)
|
|
) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector.
|
|
//
|
|
if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
|
|
if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) {
|
|
//
|
|
// If it is tunnel mode, the UEFI part must be the initiator.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Get the Virtual IP address from the Tsi traffic selector.
|
|
// TODO: check the CFG reply payload
|
|
//
|
|
CopyMem (
|
|
&ChildSaSession->SpdSelector->LocalAddress[0].Address,
|
|
TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR),
|
|
(ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ?
|
|
sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS)
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 5. Generate keymats for IPsec protocol.
|
|
//
|
|
Ikev2GenerateChildSaKeys (ChildSaSession, NULL);
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
//
|
|
// 6. Change the state of IkeSaSession
|
|
//
|
|
IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished);
|
|
IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Gernerates IKEv2 packet for IKE_SA_INIT exchange.
|
|
|
|
@param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange.
|
|
@param[in] Context Context Data passed by caller.
|
|
|
|
@retval EFI_SUCCESS The IKE packet generation succeeded.
|
|
@retval Others The IKE packet generation failed.
|
|
|
|
**/
|
|
IKE_PACKET*
|
|
Ikev2InitCertGenerator (
|
|
IN UINT8 *SaSession,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
IKE_PACKET *IkePacket;
|
|
IKE_PAYLOAD *CertReqPayload;
|
|
LIST_ENTRY *Node;
|
|
IKE_PAYLOAD *NoncePayload;
|
|
|
|
if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// The first two messages exchange is same between PSK and Cert.
|
|
//
|
|
IkePacket = Ikev2InitPskGenerator (SaSession, Context);
|
|
|
|
if ((IkePacket != NULL) && (!((IKEV2_SA_SESSION *)SaSession)->SessionCommon.IsInitiator)) {
|
|
//
|
|
// Add the Certification Request Payload
|
|
//
|
|
CertReqPayload = Ikev2GenerateCertificatePayload (
|
|
(IKEV2_SA_SESSION *)SaSession,
|
|
IKEV2_PAYLOAD_TYPE_NONE,
|
|
(UINT8*)PcdGetPtr(UefiCaFile),
|
|
PcdGet32(UefiCaFileSize),
|
|
IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT,
|
|
TRUE
|
|
);
|
|
//
|
|
// Change Nonce Payload Next payload type.
|
|
//
|
|
IKE_PACKET_END_PAYLOAD (IkePacket, Node);
|
|
NoncePayload = IKE_PAYLOAD_BY_PACKET (Node);
|
|
((IKEV2_NONCE *)NoncePayload->PayloadBuf)->Header.NextPayload = IKEV2_PAYLOAD_TYPE_CERTREQ;
|
|
|
|
//
|
|
// Add Certification Request Payload
|
|
//
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload);
|
|
}
|
|
|
|
return IkePacket;
|
|
}
|
|
|
|
/**
|
|
Parses the IKEv2 packet for IKE_SA_INIT exchange.
|
|
|
|
@param[in] SaSession Pointer to IKEV2_SA_SESSION related to the exchange.
|
|
@param[in] IkePacket The received IKEv2 packet to be parsed.
|
|
|
|
@retval EFI_SUCCESS The IKEv2 packet is acceptable and the relative data is
|
|
saved for furthure communication.
|
|
@retval EFI_INVALID_PARAMETER The IKE packet is malformed or the SA proposal is unacceptable.
|
|
@retval EFI_UNSUPPORTED The certificate authentication is not supported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2InitCertParser (
|
|
IN UINT8 *SaSession,
|
|
IN IKE_PACKET *IkePacket
|
|
)
|
|
{
|
|
if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// The first two messages exchange is same between PSK and Cert.
|
|
// Todo: Parse Certificate Request from responder Initial Exchange.
|
|
//
|
|
return Ikev2InitPskParser (SaSession, IkePacket);
|
|
}
|
|
|
|
/**
|
|
Generates the IKEv2 packet for IKE_AUTH exchange.
|
|
|
|
@param[in] SaSession Pointer to IKEV2_SA_SESSION.
|
|
@param[in] Context Context data passed by caller.
|
|
|
|
@retval Pointer to IKEv2 Packet to be sent out.
|
|
|
|
**/
|
|
IKE_PACKET *
|
|
Ikev2AuthCertGenerator (
|
|
IN UINT8 *SaSession,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
IKE_PACKET *IkePacket;
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
IKE_PAYLOAD *IdPayload;
|
|
IKE_PAYLOAD *AuthPayload;
|
|
IKE_PAYLOAD *SaPayload;
|
|
IKE_PAYLOAD *TsiPayload;
|
|
IKE_PAYLOAD *TsrPayload;
|
|
IKE_PAYLOAD *NotifyPayload;
|
|
IKE_PAYLOAD *CpPayload;
|
|
IKE_PAYLOAD *CertPayload;
|
|
IKE_PAYLOAD *CertReqPayload;
|
|
IKEV2_CHILD_SA_SESSION *ChildSaSession;
|
|
|
|
if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) {
|
|
return NULL;
|
|
}
|
|
|
|
IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
|
|
ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
|
|
|
|
CpPayload = NULL;
|
|
NotifyPayload = NULL;
|
|
CertPayload = NULL;
|
|
CertReqPayload = NULL;
|
|
|
|
//
|
|
// 1. Allocate IKE Packet
|
|
//
|
|
IkePacket= IkePacketAlloc ();
|
|
ASSERT (IkePacket != NULL);
|
|
|
|
//
|
|
// 1.a Fill the IkePacket Header.
|
|
//
|
|
IkePacket->Header->ExchangeType = IKEV2_EXCHANGE_TYPE_AUTH;
|
|
IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
|
|
IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
|
|
IkePacket->Header->Version = (UINT8)(2 << 4);
|
|
if (ChildSaSession->SessionCommon.IsInitiator) {
|
|
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_INIT;
|
|
} else {
|
|
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ID_RSP;
|
|
}
|
|
|
|
//
|
|
// According to RFC4306_2.2, For the IKE_SA_INIT message the MessageID should
|
|
// be always number 0 and 1;
|
|
//
|
|
IkePacket->Header->MessageId = 1;
|
|
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
|
|
} else {
|
|
IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
|
|
}
|
|
|
|
//
|
|
// 2. Generate ID Payload according to IP version and address.
|
|
//
|
|
IdPayload = Ikev2GenerateCertIdPayload (
|
|
&IkeSaSession->SessionCommon,
|
|
IKEV2_PAYLOAD_TYPE_CERT,
|
|
(UINT8 *)PcdGetPtr (UefiCertificate),
|
|
PcdGet32 (UefiCertificateSize)
|
|
);
|
|
|
|
//
|
|
// 3. Generate Certificate Payload
|
|
//
|
|
CertPayload = Ikev2GenerateCertificatePayload (
|
|
IkeSaSession,
|
|
(UINT8)(IkeSaSession->SessionCommon.IsInitiator ? IKEV2_PAYLOAD_TYPE_CERTREQ : IKEV2_PAYLOAD_TYPE_AUTH),
|
|
(UINT8 *)PcdGetPtr (UefiCertificate),
|
|
PcdGet32 (UefiCertificateSize),
|
|
IKEV2_CERT_ENCODEING_X509_CERT_SIGN,
|
|
FALSE
|
|
);
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
CertReqPayload = Ikev2GenerateCertificatePayload (
|
|
IkeSaSession,
|
|
IKEV2_PAYLOAD_TYPE_AUTH,
|
|
(UINT8 *)PcdGetPtr (UefiCertificate),
|
|
PcdGet32 (UefiCertificateSize),
|
|
IKEV2_CERT_ENCODEING_HASH_AND_URL_OF_X509_CERT,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
//
|
|
// 4. Generate Auth Payload
|
|
// If it is tunnel mode, should create the configuration payload after the
|
|
// Auth payload.
|
|
//
|
|
if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
|
|
AuthPayload = Ikev2CertGenerateAuthPayload (
|
|
ChildSaSession->IkeSaSession,
|
|
IdPayload,
|
|
IKEV2_PAYLOAD_TYPE_SA,
|
|
FALSE,
|
|
(UINT8 *)PcdGetPtr (UefiCertificateKey),
|
|
PcdGet32 (UefiCertificateKeySize),
|
|
ChildSaSession->IkeSaSession->Pad->Data->AuthData,
|
|
ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize
|
|
);
|
|
} else {
|
|
AuthPayload = Ikev2CertGenerateAuthPayload (
|
|
ChildSaSession->IkeSaSession,
|
|
IdPayload,
|
|
IKEV2_PAYLOAD_TYPE_CP,
|
|
FALSE,
|
|
(UINT8 *)PcdGetPtr (UefiCertificateKey),
|
|
PcdGet32 (UefiCertificateKeySize),
|
|
ChildSaSession->IkeSaSession->Pad->Data->AuthData,
|
|
ChildSaSession->IkeSaSession->Pad->Data->AuthDataSize
|
|
);
|
|
if (IkeSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) {
|
|
CpPayload = Ikev2GenerateCpPayload (
|
|
ChildSaSession->IkeSaSession,
|
|
IKEV2_PAYLOAD_TYPE_SA,
|
|
IKEV2_CFG_ATTR_INTERNAL_IP4_ADDRESS
|
|
);
|
|
} else {
|
|
CpPayload = Ikev2GenerateCpPayload (
|
|
ChildSaSession->IkeSaSession,
|
|
IKEV2_PAYLOAD_TYPE_SA,
|
|
IKEV2_CFG_ATTR_INTERNAL_IP6_ADDRESS
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 5. Generate SA Payload according to the Sa Data in ChildSaSession
|
|
//
|
|
SaPayload = Ikev2GenerateSaPayload (
|
|
ChildSaSession->SaData,
|
|
IKEV2_PAYLOAD_TYPE_TS_INIT,
|
|
IkeSessionTypeChildSa
|
|
);
|
|
|
|
if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
|
|
//
|
|
// Generate Tsi and Tsr.
|
|
//
|
|
TsiPayload = Ikev2GenerateTsPayload (
|
|
ChildSaSession,
|
|
IKEV2_PAYLOAD_TYPE_TS_RSP,
|
|
FALSE
|
|
);
|
|
|
|
TsrPayload = Ikev2GenerateTsPayload (
|
|
ChildSaSession,
|
|
IKEV2_PAYLOAD_TYPE_NOTIFY,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Generate Notify Payload. If transport mode, there should have Notify
|
|
// payload with TRANSPORT_MODE notification.
|
|
//
|
|
NotifyPayload = Ikev2GenerateNotifyPayload (
|
|
0,
|
|
IKEV2_PAYLOAD_TYPE_NONE,
|
|
0,
|
|
IKEV2_NOTIFICATION_USE_TRANSPORT_MODE,
|
|
NULL,
|
|
NULL,
|
|
0
|
|
);
|
|
} else {
|
|
//
|
|
// Generate Tsr for Tunnel mode.
|
|
//
|
|
TsiPayload = Ikev2GenerateTsPayload (
|
|
ChildSaSession,
|
|
IKEV2_PAYLOAD_TYPE_TS_RSP,
|
|
TRUE
|
|
);
|
|
TsrPayload = Ikev2GenerateTsPayload (
|
|
ChildSaSession,
|
|
IKEV2_PAYLOAD_TYPE_NONE,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, IdPayload);
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertPayload);
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, CertReqPayload);
|
|
}
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, AuthPayload);
|
|
if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, CpPayload);
|
|
}
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, SaPayload);
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsiPayload);
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, TsrPayload);
|
|
if (IkeSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTransport) {
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, NotifyPayload);
|
|
}
|
|
|
|
return IkePacket;
|
|
}
|
|
|
|
/**
|
|
Parses IKE_AUTH packet.
|
|
|
|
@param[in] SaSession Pointer to the IKE_SA_SESSION related to this packet.
|
|
@param[in] IkePacket Pointer to the IKE_AUTH packet to be parsered.
|
|
|
|
@retval EFI_INVALID_PARAMETER The IKEv2 packet is malformed or the SA
|
|
proposal is unacceptable.
|
|
@retval EFI_SUCCESS The IKE packet is acceptable and the
|
|
relative data is saved for furthure communication.
|
|
@retval EFI_UNSUPPORTED The certificate authentication is not supported.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2AuthCertParser (
|
|
IN UINT8 *SaSession,
|
|
IN IKE_PACKET *IkePacket
|
|
)
|
|
{
|
|
IKEV2_CHILD_SA_SESSION *ChildSaSession;
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
IKE_PAYLOAD *IkePayload;
|
|
IKE_PAYLOAD *SaPayload;
|
|
IKE_PAYLOAD *IdiPayload;
|
|
IKE_PAYLOAD *IdrPayload;
|
|
IKE_PAYLOAD *AuthPayload;
|
|
IKE_PAYLOAD *TsiPayload;
|
|
IKE_PAYLOAD *TsrPayload;
|
|
IKE_PAYLOAD *CertPayload;
|
|
IKE_PAYLOAD *CertReqPayload;
|
|
IKE_PAYLOAD *VerifiedAuthPayload;
|
|
LIST_ENTRY *Entry;
|
|
EFI_STATUS Status;
|
|
|
|
if (!FeaturePcdGet (PcdIpsecCertiifcateEnabled)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
|
|
ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (GetFirstNode (&IkeSaSession->ChildSaSessionList));
|
|
|
|
SaPayload = NULL;
|
|
IdiPayload = NULL;
|
|
IdrPayload = NULL;
|
|
AuthPayload = NULL;
|
|
TsiPayload = NULL;
|
|
TsrPayload = NULL;
|
|
CertPayload = NULL;
|
|
CertReqPayload = NULL;
|
|
VerifiedAuthPayload = NULL;
|
|
Status = EFI_INVALID_PARAMETER;
|
|
|
|
//
|
|
// Iterate payloads to find the SaPayload/ID/AUTH/TS Payload.
|
|
//
|
|
NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
|
|
IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
|
|
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_INIT) {
|
|
IdiPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_ID_RSP) {
|
|
IdrPayload = IkePayload;
|
|
}
|
|
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_SA) {
|
|
SaPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_AUTH) {
|
|
AuthPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {
|
|
TsiPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_RSP) {
|
|
TsrPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERT) {
|
|
CertPayload = IkePayload;
|
|
}
|
|
if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_CERTREQ) {
|
|
CertReqPayload = IkePayload;
|
|
}
|
|
}
|
|
|
|
if ((SaPayload == NULL) || (AuthPayload == NULL) || (TsiPayload == NULL) ||
|
|
(TsrPayload == NULL) || (CertPayload == NULL)) {
|
|
goto Exit;
|
|
}
|
|
if ((IdiPayload == NULL) && (IdrPayload == NULL)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Check IkePacket Header is match the state
|
|
//
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
|
|
//
|
|
// 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_RESPOND
|
|
//
|
|
if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_RESPOND) ||
|
|
(IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) {
|
|
goto Exit;
|
|
}
|
|
} else {
|
|
//
|
|
// 1. Check the IkePacket->Hdr == IKE_HEADER_FLAGS_INIT
|
|
//
|
|
if ((IkePacket->Header->Flags != IKE_HEADER_FLAGS_INIT) ||
|
|
(IkePacket->Header->ExchangeType != IKEV2_EXCHANGE_TYPE_AUTH)) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Verify the Auth Payload.
|
|
//
|
|
VerifiedAuthPayload = Ikev2CertGenerateAuthPayload (
|
|
IkeSaSession,
|
|
IkeSaSession->SessionCommon.IsInitiator ? IdrPayload:IdiPayload,
|
|
IKEV2_PAYLOAD_TYPE_SA,
|
|
TRUE,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
if ((VerifiedAuthPayload != NULL) &&
|
|
(!IpSecCryptoIoVerifySignDataByCertificate (
|
|
CertPayload->PayloadBuf + sizeof (IKEV2_CERT),
|
|
CertPayload->PayloadSize - sizeof (IKEV2_CERT),
|
|
(UINT8 *)PcdGetPtr (UefiCaFile),
|
|
PcdGet32 (UefiCaFileSize),
|
|
VerifiedAuthPayload->PayloadBuf + sizeof (IKEV2_AUTH),
|
|
VerifiedAuthPayload->PayloadSize - sizeof (IKEV2_AUTH),
|
|
AuthPayload->PayloadBuf + sizeof (IKEV2_AUTH),
|
|
AuthPayload->PayloadSize - sizeof (IKEV2_AUTH)
|
|
))) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// 3. Parse the SA Payload to find out the cryptographic suite
|
|
// and fill in the SA paramse into CommonSession->SaParams. If no acceptable
|
|
// porposal found, return EFI_INVALID_PARAMETER.
|
|
//
|
|
if (!Ikev2ChildSaParseSaPayload (ChildSaSession, SaPayload, IkePacket->Header->Flags)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// 4. Parse TSi, TSr payloads.
|
|
//
|
|
if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId !=
|
|
((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId) &&
|
|
(((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0) &&
|
|
(((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId != 0)
|
|
) {
|
|
goto Exit;
|
|
}
|
|
|
|
if (!IkeSaSession->SessionCommon.IsInitiator) {
|
|
//
|
|
//Todo:check the Port range. Only support any port and one certain port here.
|
|
//
|
|
ChildSaSession->ProtoId = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->IpProtocolId;
|
|
ChildSaSession->LocalPort = ((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
|
|
ChildSaSession->RemotePort = ((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort;
|
|
//
|
|
// Association a SPD with this SA.
|
|
//
|
|
if (EFI_ERROR (Ikev2ChildSaAssociateSpdEntry (ChildSaSession))) {
|
|
goto Exit;
|
|
}
|
|
//
|
|
// Associate the IkeSaSession's SPD to the first ChildSaSession's SPD.
|
|
//
|
|
if (ChildSaSession->IkeSaSession->Spd == NULL) {
|
|
ChildSaSession->IkeSaSession->Spd = ChildSaSession->Spd;
|
|
Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);
|
|
}
|
|
} else {
|
|
//
|
|
// Todo:check the Port range.
|
|
//
|
|
if ((((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
|
|
(((TRAFFIC_SELECTOR *)(TsrPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->RemotePort)
|
|
) {
|
|
goto Exit;
|
|
}
|
|
if ((((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != 0) &&
|
|
(((TRAFFIC_SELECTOR *)(TsiPayload->PayloadBuf + sizeof (IKEV2_TS)))->StartPort != ChildSaSession->LocalPort)
|
|
) {
|
|
goto Exit;
|
|
}
|
|
//
|
|
// For the tunnel mode, it should add the vitual IP address into the SA's SPD Selector.
|
|
//
|
|
if (ChildSaSession->Spd->Data->ProcessingPolicy->Mode == EfiIPsecTunnel) {
|
|
if (!ChildSaSession->IkeSaSession->SessionCommon.IsInitiator) {
|
|
//
|
|
// If it is tunnel mode, the UEFI part must be the initiator.
|
|
//
|
|
goto Exit;
|
|
}
|
|
//
|
|
// Get the Virtual IP address from the Tsi traffic selector.
|
|
// TODO: check the CFG reply payload
|
|
//
|
|
CopyMem (
|
|
&ChildSaSession->SpdSelector->LocalAddress[0].Address,
|
|
TsiPayload->PayloadBuf + sizeof (IKEV2_TS) + sizeof (TRAFFIC_SELECTOR),
|
|
(ChildSaSession->SessionCommon.UdpService->IpVersion == IP_VERSION_4) ?
|
|
sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS)
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// 5. Generat keymats for IPsec protocol.
|
|
//
|
|
Ikev2GenerateChildSaKeys (ChildSaSession, NULL);
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
//
|
|
// 6. Change the state of IkeSaSession
|
|
//
|
|
IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateIkeSaEstablished);
|
|
IkeSaSession->SessionCommon.State = IkeStateIkeSaEstablished;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
Exit:
|
|
if (VerifiedAuthPayload != NULL) {
|
|
IkePayloadFree (VerifiedAuthPayload);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Generates the DH Public Key.
|
|
|
|
This generates the DH local public key and store it in the IKE SA Session's GxBuffer.
|
|
|
|
@param[in] IkeSaSession Pointer to related IKE SA Session.
|
|
|
|
@retval EFI_SUCCESS The operation succeeded.
|
|
@retval Others The operation failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2GenerateSaDhPublicKey (
|
|
IN IKEV2_SA_SESSION *IkeSaSession
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
IKEV2_SESSION_KEYS *IkeKeys;
|
|
|
|
IkeSaSession->IkeKeys = AllocateZeroPool (sizeof (IKEV2_SESSION_KEYS));
|
|
ASSERT (IkeSaSession->IkeKeys != NULL);
|
|
IkeKeys = IkeSaSession->IkeKeys;
|
|
IkeKeys->DhBuffer = AllocateZeroPool (sizeof (IKEV2_DH_BUFFER));
|
|
ASSERT (IkeKeys->DhBuffer != NULL);
|
|
|
|
//
|
|
// Init DH with the certain DH Group Description.
|
|
//
|
|
IkeKeys->DhBuffer->GxSize = OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size >> 3;
|
|
IkeKeys->DhBuffer->GxBuffer = AllocateZeroPool (IkeKeys->DhBuffer->GxSize);
|
|
ASSERT (IkeKeys->DhBuffer->GxBuffer != NULL);
|
|
|
|
//
|
|
// Get X PublicKey
|
|
//
|
|
Status = IpSecCryptoIoDhGetPublicKey (
|
|
&IkeKeys->DhBuffer->DhContext,
|
|
OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].GroupGenerator,
|
|
OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Size,
|
|
OakleyModpGroup[(UINT8)IkeSaSession->SessionCommon.PreferDhGroup].Modulus,
|
|
IkeKeys->DhBuffer->GxBuffer,
|
|
&IkeKeys->DhBuffer->GxSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam X public key error Status = %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
IPSEC_DUMP_BUF ("DH Public Key (g^x) Dump", IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Computes the DH Shared/Exchange Key.
|
|
|
|
Given peer's public key, this function computes the exchanged common key and
|
|
stores it in the IKEv2 SA Session's GxyBuffer.
|
|
|
|
@param[in] DhBuffer Pointer to buffer of peer's puliic key.
|
|
@param[in] KePayload Pointer to received key payload.
|
|
|
|
@retval EFI_SUCCESS The operation succeeded.
|
|
@retval Otherwise The operation failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2GenerateSaDhComputeKey (
|
|
IN IKEV2_DH_BUFFER *DhBuffer,
|
|
IN IKE_PAYLOAD *KePayload
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
IKEV2_KEY_EXCHANGE *Ke;
|
|
UINT8 *PubKey;
|
|
UINTN PubKeySize;
|
|
|
|
Ke = (IKEV2_KEY_EXCHANGE *) KePayload->PayloadBuf;
|
|
PubKey = (UINT8 *) (Ke + 1);
|
|
PubKeySize = KePayload->PayloadSize - sizeof (IKEV2_KEY_EXCHANGE);
|
|
DhBuffer->GxySize = DhBuffer->GxSize;
|
|
DhBuffer->GxyBuffer = AllocateZeroPool (DhBuffer->GxySize);
|
|
ASSERT (DhBuffer->GxyBuffer != NULL);
|
|
|
|
//
|
|
// Get GxyBuf
|
|
//
|
|
Status = IpSecCryptoIoDhComputeKey (
|
|
DhBuffer->DhContext,
|
|
PubKey,
|
|
PubKeySize,
|
|
DhBuffer->GxyBuffer,
|
|
&DhBuffer->GxySize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Error CPLKeyManGetKeyParam Y session key error Status = %r\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Create GxyBuf.
|
|
//
|
|
DhBuffer->GySize = PubKeySize;
|
|
DhBuffer->GyBuffer = AllocateZeroPool (DhBuffer->GySize);
|
|
ASSERT (DhBuffer->GyBuffer != NULL);
|
|
CopyMem (DhBuffer->GyBuffer, PubKey, DhBuffer->GySize);
|
|
|
|
IPSEC_DUMP_BUF ("DH Public Key (g^y) Dump", DhBuffer->GyBuffer, DhBuffer->GySize);
|
|
IPSEC_DUMP_BUF ("DH Shared Key (g^xy) Dump", DhBuffer->GxyBuffer, DhBuffer->GxySize);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Generates the IKE SKEYSEED and seven other secrets. SK_d, SK_ai, SK_ar, SK_ei, SK_er,
|
|
SK_pi, SK_pr are keys for the furthure IKE exchange.
|
|
|
|
@param[in] IkeSaSession Pointer to IKE SA Session.
|
|
@param[in] KePayload Pointer to Key payload used to generate the Key.
|
|
|
|
@retval EFI_UNSUPPORTED If one or more Algorithm Id is not supported.
|
|
@retval EFI_OUT_OF_RESOURCES If there is no enough resource to be allocated to
|
|
meet the requirement.
|
|
@retval EFI_SUCCESS The operation succeeded.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2GenerateSaKeys (
|
|
IN IKEV2_SA_SESSION *IkeSaSession,
|
|
IN IKE_PAYLOAD *KePayload
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
IKEV2_SA_PARAMS *SaParams;
|
|
IPSEC_PAD_ENTRY *Pad;
|
|
PRF_DATA_FRAGMENT Fragments[4];
|
|
UINT64 InitiatorCookieNet;
|
|
UINT64 ResponderCookieNet;
|
|
UINT8 *KeyBuffer;
|
|
UINTN KeyBufferSize;
|
|
UINTN AuthAlgKeyLen;
|
|
UINTN EncryptAlgKeyLen;
|
|
UINTN IntegrityAlgKeyLen;
|
|
UINTN PrfAlgKeyLen;
|
|
UINT8 *OutputKey;
|
|
UINTN OutputKeyLength;
|
|
UINT8 *Digest;
|
|
UINTN DigestSize;
|
|
|
|
Digest = NULL;
|
|
OutputKey = NULL;
|
|
KeyBuffer = NULL;
|
|
|
|
//
|
|
// Generate Gxy
|
|
//
|
|
Ikev2GenerateSaDhComputeKey (IkeSaSession->IkeKeys->DhBuffer, KePayload);
|
|
|
|
Pad = IkeSaSession->Pad;
|
|
|
|
//
|
|
// Get the key length of Authenticaion, Encryption, PRF, and Integrity.
|
|
//
|
|
SaParams = IkeSaSession->SessionCommon.SaParams;
|
|
AuthAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);
|
|
EncryptAlgKeyLen = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId);
|
|
IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId);
|
|
PrfAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);
|
|
|
|
//
|
|
// If one or more algorithm is not support, return EFI_UNSUPPORTED.
|
|
//
|
|
if (AuthAlgKeyLen == 0 ||
|
|
EncryptAlgKeyLen == 0 ||
|
|
IntegrityAlgKeyLen == 0 ||
|
|
PrfAlgKeyLen == 0
|
|
) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Compute SKEYSEED = prf(Ni | Nr, g^ir)
|
|
//
|
|
KeyBufferSize = IkeSaSession->NiBlkSize + IkeSaSession->NrBlkSize;
|
|
KeyBuffer = AllocateZeroPool (KeyBufferSize);
|
|
ASSERT (KeyBuffer != NULL);
|
|
|
|
CopyMem (KeyBuffer, IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);
|
|
CopyMem (KeyBuffer + IkeSaSession->NiBlkSize, IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);
|
|
|
|
Fragments[0].Data = IkeSaSession->IkeKeys->DhBuffer->GxyBuffer;
|
|
Fragments[0].DataSize = IkeSaSession->IkeKeys->DhBuffer->GxySize;
|
|
|
|
DigestSize = IpSecGetHmacDigestLength ((UINT8)SaParams->Prf);
|
|
Digest = AllocateZeroPool (DigestSize);
|
|
|
|
if (Digest == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
IpSecCryptoIoHmac (
|
|
(UINT8)SaParams->Prf,
|
|
KeyBuffer,
|
|
KeyBufferSize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
1,
|
|
Digest,
|
|
DigestSize
|
|
);
|
|
|
|
//
|
|
// {SK_d | SK_ai | SK_ar | SK_ei | SK_er | SK_pi | SK_pr } = prf+
|
|
// (SKEYSEED, Ni | Nr | SPIi | SPIr )
|
|
//
|
|
Fragments[0].Data = IkeSaSession->NiBlock;
|
|
Fragments[0].DataSize = IkeSaSession->NiBlkSize;
|
|
Fragments[1].Data = IkeSaSession->NrBlock;
|
|
Fragments[1].DataSize = IkeSaSession->NrBlkSize;
|
|
InitiatorCookieNet = HTONLL (IkeSaSession->InitiatorCookie);
|
|
ResponderCookieNet = HTONLL (IkeSaSession->ResponderCookie);
|
|
Fragments[2].Data = (UINT8 *)(&InitiatorCookieNet);
|
|
Fragments[2].DataSize = sizeof (IkeSaSession->InitiatorCookie);
|
|
Fragments[3].Data = (UINT8 *)(&ResponderCookieNet);
|
|
Fragments[3].DataSize = sizeof (IkeSaSession->ResponderCookie);
|
|
|
|
IPSEC_DUMP_BUF (">>> NiBlock", IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);
|
|
IPSEC_DUMP_BUF (">>> NrBlock", IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);
|
|
IPSEC_DUMP_BUF (">>> InitiatorCookie", (UINT8 *)&IkeSaSession->InitiatorCookie, sizeof(UINT64));
|
|
IPSEC_DUMP_BUF (">>> ResponderCookie", (UINT8 *)&IkeSaSession->ResponderCookie, sizeof(UINT64));
|
|
|
|
OutputKeyLength = PrfAlgKeyLen +
|
|
2 * EncryptAlgKeyLen +
|
|
2 * AuthAlgKeyLen +
|
|
2 * IntegrityAlgKeyLen;
|
|
OutputKey = AllocateZeroPool (OutputKeyLength);
|
|
|
|
//
|
|
// Generate Seven Keymates.
|
|
//
|
|
Status = Ikev2SaGenerateKey (
|
|
(UINT8)SaParams->Prf,
|
|
Digest,
|
|
DigestSize,
|
|
OutputKey,
|
|
OutputKeyLength,
|
|
Fragments,
|
|
4
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Save the seven keys into KeySession.
|
|
// First, SK_d
|
|
//
|
|
IkeSaSession->IkeKeys->SkdKey = AllocateZeroPool (PrfAlgKeyLen);
|
|
IkeSaSession->IkeKeys->SkdKeySize = PrfAlgKeyLen;
|
|
CopyMem (IkeSaSession->IkeKeys->SkdKey, OutputKey, PrfAlgKeyLen);
|
|
|
|
IPSEC_DUMP_BUF (">>> SK_D Key", IkeSaSession->IkeKeys->SkdKey, PrfAlgKeyLen);
|
|
|
|
//
|
|
// Second, Sk_ai
|
|
//
|
|
IkeSaSession->IkeKeys->SkAiKey = AllocateZeroPool (IntegrityAlgKeyLen);
|
|
IkeSaSession->IkeKeys->SkAiKeySize = IntegrityAlgKeyLen;
|
|
CopyMem (IkeSaSession->IkeKeys->SkAiKey, OutputKey + PrfAlgKeyLen, IntegrityAlgKeyLen);
|
|
|
|
IPSEC_DUMP_BUF (">>> SK_Ai Key", IkeSaSession->IkeKeys->SkAiKey, IkeSaSession->IkeKeys->SkAiKeySize);
|
|
|
|
//
|
|
// Third, Sk_ar
|
|
//
|
|
IkeSaSession->IkeKeys->SkArKey = AllocateZeroPool (IntegrityAlgKeyLen);
|
|
IkeSaSession->IkeKeys->SkArKeySize = IntegrityAlgKeyLen;
|
|
CopyMem (
|
|
IkeSaSession->IkeKeys->SkArKey,
|
|
OutputKey + PrfAlgKeyLen + IntegrityAlgKeyLen,
|
|
IntegrityAlgKeyLen
|
|
);
|
|
|
|
IPSEC_DUMP_BUF (">>> SK_Ar Key", IkeSaSession->IkeKeys->SkArKey, IkeSaSession->IkeKeys->SkArKeySize);
|
|
|
|
//
|
|
// Fourth, Sk_ei
|
|
//
|
|
IkeSaSession->IkeKeys->SkEiKey = AllocateZeroPool (EncryptAlgKeyLen);
|
|
IkeSaSession->IkeKeys->SkEiKeySize = EncryptAlgKeyLen;
|
|
|
|
CopyMem (
|
|
IkeSaSession->IkeKeys->SkEiKey,
|
|
OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen,
|
|
EncryptAlgKeyLen
|
|
);
|
|
IPSEC_DUMP_BUF (
|
|
">>> SK_Ei Key",
|
|
OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen,
|
|
EncryptAlgKeyLen
|
|
);
|
|
|
|
//
|
|
// Fifth, Sk_er
|
|
//
|
|
IkeSaSession->IkeKeys->SkErKey = AllocateZeroPool (EncryptAlgKeyLen);
|
|
IkeSaSession->IkeKeys->SkErKeySize = EncryptAlgKeyLen;
|
|
|
|
CopyMem (
|
|
IkeSaSession->IkeKeys->SkErKey,
|
|
OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen,
|
|
EncryptAlgKeyLen
|
|
);
|
|
IPSEC_DUMP_BUF (
|
|
">>> SK_Er Key",
|
|
OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + EncryptAlgKeyLen,
|
|
EncryptAlgKeyLen
|
|
);
|
|
|
|
//
|
|
// Sixth, Sk_pi
|
|
//
|
|
IkeSaSession->IkeKeys->SkPiKey = AllocateZeroPool (AuthAlgKeyLen);
|
|
IkeSaSession->IkeKeys->SkPiKeySize = AuthAlgKeyLen;
|
|
|
|
CopyMem (
|
|
IkeSaSession->IkeKeys->SkPiKey,
|
|
OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen,
|
|
AuthAlgKeyLen
|
|
);
|
|
IPSEC_DUMP_BUF (
|
|
">>> SK_Pi Key",
|
|
OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen,
|
|
AuthAlgKeyLen
|
|
);
|
|
|
|
//
|
|
// Seventh, Sk_pr
|
|
//
|
|
IkeSaSession->IkeKeys->SkPrKey = AllocateZeroPool (AuthAlgKeyLen);
|
|
IkeSaSession->IkeKeys->SkPrKeySize = AuthAlgKeyLen;
|
|
|
|
CopyMem (
|
|
IkeSaSession->IkeKeys->SkPrKey,
|
|
OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen,
|
|
AuthAlgKeyLen
|
|
);
|
|
IPSEC_DUMP_BUF (
|
|
">>> SK_Pr Key",
|
|
OutputKey + AuthAlgKeyLen + 2 * IntegrityAlgKeyLen + 2 * EncryptAlgKeyLen + AuthAlgKeyLen,
|
|
AuthAlgKeyLen
|
|
);
|
|
|
|
|
|
Exit:
|
|
if (Digest != NULL) {
|
|
FreePool (Digest);
|
|
}
|
|
if (KeyBuffer != NULL) {
|
|
FreePool (KeyBuffer);
|
|
}
|
|
if (OutputKey != NULL) {
|
|
FreePool (OutputKey);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Generates the Keys for the furthure IPsec Protocol.
|
|
|
|
@param[in] ChildSaSession Pointer to IKE Child SA Session.
|
|
@param[in] KePayload Pointer to Key payload used to generate the Key.
|
|
|
|
@retval EFI_UNSUPPORTED If one or more Algorithm Id is not supported.
|
|
@retval EFI_SUCCESS The operation succeeded.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2GenerateChildSaKeys (
|
|
IN IKEV2_CHILD_SA_SESSION *ChildSaSession,
|
|
IN IKE_PAYLOAD *KePayload
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
IKEV2_SA_PARAMS *SaParams;
|
|
PRF_DATA_FRAGMENT Fragments[3];
|
|
UINTN EncryptAlgKeyLen;
|
|
UINTN IntegrityAlgKeyLen;
|
|
UINT8* OutputKey;
|
|
UINTN OutputKeyLength;
|
|
|
|
if (KePayload != NULL) {
|
|
//
|
|
// Generate Gxy
|
|
//
|
|
Ikev2GenerateSaDhComputeKey (ChildSaSession->DhBuffer, KePayload);
|
|
Fragments[0].Data = ChildSaSession->DhBuffer->GxyBuffer;
|
|
Fragments[0].DataSize = ChildSaSession->DhBuffer->GxySize;
|
|
}
|
|
|
|
Fragments[1].Data = ChildSaSession->NiBlock;
|
|
Fragments[1].DataSize = ChildSaSession->NiBlkSize;
|
|
Fragments[2].Data = ChildSaSession->NrBlock;
|
|
Fragments[2].DataSize = ChildSaSession->NrBlkSize;
|
|
|
|
//
|
|
// Get the key length of Authenticaion, Encryption, PRF, and Integrity.
|
|
//
|
|
SaParams = ChildSaSession->SessionCommon.SaParams;
|
|
EncryptAlgKeyLen = IpSecGetEncryptKeyLength ((UINT8)SaParams->EncAlgId);
|
|
IntegrityAlgKeyLen = IpSecGetHmacDigestLength ((UINT8)SaParams->IntegAlgId);
|
|
OutputKeyLength = 2 * EncryptAlgKeyLen + 2 * IntegrityAlgKeyLen;
|
|
|
|
if ((EncryptAlgKeyLen == 0) || (IntegrityAlgKeyLen == 0)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
//
|
|
// If KePayload is not NULL, calculate KEYMAT = prf+(SK_d, g^ir (new) | Ni | Nr ),
|
|
// otherwise, KEYMAT = prf+(SK_d, Ni | Nr )
|
|
//
|
|
OutputKey = AllocateZeroPool (OutputKeyLength);
|
|
|
|
//
|
|
// Derive Key from the SkdKey Buffer.
|
|
//
|
|
Status = Ikev2SaGenerateKey (
|
|
(UINT8)ChildSaSession->IkeSaSession->SessionCommon.SaParams->Prf,
|
|
ChildSaSession->IkeSaSession->IkeKeys->SkdKey,
|
|
ChildSaSession->IkeSaSession->IkeKeys->SkdKeySize,
|
|
OutputKey,
|
|
OutputKeyLength,
|
|
KePayload == NULL ? &Fragments[1] : Fragments,
|
|
KePayload == NULL ? 2 : 3
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
FreePool (OutputKey);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Copy KEYMATE (SK_ENCRYPT_i | SK_ENCRYPT_r | SK_INTEG_i | SK_INTEG_r) to
|
|
// ChildKeyMates.
|
|
//
|
|
if (!ChildSaSession->SessionCommon.IsInitiator) {
|
|
|
|
//
|
|
// Initiator Encryption Key
|
|
//
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId;
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen);
|
|
|
|
CopyMem (
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,
|
|
OutputKey,
|
|
EncryptAlgKeyLen
|
|
);
|
|
|
|
//
|
|
// Initiator Authentication Key
|
|
//
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId;
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen);
|
|
|
|
CopyMem (
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,
|
|
OutputKey + EncryptAlgKeyLen,
|
|
IntegrityAlgKeyLen
|
|
);
|
|
|
|
//
|
|
// Responder Encrypt Key
|
|
//
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId;
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen);
|
|
|
|
CopyMem (
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,
|
|
OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen,
|
|
EncryptAlgKeyLen
|
|
);
|
|
|
|
//
|
|
// Responder Authentication Key
|
|
//
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId;
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen);
|
|
|
|
CopyMem (
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,
|
|
OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen,
|
|
IntegrityAlgKeyLen
|
|
);
|
|
} else {
|
|
//
|
|
// Initiator Encryption Key
|
|
//
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId;
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen);
|
|
|
|
CopyMem (
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,
|
|
OutputKey,
|
|
EncryptAlgKeyLen
|
|
);
|
|
|
|
//
|
|
// Initiator Authentication Key
|
|
//
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId;
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen);
|
|
|
|
CopyMem (
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,
|
|
OutputKey + EncryptAlgKeyLen,
|
|
IntegrityAlgKeyLen
|
|
);
|
|
|
|
//
|
|
// Responder Encryption Key
|
|
//
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncAlgoId = (UINT8)SaParams->EncAlgId;
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKeyLength = EncryptAlgKeyLen;
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey = AllocateZeroPool (EncryptAlgKeyLen);
|
|
|
|
CopyMem (
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,
|
|
OutputKey + EncryptAlgKeyLen + IntegrityAlgKeyLen,
|
|
EncryptAlgKeyLen
|
|
);
|
|
|
|
//
|
|
// Responder Authentication Key
|
|
//
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthAlgoId = (UINT8)SaParams->IntegAlgId;
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKeyLength = IntegrityAlgKeyLen;
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey = AllocateZeroPool (IntegrityAlgKeyLen);
|
|
|
|
CopyMem (
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,
|
|
OutputKey + 2 * EncryptAlgKeyLen + IntegrityAlgKeyLen,
|
|
IntegrityAlgKeyLen
|
|
);
|
|
}
|
|
|
|
IPSEC_DUMP_BUF (
|
|
" >>> Local Encryption Key",
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey,
|
|
EncryptAlgKeyLen
|
|
);
|
|
IPSEC_DUMP_BUF (
|
|
" >>> Remote Encryption Key",
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey,
|
|
EncryptAlgKeyLen
|
|
);
|
|
IPSEC_DUMP_BUF (
|
|
" >>> Local Authentication Key",
|
|
ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey,
|
|
IntegrityAlgKeyLen
|
|
);
|
|
IPSEC_DUMP_BUF (
|
|
" >>> Remote Authentication Key",
|
|
ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey,
|
|
IntegrityAlgKeyLen
|
|
);
|
|
|
|
FreePool (OutputKey);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER mIkev2Initial[][2] = {
|
|
{ //PSK
|
|
{ // IKEV2_INIT
|
|
Ikev2InitPskParser,
|
|
Ikev2InitPskGenerator
|
|
},
|
|
{ //IKEV2_AUTH
|
|
Ikev2AuthPskParser,
|
|
Ikev2AuthPskGenerator
|
|
}
|
|
},
|
|
{ // CERT
|
|
{ // IKEV2_INIT
|
|
Ikev2InitCertParser,
|
|
Ikev2InitCertGenerator
|
|
},
|
|
{ // IKEV2_AUTH
|
|
Ikev2AuthCertParser,
|
|
Ikev2AuthCertGenerator
|
|
},
|
|
},
|
|
};
|