Ryzen/AmiPspPkg/Pei/PeiAmiPsp.c
2022-12-23 15:14:44 +08:00

360 lines
13 KiB
C

//*************************************************************************
//*************************************************************************
//** **
//** (C)Copyright 1985-2019, American Megatrends, Inc. **
//** **
//** All Rights Reserved. **
//** **
//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
//** **
//** Phone: (770)-246-8600 **
//** **
//*************************************************************************
//*************************************************************************
/** @file
This file contains code for Platform Secure Boot related functionality
**/
#include "Token.h"
#include <Guid/AmiPsp.h>
#include <Library/HobLib.h>
#include <RomLayout.h>
#include <AmiPeiLib.h>
#include <Ppi/CryptoPPI.h>
#include <BaseCryptLib.h>
#include <Include/AmiCertificate.h>
#include <Protocol/Hash.h>
#include <Library/DebugLib.h>
#define ROM_LAYOUT_FFS_GUID \
{ 0x0DCA793A, 0xEA96, 0x42d8, 0xBD, 0x7B, 0xDC, 0x7F, 0x68, 0x4E, 0x38, 0xC1 }
extern EFI_GUID gAmiDigitalSignaturePPIGuid;
typedef struct _ROM_LAYOUT_SECTION {
EFI_GUID Guid;
ROM_AREA Layout[1];
} ROM_LAYOUT_SECTION;
static EFI_GUID RomLayoutFfsGuid = ROM_LAYOUT_FFS_GUID;
static EFI_GUID gFWkey_RSA2048_Guid = EFI_CERT_RSA2048_GUID;
static EFI_GUID gFWkeyGuid = PR_KEY_GUID;
static EFI_GUID gEfiHashAlgorithmSha256Guid = EFI_HASH_ALGORITHM_SHA256_GUID;
#define FV_IN_RAM 0
#if FV_IN_RAM
UINT8 *FvInRamStart;
UINTN RamOffset;
#endif
/**
Function to read ROM_LAYOUT data from FFS file
@param PeiServices pointer to PEI services
@param Layout pointer to output buffer
@retval EFI_SUCCESS if ROM layout is retrieved
**/
EFI_STATUS
GetRomLayout(
IN EFI_PEI_SERVICES **PeiServices,
OUT ROM_AREA **Layout
)
{
EFI_STATUS Status;
EFI_FIRMWARE_VOLUME_HEADER *BootFv;
EFI_FFS_FILE_HEADER *File = NULL;
ROM_LAYOUT_SECTION *Section;
Status = (*PeiServices)->FfsFindNextVolume (PeiServices, 0, &BootFv);
if (EFI_ERROR(Status))
return Status;
do
{
Status = (*PeiServices)->FfsFindNextFile (PeiServices, EFI_FV_FILETYPE_FREEFORM, BootFv, &File);
if (!EFI_ERROR(Status) && !guidcmp (&(File->Name), &RomLayoutFfsGuid))
break;
} while (Status == EFI_SUCCESS);
if (EFI_ERROR (Status))
return Status;
Status = (*PeiServices)->FfsFindSectionData (PeiServices, EFI_SECTION_FREEFORM_SUBTYPE_GUID, File, &Section);
if (EFI_ERROR (Status))
return Status;
*Layout = Section->Layout;
return EFI_SUCCESS;
}
/**
Verify DXE volume, signed at build time
@param PeiServices pointer to PEI services
@param pFv pointer to Firmware volume header
@param pFile pointer to DxeSig file header
@retval EFI_SUCCESS if DXE volume verified without errors
**/
EFI_STATUS
CheckDxeSign(
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_FIRMWARE_VOLUME_HEADER *Fv,
IN EFI_FFS_FILE_HEADER *File
)
{
EFI_STATUS Status = EFI_SUCCESS;
AMI_CRYPT_DIGITAL_SIGNATURE_PPI *AmiSigPpi = NULL;
VOID *HashCtx = NULL;
UINTN CtxSize;
UINT8 HashDb[SHA256_DIGEST_SIZE];
UINT8* CurrPosition;
INTN CmpStatus;
APTIO_FW_CAPSULE_HEADER *AptioFwCapsHdrPtr;
PEI_CRYPT_HANDLE HashHndl;
PEI_CRYPT_HANDLE PubKeyHndl;
UINT32 Flags = 0;
ROM_AREA *RomAreaTbl;
VOID *Sig;
UINTN Index;
Status = (*PeiServices)->LocatePpi (PeiServices, &gAmiDigitalSignaturePPIGuid, 0, NULL, &AmiSigPpi);
if (EFI_ERROR(Status))
return Status;
CtxSize = Sha256GetContextSize();
Status = (*PeiServices)->AllocatePool (PeiServices, CtxSize, &HashCtx);
ASSERT_PEI_ERROR (PeiServices, Status);
if (EFI_ERROR (Status))
return Status;
// Adjust to section
CurrPosition = (UINT8*)File;
CurrPosition += sizeof (EFI_FFS_FILE_HEADER);
// At file section
CurrPosition += sizeof (EFI_COMMON_SECTION_HEADER);
CmpStatus = guidcmp (CurrPosition,&gDxeSigSectionGuid);
if (0 != CmpStatus)
return EFI_VOLUME_CORRUPTED;
(UINT8*)AptioFwCapsHdrPtr = CurrPosition + sizeof (EFI_GUID);
if (AptioFwCapsHdrPtr->RomImageOffset > FWCAPSULE_MAX_HDR_SIZE)
return EFI_SECURITY_VIOLATION;
// For now Aptio FW Capsule only supports WIN_CERT_TYPE_EFI_GUID
if (AptioFwCapsHdrPtr->FWCert.SignCert.Hdr.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID)
return EFI_SECURITY_VIOLATION;
// Version 010 and later supporting extended flags
if (AptioFwCapsHdrPtr->CapHdr.Flags & CAPSULE_FLAGS_CAPHDR_IN_SIGNCERT)
{
if (AptioFwCapsHdrPtr->CapHdr.Flags & CAPSULE_FLAGS_RSA_PSS_PADDING_SCHEME)
Flags = EFI_CRYPT_RSASSA_PSS;
else
Flags = EFI_CRYPT_RSASSA_PKCS1V15;
}
else
Flags = EFI_CRYPT_RSASSA_PSS;
HashHndl.AlgGuid = gEfiHashAlgorithmSha256Guid;
HashHndl.BlobSize = SHA256_DIGEST_SIZE;
HashHndl.Blob = (UINT8*)&HashDb;
// 1. Compare Capsule's Sign Cert key with Platform Root Key
PubKeyHndl.BlobSize = DEFAULT_RSA_KEY_MODULUS_LEN;
PubKeyHndl.AlgGuid = gFWkey_RSA2048_Guid;
PubKeyHndl.Blob = (UINT8*)AptioFwCapsHdrPtr->FWCert.SignCert.CertData.PublicKey;
Status = AmiSigPpi->VerifyKey (AmiSigPpi, &gFWkeyGuid, &PubKeyHndl);
DEBUG((DEBUG_INFO, "DxeSign:Compare Platform and SignCert Keys : %r\n", Status));
// Skip the RootCert key checking if SignCert Key and PR Key are a Match
if (EFI_ERROR (Status))
{
// 1.1 Compare Capsule's Cert Root key with Platform Root
PubKeyHndl.Blob = (UINT8*)AptioFwCapsHdrPtr->FWCert.RootCert.PublicKey;
Status = AmiSigPpi->VerifyKey (AmiSigPpi, &gFWkeyGuid, &PubKeyHndl);
DEBUG((DEBUG_INFO, "DxeSign:Compare Platform and RootCert Keys : %r\n", Status));
if (EFI_ERROR(Status))
return Status;
// 2. Verify RootCert.Signature
// 2.1 Compute FWCert.SignCert.PublicKey Hash
Sha256Init (HashCtx);
if (AptioFwCapsHdrPtr->CapHdr.Flags & CAPSULE_FLAGS_SIGNKEY_IN_ROOTCERT)
{
Sha256Update (HashCtx, (UINT8*)AptioFwCapsHdrPtr->FWCert.SignCert.CertData.PublicKey,
DEFAULT_RSA_KEY_MODULUS_LEN);
}
else
{
// 2.2 Compute FWCert.SignCert Hash
Sha256Update (HashCtx, (UINT8*)&AptioFwCapsHdrPtr->FWCert.SignCert, sizeof (AMI_CERTIFICATE_RSA2048_SHA256));
}
if (!Sha256Final (HashCtx, HashDb))
return EFI_SECURITY_VIOLATION;
Sig = (void*)AptioFwCapsHdrPtr->FWCert.RootCert.Signature;
Status = AmiSigPpi->VerifySig (AmiSigPpi, &PubKeyHndl, &HashHndl, Sig,
DEFAULT_RSA_SIG_LEN, Flags);
DEBUG((DEBUG_INFO, "DxeSign:Verify Root Cert : %r\n", Status));
if (EFI_ERROR (Status))
return Status;
}
#if FV_IN_RAM
Status = (*PeiServices)->AllocatePool (PeiServices, (UINTN)pFv->FvLength + 0x1000, &FvInRamStart);
if (EFI_ERROR(Status))
return Status;
// Align 64 byte or 4096
(UINTN)FvInRamStart = ((UINTN)FvInRamStart & 0xFFFFF000) + 0x1000;
//#### CopyMem_LpcDma(FvInRamStart, pFv, (UINTN)pFv->FvLength);
MemCpy32 (FvInRamStart, pFv, (UINTN)pFv->FvLength);
RamOffset = (UINT8*)pFv - FvInRamStart;
#endif //FV_IN_RAM
// 3. Verify Signing Cert Signature
// 3.1 The Rom image hash is calculated based on info from the Rom Area map
RomAreaTbl = (ROM_AREA *)(UINTN)((UINT32)AptioFwCapsHdrPtr +
AptioFwCapsHdrPtr->RomLayoutOffset);
// Initialize a SHA hash context.
Sha256Init (HashCtx);
// number of signed elements in RomMap may not exceed max_num_elem constant.
// overall number of elements in the RomMap may not exceed max_num_elem x 2
for (Index = 0; RomAreaTbl[Index].Size != 0 &&
((UINTN)&RomAreaTbl[Index] < (UINTN)((UINT32)AptioFwCapsHdrPtr+AptioFwCapsHdrPtr->RomImageOffset));
Index++)
{
if (!(RomAreaTbl[Index].Attributes & ROM_AREA_FV_SIGNED))
continue;
// RomArea has offsets relative to ROM start
#if FV_IN_RAM
Sha256Update (HashCtx, (UINT8 *)((UINTN)(0xFFFFFFFF - FLASH_SIZE + 1) + RomAreaTbl[Index].Offset - RamOffset), RomAreaTbl[Index].Size);
#else
Sha256Update (HashCtx, (UINT8 *)((UINTN)(0xFFFFFFFF - FLASH_SIZE + 1) + RomAreaTbl[Index].Offset), RomAreaTbl[Index].Size);
#endif // FV_IN_RAM
}
// 3.2 Hash of Capsule Hdr + FW Certificate Hdr
if (AptioFwCapsHdrPtr->CapHdr.Flags & CAPSULE_FLAGS_CAPHDR_IN_SIGNCERT)
Sha256Update (HashCtx, (UINT8*)AptioFwCapsHdrPtr, (UINTN)&AptioFwCapsHdrPtr->FWCert.SignCert.CertData - (UINTN)AptioFwCapsHdrPtr);
// 3.3 Hash of the ROM_MAP table
Sha256Update (HashCtx, (UINT8*)RomAreaTbl, ((Index + 1) * sizeof (ROM_AREA)));
if (!Sha256Final (HashCtx, HashDb))
return EFI_SECURITY_VIOLATION;
Sig = (void*)AptioFwCapsHdrPtr->FWCert.SignCert.CertData.Signature;
PubKeyHndl.Blob = (UINT8*)AptioFwCapsHdrPtr->FWCert.SignCert.CertData.PublicKey;
Status = AmiSigPpi->VerifySig (AmiSigPpi, &PubKeyHndl, &HashHndl, Sig, DEFAULT_RSA_SIG_LEN, Flags);
DEBUG((DEBUG_INFO, "DxeSign:Verify Sign Certificate Sig : %r\n", Status));
return Status;
}
/**
This function is the entry point for PeiAmiPsp PEIM.
@param FileHandle Pointer to the FFS file header.
@param PeiServices Pointer to the PEI services table.
@retval EFI_STATUS EFI_SUCCESS
This function will not return if EFI_STATUS != EFI_SUCCESS
**/
EFI_STATUS
EFIAPI
PeiAmiPspEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status = EFI_SUCCESS;
EFI_BOOT_MODE BootMode;
ROM_AREA *Area;
EFI_FIRMWARE_VOLUME_HEADER *Fv;
VOID *File = NULL;
INTN CmpStatus;
BootMode = GetBootModeHob();
if(BootMode == BOOT_IN_RECOVERY_MODE)
return Status;
Status = GetRomLayout (PeiServices, &Area);
for(Area; Area->Size != 0; Area++)
{
if (!(Area->Attributes & ROM_AREA_FV_SIGNED)) continue;
if ((ROM_AREA_FV_PEI + ROM_AREA_FV_DXE) != (Area->Attributes & (ROM_AREA_FV_PEI + ROM_AREA_FV_DXE)))
continue;
// Find DXE FV
if(((Area->Address - 1) + Area->Size) != 0xFFFFFFFF)
break; // not FV_BB
}
// if not found - stop
if((ROM_AREA_FV_PEI+ROM_AREA_FV_DXE) != (Area->Attributes & (ROM_AREA_FV_PEI+ROM_AREA_FV_DXE)))
goto ErrorLoop;
Fv = (EFI_FIRMWARE_VOLUME_HEADER*)Area->Address;
Status = (*PeiServices)->FfsFindNextFile (PeiServices,
EFI_FV_FILETYPE_FREEFORM, Fv, &File);
if (EFI_ERROR(Status))
goto ErrorLoop;
// Compare GUID - it can be capsule FFS file or other files
CmpStatus = guidcmp (&((EFI_FFS_FILE_HEADER*)File)->Name,&gDxeSigFfsGuid);
if (0 != CmpStatus)
{
while (!EFI_ERROR(Status))
{
Status = (*PeiServices)->FfsFindNextFile (PeiServices,
EFI_FV_FILETYPE_FREEFORM, Fv, &File);
if (EFI_ERROR (Status))
goto ErrorLoop;
CmpStatus = guidcmp (&((EFI_FFS_FILE_HEADER*)File)->Name,&gDxeSigFfsGuid);
if (!CmpStatus)
break;
}
if (0 != CmpStatus)
goto ErrorLoop;
}
Status = CheckDxeSign (PeiServices, Fv, File);
if(EFI_ERROR(Status))
goto ErrorLoop;
return Status;
ErrorLoop:
while(1);
}
//*************************************************************************
//*************************************************************************
//** **
//** (C)Copyright 1985-2019, American Megatrends, Inc. **
//** **
//** All Rights Reserved. **
//** **
//** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 **
//** **
//** Phone: (770)-246-8600 **
//** **
//*************************************************************************
//*************************************************************************