audk/NetworkPkg/IpSecDxe/Ikev2/Sa.c

2262 lines
70 KiB
C

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