//
// This file contains a 'Sample Driver' and is licensed as such
// under the terms of your license agreement with Intel or your
// vendor. This file may be modified by the user, subject to
// the additional terms of the license agreement
//
/**
Utility to enroll UEFI value, including PK, KEK, db/dbx/dbt at build time.
Copyright (c) 2014 - 2020, Intel Corporation. All rights reserved.
This software and associated documentation (if any) is furnished
under a license and may only be used or copied in accordance
with the terms of the license. Except as permitted by such
license, no part of this software or documentation may be
reproduced, stored in a retrieval system, or transmitted in any
form or by any means without the express written consent of
Intel Corporation.
**/
#include "KeyEnroll.h"
#include "VariableCommon.h"
#include "EfiUtilityMsgs.c"
#include "AuthVariable.h"
#include
EFI_GUID gEfiGlobalVariableGuid = EFI_GLOBAL_VARIABLE;
EFI_GUID gEfiImageSecurityDatabaseGuid = EFI_IMAGE_SECURITY_DATABASE_GUID;
EFI_GUID gEfiSystemNvDataFvGuid = EFI_SYSTEM_NV_DATA_FV_GUID;
EFI_GUID gEfiCertRsa2048Guid = EFI_CERT_RSA2048_GUID;
EFI_GUID gEfiCertX509Guid = EFI_CERT_X509_GUID;
EFI_GUID gEfiCertSha1Guid = EFI_CERT_SHA1_GUID;
EFI_GUID gEfiCertSha256Guid = EFI_CERT_SHA256_GUID;
EFI_GUID gEfiCertSha384Guid = EFI_CERT_SHA384_GUID;
EFI_GUID gEfiCertSha512Guid = EFI_CERT_SHA512_GUID;
EFI_GUID gEfiCertTypeRsa2048Sha256Guid = EFI_CERT_TYPE_RSA2048_SHA256_GUID;
EFI_GUID gEfiCertTypePkcs7Guid = EFI_CERT_TYPE_PKCS7_GUID;
EFI_GUID gEfiCertX509Sha256Guid = EFI_CERT_X509_SHA256_GUID;
EFI_GUID gEfiCertX509Sha384Guid = EFI_CERT_X509_SHA384_GUID;
EFI_GUID gEfiCertX509Sha512Guid = EFI_CERT_X509_SHA512_GUID;
//
// OID ASN.1 Value for Hash Algorithms
//
UINT8 mHashOidValueSha1[] = {0x2B, 0x0E, 0x03, 0x02, 0x1A};
UINT8 mHashOidValueSha256[] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01};
UINT8 mHashOidValueSha384[] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02};
UINT8 mHashOidValueSha512[] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03};
HASH_TABLE mHash[] = {
{ L"SHA1", SHA1_DIGEST_SIZE, mHashOidValueSha1, sizeof(mHashOidValueSha1)},
{ L"SHA256", SHA256_DIGEST_SIZE, mHashOidValueSha256, sizeof(mHashOidValueSha256)},
{ L"SHA384", SHA384_DIGEST_SIZE, mHashOidValueSha384, sizeof(mHashOidValueSha384)},
{ L"SHA512", SHA512_DIGEST_SIZE, mHashOidValueSha512, sizeof(mHashOidValueSha512)},
};
G_EFI_FD_INFO gEfiFdInfo;
LIST_ENTRY mVarListEntry;
UINT8 mIgnoreTimeStamp;
unsigned int
xtoi (
char *str
);
VOID
PrintUtilityInfo (
VOID
)
/*++
Routine Description:
Displays the standard utility information to SDTOUT
Arguments:
None
Returns:
None
--*/
{
printf (
"%s - Tiano KeyEnroll Utility."" Version %i.%i\n\n",
UTILITY_NAME,
UTILITY_MAJOR_VERSION,
UTILITY_MINOR_VERSION
);
}
VOID
PrintUsage (
VOID
)
/*++
Routine Description:
Displays the utility usage syntax to STDOUT
Arguments:
None
Returns:
None
--*/
{
printf ("Usage: %s InputFile [OutputFile] [Command] [SubCommand] [Options [Parameter(s)]]\n"
"\tCommand: PK|KEK|db|dbx|VAR|INFO\n"
"\tPK ADD|DEL [-F [-G ]]\n"
"\tKEK ADD|APPEND|DEL [-F |-K -G ]\n"
"\tdb|dbx ADD|APPEND|DEL [-F |-I -G ]\n"
"\tdbt ADD|APPEND|DEL [-F -G ]\n"
"\tdbx ADD|APPEND -F -G -H SHA256|SHA384|SHA512 [-DATE |NOW -TIME |NOW]]\n"
"\tVAR ADD|APPEND|DEL -N -G [-A -D [-T]]\n"
"\tINFO [PK|KEK|db|dbx|dbt|ALL]\n"
"", UTILITY_NAME);
printf (" Where:\n");
printf ("\tInputFile - Name of the input FD file.\n");
printf ("\tOutputFile - Name of the output FD file. No such parameter for INFO command.\n");
printf ("\tCertFile - DER-encoded certificate.\n");
printf ("\tKeyFile - Public key binary file.\n");
printf ("\tImageFile - UEFI PE/COFF image file.\n");
printf ("\tDataFile - The raw bytes passed in *Data to SetVariable()... \n");
printf ("\t If -T is also specified, it includes an EFI_VARIABLE_AUTHENTICATION_2\n");
printf ("\t concatenated with the new variable value for time based Auth Variable.\n");
}
/**
Compare two EFI_TIME data.
@param FirstTime A pointer to the first EFI_TIME data.
@param SecondTime A pointer to the second EFI_TIME data.
@retval TRUE The FirstTime is not later than the SecondTime.
@retval FALSE The FirstTime is later than the SecondTime.
**/
BOOLEAN
CompareTimeStamp (
IN EFI_TIME *FirstTime,
IN EFI_TIME *SecondTime
)
{
if (FirstTime->Year != SecondTime->Year) {
return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
} else if (FirstTime->Month != SecondTime->Month) {
return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
} else if (FirstTime->Day != SecondTime->Day) {
return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
} else if (FirstTime->Hour != SecondTime->Hour) {
return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
} else if (FirstTime->Minute != SecondTime->Minute) {
return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
}
return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
}
VOID
GetCurrentTime (
OUT EFI_TIME *TimeStamp
)
{
time_t CurTime;
struct tm *GmTime;
memset (TimeStamp, 0, sizeof (*TimeStamp));
if (mIgnoreTimeStamp == 1) {
return;
}
time (&CurTime);
GmTime = gmtime (&CurTime);
if (GmTime == NULL) {
return;
}
TimeStamp->Year = (UINT16)GmTime->tm_year + 1900; // Year is 1900-based
TimeStamp->Month = (UINT8)GmTime->tm_mon + 1; // Month is zero based.
TimeStamp->Day = (UINT8)GmTime->tm_mday;
TimeStamp->Hour = (UINT8)GmTime->tm_hour;
TimeStamp->Minute = (UINT8)GmTime->tm_min;
TimeStamp->Second = (UINT8)GmTime->tm_sec;
}
BOOLEAN
IsGuidData (
IN CHAR8 *StringData,
IN EFI_GUID *Guid
)
/*++
Routine Description:
Check whether a string is a GUID
Arguments:
StringData - the String
Guid - Guid to hold the value
Returns:
TRUE - StringData is a GUID, and Guid field is filled.
FALSE - StringData is not a GUID
--*/
{
if (strlen (StringData) != strlen ("00000000-0000-0000-0000-000000000000")) {
return FALSE;
}
if ((StringData[8] != '-') ||
(StringData[13] != '-') ||
(StringData[18] != '-') ||
(StringData[23] != '-') ) {
return FALSE;
}
StringToGuid (StringData, Guid);
return TRUE;
}
BOOLEAN
IsDateData (
IN CHAR8 *StringData,
IN EFI_TIME *Time
)
{
UINTN Index;
UINT32 Month;
UINT32 Day;
UINT32 Year;
EFI_TIME TempTime;
if ((strcmp (StringData, "NOW") == 0) ||
(strcmp (StringData, "now") == 0)) {
//
// Fetch the current time based on UTC timezone
//
GetCurrentTime (&TempTime);
Time->Month = TempTime.Month;
Time->Day = TempTime.Day;
Time->Year = TempTime.Year;
return TRUE;
}
if (strlen (StringData) != strlen ("MM/DD/YYYY")) {
return FALSE;
}
if ((StringData[2] != '/') ||
(StringData[5] != '/') ) {
return FALSE;
}
for (Index = 0; Index < 10; Index++) {
if ((Index == 2) || (Index == 5)) {
continue;
}
if ((StringData[Index] >= '0') && (StringData[Index] <= '9')) {
continue;
} else {
return FALSE;
}
}
Index = sscanf (
StringData,
"%02u/%02u/%04u",
&Month,
&Day,
&Year
);
if (Index != 3) {
return FALSE;
}
if ((Month < 1) || (Month > 12)) {
return FALSE;
}
if ((Day < 1) || (Day > 31)) {
return FALSE;
}
if ((Year < 1900) || (Year > 9999)) {
return FALSE;
}
Time->Month = (UINT8)Month;
Time->Day = (UINT8)Day;
Time->Year = (UINT16)Year;
return TRUE;
}
BOOLEAN
IsTimeData (
IN CHAR8 *StringData,
IN EFI_TIME *Time
)
{
UINTN Index;
UINT32 Hour;
UINT32 Minute;
UINT32 Second;
EFI_TIME TempTime;
if ((strcmp (StringData, "NOW") == 0) ||
(strcmp (StringData, "now") == 0)) {
//
// Fetch the current time based on UTC timezone
//
GetCurrentTime (&TempTime);
Time->Hour = TempTime.Hour;
Time->Minute = TempTime.Minute;
Time->Second = TempTime.Second;
return TRUE;
}
if (strlen (StringData) != strlen ("HH:MM:SS")) {
return FALSE;
}
if ((StringData[2] != ':') ||
(StringData[5] != ':') ) {
return FALSE;
}
for (Index = 0; Index < 8; Index++) {
if ((Index == 2) || (Index == 5)) {
continue;
}
if ((StringData[Index] >= '0') && (StringData[Index] <= '9')) {
continue;
} else {
return FALSE;
}
}
Index = sscanf (
StringData,
"%02u:%02u:%02u",
&Hour,
&Minute,
&Second
);
if (Index != 3) {
return FALSE;
}
if (Hour > 23) {
return FALSE;
}
if (Minute > 59) {
return FALSE;
}
if (Second > 59) {
return FALSE;
}
Time->Hour = (UINT8)Hour;
Time->Minute = (UINT8)Minute;
Time->Second = (UINT8)Second;
return TRUE;
}
/**
Retrieve the TBSCertificate from one given X.509 certificate.
@param[in] Cert Pointer to the given DER-encoded X509 certificate.
@param[in] CertSize Size of the X509 certificate in bytes.
@param[out] TBSCert DER-Encoded To-Be-Signed certificate.
@param[out] TBSCertSize Size of the TBS certificate in bytes.
If Cert is NULL, then return FALSE.
If TBSCert is NULL, then return FALSE.
If TBSCertSize is NULL, then return FALSE.
@retval TRUE The TBSCertificate was retrieved successfully.
@retval FALSE Invalid X.509 certificate.
**/
BOOLEAN
EFIAPI
X509GetTBSCert (
IN CONST UINT8 *Cert,
IN UINTN CertSize,
OUT UINT8 **TBSCert,
OUT UINTN *TBSCertSize
)
{
CONST UINT8 *Temp;
INTN Asn1Tag;
INTN ObjClass;
UINTN Length;
//
// Check input parameters.
//
if ((Cert == NULL) || (TBSCert == NULL) || (TBSCertSize == NULL)) {
return FALSE;
}
//
// An X.509 Certificate is: (defined in RFC3280)
// Certificate ::= SEQUENCE {
// tbsCertificate TBSCertificate,
// signatureAlgorithm AlgorithmIdentifier,
// signature BIT STRING }
//
// and
//
// TBSCertificate ::= SEQUENCE {
// version [0] Version DEFAULT v1,
// ...
// }
//
// So we can just ASN1-parse the x.509 DER-encoded data. If we strip
// the first SEQUENCE, the second SEQUENCE is the TBSCertificate.
//
Temp = Cert;
ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)CertSize);
if (Asn1Tag != V_ASN1_SEQUENCE) {
return FALSE;
}
*TBSCert = (UINT8 *)Temp;
ASN1_get_object (&Temp, (long *)&Length, (int *)&Asn1Tag, (int *)&ObjClass, (long)Length);
//
// Verify the parsed TBSCertificate is one correct SEQUENCE data.
//
if (Asn1Tag != V_ASN1_SEQUENCE) {
return FALSE;
}
*TBSCertSize = Length + (Temp - *TBSCert);
return TRUE;
}
VOID
DumpHex (
IN UINT8 *Buffer,
IN UINTN BufferSize
)
/*++
Routine Description:
Dump hex data
Arguments:
Buffer - Buffer address
BufferSize - Buffer size
Returns:
None
--*/
{
UINTN Index;
UINTN IndexJ;
#define COL_SIZE 16
for (Index = 0; Index < BufferSize/COL_SIZE; Index++) {
printf (" %04x: ", (UINT16) Index * COL_SIZE);
for (IndexJ = 0; IndexJ < COL_SIZE; IndexJ++) {
printf ("%02x ", *(Buffer + Index * COL_SIZE + IndexJ));
}
printf ("\n");
}
if ((BufferSize % COL_SIZE) != 0) {
printf (" %04x: ", (UINT16) Index * COL_SIZE);
for (IndexJ = 0; IndexJ < (BufferSize % COL_SIZE); IndexJ++) {
printf ("%02x ", *(Buffer + Index * COL_SIZE + IndexJ));
}
printf ("\n");
}
}
VOID
Unicode2AsciiString (
IN CHAR16 *UniString,
OUT CHAR8 *String
)
/*++
Routine Description:
Write ascii string as unicode string format to FILE
Arguments:
String - Pointer to string that is written to FILE.
UniString - Pointer to unicode string
Returns:
NULL
--*/
{
while (*UniString != '\0') {
*(String++) = (CHAR8)*(UniString++);
}
*String = '\0';
}
VOID
Ascii2UnicodeString (
IN CHAR8 *String,
OUT CHAR16 *UniString
)
/*++
Routine Description:
Write ascii string as unicode string format to FILE
Arguments:
String - Pointer to string that is written to FILE.
UniString - Pointer to unicode string
Returns:
NULL
--*/
{
while (*String != '\0') {
*(UniString++) = (CHAR16)*(String++);
}
*UniString = '\0';
}
STATUS
ReadInputFile (
IN CHAR8 *FileName,
OUT UINT8 **FileData,
OUT UINT32 *FileSize,
OUT UINT8 **FileBufferRaw OPTIONAL
)
/*++
Routine Description:
Read input file
Arguments:
FileName - The input file name
FileData - The input file data, the memory is alligned.
FileSize - The input file size
FileBufferRaw - The memory to hold input file data. The caller should use this to free the memory.
Returns:
STATUS_SUCCESS - The file found and data read
STATUS_ERROR - The file data is not read
STATUS_WARNING - The file is not found
--*/
{
FILE *FpIn;
UINT32 TempResult;
//
// Open the Input Fvrecovery.fv file
//
if ((FpIn = fopen (FileName, "rb")) == NULL) {
//
// Return WARNING, let caller make decision
//
// Error (NULL, 0, 0, "Unable to open file", FileName);
return STATUS_WARNING;
}
//
// Get the Input Fvrecovery.fv file size
//
fseek (FpIn, 0, SEEK_END);
*FileSize = ftell (FpIn);
//
// Read the contents of input file to memory buffer
//
if (FileBufferRaw != NULL) {
*FileBufferRaw = (UINT8 *) malloc (*FileSize + 0x10000);
if (NULL == *FileBufferRaw) {
Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
fclose (FpIn);
return STATUS_ERROR;
}
TempResult = 0x10000 - (UINT32) ((UINTN) *FileBufferRaw & 0x0FFFF);
*FileData = (UINT8 *)((UINTN)*FileBufferRaw + TempResult);
} else {
*FileData = (UINT8 *) malloc (*FileSize);
if (NULL == *FileData) {
Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL);
fclose (FpIn);
return STATUS_ERROR;
}
}
fseek (FpIn, 0, SEEK_SET);
TempResult = fread (*FileData, 1, *FileSize, FpIn);
if (TempResult != *FileSize) {
Error (NULL, 0, 0, "Read input file error!", NULL);
if (FileBufferRaw != NULL) {
free ((VOID *)*FileBufferRaw);
} else {
free ((VOID *)*FileData);
}
fclose (FpIn);
return STATUS_ERROR;
}
//
// Close the input Fvrecovery.fv file
//
fclose (FpIn);
return STATUS_SUCCESS;
}
STATUS
WriteOutputFile (
IN CHAR8 *FileName,
IN UINT8 *FileData,
IN UINT32 FileSize
)
/*++
Routine Description:
Read input file
Arguments:
FileName - The input file name
FileData - The input file data
FileSize - The input file size
Returns:
STATUS_SUCCESS - Write file data successfully
STATUS_ERROR - The file data is not written
--*/
{
FILE *FpOut;
//
// Open the output Fvrecovery.fv file
//
if ((FpOut = fopen (FileName, "w+b")) == NULL) {
Error (NULL, 0, 0, "Unable to open file", FileName);
return STATUS_ERROR;
}
//
// Write the output Fvrecovery.fv file
//
if ((fwrite (FileData, 1, FileSize, FpOut)) != FileSize) {
Error (NULL, 0, 0, "Write output file error!", NULL);
fclose (FpOut);
return STATUS_ERROR;
}
//
// Close the output Fvrecovery.fv file
//
fclose (FpOut);
return STATUS_SUCCESS;
}
UINT8 *
FindNextFvHeader (
IN UINT8 *FileBuffer,
IN UINTN FileLength
)
/*++
Routine Description:
Find next FvHeader in the FileBuffer
Parameters:
FileBuffer - The start FileBuffer which needs to be searched
FileLength - The whole File Length.
Return:
FvHeader - The FvHeader is found successfully.
NULL - The FvHeader is not found.
--*/
{
UINT8 *FileHeader;
EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
UINT16 FileChecksum;
FileHeader = FileBuffer;
for (; (UINTN)FileBuffer < (UINTN)FileHeader + FileLength; FileBuffer += 8) {
FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer;
if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
//
// potential candidate
//
//
// Check checksum
//
if (FvHeader->FvLength > FileLength) {
continue;
}
if (FvHeader->HeaderLength >= FileLength) {
continue;
}
FileChecksum = CalculateChecksum16 ((UINT16 *)FileBuffer, FvHeader->HeaderLength / sizeof (UINT16));
if (FileChecksum != 0) {
continue;
}
//
// Check revision and reserved field
//
if ((FvHeader->Revision == EFI_FVH_PI_REVISION) &&
(FvHeader->Reserved[0] == 0) ){
return FileHeader;
}
}
}
return NULL;
}
UINT32
GetVariableInfoFromFd (
IN UINT8 *FdBuffer,
IN UINT32 FdFileSize,
OUT UINT8 **VariableFv
)
/*++
Routine Description:
Get Variable information from Fd file.
Assume Fv region is continuous in Fd file.
Arguments:
FdBuffer - Fd file buffer.
FdFileSize - Fd file size.
Fvrecovery - Fvrecovery pointer in Fd file buffer
Returns:
Fvrecovery file size
--*/
{
UINT8 *FileBuffer;
UINT32 VariableFvFileSize;
FileBuffer = FindNextFvHeader (FdBuffer, FdFileSize);
if (FileBuffer == NULL) {
*VariableFv = NULL;
return 0;
}
VariableFvFileSize = 0;
*VariableFv = NULL;
while ((UINTN)FileBuffer < (UINTN)FdBuffer + FdFileSize) {
//
// Check variable
//
if (((EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer)->Signature != EFI_FVH_SIGNATURE) {
FileBuffer += 0x10;
continue;
}
if (CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer)->FileSystemGuid) == 0) {
VariableFvFileSize = (UINT32)((EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer)->FvLength;
*VariableFv = FileBuffer;
break;
}
//
// Next fv
//
FileBuffer = FindNextFvHeader (FileBuffer, (UINTN)FdBuffer + FdFileSize - (UINTN)FileBuffer);
if (FileBuffer == NULL) {
break;
}
FileBuffer = (UINT8 *)FileBuffer + ((EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer)->FvLength;
}
return VariableFvFileSize;
}
/**
Exchange the data between Efi variable and the data of VarList
If VarToList is TRUE, copy the efi variable data to the VarList; Otherwise,
update the data from varlist to efi variable.
@param VarToList The flag to control the direction of exchange.
@param StorageListHead Decide which variale list be updated
@retval EFI_SUCCESS Get the address successfully.
**/
EFI_STATUS
EfiVarAndListExchange (
IN BOOLEAN VarToList,
IN LIST_ENTRY *StorageListHead
)
{
EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
EFI_STATUS Status;
VOID *VariableStoreHeader;
VARIABLE_TYPE VariableType;
Status = EFI_ABORTED;
VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
VariableStoreHeader = (VOID *)((CHAR8 *)VarAddr + VarAddr->HeaderLength);
//
// Judge the layout of NV by gEfiVariableGuid
//
VariableType = CheckVarStore (VariableStoreHeader);
Status = SynEfiVariable (VarToList, VariableType, StorageListHead);
return Status;
}
/**
Free resources of a storage.
@param Storage Pointer of the storage
**/
VOID
DestroyStorage (
IN VARIABLE_INFO_PRIVATE *Storage
)
{
if (Storage == NULL) {
return;
}
if (Storage->Name != NULL) {
free (Storage->Name);
}
if (Storage->Buffer != NULL) {
free (Storage->Buffer);
}
free (Storage);
Storage = NULL;
}
/**
Free resources allocated for all Storage in an LIST_ENTRY.
@param FormSet Pointer of the FormSet
**/
VOID
DestroyAllStorage (
IN LIST_ENTRY *StorageListHead
)
{
LIST_ENTRY *Link;
VARIABLE_INFO_PRIVATE *Storage;
if (StorageListHead->ForwardLink != NULL) {
while (!IsListEmpty (StorageListHead)) {
Link = GetFirstNode (StorageListHead);
Storage = VARIABLE_INFO_PRIVATE_FROM_LINK (Link);
RemoveEntryList (&Storage->Link);
DestroyStorage (Storage);
}
}
StorageListHead = NULL;
}
LIST_ENTRY *
FindVariableList (
IN LIST_ENTRY *StorageListHead,
IN CHAR16 *Name,
IN EFI_GUID *Guid
)
{
LIST_ENTRY *Link;
VARIABLE_INFO_PRIVATE *Storage;
if (StorageListHead->ForwardLink != NULL) {
Link = GetFirstNode (StorageListHead);
while (!IsNull (StorageListHead, Link)) {
Storage = VARIABLE_INFO_PRIVATE_FROM_LINK (Link);
if ((CompareGuid (&Storage->Guid, Guid) == 0) &&
(KeyEnrollStrCmp (Storage->Name, Name) == 0)) {
return Link;
}
Link = GetNextNode (StorageListHead, Link);
}
}
return NULL;
}
/*
Find out the matching VARIABLE_INFO_PRIVATE by variable name and guid.
@param[in] VariableName Name of variable to be find.
@param[in] VendorGuid Variable vendor GUID.
@retval VARIABLE_INFO_PRIVATE A pointer to VARIABLE_INFO_PRIVATE.
@retval NULL Not find.
*/
VARIABLE_INFO_PRIVATE*
FindVariableInfoPtr(
IN CHAR16 *VariableName,
IN EFI_GUID *VendorGuid
)
{
LIST_ENTRY *ListEntry;
//
// Try to get auth variable by name and GUID.
//
ListEntry = FindVariableList (&mVarListEntry, VariableName, VendorGuid);
if (ListEntry != NULL) {
return VARIABLE_INFO_PRIVATE_FROM_LINK (ListEntry);
}
return NULL;
}
/**
Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
And copy the combined data to final data.
@param[in] Data Pointer to original EFI_SIGNATURE_LIST.
@param[in] DataSize Size of Data buffer.
@param[in] NewData Pointer to new EFI_SIGNATURE_LIST.
@param[in] NewDataSize Size of NewData buffer.
@param[out] FinalData Pointer to final combined EFI_SIGNATURE_LIST.
@param[out] FinalDataSize Size of FinalData buffer.
**/
VOID
FilterSignatureList (
IN VOID *Data,
IN UINTN DataSize,
IN VOID *NewData,
IN UINTN NewDataSize,
OUT VOID *FinalData,
OUT UINTN *FinalDataSize
)
{
EFI_SIGNATURE_LIST *CertList;
EFI_SIGNATURE_DATA *Cert;
UINTN CertCount;
EFI_SIGNATURE_LIST *NewCertList;
EFI_SIGNATURE_DATA *NewCert;
UINTN NewCertCount;
UINTN Index;
UINTN Index2;
UINTN NewSize;
UINTN Size;
UINT8 *Tail;
UINTN CopiedCount;
UINTN SignatureListSize;
BOOLEAN IsNewCert;
//
// Copy the original data to final data first.
//
CopyMem (FinalData, Data, DataSize);
*FinalDataSize = DataSize;
if (NewDataSize == 0) {
return;
}
Tail = (UINT8 *) FinalData + *FinalDataSize;
NewSize = NewDataSize;
NewCertList = (EFI_SIGNATURE_LIST *) NewData;
while ((NewSize > 0) && (NewSize >= NewCertList->SignatureListSize)) {
NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
CopiedCount = 0;
for (Index = 0; Index < NewCertCount; Index++) {
IsNewCert = TRUE;
Size = DataSize;
CertList = (EFI_SIGNATURE_LIST *) Data;
while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
if ((CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) == 0) &&
(CertList->SignatureSize == NewCertList->SignatureSize)) {
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
for (Index2 = 0; Index2 < CertCount; Index2++) {
//
// Iterate each Signature Data in this Signature List.
//
if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
IsNewCert = FALSE;
break;
}
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
}
}
if (!IsNewCert) {
break;
}
Size -= CertList->SignatureListSize;
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
}
if (IsNewCert) {
printf ("found new cert!\n");
//
// New EFI_SIGNATURE_DATA, keep it.
//
if (CopiedCount == 0) {
//
// Copy EFI_SIGNATURE_LIST header for only once.
//
CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
}
CopyMem (Tail, NewCert, NewCertList->SignatureSize);
Tail += NewCertList->SignatureSize;
CopiedCount++;
}
NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
}
//
// Update SignatureListSize in the kept EFI_SIGNATURE_LIST.
//
if (CopiedCount != 0) {
SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
CertList->SignatureListSize = (UINT32) SignatureListSize;
}
NewSize -= NewCertList->SignatureListSize;
NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
}
*FinalDataSize = (Tail - (UINT8 *) FinalData);
}
EFI_STATUS
UpdateVariableList (
IN LIST_ENTRY *Link,
IN CHAR16 *Name,
IN EFI_GUID *Guid,
IN UINT32 Attributes,
IN EFI_TIME *TimeStamp,
IN UINTN Size,
IN UINT8 *Buffer,
IN BOOLEAN Append
)
{
VARIABLE_INFO_PRIVATE *Storage;
UINTN NewSize;
UINT8 *NewBuffer;
Storage = VARIABLE_INFO_PRIVATE_FROM_LINK (Link);
Storage->Attributes = Attributes;
if (Append) {
if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
//
// When the new TimeStamp value is later than the current timestamp associated
// with the variable, we need associate the new timestamp with the updated value.
//
if (CompareTimeStamp (&Storage->TimeStamp, TimeStamp)) {
CopyMem (&Storage->TimeStamp, TimeStamp, sizeof (*TimeStamp));
}
}
NewSize = Storage->Size + Size;
NewBuffer = malloc (NewSize);
if (NewBuffer == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
return EFI_OUT_OF_RESOURCES;
}
ASSERT (Storage->Buffer != NULL);
if (((CompareGuid (Guid, &gEfiImageSecurityDatabaseGuid) == 0) &&
((KeyEnrollStrCmp (Name, EFI_IMAGE_SECURITY_DATABASE) == 0) || (KeyEnrollStrCmp (Name, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
(KeyEnrollStrCmp (Name, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||
((CompareGuid (Guid, &gEfiGlobalVariableGuid) == 0) && (KeyEnrollStrCmp (Name, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {
FilterSignatureList (
Storage->Buffer,
Storage->Size,
Buffer,
Size,
NewBuffer,
&NewSize
);
} else {
CopyMem (NewBuffer, Storage->Buffer, Storage->Size);
CopyMem (NewBuffer + Storage->Size, Buffer, Size);
}
Storage->Size = NewSize;
free (Storage->Buffer);
Storage->Buffer = NewBuffer;
} else {
if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
CopyMem (&Storage->TimeStamp, TimeStamp, sizeof (*TimeStamp));
}
Storage->Size = Size;
ASSERT (Storage->Buffer != NULL);
free (Storage->Buffer);
Storage->Buffer = malloc (Size);
if (Storage->Buffer == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
return EFI_OUT_OF_RESOURCES;
}
CopyMem (Storage->Buffer, Buffer, Size);
}
return EFI_SUCCESS;
}
EFI_STATUS
CreateVariableList (
IN LIST_ENTRY *StorageListHead,
IN CHAR16 *Name,
IN EFI_GUID *Guid,
IN UINT32 Attributes,
IN EFI_TIME *TimeStamp,
IN UINTN Size,
IN UINT8 *Buffer,
IN BOOLEAN Append
)
{
VARIABLE_INFO_PRIVATE *Storage;
UINTN VarNameSize;
LIST_ENTRY *Link;
EFI_TIME TempTimeStamp;
if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
(TimeStamp == NULL)) {
//
// Fetch the current time based on UTC timezone
//
GetCurrentTime (&TempTimeStamp);
TimeStamp = &TempTimeStamp;
}
//
// Check previous one
//
Link = FindVariableList (StorageListHead, Name, Guid);
if (Link != NULL) {
return UpdateVariableList (
Link,
Name,
Guid,
Attributes,
TimeStamp,
Size,
Buffer,
Append
);
}
//
// Create new one
//
Storage = malloc (sizeof (*Storage));
if (Storage == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
return EFI_OUT_OF_RESOURCES;
}
Storage->Signature = VARIABLE_INFO_PRIVATE_SIGNATURE;
CopyMem (&Storage->Guid, Guid, sizeof(*Guid));
VarNameSize = KeyEnrollStrSize (Name);
Storage->Name = malloc (VarNameSize);
if (Storage->Name == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
free (Storage);
return EFI_OUT_OF_RESOURCES;
}
CopyMem (Storage->Name, Name, VarNameSize);
Storage->Attributes = Attributes;
Storage->Size = Size;
ASSERT (Storage->Size != 0);
Storage->Buffer = malloc (Size);
if (Storage->Buffer == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
free (Storage->Name);
free (Storage);
return EFI_OUT_OF_RESOURCES;
}
CopyMem (Storage->Buffer, Buffer, Size);
if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
CopyMem (&Storage->TimeStamp, TimeStamp, sizeof (*TimeStamp));
}
InsertTailList(StorageListHead, &Storage->Link);
return EFI_SUCCESS;
}
EFI_STATUS
DeleteVariableList (
IN LIST_ENTRY *StorageListHead,
IN CHAR16 *Name,
IN EFI_GUID *Guid
)
{
VARIABLE_INFO_PRIVATE *Storage;
LIST_ENTRY *Link;
Link = FindVariableList (StorageListHead, Name, Guid);
if (Link == NULL) {
return EFI_NOT_FOUND;
}
Storage = VARIABLE_INFO_PRIVATE_FROM_LINK (Link);
RemoveEntryList (&Storage->Link);
DestroyStorage (Storage);
return EFI_SUCCESS;
}
VOID
SwapEndian (
IN UINT8 *Area,
IN UINT32 Size
)
/*++
Routine Description:
Swap area from big endian to little endian
Arguments:
Area - Buffer address
Size - Buffer size
Returns:
None
--*/
{
UINT8 Temp;
UINTN Index;
for (Index = 0; Index < (UINTN)Size / 2; Index++) {
Temp = *(Area + Index);
*(Area + Index) = *(Area + Size - 1 - Index);
*(Area + Size - 1 - Index) = Temp;
}
}
/**
Load PE/COFF image information into internal buffer and check its validity.
@retval EFI_SUCCESS Successful
@retval EFI_UNSUPPORTED Invalid PE/COFF file
@retval EFI_ABORTED Serious error occurs, like file I/O error etc.
**/
EFI_STATUS
LoadPeImage (
IN UINT8 *ImageBase,
IN UINTN ImageSize,
OUT EFI_IMAGE_SECURITY_DATA_DIRECTORY **SecDataDir
)
{
EFI_IMAGE_DOS_HEADER *DosHdr;
EFI_IMAGE_NT_HEADERS32 *NtHeader32;
EFI_IMAGE_NT_HEADERS64 *NtHeader64;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION NtHeader;
UINT32 PeCoffHeaderOffset;
UINT16 Magic;
NtHeader32 = NULL;
NtHeader64 = NULL;
//
// Read the Dos header
//
DosHdr = (EFI_IMAGE_DOS_HEADER *)(ImageBase);
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
//
// DOS image header is present,
// So read the PE header after the DOS image header
//
PeCoffHeaderOffset = DosHdr->e_lfanew;
} else {
PeCoffHeaderOffset = 0;
}
//
// Read PE header and check the signature validity and machine compatibility
//
NtHeader32 = (EFI_IMAGE_NT_HEADERS32 *) (ImageBase + PeCoffHeaderOffset);
if (NtHeader32->Signature != EFI_IMAGE_NT_SIGNATURE) {
return EFI_UNSUPPORTED;
}
NtHeader.Pe32 = NtHeader32;
//
// Measuring PE/COFF Image Header;
// But CheckSum field and SECURITY data directory (certificate) are excluded
//
//
// Get the magic value from the PE/COFF Optional Header
//
Magic = NtHeader.Pe32->OptionalHeader.Magic;
//
// Check the architecture field of PE header and get the Certificate Data Directory data
// Note the size of FileHeader field is constant for both IA32 and X64 arch
//
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
*SecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY *) &(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
} else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *) (ImageBase + PeCoffHeaderOffset);
*SecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY *) &(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
} else {
return EFI_UNSUPPORTED;
}
return EFI_SUCCESS;
}
/**
Calculate hash of Pe/Coff image based on the authenticode image hashing in
PE/COFF Specification 8.0 Appendix A
@param[in] HashAlg Hash algorithm type.
@retval TRUE Successfully hash image.
@retval FALSE Fail in hash image.
**/
BOOLEAN
HashPeImage (
IN UINT32 HashAlg,
IN UINT8 *ImageBase,
IN UINTN ImageSize,
OUT UINT8 *ImageDigest,
OUT UINTN *ImageDigestSize,
OUT EFI_GUID *CertType
)
{
BOOLEAN Status;
EFI_IMAGE_DOS_HEADER *DosHdr;
UINT32 PeCoffHeaderOffset;
EFI_IMAGE_SECTION_HEADER *Section;
UINT8 *HashBase;
UINTN HashSize;
UINTN SumOfBytesHashed;
EFI_IMAGE_SECTION_HEADER *SectionHeader;
UINTN Index;
UINTN Pos;
UINT16 Magic;
EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
UINT32 NumberOfRvaAndSizes;
UINT32 CertSize;
EVP_MD_CTX ctx;
const EVP_MD *md;
SectionHeader = NULL;
Status = FALSE;
//
// Initialize context of hash.
//
if (HashAlg == HASHALG_SHA1) {
*ImageDigestSize = SHA1_DIGEST_SIZE;
CopyMem (CertType, &gEfiCertSha1Guid, sizeof(*CertType));
} else if (HashAlg == HASHALG_SHA256) {
*ImageDigestSize = SHA256_DIGEST_SIZE;
CopyMem (CertType, &gEfiCertSha256Guid, sizeof(*CertType));
} else if (HashAlg == HASHALG_SHA384) {
*ImageDigestSize = SHA384_DIGEST_SIZE;
CopyMem (CertType, &gEfiCertSha384Guid, sizeof(*CertType));
} else if (HashAlg == HASHALG_SHA512) {
*ImageDigestSize = SHA512_DIGEST_SIZE;
CopyMem (CertType, &gEfiCertSha512Guid, sizeof(*CertType));
} else {
printf ("HashPeImage - HashAlg : 0x%x\n", HashAlg);
return FALSE;
}
ZeroMem (ImageDigest, *ImageDigestSize);
switch (HashAlg) {
case HASHALG_SHA1:
md = EVP_sha1();
break;
case HASHALG_SHA256:
md = EVP_sha256();
break;
case HASHALG_SHA384:
md = EVP_sha384();
break;
case HASHALG_SHA512:
md = EVP_sha512();
break;
default:
md = NULL;
break;
}
//
// Check PE/COFF image
//
DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageBase;
PeCoffHeaderOffset = 0;
if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
PeCoffHeaderOffset = DosHdr->e_lfanew;
}
Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageBase + PeCoffHeaderOffset);
if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
printf ("Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE\n");
Status = FALSE;
goto Done;
}
//
// PE/COFF Image Measurement
//
// NOTE: The following codes/steps are based upon the authenticode image hashing in
// PE/COFF Specification 8.0 Appendix A.
//
//
// 1. Load the image header into memory.
// 2. Initialize a SHA hash context.
EVP_DigestInit(&ctx, md);
//
// Measuring PE/COFF Image Header;
// But CheckSum field and SECURITY data directory (certificate) are excluded
//
//
// Get the magic value from the PE/COFF Optional Header
//
Magic = Hdr.Pe32->OptionalHeader.Magic;
//
// 3. Calculate the distance from the base of the image header to the image checksum address.
// 4. Hash the image header from its base to beginning of the image checksum.
//
HashBase = ImageBase;
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset.
//
NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
HashSize = (UINTN) ((UINT8 *) (&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
} else {
//
// Use PE32+ offset.
//
NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
HashSize = (UINTN) ((UINT8 *) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
}
EVP_DigestUpdate(&ctx, HashBase, HashSize);
//
// 5. Skip over the image checksum (it occupies a single ULONG).
//
if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
//
// 6. Since there is no Cert Directory in optional header, hash everything
// from the end of the checksum to the end of image header.
//
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset.
//
HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageBase);
} else {
//
// Use PE32+ offset.
//
HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageBase);
}
if (HashSize != 0) {
EVP_DigestUpdate(&ctx, HashBase, HashSize);
}
} else {
//
// 7. Hash everything from the end of the checksum to the start of the Cert Directory.
//
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset.
//
HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
HashSize = (UINTN) ((UINT8 *) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
} else {
//
// Use PE32+ offset.
//
HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
HashSize = (UINTN) ((UINT8 *) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
}
if (HashSize != 0) {
EVP_DigestUpdate(&ctx, HashBase, HashSize);
}
//
// 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
// 9. Hash everything from the end of the Cert Directory to the end of image header.
//
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset
//
HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - ImageBase);
} else {
//
// Use PE32+ offset.
//
HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - ImageBase);
}
EVP_DigestUpdate(&ctx, HashBase, HashSize);
}
//
// 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
//
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset.
//
SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
} else {
//
// Use PE32+ offset
//
SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
}
//
// 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
// structures in the image. The 'NumberOfSections' field of the image
// header indicates how big the table should be. Do not include any
// IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
//
SectionHeader = (EFI_IMAGE_SECTION_HEADER *) malloc (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
if (SectionHeader == NULL) {
printf ("SectionHeader == NULL\n");
Status = FALSE;
goto Done;
}
ZeroMem (SectionHeader, sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
//
// 12. Using the 'PointerToRawData' in the referenced section headers as
// a key, arrange the elements in the table in ascending order. In other
// words, sort the section headers according to the disk-file offset of
// the section.
//
Section = (EFI_IMAGE_SECTION_HEADER *) (
ImageBase +
PeCoffHeaderOffset +
sizeof (UINT32) +
sizeof (EFI_IMAGE_FILE_HEADER) +
Hdr.Pe32->FileHeader.SizeOfOptionalHeader
);
for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
Pos = Index;
while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
Pos--;
}
CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
Section += 1;
}
//
// 13. Walk through the sorted table, bring the corresponding section
// into memory, and hash the entire section (using the 'SizeOfRawData'
// field in the section header to determine the amount of data to hash).
// 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
// 15. Repeat steps 13 and 14 for all the sections in the sorted table.
//
for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
Section = &SectionHeader[Index];
if (Section->SizeOfRawData == 0) {
continue;
}
HashBase = ImageBase + Section->PointerToRawData;
HashSize = (UINTN) Section->SizeOfRawData;
EVP_DigestUpdate(&ctx, HashBase, HashSize);
SumOfBytesHashed += HashSize;
}
//
// 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
// data in the file that needs to be added to the hash. This data begins
// at file offset SUM_OF_BYTES_HASHED and its length is:
// FileSize - (CertDirectory->Size)
//
if (ImageSize > SumOfBytesHashed) {
HashBase = ImageBase + SumOfBytesHashed;
if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
CertSize = 0;
} else {
if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
//
// Use PE32 offset.
//
CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
} else {
//
// Use PE32+ offset.
//
CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
}
}
if (ImageSize > CertSize + SumOfBytesHashed) {
HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
EVP_DigestUpdate(&ctx, HashBase, HashSize);
}
}
EVP_DigestFinal(&ctx, (UINT8 *)ImageDigest, NULL);
Status = TRUE;
Done:
if (SectionHeader != NULL) {
free (SectionHeader);
}
return Status;
}
/**
Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of
Pe/Coff image based on the authenticated image hashing in PE/COFF Specification
8.0 Appendix A
@retval EFI_UNSUPPORTED Hash algorithm is not supported.
@retval EFI_SUCCESS Hash successfully.
**/
EFI_STATUS
HashPeImageByType (
IN UINT8 *ImageBase,
IN UINTN ImageSize,
IN UINT8 *AuthData,
IN UINTN AuthDataSize,
OUT UINT8 *ImageDigest,
OUT UINTN *ImageDigestSize,
OUT EFI_GUID *CertType
)
{
UINT8 Index;
for (Index = 0; Index < HASHALG_MAX; Index++) {
//
// Check the Hash algorithm in PE/COFF Authenticode.
// According to PKCS#7 Definition:
// SignedData ::= SEQUENCE {
// version Version,
// digestAlgorithms DigestAlgorithmIdentifiers,
// contentInfo ContentInfo,
// .... }
// The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
// This field has the fixed offset (+32) in final Authenticode ASN.1 data.
// Fixed offset (+32) is calculated based on two bytes of length encoding.
//
if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
//
// Only support two bytes of Long Form of Length Encoding.
//
continue;
}
if (AuthDataSize < 32 + mHash[Index].OidLength) {
return EFI_UNSUPPORTED;
}
if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
break;
}
}
if (Index == HASHALG_MAX) {
return EFI_UNSUPPORTED;
}
//
// HASH PE Image based on Hash algorithm in PE/COFF Authenticode.
//
if (!HashPeImage(Index, ImageBase, ImageSize, ImageDigest, ImageDigestSize, CertType)) {
return EFI_UNSUPPORTED;
}
return EFI_SUCCESS;
}
EFI_STATUS
CreateImageCertificateList (
IN CHAR8 *ImageFile,
IN EFI_GUID *SignatureOwner,
OUT EFI_SIGNATURE_LIST **Cert
)
{
STATUS Status;
EFI_STATUS EfiStatus;
UINT8 *ImageBase = NULL;
UINTN ImageSize = 0;
EFI_SIGNATURE_DATA *CertData=NULL;
EFI_IMAGE_SECURITY_DATA_DIRECTORY *SecDataDir;
WIN_CERTIFICATE *Certificate;
UINT8 ImageDigest[MAX_DIGEST_SIZE];
UINTN ImageDigestSize;
EFI_GUID CertType;
WIN_CERTIFICATE_UEFI_GUID *GuidCertData;
WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
Status = ReadInputFile (ImageFile, &ImageBase, (UINT32 *) &ImageSize, NULL);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Unable to open file", ImageFile);
return EFI_NOT_FOUND;
}
EfiStatus = LoadPeImage (ImageBase, ImageSize, &SecDataDir);
if (EFI_ERROR (EfiStatus)) {
Error (NULL, 0, 0, "Unable to load PE image", ImageFile);
return EFI_UNSUPPORTED;
}
if (SecDataDir->SizeOfCert == 0) {
if (!HashPeImage (HASHALG_SHA256, ImageBase, ImageSize, ImageDigest, &ImageDigestSize, &CertType)) {
Error (NULL, 0, 0, "Unable to hash PE image", ImageFile);
free (ImageBase);
return EFI_UNSUPPORTED;
}
} else {
//
// Read the certificate data
//
Certificate = (WIN_CERTIFICATE *)(ImageBase + SecDataDir->Offset);
if (Certificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
GuidCertData = (WIN_CERTIFICATE_UEFI_GUID *) Certificate;
if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof(EFI_GUID)) == 0) {
if (!HashPeImage (HASHALG_SHA256, ImageBase, ImageSize, ImageDigest, &ImageDigestSize, &CertType)) {
Error (NULL, 0, 0, "Image wCertificateType is EFI_GUID, but unable to hash PE image", ImageFile);
free (ImageBase);
return EFI_UNSUPPORTED;
}
} else if (CompareMem (&GuidCertData->CertType, &gEfiCertTypePkcs7Guid, sizeof(EFI_GUID)) == 0) {
Status = HashPeImageByType (
ImageBase,
ImageSize,
(UINT8 *)GuidCertData + sizeof(GuidCertData->Hdr) + sizeof(GuidCertData->CertType),
GuidCertData->Hdr.dwLength - sizeof(GuidCertData->Hdr) - sizeof(GuidCertData->CertType),
ImageDigest,
&ImageDigestSize,
&CertType
);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 0, "Image wCertificateType is EFI_GUID, Unable to hash PE image by type", ImageFile);
free (ImageBase);
return EFI_UNSUPPORTED;
}
} else {
Error (NULL, 0, 0, "Image wCertificateType is EFI_GUID, but CertType is NOT gEfiCertTypeRsa2048Sha256Guid or gEfiCertTypePkcs7Guid", ImageFile);
free (ImageBase);
return EFI_UNSUPPORTED;
}
} else if (Certificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) Certificate;
Status = HashPeImageByType (
ImageBase,
ImageSize,
PkcsCertData->CertData,
PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr),
ImageDigest,
&ImageDigestSize,
&CertType
);
if (EFI_ERROR (Status)) {
Error (NULL, 0, 0, "Image wCertificateType is PKCS_SIGNED_DATA, Unable to hash PE image by type", ImageFile);
free (ImageBase);
return EFI_UNSUPPORTED;
}
} else {
Error (NULL, 0, 0, "Image wCertificateType is unknown", ImageFile);
free (ImageBase);
return EFI_UNSUPPORTED;
}
}
// Allocate space for PK certificate list and initialize it.
// Create PK database entry w/ SignatureHeaderSize equals 0.
//
*Cert = (EFI_SIGNATURE_LIST*) malloc (
sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1
+ ImageDigestSize
);
if (*Cert == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
free (ImageBase);
return EFI_OUT_OF_RESOURCES;
}
(*Cert)->SignatureListSize = (UINT32) (sizeof(EFI_SIGNATURE_LIST)
+ sizeof(EFI_SIGNATURE_DATA) - 1
+ ImageDigestSize);
(*Cert)->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + ImageDigestSize);
(*Cert)->SignatureHeaderSize = 0;
CopyMem (&(*Cert)->SignatureType, &CertType, sizeof(EFI_GUID));
CertData = (EFI_SIGNATURE_DATA*) ((UINTN)(*Cert)
+ sizeof(EFI_SIGNATURE_LIST)
+ (*Cert)->SignatureHeaderSize);
CopyMem (&CertData->SignatureOwner, SignatureOwner, sizeof(EFI_GUID));
CopyMem ((VOID*)&(CertData->SignatureData[0]), ImageDigest, ImageDigestSize);
free (ImageBase);
return EFI_SUCCESS;
}
EFI_STATUS
CreatePkCertificateList (
IN CHAR8 *PkKeyFile,
IN EFI_GUID *SignatureOwner,
OUT EFI_SIGNATURE_LIST **Cert
)
{
STATUS Status;
UINT8 *PkKeyData = NULL;
UINTN PkKeyDataSize = 0;
EFI_SIGNATURE_DATA *CertData=NULL;
CPL_KEY_INFO *KeyInfo;
VOID *KeyBuffer = NULL;
Status = ReadInputFile (PkKeyFile, &PkKeyData, (UINT32 *) &PkKeyDataSize, NULL);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Unable to open file", PkKeyFile);
return EFI_NOT_FOUND;
}
KeyInfo = (CPL_KEY_INFO *)PkKeyData;
if (KeyInfo->KeyLengthInBits/8 != WIN_CERT_UEFI_RSA2048_SIZE) {
Error (NULL, 0, 0, "PkKey data file format wrong", PkKeyFile);
free (PkKeyData);
return EFI_UNSUPPORTED;
}
KeyBuffer = (VOID *)(KeyInfo + 1);
SwapEndian (KeyBuffer, WIN_CERT_UEFI_RSA2048_SIZE);
// Allocate space for PK certificate list
// and initialize the list.
// Create PK database entry w/ SignatureHeaderSize equals 0.
//
*Cert = (EFI_SIGNATURE_LIST*) malloc (
sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1
+ WIN_CERT_UEFI_RSA2048_SIZE
);
if (*Cert == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
free (PkKeyData);
return EFI_OUT_OF_RESOURCES;
}
(*Cert)->SignatureListSize = sizeof(EFI_SIGNATURE_LIST)
+ sizeof(EFI_SIGNATURE_DATA) - 1
+ WIN_CERT_UEFI_RSA2048_SIZE;
(*Cert)->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE;
(*Cert)->SignatureHeaderSize = 0;
CopyMem (&(*Cert)->SignatureType, &gEfiCertRsa2048Guid, sizeof(EFI_GUID));
CertData = (EFI_SIGNATURE_DATA*)((UINTN)(*Cert)
+ sizeof(EFI_SIGNATURE_LIST)
+ (*Cert)->SignatureHeaderSize);
CopyMem (&CertData->SignatureOwner, SignatureOwner, sizeof(EFI_GUID));
//
// Fill the PK database with PKpub data from PKKeyFile.
//
CopyMem ((VOID*)&(CertData->SignatureData[0]), KeyBuffer, WIN_CERT_UEFI_RSA2048_SIZE);
free (PkKeyData);
return EFI_SUCCESS;
}
BOOLEAN
IsX509FileDER (
IN CONST UINT8 *X509Data,
IN UINTN X509DataSize
)
{
X509 *X509Cert;
//
// Read DER-encoded X509 Certificate and Construct X509 object.
//
X509Cert = d2i_X509 (NULL, &X509Data, (long) X509DataSize);
if (X509Cert == NULL) {
return FALSE;
}
return TRUE;
}
BOOLEAN
IsX509FilePEM (
IN CONST UINT8 *X509Data,
IN UINTN X509DataSize
)
{
if (X509DataSize <= sizeof("-----BEGIN")) {
return FALSE;
}
if (memcmp (X509Data, "-----BEGIN", sizeof("-----BEGIN") - 1) != 0) {
return FALSE;
}
return TRUE;
}
EFI_STATUS
CreatePkX509CertificateList (
IN CHAR8 *X509File,
IN EFI_GUID *SignatureOwner,
OUT EFI_SIGNATURE_LIST **Cert
)
{
STATUS Status;
UINT8 *X509Data = NULL;
UINTN X509DataSize = 0;
EFI_SIGNATURE_DATA *CertData=NULL;
Status = ReadInputFile (X509File, &X509Data, (UINT32 *) &X509DataSize, NULL);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Unable to open file", X509File);
return EFI_NOT_FOUND;
}
if (!IsX509FileDER (X509Data, X509DataSize)) {
if (IsX509FilePEM (X509Data, X509DataSize)) {
Error (NULL, 0, 0, "PEM format X509 file unsupported", X509File);
} else {
Error (NULL, 0, 0, "Non-DER format X509 file unsupported", X509File);
}
return EFI_UNSUPPORTED;
}
// Allocate space for PK certificate list and initialize it.
// Create PK database entry w/ SignatureHeaderSize equals 0.
//
*Cert = (EFI_SIGNATURE_LIST*) malloc (
sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1
+ X509DataSize
);
if (*Cert == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
return EFI_OUT_OF_RESOURCES;
}
(*Cert)->SignatureListSize = (UINT32) (sizeof(EFI_SIGNATURE_LIST)
+ sizeof(EFI_SIGNATURE_DATA) - 1
+ X509DataSize);
(*Cert)->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
(*Cert)->SignatureHeaderSize = 0;
CopyMem (&(*Cert)->SignatureType, &gEfiCertX509Guid, sizeof(EFI_GUID));
CertData = (EFI_SIGNATURE_DATA*) ((UINTN)(*Cert)
+ sizeof(EFI_SIGNATURE_LIST)
+ (*Cert)->SignatureHeaderSize);
CopyMem (&CertData->SignatureOwner, SignatureOwner, sizeof(EFI_GUID));
CopyMem ((VOID*)&(CertData->SignatureData[0]), X509Data, X509DataSize);
free (X509Data);
return EFI_SUCCESS;
}
EFI_STATUS
CreatePkX509CertificateListHash (
IN CHAR8 *X509File,
IN EFI_GUID *SignatureOwner,
IN UINT32 HashAlg,
IN EFI_TIME *Time,
OUT EFI_SIGNATURE_LIST **Cert
)
{
STATUS Status;
UINT8 *X509Data = NULL;
UINTN X509DataSize = 0;
EFI_SIGNATURE_DATA *CertData=NULL;
UINT8 *TBSCert;
UINTN TBSCertSize;
EFI_CERT_X509_SHA256 X509Sha256;
EFI_CERT_X509_SHA384 X509Sha384;
EFI_CERT_X509_SHA512 X509Sha512;
UINT8 *X509Hash;
UINTN X509HashSize;
EVP_MD_CTX ctx;
const EVP_MD *md;
Status = ReadInputFile (X509File, &X509Data, (UINT32 *) &X509DataSize, NULL);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Unable to open file", X509File);
return EFI_NOT_FOUND;
}
if (!IsX509FileDER (X509Data, X509DataSize)) {
if (IsX509FilePEM (X509Data, X509DataSize)) {
Error (NULL, 0, 0, "PEM format X509 file unsupported", X509File);
} else {
Error (NULL, 0, 0, "Non-DER format X509 file unsupported", X509File);
}
return EFI_UNSUPPORTED;
}
//
// Retrieve the TBSCertificate from the X.509 Certificate.
//
if (!X509GetTBSCert (X509Data, X509DataSize, &TBSCert, &TBSCertSize)) {
return EFI_UNSUPPORTED;
}
switch (HashAlg) {
case HASHALG_SHA256:
md = EVP_sha256();
EVP_DigestInit(&ctx, md);
EVP_DigestUpdate(&ctx, TBSCert, TBSCertSize);
EVP_DigestFinal(&ctx, (UINT8 *)&X509Sha256.ToBeSignedHash, NULL);
CopyMem (&X509Sha256.TimeOfRevocation, Time, sizeof(EFI_TIME));
X509Hash = (UINT8 *)&X509Sha256;
X509HashSize = sizeof(X509Sha256);
break;
case HASHALG_SHA384:
md = EVP_sha384();
EVP_DigestInit(&ctx, md);
EVP_DigestUpdate(&ctx, TBSCert, TBSCertSize);
EVP_DigestFinal(&ctx, (UINT8 *)&X509Sha384.ToBeSignedHash, NULL);
CopyMem (&X509Sha384.TimeOfRevocation, Time, sizeof(EFI_TIME));
X509Hash = (UINT8 *)&X509Sha384;
X509HashSize = sizeof(X509Sha384);
break;
case HASHALG_SHA512:
md = EVP_sha512();
EVP_DigestInit(&ctx, md);
EVP_DigestUpdate(&ctx, TBSCert, TBSCertSize);
EVP_DigestFinal(&ctx, (UINT8 *)&X509Sha512.ToBeSignedHash, NULL);
CopyMem (&X509Sha512.TimeOfRevocation, Time, sizeof(EFI_TIME));
X509Hash = (UINT8 *)&X509Sha512;
X509HashSize = sizeof(X509Sha512);
break;
default:
assert (FALSE);
md = NULL;
X509Hash = NULL;
X509HashSize = 0;
break;
}
// Allocate space for PK certificate list and initialize it.
// Create PK database entry w/ SignatureHeaderSize equals 0.
//
*Cert = (EFI_SIGNATURE_LIST*) malloc (
sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1
+ X509HashSize
);
if (*Cert == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
return EFI_OUT_OF_RESOURCES;
}
(*Cert)->SignatureListSize = (UINT32) (sizeof(EFI_SIGNATURE_LIST)
+ sizeof(EFI_SIGNATURE_DATA) - 1
+ X509HashSize);
(*Cert)->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509HashSize);
(*Cert)->SignatureHeaderSize = 0;
switch (HashAlg) {
case HASHALG_SHA256:
CopyMem (&(*Cert)->SignatureType, &gEfiCertX509Sha256Guid, sizeof(EFI_GUID));
break;
case HASHALG_SHA384:
CopyMem (&(*Cert)->SignatureType, &gEfiCertX509Sha384Guid, sizeof(EFI_GUID));
break;
case HASHALG_SHA512:
CopyMem (&(*Cert)->SignatureType, &gEfiCertX509Sha512Guid, sizeof(EFI_GUID));
break;
}
CertData = (EFI_SIGNATURE_DATA*) ((UINTN)(*Cert)
+ sizeof(EFI_SIGNATURE_LIST)
+ (*Cert)->SignatureHeaderSize);
CopyMem (&CertData->SignatureOwner, SignatureOwner, sizeof(EFI_GUID));
CopyMem ((VOID*)&(CertData->SignatureData[0]), X509Hash, X509HashSize);
free (X509Data);
return EFI_SUCCESS;
}
EFI_STATUS
EnrollPlatformKey (
IN CHAR8 *PkFile,
IN EFI_GUID *SignatureOwner
)
{
EFI_STATUS EfiStatus;
EFI_SIGNATURE_LIST *PkCert;
EfiStatus = CreatePkX509CertificateList (
PkFile,
SignatureOwner,
&PkCert
);
if (EFI_ERROR (EfiStatus)) {
printf ("EnrollPlatformKey - CreatePkX509CertificateList fail!\n");
return EfiStatus;
}
EfiStatus = CreateVariableList (
&mVarListEntry,
EFI_PLATFORM_KEY_NAME,
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
NULL,
PkCert->SignatureListSize,
(UINT8 *)PkCert,
FALSE
);
if (!EFI_ERROR (EfiStatus)) {
printf ("EnrollPlatformKey - success!\n");
} else {
printf ("EnrollPlatformKey - fail!\n");
return EfiStatus;
}
return EfiStatus;
}
EFI_STATUS
DeletePlatformKey (
VOID
)
{
EFI_STATUS EfiStatus;
EfiStatus = DeleteVariableList (
&mVarListEntry,
EFI_PLATFORM_KEY_NAME,
&gEfiGlobalVariableGuid
);
if (EFI_ERROR (EfiStatus)) {
printf ("DeletePlatformKey - not found!\n");
return EfiStatus;
}
printf ("DeletePlatformKey - success!\n");
return EfiStatus;
}
EFI_STATUS
EnrollKeyExchangeKey (
IN CHAR8 *PkFile,
IN EFI_GUID *SignatureOwner,
IN BOOLEAN Append,
IN BOOLEAN IsCertFile
)
{
EFI_STATUS EfiStatus;
EFI_SIGNATURE_LIST *KekCert;
if (IsCertFile) {
EfiStatus = CreatePkX509CertificateList (
PkFile,
SignatureOwner,
&KekCert
);
if (EFI_ERROR (EfiStatus)) {
printf ("EnrollKeyExchangeKey - CreatePkX509CertificateList fail!\n");
return EfiStatus;
}
} else {
EfiStatus = CreatePkCertificateList (
PkFile,
SignatureOwner,
&KekCert
);
if (EFI_ERROR (EfiStatus)) {
printf ("EnrollKeyExchangeKey - CreatePkCertificateList fail!\n");
return EfiStatus;
}
}
EfiStatus = CreateVariableList (
&mVarListEntry,
EFI_KEY_EXCHANGE_KEY_NAME,
&gEfiGlobalVariableGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
NULL,
KekCert->SignatureListSize,
(UINT8 *)KekCert,
Append
);
if (!EFI_ERROR (EfiStatus)) {
printf ("EnrollKeyExchangeKey - success!\n");
} else {
printf ("EnrollKeyExchangeKey - fail!\n");
}
return EFI_SUCCESS;
}
EFI_STATUS
DeleteKeyExchangeKey (
VOID
)
{
EFI_STATUS EfiStatus;
EfiStatus = DeleteVariableList (
&mVarListEntry,
EFI_KEY_EXCHANGE_KEY_NAME,
&gEfiGlobalVariableGuid
);
if (EFI_ERROR (EfiStatus)) {
printf ("DeleteKeyExchangeKey - not found!\n");
return EfiStatus;
}
printf ("DeleteKeyExchangeKey - success!\n");
return EfiStatus;
}
EFI_STATUS
EnrollSignatureDBHash (
IN CHAR8 *PkFile,
IN EFI_GUID *SignatureOwner,
IN BOOLEAN Append,
IN UINT8 DbIndex,
IN UINT32 HashAlg,
IN EFI_TIME *Time
)
{
EFI_STATUS EfiStatus;
EFI_SIGNATURE_LIST *DbCert;
CHAR16 *Name;
EfiStatus = CreatePkX509CertificateListHash (
PkFile,
SignatureOwner,
HashAlg,
Time,
&DbCert
);
if (EFI_ERROR (EfiStatus)) {
printf ("EnrollSignatureDBHash - CreatePkX509CertificateListHash fail!\n");
return EfiStatus;
}
switch (DbIndex) {
case 0:
Name = EFI_IMAGE_SECURITY_DATABASE;
break;
case 1:
Name = EFI_IMAGE_SECURITY_DATABASE1;
break;
case 2:
Name = EFI_IMAGE_SECURITY_DATABASE2;
break;
default:
Name = NULL;
assert(FALSE);
break;
}
ASSERT (Name != NULL);
EfiStatus = CreateVariableList (
&mVarListEntry,
Name,
&gEfiImageSecurityDatabaseGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
NULL,
DbCert->SignatureListSize,
(UINT8 *)DbCert,
Append
);
if (!EFI_ERROR (EfiStatus)) {
printf ("EnrollSignatureDBHash - success!\n");
} else {
printf ("EnrollSignatureDBHash - fail!\n");
}
return EFI_SUCCESS;
}
EFI_STATUS
EnrollSignatureDB (
IN CHAR8 *PkFile,
IN EFI_GUID *SignatureOwner,
IN BOOLEAN Append,
IN UINT8 DbIndex,
IN BOOLEAN IsCertFile
)
{
EFI_STATUS EfiStatus;
EFI_SIGNATURE_LIST *DbCert;
CHAR16 *Name;
if (IsCertFile) {
EfiStatus = CreatePkX509CertificateList (
PkFile,
SignatureOwner,
&DbCert
);
if (EFI_ERROR (EfiStatus)) {
printf ("EnrollSignatureDB - CreatePkX509CertificateList fail!\n");
return EfiStatus;
}
} else {
EfiStatus = CreateImageCertificateList (
PkFile,
SignatureOwner,
&DbCert
);
if (EFI_ERROR (EfiStatus)) {
printf ("EnrollSignatureDB - CreateImageCertificateList fail!\n");
return EfiStatus;
}
}
switch (DbIndex) {
case 0:
Name = EFI_IMAGE_SECURITY_DATABASE;
break;
case 1:
Name = EFI_IMAGE_SECURITY_DATABASE1;
break;
case 2:
Name = EFI_IMAGE_SECURITY_DATABASE2;
break;
default:
Name = NULL;
assert(FALSE);
break;
}
ASSERT (Name != NULL);
EfiStatus = CreateVariableList (
&mVarListEntry,
Name,
&gEfiImageSecurityDatabaseGuid,
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
NULL,
DbCert->SignatureListSize,
(UINT8 *)DbCert,
Append
);
if (!EFI_ERROR (EfiStatus)) {
printf ("EnrollSignatureDB - success!\n");
} else {
printf ("EnrollSignatureDB - fail!\n");
}
return EFI_SUCCESS;
}
EFI_STATUS
DeleteSignatureDB (
IN UINT8 DbIndex
)
{
CHAR16 *Name;
EFI_STATUS EfiStatus;
switch (DbIndex) {
case 0:
Name = EFI_IMAGE_SECURITY_DATABASE;
break;
case 1:
Name = EFI_IMAGE_SECURITY_DATABASE1;
break;
case 2:
Name = EFI_IMAGE_SECURITY_DATABASE2;
break;
default:
Name = NULL;
assert(FALSE);
break;
}
ASSERT (Name != NULL);
EfiStatus = DeleteVariableList (
&mVarListEntry,
Name,
&gEfiImageSecurityDatabaseGuid
);
if (EFI_ERROR (EfiStatus)) {
printf ("DeleteSignatureDB - not found!\n");
return EfiStatus;
}
printf ("DeleteSignatureDB - success!\n");
return EfiStatus;
}
STATUS
ProcessPk (
IN INTN argc,
IN CHAR8 **argv
)
{
EFI_GUID Guid;
if ((strcmp (argv[4], "ADD") == 0) ||
(strcmp (argv[4], "add") == 0)) {
if ((argc != 7) && (argc != 9)) {
Error (NULL, 0, 0, "PK ADD: invalid number of input parameters specified", NULL);
return STATUS_ERROR;
}
if ((strcmp (argv[5], "-F") != 0) &&
(strcmp (argv[5], "-f") != 0)) {
Error (NULL, 0, 0, "PK ADD: -F is not specified", NULL);
return STATUS_ERROR;
}
if (argc == 9) {
if ((strcmp (argv[7], "-G") != 0) &&
(strcmp (argv[7], "-g") != 0)) {
Error (NULL, 0, 0, "PK ADD: -G is not specified", NULL);
return STATUS_ERROR;
}
if (!IsGuidData (argv[8], &Guid)) {
Error (NULL, 0, 0, "PK ADD: Unknown Guid - ", argv[8]);
return STATUS_ERROR;
}
} else {
CopyMem (&Guid, &gEfiGlobalVariableGuid, sizeof(Guid));
}
return EnrollPlatformKey (argv[6], &Guid);
} else if ((strcmp (argv[4], "DEL") == 0) ||
(strcmp (argv[4], "del") == 0)) {
if (argc != 5) {
Error (NULL, 0, 0, "PK DEL: invalid number of input parameters specified", NULL);
return STATUS_ERROR;
}
return DeletePlatformKey ();
}
Error (NULL, 0, 0, "PK: Unknown SubCommand - ", argv[4]);
return STATUS_ERROR;
}
STATUS
ProcessKek (
IN INTN argc,
IN CHAR8 **argv
)
{
EFI_GUID Guid;
BOOLEAN Append;
BOOLEAN IsCertFile;
if ((strcmp (argv[4], "ADD") == 0) ||
(strcmp (argv[4], "add") == 0) ||
(strcmp (argv[4], "APPEND") == 0) ||
(strcmp (argv[4], "append") == 0)) {
if (argc != 9) {
Error (NULL, 0, 0, "KEK ADD|APPEND: invalid number of input parameters specified", NULL);
return STATUS_ERROR;
}
if ((strcmp (argv[5], "-F") != 0) &&
(strcmp (argv[5], "-f") != 0) &&
(strcmp (argv[5], "-K") != 0) &&
(strcmp (argv[5], "-k") != 0)) {
Error (NULL, 0, 0, "KEK ADD|APPEND: -F|-K is not specified", NULL);
return STATUS_ERROR;
}
if ((strcmp (argv[7], "-G") != 0) &&
(strcmp (argv[7], "-g") != 0)) {
Error (NULL, 0, 0, "KEK ADD|APPEND: -G is not specified", NULL);
return STATUS_ERROR;
}
if (!IsGuidData (argv[8], &Guid)) {
Error (NULL, 0, 0, "KEK ADD|APPEND: Unknown Guid - ", argv[8]);
return STATUS_ERROR;
}
if ((strcmp (argv[4], "APPEND") == 0) ||
(strcmp (argv[4], "append") == 0)) {
Append = TRUE;
} else {
Append = FALSE;
}
if ((strcmp (argv[5], "-F") == 0) ||
(strcmp (argv[5], "-f") == 0)) {
IsCertFile = TRUE;
} else {
IsCertFile = FALSE;
}
return EnrollKeyExchangeKey (argv[6], &Guid, Append, IsCertFile);
} else if ((strcmp (argv[4], "DEL") == 0) ||
(strcmp (argv[4], "del") == 0)) {
if (argc != 5) {
Error (NULL, 0, 0, "KEK DEL: invalid number of input parameters specified", NULL);
return STATUS_ERROR;
}
return DeleteKeyExchangeKey ();
}
Error (NULL, 0, 0, "KEK: Unknown SubCommand - ", argv[4]);
return STATUS_ERROR;
}
STATUS
ProcessDb (
IN INTN argc,
IN CHAR8 **argv,
IN UINT8 DbIndex
)
{
EFI_GUID Guid;
BOOLEAN Append;
BOOLEAN IsCertFile;
UINT32 HashAlg;
EFI_TIME Time;
if ((strcmp (argv[4], "ADD") == 0) ||
(strcmp (argv[4], "add") == 0) ||
(strcmp (argv[4], "APPEND") == 0) ||
(strcmp (argv[4], "append") == 0)) {
if (argc < 9) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: invalid number of input parameters specified", NULL);
return STATUS_ERROR;
}
if ((strcmp (argv[5], "-F") != 0) &&
(strcmp (argv[5], "-f") != 0) &&
(strcmp (argv[5], "-I") != 0) &&
(strcmp (argv[5], "-i") != 0)) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: -F|-I is not specified", NULL);
return STATUS_ERROR;
}
if ((strcmp (argv[7], "-G") != 0) &&
(strcmp (argv[7], "-g") != 0)) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: -G is not specified", NULL);
return STATUS_ERROR;
}
if (!IsGuidData (argv[8], &Guid)) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: Unknown Guid - ", argv[8]);
return STATUS_ERROR;
}
if ((strcmp (argv[4], "APPEND") == 0) ||
(strcmp (argv[4], "append") == 0)) {
Append = TRUE;
} else {
Append = FALSE;
}
if ((strcmp (argv[5], "-F") == 0) ||
(strcmp (argv[5], "-f") == 0)) {
IsCertFile = TRUE;
} else {
IsCertFile = FALSE;
}
if (argc == 9) {
return EnrollSignatureDB (argv[6], &Guid, Append, DbIndex, IsCertFile);
}
//
// Hash
//
if (argc < 11) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: invalid number of paramter for cert hash", NULL);
}
if ((strcmp (argv[9], "-H") != 0) &&
(strcmp (argv[9], "-h") != 0)) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: -H is not specified", NULL);
return STATUS_ERROR;
}
HashAlg = HASHALG_MAX;
if ((strcmp (argv[10], "SHA256") == 0) ||
(strcmp (argv[10], "sha256") == 0) ) {
HashAlg = HASHALG_SHA256;
} else if ((strcmp (argv[10], "SHA384") == 0) ||
(strcmp (argv[10], "sha384") == 0) ) {
HashAlg = HASHALG_SHA384;
} else if ((strcmp (argv[10], "SHA512") == 0) ||
(strcmp (argv[10], "sha512") == 0) ) {
HashAlg = HASHALG_SHA512;
}
if (HashAlg == HASHALG_MAX) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: Unknown Hash Algorithm", NULL);
return STATUS_ERROR;
}
ZeroMem (&Time, sizeof(EFI_TIME));
if (argc != 11) {
if (argc != 15) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: invalid number of paramter for cert time", NULL);
return STATUS_ERROR;
}
if ((strcmp (argv[11], "-DATE") != 0) &&
(strcmp (argv[11], "-date") != 0)) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: -DATE is not specified", NULL);
return STATUS_ERROR;
}
if (!IsDateData (argv[12], &Time)) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: Unknown Date - ", argv[12]);
return STATUS_ERROR;
}
if ((strcmp (argv[13], "-TIME") != 0) &&
(strcmp (argv[13], "-time") != 0)) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: -TIME is not specified", NULL);
return STATUS_ERROR;
}
if (!IsTimeData (argv[14], &Time)) {
Error (NULL, 0, 0, "db|dbx|dbt ADD|APPEND: Unknown Time - ", argv[14]);
return STATUS_ERROR;
}
}
return EnrollSignatureDBHash (argv[6], &Guid, Append, DbIndex, HashAlg, &Time);
} else if ((strcmp (argv[4], "DEL") == 0) ||
(strcmp (argv[4], "del") == 0)) {
if (argc != 5) {
Error (NULL, 0, 0, "db|dbx|dbt DEL: invalid number of input parameters specified", NULL);
return STATUS_ERROR;
}
return DeleteSignatureDB (DbIndex);
}
Error (NULL, 0, 0, "db|dbx|dbt: Unknown SubCommand - ", argv[4]);
return STATUS_ERROR;
}
EFI_STATUS
EnrollVar (
IN CHAR8 *Name,
IN EFI_GUID *Guid,
IN UINT32 Attributes,
IN UINTN DataSize,
IN VOID *Data,
IN BOOLEAN TimeBased,
IN BOOLEAN Append
)
{
EFI_STATUS EfiStatus;
CHAR16 *UnicodeBuf;
UINT8 *Payload;
UINTN PayloadSize;
EFI_TIME *TimeStamp;
UnicodeBuf = malloc ((strlen(Name) + 1) * sizeof(CHAR16));
if (UnicodeBuf == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory for variable name", NULL);
return EFI_OUT_OF_RESOURCES;
}
Ascii2UnicodeString (Name, UnicodeBuf);
TimeStamp = NULL;
Payload = (UINT8 *) Data;
PayloadSize = DataSize;
if (TimeBased) {
TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;
Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
}
EfiStatus = CreateVariableList (
&mVarListEntry,
UnicodeBuf,
Guid,
Attributes,
TimeStamp,
PayloadSize,
Payload,
Append
);
if (!EFI_ERROR (EfiStatus)) {
printf ("EnrollVar - success!\n");
} else {
printf ("EnrollVar - fail!\n");
}
free (UnicodeBuf);
return EfiStatus;
}
EFI_STATUS
DeleteVar (
IN CHAR8 *Name,
IN EFI_GUID *Guid
)
{
EFI_STATUS EfiStatus;
CHAR16 *UnicodeBuf;
UnicodeBuf = malloc ((strlen(Name) + 1) * sizeof(CHAR16));
if (UnicodeBuf == NULL) {
Error (NULL, 0, 0, "Unable to allocate memory", NULL);
return EFI_OUT_OF_RESOURCES;
}
Ascii2UnicodeString (Name, UnicodeBuf);
EfiStatus = DeleteVariableList (
&mVarListEntry,
UnicodeBuf,
Guid
);
if (EFI_ERROR (EfiStatus)) {
printf ("DeleteVar - not found!\n");
} else {
printf ("DeleteVar - success!\n");
}
free (UnicodeBuf);
return EfiStatus;
}
/*
This function will check and parse the command line parameter.
@param[in] argc The number of input parameters.
@param[in] argv Point to input each parameters.
@param[out] SubCmd Point to the operation type.
@retval EFI_SUCCESS All input parameters are valid.
@retval EFI_INVALID_PARAMETER The number of input parameters or
input parameters are invalid.
*/
EFI_STATUS
ParsingVariableParams (
IN INTN argc,
IN CHAR8 **argv,
OUT EFI_COMMAND_OPER_TYPE *SubCmd
)
{
CHAR8 *SubCmdPtr;
UINTN Index;
if (argc != 9 && argc != 13 && argc != 14) {
Error (NULL, 0, 0, "VAR: invalid number of input parameters specified", NULL);
return EFI_INVALID_PARAMETER;
}
if (argv == NULL || SubCmd == NULL) {
return EFI_INVALID_PARAMETER;
}
SubCmdPtr = malloc (strlen (argv[4]) + 1);
if (SubCmdPtr == NULL) {
return EFI_OUT_OF_RESOURCES;
}
memset (SubCmdPtr, 0, strlen (argv[4]) + 1);
memcpy (SubCmdPtr, argv[4], strlen (argv[4]) + 1);
for (Index = 0; Index < strlen (argv[4]) + 1; Index = Index + 1) {
//
// Convert lower letter to upper one.
//
if ((SubCmdPtr[Index] >= 'a') && (SubCmdPtr[Index] <= 'z')) {
SubCmdPtr[Index] -= 32;
}
}
if (strcmp (SubCmdPtr, "ADD") == 0) {
*SubCmd = VariableTypeAdd;
} else if (strcmp (SubCmdPtr, "DEL") == 0) {
*SubCmd = VariableTypeDel;
} else if (strcmp (SubCmdPtr, "APPEND") == 0) {
*SubCmd = VariableTypeAppend;
} else {
Error (NULL, 0, 0, "VAR: Unknown SubCommand - ", argv[4]);
return EFI_INVALID_PARAMETER;
}
if ( (strcmp (argv[5], "-N") != 0) &&
(strcmp (argv[5], "-n") != 0)
) {
Error (NULL, 0, 0, "VAR: -N is not specified", NULL);
return EFI_INVALID_PARAMETER;
}
if ( (strcmp (argv[7], "-G") != 0) &&
(strcmp (argv[7], "-g") != 0)
) {
Error (NULL, 0, 0, "VAR: -G is not specified", NULL);
return EFI_INVALID_PARAMETER;
}
if (argc >= 13) {
if ( (strcmp (argv[9], "-A") != 0) &&
(strcmp (argv[9], "-a") != 0)
) {
Error (NULL, 0, 0, "VAR: -A is not specified", NULL);
return EFI_INVALID_PARAMETER;
}
if ( (strcmp (argv[11], "-D") != 0) &&
(strcmp (argv[11], "-d") != 0)
) {
Error (NULL, 0, 0, "VAR: -D is not specified", NULL);
return EFI_INVALID_PARAMETER;
}
}
if (argc == 14) {
if ( (strcmp (argv[13], "-T") != 0) &&
(strcmp (argv[13], "-t") != 0)
) {
Error (NULL, 0, 0, "VAR: -T is not specified", NULL);
return EFI_INVALID_PARAMETER;
}
}
return EFI_SUCCESS;
}
STATUS
ProcessVar (
IN INTN argc,
IN CHAR8 **argv
)
{
EFI_STATUS VerifyStatus;
EFI_COMMAND_OPER_TYPE CommandType;
EFI_GUID Guid;
UINT8 *Data;
UINTN DataSize;
STATUS Status;
UINT32 Attributes;
BOOLEAN TimeBased;
Attributes = 0;
Data = NULL;
DataSize = 0;
VerifyStatus = ParsingVariableParams (argc, argv, &CommandType);
if (EFI_ERROR (VerifyStatus)) {
return VerifyStatus;
}
//
// Make "certdb" variable as private variable.
//
if (strcmp(argv[6], "certdb") == 0) {
Error (NULL, 0, 0, "Invalid variable name.", NULL);
return STATUS_ERROR;
}
if (!IsGuidData (argv[8], &Guid)) {
Error (NULL, 0, 0, "Unknown Guid - ", argv[8]);
return STATUS_ERROR;
}
if (argc >= 13) {
Attributes = xtoi (argv[10]);
Status = ReadInputFile (argv[12], &Data, (UINT32 *) &DataSize, NULL);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Can not get data - ", argv[12]);
return STATUS_ERROR;
}
}
TimeBased = (argc == 14) ? TRUE : FALSE;
if ( ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
!TimeBased
) {
Error (NULL, 0, 0, "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set is not matching -T flag.", NULL);
return STATUS_ERROR;
}
if ( ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) &&
TimeBased
) {
Error (NULL, 0, 0, "EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set is not matching -T flag.", NULL);
return STATUS_ERROR;
}
//
// Non-timebased or "db","dbx","dbt","PK","KEY" variable will use previous logic to handling.
//
if ( strcmp(argv[6], "db") == 0 ||
strcmp(argv[6], "dbx") == 0 ||
strcmp(argv[6], "dbt") == 0 ||
strcmp(argv[6], "PK") == 0 ||
strcmp(argv[6], "KEY") == 0 ||
!TimeBased
) {
if (CommandType == VariableTypeDel) {
Status = DeleteVar (argv[6], &Guid);
} else {
Status = EnrollVar (
argv[6],
&Guid,
Attributes,
DataSize,
Data,
TimeBased,
CommandType == VariableTypeAppend ? TRUE : FALSE
);
}
} else {
Status = ProcessAuthVar (
argv[6],
&Guid,
Data,
DataSize,
Attributes,
CommandType
);
}
FREE_NON_NULL_PTR (Data);
return Status;
}
VOID
DumpTimestamp (
IN EFI_TIME *TimeOfRevocation
)
{
printf (" %02d/%02d/%04d %02d:%02d:%02d\n",
TimeOfRevocation->Month,
TimeOfRevocation->Day,
TimeOfRevocation->Year,
TimeOfRevocation->Hour,
TimeOfRevocation->Minute,
TimeOfRevocation->Second
);
}
VOID
DumpCert (
IN UINT8 *Buffer,
IN UINTN Size
)
{
EFI_SIGNATURE_LIST *CertList;
EFI_SIGNATURE_DATA *Cert;
UINT32 CertCount;
UINT32 CertListIndex;
UINT32 CertIndex;
CertListIndex = 0;
CertList = (EFI_SIGNATURE_LIST *)Buffer;
while ((UINTN)CertList < (UINTN)Buffer + Size) {
printf ("SIGNATURE_LIST[%d]\n", CertListIndex);
printf (" SignatureType - %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
CertList->SignatureType.Data1,
CertList->SignatureType.Data2,
CertList->SignatureType.Data3,
CertList->SignatureType.Data4[0],
CertList->SignatureType.Data4[1],
CertList->SignatureType.Data4[2],
CertList->SignatureType.Data4[3],
CertList->SignatureType.Data4[4],
CertList->SignatureType.Data4[5],
CertList->SignatureType.Data4[6],
CertList->SignatureType.Data4[7]
);
printf (" SignatureListSize - %08x\n", CertList->SignatureListSize);
printf (" SignatureHeaderSize - %08x\n", CertList->SignatureHeaderSize);
printf (" SignatureSize - %08x\n", CertList->SignatureSize);
Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
CertCount = (CertList->SignatureListSize - sizeof(EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
for (CertIndex = 0; CertIndex < CertCount; CertIndex++) {
printf (" SIGNATURE_DATA[%d]\n", CertIndex);
printf (" SignatureOwner - %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
Cert->SignatureOwner.Data1,
Cert->SignatureOwner.Data2,
Cert->SignatureOwner.Data3,
Cert->SignatureOwner.Data4[0],
Cert->SignatureOwner.Data4[1],
Cert->SignatureOwner.Data4[2],
Cert->SignatureOwner.Data4[3],
Cert->SignatureOwner.Data4[4],
Cert->SignatureOwner.Data4[5],
Cert->SignatureOwner.Data4[6],
Cert->SignatureOwner.Data4[7]
);
printf (" Signature - \n");
if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid) == 0) {
EFI_CERT_X509_SHA256 *CertX509Sha256;
CertX509Sha256 = (EFI_CERT_X509_SHA256 *)Cert->SignatureData;
printf (" SHA256 - \n");
DumpHex (CertX509Sha256->ToBeSignedHash, sizeof(CertX509Sha256->ToBeSignedHash));
printf (" Timestamp - \n");
DumpTimestamp (&CertX509Sha256->TimeOfRevocation);
} else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid) == 0) {
EFI_CERT_X509_SHA384 *CertX509Sha384;
CertX509Sha384 = (EFI_CERT_X509_SHA384 *)Cert->SignatureData;
printf (" SHA384 - \n");
DumpHex (CertX509Sha384->ToBeSignedHash, sizeof(CertX509Sha384->ToBeSignedHash));
printf (" Timestamp - \n");
DumpTimestamp (&CertX509Sha384->TimeOfRevocation);
} else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid) == 0) {
EFI_CERT_X509_SHA512 *CertX509Sha512;
CertX509Sha512 = (EFI_CERT_X509_SHA512 *)Cert->SignatureData;
printf (" SHA512 - \n");
DumpHex (CertX509Sha512->ToBeSignedHash, sizeof(CertX509Sha512->ToBeSignedHash));
printf (" Timestamp - \n");
DumpTimestamp (&CertX509Sha512->TimeOfRevocation);
} else {
DumpHex (Cert->SignatureData, CertList->SignatureSize - (sizeof(EFI_SIGNATURE_DATA) - 1));
}
Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + CertList->SignatureSize);
}
CertList = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);
CertListIndex ++;
}
}
VOID
DumpVarStorage (
IN VARIABLE_INFO_PRIVATE *Storage,
IN BOOLEAN IsDumpCert
)
{
printf ("Variable:\n");
printf (" Name - %S\n", (wchar_t*)Storage->Name);
printf (" Guid - %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
Storage->Guid.Data1,
Storage->Guid.Data2,
Storage->Guid.Data3,
Storage->Guid.Data4[0],
Storage->Guid.Data4[1],
Storage->Guid.Data4[2],
Storage->Guid.Data4[3],
Storage->Guid.Data4[4],
Storage->Guid.Data4[5],
Storage->Guid.Data4[6],
Storage->Guid.Data4[7]
);
printf (" Attributes - %08x\n", Storage->Attributes);
printf (" Size - %08x\n", (UINT32) Storage->Size);
printf (" Buffer - \n");
if (IsDumpCert) {
DumpCert (Storage->Buffer, Storage->Size);
} else {
DumpHex (Storage->Buffer, Storage->Size);
}
printf ("\n");
}
VOID
DumpInfo (
IN CHAR16 *Name,
IN EFI_GUID *Guid
)
{
LIST_ENTRY *Link;
VARIABLE_INFO_PRIVATE *Storage;
Link = FindVariableList (
&mVarListEntry,
Name,
Guid
);
if (Link == NULL) {
printf ("DumpInfo - not found!\n");
return ;
}
Storage = VARIABLE_INFO_PRIVATE_FROM_LINK (Link);
DumpVarStorage (Storage, TRUE);
return ;
}
VOID
DumpVariableList (
IN LIST_ENTRY *StorageListHead
)
{
LIST_ENTRY *Link;
VARIABLE_INFO_PRIVATE *Storage;
if (StorageListHead->ForwardLink != NULL) {
Link = GetFirstNode (StorageListHead);
while (!IsNull (StorageListHead, Link)) {
Storage = VARIABLE_INFO_PRIVATE_FROM_LINK (Link);
DumpVarStorage (Storage, FALSE);
Link = GetNextNode (StorageListHead, Link);
}
}
}
STATUS
ProcessInfo (
IN INTN argc,
IN CHAR8 **argv
)
{
if ((argc == 4) &&
((strcmp (argv[3], "PK") == 0) ||
(strcmp (argv[3], "pk") == 0))) {
DumpInfo (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid);
return STATUS_SUCCESS;
}
else if ((argc == 4) &&
((strcmp (argv[3], "KEK") == 0) ||
(strcmp (argv[3], "kek") == 0))) {
DumpInfo (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid);
return STATUS_SUCCESS;
}
else if ((argc == 4) &&
((strcmp (argv[3], "DB") == 0) ||
(strcmp (argv[3], "db") == 0))) {
DumpInfo (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid);
return STATUS_SUCCESS;
}
else if ((argc == 4) &&
((strcmp (argv[3], "DBX") == 0) ||
(strcmp (argv[3], "dbx") == 0))) {
DumpInfo (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid);
return STATUS_SUCCESS;
}
else if ((argc == 4) &&
((strcmp (argv[3], "DBT") == 0) ||
(strcmp (argv[3], "dbt") == 0))) {
DumpInfo (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid);
return STATUS_SUCCESS;
}
else if ((argc == 4) &&
((strcmp (argv[3], "ALL") == 0) ||
(strcmp (argv[3], "all") == 0))) {
DumpVariableList (&mVarListEntry);
return STATUS_SUCCESS;
}
Error (NULL, 0, 0, "INFO: Unknown SubCommand - ", argv[3]);
return STATUS_ERROR;
}
STATUS
ProcessKey (
IN INTN argc,
IN CHAR8 **argv
)
{
if ((strcmp (argv[2], "INFO") == 0) ||
(strcmp (argv[2], "info") == 0)) {
return ProcessInfo (argc, argv);
}
if ((strcmp (argv[3], "VAR") == 0) ||
(strcmp (argv[3], "var") == 0)) {
return ProcessVar (argc, argv);
}
else if ((strcmp (argv[3], "PK") == 0) ||
(strcmp (argv[3], "pk") == 0)) {
return ProcessPk (argc, argv);
}
else if ((strcmp (argv[3], "KEK") == 0) ||
(strcmp (argv[3], "kek") == 0)) {
return ProcessKek (argc, argv);
}
else if ((strcmp (argv[3], "DB") == 0) ||
(strcmp (argv[3], "db") == 0)) {
return ProcessDb (argc, argv, 0);
}
else if ((strcmp (argv[3], "DBX") == 0) ||
(strcmp (argv[3], "dbx") == 0)) {
return ProcessDb (argc, argv, 1);
}
else if ((strcmp (argv[3], "DBT") == 0) ||
(strcmp (argv[3], "dbt") == 0)) {
return ProcessDb (argc, argv, 2);
}
Error (NULL, 0, 0, "KeyEnroll: Unknown Command - ", argv[3]);
return STATUS_ERROR;
}
STATUS
KeyEnroll (
IN INTN argc,
IN CHAR8 **argv
)
/*++
Routine Description:
Main function for KeyEnroll.
Arguments:
argc - Number of command line parameters.
argv - Array of pointers to parameter strings.
Returns:
STATUS_SUCCESS - Utility exits successfully.
STATUS_ERROR - Some error occurred during execution.
--*/
{
UINT32 VariableFvFileSize;
UINT8 *VariableFvFileBuffer;
STATUS Status;
UINT8 *FdFileBuffer;
UINT32 FdFileSize;
EFI_FIRMWARE_VOLUME_HEADER *VarAddr;
VOID *VariableStoreHeader;
VARIABLE_TYPE VariableType;
//
// Step 1: Read InputFvRecovery.fv data
//
Status = ReadInputFile (argv[1], &FdFileBuffer, &FdFileSize, NULL);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Unable to open file", "%s", argv[1]);
return Status;
}
//
// Get Variable information
//
VariableFvFileSize = GetVariableInfoFromFd (FdFileBuffer, FdFileSize, &VariableFvFileBuffer);
if ((VariableFvFileSize == 0) || (VariableFvFileBuffer == NULL)) {
Error (NULL, 0, 0, "Variable FV not found in Fd file!", NULL);
free ((VOID *)FdFileBuffer);
return STATUS_ERROR;
}
gEfiFdInfo.EfiVariableAddr = (UINTN)VariableFvFileBuffer;
VarAddr = (EFI_FIRMWARE_VOLUME_HEADER *) gEfiFdInfo.EfiVariableAddr;
VariableStoreHeader = (VOID *)((UINT8 *)VarAddr + VarAddr->HeaderLength);
VariableType = CheckVarStore (VariableStoreHeader);
switch (VariableType) {
case VariableTypeTimeBasedAuth:
printf ("VaraibleFv: Time-Based AuthVariable\n");
break;
case VariableTypeCountBasedAuth:
printf ("VaraibleFv: Monotonic-Based AuthVariable - unsupported\n");
return STATUS_ERROR;
break;
case VariableTypeNormal:
printf ("VaraibleFv: Normal Variable - unsupported\n");
return STATUS_ERROR;
break;
default:
printf ("VaraibleFv: Unknown - unsupported\n");
return STATUS_ERROR;
}
InitializeListHead (&mVarListEntry);
Status = EfiVarAndListExchange (TRUE, &mVarListEntry);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "EfiVarAndListExchange (VarToList) Error!", NULL);
return Status;
}
//
// Construct Key
//
Status = ProcessKey (argc, argv);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "ProcessKey fail!", NULL);
free ((VOID *)FdFileBuffer);
return STATUS_ERROR;
}
if ((strcmp (argv[2], "INFO") == 0) ||
(strcmp (argv[2], "info") == 0)) {
return STATUS_SUCCESS;
}
Status = EfiVarAndListExchange (FALSE, &mVarListEntry);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "EfiVarAndListExchange (ListToVar) Error!", NULL);
return Status;
}
DestroyAllStorage (&mVarListEntry);
//
// Step 5: Write OutputFvRecovery.fv data
//
Status = WriteOutputFile (argv[2], FdFileBuffer, FdFileSize);
free ((VOID *)FdFileBuffer);
if (Status != STATUS_SUCCESS) {
Error (NULL, 0, 0, "Unable to write file", "%s", argv[2]);
return Status;
}
printf ("Write Variable Successfully!\n");
return Status;
}
int
main (
int argc,
char **argv
)
/*++
Routine Description:
Main function.
Arguments:
argc - Number of command line parameters.
argv - Array of pointers to parameter strings.
Returns:
STATUS_SUCCESS - Utility exits successfully.
STATUS_ERROR - Some error occurred during execution.
--*/
{
SetUtilityName (UTILITY_NAME);
mIgnoreTimeStamp = 0;
//
// Display utility information
//
PrintUtilityInfo ();
//
// Verify the correct number of arguments
//
if (argc >= MIN_ARGS) {
if (strcmp(argv[argc-1],"-nt") == 0){
argc -= 1;
mIgnoreTimeStamp = 1;
}
return KeyEnroll (argc, argv);
} else {
Error (NULL, 0, 0, "invalid number of input parameters specified", NULL);
PrintUsage ();
return STATUS_ERROR;
}
}
unsigned int
xtoi (
char *str
)
/*++
Routine Description:
Convert hex string to uint
Arguments:
Str - The string
Returns:
--*/
{
unsigned int u;
char c;
unsigned int m;
if (str == NULL) {
return 0;
}
m = (unsigned int) -1 >> 4;
//
// skip preceeding white space
//
while (*str && *str == ' ') {
str += 1;
}
//
// skip preceeding zeros
//
while (*str && *str == '0') {
str += 1;
}
//
// skip preceeding white space
//
if (*str && (*str == 'x' || *str == 'X')) {
str += 1;
}
//
// convert hex digits
//
u = 0;
c = *(str++);
while (c) {
if (c >= 'a' && c <= 'f') {
c -= 'a' - 'A';
}
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
if (u > m) {
return (unsigned int) -1;
}
u = (u << 4) | (c - (c >= 'A' ? 'A' - 10 : '0'));
} else {
//
// Let aplication exit immediately
//
Error (NULL, 0, 0, "Hex value is expected!", NULL);
exit (0);
break;
}
c = *(str++);
}
return u;
}
INTN
KeyEnrollStrCmp (
IN CONST CHAR16 *FirstString,
IN CONST CHAR16 *SecondString
)
{
while ((*FirstString != L'\0') && (*FirstString == *SecondString)) {
FirstString++;
SecondString++;
}
return *FirstString - *SecondString;
}
UINTN
KeyEnrollStrLen (
IN CONST CHAR16 *String
)
{
UINTN Length;
if (String == NULL) {
return 0;
}
for (Length = 0; *String != L'\0'; String++, Length++) {
;
}
return Length;
}
UINTN
KeyEnrollStrSize (
IN CONST CHAR16 *String
)
{
return (KeyEnrollStrLen (String) + 1) * sizeof(CHAR16);
}
INTN
CompareMem (
IN CONST VOID *DestinationBuffer,
IN CONST VOID *SourceBuffer,
IN UINTN Length
)
{
while ((--Length != 0) &&
(*(INT8*)DestinationBuffer == *(INT8*)SourceBuffer)) {
DestinationBuffer = (INT8*)DestinationBuffer + 1;
SourceBuffer = (INT8*)SourceBuffer + 1;
}
return (INTN)*(UINT8*)DestinationBuffer - (INTN)*(UINT8*)SourceBuffer;
}
LIST_ENTRY *
EFIAPI
GetFirstNode (
IN CONST LIST_ENTRY *List
)
{
return List->ForwardLink;
}
BOOLEAN
EFIAPI
IsNull (
IN CONST LIST_ENTRY *List,
IN CONST LIST_ENTRY *Node
)
{
return (BOOLEAN)(Node == List);
}
LIST_ENTRY *
EFIAPI
GetNextNode (
IN CONST LIST_ENTRY *List,
IN CONST LIST_ENTRY *Node
)
{
return Node->ForwardLink;
}
LIST_ENTRY *
EFIAPI
InitializeListHead (
IN OUT LIST_ENTRY *ListHead
)
{
ListHead->ForwardLink = ListHead;
ListHead->BackLink = ListHead;
return ListHead;
}
LIST_ENTRY *
EFIAPI
InsertTailList (
IN OUT LIST_ENTRY *ListHead,
IN OUT LIST_ENTRY *Entry
)
{
Entry->ForwardLink = ListHead;
Entry->BackLink = ListHead->BackLink;
Entry->BackLink->ForwardLink = Entry;
ListHead->BackLink = Entry;
return ListHead;
}
LIST_ENTRY *
EFIAPI
RemoveEntryList (
IN CONST LIST_ENTRY *Entry
)
{
Entry->ForwardLink->BackLink = Entry->BackLink;
Entry->BackLink->ForwardLink = Entry->ForwardLink;
return Entry->ForwardLink;
}
BOOLEAN
EFIAPI
IsListEmpty (
IN CONST LIST_ENTRY *ListHead
)
{
return (BOOLEAN)(ListHead->ForwardLink == ListHead);
}