slimbootloader/BootloaderCommonPkg/Library/ContainerLib/ContainerLib.c

951 lines
29 KiB
C

/** @file
Container library implementation.
Copyright (c) 2019 - 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiPei.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/BootloaderCommonLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/BlMemoryAllocationLib.h>
#include <Library/ContainerLib.h>
#include <Library/CryptoLib.h>
#include <Library/SecureBootLib.h>
#include <Library/DecompressLib.h>
#define TEMP_BUF_ALIGN 0x10
#define AUTH_DATA_ALIGN 0x04
#define IS_FLASH_ADDRESS(x) (((UINT32)(UINTN)(x)) >= 0xF0000000)
/**
Get the container pointer by the container signature
@param[in] Signature The signature for the container to get.
@retval NULL The service is not available.
@retval Others The pointer of container entry.
**/
STATIC
CONTAINER_ENTRY *
GetContainerBySignature (
IN UINT32 Signature
)
{
UINT32 Index;
CONTAINER_LIST *ContainerList;
CONTAINER_ENTRY *ContainerEntry;
ContainerList = (CONTAINER_LIST *)GetContainerListPtr ();
if (ContainerList != NULL) {
for (Index = 0; Index < ContainerList->Count; Index++) {
ContainerEntry = (CONTAINER_ENTRY *)&ContainerList->Entry[Index];
if (ContainerEntry->Signature == Signature) {
return ContainerEntry;
}
}
}
return NULL;
}
/**
This function returns the container header size.
@param[in] ContainerEntry Container entry pointer.
@retval Container header size.
**/
STATIC
UINT32
GetContainerHeaderSize (
IN CONTAINER_HDR *ContainerHdr
)
{
INTN Offset;
UINT32 Index;
COMPONENT_ENTRY *CompEntry;
Offset = 0;
if (ContainerHdr != NULL) {
CompEntry = (COMPONENT_ENTRY *)&ContainerHdr[1];
if(ContainerHdr->Count > MAX_CONTAINER_SUB_IMAGE) {
return 0;
}
for (Index = 0; Index < ContainerHdr->Count; Index++) {
CompEntry = (COMPONENT_ENTRY *)((UINT8 *)(CompEntry + 1) + CompEntry->HashSize);
Offset = (UINT8 *)CompEntry - (UINT8 *)ContainerHdr;
if ((Offset < 0) || (Offset > ContainerHdr->DataOffset)) {
Offset = 0;
break;
}
}
}
return (UINT32)Offset;
}
/**
This function registers a container.
@param[in] ContainerBase Container base address to register.
@retval EFI_NOT_READY Not ready for register yet.
@retval EFI_BUFFER_TOO_SMALL Insufficant max container entry number.
@retval EFI_OUT_OF_RESOURCES No space to add new container.
@retval EFI_UNSUPPORTED Duplicated container found.
@retval EFI_SUCCESS The container has been registered successfully.
**/
STATIC
EFI_STATUS
RegisterContainerInternal (
IN UINT32 ContainerBase
)
{
CONTAINER_LIST *ContainerList;
CONTAINER_HDR *ContainerHdr;
CONTAINER_ENTRY *ContainerEntry;
UINT32 Index;
VOID *Buffer;
UINT32 MaxHdrSize;
ContainerList = (CONTAINER_LIST *)GetContainerListPtr ();
if (ContainerList == NULL) {
return EFI_NOT_READY;
}
ContainerHdr = (CONTAINER_HDR *)(UINTN)ContainerBase;
ContainerEntry = GetContainerBySignature (ContainerHdr->Signature);
if (ContainerEntry != NULL) {
return EFI_UNSUPPORTED;
}
Index = ContainerList->Count;
if (Index >= PcdGet32 (PcdContainerMaxNumber)) {
return EFI_BUFFER_TOO_SMALL;
}
MaxHdrSize = GetContainerHeaderSize (ContainerHdr) + SIGNATURE_AND_KEY_SIZE_MAX;
if (MaxHdrSize > ContainerHdr->DataOffset) {
MaxHdrSize = ContainerHdr->DataOffset;
}
Buffer = AllocatePool (MaxHdrSize);
if (Buffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
ContainerList->Entry[Index].Signature = ContainerHdr->Signature;
ContainerList->Entry[Index].HeaderCache = (UINT32)(UINTN)Buffer;
ContainerList->Entry[Index].HeaderSize = MaxHdrSize ;
ContainerList->Entry[Index].Base = ContainerBase;
CopyMem (Buffer, (VOID *)(UINTN)ContainerBase, MaxHdrSize);
ContainerList->Count++;
return EFI_SUCCESS;
}
/**
This function unregisters a container with given signature.
@param[in] Signature Container signature.
@retval EFI_NOT_READY Not ready for unregister yet.
@retval EFI_NOT_FOUND Not container available for unregisteration.
@retval EFI_SUCCESS The container has been unregistered successfully.
**/
EFI_STATUS
UnregisterContainer (
IN UINT32 Signature
)
{
EFI_STATUS Status;
CONTAINER_LIST *ContainerList;
CONTAINER_ENTRY *ContainerEntry;
UINT32 Index;
UINT32 LastIndex;
ContainerList = (CONTAINER_LIST *)GetContainerListPtr ();
if (ContainerList == NULL) {
return EFI_NOT_READY;
}
Status = EFI_NOT_FOUND;
if (ContainerList->Count == 0) {
return Status;
}
LastIndex = ContainerList->Count - 1;
if (Signature == 0xFFFFFFFF) {
Index = LastIndex;
} else {
for (Index = 0; Index < ContainerList->Count; Index++) {
ContainerEntry = (CONTAINER_ENTRY *)&ContainerList->Entry[Index];
if (ContainerEntry->Signature == Signature) {
break;
}
}
}
if (Index < ContainerList->Count) {
FreePool ((VOID *)(UINTN)ContainerList->Entry[Index].HeaderCache);
ContainerList->Entry[Index] = ContainerList->Entry[LastIndex];
ContainerList->Count--;
Status = EFI_SUCCESS;
}
return Status;
}
/**
This function returns the component entry info.
@param[in] ContainerEntry Container entry pointer.
@param[in] ComponentName Component name in container.
@retval Container header size.
**/
COMPONENT_ENTRY *
EFIAPI
LocateComponentEntryFromContainer (
IN CONTAINER_HDR *ContainerHdr,
IN UINT32 ComponentName
)
{
UINT32 Index;
COMPONENT_ENTRY *CompEntry;
COMPONENT_ENTRY *CurrEntry;
CompEntry = NULL;
CurrEntry = (COMPONENT_ENTRY *)&ContainerHdr[1];
for (Index = 0; Index < ContainerHdr->Count; Index++) {
if (CurrEntry->Name == ComponentName) {
CompEntry = CurrEntry;
break;
}
CurrEntry = (COMPONENT_ENTRY *)((UINT8 *)(CurrEntry + 1) + CurrEntry->HashSize);
}
return CompEntry;
}
/**
This function returns the hash alg type from auth type.
@param[in] AuthType Authorization Type.
@retval Hash Algorithm Type.
**/
HASH_ALG_TYPE
GetHashAlg(
AUTH_TYPE AuthType
)
{
HASH_ALG_TYPE HashAlg;
HashAlg = HASH_TYPE_NONE;
if((AuthType == AUTH_TYPE_SIG_RSA2048_PKCSI1_SHA256)
|| (AuthType == AUTH_TYPE_SIG_RSA2048_PSS_SHA256) || (AuthType == AUTH_TYPE_SHA2_256)) {
HashAlg = HASH_TYPE_SHA256;
} else if ((AuthType == AUTH_TYPE_SIG_RSA3072_PKCSI1_SHA384)
|| (AuthType == AUTH_TYPE_SIG_RSA3072_PSS_SHA384) || (AuthType == AUTH_TYPE_SHA2_384)) {
HashAlg = HASH_TYPE_SHA384;
}
return HashAlg;
}
/**
Authenticate a container header or component.
@param[in] Data Data buffer to be authenticated.
@param[in] Length Data length to be authenticated.
@param[in] AuthType Authentication type.
@param[in] AuthData Authentication data buffer.
@param[in] HashData Hash data buffer.
@param[in] Usage Hash usage.
@retval EFI_UNSUPPORTED Unsupported AuthType.
@retval EFI_SECURITY_VIOLATION Authentication failed.
@retval EFI_SUCCESS Authentication succeeded.
**/
STATIC
EFI_STATUS
AuthenticateComponent (
IN UINT8 *Data,
IN UINT32 Length,
IN UINT8 AuthType,
IN UINT8 *AuthData,
IN UINT8 *HashData,
IN UINT32 Usage
)
{
EFI_STATUS Status;
UINT8 *SigPtr;
UINT8 *KeyPtr;
SIGNATURE_HDR *SignHdr;
if (!FeaturePcdGet (PcdVerifiedBootEnabled)) {
Status = EFI_SUCCESS;
} else {
if (AuthType == AUTH_TYPE_SHA2_256) {
Status = DoHashVerify (Data, Length, Usage, HASH_TYPE_SHA256, HashData);
} else if (AuthType == AUTH_TYPE_SHA2_384) {
Status = DoHashVerify (Data, Length, Usage, HASH_TYPE_SHA384, HashData);
} else if ((AuthType == AUTH_TYPE_SIG_RSA2048_PKCSI1_SHA256) || ( AuthType == AUTH_TYPE_SIG_RSA3072_PKCSI1_SHA384)
|| (AuthType == AUTH_TYPE_SIG_RSA2048_PSS_SHA256) || ( AuthType == AUTH_TYPE_SIG_RSA3072_PSS_SHA384)) {
SigPtr = (UINT8 *) AuthData;
SignHdr = (SIGNATURE_HDR *) SigPtr;
KeyPtr = (UINT8 *)SignHdr + sizeof(SIGNATURE_HDR) + SignHdr->SigSize ;
Status = DoRsaVerify (Data, Length, Usage, SignHdr,
(PUB_KEY_HDR *) KeyPtr, GetHashAlg(AuthType), HashData, NULL);
} else if (AuthType == AUTH_TYPE_NONE) {
Status = EFI_SUCCESS;
} else {
Status = EFI_UNSUPPORTED;
}
}
return Status;
}
/**
Return Containser Key Type based on its signature
@param[in] ContainerSig Signature of the container
@retval COMP_TYPE_PUBKEY_OS for CONTAINER boot image
COMP_TYPE_PUBKEY_CFG_DATA, otherwise
**/
UINT32
GetContainerKeyUsageBySig (
IN UINT32 ContainerSig
)
{
UINT8 Idx;
if (ContainerSig == CONTAINER_KEY_HASH_STORE_SIGNATURE) {
return HASH_USAGE_PUBKEY_MASTER;
} else if (ContainerSig == CONTAINER_BOOT_SIGNATURE) {
return HASH_USAGE_PUBKEY_OS;
} else if ((ContainerSig & 0x00FFFFFF) == CONTAINER_OEM_BASE_SIGNATURE) {
Idx = (ContainerSig >> 24) - '0';
if (Idx < 8) {
return HASH_USAGE_PUBKEY_OEM (Idx);
}
}
return HASH_USAGE_PUBKEY_CONTAINER_DEF;
}
/**
This function authenticates a container
@param[in] ContainerHeader Container base address to register.
@param[in] ContainerCallback Callback regsiterd to notify container buf info
@retval EFI_SUCCESS The container has been authenticated successfully.
@retval EFI_UNSUPPORTED If container header is invalid or autheication fails
**/
EFI_STATUS
AutheticateContainerInternal (
IN CONTAINER_HDR *ContainerHeader,
IN LOAD_COMPONENT_CALLBACK ContainerCallback
)
{
CONTAINER_HDR *ContainerHdr;
CONTAINER_ENTRY *ContainerEntry;
COMPONENT_ENTRY *CompEntry;
UINT8 *AuthData;
UINT32 ContainerHdrSize;
UINT8 AuthType;
UINT8 *DataBuf;
UINT8 *CompData;
UINT32 DataLen;
UINT32 SignedDataLen;
UINT32 Index;
LOADER_COMPRESSED_HEADER *CompressHdr;
EFI_STATUS Status;
COMPONENT_CALLBACK_INFO CbInfo;
// Find authentication data offset and authenticate the container header
Status = EFI_UNSUPPORTED;
ContainerEntry = GetContainerBySignature (ContainerHeader->Signature);
if (ContainerEntry != NULL) {
ContainerHdr = (CONTAINER_HDR *)(UINTN)ContainerEntry->HeaderCache;
ContainerHdrSize = GetContainerHeaderSize (ContainerHdr);
if (ContainerHdrSize > 0) {
AuthType = ContainerHdr->AuthType;
AuthData = (UINT8 *)ContainerHdr + ALIGN_UP(ContainerHdrSize, AUTH_DATA_ALIGN);
if ((AuthType == AUTH_TYPE_NONE) && FeaturePcdGet (PcdVerifiedBootEnabled)) {
Status = EFI_SECURITY_VIOLATION;
} else {
Status = AuthenticateComponent ((UINT8 *)ContainerHdr, ContainerHdrSize,
AuthType, AuthData, NULL,
GetContainerKeyUsageBySig (ContainerHeader->Signature));
if ((!EFI_ERROR(Status)) && (ContainerCallback != NULL)) {
// Update component Call back info after container header authenticaton is done
// This info will used by firmware stage to extend to TPM
CbInfo.ComponentType = ContainerHeader->Signature;
CbInfo.CompBuf = (UINT8 *)ContainerHdr;
CbInfo.CompLen = ContainerHdrSize;
CbInfo.HashAlg = GetHashAlg(AuthType);
CbInfo.HashData = NULL;
ContainerCallback (PROGESS_ID_AUTHENTICATE, &CbInfo);
}
}
}
}
if (!EFI_ERROR (Status) && \
((ContainerHdr->Flags & CONTAINER_HDR_FLAG_MONO_SIGNING) != 0)) {
// Additional verification if the container is signed monolithically.
// It is required for the container to be loaded in memory before registeration.
Status = EFI_UNSUPPORTED;
if ((ContainerHdr->Count > 1) && !IS_FLASH_ADDRESS (ContainerHeader)) {
// Use the last entry to verify all other combined components
CompEntry = (COMPONENT_ENTRY *)&ContainerHdr[1];
for (Index = 0; Index < (UINT32)(ContainerHdr->Count - 1); Index++) {
CompEntry = (COMPONENT_ENTRY *)((UINT8 *)(CompEntry + 1) + CompEntry->HashSize);
}
CompData = (UINT8 *)(UINTN)(ContainerEntry->Base + ContainerHdr->DataOffset + CompEntry->Offset);
CompressHdr = (LOADER_COMPRESSED_HEADER *)CompData;
if (CompressHdr->Signature == LZDM_SIGNATURE) {
SignedDataLen = sizeof (LOADER_COMPRESSED_HEADER) + CompressHdr->CompressedSize;
AuthData = CompData + ALIGN_UP(SignedDataLen, AUTH_DATA_ALIGN);
DataBuf = (UINT8 *)(UINTN)(ContainerEntry->Base + ContainerHdr->DataOffset);
DataLen = CompEntry->Offset;
Status = AuthenticateComponent (DataBuf, DataLen, CompEntry->AuthType,
AuthData, CompEntry->HashData, 0);
if ((!EFI_ERROR(Status)) && (ContainerCallback != NULL)) {
// Update component Call back info after authenticaton is done
// This info will used by firmware stage to extend to TPM
CbInfo.ComponentType = ContainerHeader->Signature;
CbInfo.CompBuf = DataBuf;
CbInfo.CompLen = DataLen;
CbInfo.HashAlg = GetHashAlg(CompEntry->AuthType);
CbInfo.HashData = CompEntry->HashData;
ContainerCallback (PROGESS_ID_AUTHENTICATE, &CbInfo);
}
}
}
}
return Status;
}
/**
This function registers a container.
@param[in] ContainerBase Container base address to register.
@param[in] ContainerCallback Callback regsiterd to notify container buf info
@retval EFI_NOT_READY Not ready for register yet.
@retval EFI_BUFFER_TOO_SMALL Insufficant max container entry number.
@retval EFI_OUT_OF_RESOURCES No space to add new container.
@retval EFI_SUCCESS The container has been registered successfully.
**/
EFI_STATUS
RegisterContainer (
IN UINT32 ContainerBase,
IN LOAD_COMPONENT_CALLBACK ContainerCallback
)
{
EFI_STATUS Status;
CONTAINER_HDR *ContainerHdr;
UINT64 SignatureBuffer;
ContainerHdr = (CONTAINER_HDR *)(UINTN)ContainerBase;
SignatureBuffer = ContainerHdr->Signature;
DEBUG ((DEBUG_INFO, "Registering container %4a\n", (CHAR8 *)&SignatureBuffer));
// Register container
Status = RegisterContainerInternal (ContainerBase);
if (!EFI_ERROR (Status)) {
Status = AutheticateContainerInternal (ContainerHdr, ContainerCallback);
if (EFI_ERROR (Status)) {
// Unregister the container since authentication failed
UnregisterContainer (ContainerHdr->Signature);
}
}
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "Registering container failed due to %r\n", Status));
}
return Status;
}
/**
Locate a component information from a container.
@param[in] ContainerSig Container signature.
@param[in] ComponentName Component name.
@param[in,out] ContainerEntryPtr Pointer to receive container entry info.
@param[in,out] ComponentEntryPtr Pointer to receive component entry info.
@retval EFI_UNSUPPORTED Unsupported AuthType.
@retval EFI_NOT_FOUND Cannot locate component.
@retval EFI_SECURITY_VIOLATION Authentication failed.
@retval EFI_SUCCESS component region is located successfully.
**/
EFI_STATUS
LocateComponentEntry (
IN UINT32 ContainerSig,
IN UINT32 ComponentName,
IN OUT CONTAINER_ENTRY **ContainerEntryPtr,
IN OUT COMPONENT_ENTRY **ComponentEntryPtr
)
{
EFI_STATUS Status;
CONTAINER_HDR *ContainerHdr;
CONTAINER_ENTRY *ContainerEntry;
COMPONENT_ENTRY *CompEntry;
UINT32 ContainerBase;
UINT32 ContainerSize;
CompEntry = NULL;
// Search container header from cache
ContainerEntry = GetContainerBySignature (ContainerSig);
if (ContainerEntry == NULL) {
// Location container from Flash Map
Status = GetComponentInfo (ContainerSig, &ContainerBase, &ContainerSize);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
// Register container temporarily
Status = RegisterContainer (ContainerBase, NULL);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
// Find authentication data offset and authenticate the container header
ContainerEntry = GetContainerBySignature (ContainerSig);
if (ContainerEntry == NULL) {
return EFI_UNSUPPORTED;
}
}
// Locate the component from the container header
ContainerHdr = (CONTAINER_HDR *)(UINTN)ContainerEntry->HeaderCache;
if (ComponentName != 0) {
CompEntry = LocateComponentEntryFromContainer (ContainerHdr, ComponentName);
if (CompEntry == NULL) {
return EFI_NOT_FOUND;
}
}
if (ContainerEntryPtr != NULL) {
*ContainerEntryPtr = ContainerEntry;
}
if (ComponentEntryPtr != NULL) {
*ComponentEntryPtr = CompEntry;
}
return EFI_SUCCESS;
}
/**
Get Next Component in a container.
@param[in] ContainerSig Container signature or component type.
@param[in, out] ComponentName Pointer to receive next component name.
@retval EFI_INVALID_PARAMETER ComponentName is NULL.
@retval EFI_NOT_FOUND Cannot find next component.
@retval EFI_SUCCESS Next component was found successfully.
**/
EFI_STATUS
EFIAPI
GetNextAvailableComponent (
IN UINT32 ContainerSig,
IN UINT32 *ComponentName
)
{
EFI_STATUS Status;
CONTAINER_HDR *ContainerHdr;
CONTAINER_ENTRY *ContainerEntry;
COMPONENT_ENTRY *CurrEntry;
COMPONENT_ENTRY *NextEntry;
UINT32 Index;
if (ComponentName == NULL) {
return EFI_INVALID_PARAMETER;
}
// Search container header from cache
Status = EFI_NOT_FOUND;
ContainerEntry = GetContainerBySignature (ContainerSig);
if (ContainerEntry == NULL) {
return Status;
}
ContainerHdr = (CONTAINER_HDR *)(UINTN)ContainerEntry->HeaderCache;
if (ContainerHdr->Count == 0) {
return Status;
}
CurrEntry = (COMPONENT_ENTRY *)&ContainerHdr[1];
if ((*ComponentName == 0) && ((CurrEntry->Attribute & COMPONENT_ENTRY_ATTR_RESERVED) == 0)){
*ComponentName = CurrEntry->Name;
Status = EFI_SUCCESS;
} else {
NextEntry = (COMPONENT_ENTRY *)((UINT8 *)(CurrEntry + 1) + CurrEntry->HashSize);
for (Index = 0; Index < (UINT32)(ContainerHdr->Count-1); Index++) {
if ((CurrEntry->Attribute & COMPONENT_ENTRY_ATTR_RESERVED) == 0) {
if (*ComponentName == CurrEntry->Name) {
if ((NextEntry->Attribute & COMPONENT_ENTRY_ATTR_RESERVED) == 0) {
*ComponentName = NextEntry->Name;
Status = EFI_SUCCESS;
break;
} else {
NextEntry = (COMPONENT_ENTRY *)((UINT8 *)(NextEntry + 1) + NextEntry->HashSize);
continue;
}
}
}
CurrEntry = NextEntry;
NextEntry = (COMPONENT_ENTRY *)((UINT8 *)(CurrEntry + 1) + CurrEntry->HashSize);
}
}
return Status;
}
/**
Locate a component region information from a container or flash map.
@param[in] ContainerSig Container signature or component type.
@param[in] ComponentName component name.
@param[in, out] Buffer Pointer to receive component base.
@param[in, out] Length Pointer to receive component size.
@retval EFI_UNSUPPORTED Unsupported AuthType.
@retval EFI_NOT_FOUND Cannot locate component.
@retval EFI_SECURITY_VIOLATION Authentication failed.
@retval EFI_SUCCESS Authentication succeeded.
**/
EFI_STATUS
EFIAPI
LocateComponent (
IN UINT32 ContainerSig,
IN UINT32 ComponentName,
IN OUT VOID **Buffer,
IN OUT UINT32 *Length
)
{
EFI_STATUS Status;
CONTAINER_HDR *ContainerHdr;
CONTAINER_ENTRY *ContainerEntry;
COMPONENT_ENTRY *CompEntry;
if (ContainerSig < COMP_TYPE_INVALID) {
// It is a component type, so get the info from flash map
Status = GetComponentInfo (ComponentName, (UINT32 *)Buffer, Length);
return EFI_NOT_FOUND;
}
Status = LocateComponentEntry (ContainerSig, ComponentName, &ContainerEntry, &CompEntry);
if (EFI_ERROR (Status)) {
return Status;
}
if ((ContainerEntry != NULL) && (CompEntry != NULL)) {
ContainerHdr = (CONTAINER_HDR *)(UINTN)ContainerEntry->HeaderCache;
if (Buffer != NULL) {
*Buffer = (VOID *)(UINTN)(ContainerEntry->Base + ContainerHdr->DataOffset + CompEntry->Offset);
}
if (Length != NULL) {
*Length = CompEntry->Size;
}
} else {
Status = EFI_NOT_FOUND;
}
return Status;
}
/**
Load a component from a container or flahs map to memory and call callback
function at predefined point.
@param[in] ContainerSig Container signature or component type.
@param[in] ComponentName Component name.
@param[in,out] Buffer Pointer to receive component base.
@param[in,out] Length Pointer to receive component size.
@param[in,out] LoadComponentCallback Callback function pointer.
@retval EFI_UNSUPPORTED Unsupported AuthType.
@retval EFI_NOT_FOUND Cannot locate component.
@retval EFI_BUFFER_TOO_SMALL Specified buffer size is too small.
@retval EFI_SECURITY_VIOLATION Authentication failed.
@retval EFI_SUCCESS Authentication succeeded.
**/
EFI_STATUS
EFIAPI
LoadComponentWithCallback (
IN UINT32 ContainerSig,
IN UINT32 ComponentName,
IN OUT VOID **Buffer,
IN OUT UINT32 *Length,
IN LOAD_COMPONENT_CALLBACK LoadComponentCallback
)
{
EFI_STATUS Status;
LOADER_COMPRESSED_HEADER *CompressHdr;
CONTAINER_HDR *ContainerHdr;
CONTAINER_ENTRY *ContainerEntry;
COMPONENT_ENTRY *CompEntry;
UINT8 *CompData;
UINT8 *CompBuf;
UINT8 *HashData;
VOID *CompBase;
VOID *ScrBuf;
VOID *AllocBuf;
VOID *ReqCompBase;
UINT32 Usage;
UINT8 AuthType;
UINT32 DecompressedLen;
UINT32 CompLen;
UINT32 CompLoc;
UINT32 AllocLen;
UINT32 SignedDataLen;
UINT32 DstLen;
UINT32 ScrLen;
BOOLEAN IsInFlash;
COMPONENT_CALLBACK_INFO CbInfo;
UINT32 ComponentId;
UINT64 ContainerIdBuf;
UINT64 ComponentIdBuf;
ComponentId = ContainerSig;
CompLoc = 0;
ComponentIdBuf = ComponentName;
if (ContainerSig < COMP_TYPE_INVALID) {
ContainerIdBuf = FLASH_MAP_SIG_HEADER;
} else {
ContainerIdBuf = ContainerSig;
}
DEBUG ((DEBUG_INFO, "Loading Component %4a:%4a\n", (CHAR8 *)&ContainerIdBuf, (CHAR8 *)&ComponentIdBuf));
if (ContainerSig < COMP_TYPE_INVALID) {
// Check if it is component type
Usage = 1 << ContainerSig;
ContainerSig = 0;
Status = GetComponentInfo (ComponentName, &CompLoc, &CompLen);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
CompData = (VOID *)(UINTN)CompLoc;
if (FeaturePcdGet (PcdVerifiedBootEnabled)) {
if(FixedPcdGet8(PcdCompSignHashAlg) == HASH_TYPE_SHA256) {
AuthType = AUTH_TYPE_SHA2_256;
} else if (FixedPcdGet8(PcdCompSignHashAlg) == HASH_TYPE_SHA384) {
AuthType = AUTH_TYPE_SHA2_384;
} else {
return EFI_UNSUPPORTED;
}
} else {
AuthType = AUTH_TYPE_NONE;
}
HashData = NULL;
} else {
// Find the component info
Status = LocateComponentEntry (ContainerSig, ComponentName, &ContainerEntry, &CompEntry);
if (EFI_ERROR (Status)) {
return Status;
}
if ((ContainerEntry == NULL) || (CompEntry == NULL)) {
return EFI_NOT_FOUND;
}
if ((CompEntry->Attribute & COMPONENT_ENTRY_ATTR_RESERVED) != 0) {
return EFI_UNSUPPORTED;
}
// Collect component info
ContainerHdr = (CONTAINER_HDR *)(UINTN)ContainerEntry->HeaderCache;
AuthType = CompEntry->AuthType;
HashData = CompEntry->HashData;
Usage = 0;
CompData = (UINT8 *)(UINTN)(ContainerEntry->Base + ContainerHdr->DataOffset + CompEntry->Offset);
CompLen = CompEntry->Size;
}
if (LoadComponentCallback != NULL) {
LoadComponentCallback (PROGESS_ID_LOCATE, NULL);
}
// Component must have LOADER_COMPRESSED_HEADER
Status = EFI_UNSUPPORTED;
CompressHdr = (LOADER_COMPRESSED_HEADER *)CompData;
if (CompressHdr == NULL) {
return EFI_NOT_FOUND;
}
if (IS_COMPRESSED (CompressHdr)) {
SignedDataLen = sizeof (LOADER_COMPRESSED_HEADER) + CompressHdr->CompressedSize;
if (CompressHdr->Size == 0) {
Status = EFI_SUCCESS;
DstLen = 0;
ScrLen = 0;
} else {
if (SignedDataLen <= CompLen) {
Status = DecompressGetInfo (CompressHdr->Signature, CompressHdr->Data,
CompressHdr->CompressedSize, &DstLen, &ScrLen);
}
}
}
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
// If it is required to use an existing buffer, verify the size
ReqCompBase = NULL;
DecompressedLen = CompressHdr->Size;
if ((Buffer != NULL) && (*Buffer != NULL)) {
ReqCompBase = *Buffer;
if ((Length != NULL) && (*Length != 0) && (*Length < DecompressedLen)) {
return EFI_BUFFER_TOO_SMALL;
}
}
// If it is on flash, the data needs to be copied into memory first
// before authentication for security concern.
IsInFlash = IS_FLASH_ADDRESS (CompData);
AllocLen = ScrLen + TEMP_BUF_ALIGN * 2;
if (IsInFlash) {
AllocLen += SignedDataLen;
}
AllocBuf = AllocateTemporaryMemory (AllocLen);
if (AllocBuf == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (IsInFlash) {
// Authenticate component and decompress it if required
CompBuf = AllocBuf;
ScrBuf = (UINT8 *)AllocBuf + ALIGN_UP (SignedDataLen, TEMP_BUF_ALIGN);
CopyMem (CompBuf, CompData, SignedDataLen);
if (LoadComponentCallback != NULL) {
LoadComponentCallback (PROGESS_ID_COPY, NULL);
}
} else {
CompBuf = CompData;
ScrBuf = AllocBuf;
}
// Verify the component
Status = AuthenticateComponent (CompBuf, SignedDataLen, AuthType,
CompData + ALIGN_UP(SignedDataLen, AUTH_DATA_ALIGN), HashData, Usage);
if (LoadComponentCallback != NULL) {
if(Status == EFI_SUCCESS){
// Update component Call back info after authenticaton is done
// This info will used by firmware stage to extend to TPM
CbInfo.ComponentType = ComponentId;
CbInfo.CompBuf = CompData;
CbInfo.CompLen = SignedDataLen;
CbInfo.HashAlg = GetHashAlg(AuthType);
CbInfo.HashData = HashData;
LoadComponentCallback (PROGESS_ID_AUTHENTICATE, &CbInfo);
} else {
LoadComponentCallback (PROGESS_ID_AUTHENTICATE, NULL);
}
}
if (!EFI_ERROR (Status)) {
CompressHdr = (LOADER_COMPRESSED_HEADER *)CompBuf;
if (ReqCompBase == NULL) {
CompBase = AllocatePages (EFI_SIZE_TO_PAGES ((UINTN) DecompressedLen));
} else {
CompBase = ReqCompBase;
}
if (CompBase != NULL) {
Status = Decompress (CompressHdr->Signature, CompressHdr->Data, CompressHdr->CompressedSize,
CompBase, ScrBuf);
if (LoadComponentCallback != NULL) {
LoadComponentCallback (PROGESS_ID_DECOMPRESS, NULL);
}
if (EFI_ERROR (Status)) {
if (ReqCompBase == NULL) {
FreePages (CompBase, EFI_SIZE_TO_PAGES ((UINTN) DecompressedLen));
}
}
} else {
if (CompressHdr->Size == 0) {
Status = EFI_BAD_BUFFER_SIZE;
} else {
Status = EFI_OUT_OF_RESOURCES;
}
}
} else {
Status = EFI_SECURITY_VIOLATION;
}
FreeTemporaryMemory (AllocBuf);
if (!EFI_ERROR (Status)) {
if (Buffer != NULL) {
*Buffer = CompBase;
}
if (Length != NULL) {
*Length = DecompressedLen;
}
}
return Status;
}
/**
Load a component from a container or flash map to memory.
@param[in] ContainerSig Container signature or component type.
@param[in] ComponentName Component name.
@param[in,out] Buffer Pointer to receive component base.
@param[in,out] Length Pointer to receive component size.
@retval EFI_UNSUPPORTED Unsupported AuthType.
@retval EFI_NOT_FOUND Cannot locate component.
@retval EFI_BUFFER_TOO_SMALL Specified buffer size is too small.
@retval EFI_SECURITY_VIOLATION Authentication failed.
@retval EFI_SUCCESS Authentication succeeded.
**/
EFI_STATUS
EFIAPI
LoadComponent (
IN UINT32 ContainerSig,
IN UINT32 ComponentName,
IN OUT VOID **Buffer,
IN OUT UINT32 *Length
)
{
return LoadComponentWithCallback (ContainerSig, ComponentName, Buffer, Length, NULL);
}