/** @file | |
Measure TCG required variable. | |
Copyright (c) 2013 - 2017, 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 <PiDxe.h> | |
#include <Guid/ImageAuthentication.h> | |
#include <IndustryStandard/UefiTcgPlatform.h> | |
#include <Library/UefiBootServicesTableLib.h> | |
#include <Library/UefiRuntimeServicesTableLib.h> | |
#include <Library/MemoryAllocationLib.h> | |
#include <Library/BaseMemoryLib.h> | |
#include <Library/DebugLib.h> | |
#include <Library/BaseLib.h> | |
#include <Library/TpmMeasurementLib.h> | |
typedef struct { | |
CHAR16 *VariableName; | |
EFI_GUID *VendorGuid; | |
} VARIABLE_TYPE; | |
typedef struct { | |
CHAR16 *VariableName; | |
EFI_GUID *VendorGuid; | |
VOID *Data; | |
UINTN Size; | |
} VARIABLE_RECORD; | |
#define MEASURED_AUTHORITY_COUNT_MAX 0x100 | |
UINTN mMeasuredAuthorityCount = 0; | |
UINTN mMeasuredAuthorityCountMax = 0; | |
VARIABLE_RECORD *mMeasuredAuthorityList = NULL; | |
VARIABLE_TYPE mVariableType[] = { | |
{EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid}, | |
}; | |
/** | |
This function will check if VarName should be recorded and return the address of VarName if it is needed. | |
@param[in] VarName A Null-terminated string that is the name of the vendor's variable. | |
@return the address of VarName. | |
**/ | |
CHAR16 * | |
AssignVarName ( | |
IN CHAR16 *VarName | |
) | |
{ | |
UINTN Index; | |
for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) { | |
if (StrCmp (VarName, mVariableType[Index].VariableName) == 0) { | |
return mVariableType[Index].VariableName; | |
} | |
} | |
return NULL; | |
} | |
/** | |
This function will check if VendorGuid should be recorded and return the address of VendorGuid if it is needed. | |
@param[in] VendorGuid A unique identifier for the vendor. | |
@return the address of VendorGuid. | |
**/ | |
EFI_GUID * | |
AssignVendorGuid ( | |
IN EFI_GUID *VendorGuid | |
) | |
{ | |
UINTN Index; | |
for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) { | |
if (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid)) { | |
return mVariableType[Index].VendorGuid; | |
} | |
} | |
return NULL; | |
} | |
/** | |
This function will add variable information to MeasuredAuthorityList. | |
@param[in] VarName A Null-terminated string that is the name of the vendor's variable. | |
@param[in] VendorGuid A unique identifier for the vendor. | |
@param[in] VarData The content of the variable data. | |
@param[in] VarSize The size of the variable data. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
**/ | |
EFI_STATUS | |
AddDataMeasured ( | |
IN CHAR16 *VarName, | |
IN EFI_GUID *VendorGuid, | |
IN VOID *Data, | |
IN UINTN Size | |
) | |
{ | |
VARIABLE_RECORD *NewMeasuredAuthorityList; | |
ASSERT (mMeasuredAuthorityCount <= mMeasuredAuthorityCountMax); | |
if (mMeasuredAuthorityCount == mMeasuredAuthorityCountMax) { | |
// | |
// Need enlarge | |
// | |
NewMeasuredAuthorityList = AllocateZeroPool (sizeof(VARIABLE_RECORD) * (mMeasuredAuthorityCountMax + MEASURED_AUTHORITY_COUNT_MAX)); | |
if (NewMeasuredAuthorityList == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
if (mMeasuredAuthorityList != NULL) { | |
CopyMem (NewMeasuredAuthorityList, mMeasuredAuthorityList, sizeof(VARIABLE_RECORD) * mMeasuredAuthorityCount); | |
FreePool (mMeasuredAuthorityList); | |
} | |
mMeasuredAuthorityList = NewMeasuredAuthorityList; | |
mMeasuredAuthorityCountMax += MEASURED_AUTHORITY_COUNT_MAX; | |
} | |
// | |
// Add new entry | |
// | |
mMeasuredAuthorityList[mMeasuredAuthorityCount].VariableName = AssignVarName (VarName); | |
mMeasuredAuthorityList[mMeasuredAuthorityCount].VendorGuid = AssignVendorGuid (VendorGuid); | |
mMeasuredAuthorityList[mMeasuredAuthorityCount].Size = Size; | |
mMeasuredAuthorityList[mMeasuredAuthorityCount].Data = AllocatePool (Size); | |
if (mMeasuredAuthorityList[mMeasuredAuthorityCount].Data == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyMem (mMeasuredAuthorityList[mMeasuredAuthorityCount].Data, Data, Size); | |
mMeasuredAuthorityCount++; | |
return EFI_SUCCESS; | |
} | |
/** | |
This function will return if this variable is already measured. | |
@param[in] VarName A Null-terminated string that is the name of the vendor's variable. | |
@param[in] VendorGuid A unique identifier for the vendor. | |
@param[in] VarData The content of the variable data. | |
@param[in] VarSize The size of the variable data. | |
@retval TRUE The data is already measured. | |
@retval FALSE The data is not measured yet. | |
**/ | |
BOOLEAN | |
IsDataMeasured ( | |
IN CHAR16 *VarName, | |
IN EFI_GUID *VendorGuid, | |
IN VOID *Data, | |
IN UINTN Size | |
) | |
{ | |
UINTN Index; | |
for (Index = 0; Index < mMeasuredAuthorityCount; Index++) { | |
if ((StrCmp (VarName, mMeasuredAuthorityList[Index].VariableName) == 0) && | |
(CompareGuid (VendorGuid, mMeasuredAuthorityList[Index].VendorGuid)) && | |
(CompareMem (Data, mMeasuredAuthorityList[Index].Data, Size) == 0) && | |
(Size == mMeasuredAuthorityList[Index].Size)) { | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
/** | |
This function will return if this variable is SecureAuthority Variable. | |
@param[in] VariableName A Null-terminated string that is the name of the vendor's variable. | |
@param[in] VendorGuid A unique identifier for the vendor. | |
@retval TRUE This is SecureAuthority Variable | |
@retval FALSE This is not SecureAuthority Variable | |
**/ | |
BOOLEAN | |
IsSecureAuthorityVariable ( | |
IN CHAR16 *VariableName, | |
IN EFI_GUID *VendorGuid | |
) | |
{ | |
UINTN Index; | |
for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) { | |
if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) && | |
(CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) { | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
/** | |
Measure and log an EFI variable, and extend the measurement result into a specific PCR. | |
@param[in] VarName A Null-terminated string that is the name of the vendor's variable. | |
@param[in] VendorGuid A unique identifier for the vendor. | |
@param[in] VarData The content of the variable data. | |
@param[in] VarSize The size of the variable data. | |
@retval EFI_SUCCESS Operation completed successfully. | |
@retval EFI_OUT_OF_RESOURCES Out of memory. | |
@retval EFI_DEVICE_ERROR The operation was unsuccessful. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MeasureVariable ( | |
IN CHAR16 *VarName, | |
IN EFI_GUID *VendorGuid, | |
IN VOID *VarData, | |
IN UINTN VarSize | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN VarNameLength; | |
UEFI_VARIABLE_DATA *VarLog; | |
UINT32 VarLogSize; | |
// | |
// The UEFI_VARIABLE_DATA.VariableData value shall be the EFI_SIGNATURE_DATA value | |
// from the EFI_SIGNATURE_LIST that contained the authority that was used to validate the image | |
// | |
VarNameLength = StrLen (VarName); | |
VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize | |
- sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); | |
VarLog = (UEFI_VARIABLE_DATA *) AllocateZeroPool (VarLogSize); | |
if (VarLog == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
CopyMem (&VarLog->VariableName, VendorGuid, sizeof(VarLog->VariableName)); | |
VarLog->UnicodeNameLength = VarNameLength; | |
VarLog->VariableDataLength = VarSize; | |
CopyMem ( | |
VarLog->UnicodeName, | |
VarName, | |
VarNameLength * sizeof (*VarName) | |
); | |
CopyMem ( | |
(CHAR16 *)VarLog->UnicodeName + VarNameLength, | |
VarData, | |
VarSize | |
); | |
DEBUG ((EFI_D_INFO, "DxeImageVerification: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_AUTHORITY)); | |
DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); | |
Status = TpmMeasureAndLogData ( | |
7, | |
EV_EFI_VARIABLE_AUTHORITY, | |
VarLog, | |
VarLogSize, | |
VarLog, | |
VarLogSize | |
); | |
FreePool (VarLog); | |
return Status; | |
} | |
/** | |
SecureBoot Hook for processing image verification. | |
@param[in] VariableName Name of Variable to be found. | |
@param[in] VendorGuid Variable vendor GUID. | |
@param[in] DataSize Size of Data found. If size is less than the | |
data, this value contains the required size. | |
@param[in] Data Data pointer. | |
**/ | |
VOID | |
EFIAPI | |
SecureBootHook ( | |
IN CHAR16 *VariableName, | |
IN EFI_GUID *VendorGuid, | |
IN UINTN DataSize, | |
IN VOID *Data | |
) | |
{ | |
EFI_STATUS Status; | |
if (!IsSecureAuthorityVariable (VariableName, VendorGuid)) { | |
return ; | |
} | |
if (IsDataMeasured (VariableName, VendorGuid, Data, DataSize)) { | |
DEBUG ((EFI_D_ERROR, "MeasureSecureAuthorityVariable - IsDataMeasured\n")); | |
return ; | |
} | |
Status = MeasureVariable ( | |
VariableName, | |
VendorGuid, | |
Data, | |
DataSize | |
); | |
DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status)); | |
if (!EFI_ERROR (Status)) { | |
AddDataMeasured (VariableName, VendorGuid, Data, DataSize); | |
} | |
return ; | |
} |