mirror of https://github.com/acidanthera/audk.git
1022 lines
29 KiB
C
1022 lines
29 KiB
C
/** @file
|
|
Common interfaces to call Security library.
|
|
|
|
Copyright (c) 2009 - 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 "IpSecCryptIo.h"
|
|
//
|
|
// The informations for the supported Encrypt/Decrpt Alogrithm.
|
|
//
|
|
GLOBAL_REMOVE_IF_UNREFERENCED ENCRYPT_ALGORITHM mIpsecEncryptAlgorithmList[IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE] = {
|
|
{IKE_EALG_NULL, 0, 0, 1, NULL, NULL, NULL, NULL},
|
|
{IKE_EALG_NONE, 0, 0, 1, NULL, NULL, NULL, NULL},
|
|
{IKE_EALG_3DESCBC, 24, 8, 8, TdesGetContextSize, TdesInit, TdesCbcEncrypt, TdesCbcDecrypt},
|
|
{IKE_EALG_AESCBC, 16, 16, 16, AesGetContextSize, AesInit, AesCbcEncrypt, AesCbcDecrypt}
|
|
};
|
|
|
|
//
|
|
// The informations for the supported Authentication algorithm
|
|
//
|
|
GLOBAL_REMOVE_IF_UNREFERENCED AUTH_ALGORITHM mIpsecAuthAlgorithmList[IPSEC_AUTH_ALGORITHM_LIST_SIZE] = {
|
|
{IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},
|
|
{IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},
|
|
{IKE_AALG_SHA1HMAC, 20, 12, 64, HmacSha1GetContextSize, HmacSha1Init, HmacSha1Update, HmacSha1Final}
|
|
};
|
|
|
|
//
|
|
// The information for the supported Hash aglorithm
|
|
//
|
|
GLOBAL_REMOVE_IF_UNREFERENCED HASH_ALGORITHM mIpsecHashAlgorithmList[IPSEC_HASH_ALGORITHM_LIST_SIZE] = {
|
|
{IKE_AALG_NONE, 0, 0, 0, NULL, NULL, NULL, NULL},
|
|
{IKE_AALG_NULL, 0, 0, 0, NULL, NULL, NULL, NULL},
|
|
{IKE_AALG_SHA1HMAC, 20, 12, 64, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final}
|
|
};
|
|
|
|
BOOLEAN mInitialRandomSeed = FALSE;
|
|
|
|
/**
|
|
Get the block size of specified encryption algorithm.
|
|
|
|
@param[in] AlgorithmId The encryption algorithm ID.
|
|
|
|
@return The value of block size.
|
|
|
|
**/
|
|
UINTN
|
|
IpSecGetEncryptBlockSize (
|
|
IN UINT8 AlgorithmId
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
|
|
if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
|
|
return mIpsecEncryptAlgorithmList[Index].BlockSize;
|
|
}
|
|
}
|
|
|
|
return (UINTN) -1;
|
|
}
|
|
|
|
/**
|
|
Get the key length of the specified encryption algorithm.
|
|
|
|
@param[in] AlgorithmId The encryption algorithm ID.
|
|
|
|
@return The value of key length.
|
|
|
|
**/
|
|
UINTN
|
|
IpSecGetEncryptKeyLength (
|
|
IN UINT8 AlgorithmId
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
|
|
if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
|
|
return mIpsecEncryptAlgorithmList[Index].KeyLength;
|
|
}
|
|
}
|
|
|
|
return (UINTN) -1;
|
|
}
|
|
|
|
/**
|
|
Get the IV size of the specified encryption algorithm.
|
|
|
|
@param[in] AlgorithmId The encryption algorithm ID.
|
|
|
|
@return The value of IV size.
|
|
|
|
**/
|
|
UINTN
|
|
IpSecGetEncryptIvLength (
|
|
IN UINT8 AlgorithmId
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
|
|
if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
|
|
return mIpsecEncryptAlgorithmList[Index].IvLength;
|
|
}
|
|
}
|
|
|
|
return (UINTN) -1;
|
|
}
|
|
|
|
/**
|
|
Get the HMAC digest length by the specified Algorithm ID.
|
|
|
|
@param[in] AlgorithmId The specified Alogrithm ID.
|
|
|
|
@return The digest length of the specified Authentication Algorithm ID.
|
|
|
|
**/
|
|
UINTN
|
|
IpSecGetHmacDigestLength (
|
|
IN UINT8 AlgorithmId
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {
|
|
if (mIpsecAuthAlgorithmList[Index].AlgorithmId == AlgorithmId) {
|
|
//
|
|
// Return the Digest Length of the Algorithm.
|
|
//
|
|
return mIpsecAuthAlgorithmList[Index].DigestLength;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
Get the ICV size of the specified Authenticaion algorithm.
|
|
|
|
@param[in] AlgorithmId The Authentication algorithm ID.
|
|
|
|
@return The value of ICV size.
|
|
|
|
**/
|
|
UINTN
|
|
IpSecGetIcvLength (
|
|
IN UINT8 AlgorithmId
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {
|
|
if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {
|
|
return mIpsecAuthAlgorithmList[Index].IcvLength;
|
|
}
|
|
}
|
|
|
|
return (UINTN) -1;
|
|
}
|
|
|
|
/**
|
|
Generate a random data for IV. If the IvSize is zero, not needed to create
|
|
IV and return EFI_SUCCESS.
|
|
|
|
@param[in] IvBuffer The pointer of the IV buffer.
|
|
@param[in] IvSize The IV size in bytes.
|
|
|
|
@retval EFI_SUCCESS Create a random data for IV.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecGenerateIv (
|
|
IN UINT8 *IvBuffer,
|
|
IN UINTN IvSize
|
|
)
|
|
{
|
|
if (IvSize != 0) {
|
|
return IpSecCryptoIoGenerateRandomBytes (IvBuffer, IvSize);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Get index of the specified encryption algorithm from the mIpsecEncryptAlgorithmList.
|
|
|
|
@param[in] AlgorithmId The encryption algorithm ID.
|
|
|
|
@return the index.
|
|
|
|
**/
|
|
UINTN
|
|
IpSecGetIndexFromEncList (
|
|
IN UINT8 AlgorithmId
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
for (Index = 0; Index < IPSEC_ENCRYPT_ALGORITHM_LIST_SIZE; Index++) {
|
|
if (AlgorithmId == mIpsecEncryptAlgorithmList[Index].AlgorithmId) {
|
|
return Index;
|
|
}
|
|
}
|
|
|
|
return (UINTN) -1;
|
|
}
|
|
|
|
/**
|
|
Get index of the specified encryption algorithm from the mIpsecAuthAlgorithmList.
|
|
|
|
@param[in] AlgorithmId The encryption algorithm ID.
|
|
|
|
@return the index.
|
|
|
|
**/
|
|
UINTN
|
|
IpSecGetIndexFromAuthList (
|
|
IN UINT8 AlgorithmId
|
|
)
|
|
{
|
|
UINT8 Index;
|
|
|
|
for (Index = 0; Index < IPSEC_AUTH_ALGORITHM_LIST_SIZE; Index++) {
|
|
if (AlgorithmId == mIpsecAuthAlgorithmList[Index].AlgorithmId) {
|
|
//
|
|
// The BlockSize is same with IvSize.
|
|
//
|
|
return Index;
|
|
}
|
|
}
|
|
|
|
return (UINTN) -1;
|
|
}
|
|
|
|
/**
|
|
Encrypt the buffer.
|
|
|
|
This function calls relevant encryption interface from CryptoLib according to
|
|
the input algorithm ID. The InData should be multiple of block size. This function
|
|
doesn't perform the padding. If it has the Ivec data, the length of it should be
|
|
same with the block size. The block size is different from the different algorithm.
|
|
|
|
@param[in] AlgorithmId The Algorithm identification defined in RFC.
|
|
@param[in] Key Pointer to the buffer containing encrypting key.
|
|
@param[in] KeyBits The length of the key in bits.
|
|
@param[in] Ivec Point to the buffer containing the Initialization
|
|
Vector (IV) data.
|
|
@param[in] InData Point to the buffer containing the data to be
|
|
encrypted.
|
|
@param[in] InDataLength The length of InData in Bytes.
|
|
@param[out] OutData Point to the buffer that receives the encryption
|
|
output.
|
|
|
|
@retval EFI_UNSUPPORTED The input Algorithm is not supported.
|
|
@retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.
|
|
@retval EFI_SUCCESS The operation completed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoEncrypt (
|
|
IN CONST UINT8 AlgorithmId,
|
|
IN CONST UINT8 *Key,
|
|
IN CONST UINTN KeyBits,
|
|
IN CONST UINT8 *Ivec, OPTIONAL
|
|
IN UINT8 *InData,
|
|
IN UINTN InDataLength,
|
|
OUT UINT8 *OutData
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN ContextSize;
|
|
UINT8 *Context;
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
switch (AlgorithmId) {
|
|
|
|
case IKE_EALG_NULL:
|
|
case IKE_EALG_NONE:
|
|
CopyMem (OutData, InData, InDataLength);
|
|
return EFI_SUCCESS;
|
|
|
|
case IKE_EALG_3DESCBC:
|
|
case IKE_EALG_AESCBC:
|
|
Index = IpSecGetIndexFromEncList (AlgorithmId);
|
|
if (Index == -1) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Get Context Size
|
|
//
|
|
ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize ();
|
|
Context = AllocateZeroPool (ContextSize);
|
|
|
|
if (Context == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// Initiate Context
|
|
//
|
|
if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {
|
|
if (mIpsecEncryptAlgorithmList[Index].CipherEncrypt (Context, InData, InDataLength, Ivec, OutData)) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return Status;
|
|
|
|
}
|
|
|
|
if (Context != NULL) {
|
|
FreePool (Context);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Decrypts the buffer.
|
|
|
|
This function calls relevant Decryption interface from CryptoLib according to
|
|
the input algorithm ID. The InData should be multiple of block size. This function
|
|
doesn't perform the padding. If it has the Ivec data, the length of it should be
|
|
same with the block size. The block size is different from the different algorithm.
|
|
|
|
@param[in] AlgorithmId The Algorithm identification defined in RFC.
|
|
@param[in] Key Pointer to the buffer containing encrypting key.
|
|
@param[in] KeyBits The length of the key in bits.
|
|
@param[in] Ivec Point to the buffer containing the Initialization
|
|
Vector (IV) data.
|
|
@param[in] InData Point to the buffer containing the data to be
|
|
decrypted.
|
|
@param[in] InDataLength The length of InData in Bytes.
|
|
@param[out] OutData Pointer to the buffer that receives the decryption
|
|
output.
|
|
|
|
@retval EFI_UNSUPPORTED The input Algorithm is not supported.
|
|
@retval EFI_OUT_OF_RESOURCE The required resource can't be allocated.
|
|
@retval EFI_SUCCESS The operation completed successfully.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoDecrypt (
|
|
IN CONST UINT8 AlgorithmId,
|
|
IN CONST UINT8 *Key,
|
|
IN CONST UINTN KeyBits,
|
|
IN CONST UINT8 *Ivec, OPTIONAL
|
|
IN UINT8 *InData,
|
|
IN UINTN InDataLength,
|
|
OUT UINT8 *OutData
|
|
)
|
|
{
|
|
UINTN Index;
|
|
UINTN ContextSize;
|
|
UINT8 *Context;
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
|
|
switch (AlgorithmId) {
|
|
|
|
case IKE_EALG_NULL:
|
|
case IKE_EALG_NONE:
|
|
CopyMem (OutData, InData, InDataLength);
|
|
return EFI_SUCCESS;
|
|
|
|
case IKE_EALG_3DESCBC:
|
|
case IKE_EALG_AESCBC:
|
|
Index = IpSecGetIndexFromEncList(AlgorithmId);
|
|
if (Index == -1) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Get Context Size
|
|
//
|
|
ContextSize = mIpsecEncryptAlgorithmList[Index].CipherGetContextSize();
|
|
Context = AllocateZeroPool (ContextSize);
|
|
if (Context == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Initiate Context
|
|
//
|
|
if (mIpsecEncryptAlgorithmList[Index].CipherInitiate (Context, Key, KeyBits)) {
|
|
if (mIpsecEncryptAlgorithmList[Index].CipherDecrypt (Context, InData, InDataLength, Ivec, OutData)) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return Status;
|
|
}
|
|
|
|
if (Context != NULL) {
|
|
FreePool (Context);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Digests the Payload with key and store the result into the OutData.
|
|
|
|
This function calls relevant Hmac interface from CryptoLib according to
|
|
the input algorithm ID. It computes all datas from InDataFragment and output
|
|
the result into the OutData buffer. If the OutDataSize is larger than the related
|
|
HMAC algorithm output size, return EFI_INVALID_PARAMETER.
|
|
|
|
@param[in] AlgorithmId The authentication Identification.
|
|
@param[in] Key Pointer of the authentication key.
|
|
@param[in] KeyLength The length of the Key in bytes.
|
|
@param[in] InDataFragment The list contains all data to be authenticated.
|
|
@param[in] FragmentCount The size of the InDataFragment.
|
|
@param[out] OutData For in, the buffer to receive the output data.
|
|
For out, the buffer contains the authenticated data.
|
|
@param[in] OutDataSize The size of the buffer of OutData.
|
|
|
|
@retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.
|
|
@retval EFI_INVALID_PARAMETER The OutData buffer size is larger than algorithm digest size.
|
|
@retval EFI_SUCCESS Authenticate the payload successfully.
|
|
@retval otherwise Authentication of the payload fails.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoHmac (
|
|
IN CONST UINT8 AlgorithmId,
|
|
IN CONST UINT8 *Key,
|
|
IN UINTN KeyLength,
|
|
IN HASH_DATA_FRAGMENT *InDataFragment,
|
|
IN UINTN FragmentCount,
|
|
OUT UINT8 *OutData,
|
|
IN UINTN OutDataSize
|
|
)
|
|
{
|
|
UINTN ContextSize;
|
|
UINTN Index;
|
|
UINT8 FragmentIndex;
|
|
UINT8 *HashContext;
|
|
EFI_STATUS Status;
|
|
UINT8 *OutHashData;
|
|
UINTN OutHashSize;
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
OutHashData = NULL;
|
|
|
|
OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);
|
|
//
|
|
// If the expected hash data size is larger than the related Hash algorithm
|
|
// output length, return EFI_INVALID_PARAMETER.
|
|
//
|
|
if (OutDataSize > OutHashSize) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
OutHashData = AllocatePool (OutHashSize);
|
|
|
|
if (OutHashData == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
switch (AlgorithmId) {
|
|
|
|
case IKE_AALG_NONE :
|
|
case IKE_AALG_NULL :
|
|
return EFI_SUCCESS;
|
|
|
|
case IKE_AALG_SHA1HMAC:
|
|
Index = IpSecGetIndexFromAuthList (AlgorithmId);
|
|
if (Index == -1) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Get Context Size
|
|
//
|
|
ContextSize = mIpsecAuthAlgorithmList[Index].HmacGetContextSize();
|
|
HashContext = AllocateZeroPool (ContextSize);
|
|
|
|
if (HashContext == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Initiate HMAC context and hash the input data.
|
|
//
|
|
if (mIpsecAuthAlgorithmList[Index].HmacInitiate(HashContext, Key, KeyLength)) {
|
|
for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {
|
|
if (!mIpsecAuthAlgorithmList[Index].HmacUpdate (
|
|
HashContext,
|
|
InDataFragment[FragmentIndex].Data,
|
|
InDataFragment[FragmentIndex].DataSize
|
|
)
|
|
) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
if (mIpsecAuthAlgorithmList[Index].HmacFinal (HashContext, OutHashData)) {
|
|
//
|
|
// In some cases, like the Icv computing, the Icv size might be less than
|
|
// the key length size, so copy the part of hash data to the OutData.
|
|
//
|
|
CopyMem (OutData, OutHashData, OutDataSize);
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
default:
|
|
return Status;
|
|
}
|
|
|
|
Exit:
|
|
if (HashContext != NULL) {
|
|
FreePool (HashContext);
|
|
}
|
|
if (OutHashData != NULL) {
|
|
FreePool (OutHashData);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Digests the Payload and store the result into the OutData.
|
|
|
|
This function calls relevant Hash interface from CryptoLib according to
|
|
the input algorithm ID. It computes all datas from InDataFragment and output
|
|
the result into the OutData buffer. If the OutDataSize is larger than the related
|
|
Hash algorithm output size, return EFI_INVALID_PARAMETER.
|
|
|
|
@param[in] AlgorithmId The authentication Identification.
|
|
@param[in] InDataFragment A list contains all data to be authenticated.
|
|
@param[in] FragmentCount The size of the InDataFragment.
|
|
@param[out] OutData For in, the buffer to receive the output data.
|
|
For out, the buffer contains the authenticated data.
|
|
@param[in] OutDataSize The size of the buffer of OutData.
|
|
|
|
@retval EFI_UNSUPPORTED If the AuthAlg is not in the support list.
|
|
@retval EFI_SUCCESS Authenticated the payload successfully.
|
|
@retval EFI_INVALID_PARAMETER If the OutDataSize is larger than the related Hash
|
|
algorithm could handle.
|
|
@retval otherwise Authentication of the payload failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoHash (
|
|
IN CONST UINT8 AlgorithmId,
|
|
IN HASH_DATA_FRAGMENT *InDataFragment,
|
|
IN UINTN FragmentCount,
|
|
OUT UINT8 *OutData,
|
|
IN UINTN OutDataSize
|
|
)
|
|
{
|
|
UINTN ContextSize;
|
|
UINTN Index;
|
|
UINT8 FragmentIndex;
|
|
UINT8 *HashContext;
|
|
EFI_STATUS Status;
|
|
UINT8 *OutHashData;
|
|
UINTN OutHashSize;
|
|
|
|
Status = EFI_UNSUPPORTED;
|
|
OutHashData = NULL;
|
|
|
|
OutHashSize = IpSecGetHmacDigestLength (AlgorithmId);
|
|
//
|
|
// If the expected hash data size is larger than the related Hash algorithm
|
|
// output length, return EFI_INVALID_PARAMETER.
|
|
//
|
|
if (OutDataSize > OutHashSize) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
OutHashData = AllocatePool (OutHashSize);
|
|
if (OutHashData == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
switch (AlgorithmId) {
|
|
|
|
case IKE_AALG_NONE:
|
|
case IKE_AALG_NULL:
|
|
return EFI_SUCCESS;
|
|
|
|
case IKE_AALG_SHA1HMAC:
|
|
Index = IpSecGetIndexFromAuthList (AlgorithmId);
|
|
if (Index == -1) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Get Context Size
|
|
//
|
|
ContextSize = mIpsecHashAlgorithmList[Index].HashGetContextSize();
|
|
HashContext = AllocateZeroPool (ContextSize);
|
|
if (HashContext == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Initiate Hash context and hash the input data.
|
|
//
|
|
if (mIpsecHashAlgorithmList[Index].HashInitiate(HashContext)) {
|
|
for (FragmentIndex = 0; FragmentIndex < FragmentCount; FragmentIndex++) {
|
|
if (!mIpsecHashAlgorithmList[Index].HashUpdate (
|
|
HashContext,
|
|
InDataFragment[FragmentIndex].Data,
|
|
InDataFragment[FragmentIndex].DataSize
|
|
)
|
|
) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
if (mIpsecHashAlgorithmList[Index].HashFinal (HashContext, OutHashData)) {
|
|
//
|
|
// In some cases, like the Icv computing, the Icv size might be less than
|
|
// the key length size, so copy the part of hash data to the OutData.
|
|
//
|
|
CopyMem (OutData, OutHashData, OutDataSize);
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
default:
|
|
return Status;
|
|
}
|
|
|
|
Exit:
|
|
if (HashContext != NULL) {
|
|
FreePool (HashContext);
|
|
}
|
|
if (OutHashData != NULL) {
|
|
FreePool (OutHashData);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Generates the Diffie-Hellman public key.
|
|
|
|
This function first initiate a DHContext, then call the DhSetParameter() to set
|
|
the prime and primelength, at end call the DhGenerateKey() to generates random
|
|
secret exponent, and computes the public key. The output returned via parameter
|
|
PublicKey and PublicKeySize. DH context is updated accordingly. If the PublicKey
|
|
buffer is too small to hold the public key, EFI_INVALID_PARAMETER is returned
|
|
and PublicKeySize is set to the required buffer size to obtain the public key.
|
|
|
|
@param[in, out] DhContext Pointer to the DH context.
|
|
@param[in] Generator Value of generator.
|
|
@param[in] PrimeLength Length in bits of prime to be generated.
|
|
@param[in] Prime Pointer to the buffer to receive the generated
|
|
prime number.
|
|
@param[out] PublicKey Pointer to the buffer to receive generated public key.
|
|
@param[in, out] PublicKeySize For in, the size of PublicKey buffer in bytes.
|
|
For out, the size of data returned in PublicKey
|
|
buffer in bytes.
|
|
|
|
@retval EFI_SUCCESS The operation performs successfully.
|
|
@retval Otherwise The operation is failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoDhGetPublicKey (
|
|
IN OUT UINT8 **DhContext,
|
|
IN UINTN Generator,
|
|
IN UINTN PrimeLength,
|
|
IN CONST UINT8 *Prime,
|
|
OUT UINT8 *PublicKey,
|
|
IN OUT UINTN *PublicKeySize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
*DhContext = DhNew ();
|
|
ASSERT (*DhContext != NULL);
|
|
if (!DhSetParameter (*DhContext, Generator, PrimeLength, Prime)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
if (!DhGenerateKey (*DhContext, PublicKey, PublicKeySize)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
return EFI_SUCCESS;
|
|
|
|
Exit:
|
|
if (*DhContext != NULL) {
|
|
DhFree (*DhContext);
|
|
DhContext = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Generates exchanged common key.
|
|
|
|
Given peer's public key, this function computes the exchanged common key, based
|
|
on its own context including value of prime modulus and random secret exponent.
|
|
|
|
@param[in, out] DhContext Pointer to the DH context.
|
|
@param[in] PeerPublicKey Pointer to the peer's Public Key.
|
|
@param[in] PeerPublicKeySize Size of peer's public key in bytes.
|
|
@param[out] Key Pointer to the buffer to receive generated key.
|
|
@param[in, out] KeySize For in, the size of Key buffer in bytes.
|
|
For out, the size of data returned in Key
|
|
buffer in bytes.
|
|
|
|
@retval EFI_SUCCESS The operation performs successfully.
|
|
@retval Otherwise The operation is failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoDhComputeKey (
|
|
IN OUT UINT8 *DhContext,
|
|
IN CONST UINT8 *PeerPublicKey,
|
|
IN UINTN PeerPublicKeySize,
|
|
OUT UINT8 *Key,
|
|
IN OUT UINTN *KeySize
|
|
)
|
|
{
|
|
if (!DhComputeKey (DhContext, PeerPublicKey, PeerPublicKeySize, Key, KeySize)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Releases the DH context. If DhContext is NULL, return EFI_INVALID_PARAMETER.
|
|
|
|
@param[in, out] DhContext Pointer to the DH context to be freed.
|
|
|
|
@retval EFI_SUCCESS The operation performs successfully.
|
|
@retval EFI_INVALID_PARAMETER The DhContext is NULL.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoFreeDh (
|
|
IN OUT UINT8 **DhContext
|
|
)
|
|
{
|
|
if (*DhContext == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
DhFree (*DhContext);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Generates random numbers of specified size.
|
|
|
|
If the Random Generator wasn't initiated, initiate it first, then call RandomBytes.
|
|
|
|
@param[out] OutBuffer Pointer to buffer to receive random value.
|
|
@param[in] Bytes Size of random bytes to generate.
|
|
|
|
@retval EFI_SUCCESS The operation performs successfully.
|
|
@retval Otherwise The operation is failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoGenerateRandomBytes (
|
|
OUT UINT8* OutBuffer,
|
|
IN UINTN Bytes
|
|
)
|
|
{
|
|
if (!mInitialRandomSeed) {
|
|
RandomSeed (NULL, 0);
|
|
mInitialRandomSeed = TRUE;
|
|
}
|
|
if (RandomBytes (OutBuffer, Bytes)) {
|
|
return EFI_SUCCESS;
|
|
} else {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Authenticate data with the certificate.
|
|
|
|
@param[in] InData Pointer to the Data to be signed.
|
|
@param[in] InDataSize InData size in bytes.
|
|
@param[in] PrivateKey Pointer to the private key.
|
|
@param[in] PrivateKeySize The size of Private Key in bytes.
|
|
@param[in] KeyPassWord Pointer to the password for retrieving private key.
|
|
@param[in] KeyPwdSize The size of Key Password in bytes.
|
|
@param[out] OutData The pointer to the signed data.
|
|
@param[in, out] OutDataSize Pointer to contain the size of out data.
|
|
|
|
**/
|
|
VOID
|
|
IpSecCryptoIoAuthDataWithCertificate (
|
|
IN UINT8 *InData,
|
|
IN UINTN InDataSize,
|
|
IN UINT8 *PrivateKey,
|
|
IN UINTN PrivateKeySize,
|
|
IN UINT8 *KeyPassWord,
|
|
IN UINTN KeyPwdSize,
|
|
OUT UINT8 **OutData,
|
|
IN OUT UINTN *OutDataSize
|
|
)
|
|
{
|
|
UINT8 *RsaContext;
|
|
UINT8 *Signature;
|
|
UINTN SigSize;
|
|
|
|
SigSize = 0;
|
|
RsaContext = NULL;
|
|
|
|
//
|
|
// Retrieve RSA Private Key from password-protected PEM data
|
|
//
|
|
RsaGetPrivateKeyFromPem (
|
|
(CONST UINT8 *)PrivateKey,
|
|
PrivateKeySize,
|
|
(CONST CHAR8 *)KeyPassWord,
|
|
(VOID **) &RsaContext
|
|
);
|
|
if (RsaContext == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Sign data
|
|
//
|
|
Signature = NULL;
|
|
if (!RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize)) {
|
|
Signature = AllocateZeroPool (SigSize);
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
RsaPkcs1Sign (RsaContext, InData, InDataSize, Signature, &SigSize);
|
|
|
|
*OutData = Signature;
|
|
*OutDataSize = SigSize;
|
|
|
|
if (RsaContext != NULL) {
|
|
RsaFree (RsaContext);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Verify the singed data with the public key which is contained in a certificate.
|
|
|
|
@param[in] InCert Pointer to the Certificate which contains the
|
|
public key.
|
|
@param[in] CertLen The size of Certificate in bytes.
|
|
@param[in] InCa Pointer to the CA certificate
|
|
@param[in] CaLen The size of CA certificate in bytes.
|
|
@param[in] InData Pointer to octet message hash to be checked.
|
|
@param[in] InDataSize Size of the message hash in bytes.
|
|
@param[in] Singnature The pointer to the RSA PKCS1-V1_5 signature to be verified.
|
|
@param[in] SigSize Size of signature in bytes.
|
|
|
|
@retval TRUE Valid signature encoded in PKCS1-v1_5.
|
|
@retval FALSE Invalid signature or invalid RSA context.
|
|
|
|
**/
|
|
BOOLEAN
|
|
IpSecCryptoIoVerifySignDataByCertificate (
|
|
IN UINT8 *InCert,
|
|
IN UINTN CertLen,
|
|
IN UINT8 *InCa,
|
|
IN UINTN CaLen,
|
|
IN UINT8 *InData,
|
|
IN UINTN InDataSize,
|
|
IN UINT8 *Singnature,
|
|
IN UINTN SigSize
|
|
)
|
|
{
|
|
UINT8 *RsaContext;
|
|
BOOLEAN Status;
|
|
|
|
//
|
|
// Create the RSA Context
|
|
//
|
|
RsaContext = RsaNew ();
|
|
if (RsaContext == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Verify the validity of X509 Certificate
|
|
//
|
|
if (!X509VerifyCert (InCert, CertLen, InCa, CaLen)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Retrieve the RSA public Key from Certificate
|
|
//
|
|
RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **)&RsaContext);
|
|
|
|
//
|
|
// Verify data
|
|
//
|
|
Status = RsaPkcs1Verify (RsaContext, InData, InDataSize, Singnature, SigSize);
|
|
|
|
if (RsaContext != NULL) {
|
|
RsaFree (RsaContext);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Retrieves the RSA Public Key from one X509 certificate (DER format only).
|
|
|
|
@param[in] InCert Pointer to the certificate.
|
|
@param[in] CertLen The size of the certificate in bytes.
|
|
@param[out] PublicKey Pointer to the retrieved public key.
|
|
@param[out] PublicKeyLen Size of Public Key in bytes.
|
|
|
|
@retval EFI_SUCCESS Successfully get the public Key.
|
|
@retval EFI_INVALID_PARAMETER The certificate is malformed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoGetPublicKeyFromCert (
|
|
IN UINT8 *InCert,
|
|
IN UINTN CertLen,
|
|
OUT UINT8 **PublicKey,
|
|
OUT UINTN *PublicKeyLen
|
|
)
|
|
{
|
|
UINT8 *RsaContext;
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
//
|
|
// Create the RSA Context
|
|
//
|
|
RsaContext = RsaNew ();
|
|
|
|
//
|
|
// Retrieve the RSA public key from CA Certificate
|
|
//
|
|
if (!RsaGetPublicKeyFromX509 ((CONST UINT8 *)InCert, CertLen, (VOID **) &RsaContext)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto EXIT;
|
|
}
|
|
|
|
*PublicKeyLen = 0;
|
|
|
|
RsaGetKey (RsaContext, RsaKeyN, NULL, PublicKeyLen);
|
|
|
|
*PublicKey = AllocateZeroPool (*PublicKeyLen);
|
|
if (*PublicKey == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
if (!RsaGetKey (RsaContext, RsaKeyN, *PublicKey, PublicKeyLen)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
EXIT:
|
|
if (RsaContext != NULL) {
|
|
RsaFree (RsaContext);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Retrieves the subject name from one X509 certificate (DER format only).
|
|
|
|
@param[in] InCert Pointer to the X509 certificate.
|
|
@param[in] CertSize The size of the X509 certificate in bytes.
|
|
@param[out] CertSubject Pointer to the retrieved certificate subject.
|
|
@param[out] SubjectSize The size of Certificate Subject in bytes.
|
|
|
|
@retval EFI_SUCCESS Retrieved the certificate subject successfully.
|
|
@retval EFI_INVALID_PARAMETER The certificate is malformed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
IpSecCryptoIoGetSubjectFromCert (
|
|
IN UINT8 *InCert,
|
|
IN UINTN CertSize,
|
|
OUT UINT8 **CertSubject,
|
|
OUT UINTN *SubjectSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
*SubjectSize = 0;
|
|
X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize);
|
|
|
|
*CertSubject = AllocateZeroPool (*SubjectSize);
|
|
if (!X509GetSubjectName (InCert, CertSize, *CertSubject, SubjectSize)) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return Status;
|
|
}
|