slimbootloader/PayloadPkg/OsLoader/KeyManagement.c

271 lines
9.9 KiB
C

/** @file
Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "OsLoader.h"
extern CONST CHAR8 *mMmcDllStr;
UINT8 mRpmbKeyCount = 0;
/**
Check the eMMC storage serial number validity.
If card serial number != SPI flash serial number, then
save the new serial number from the card to SPI flash and
warm reset the platform.
@retval EFI_SUCCESS Successfully checked and saved the serial number.
@retval EFI_NOT_FOUND Couldnt retrieve serial number either from card or flash.
@retval EFI_DEVICE_ERROR Couldnt save the new serial number to SPI flash.
**/
EFI_STATUS
EmmcSerialNumCheck (
VOID
)
{
EFI_STATUS Status;
EMMC_TUNING_DATA EmmcTuningData;
UINTN VariableLen;
LOADER_PLATFORM_INFO *LoaderPlatformInfo;
PLATFORM_SERVICE *PlatformService;
PlatformService = NULL;
// Get serial number from the eMMC card
LoaderPlatformInfo = (LOADER_PLATFORM_INFO *)GetLoaderPlatformInfoPtr();
if (LoaderPlatformInfo == NULL) {
return EFI_NOT_FOUND;
}
// Get serial number from SPI flash
VariableLen = sizeof (EmmcTuningData);
Status = GetVariable ((CHAR8 *)mMmcDllStr, NULL, &VariableLen, (void *)&EmmcTuningData);
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
// Compare serial number from the card and SPI flash
if (AsciiStriCmp (LoaderPlatformInfo->SerialNumber, EmmcTuningData.SerialNumber) != 0) {
AsciiStrCpyS (EmmcTuningData.SerialNumber, sizeof(EmmcTuningData.SerialNumber), LoaderPlatformInfo->SerialNumber);
// Save new serial number into SPI flash
Status = SetVariable ((CHAR8 *)mMmcDllStr, 0, sizeof (EMMC_TUNING_DATA), (VOID *)&EmmcTuningData);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "MMC serial number save to flash unsuccessful, Status = %r\n", Status));
return EFI_DEVICE_ERROR;
}
// Reset platform
PlatformService = (PLATFORM_SERVICE *) GetServiceBySignature (PLATFORM_SERVICE_SIGNATURE);
if ((PlatformService != NULL) && (PlatformService->ResetSystem != NULL)) {
DEBUG ((DEBUG_ERROR, "Initializing Platform Warm Reset due to inconsistent serial number\n"));
PlatformService->ResetSystem (EfiResetWarm);
}
}
return Status;
}
/**
Seed Sanity check to check seed HOB validity before passing to OS.
This is needed to ensure that only the correct seeds are passed from Stage2 HOB buffer
to OS based on the Image type( OS, Trusty flags) for current target boot index[0].
1.native android (AOS loader) without Trusty OS (evmm) = only rpmb needed
2.native android (AOS loader) with Trusty OS = dseed + rpmb
3.Clear linux without Trusty = useed + dseed
4.Clear Linux with Trusty (no AOS loader) = all (useed/dseed/rpmb keys)
5.ACRN = all
@param[in] CurrentBootOption Current boot option
@param[in,out] SeedList Pointer to the Seed list
@retval EFI_SUCCESS Successfully checked the seed validity.
@retval EFI_NOT_FOUND Couldnt retrieve seeds or couldnt find bootoptionslist.
**/
EFI_STATUS
SeedSanityCheck (
IN OS_BOOT_OPTION *CurrentBootOption,
IN OUT LOADER_SEED_LIST *SeedList
)
{
OS_BOOT_OPTION_LIST *OsBootOptionList;
SEED_LIST_INFO_HOB *SeedListInfo;
UINT8 OsImageType;
UINT8 CurrentOsImageType;
BOOLEAN TrustyFlag;
BOOLEAN CurrentTrustyFlag;
BOOLEAN ClearSeedHOB;
UINT8 Index;
UINT8 UseedCount;
UINT8 DseedCount;
UINT32 SeedListLen;
EFI_STATUS Status;
Status = EFI_SUCCESS;
ClearSeedHOB = FALSE;
UseedCount = 0;
DseedCount = 0;
SeedListLen = 0;
OsBootOptionList = GetBootOptionList ();
if ((OsBootOptionList == NULL) || (OsBootOptionList->OsBootOptionCount == 0)) {
return EFI_NOT_FOUND;
}
SeedListInfo = GetSeedListInfoHOB (&SeedListLen);
if ((SeedListInfo == NULL) || (SeedListLen == 0)) {
return EFI_NOT_FOUND;
}
// Get OStype/ Trusty Flag from Osbootoptionlist for index: 0
// as its assumed that target OS should always be at index:0
OsImageType = OsBootOptionList->OsBootOption[0].ImageType;
TrustyFlag = (OsBootOptionList->OsBootOption[0].BootFlags & BOOT_FLAGS_TRUSTY) >> 2;
// Get Os type/Trusty flag from current boot option
CurrentOsImageType = CurrentBootOption->ImageType;
CurrentTrustyFlag = (CurrentBootOption->BootFlags & BOOT_FLAGS_TRUSTY) >> 2;
// Compare OS type/Trusty flags of current bootoption with bootoption index 0
if((OsImageType == CurrentOsImageType) && (TrustyFlag == CurrentTrustyFlag)) {
// Retrieve Seeds from HOB
for(Index = 0; Index < SeedListInfo->TotalSeedCount; Index++) {
Status = GetSeedData (SEED_ENTRY_TYPE_SVNSEED, SEED_ENTRY_USAGE_USEED, UseedCount, sizeof(SVN_SEED_INFO), (UINT8 *)&SeedList->UseedList[UseedCount]);
if (!EFI_ERROR (Status)) {
UseedCount++;
}
Status = GetSeedData (SEED_ENTRY_TYPE_SVNSEED, SEED_ENTRY_USAGE_DSEED, DseedCount, sizeof(SVN_SEED_INFO), (UINT8 *)&SeedList->DseedList[DseedCount]);
if (!EFI_ERROR (Status)) {
DseedCount++;
}
// First get RPMB seed based on card Serial Number.
Status = GetSeedData (SEED_ENTRY_TYPE_RPMB, SEED_ENTRY_USAGE_BASED_ON_SERIALNO, mRpmbKeyCount, MKHI_BOOTLOADER_SEED_LEN, (UINT8 *)&SeedList->RpmbHeciSeeds[mRpmbKeyCount]);
if (EFI_ERROR (Status)) {
// If not found, then SBL has tied it with Zero based Serial Number.
Status = GetSeedData (SEED_ENTRY_TYPE_RPMB, SEED_ENTRY_USAGE_NOT_BASED_ON_SERIALNO, mRpmbKeyCount, MKHI_BOOTLOADER_SEED_LEN, (UINT8 *)&SeedList->RpmbHeciSeeds[mRpmbKeyCount]);
}
if (!EFI_ERROR (Status)) {
mRpmbKeyCount++;
}
}
// Check Image Type and only then only pass seeds to OS. If not, zero out the HOB
if(!((OsImageType == EnumImageTypeClearLinux) || (OsImageType == EnumImageTypeAcrn))) {
if(UseedCount > 0) {
// No other Image should have useeds. Zero out HOB buffer
ClearSeedHOB = TRUE;
}
}
if(!((OsImageType == EnumImageTypeClearLinux) || (OsImageType == EnumImageTypeAcrn) ||
((OsImageType == EnumImageTypeAdroid) && (TrustyFlag != 0)))) {
if(DseedCount > 0) {
// No other Image should have dseeds. Zero out HOB buffer
ClearSeedHOB = TRUE;
}
}
if (!((OsImageType == EnumImageTypeAdroid) || (OsImageType == EnumImageTypeAcrn) ||
((OsImageType == EnumImageTypeClearLinux) && (TrustyFlag != 0)))) {
if(mRpmbKeyCount > 0) {
// No other Image should have rpmb keys. Zero out HOB buffer
ClearSeedHOB = TRUE;
}
}
} else {
// Current boot option Image type is not same as Bootoption[0] ImageType.
// Donot send incorrect seeds to OS. Zero out the HOB
ClearSeedHOB = TRUE;
}
if (ClearSeedHOB) {
DEBUG ((DEBUG_ERROR, "Clear SeedList buffer due to OSImageType error\n"));
ZeroMem(SeedListInfo,SeedListLen);
}
return EFI_SUCCESS;
}
/**
Provision the RPMB key into RPMB partition.
Currently, there is only eMMC RPMB support. So this flow works
only if DeviceType = eMMC.
@param[in] CurrentBootOption Current boot option
@param[in] SeedList Pointer to the Seed list
@retval EFI_SUCCESS Successfully provisioned the RPMB key.
@retval EFI_NOT_FOUND Couldn't find PlatformService->CfgData or PlatformInfo
or SeedList not found.
@retval EFI_UNSUPPORTED RpmbProvisioning CfgData flag not enabled or SeedList
feature not enabled.
@retval EFI_OUT_OF_RESOURCES Couldn't allocate memory.
@retval Others Error occurred inside RPMB library.
**/
EFI_STATUS
RpmbKeyProvisioning (
IN OS_BOOT_OPTION *CurrentBootOption,
IN LOADER_SEED_LIST *SeedList
)
{
LOADER_PLATFORM_INFO *LoaderPlatformInfo;
GEN_CFG_DATA *GenCfgData;
UINT8 Index;
BOOLEAN Eom;
RPMB_RESPONSE_RESULT Result;
EFI_STATUS Status;
UINT8 *RpmbSeedInfo;
Result = 0;
if((SeedList == NULL) || (mRpmbKeyCount == 0)){
return EFI_NOT_FOUND;
}
// Check for the storage device medium: emmc/ufs/nvme.
// Currently only eMMC rpmb provisioning is supported
if (CurrentBootOption->DevType != OsBootDeviceEmmc) {
return EFI_UNSUPPORTED;
}
// Get Rpmb Key provisioning flag from Cfg Data
GenCfgData = (GEN_CFG_DATA *) FindConfigDataByTag (CDATA_GEN_TAG);
if (GenCfgData == NULL) {
return EFI_NOT_FOUND;
}
if((!GenCfgData->RpmbKeyProvisioning) || (!PcdGetBool (PcdSeedListEnabled))) {
return EFI_UNSUPPORTED;
}
LoaderPlatformInfo = (LOADER_PLATFORM_INFO *)GetLoaderPlatformInfoPtr();
if (LoaderPlatformInfo == NULL) {
return EFI_NOT_FOUND;
}
// Get manufacturing state
Eom = ((LoaderPlatformInfo->HwState & HWSTATE_IN_MANUFACTURING_MODE) == 0) ?TRUE:FALSE;
// Proceed further only if its in production mode and if the verified boot is enabled
if((Eom) || ((LoaderPlatformInfo->LdrFeatures & FEATURE_VERIFIED_BOOT) == FEATURE_VERIFIED_BOOT)) {
return EFI_UNSUPPORTED;
}
// Copy 32 bytes for APL
Status = EFI_UNSUPPORTED;
for(Index = 0;Index < mRpmbKeyCount; Index++) {
RpmbSeedInfo = (UINT8 *)&SeedList->RpmbHeciSeeds[Index];
Status = RpmbProgramKey(CurrentBootOption->DevType, 0, RpmbSeedInfo, 32, &Result);
}
return Status;
}