mirror of https://github.com/acidanthera/audk.git
3367 lines
110 KiB
C
3367 lines
110 KiB
C
/** @file
|
|
The implementation of Payloads Creation.
|
|
|
|
(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
|
|
Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php.
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include "Utility.h"
|
|
#include "IpSecDebug.h"
|
|
#include "IpSecConfigImpl.h"
|
|
#include "IpSecCryptIo.h"
|
|
|
|
//
|
|
// The Constant String of "Key Pad for IKEv2" for Authentication Payload generation.
|
|
//
|
|
#define CONSTANT_KEY_SIZE 17
|
|
GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 mConstantKey[CONSTANT_KEY_SIZE] =
|
|
{
|
|
'K', 'e', 'y', ' ', 'P', 'a', 'd', ' ', 'f', 'o', 'r', ' ', 'I', 'K', 'E', 'v', '2'
|
|
};
|
|
|
|
/**
|
|
Generate Ikev2 SA payload according to SessionSaData
|
|
|
|
@param[in] SessionSaData The data used in SA payload.
|
|
@param[in] NextPayload The payload type presented in NextPayload field of
|
|
SA Payload header.
|
|
@param[in] Type The SA type. It MUST be neither (1) for IKE_SA or
|
|
(2) for CHILD_SA or (3) for INFO.
|
|
|
|
@retval a Pointer to SA IKE payload.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2GenerateSaPayload (
|
|
IN IKEV2_SA_DATA *SessionSaData,
|
|
IN UINT8 NextPayload,
|
|
IN IKE_SESSION_TYPE Type
|
|
)
|
|
{
|
|
IKE_PAYLOAD *SaPayload;
|
|
IKEV2_SA_DATA *SaData;
|
|
UINTN SaDataSize;
|
|
|
|
SaPayload = IkePayloadAlloc ();
|
|
if (SaPayload == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// TODO: Get the Proposal Number and Transform Number from IPsec Config,
|
|
// after the Ipsecconfig Application is support it.
|
|
//
|
|
|
|
if (Type == IkeSessionTypeIkeSa) {
|
|
SaDataSize = sizeof (IKEV2_SA_DATA) +
|
|
SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) +
|
|
sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 4;
|
|
} else {
|
|
SaDataSize = sizeof (IKEV2_SA_DATA) +
|
|
SessionSaData->NumProposals * sizeof (IKEV2_PROPOSAL_DATA) +
|
|
sizeof (IKEV2_TRANSFORM_DATA) * SessionSaData->NumProposals * 3;
|
|
|
|
}
|
|
|
|
SaData = AllocateZeroPool (SaDataSize);
|
|
if (SaData == NULL) {
|
|
IkePayloadFree (SaPayload);
|
|
return NULL;
|
|
}
|
|
|
|
CopyMem (SaData, SessionSaData, SaDataSize);
|
|
SaData->SaHeader.Header.NextPayload = NextPayload;
|
|
SaPayload->PayloadType = IKEV2_PAYLOAD_TYPE_SA;
|
|
SaPayload->PayloadBuf = (UINT8 *) SaData;
|
|
|
|
return SaPayload;
|
|
}
|
|
|
|
/**
|
|
Generate a Nonce payload containing the input parameter NonceBuf.
|
|
|
|
@param[in] NonceBuf The nonce buffer contains the whole Nonce payload block
|
|
except the payload header.
|
|
@param[in] NonceSize The buffer size of the NonceBuf
|
|
@param[in] NextPayload The payload type presented in the NextPayload field
|
|
of Nonce Payload header.
|
|
|
|
@retval Pointer to Nonce IKE paload.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2GenerateNoncePayload (
|
|
IN UINT8 *NonceBuf,
|
|
IN UINTN NonceSize,
|
|
IN UINT8 NextPayload
|
|
)
|
|
{
|
|
IKE_PAYLOAD *NoncePayload;
|
|
IKEV2_NONCE *Nonce;
|
|
UINTN Size;
|
|
UINT8 *NonceBlock;
|
|
|
|
// 1 2 3
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload !C! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Nonce Data ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
Size = sizeof (IKEV2_NONCE) + NonceSize;
|
|
NonceBlock = NonceBuf;
|
|
|
|
Nonce = AllocateZeroPool (Size);
|
|
if (Nonce == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
CopyMem (Nonce + 1, NonceBlock, Size - sizeof (IKEV2_NONCE));
|
|
|
|
Nonce->Header.NextPayload = NextPayload;
|
|
Nonce->Header.PayloadLength = (UINT16) Size;
|
|
NoncePayload = IkePayloadAlloc ();
|
|
if (NoncePayload == NULL) {
|
|
FreePool (Nonce);
|
|
return NULL;
|
|
}
|
|
|
|
NoncePayload->PayloadType = IKEV2_PAYLOAD_TYPE_NONCE;
|
|
NoncePayload->PayloadBuf = (UINT8 *) Nonce;
|
|
NoncePayload->PayloadSize = Size;
|
|
|
|
return NoncePayload;
|
|
}
|
|
|
|
/**
|
|
Generate a Key Exchange payload according to the DH group type and save the
|
|
public Key into IkeSaSession IkeKey field.
|
|
|
|
@param[in, out] IkeSaSession Pointer of the IKE_SA_SESSION.
|
|
@param[in] NextPayload The payload type presented in the NextPayload field of Key
|
|
Exchange Payload header.
|
|
|
|
@retval Pointer to Key IKE payload.
|
|
|
|
**/
|
|
IKE_PAYLOAD*
|
|
Ikev2GenerateKePayload (
|
|
IN OUT IKEV2_SA_SESSION *IkeSaSession,
|
|
IN UINT8 NextPayload
|
|
)
|
|
{
|
|
IKE_PAYLOAD *KePayload;
|
|
IKEV2_KEY_EXCHANGE *Ke;
|
|
UINTN KeSize;
|
|
IKEV2_SESSION_KEYS *IkeKeys;
|
|
|
|
//
|
|
// 1 2 3
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload !C! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! DH Group # ! RESERVED !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Key Exchange Data ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
IkeKeys = IkeSaSession->IkeKeys;
|
|
|
|
if (IkeSaSession->SessionCommon.IsInitiator) {
|
|
KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize;
|
|
} else {
|
|
KeSize = sizeof (IKEV2_KEY_EXCHANGE) + IkeKeys->DhBuffer->GxSize;
|
|
}
|
|
|
|
//
|
|
// Allocate buffer for Key Exchange
|
|
//
|
|
Ke = AllocateZeroPool (KeSize);
|
|
if (Ke == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
Ke->Header.NextPayload = NextPayload;
|
|
Ke->Header.PayloadLength = (UINT16) KeSize;
|
|
Ke->DhGroup = IkeSaSession->SessionCommon.PreferDhGroup;
|
|
|
|
CopyMem (Ke + 1, IkeKeys->DhBuffer->GxBuffer, IkeKeys->DhBuffer->GxSize);
|
|
|
|
//
|
|
// Create IKE_PAYLOAD to point to Key Exchange payload
|
|
//
|
|
KePayload = IkePayloadAlloc ();
|
|
if (KePayload == NULL) {
|
|
FreePool (Ke);
|
|
return NULL;
|
|
}
|
|
|
|
KePayload->PayloadType = IKEV2_PAYLOAD_TYPE_KE;
|
|
KePayload->PayloadBuf = (UINT8 *) Ke;
|
|
KePayload->PayloadSize = KeSize;
|
|
return KePayload;
|
|
}
|
|
|
|
/**
|
|
Generate a ID payload.
|
|
|
|
@param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload.
|
|
@param[in] NextPayload The payload type presented in the NextPayload field
|
|
of ID Payload header.
|
|
|
|
@retval Pointer to ID IKE payload.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2GenerateIdPayload (
|
|
IN IKEV2_SESSION_COMMON *CommonSession,
|
|
IN UINT8 NextPayload
|
|
)
|
|
{
|
|
IKE_PAYLOAD *IdPayload;
|
|
IKEV2_ID *Id;
|
|
UINTN IdSize;
|
|
UINT8 IpVersion;
|
|
UINT8 AddrSize;
|
|
|
|
//
|
|
// ID payload
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload ! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! ID Type ! RESERVED !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Identification Data ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
|
|
IpVersion = CommonSession->UdpService->IpVersion;
|
|
AddrSize = (UINT8) ((IpVersion == IP_VERSION_4) ? sizeof(EFI_IPv4_ADDRESS) : sizeof(EFI_IPv6_ADDRESS));
|
|
IdSize = sizeof (IKEV2_ID) + AddrSize;
|
|
|
|
Id = (IKEV2_ID *) AllocateZeroPool (IdSize);
|
|
if (Id == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
IdPayload = IkePayloadAlloc ();
|
|
if (IdPayload == NULL) {
|
|
FreePool (Id);
|
|
return NULL;
|
|
}
|
|
|
|
IdPayload->PayloadType = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP);
|
|
IdPayload->PayloadBuf = (UINT8 *) Id;
|
|
IdPayload->PayloadSize = IdSize;
|
|
|
|
//
|
|
// Set generic header of identification payload
|
|
//
|
|
Id->Header.NextPayload = NextPayload;
|
|
Id->Header.PayloadLength = (UINT16) IdSize;
|
|
Id->IdType = (UINT8) ((IpVersion == IP_VERSION_4) ? IKEV2_ID_TYPE_IPV4_ADDR : IKEV2_ID_TYPE_IPV6_ADDR);
|
|
CopyMem (Id + 1, &CommonSession->LocalPeerIp, AddrSize);
|
|
|
|
return IdPayload;
|
|
}
|
|
|
|
/**
|
|
Generate a ID payload.
|
|
|
|
@param[in] CommonSession Pointer to IKEV2_SESSION_COMMON related to ID payload.
|
|
@param[in] NextPayload The payload type presented in the NextPayload field
|
|
of ID Payload header.
|
|
@param[in] InCert Pointer to the Certificate which distinguished name
|
|
will be added into the Id payload.
|
|
@param[in] CertSize Size of the Certificate.
|
|
|
|
@retval Pointer to ID IKE payload.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2GenerateCertIdPayload (
|
|
IN IKEV2_SESSION_COMMON *CommonSession,
|
|
IN UINT8 NextPayload,
|
|
IN UINT8 *InCert,
|
|
IN UINTN CertSize
|
|
)
|
|
{
|
|
IKE_PAYLOAD *IdPayload;
|
|
IKEV2_ID *Id;
|
|
UINTN IdSize;
|
|
UINTN SubjectSize;
|
|
UINT8 *CertSubject;
|
|
|
|
//
|
|
// ID payload
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload ! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! ID Type ! RESERVED !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Identification Data ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
|
|
SubjectSize = 0;
|
|
CertSubject = NULL;
|
|
IpSecCryptoIoGetSubjectFromCert (
|
|
InCert,
|
|
CertSize,
|
|
&CertSubject,
|
|
&SubjectSize
|
|
);
|
|
if (SubjectSize != 0) {
|
|
ASSERT (CertSubject != NULL);
|
|
}
|
|
|
|
IdSize = sizeof (IKEV2_ID) + SubjectSize;
|
|
|
|
Id = (IKEV2_ID *) AllocateZeroPool (IdSize);
|
|
if (Id == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
IdPayload = IkePayloadAlloc ();
|
|
if (IdPayload == NULL) {
|
|
FreePool (Id);
|
|
return NULL;
|
|
}
|
|
|
|
IdPayload->PayloadType = (UINT8) ((CommonSession->IsInitiator) ? IKEV2_PAYLOAD_TYPE_ID_INIT : IKEV2_PAYLOAD_TYPE_ID_RSP);
|
|
IdPayload->PayloadBuf = (UINT8 *) Id;
|
|
IdPayload->PayloadSize = IdSize;
|
|
|
|
//
|
|
// Set generic header of identification payload
|
|
//
|
|
Id->Header.NextPayload = NextPayload;
|
|
Id->Header.PayloadLength = (UINT16) IdSize;
|
|
Id->IdType = 9;
|
|
CopyMem (Id + 1, CertSubject, SubjectSize);
|
|
|
|
if (CertSubject != NULL) {
|
|
FreePool (CertSubject);
|
|
}
|
|
return IdPayload;
|
|
}
|
|
|
|
/**
|
|
Generate a Authentication Payload.
|
|
|
|
This function is used for both Authentication generation and verification. When the
|
|
IsVerify is TRUE, it create a Auth Data for verification. This function choose the
|
|
related IKE_SA_INIT Message for Auth data creation according to the IKE Session's type
|
|
and the value of IsVerify parameter.
|
|
|
|
@param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to.
|
|
@param[in] IdPayload Pointer to the ID payload to be used for Authentication
|
|
payload generation.
|
|
@param[in] NextPayload The type filled into the Authentication Payload next
|
|
payload field.
|
|
@param[in] IsVerify If it is TURE, the Authentication payload is used for
|
|
verification.
|
|
|
|
@return pointer to IKE Authentication payload for Pre-shared key method.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2PskGenerateAuthPayload (
|
|
IN IKEV2_SA_SESSION *IkeSaSession,
|
|
IN IKE_PAYLOAD *IdPayload,
|
|
IN UINT8 NextPayload,
|
|
IN BOOLEAN IsVerify
|
|
)
|
|
{
|
|
UINT8 *Digest;
|
|
UINTN DigestSize;
|
|
PRF_DATA_FRAGMENT Fragments[3];
|
|
UINT8 *KeyBuf;
|
|
UINTN KeySize;
|
|
IKE_PAYLOAD *AuthPayload;
|
|
IKEV2_AUTH *PayloadBuf;
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Auth = Prf(Prf(Secret,"Key Pad for IKEv2),IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
|
|
//
|
|
// 1 2 3
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload !C! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Auth Method ! RESERVED !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Authentication Data ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
|
|
KeyBuf = NULL;
|
|
AuthPayload = NULL;
|
|
Digest = NULL;
|
|
|
|
DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf);
|
|
Digest = AllocateZeroPool (DigestSize);
|
|
if (Digest == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (IdPayload == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Calcualte Prf(Seceret, "Key Pad for IKEv2");
|
|
//
|
|
Fragments[0].Data = (UINT8 *) mConstantKey;
|
|
Fragments[0].DataSize = CONSTANT_KEY_SIZE;
|
|
|
|
Status = IpSecCryptoIoHmac (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
|
|
IkeSaSession->Pad->Data->AuthData,
|
|
IkeSaSession->Pad->Data->AuthDataSize,
|
|
(HASH_DATA_FRAGMENT *)Fragments,
|
|
1,
|
|
Digest,
|
|
DigestSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Store the AuthKey into KeyBuf
|
|
//
|
|
KeyBuf = AllocateZeroPool (DigestSize);
|
|
if (KeyBuf == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
CopyMem (KeyBuf, Digest, DigestSize);
|
|
KeySize = DigestSize;
|
|
|
|
//
|
|
// Calculate Prf(SK_Pi/r, IDi/r)
|
|
//
|
|
Fragments[0].Data = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
|
|
Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
|
|
|
|
if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
|
|
(!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
|
|
) {
|
|
Status = IpSecCryptoIoHmac (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
|
|
IkeSaSession->IkeKeys->SkPrKey,
|
|
IkeSaSession->IkeKeys->SkPrKeySize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
1,
|
|
Digest,
|
|
DigestSize
|
|
);
|
|
} else {
|
|
Status = IpSecCryptoIoHmac (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
|
|
IkeSaSession->IkeKeys->SkPiKey,
|
|
IkeSaSession->IkeKeys->SkPiKeySize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
1,
|
|
Digest,
|
|
DigestSize
|
|
);
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Copy data to Fragments.
|
|
//
|
|
if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
|
|
(!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
|
|
) {
|
|
Fragments[0].Data = IkeSaSession->RespPacket;
|
|
Fragments[0].DataSize = IkeSaSession->RespPacketSize;
|
|
Fragments[1].Data = IkeSaSession->NiBlock;
|
|
Fragments[1].DataSize = IkeSaSession->NiBlkSize;
|
|
} else {
|
|
Fragments[0].Data = IkeSaSession->InitPacket;
|
|
Fragments[0].DataSize = IkeSaSession->InitPacketSize;
|
|
Fragments[1].Data = IkeSaSession->NrBlock;
|
|
Fragments[1].DataSize = IkeSaSession->NrBlkSize;
|
|
}
|
|
|
|
//
|
|
// Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2].
|
|
//
|
|
Fragments[2].Data = AllocateZeroPool (DigestSize);
|
|
if (Fragments[2].Data == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
Fragments[2].DataSize = DigestSize;
|
|
CopyMem (Fragments[2].Data, Digest, DigestSize);
|
|
|
|
//
|
|
// Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
|
|
//
|
|
Status = IpSecCryptoIoHmac (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
|
|
KeyBuf,
|
|
KeySize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
3,
|
|
Digest,
|
|
DigestSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Allocate buffer for Auth Payload
|
|
//
|
|
AuthPayload = IkePayloadAlloc ();
|
|
if (AuthPayload == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
AuthPayload->PayloadSize = sizeof (IKEV2_AUTH) + DigestSize;
|
|
PayloadBuf = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize);
|
|
if (PayloadBuf == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Fill in Auth payload.
|
|
//
|
|
PayloadBuf->Header.NextPayload = NextPayload;
|
|
PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize);
|
|
if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodPreSharedSecret) {
|
|
//
|
|
// Only support Shared Key Message Integrity
|
|
//
|
|
PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_SKMI;
|
|
} else {
|
|
//
|
|
// Not support other Auth method.
|
|
//
|
|
Status = EFI_UNSUPPORTED;
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth
|
|
// payload block.
|
|
//
|
|
CopyMem (
|
|
PayloadBuf + 1,
|
|
Digest,
|
|
DigestSize
|
|
);
|
|
|
|
//
|
|
// Fill in IKE_PACKET
|
|
//
|
|
AuthPayload->PayloadBuf = (UINT8 *) PayloadBuf;
|
|
AuthPayload->PayloadType = IKEV2_PAYLOAD_TYPE_AUTH;
|
|
|
|
EXIT:
|
|
if (KeyBuf != NULL) {
|
|
FreePool (KeyBuf);
|
|
}
|
|
if (Digest != NULL) {
|
|
FreePool (Digest);
|
|
}
|
|
if (Fragments[2].Data != NULL) {
|
|
//
|
|
// Free the buffer which contains the result of Prf(SK_Pr, IDi/r)
|
|
//
|
|
FreePool (Fragments[2].Data);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
if (AuthPayload != NULL) {
|
|
IkePayloadFree (AuthPayload);
|
|
}
|
|
return NULL;
|
|
} else {
|
|
return AuthPayload;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Generate a Authentication Payload for Certificate Auth method.
|
|
|
|
This function has two functions. One is creating a local Authentication
|
|
Payload for sending and other is creating the remote Authentication data
|
|
for verification when the IsVerify is TURE.
|
|
|
|
@param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to.
|
|
@param[in] IdPayload Pointer to the ID payload to be used for Authentication
|
|
payload generation.
|
|
@param[in] NextPayload The type filled into the Authentication Payload
|
|
next payload field.
|
|
@param[in] IsVerify If it is TURE, the Authentication payload is used
|
|
for verification.
|
|
@param[in] UefiPrivateKey Pointer to the UEFI private key. Ignore it when
|
|
verify the authenticate payload.
|
|
@param[in] UefiPrivateKeyLen The size of UefiPrivateKey in bytes. Ignore it
|
|
when verify the authenticate payload.
|
|
@param[in] UefiKeyPwd Pointer to the password of UEFI private key.
|
|
Ignore it when verify the authenticate payload.
|
|
@param[in] UefiKeyPwdLen The size of UefiKeyPwd in bytes.Ignore it when
|
|
verify the authenticate payload.
|
|
|
|
@return pointer to IKE Authentication payload for Cerifitcation method.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2CertGenerateAuthPayload (
|
|
IN IKEV2_SA_SESSION *IkeSaSession,
|
|
IN IKE_PAYLOAD *IdPayload,
|
|
IN UINT8 NextPayload,
|
|
IN BOOLEAN IsVerify,
|
|
IN UINT8 *UefiPrivateKey,
|
|
IN UINTN UefiPrivateKeyLen,
|
|
IN UINT8 *UefiKeyPwd,
|
|
IN UINTN UefiKeyPwdLen
|
|
)
|
|
{
|
|
UINT8 *Digest;
|
|
UINTN DigestSize;
|
|
PRF_DATA_FRAGMENT Fragments[3];
|
|
UINT8 *KeyBuf;
|
|
IKE_PAYLOAD *AuthPayload;
|
|
IKEV2_AUTH *PayloadBuf;
|
|
EFI_STATUS Status;
|
|
UINT8 *Signature;
|
|
UINTN SigSize;
|
|
|
|
//
|
|
// Auth = Prf(Scert,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
|
|
//
|
|
// 1 2 3
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload !C! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Auth Method ! RESERVED !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Authentication Data ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
//
|
|
// Initial point
|
|
//
|
|
KeyBuf = NULL;
|
|
AuthPayload = NULL;
|
|
Digest = NULL;
|
|
Signature = NULL;
|
|
SigSize = 0;
|
|
|
|
if (IdPayload == NULL) {
|
|
return NULL;
|
|
}
|
|
DigestSize = IpSecGetHmacDigestLength ((UINT8)IkeSaSession->SessionCommon.SaParams->Prf);
|
|
Digest = AllocateZeroPool (DigestSize);
|
|
if (Digest == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Store the AuthKey into KeyBuf
|
|
//
|
|
KeyBuf = AllocateZeroPool (DigestSize);
|
|
if (KeyBuf == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
CopyMem (KeyBuf, Digest, DigestSize);
|
|
|
|
//
|
|
// Calculate Prf(SK_Pi/r, IDi/r)
|
|
//
|
|
Fragments[0].Data = IdPayload->PayloadBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
|
|
Fragments[0].DataSize = IdPayload->PayloadSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER);
|
|
|
|
IpSecDumpBuf ("RestofIDPayload", Fragments[0].Data, Fragments[0].DataSize);
|
|
|
|
if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
|
|
(!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
|
|
) {
|
|
Status = IpSecCryptoIoHmac(
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
|
|
IkeSaSession->IkeKeys->SkPrKey,
|
|
IkeSaSession->IkeKeys->SkPrKeySize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
1,
|
|
Digest,
|
|
DigestSize
|
|
);
|
|
IpSecDumpBuf ("MACedIDForR", Digest, DigestSize);
|
|
} else {
|
|
Status = IpSecCryptoIoHmac (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
|
|
IkeSaSession->IkeKeys->SkPiKey,
|
|
IkeSaSession->IkeKeys->SkPiKeySize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
1,
|
|
Digest,
|
|
DigestSize
|
|
);
|
|
IpSecDumpBuf ("MACedIDForI", Digest, DigestSize);
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Copy data to Fragments.
|
|
//
|
|
if ((IkeSaSession->SessionCommon.IsInitiator && IsVerify) ||
|
|
(!IkeSaSession->SessionCommon.IsInitiator && !IsVerify)
|
|
) {
|
|
Fragments[0].Data = IkeSaSession->RespPacket;
|
|
Fragments[0].DataSize = IkeSaSession->RespPacketSize;
|
|
Fragments[1].Data = IkeSaSession->NiBlock;
|
|
Fragments[1].DataSize = IkeSaSession->NiBlkSize;
|
|
IpSecDumpBuf ("RealMessage2", Fragments[0].Data, Fragments[0].DataSize);
|
|
IpSecDumpBuf ("NonceIDdata", Fragments[1].Data, Fragments[1].DataSize);
|
|
} else {
|
|
Fragments[0].Data = IkeSaSession->InitPacket;
|
|
Fragments[0].DataSize = IkeSaSession->InitPacketSize;
|
|
Fragments[1].Data = IkeSaSession->NrBlock;
|
|
Fragments[1].DataSize = IkeSaSession->NrBlkSize;
|
|
IpSecDumpBuf ("RealMessage1", Fragments[0].Data, Fragments[0].DataSize);
|
|
IpSecDumpBuf ("NonceRDdata", Fragments[1].Data, Fragments[1].DataSize);
|
|
}
|
|
|
|
//
|
|
// Copy the result of Prf(SK_Pr, IDi/r) to Fragments[2].
|
|
//
|
|
Fragments[2].Data = AllocateZeroPool (DigestSize);
|
|
if (Fragments[2].Data == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
Fragments[2].DataSize = DigestSize;
|
|
CopyMem (Fragments[2].Data, Digest, DigestSize);
|
|
|
|
//
|
|
// Calculate Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r))
|
|
//
|
|
Status = IpSecCryptoIoHash (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->Prf,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
3,
|
|
Digest,
|
|
DigestSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto EXIT;
|
|
}
|
|
|
|
IpSecDumpBuf ("HashSignedOctects", Digest, DigestSize);
|
|
//
|
|
// Sign the data by the private Key
|
|
//
|
|
if (!IsVerify) {
|
|
IpSecCryptoIoAuthDataWithCertificate (
|
|
Digest,
|
|
DigestSize,
|
|
UefiPrivateKey,
|
|
UefiPrivateKeyLen,
|
|
UefiKeyPwd,
|
|
UefiKeyPwdLen,
|
|
&Signature,
|
|
&SigSize
|
|
);
|
|
|
|
if (SigSize == 0 || Signature == NULL) {
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate buffer for Auth Payload
|
|
//
|
|
AuthPayload = IkePayloadAlloc ();
|
|
if (AuthPayload == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
if (!IsVerify) {
|
|
AuthPayload->PayloadSize = sizeof (IKEV2_AUTH) + SigSize;
|
|
} else {
|
|
AuthPayload->PayloadSize = sizeof (IKEV2_AUTH) + DigestSize;
|
|
}
|
|
|
|
PayloadBuf = (IKEV2_AUTH *) AllocateZeroPool (AuthPayload->PayloadSize);
|
|
if (PayloadBuf == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Fill in Auth payload.
|
|
//
|
|
PayloadBuf->Header.NextPayload = NextPayload;
|
|
PayloadBuf->Header.PayloadLength = (UINT16) (AuthPayload->PayloadSize);
|
|
if (IkeSaSession->Pad->Data->AuthMethod == EfiIPsecAuthMethodCertificates) {
|
|
PayloadBuf->AuthMethod = IKEV2_AUTH_METHOD_RSA;
|
|
} else {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto EXIT;
|
|
}
|
|
|
|
//
|
|
// Copy the result of Prf(Key,IKE_SA_INIi/r|Ni/r|Prf(SK_Pr, IDi/r)) to Auth
|
|
// payload block.
|
|
//
|
|
if (!IsVerify) {
|
|
CopyMem (PayloadBuf + 1, Signature, SigSize);
|
|
} else {
|
|
CopyMem (PayloadBuf + 1, Digest, DigestSize);
|
|
}
|
|
|
|
//
|
|
// Fill in IKE_PACKET
|
|
//
|
|
AuthPayload->PayloadBuf = (UINT8 *) PayloadBuf;
|
|
AuthPayload->PayloadType = IKEV2_PAYLOAD_TYPE_AUTH;
|
|
|
|
EXIT:
|
|
if (KeyBuf != NULL) {
|
|
FreePool (KeyBuf);
|
|
}
|
|
if (Digest != NULL) {
|
|
FreePool (Digest);
|
|
}
|
|
if (Signature != NULL) {
|
|
FreePool (Signature);
|
|
}
|
|
if (Fragments[2].Data != NULL) {
|
|
//
|
|
// Free the buffer which contains the result of Prf(SK_Pr, IDi/r)
|
|
//
|
|
FreePool (Fragments[2].Data);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
if (AuthPayload != NULL) {
|
|
IkePayloadFree (AuthPayload);
|
|
}
|
|
return NULL;
|
|
} else {
|
|
return AuthPayload;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Generate TS payload.
|
|
|
|
This function generates TSi or TSr payload according to type of next payload.
|
|
If the next payload is Responder TS, gereate TSi Payload. Otherwise, generate
|
|
TSr payload.
|
|
|
|
@param[in] ChildSa Pointer to IKEV2_CHILD_SA_SESSION related to this TS payload.
|
|
@param[in] NextPayload The payload type presented in the NextPayload field
|
|
of ID Payload header.
|
|
@param[in] IsTunnel It indicates that if the Ts Payload is after the CP payload.
|
|
If yes, it means the Tsi and Tsr payload should be with
|
|
Max port range and address range and protocol is marked
|
|
as zero.
|
|
|
|
@retval Pointer to Ts IKE payload.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2GenerateTsPayload (
|
|
IN IKEV2_CHILD_SA_SESSION *ChildSa,
|
|
IN UINT8 NextPayload,
|
|
IN BOOLEAN IsTunnel
|
|
)
|
|
{
|
|
IKE_PAYLOAD *TsPayload;
|
|
IKEV2_TS *TsPayloadBuf;
|
|
TRAFFIC_SELECTOR *TsSelector;
|
|
UINTN SelectorSize;
|
|
UINTN TsPayloadSize;
|
|
UINT8 IpVersion;
|
|
UINT8 AddrSize;
|
|
|
|
//
|
|
// 1 2 3
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload !C! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Number of TSs ! RESERVED !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ <Traffic Selectors> ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
|
|
TsPayload = IkePayloadAlloc();
|
|
if (TsPayload == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
IpVersion = ChildSa->SessionCommon.UdpService->IpVersion;
|
|
//
|
|
// The Starting Address and Ending Address is variable length depends on
|
|
// is IPv4 or IPv6
|
|
//
|
|
AddrSize = (UINT8)((IpVersion == IP_VERSION_4) ? sizeof (EFI_IPv4_ADDRESS) : sizeof (EFI_IPv6_ADDRESS));
|
|
SelectorSize = sizeof (TRAFFIC_SELECTOR) + 2 * AddrSize;
|
|
TsPayloadSize = sizeof (IKEV2_TS) + SelectorSize;
|
|
TsPayloadBuf = AllocateZeroPool (TsPayloadSize);
|
|
if (TsPayloadBuf == NULL) {
|
|
goto ON_ERROR;
|
|
}
|
|
|
|
TsPayload->PayloadBuf = (UINT8 *) TsPayloadBuf;
|
|
TsSelector = (TRAFFIC_SELECTOR*)(TsPayloadBuf + 1);
|
|
|
|
TsSelector->TSType = (UINT8)((IpVersion == IP_VERSION_4) ? IKEV2_TS_TYPE_IPV4_ADDR_RANGE : IKEV2_TS_TYPS_IPV6_ADDR_RANGE);
|
|
|
|
//
|
|
// For tunnel mode
|
|
//
|
|
if (IsTunnel) {
|
|
TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL;
|
|
TsSelector->SelecorLen = (UINT16) SelectorSize;
|
|
TsSelector->StartPort = 0;
|
|
TsSelector->EndPort = IKEV2_TS_ANY_PORT;
|
|
ZeroMem ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR), AddrSize);
|
|
SetMem ((UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize, AddrSize, 0xff);
|
|
|
|
} else {
|
|
//
|
|
// TODO: Support port range and address range
|
|
//
|
|
if (NextPayload == IKEV2_PAYLOAD_TYPE_TS_RSP){
|
|
//
|
|
// Create initiator Traffic Selector
|
|
//
|
|
TsSelector->SelecorLen = (UINT16)SelectorSize;
|
|
|
|
//
|
|
// Currently only support the port range from 0~0xffff. Don't support other
|
|
// port range.
|
|
// TODO: support Port range
|
|
//
|
|
if (ChildSa->SessionCommon.IsInitiator) {
|
|
if (ChildSa->Spd->Selector->LocalPort != 0 &&
|
|
ChildSa->Spd->Selector->LocalPortRange == 0) {
|
|
//
|
|
// For not port range.
|
|
//
|
|
TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort;
|
|
TsSelector->EndPort = ChildSa->Spd->Selector->LocalPort;
|
|
} else if (ChildSa->Spd->Selector->LocalPort == 0){
|
|
//
|
|
// For port from 0~0xffff
|
|
//
|
|
TsSelector->StartPort = 0;
|
|
TsSelector->EndPort = IKEV2_TS_ANY_PORT;
|
|
} else {
|
|
//
|
|
// Not support now.
|
|
//
|
|
goto ON_ERROR;
|
|
}
|
|
} else {
|
|
if (ChildSa->Spd->Selector->RemotePort != 0 &&
|
|
ChildSa->Spd->Selector->RemotePortRange == 0) {
|
|
//
|
|
// For not port range.
|
|
//
|
|
TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort;
|
|
TsSelector->EndPort = ChildSa->Spd->Selector->RemotePort;
|
|
} else if (ChildSa->Spd->Selector->RemotePort == 0) {
|
|
//
|
|
// For port from 0~0xffff
|
|
//
|
|
TsSelector->StartPort = 0;
|
|
TsSelector->EndPort = IKEV2_TS_ANY_PORT;
|
|
} else {
|
|
//
|
|
// Not support now.
|
|
//
|
|
goto ON_ERROR;
|
|
}
|
|
}
|
|
//
|
|
// Copy Address.Currently the address range is not supported.
|
|
// The Starting address is same as Ending address
|
|
// TODO: Support Address Range.
|
|
//
|
|
CopyMem (
|
|
(UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR),
|
|
ChildSa->SessionCommon.IsInitiator ?
|
|
ChildSa->Spd->Selector->LocalAddress :
|
|
ChildSa->Spd->Selector->RemoteAddress,
|
|
AddrSize
|
|
);
|
|
CopyMem (
|
|
(UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize,
|
|
ChildSa->SessionCommon.IsInitiator ?
|
|
ChildSa->Spd->Selector->LocalAddress :
|
|
ChildSa->Spd->Selector->RemoteAddress,
|
|
AddrSize
|
|
);
|
|
//
|
|
// If the Next Payload is not TS responder, this TS payload type is the TS responder.
|
|
//
|
|
TsPayload->PayloadType = IKEV2_PAYLOAD_TYPE_TS_INIT;
|
|
}else{
|
|
//
|
|
// Create responder Traffic Selector
|
|
//
|
|
TsSelector->SelecorLen = (UINT16)SelectorSize;
|
|
|
|
//
|
|
// Currently only support the port range from 0~0xffff. Don't support other
|
|
// port range.
|
|
// TODO: support Port range
|
|
//
|
|
if (!ChildSa->SessionCommon.IsInitiator) {
|
|
if (ChildSa->Spd->Selector->LocalPort != 0 &&
|
|
ChildSa->Spd->Selector->LocalPortRange == 0) {
|
|
//
|
|
// For not port range.
|
|
//
|
|
TsSelector->StartPort = ChildSa->Spd->Selector->LocalPort;
|
|
TsSelector->EndPort = ChildSa->Spd->Selector->LocalPort;
|
|
} else if (ChildSa->Spd->Selector->LocalPort == 0){
|
|
//
|
|
// For port from 0~0xffff
|
|
//
|
|
TsSelector->StartPort = 0;
|
|
TsSelector->EndPort = IKEV2_TS_ANY_PORT;
|
|
} else {
|
|
//
|
|
// Not support now.
|
|
//
|
|
goto ON_ERROR;
|
|
}
|
|
} else {
|
|
if (ChildSa->Spd->Selector->RemotePort != 0 &&
|
|
ChildSa->Spd->Selector->RemotePortRange == 0) {
|
|
//
|
|
// For not port range.
|
|
//
|
|
TsSelector->StartPort = ChildSa->Spd->Selector->RemotePort;
|
|
TsSelector->EndPort = ChildSa->Spd->Selector->RemotePort;
|
|
} else if (ChildSa->Spd->Selector->RemotePort == 0){
|
|
//
|
|
// For port from 0~0xffff
|
|
//
|
|
TsSelector->StartPort = 0;
|
|
TsSelector->EndPort = IKEV2_TS_ANY_PORT;
|
|
} else {
|
|
//
|
|
// Not support now.
|
|
//
|
|
goto ON_ERROR;
|
|
}
|
|
}
|
|
//
|
|
// Copy Address.Currently the address range is not supported.
|
|
// The Starting address is same as Ending address
|
|
// TODO: Support Address Range.
|
|
//
|
|
CopyMem (
|
|
(UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR),
|
|
ChildSa->SessionCommon.IsInitiator ?
|
|
ChildSa->Spd->Selector->RemoteAddress :
|
|
ChildSa->Spd->Selector->LocalAddress,
|
|
AddrSize
|
|
);
|
|
CopyMem (
|
|
(UINT8*)TsSelector + sizeof(TRAFFIC_SELECTOR) + AddrSize,
|
|
ChildSa->SessionCommon.IsInitiator ?
|
|
ChildSa->Spd->Selector->RemoteAddress :
|
|
ChildSa->Spd->Selector->LocalAddress,
|
|
AddrSize
|
|
);
|
|
//
|
|
// If the Next Payload is not TS responder, this TS payload type is the TS responder.
|
|
//
|
|
TsPayload->PayloadType = IKEV2_PAYLOAD_TYPE_TS_RSP;
|
|
}
|
|
}
|
|
|
|
if (ChildSa->Spd->Selector->NextLayerProtocol != 0xffff) {
|
|
TsSelector->IpProtocolId = (UINT8)ChildSa->Spd->Selector->NextLayerProtocol;
|
|
} else {
|
|
TsSelector->IpProtocolId = IKEV2_TS_ANY_PROTOCOL;
|
|
}
|
|
|
|
TsPayloadBuf->Header.NextPayload = NextPayload;
|
|
TsPayloadBuf->Header.PayloadLength = (UINT16)TsPayloadSize;
|
|
TsPayloadBuf->TSNumbers = 1;
|
|
TsPayload->PayloadSize = TsPayloadSize;
|
|
goto ON_EXIT;
|
|
|
|
ON_ERROR:
|
|
if (TsPayload != NULL) {
|
|
IkePayloadFree (TsPayload);
|
|
TsPayload = NULL;
|
|
}
|
|
ON_EXIT:
|
|
return TsPayload;
|
|
}
|
|
|
|
/**
|
|
Generate the Notify payload.
|
|
|
|
Since the structure of Notify payload which defined in RFC 4306 is simple, so
|
|
there is no internal data structure for Notify payload. This function generate
|
|
Notify payload defined in RFC 4306, but all the fields in this payload are still
|
|
in host order and need call Ikev2EncodePayload() to convert those fields from
|
|
the host order to network order beforing sending it.
|
|
|
|
@param[in] ProtocolId The protocol type ID. For IKE_SA it MUST be one (1).
|
|
For IPsec SAs it MUST be neither (2) for AH or (3)
|
|
for ESP.
|
|
@param[in] NextPayload The next paylaod type in NextPayload field of
|
|
the Notify payload.
|
|
@param[in] SpiSize Size of the SPI in SPI size field of the Notify Payload.
|
|
@param[in] MessageType The message type in NotifyMessageType field of the
|
|
Notify Payload.
|
|
@param[in] SpiBuf Pointer to buffer contains the SPI value.
|
|
@param[in] NotifyData Pointer to buffer contains the notification data.
|
|
@param[in] NotifyDataSize The size of NotifyData in bytes.
|
|
|
|
|
|
@retval Pointer to IKE Notify Payload.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2GenerateNotifyPayload (
|
|
IN UINT8 ProtocolId,
|
|
IN UINT8 NextPayload,
|
|
IN UINT8 SpiSize,
|
|
IN UINT16 MessageType,
|
|
IN UINT8 *SpiBuf,
|
|
IN UINT8 *NotifyData,
|
|
IN UINTN NotifyDataSize
|
|
)
|
|
{
|
|
IKE_PAYLOAD *NotifyPayload;
|
|
IKEV2_NOTIFY *Notify;
|
|
UINT16 NotifyPayloadLen;
|
|
UINT8 *MessageData;
|
|
|
|
// 1 2 3
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload !C! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Protocol ID ! SPI Size ! Notify Message Type !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Security Parameter Index (SPI) ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Notification Data ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
//
|
|
NotifyPayloadLen = (UINT16) (sizeof (IKEV2_NOTIFY) + NotifyDataSize + SpiSize);
|
|
Notify = (IKEV2_NOTIFY *) AllocateZeroPool (NotifyPayloadLen);
|
|
if (Notify == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Set Delete Payload's Generic Header
|
|
//
|
|
Notify->Header.NextPayload = NextPayload;
|
|
Notify->Header.PayloadLength = NotifyPayloadLen;
|
|
Notify->SpiSize = SpiSize;
|
|
Notify->ProtocolId = ProtocolId;
|
|
Notify->MessageType = MessageType;
|
|
|
|
//
|
|
// Copy Spi , for Cookie Notify, there is no SPI.
|
|
//
|
|
if (SpiBuf != NULL && SpiSize != 0 ) {
|
|
CopyMem (Notify + 1, SpiBuf, SpiSize);
|
|
}
|
|
|
|
MessageData = ((UINT8 *) (Notify + 1)) + SpiSize;
|
|
|
|
//
|
|
// Copy Notification Data
|
|
//
|
|
if (NotifyDataSize != 0) {
|
|
CopyMem (MessageData, NotifyData, NotifyDataSize);
|
|
}
|
|
|
|
//
|
|
// Create Payload for and set type as IKEV2_PAYLOAD_TYPE_NOTIFY
|
|
//
|
|
NotifyPayload = IkePayloadAlloc ();
|
|
if (NotifyPayload == NULL) {
|
|
FreePool (Notify);
|
|
return NULL;
|
|
}
|
|
|
|
NotifyPayload->PayloadType = IKEV2_PAYLOAD_TYPE_NOTIFY;
|
|
NotifyPayload->PayloadBuf = (UINT8 *) Notify;
|
|
NotifyPayload->PayloadSize = NotifyPayloadLen;
|
|
return NotifyPayload;
|
|
}
|
|
|
|
/**
|
|
Generate the Delete payload.
|
|
|
|
Since the structure of Delete payload which defined in RFC 4306 is simple,
|
|
there is no internal data structure for Delete payload. This function generate
|
|
Delete payload defined in RFC 4306, but all the fields in this payload are still
|
|
in host order and need call Ikev2EncodePayload() to convert those fields from
|
|
the host order to network order beforing sending it.
|
|
|
|
@param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload generation.
|
|
@param[in] NextPayload The next paylaod type in NextPayload field of
|
|
the Delete payload.
|
|
@param[in] SpiSize Size of the SPI in SPI size field of the Delete Payload.
|
|
@param[in] SpiNum Number of SPI in NumofSPIs field of the Delete Payload.
|
|
@param[in] SpiBuf Pointer to buffer contains the SPI value.
|
|
|
|
@retval a Pointer of IKE Delete Payload.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2GenerateDeletePayload (
|
|
IN IKEV2_SA_SESSION *IkeSaSession,
|
|
IN UINT8 NextPayload,
|
|
IN UINT8 SpiSize,
|
|
IN UINT16 SpiNum,
|
|
IN UINT8 *SpiBuf
|
|
|
|
)
|
|
{
|
|
IKE_PAYLOAD *DelPayload;
|
|
IKEV2_DELETE *Del;
|
|
UINT16 SpiBufSize;
|
|
UINT16 DelPayloadLen;
|
|
|
|
// 1 2 3
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload !C! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Protocol ID ! SPI Size ! # of SPIs !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Security Parameter Index(es) (SPI) ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
SpiBufSize = (UINT16) (SpiSize * SpiNum);
|
|
if (SpiBufSize != 0 && SpiBuf == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
DelPayloadLen = (UINT16) (sizeof (IKEV2_DELETE) + SpiBufSize);
|
|
|
|
Del = AllocateZeroPool (DelPayloadLen);
|
|
if (Del == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Set Delete Payload's Generic Header
|
|
//
|
|
Del->Header.NextPayload = NextPayload;
|
|
Del->Header.PayloadLength = DelPayloadLen;
|
|
Del->NumSpis = SpiNum;
|
|
Del->SpiSize = SpiSize;
|
|
|
|
if (SpiSize == 4) {
|
|
//
|
|
// TODO: should consider the AH if needs to support.
|
|
//
|
|
Del->ProtocolId = IPSEC_PROTO_IPSEC_ESP;
|
|
} else {
|
|
Del->ProtocolId = IPSEC_PROTO_ISAKMP;
|
|
}
|
|
|
|
//
|
|
// Set Del Payload's Idntification Data
|
|
//
|
|
CopyMem (Del + 1, SpiBuf, SpiBufSize);
|
|
DelPayload = IkePayloadAlloc ();
|
|
if (DelPayload == NULL) {
|
|
FreePool (Del);
|
|
return NULL;
|
|
}
|
|
|
|
DelPayload->PayloadType = IKEV2_PAYLOAD_TYPE_DELETE;
|
|
DelPayload->PayloadBuf = (UINT8 *) Del;
|
|
DelPayload->PayloadSize = DelPayloadLen;
|
|
return DelPayload;
|
|
}
|
|
|
|
/**
|
|
Generate the Configuration payload.
|
|
|
|
This function generate configuration payload defined in RFC 4306, but all the
|
|
fields in this payload are still in host order and need call Ikev2EncodePayload()
|
|
to convert those fields from the host order to network order beforing sending it.
|
|
|
|
@param[in] IkeSaSession Pointer to IKE SA Session to be used for Delete payload
|
|
generation.
|
|
@param[in] NextPayload The next paylaod type in NextPayload field of
|
|
the Delete payload.
|
|
@param[in] CfgType The attribute type in the Configuration attribute.
|
|
|
|
@retval Pointer to IKE CP Payload.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2GenerateCpPayload (
|
|
IN IKEV2_SA_SESSION *IkeSaSession,
|
|
IN UINT8 NextPayload,
|
|
IN UINT8 CfgType
|
|
)
|
|
{
|
|
IKE_PAYLOAD *CpPayload;
|
|
IKEV2_CFG *Cfg;
|
|
UINT16 PayloadLen;
|
|
IKEV2_CFG_ATTRIBUTES *CfgAttributes;
|
|
|
|
//
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload !C! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! CFG Type ! RESERVED !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ Configuration Attributes ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
|
|
PayloadLen = (UINT16) (sizeof (IKEV2_CFG) + sizeof (IKEV2_CFG_ATTRIBUTES));
|
|
Cfg = (IKEV2_CFG *) AllocateZeroPool (PayloadLen);
|
|
|
|
if (Cfg == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
CfgAttributes = (IKEV2_CFG_ATTRIBUTES *)((UINT8 *)Cfg + sizeof (IKEV2_CFG));
|
|
|
|
//
|
|
// Only generate the configuration payload with an empty INTERNAL_IP4_ADDRESS
|
|
// or INTERNAL_IP6_ADDRESS.
|
|
//
|
|
|
|
Cfg->Header.NextPayload = NextPayload;
|
|
Cfg->Header.PayloadLength = PayloadLen;
|
|
Cfg->CfgType = IKEV2_CFG_TYPE_REQUEST;
|
|
|
|
CfgAttributes->AttritType = CfgType;
|
|
CfgAttributes->ValueLength = 0;
|
|
|
|
CpPayload = IkePayloadAlloc ();
|
|
if (CpPayload == NULL) {
|
|
if (Cfg != NULL) {
|
|
FreePool (Cfg);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CpPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CP;
|
|
CpPayload->PayloadBuf = (UINT8 *) Cfg;
|
|
CpPayload->PayloadSize = PayloadLen;
|
|
return CpPayload;
|
|
}
|
|
|
|
/**
|
|
Parser the Notify Cookie payload.
|
|
|
|
This function parses the Notify Cookie payload.If the Notify ProtocolId is not
|
|
IPSEC_PROTO_ISAKMP or if the SpiSize is not zero or if the MessageType is not
|
|
the COOKIE, return EFI_INVALID_PARAMETER.
|
|
|
|
@param[in] IkeNCookie Pointer to the IKE_PAYLOAD which contians the
|
|
Notify Cookie payload.
|
|
the Notify payload.
|
|
@param[in, out] IkeSaSession Pointer to the relevant IKE SA Session.
|
|
|
|
@retval EFI_SUCCESS The Notify Cookie Payload is valid.
|
|
@retval EFI_INVALID_PARAMETER The Notify Cookie Payload is invalid.
|
|
@retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2ParserNotifyCookiePayload (
|
|
IN IKE_PAYLOAD *IkeNCookie,
|
|
IN OUT IKEV2_SA_SESSION *IkeSaSession
|
|
)
|
|
{
|
|
IKEV2_NOTIFY *NotifyPayload;
|
|
UINTN NotifyDataSize;
|
|
|
|
NotifyPayload = (IKEV2_NOTIFY *)IkeNCookie->PayloadBuf;
|
|
|
|
if ((NotifyPayload->ProtocolId != IPSEC_PROTO_ISAKMP) ||
|
|
(NotifyPayload->SpiSize != 0) ||
|
|
(NotifyPayload->MessageType != IKEV2_NOTIFICATION_COOKIE)
|
|
) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
NotifyDataSize = NotifyPayload->Header.PayloadLength - sizeof (IKEV2_NOTIFY);
|
|
IkeSaSession->NCookie = AllocateZeroPool (NotifyDataSize);
|
|
if (IkeSaSession->NCookie == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
IkeSaSession->NCookieSize = NotifyDataSize;
|
|
|
|
CopyMem (
|
|
IkeSaSession->NCookie,
|
|
(UINT8 *)NotifyPayload + sizeof (IKEV2_NOTIFY),
|
|
NotifyDataSize
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Generate the Certificate payload or Certificate Request Payload.
|
|
|
|
Since the Certificate Payload structure is same with Certificate Request Payload,
|
|
the only difference is that one contains the Certificate Data, other contains
|
|
the acceptable certificateion CA. This function generate Certificate payload
|
|
or Certificate Request Payload defined in RFC 4306, but all the fields
|
|
in the payload are still in host order and need call Ikev2EncodePayload()
|
|
to convert those fields from the host order to network order beforing sending it.
|
|
|
|
@param[in] IkeSaSession Pointer to IKE SA Session to be used of Delete payload
|
|
generation.
|
|
@param[in] NextPayload The next paylaod type in NextPayload field of
|
|
the Delete payload.
|
|
@param[in] Certificate Pointer of buffer contains the certification data.
|
|
@param[in] CertificateLen The length of Certificate in byte.
|
|
@param[in] EncodeType Specified the Certificate Encodeing which is defined
|
|
in RFC 4306.
|
|
@param[in] IsRequest To indicate create Certificate Payload or Certificate
|
|
Request Payload. If it is TURE, create Certificate
|
|
Payload. Otherwise, create Certificate Request Payload.
|
|
|
|
@retval a Pointer to IKE Payload whose payload buffer containing the Certificate
|
|
payload or Certificated Request payload.
|
|
|
|
**/
|
|
IKE_PAYLOAD *
|
|
Ikev2GenerateCertificatePayload (
|
|
IN IKEV2_SA_SESSION *IkeSaSession,
|
|
IN UINT8 NextPayload,
|
|
IN UINT8 *Certificate,
|
|
IN UINTN CertificateLen,
|
|
IN UINT8 EncodeType,
|
|
IN BOOLEAN IsRequest
|
|
)
|
|
{
|
|
IKE_PAYLOAD *CertPayload;
|
|
IKEV2_CERT *Cert;
|
|
UINT16 PayloadLen;
|
|
UINT8 *PublicKey;
|
|
UINTN PublicKeyLen;
|
|
HASH_DATA_FRAGMENT Fragment[1];
|
|
UINT8 *HashData;
|
|
UINTN HashDataSize;
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// 1 2 3
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload !C! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Cert Encoding ! !
|
|
// +-+-+-+-+-+-+-+-+ !
|
|
// ~ Certificate Data/Authority ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
|
|
Status = EFI_SUCCESS;
|
|
PublicKey = NULL;
|
|
PublicKeyLen = 0;
|
|
|
|
if (!IsRequest) {
|
|
PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + CertificateLen);
|
|
} else {
|
|
//
|
|
// SHA1 Hash length is 20.
|
|
//
|
|
PayloadLen = (UINT16) (sizeof (IKEV2_CERT) + 20);
|
|
}
|
|
|
|
Cert = AllocateZeroPool (PayloadLen);
|
|
if (Cert == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Generate Certificate Payload or Certificate Request Payload.
|
|
//
|
|
Cert->Header.NextPayload = NextPayload;
|
|
Cert->Header.PayloadLength = PayloadLen;
|
|
Cert->CertEncoding = EncodeType;
|
|
if (!IsRequest) {
|
|
CopyMem (
|
|
((UINT8 *)Cert) + sizeof (IKEV2_CERT),
|
|
Certificate,
|
|
CertificateLen
|
|
);
|
|
} else {
|
|
Status = IpSecCryptoIoGetPublicKeyFromCert (
|
|
Certificate,
|
|
CertificateLen,
|
|
&PublicKey,
|
|
&PublicKeyLen
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
Fragment[0].Data = PublicKey;
|
|
Fragment[0].DataSize = PublicKeyLen;
|
|
HashDataSize = IpSecGetHmacDigestLength (IKE_AALG_SHA1HMAC);
|
|
HashData = AllocateZeroPool (HashDataSize);
|
|
if (HashData == NULL) {
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
Status = IpSecCryptoIoHash (
|
|
IKE_AALG_SHA1HMAC,
|
|
Fragment,
|
|
1,
|
|
HashData,
|
|
HashDataSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
CopyMem (
|
|
((UINT8 *)Cert) + sizeof (IKEV2_CERT),
|
|
HashData,
|
|
HashDataSize
|
|
);
|
|
}
|
|
|
|
CertPayload = IkePayloadAlloc ();
|
|
if (CertPayload == NULL) {
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
if (!IsRequest) {
|
|
CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERT;
|
|
} else {
|
|
CertPayload->PayloadType = IKEV2_PAYLOAD_TYPE_CERTREQ;
|
|
}
|
|
|
|
CertPayload->PayloadBuf = (UINT8 *) Cert;
|
|
CertPayload->PayloadSize = PayloadLen;
|
|
return CertPayload;
|
|
|
|
ON_EXIT:
|
|
if (Cert != NULL) {
|
|
FreePool (Cert);
|
|
}
|
|
if (PublicKey != NULL) {
|
|
FreePool (PublicKey);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Remove and free all IkePayloads in the specified IkePacket.
|
|
|
|
@param[in] IkePacket The pointer of IKE_PACKET.
|
|
|
|
**/
|
|
VOID
|
|
ClearAllPayloads (
|
|
IN IKE_PACKET *IkePacket
|
|
)
|
|
{
|
|
LIST_ENTRY *PayloadEntry;
|
|
IKE_PAYLOAD *IkePayload;
|
|
//
|
|
// remove all payloads from list and free each payload.
|
|
//
|
|
while (!IsListEmpty (&IkePacket->PayloadList)) {
|
|
PayloadEntry = IkePacket->PayloadList.ForwardLink;
|
|
IkePayload = IKE_PAYLOAD_BY_PACKET (PayloadEntry);
|
|
IKE_PACKET_REMOVE_PAYLOAD (IkePacket, IkePayload);
|
|
IkePayloadFree (IkePayload);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Transfer the intrnal data structure IKEV2_SA_DATA to IKEV2_SA structure defined in RFC.
|
|
|
|
@param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the SA Session.
|
|
@param[in] SaData Pointer to IKEV2_SA_DATA to be transfered.
|
|
|
|
@retval return the pointer of IKEV2_SA.
|
|
|
|
**/
|
|
IKEV2_SA*
|
|
Ikev2EncodeSa (
|
|
IN IKEV2_SESSION_COMMON *SessionCommon,
|
|
IN IKEV2_SA_DATA *SaData
|
|
)
|
|
{
|
|
IKEV2_SA *Sa;
|
|
UINTN SaSize;
|
|
IKEV2_PROPOSAL_DATA *ProposalData;
|
|
IKEV2_TRANSFORM_DATA *TransformData;
|
|
UINTN TotalTransforms;
|
|
UINTN SaAttrsSize;
|
|
UINTN TransformsSize;
|
|
UINTN TransformSize;
|
|
UINTN ProposalsSize;
|
|
UINTN ProposalSize;
|
|
UINTN ProposalIndex;
|
|
UINTN TransformIndex;
|
|
IKE_SA_ATTRIBUTE *SaAttribute;
|
|
IKEV2_PROPOSAL *Proposal;
|
|
IKEV2_TRANSFORM *Transform;
|
|
|
|
//
|
|
// Transform IKE_SA_DATA structure to IKE_SA Payload.
|
|
// Header length is host order.
|
|
// The returned IKE_SA struct should be freed by caller.
|
|
//
|
|
TotalTransforms = 0;
|
|
//
|
|
// Calculate the Proposal numbers and Transform numbers.
|
|
//
|
|
for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) {
|
|
|
|
ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1) + ProposalIndex;
|
|
TotalTransforms += ProposalData->NumTransforms;
|
|
|
|
}
|
|
SaSize = sizeof (IKEV2_SA) +
|
|
SaData->NumProposals * sizeof (IKEV2_PROPOSAL) +
|
|
TotalTransforms * (sizeof (IKEV2_TRANSFORM) + MAX_SA_ATTRS_SIZE);
|
|
//
|
|
// Allocate buffer for IKE_SA.
|
|
//
|
|
Sa = AllocateZeroPool (SaSize);
|
|
if (Sa == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
CopyMem (Sa, SaData, sizeof (IKEV2_SA));
|
|
Sa->Header.PayloadLength = (UINT16) sizeof (IKEV2_SA);
|
|
ProposalsSize = 0;
|
|
Proposal = (IKEV2_PROPOSAL *) (Sa + 1);
|
|
|
|
//
|
|
// Set IKE_PROPOSAL
|
|
//
|
|
ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1);
|
|
for (ProposalIndex = 0; ProposalIndex < SaData->NumProposals; ProposalIndex++) {
|
|
Proposal->ProposalIndex = ProposalData->ProposalIndex;
|
|
Proposal->ProtocolId = ProposalData->ProtocolId;
|
|
Proposal->NumTransforms = ProposalData->NumTransforms;
|
|
|
|
if (ProposalData->Spi == 0) {
|
|
Proposal->SpiSize = 0;
|
|
} else {
|
|
Proposal->SpiSize = 4;
|
|
*(UINT32 *) (Proposal + 1) = HTONL (*((UINT32*)ProposalData->Spi));
|
|
}
|
|
|
|
TransformsSize = 0;
|
|
Transform = (IKEV2_TRANSFORM *) ((UINT8 *) (Proposal + 1) + Proposal->SpiSize);
|
|
|
|
//
|
|
// Set IKE_TRANSFORM
|
|
//
|
|
for (TransformIndex = 0; TransformIndex < ProposalData->NumTransforms; TransformIndex++) {
|
|
TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex;
|
|
Transform->TransformType = TransformData->TransformType;
|
|
Transform->TransformId = HTONS (TransformData->TransformId);
|
|
SaAttrsSize = 0;
|
|
|
|
//
|
|
// If the Encryption Algorithm is variable key length set the key length in attribute.
|
|
// Note that only a single attribute type (Key Length) is defined and it is fixed length.
|
|
//
|
|
if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_ENCR && TransformData->Attribute.Attr.AttrValue != 0) {
|
|
SaAttribute = (IKE_SA_ATTRIBUTE *) (Transform + 1);
|
|
SaAttribute->AttrType = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT);
|
|
SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue);
|
|
SaAttrsSize = sizeof (IKE_SA_ATTRIBUTE);
|
|
}
|
|
|
|
//
|
|
// If the Integrity Algorithm is variable key length set the key length in attribute.
|
|
//
|
|
if (Transform->TransformType == IKEV2_TRANSFORM_TYPE_INTEG && TransformData->Attribute.Attr.AttrValue != 0) {
|
|
SaAttribute = (IKE_SA_ATTRIBUTE *) (Transform + 1);
|
|
SaAttribute->AttrType = HTONS (IKEV2_ATTRIBUTE_TYPE_KEYLEN | SA_ATTR_FORMAT_BIT);
|
|
SaAttribute->Attr.AttrValue = HTONS (TransformData->Attribute.Attr.AttrValue);
|
|
SaAttrsSize = sizeof (IKE_SA_ATTRIBUTE);
|
|
}
|
|
|
|
TransformSize = sizeof (IKEV2_TRANSFORM) + SaAttrsSize;
|
|
TransformsSize += TransformSize;
|
|
|
|
Transform->Header.NextPayload = IKE_TRANSFORM_NEXT_PAYLOAD_MORE;
|
|
Transform->Header.PayloadLength = HTONS ((UINT16)TransformSize);
|
|
|
|
if (TransformIndex == (UINTN)(ProposalData->NumTransforms - 1)) {
|
|
Transform->Header.NextPayload = IKE_TRANSFORM_NEXT_PAYLOAD_NONE;
|
|
}
|
|
|
|
Transform = (IKEV2_TRANSFORM *)((UINT8 *) Transform + TransformSize);
|
|
}
|
|
|
|
//
|
|
// Set Proposal's Generic Header.
|
|
//
|
|
ProposalSize = sizeof (IKEV2_PROPOSAL) + Proposal->SpiSize + TransformsSize;
|
|
ProposalsSize += ProposalSize;
|
|
Proposal->Header.NextPayload = IKE_PROPOSAL_NEXT_PAYLOAD_MORE;
|
|
Proposal->Header.PayloadLength = HTONS ((UINT16)ProposalSize);
|
|
|
|
if (ProposalIndex == (UINTN)(SaData->NumProposals - 1)) {
|
|
Proposal->Header.NextPayload = IKE_PROPOSAL_NEXT_PAYLOAD_NONE;
|
|
}
|
|
|
|
//
|
|
// Point to next Proposal Payload
|
|
//
|
|
Proposal = (IKEV2_PROPOSAL *) ((UINT8 *) Proposal + ProposalSize);
|
|
ProposalData = (IKEV2_PROPOSAL_DATA *)(((UINT8 *)ProposalData) + sizeof (IKEV2_PROPOSAL_DATA) + (TransformIndex * sizeof (IKEV2_TRANSFORM_DATA)));
|
|
}
|
|
//
|
|
// Set SA's Generic Header.
|
|
//
|
|
Sa->Header.PayloadLength = (UINT16) (Sa->Header.PayloadLength + ProposalsSize);
|
|
return Sa;
|
|
}
|
|
|
|
/**
|
|
Decode SA payload.
|
|
|
|
This function converts the received SA payload to internal data structure.
|
|
|
|
@param[in] SessionCommon Pointer to IKE Common Session used to decode the SA
|
|
Payload.
|
|
@param[in] Sa Pointer to SA Payload
|
|
|
|
@return a Pointer to internal data structure for SA payload.
|
|
|
|
**/
|
|
IKEV2_SA_DATA *
|
|
Ikev2DecodeSa (
|
|
IN IKEV2_SESSION_COMMON *SessionCommon,
|
|
IN IKEV2_SA *Sa
|
|
)
|
|
{
|
|
IKEV2_SA_DATA *SaData;
|
|
EFI_STATUS Status;
|
|
IKEV2_PROPOSAL *Proposal;
|
|
IKEV2_TRANSFORM *Transform;
|
|
UINTN TotalProposals;
|
|
UINTN TotalTransforms;
|
|
UINTN ProposalNextPayloadSum;
|
|
UINTN ProposalIndex;
|
|
UINTN TransformIndex;
|
|
UINTN SaRemaining;
|
|
UINT16 ProposalSize;
|
|
UINTN ProposalRemaining;
|
|
UINT16 TransformSize;
|
|
UINTN SaAttrRemaining;
|
|
IKE_SA_ATTRIBUTE *SaAttribute;
|
|
IKEV2_PROPOSAL_DATA *ProposalData;
|
|
IKEV2_TRANSFORM_DATA *TransformData;
|
|
UINT8 *Spi;
|
|
|
|
//
|
|
// Transfrom from IKE_SA payload to IKE_SA_DATA structure.
|
|
// Header length NTOH is already done
|
|
// The returned IKE_SA_DATA should be freed by caller
|
|
//
|
|
SaData = NULL;
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// First round sanity check and size calculae
|
|
//
|
|
TotalProposals = 0;
|
|
TotalTransforms = 0;
|
|
ProposalNextPayloadSum = 0;
|
|
SaRemaining = Sa->Header.PayloadLength - sizeof (IKEV2_SA);// Point to current position in SA
|
|
Proposal = (IKEV2_PROPOSAL *)((IKEV2_SA *)(Sa)+1);
|
|
|
|
//
|
|
// Calculate the number of Proposal payload and the total numbers of
|
|
// Transforms payload (the transforms in all proposal payload).
|
|
//
|
|
while (SaRemaining > sizeof (IKEV2_PROPOSAL)) {
|
|
ProposalSize = NTOHS (Proposal->Header.PayloadLength);
|
|
if (SaRemaining < ProposalSize) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if (Proposal->SpiSize != 0 && Proposal->SpiSize != 4) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
TotalProposals++;
|
|
TotalTransforms += Proposal->NumTransforms;
|
|
SaRemaining -= ProposalSize;
|
|
ProposalNextPayloadSum += Proposal->Header.NextPayload;
|
|
Proposal = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize);
|
|
}
|
|
|
|
//
|
|
// Check the proposal number.
|
|
// The proposal Substructure, the NextPayLoad field indicates : 0 (last) or 2 (more)
|
|
// which Specifies whether this is the last Proposal Substructure in the SA.
|
|
// Here suming all Proposal NextPayLoad field to check the proposal number is correct
|
|
// or not.
|
|
//
|
|
if (TotalProposals == 0 ||
|
|
(TotalProposals - 1) * IKE_PROPOSAL_NEXT_PAYLOAD_MORE != ProposalNextPayloadSum
|
|
) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Second round sanity check and decode. Transform the SA payload into
|
|
// a IKE_SA_DATA structure.
|
|
//
|
|
SaData = (IKEV2_SA_DATA *) AllocateZeroPool (
|
|
sizeof (IKEV2_SA_DATA) +
|
|
TotalProposals * sizeof (IKEV2_PROPOSAL_DATA) +
|
|
TotalTransforms * sizeof (IKEV2_TRANSFORM_DATA)
|
|
);
|
|
if (SaData == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
CopyMem (SaData, Sa, sizeof (IKEV2_SA));
|
|
SaData->NumProposals = TotalProposals;
|
|
ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1);
|
|
|
|
//
|
|
// Proposal Payload
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload ! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms!
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! SPI (variable) !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
for (ProposalIndex = 0, Proposal = IKEV2_SA_FIRST_PROPOSAL (Sa);
|
|
ProposalIndex < TotalProposals;
|
|
ProposalIndex++
|
|
) {
|
|
|
|
//
|
|
// TODO: check ProposalId
|
|
//
|
|
ProposalData->ProposalIndex = Proposal->ProposalIndex;
|
|
ProposalData->ProtocolId = Proposal->ProtocolId;
|
|
if (Proposal->SpiSize == 0) {
|
|
ProposalData->Spi = 0;
|
|
} else {
|
|
//
|
|
// SpiSize == 4
|
|
//
|
|
Spi = AllocateZeroPool (Proposal->SpiSize);
|
|
if (Spi == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
CopyMem (Spi, (UINT32 *) (Proposal + 1), Proposal->SpiSize);
|
|
*((UINT32*) Spi) = NTOHL (*((UINT32*) Spi));
|
|
ProposalData->Spi = Spi;
|
|
}
|
|
|
|
ProposalData->NumTransforms = Proposal->NumTransforms;
|
|
ProposalSize = NTOHS (Proposal->Header.PayloadLength);
|
|
ProposalRemaining = ProposalSize;
|
|
//
|
|
// Transform Payload
|
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! Next Payload ! RESERVED ! Payload Length !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// !Transform Type ! RESERVED ! Transform ID !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// ! !
|
|
// ~ SA Attributes ~
|
|
// ! !
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
//
|
|
Transform = IKEV2_PROPOSAL_FIRST_TRANSFORM (Proposal);
|
|
for (TransformIndex = 0; TransformIndex < Proposal->NumTransforms; TransformIndex++) {
|
|
|
|
//
|
|
// Transfer the IKEV2_TRANSFORM structure into internal IKEV2_TRANSFORM_DATA struture.
|
|
//
|
|
TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1) + TransformIndex;
|
|
TransformData->TransformId = NTOHS (Transform->TransformId);
|
|
TransformData->TransformType = Transform->TransformType;
|
|
TransformSize = NTOHS (Transform->Header.PayloadLength);
|
|
//
|
|
// Check the Proposal Data is correct.
|
|
//
|
|
if (ProposalRemaining < TransformSize) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Check if the Transform payload includes Attribution.
|
|
//
|
|
SaAttrRemaining = TransformSize - sizeof (IKEV2_TRANSFORM);
|
|
|
|
//
|
|
// According to RFC 4603, currently only the Key length attribute type is
|
|
// supported. For each Transform, there is only one attributeion.
|
|
//
|
|
if (SaAttrRemaining > 0) {
|
|
if (SaAttrRemaining != sizeof (IKE_SA_ATTRIBUTE)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
SaAttribute = (IKE_SA_ATTRIBUTE *) ((IKEV2_TRANSFORM *)(Transform) + 1);
|
|
TransformData->Attribute.AttrType = (UINT16)((NTOHS (SaAttribute->AttrType)) & ~SA_ATTR_FORMAT_BIT);
|
|
TransformData->Attribute.Attr.AttrValue = NTOHS (SaAttribute->Attr.AttrValue);
|
|
|
|
//
|
|
// Currently, only supports the Key Length Attribution.
|
|
//
|
|
if (TransformData->Attribute.AttrType != IKEV2_ATTRIBUTE_TYPE_KEYLEN) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Move to next Transform
|
|
//
|
|
Transform = IKEV2_NEXT_TRANSFORM_WITH_SIZE (Transform, TransformSize);
|
|
}
|
|
Proposal = IKEV2_NEXT_PROPOSAL_WITH_SIZE (Proposal, ProposalSize);
|
|
ProposalData = (IKEV2_PROPOSAL_DATA *) ((UINT8 *)(ProposalData + 1) +
|
|
ProposalData->NumTransforms *
|
|
sizeof (IKEV2_TRANSFORM_DATA));
|
|
}
|
|
|
|
Exit:
|
|
if (EFI_ERROR (Status) && SaData != NULL) {
|
|
FreePool (SaData);
|
|
SaData = NULL;
|
|
}
|
|
return SaData;
|
|
}
|
|
|
|
/**
|
|
General interface of payload encoding.
|
|
|
|
This function encodes the internal data structure into payload which
|
|
is defined in RFC 4306. The IkePayload->PayloadBuf is used to store both the input
|
|
payload and converted payload. Only the SA payload use the interal structure
|
|
to store the attribute. Other payload use structure which is same with the RFC
|
|
defined, for this kind payloads just do host order to network order change of
|
|
some fields.
|
|
|
|
@param[in] SessionCommon Pointer to IKE Session Common used to encode the payload.
|
|
@param[in, out] IkePayload Pointer to IKE payload to be encoded as input, and
|
|
store the encoded result as output.
|
|
|
|
@retval EFI_INVALID_PARAMETER Meet error when encoding the SA payload.
|
|
@retval EFI_SUCCESS Encoded successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2EncodePayload (
|
|
IN UINT8 *SessionCommon,
|
|
IN OUT IKE_PAYLOAD *IkePayload
|
|
)
|
|
{
|
|
IKEV2_SA_DATA *SaData;
|
|
IKEV2_SA *SaPayload;
|
|
IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;
|
|
IKEV2_NOTIFY *NotifyPayload;
|
|
IKEV2_DELETE *DeletePayload;
|
|
IKEV2_KEY_EXCHANGE *KeyPayload;
|
|
IKEV2_TS *TsPayload;
|
|
IKEV2_CFG_ATTRIBUTES *CfgAttribute;
|
|
UINT8 *TsBuffer;
|
|
UINT8 Index;
|
|
TRAFFIC_SELECTOR *TrafficSelector;
|
|
|
|
//
|
|
// Transform the Internal IKE structure to IKE payload.
|
|
// Only the SA payload use the interal structure to store the attribute.
|
|
// Other payload use structure which same with the RFC defined, so there is
|
|
// no need to tranform them to IKE payload.
|
|
//
|
|
switch (IkePayload->PayloadType) {
|
|
case IKEV2_PAYLOAD_TYPE_SA:
|
|
//
|
|
// Transform IKE_SA_DATA to IK_SA payload
|
|
//
|
|
SaData = (IKEV2_SA_DATA *) IkePayload->PayloadBuf;
|
|
SaPayload = Ikev2EncodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, SaData);
|
|
|
|
if (SaPayload == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (!IkePayload->IsPayloadBufExt) {
|
|
FreePool (IkePayload->PayloadBuf);
|
|
}
|
|
IkePayload->PayloadBuf = (UINT8 *) SaPayload;
|
|
IkePayload->IsPayloadBufExt = FALSE;
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_NOTIFY:
|
|
NotifyPayload = (IKEV2_NOTIFY *) IkePayload->PayloadBuf;
|
|
NotifyPayload->MessageType = HTONS (NotifyPayload->MessageType);
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_DELETE:
|
|
DeletePayload = (IKEV2_DELETE *) IkePayload->PayloadBuf;
|
|
DeletePayload->NumSpis = HTONS (DeletePayload->NumSpis);
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_KE:
|
|
KeyPayload = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf;
|
|
KeyPayload->DhGroup = HTONS (KeyPayload->DhGroup);
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_TS_INIT:
|
|
case IKEV2_PAYLOAD_TYPE_TS_RSP:
|
|
TsPayload = (IKEV2_TS *) IkePayload->PayloadBuf;
|
|
TsBuffer = IkePayload->PayloadBuf + sizeof (IKEV2_TS);
|
|
|
|
for (Index = 0; Index < TsPayload->TSNumbers; Index++) {
|
|
TrafficSelector = (TRAFFIC_SELECTOR *) TsBuffer;
|
|
TsBuffer = TsBuffer + TrafficSelector->SelecorLen;
|
|
//
|
|
// Host order to network order
|
|
//
|
|
TrafficSelector->SelecorLen = HTONS (TrafficSelector->SelecorLen);
|
|
TrafficSelector->StartPort = HTONS (TrafficSelector->StartPort);
|
|
TrafficSelector->EndPort = HTONS (TrafficSelector->EndPort);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_CP:
|
|
CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1);
|
|
CfgAttribute->AttritType = HTONS (CfgAttribute->AttritType);
|
|
CfgAttribute->ValueLength = HTONS (CfgAttribute->ValueLength);
|
|
|
|
case IKEV2_PAYLOAD_TYPE_ID_INIT:
|
|
case IKEV2_PAYLOAD_TYPE_ID_RSP:
|
|
case IKEV2_PAYLOAD_TYPE_AUTH:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf;
|
|
IkePayload->PayloadSize = PayloadHdr->PayloadLength;
|
|
PayloadHdr->PayloadLength = HTONS (PayloadHdr->PayloadLength);
|
|
IKEV2_DUMP_PAYLOAD (IkePayload);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
The general interface for decoding Payload.
|
|
|
|
This function converts the received Payload into internal structure.
|
|
|
|
@param[in] SessionCommon Pointer to IKE Session Common used for decoding.
|
|
@param[in, out] IkePayload Pointer to IKE payload to be decoded as input, and
|
|
store the decoded result as output.
|
|
|
|
@retval EFI_INVALID_PARAMETER Meet error when decoding the SA payload.
|
|
@retval EFI_SUCCESS Decoded successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2DecodePayload (
|
|
IN UINT8 *SessionCommon,
|
|
IN OUT IKE_PAYLOAD *IkePayload
|
|
)
|
|
{
|
|
IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;
|
|
UINT16 PayloadSize;
|
|
UINT8 PayloadType;
|
|
IKEV2_SA_DATA *SaData;
|
|
EFI_STATUS Status;
|
|
IKEV2_NOTIFY *NotifyPayload;
|
|
IKEV2_DELETE *DeletePayload;
|
|
UINT16 TsTotalSize;
|
|
TRAFFIC_SELECTOR *TsSelector;
|
|
IKEV2_TS *TsPayload;
|
|
IKEV2_KEY_EXCHANGE *KeyPayload;
|
|
IKEV2_CFG_ATTRIBUTES *CfgAttribute;
|
|
UINT8 Index;
|
|
|
|
//
|
|
// Transform the IKE payload to Internal IKE structure.
|
|
// Only the SA payload and Hash Payload use the interal
|
|
// structure to store the attribute. Other payloads use
|
|
// structure which is same with the definitions in RFC,
|
|
// so there is no need to tranform them to internal IKE
|
|
// structure.
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
PayloadSize = (UINT16) IkePayload->PayloadSize;
|
|
PayloadType = IkePayload->PayloadType;
|
|
PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePayload->PayloadBuf;
|
|
//
|
|
// The PayloadSize is the size of whole payload.
|
|
// Replace HTONS operation to assignment statements, since the result is same.
|
|
//
|
|
PayloadHdr->PayloadLength = PayloadSize;
|
|
|
|
IKEV2_DUMP_PAYLOAD (IkePayload);
|
|
switch (PayloadType) {
|
|
case IKEV2_PAYLOAD_TYPE_SA:
|
|
if (PayloadSize < sizeof (IKEV2_SA)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
SaData = Ikev2DecodeSa ((IKEV2_SESSION_COMMON *) SessionCommon, (IKEV2_SA *) PayloadHdr);
|
|
if (SaData == NULL) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if (!IkePayload->IsPayloadBufExt) {
|
|
FreePool (IkePayload->PayloadBuf);
|
|
}
|
|
|
|
IkePayload->PayloadBuf = (UINT8 *) SaData;
|
|
IkePayload->IsPayloadBufExt = FALSE;
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_ID_INIT:
|
|
case IKEV2_PAYLOAD_TYPE_ID_RSP :
|
|
if (PayloadSize < sizeof (IKEV2_ID)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_NOTIFY:
|
|
if (PayloadSize < sizeof (IKEV2_NOTIFY)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
NotifyPayload = (IKEV2_NOTIFY *) PayloadHdr;
|
|
NotifyPayload->MessageType = NTOHS (NotifyPayload->MessageType);
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_DELETE:
|
|
if (PayloadSize < sizeof (IKEV2_DELETE)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
DeletePayload = (IKEV2_DELETE *) PayloadHdr;
|
|
DeletePayload->NumSpis = NTOHS (DeletePayload->NumSpis);
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_AUTH:
|
|
if (PayloadSize < sizeof (IKEV2_AUTH)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_KE:
|
|
KeyPayload = (IKEV2_KEY_EXCHANGE *) IkePayload->PayloadBuf;
|
|
KeyPayload->DhGroup = HTONS (KeyPayload->DhGroup);
|
|
break;
|
|
|
|
case IKEV2_PAYLOAD_TYPE_TS_INIT:
|
|
case IKEV2_PAYLOAD_TYPE_TS_RSP :
|
|
TsTotalSize = 0;
|
|
if (PayloadSize < sizeof (IKEV2_TS)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
//
|
|
// Parse each traffic selector and transfer network-order to host-order
|
|
//
|
|
TsPayload = (IKEV2_TS *) IkePayload->PayloadBuf;
|
|
TsSelector = (TRAFFIC_SELECTOR *) (IkePayload->PayloadBuf + sizeof (IKEV2_TS));
|
|
|
|
for (Index = 0; Index < TsPayload->TSNumbers; Index++) {
|
|
TsSelector->SelecorLen = NTOHS (TsSelector->SelecorLen);
|
|
TsSelector->StartPort = NTOHS (TsSelector->StartPort);
|
|
TsSelector->EndPort = NTOHS (TsSelector->EndPort);
|
|
|
|
TsTotalSize = (UINT16) (TsTotalSize + TsSelector->SelecorLen);
|
|
TsSelector = (TRAFFIC_SELECTOR *) ((UINT8 *) TsSelector + TsSelector->SelecorLen);
|
|
}
|
|
//
|
|
// Check if the total size of Traffic Selectors is correct.
|
|
//
|
|
if (TsTotalSize != PayloadSize - sizeof(IKEV2_TS)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
case IKEV2_PAYLOAD_TYPE_CP:
|
|
CfgAttribute = (IKEV2_CFG_ATTRIBUTES *)(((IKEV2_CFG *) IkePayload->PayloadBuf) + 1);
|
|
CfgAttribute->AttritType = NTOHS (CfgAttribute->AttritType);
|
|
CfgAttribute->ValueLength = NTOHS (CfgAttribute->ValueLength);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Decode the IKE packet.
|
|
|
|
This function first decrypts the IKE packet if needed , then separates the whole
|
|
IKE packet from the IkePacket->PayloadBuf into IkePacket payload list.
|
|
|
|
@param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON containing
|
|
some parameter used by IKE packet decoding.
|
|
@param[in, out] IkePacket The IKE Packet to be decoded on input, and
|
|
the decoded result on return.
|
|
@param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
|
|
IKE_CHILD_TYPE are supported.
|
|
|
|
@retval EFI_SUCCESS The IKE packet is decoded successfully.
|
|
@retval Otherwise The IKE packet decoding is failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2DecodePacket (
|
|
IN IKEV2_SESSION_COMMON *SessionCommon,
|
|
IN OUT IKE_PACKET *IkePacket,
|
|
IN UINTN IkeType
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
IKEV2_COMMON_PAYLOAD_HEADER *PayloadHdr;
|
|
UINT8 PayloadType;
|
|
UINTN RemainBytes;
|
|
UINT16 PayloadSize;
|
|
IKE_PAYLOAD *IkePayload;
|
|
IKE_HEADER *IkeHeader;
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
|
|
IkeHeader = NULL;
|
|
|
|
//
|
|
// Check if the IkePacket need decrypt.
|
|
//
|
|
if (SessionCommon->State >= IkeStateAuth) {
|
|
Status = Ikev2DecryptPacket (SessionCommon, IkePacket, IkeType);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// If the IkePacket doesn't contain any payload return invalid parameter.
|
|
//
|
|
if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE) {
|
|
if ((SessionCommon->State >= IkeStateAuth) &&
|
|
(IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INFO)
|
|
) {
|
|
//
|
|
// If it is Liveness check, there will be no payload load in the encrypt payload.
|
|
//
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the PayloadTotalSize < Header length, return invalid parameter.
|
|
//
|
|
RemainBytes = IkePacket->PayloadTotalSize;
|
|
if (RemainBytes < sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// If the packet is first or second message, store whole message in
|
|
// IkeSa->InitiPacket or IkeSa->RespPacket for following Auth Payload
|
|
// calculate.
|
|
//
|
|
if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) {
|
|
IkeHeader = AllocateZeroPool (sizeof (IKE_HEADER));
|
|
if (IkeHeader == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
CopyMem (IkeHeader, IkePacket->Header, sizeof (IKE_HEADER));
|
|
|
|
//
|
|
// Before store the whole packet, roll back the host order to network order,
|
|
// since the header order was changed in the IkePacketFromNetbuf.
|
|
//
|
|
IkeHdrNetToHost (IkeHeader);
|
|
IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
|
|
if (SessionCommon->IsInitiator) {
|
|
IkeSaSession->RespPacket = AllocateZeroPool (IkePacket->Header->Length);
|
|
if (IkeSaSession->RespPacket == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
IkeSaSession->RespPacketSize = IkePacket->Header->Length;
|
|
CopyMem (IkeSaSession->RespPacket, IkeHeader, sizeof (IKE_HEADER));
|
|
CopyMem (
|
|
IkeSaSession->RespPacket + sizeof (IKE_HEADER),
|
|
IkePacket->PayloadsBuf,
|
|
IkePacket->Header->Length - sizeof (IKE_HEADER)
|
|
);
|
|
} else {
|
|
IkeSaSession->InitPacket = AllocateZeroPool (IkePacket->Header->Length);
|
|
if (IkeSaSession->InitPacket == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
IkeSaSession->InitPacketSize = IkePacket->Header->Length;
|
|
CopyMem (IkeSaSession->InitPacket, IkeHeader, sizeof (IKE_HEADER));
|
|
CopyMem (
|
|
IkeSaSession->InitPacket + sizeof (IKE_HEADER),
|
|
IkePacket->PayloadsBuf,
|
|
IkePacket->Header->Length - sizeof (IKE_HEADER)
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Point to the first Payload
|
|
//
|
|
PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) IkePacket->PayloadsBuf;
|
|
PayloadType = IkePacket->Header->NextPayload;
|
|
|
|
//
|
|
// Parse each payload
|
|
//
|
|
while (RemainBytes >= sizeof (IKEV2_COMMON_PAYLOAD_HEADER)) {
|
|
PayloadSize = NTOHS (PayloadHdr->PayloadLength);
|
|
|
|
//
|
|
//Check the size of the payload is correct.
|
|
//
|
|
if (RemainBytes < PayloadSize) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// At certain states, it should save some datas before decoding.
|
|
//
|
|
if (SessionCommon->BeforeDecodePayload != NULL) {
|
|
SessionCommon->BeforeDecodePayload (
|
|
(UINT8 *) SessionCommon,
|
|
(UINT8 *) PayloadHdr,
|
|
PayloadSize,
|
|
PayloadType
|
|
);
|
|
}
|
|
|
|
//
|
|
// Initial IkePayload
|
|
//
|
|
IkePayload = IkePayloadAlloc ();
|
|
if (IkePayload == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
IkePayload->PayloadType = PayloadType;
|
|
IkePayload->PayloadBuf = (UINT8 *) PayloadHdr;
|
|
IkePayload->PayloadSize = PayloadSize;
|
|
IkePayload->IsPayloadBufExt = TRUE;
|
|
|
|
Status = Ikev2DecodePayload ((UINT8 *) SessionCommon, IkePayload);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit;
|
|
}
|
|
|
|
IPSEC_DUMP_BUF ("After Decoding Payload", IkePayload->PayloadBuf, IkePayload->PayloadSize);
|
|
//
|
|
// Add each payload into packet
|
|
// Notice, the IkePacket->Hdr->Lenght still recode the whole IkePacket length
|
|
// which is before the decoding.
|
|
//
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
|
|
|
|
RemainBytes -= PayloadSize;
|
|
PayloadType = PayloadHdr->NextPayload;
|
|
if (PayloadType == IKEV2_PAYLOAD_TYPE_NONE) {
|
|
break;
|
|
}
|
|
|
|
PayloadHdr = (IKEV2_COMMON_PAYLOAD_HEADER *) ((UINT8 *) PayloadHdr + PayloadSize);
|
|
}
|
|
|
|
if (PayloadType != IKEV2_PAYLOAD_TYPE_NONE) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
if (EFI_ERROR (Status)) {
|
|
ClearAllPayloads (IkePacket);
|
|
}
|
|
|
|
if (IkeHeader != NULL) {
|
|
FreePool (IkeHeader);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Encode the IKE packet.
|
|
|
|
This function puts all Payloads into one payload then encrypt it if needed.
|
|
|
|
@param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing
|
|
some parameter used during IKE packet encoding.
|
|
@param[in, out] IkePacket Pointer to IKE_PACKET to be encoded as input,
|
|
and the encoded result as output.
|
|
@param[in] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
|
|
IKE_CHILD_TYPE are supportted.
|
|
|
|
@retval EFI_SUCCESS Encode IKE packet successfully.
|
|
@retval Otherwise Encode IKE packet failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2EncodePacket (
|
|
IN IKEV2_SESSION_COMMON *SessionCommon,
|
|
IN OUT IKE_PACKET *IkePacket,
|
|
IN UINTN IkeType
|
|
)
|
|
{
|
|
IKE_PAYLOAD *IkePayload;
|
|
UINTN PayloadTotalSize;
|
|
LIST_ENTRY *Entry;
|
|
EFI_STATUS Status;
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
|
|
PayloadTotalSize = 0;
|
|
//
|
|
// Encode each payload
|
|
//
|
|
for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {
|
|
IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
|
|
Entry = Entry->ForwardLink;
|
|
Status = Ikev2EncodePayload ((UINT8 *) SessionCommon, IkePayload);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (SessionCommon->AfterEncodePayload != NULL) {
|
|
//
|
|
// For certain states, save some payload for further calculation
|
|
//
|
|
SessionCommon->AfterEncodePayload (
|
|
(UINT8 *) SessionCommon,
|
|
IkePayload->PayloadBuf,
|
|
IkePayload->PayloadSize,
|
|
IkePayload->PayloadType
|
|
);
|
|
}
|
|
|
|
PayloadTotalSize += IkePayload->PayloadSize;
|
|
}
|
|
IkePacket->PayloadTotalSize = PayloadTotalSize;
|
|
|
|
Status = EFI_SUCCESS;
|
|
if (SessionCommon->State >= IkeStateAuth) {
|
|
//
|
|
// Encrypt all payload and transfer IKE packet header from Host order to Network order.
|
|
//
|
|
Status = Ikev2EncryptPacket (SessionCommon, IkePacket);
|
|
} else {
|
|
//
|
|
// Fill in the lenght into IkePacket header and transfer Host order to Network order.
|
|
//
|
|
IkePacket->Header->Length = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize);
|
|
IkeHdrHostToNet (IkePacket->Header);
|
|
}
|
|
|
|
//
|
|
// If the packet is first message, store whole message in IkeSa->InitiPacket
|
|
// for following Auth Payload calculation.
|
|
//
|
|
if (IkePacket->Header->ExchangeType == IKEV2_EXCHANGE_TYPE_INIT) {
|
|
IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
|
|
if (SessionCommon->IsInitiator) {
|
|
IkeSaSession->InitPacketSize = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER);
|
|
IkeSaSession->InitPacket = AllocateZeroPool (IkeSaSession->InitPacketSize);
|
|
if (IkeSaSession->InitPacket == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CopyMem (IkeSaSession->InitPacket, IkePacket->Header, sizeof (IKE_HEADER));
|
|
PayloadTotalSize = 0;
|
|
for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {
|
|
IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
|
|
Entry = Entry->ForwardLink;
|
|
CopyMem (
|
|
IkeSaSession->InitPacket + sizeof (IKE_HEADER) + PayloadTotalSize,
|
|
IkePayload->PayloadBuf,
|
|
IkePayload->PayloadSize
|
|
);
|
|
PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize;
|
|
}
|
|
} else {
|
|
IkeSaSession->RespPacketSize = IkePacket->PayloadTotalSize + sizeof(IKE_HEADER);
|
|
IkeSaSession->RespPacket = AllocateZeroPool (IkeSaSession->RespPacketSize);
|
|
if (IkeSaSession->RespPacket == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CopyMem (IkeSaSession->RespPacket, IkePacket->Header, sizeof (IKE_HEADER));
|
|
PayloadTotalSize = 0;
|
|
for (Entry = IkePacket->PayloadList.ForwardLink; Entry != &(IkePacket->PayloadList);) {
|
|
IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
|
|
Entry = Entry->ForwardLink;
|
|
|
|
CopyMem (
|
|
IkeSaSession->RespPacket + sizeof (IKE_HEADER) + PayloadTotalSize,
|
|
IkePayload->PayloadBuf,
|
|
IkePayload->PayloadSize
|
|
);
|
|
PayloadTotalSize = PayloadTotalSize + IkePayload->PayloadSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Decrypt IKE packet.
|
|
|
|
This function decrypts the Encrypted IKE packet and put the result into IkePacket->PayloadBuf.
|
|
|
|
@param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON containing
|
|
some parameter used during decrypting.
|
|
@param[in, out] IkePacket Pointer to IKE_PACKET to be decrypted as input,
|
|
and the decrypted result as output.
|
|
@param[in, out] IkeType The type of IKE. IKE_SA_TYPE, IKE_INFO_TYPE and
|
|
IKE_CHILD_TYPE are supportted.
|
|
|
|
@retval EFI_INVALID_PARAMETER If the IKE packet length is zero or the
|
|
IKE packet length is not aligned with Algorithm Block Size
|
|
@retval EFI_SUCCESS Decrypt IKE packet successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2DecryptPacket (
|
|
IN IKEV2_SESSION_COMMON *SessionCommon,
|
|
IN OUT IKE_PACKET *IkePacket,
|
|
IN OUT UINTN IkeType
|
|
)
|
|
{
|
|
UINT8 CryptBlockSize; // Encrypt Block Size
|
|
UINTN DecryptedSize; // Encrypted IKE Payload Size
|
|
UINT8 *DecryptedBuf; // Encrypted IKE Payload buffer
|
|
UINTN IntegritySize;
|
|
UINT8 *IntegrityBuffer;
|
|
UINTN IvSize; // Iv Size
|
|
UINT8 CheckSumSize; // Integrity Check Sum Size depends on intergrity Auth
|
|
UINT8 *CheckSumData; // Check Sum data
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
IKEV2_CHILD_SA_SESSION *ChildSaSession;
|
|
EFI_STATUS Status;
|
|
UINT8 PadLen;
|
|
HASH_DATA_FRAGMENT Fragments[1];
|
|
|
|
IvSize = 0;
|
|
IkeSaSession = NULL;
|
|
CryptBlockSize = 0;
|
|
CheckSumSize = 0;
|
|
|
|
//
|
|
// Check if the first payload is the Encrypted payload
|
|
//
|
|
if (IkePacket->Header->NextPayload != IKEV2_PAYLOAD_TYPE_ENCRYPT) {
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
CheckSumData = NULL;
|
|
DecryptedBuf = NULL;
|
|
IntegrityBuffer = NULL;
|
|
|
|
//
|
|
// Get the Block Size
|
|
//
|
|
if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
|
|
|
|
CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId);
|
|
|
|
CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId);
|
|
IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
|
|
|
|
} else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) {
|
|
|
|
ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
|
|
IkeSaSession = ChildSaSession->IkeSaSession;
|
|
CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);
|
|
CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId);
|
|
} else {
|
|
//
|
|
// The type of SA Session would either be IkeSa or ChildSa.
|
|
//
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
CheckSumData = AllocateZeroPool (CheckSumSize);
|
|
if (CheckSumData == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Fill in the Integrity buffer
|
|
//
|
|
IntegritySize = IkePacket->PayloadTotalSize + sizeof (IKE_HEADER);
|
|
IntegrityBuffer = AllocateZeroPool (IntegritySize);
|
|
if (IntegrityBuffer == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
CopyMem (IntegrityBuffer, IkePacket->Header, sizeof(IKE_HEADER));
|
|
CopyMem (IntegrityBuffer + sizeof (IKE_HEADER), IkePacket->PayloadsBuf, IkePacket->PayloadTotalSize);
|
|
|
|
//
|
|
// Change Host order to Network order, since the header order was changed
|
|
// in the IkePacketFromNetbuf.
|
|
//
|
|
IkeHdrHostToNet ((IKE_HEADER *)IntegrityBuffer);
|
|
|
|
//
|
|
// Calculate the Integrity CheckSum Data
|
|
//
|
|
Fragments[0].Data = IntegrityBuffer;
|
|
Fragments[0].DataSize = IntegritySize - CheckSumSize;
|
|
|
|
if (SessionCommon->IsInitiator) {
|
|
Status = IpSecCryptoIoHmac (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
|
|
IkeSaSession->IkeKeys->SkArKey,
|
|
IkeSaSession->IkeKeys->SkArKeySize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
1,
|
|
CheckSumData,
|
|
CheckSumSize
|
|
);
|
|
} else {
|
|
Status = IpSecCryptoIoHmac (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
|
|
IkeSaSession->IkeKeys->SkAiKey,
|
|
IkeSaSession->IkeKeys->SkAiKeySize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
1,
|
|
CheckSumData,
|
|
CheckSumSize
|
|
);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_EXIT;
|
|
}
|
|
//
|
|
// Compare the Integrity CheckSum Data with the one in IkePacket
|
|
//
|
|
if (CompareMem (
|
|
IkePacket->PayloadsBuf + IkePacket->PayloadTotalSize - CheckSumSize,
|
|
CheckSumData,
|
|
CheckSumSize
|
|
) != 0) {
|
|
DEBUG ((DEBUG_ERROR, "Error auth verify payload\n"));
|
|
Status = EFI_ACCESS_DENIED;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
IvSize = CryptBlockSize;
|
|
|
|
//
|
|
// Decrypt the payload with the key.
|
|
//
|
|
DecryptedSize = IkePacket->PayloadTotalSize - sizeof (IKEV2_COMMON_PAYLOAD_HEADER) - IvSize - CheckSumSize;
|
|
DecryptedBuf = AllocateZeroPool (DecryptedSize);
|
|
if (DecryptedBuf == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
CopyMem (
|
|
DecryptedBuf,
|
|
IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER) + IvSize,
|
|
DecryptedSize
|
|
);
|
|
|
|
if (SessionCommon->IsInitiator) {
|
|
Status = IpSecCryptoIoDecrypt (
|
|
(UINT8) SessionCommon->SaParams->EncAlgId,
|
|
IkeSaSession->IkeKeys->SkErKey,
|
|
IkeSaSession->IkeKeys->SkErKeySize << 3,
|
|
IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
|
|
DecryptedBuf,
|
|
DecryptedSize,
|
|
DecryptedBuf
|
|
);
|
|
} else {
|
|
Status = IpSecCryptoIoDecrypt (
|
|
(UINT8) SessionCommon->SaParams->EncAlgId,
|
|
IkeSaSession->IkeKeys->SkEiKey,
|
|
IkeSaSession->IkeKeys->SkEiKeySize << 3,
|
|
IkePacket->PayloadsBuf + sizeof (IKEV2_COMMON_PAYLOAD_HEADER),
|
|
DecryptedBuf,
|
|
DecryptedSize,
|
|
DecryptedBuf
|
|
);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Error decrypt buffer with %r\n", Status));
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Get the Padding length
|
|
//
|
|
//
|
|
PadLen = (UINT8) (*(DecryptedBuf + DecryptedSize - sizeof (IKEV2_PAD_LEN)));
|
|
|
|
//
|
|
// Save the next payload of encrypted payload into IkePacket->Hdr->NextPayload
|
|
//
|
|
IkePacket->Header->NextPayload = ((IKEV2_ENCRYPTED *) IkePacket->PayloadsBuf)->Header.NextPayload;
|
|
|
|
//
|
|
// Free old IkePacket->PayloadBuf and point it to decrypted paylaod buffer.
|
|
//
|
|
FreePool (IkePacket->PayloadsBuf);
|
|
IkePacket->PayloadsBuf = DecryptedBuf;
|
|
IkePacket->PayloadTotalSize = DecryptedSize - PadLen;
|
|
|
|
IPSEC_DUMP_BUF ("Decrypted Buffer", DecryptedBuf, DecryptedSize);
|
|
|
|
|
|
ON_EXIT:
|
|
if (CheckSumData != NULL) {
|
|
FreePool (CheckSumData);
|
|
}
|
|
|
|
if (EFI_ERROR (Status) && DecryptedBuf != NULL) {
|
|
FreePool (DecryptedBuf);
|
|
}
|
|
|
|
if (IntegrityBuffer != NULL) {
|
|
FreePool (IntegrityBuffer);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Encrypt IKE packet.
|
|
|
|
This function encrypt IKE packet before sending it. The Encrypted IKE packet
|
|
is put in to IKEV2 Encrypted Payload.
|
|
|
|
@param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the IKE packet.
|
|
@param[in, out] IkePacket Pointer to IKE packet to be encrypted.
|
|
|
|
@retval EFI_SUCCESS Operation is successful.
|
|
@retval Others Operation is failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2EncryptPacket (
|
|
IN IKEV2_SESSION_COMMON *SessionCommon,
|
|
IN OUT IKE_PACKET *IkePacket
|
|
)
|
|
{
|
|
UINT8 CryptBlockSize; // Encrypt Block Size
|
|
UINT8 CryptBlockSizeMask; // Block Mask
|
|
UINTN EncryptedSize; // Encrypted IKE Payload Size
|
|
UINT8 *EncryptedBuf; // Encrypted IKE Payload buffer
|
|
UINT8 *EncryptPayloadBuf; // Contain whole Encrypted Payload
|
|
UINTN EncryptPayloadSize; // Total size of the Encrypted payload
|
|
UINT8 *IntegrityBuf; // Buffer to be intergity
|
|
UINT8 *IvBuffer; // Initialization Vector
|
|
UINT8 IvSize; // Iv Size
|
|
UINT8 CheckSumSize; // Integrity Check Sum Size depends on intergrity Auth
|
|
UINT8 *CheckSumData; // Check Sum data
|
|
UINTN Index;
|
|
IKE_PAYLOAD *EncryptPayload;
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
IKEV2_CHILD_SA_SESSION *ChildSaSession;
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *Entry;
|
|
IKE_PAYLOAD *IkePayload;
|
|
HASH_DATA_FRAGMENT Fragments[1];
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// Initial all buffers to NULL.
|
|
//
|
|
EncryptedBuf = NULL;
|
|
EncryptPayloadBuf = NULL;
|
|
IvBuffer = NULL;
|
|
CheckSumData = NULL;
|
|
IkeSaSession = NULL;
|
|
CryptBlockSize = 0;
|
|
CheckSumSize = 0;
|
|
IntegrityBuf = NULL;
|
|
//
|
|
// Get the Block Size
|
|
//
|
|
if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {
|
|
|
|
CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) SessionCommon->SaParams->EncAlgId);
|
|
CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) SessionCommon->SaParams->IntegAlgId);
|
|
IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);
|
|
|
|
} else if (SessionCommon->IkeSessionType == IkeSessionTypeChildSa) {
|
|
|
|
ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);
|
|
IkeSaSession = ChildSaSession->IkeSaSession;
|
|
CryptBlockSize = (UINT8) IpSecGetEncryptBlockSize ((UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId);
|
|
CheckSumSize = (UINT8) IpSecGetIcvLength ((UINT8) IkeSaSession->SessionCommon.SaParams->IntegAlgId);
|
|
}
|
|
|
|
//
|
|
// Calcualte the EncryptPayloadSize and the PAD length
|
|
//
|
|
CryptBlockSizeMask = (UINT8) (CryptBlockSize - 1);
|
|
EncryptedSize = (IkePacket->PayloadTotalSize + sizeof (IKEV2_PAD_LEN) + CryptBlockSizeMask) & ~CryptBlockSizeMask;
|
|
EncryptedBuf = (UINT8 *) AllocateZeroPool (EncryptedSize);
|
|
if (EncryptedBuf == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Copy all payload into EncryptedIkePayload
|
|
//
|
|
Index = 0;
|
|
NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
|
|
IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);
|
|
|
|
CopyMem (EncryptedBuf + Index, IkePayload->PayloadBuf, IkePayload->PayloadSize);
|
|
Index += IkePayload->PayloadSize;
|
|
|
|
};
|
|
|
|
//
|
|
// Fill in the Pading Length
|
|
//
|
|
*(EncryptedBuf + EncryptedSize - 1) = (UINT8)(EncryptedSize - IkePacket->PayloadTotalSize - 1);
|
|
|
|
//
|
|
// The IV size is equal with block size
|
|
//
|
|
IvSize = CryptBlockSize;
|
|
IvBuffer = (UINT8 *) AllocateZeroPool (IvSize);
|
|
if (IvBuffer == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Generate IV
|
|
//
|
|
IkeGenerateIv (IvBuffer, IvSize);
|
|
|
|
//
|
|
// Encrypt payload buf
|
|
//
|
|
if (SessionCommon->IsInitiator) {
|
|
Status = IpSecCryptoIoEncrypt (
|
|
(UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId,
|
|
IkeSaSession->IkeKeys->SkEiKey,
|
|
IkeSaSession->IkeKeys->SkEiKeySize << 3,
|
|
IvBuffer,
|
|
EncryptedBuf,
|
|
EncryptedSize,
|
|
EncryptedBuf
|
|
);
|
|
} else {
|
|
Status = IpSecCryptoIoEncrypt (
|
|
(UINT8) IkeSaSession->SessionCommon.SaParams->EncAlgId,
|
|
IkeSaSession->IkeKeys->SkErKey,
|
|
IkeSaSession->IkeKeys->SkErKeySize << 3,
|
|
IvBuffer,
|
|
EncryptedBuf,
|
|
EncryptedSize,
|
|
EncryptedBuf
|
|
);
|
|
}
|
|
if (EFI_ERROR (Status)) {
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Allocate the buffer for the whole IKE payload (Encrypted Payload).
|
|
//
|
|
EncryptPayloadSize = sizeof(IKEV2_ENCRYPTED) + IvSize + EncryptedSize + CheckSumSize;
|
|
EncryptPayloadBuf = AllocateZeroPool (EncryptPayloadSize);
|
|
if (EncryptPayloadBuf == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Fill in Header of Encrypted Payload
|
|
//
|
|
((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.NextPayload = IkePacket->Header->NextPayload;
|
|
((IKEV2_ENCRYPTED *) EncryptPayloadBuf)->Header.PayloadLength = HTONS ((UINT16)EncryptPayloadSize);
|
|
|
|
//
|
|
// Fill in Iv
|
|
//
|
|
CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED), IvBuffer, IvSize);
|
|
|
|
//
|
|
// Fill in encrypted data
|
|
//
|
|
CopyMem (EncryptPayloadBuf + sizeof (IKEV2_ENCRYPTED) + IvSize, EncryptedBuf, EncryptedSize);
|
|
|
|
//
|
|
// Fill in the IKE Packet header
|
|
//
|
|
IkePacket->PayloadTotalSize = EncryptPayloadSize;
|
|
IkePacket->Header->Length = (UINT32) (sizeof (IKE_HEADER) + IkePacket->PayloadTotalSize);
|
|
IkePacket->Header->NextPayload = IKEV2_PAYLOAD_TYPE_ENCRYPT;
|
|
|
|
IntegrityBuf = AllocateZeroPool (IkePacket->Header->Length);
|
|
if (IntegrityBuf == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
IkeHdrHostToNet (IkePacket->Header);
|
|
|
|
CopyMem (IntegrityBuf, IkePacket->Header, sizeof (IKE_HEADER));
|
|
CopyMem (IntegrityBuf + sizeof (IKE_HEADER), EncryptPayloadBuf, EncryptPayloadSize);
|
|
|
|
//
|
|
// Calcualte Integrity CheckSum
|
|
//
|
|
Fragments[0].Data = IntegrityBuf;
|
|
Fragments[0].DataSize = EncryptPayloadSize + sizeof (IKE_HEADER) - CheckSumSize;
|
|
|
|
CheckSumData = AllocateZeroPool (CheckSumSize);
|
|
if (CheckSumData == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
if (SessionCommon->IsInitiator) {
|
|
|
|
IpSecCryptoIoHmac (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
|
|
IkeSaSession->IkeKeys->SkAiKey,
|
|
IkeSaSession->IkeKeys->SkAiKeySize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
1,
|
|
CheckSumData,
|
|
CheckSumSize
|
|
);
|
|
} else {
|
|
|
|
IpSecCryptoIoHmac (
|
|
(UINT8)IkeSaSession->SessionCommon.SaParams->IntegAlgId,
|
|
IkeSaSession->IkeKeys->SkArKey,
|
|
IkeSaSession->IkeKeys->SkArKeySize,
|
|
(HASH_DATA_FRAGMENT *) Fragments,
|
|
1,
|
|
CheckSumData,
|
|
CheckSumSize
|
|
);
|
|
}
|
|
|
|
//
|
|
// Copy CheckSum into Encrypted Payload
|
|
//
|
|
CopyMem (EncryptPayloadBuf + EncryptPayloadSize - CheckSumSize, CheckSumData, CheckSumSize);
|
|
|
|
IPSEC_DUMP_BUF ("Encrypted payload buffer", EncryptPayloadBuf, EncryptPayloadSize);
|
|
IPSEC_DUMP_BUF ("Integrith CheckSum Data", CheckSumData, CheckSumSize);
|
|
|
|
//
|
|
// Clean all payload under IkePacket->PayloadList.
|
|
//
|
|
ClearAllPayloads (IkePacket);
|
|
|
|
//
|
|
// Create Encrypted Payload and add into IkePacket->PayloadList
|
|
//
|
|
EncryptPayload = IkePayloadAlloc ();
|
|
if (EncryptPayload == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto ON_EXIT;
|
|
}
|
|
|
|
//
|
|
// Fill the encrypted payload into the IKE_PAYLOAD structure.
|
|
//
|
|
EncryptPayload->PayloadBuf = EncryptPayloadBuf;
|
|
EncryptPayload->PayloadSize = EncryptPayloadSize;
|
|
EncryptPayload->PayloadType = IKEV2_PAYLOAD_TYPE_ENCRYPT;
|
|
|
|
IKE_PACKET_APPEND_PAYLOAD (IkePacket, EncryptPayload);
|
|
|
|
ON_EXIT:
|
|
if (EncryptedBuf != NULL) {
|
|
FreePool (EncryptedBuf);
|
|
}
|
|
|
|
if (EFI_ERROR (Status) && EncryptPayloadBuf != NULL) {
|
|
FreePool (EncryptPayloadBuf);
|
|
}
|
|
|
|
if (IvBuffer != NULL) {
|
|
FreePool (IvBuffer);
|
|
}
|
|
|
|
if (CheckSumData != NULL) {
|
|
FreePool (CheckSumData);
|
|
}
|
|
|
|
if (IntegrityBuf != NULL) {
|
|
FreePool (IntegrityBuf);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Save some useful payloads after accepting the Packet.
|
|
|
|
@param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to the operation.
|
|
@param[in] IkePacket Pointer to received IkePacet.
|
|
@param[in] IkeType The type used to indicate it is in IkeSa or ChildSa or Info
|
|
exchange.
|
|
|
|
**/
|
|
VOID
|
|
Ikev2OnPacketAccepted (
|
|
IN IKEV2_SESSION_COMMON *SessionCommon,
|
|
IN IKE_PACKET *IkePacket,
|
|
IN UINT8 IkeType
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/**
|
|
|
|
The notification function. It will be called when the related UDP_TX_TOKEN's event
|
|
is signaled.
|
|
|
|
This function frees the Net Buffer pointed to the input Packet.
|
|
|
|
@param[in] Packet Pointer to Net buffer containing the sending IKE packet.
|
|
@param[in] EndPoint Pointer to UDP_END_POINT containing the remote and local
|
|
address information.
|
|
@param[in] IoStatus The Status of the related UDP_TX_TOKEN.
|
|
@param[in] Context Pointer to data passed from the caller.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Ikev2OnPacketSent (
|
|
IN NET_BUF *Packet,
|
|
IN UDP_END_POINT *EndPoint,
|
|
IN EFI_STATUS IoStatus,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
IKE_PACKET *IkePacket;
|
|
IKEV2_SA_SESSION *IkeSaSession;
|
|
IKEV2_CHILD_SA_SESSION *ChildSaSession;
|
|
UINT8 Value;
|
|
IPSEC_PRIVATE_DATA *Private;
|
|
EFI_STATUS Status;
|
|
|
|
IkePacket = (IKE_PACKET *) Context;
|
|
Private = NULL;
|
|
|
|
if (EFI_ERROR (IoStatus)) {
|
|
DEBUG ((DEBUG_ERROR, "Error send the last packet in IkeSessionTypeIkeSa with %r\n", IoStatus));
|
|
}
|
|
|
|
NetbufFree (Packet);
|
|
|
|
if (IkePacket->IsDeleteInfo) {
|
|
//
|
|
// For each RemotePeerIP, there are only one IKESA.
|
|
//
|
|
IkeSaSession = Ikev2SaSessionLookup (
|
|
&IkePacket->Private->Ikev2EstablishedList,
|
|
&IkePacket->RemotePeerIp
|
|
);
|
|
if (IkeSaSession == NULL) {
|
|
IkePacketFree (IkePacket);
|
|
return;
|
|
}
|
|
|
|
Private = IkePacket->Private;
|
|
if (IkePacket->Spi != 0 ) {
|
|
//
|
|
// At that time, the established Child SA still in eht ChildSaEstablishSessionList.
|
|
// And meanwhile, if the Child SA is in the the ChildSa in Delete list,
|
|
// remove it from delete list and delete it direclty.
|
|
//
|
|
ChildSaSession = Ikev2ChildSaSessionLookupBySpi (
|
|
&IkeSaSession->ChildSaEstablishSessionList,
|
|
IkePacket->Spi
|
|
);
|
|
if (ChildSaSession != NULL) {
|
|
Ikev2ChildSaSessionRemove (
|
|
&IkeSaSession->DeleteSaList,
|
|
ChildSaSession->LocalPeerSpi,
|
|
IKEV2_DELET_CHILDSA_LIST
|
|
);
|
|
|
|
//
|
|
// Delete the Child SA.
|
|
//
|
|
Ikev2ChildSaSilentDelete (
|
|
IkeSaSession,
|
|
IkePacket->Spi
|
|
);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// Delete the IKE SA
|
|
//
|
|
DEBUG (
|
|
(DEBUG_INFO,
|
|
"\n------ deleted Packet (cookie_i, cookie_r):(0x%lx, 0x%lx)------\n",
|
|
IkeSaSession->InitiatorCookie,
|
|
IkeSaSession->ResponderCookie)
|
|
);
|
|
|
|
RemoveEntryList (&IkeSaSession->BySessionTable);
|
|
Ikev2SaSessionFree (IkeSaSession);
|
|
}
|
|
}
|
|
IkePacketFree (IkePacket);
|
|
|
|
//
|
|
// when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec status
|
|
// should be changed.
|
|
//
|
|
if (Private != NULL && Private->IsIPsecDisabling) {
|
|
//
|
|
// After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in
|
|
// IPsec status variable.
|
|
//
|
|
if (IsListEmpty (&Private->Ikev1EstablishedList) && IsListEmpty (&Private->Ikev2EstablishedList)) {
|
|
Value = IPSEC_STATUS_DISABLED;
|
|
Status = gRT->SetVariable (
|
|
IPSECCONFIG_STATUS_NAME,
|
|
&gEfiIpSecConfigProtocolGuid,
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
|
|
sizeof (Value),
|
|
&Value
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
//
|
|
// Set the DisabledFlag in Private data.
|
|
//
|
|
Private->IpSec.DisabledFlag = TRUE;
|
|
Private->IsIPsecDisabling = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Send out IKEV2 packet.
|
|
|
|
@param[in] IkeUdpService Pointer to IKE_UDP_SERVICE used to send the IKE packet.
|
|
@param[in] SessionCommon Pointer to IKEV1_SESSION_COMMON related to the IKE packet.
|
|
@param[in] IkePacket Pointer to IKE_PACKET to be sent out.
|
|
@param[in] IkeType The type of IKE to point what's kind of the IKE
|
|
packet is to be sent out. IKE_SA_TYPE, IKE_INFO_TYPE
|
|
and IKE_CHILD_TYPE are supportted.
|
|
|
|
@retval EFI_SUCCESS The operation complete successfully.
|
|
@retval Otherwise The operation is failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
Ikev2SendIkePacket (
|
|
IN IKE_UDP_SERVICE *IkeUdpService,
|
|
IN UINT8 *SessionCommon,
|
|
IN IKE_PACKET *IkePacket,
|
|
IN UINTN IkeType
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
NET_BUF *IkePacketNetbuf;
|
|
UDP_END_POINT EndPoint;
|
|
IKEV2_SESSION_COMMON *Common;
|
|
|
|
Common = (IKEV2_SESSION_COMMON *) SessionCommon;
|
|
|
|
//
|
|
// Set the resend interval
|
|
//
|
|
if (Common->TimeoutInterval == 0) {
|
|
Common->TimeoutInterval = IKE_DEFAULT_TIMEOUT_INTERVAL;
|
|
}
|
|
|
|
//
|
|
// Retransfer the packet if it is initial packet.
|
|
//
|
|
if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) {
|
|
//
|
|
// Set timer for next retry, this will cancel previous timer
|
|
//
|
|
Status = gBS->SetTimer (
|
|
Common->TimeoutEvent,
|
|
TimerRelative,
|
|
MultU64x32 (Common->TimeoutInterval, 10000) // ms->100ns
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
IKE_PACKET_REF (IkePacket);
|
|
//
|
|
// If the last sent packet is same with this round packet, the packet is resent packet.
|
|
//
|
|
if (IkePacket != Common->LastSentPacket && Common->LastSentPacket != NULL) {
|
|
IkePacketFree (Common->LastSentPacket);
|
|
}
|
|
|
|
Common->LastSentPacket = IkePacket;
|
|
|
|
//
|
|
// Transform IkePacke to NetBuf
|
|
//
|
|
IkePacketNetbuf = IkeNetbufFromPacket ((UINT8 *) SessionCommon, IkePacket, IkeType);
|
|
if (IkePacketNetbuf == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ZeroMem (&EndPoint, sizeof (UDP_END_POINT));
|
|
EndPoint.RemotePort = IKE_DEFAULT_PORT;
|
|
CopyMem (&IkePacket->RemotePeerIp, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS));
|
|
CopyMem (&EndPoint.RemoteAddr, &Common->RemotePeerIp, sizeof (EFI_IP_ADDRESS));
|
|
CopyMem (&EndPoint.LocalAddr, &Common->LocalPeerIp, sizeof (EFI_IP_ADDRESS));
|
|
|
|
IPSEC_DUMP_PACKET (IkePacket, EfiIPsecOutBound, IkeUdpService->IpVersion);
|
|
|
|
if (IkeUdpService->IpVersion == IP_VERSION_4) {
|
|
EndPoint.RemoteAddr.Addr[0] = HTONL (EndPoint.RemoteAddr.Addr[0]);
|
|
EndPoint.LocalAddr.Addr[0] = HTONL (EndPoint.LocalAddr.Addr[0]);
|
|
}
|
|
|
|
//
|
|
// Call UDPIO to send out the IKE packet.
|
|
//
|
|
Status = UdpIoSendDatagram (
|
|
IkeUdpService->Output,
|
|
IkePacketNetbuf,
|
|
&EndPoint,
|
|
NULL,
|
|
Ikev2OnPacketSent,
|
|
(VOID*)IkePacket
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "Error send packet with %r\n", Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|