2782 lines
94 KiB
C
2782 lines
94 KiB
C
/** @file
|
|
Provide authentication services for the authenticated variable service
|
|
|
|
Caution: This module requires additional review when modified.
|
|
This driver will have external input - variable data and communicate buffer
|
|
in SMM mode. This external input must be validated carefully to avoid
|
|
security issues such as buffer overflow or integer overflow.
|
|
The whole SMM authentication variable design relies on the integrity of
|
|
flash part and SMM. which is assumed to be protected by platform. All
|
|
variable code and metadata in flash/SMM Memory may not be modified without
|
|
authorization. If platform fails to protect these resources, the
|
|
authentication service provided in this driver will be broken, and the
|
|
behavior is undefined.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2019, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
|
|
#include "Variable.h"
|
|
#include "AuthService.h"
|
|
#include "InsydeSecureVariable.h"
|
|
#include "VariableCache.h"
|
|
#include "VarCheck.h"
|
|
#include <KernelSetupConfig.h>
|
|
//
|
|
// Global database array for scratch
|
|
//
|
|
UINT32 mPlatformMode;
|
|
UINT32 mPlatformBootMode;
|
|
CRYPTO_SERVICES_PROTOCOL *mCryptoService = NULL;
|
|
EFI_HASH_PROTOCOL *mHash = NULL;
|
|
VOID *mSha256Hash;
|
|
|
|
EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};
|
|
//
|
|
// Public Exponent of RSA Key.
|
|
//
|
|
CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
|
|
|
|
SIGNATURE_SUPPORT_INFO mSupportSigItem[] = {
|
|
{EFI_CERT_X509_GUID, 0, FALSE, ALL_SIGNATURE_SUPPORT},
|
|
{EFI_CERT_X509_SHA256_GUID, sizeof (EFI_CERT_X509_SHA256) + sizeof (EFI_GUID), TRUE, FORBIDDEN_SIGNATURE_SUPPORT },
|
|
{EFI_CERT_X509_SHA384_GUID, sizeof (EFI_CERT_X509_SHA384) + sizeof (EFI_GUID), TRUE, FORBIDDEN_SIGNATURE_SUPPORT },
|
|
{EFI_CERT_X509_SHA512_GUID, sizeof (EFI_CERT_X509_SHA512) + sizeof (EFI_GUID), TRUE, FORBIDDEN_SIGNATURE_SUPPORT },
|
|
{EFI_CERT_SHA1_GUID, SHA1_DIGEST_SIZE + sizeof (EFI_GUID), TRUE, (AUTHORIZED_SIGNATURE_SUPPORT | FORBIDDEN_SIGNATURE_SUPPORT) },
|
|
{EFI_CERT_SHA224_GUID, 28 + sizeof (EFI_GUID), TRUE, (AUTHORIZED_SIGNATURE_SUPPORT | FORBIDDEN_SIGNATURE_SUPPORT) },
|
|
{EFI_CERT_SHA256_GUID, SHA256_DIGEST_SIZE + sizeof (EFI_GUID), TRUE, (AUTHORIZED_SIGNATURE_SUPPORT | FORBIDDEN_SIGNATURE_SUPPORT) },
|
|
{EFI_CERT_SHA384_GUID, 48 + sizeof (EFI_GUID), TRUE, (AUTHORIZED_SIGNATURE_SUPPORT | FORBIDDEN_SIGNATURE_SUPPORT) },
|
|
{EFI_CERT_SHA512_GUID, 64 + sizeof (EFI_GUID), TRUE, (AUTHORIZED_SIGNATURE_SUPPORT | FORBIDDEN_SIGNATURE_SUPPORT) }
|
|
};
|
|
|
|
/**
|
|
Internal function to delete a Variable given its name and GUID, no authentication
|
|
required.
|
|
|
|
@param[in] VariableName Name of the Variable.
|
|
@param[in] VendorGuid GUID of the Variable.
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
|
|
@retval EFI_SUCCESS Variable deleted successfully.
|
|
@return Others The driver failded to start the device.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
DeleteVariable (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
UINTN VariableCount;
|
|
|
|
|
|
Status = FindVariableByLifetime (VariableName, VendorGuid, &Variable, &VariableCount, Global);
|
|
if (EFI_ERROR (Status)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
ASSERT (Variable.CurrPtr != NULL);
|
|
return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL, Global);
|
|
}
|
|
|
|
/**
|
|
Convert all of module authenticated service relative pointers to virtual address.
|
|
**/
|
|
VOID
|
|
AuthVariableClassAddressChange (
|
|
VOID
|
|
)
|
|
{
|
|
gRT->ConvertPointer (0x0, (VOID **) &mCertDbList);
|
|
gRT->ConvertPointer (0x0, (VOID **) &mStorageArea);
|
|
gRT->ConvertPointer (0x0, (VOID **) &mSha256Hash);
|
|
gRT->ConvertPointer (0x0, (VOID **) &mCryptoService);
|
|
gRT->ConvertPointer (0x0, (VOID **) &mHash);
|
|
}
|
|
|
|
/**
|
|
This function uses to clear all of secure settings. These variable
|
|
includes PK, KEK, db, dbx.
|
|
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
|
|
@retval EFI_SUCCESS Clear secure settings successful.
|
|
--*/
|
|
EFI_STATUS
|
|
ClearSecureSettings (
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
UINTN VariableCount;
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
UINT32 VarAttr;
|
|
EFI_STATUS Status;
|
|
|
|
VariableCount = 0;
|
|
FindVariableByLifetime (
|
|
EFI_SETUP_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
|
|
mPlatformMode = SETUP_MODE;
|
|
if (Variable.CurrPtr != NULL) {
|
|
VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
|
|
Status = UpdateVariable (
|
|
EFI_SETUP_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&mPlatformMode,
|
|
0,
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
NULL,
|
|
Global
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
//
|
|
// Clear PK, KEK, db and dbx
|
|
//
|
|
Status = DeleteVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, Global);
|
|
ASSERT_EFI_ERROR (Status);
|
|
Status = DeleteVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, Global);
|
|
ASSERT_EFI_ERROR (Status);
|
|
Status = DeleteVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, Global);
|
|
ASSERT_EFI_ERROR (Status);
|
|
Status = DeleteVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, Global);
|
|
ASSERT_EFI_ERROR (Status);
|
|
Status = DeleteVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, Global);
|
|
ASSERT_EFI_ERROR (Status);
|
|
Status = DeleteVariable (EFI_IMAGE_SECURITY_DATABASE3, &gEfiImageSecurityDatabaseGuid, Global);
|
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
This function only uses for create dummy dbx data when dbx variable doesn't exist.
|
|
|
|
@param[in, out] BufferSize On input, this is input buffer size.
|
|
On output, this is buffer size of dummy data.
|
|
@param[out] Buffer Pointer to buffer to save dummy dbx data.
|
|
|
|
@retval EFI_SUCCESS Create dummy dbx data successful.
|
|
@retval EFI_INVALID_PARAMETER BufferSize or Buffer is NULL.
|
|
@retval EFI_BUFFER_TOO_SMALL Input buffer size is too small.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
CreateDummyDbxData (
|
|
IN OUT UINTN *BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_SIGNATURE_LIST *SignatureList;
|
|
UINT32 RequestBufferSize;
|
|
|
|
if (BufferSize == NULL || Buffer == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
RequestBufferSize = sizeof (EFI_SIGNATURE_LIST) + SHA256_DIGEST_SIZE + sizeof (EFI_GUID);
|
|
if (*BufferSize < RequestBufferSize) {
|
|
*BufferSize = RequestBufferSize;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
*BufferSize = RequestBufferSize;
|
|
SignatureList = Buffer;
|
|
ZeroMem (SignatureList, RequestBufferSize);
|
|
SignatureList->SignatureListSize = RequestBufferSize;
|
|
SignatureList->SignatureSize = RequestBufferSize - sizeof (EFI_SIGNATURE_LIST);
|
|
CopyMem (&SignatureList->SignatureType, &gEfiCertSha256Guid, sizeof (EFI_GUID));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Initializes for authenticated variable service.
|
|
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
|
|
@retval EFI_SUCCESS Function successfully executed.
|
|
@retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources.
|
|
**/
|
|
EFI_STATUS
|
|
AuthenticatedVariableServiceInitialize (
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
UINT32 VarAttr;
|
|
UINTN VariableCount;
|
|
EFI_TIME TimeStamp;
|
|
UINTN VariableSize;
|
|
UINT32 ListSize;
|
|
|
|
if (mSmst == NULL) {
|
|
Status = gBS->LocateProtocol (
|
|
&gCryptoServicesProtocolGuid,
|
|
NULL,
|
|
(VOID **)&mCryptoService
|
|
);
|
|
|
|
ASSERT (mCryptoService != NULL);
|
|
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiHashProtocolGuid,
|
|
NULL,
|
|
(VOID **)&mHash
|
|
);
|
|
|
|
ASSERT (mHash != NULL);
|
|
} else {
|
|
Status = mSmst->SmmLocateProtocol (
|
|
&gCryptoServicesProtocolGuid,
|
|
NULL,
|
|
(VOID **)&mCryptoService
|
|
);
|
|
ASSERT (mCryptoService != NULL);
|
|
|
|
Status = mSmst->SmmLocateProtocol (
|
|
&gEfiHashProtocolGuid,
|
|
NULL,
|
|
(VOID **)&mHash
|
|
);
|
|
ASSERT (mHash != NULL);
|
|
}
|
|
|
|
SyncAuthData (Global);
|
|
mSha256Hash = VariableAllocateZeroBuffer (SHA256_DIGEST_SIZE, TRUE);
|
|
|
|
if (mSmst == NULL) {
|
|
//
|
|
// Check "SignatureSupport" variable's existence.
|
|
// If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
|
|
//
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetime (
|
|
EFI_SIGNATURE_SUPPORT_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
|
|
if (Variable.CurrPtr == NULL) {
|
|
VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS;
|
|
Status = UpdateVariable (
|
|
EFI_SIGNATURE_SUPPORT_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
mSignatureSupport,
|
|
SIGSUPPORT_NUM * sizeof (EFI_GUID),
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
NULL,
|
|
Global
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
//
|
|
// Check "certdb" variable's existence.
|
|
// If it doesn't exist, then create a new one with
|
|
// EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
|
|
//
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetime (
|
|
EFI_CERT_DB_NAME,
|
|
&gEfiGenericVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
|
|
if (Variable.CurrPtr == NULL) {
|
|
VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
|
|
ListSize = 0;
|
|
ZeroMem (&TimeStamp, sizeof (TimeStamp));
|
|
Status = UpdateVariable (
|
|
EFI_CERT_DB_NAME,
|
|
&gEfiGenericVariableGuid,
|
|
&ListSize,
|
|
sizeof (UINT32),
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
&TimeStamp,
|
|
Global
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
//
|
|
// Check "certdbv" variable's existence.
|
|
// If it doesn't exist, then create a new one with
|
|
// EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
|
|
//
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetime (
|
|
EFI_CERT_DB_VOLATILE_NAME,
|
|
&gEfiGenericVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
|
|
if (Variable.CurrPtr == NULL) {
|
|
VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
|
|
ListSize = 0;
|
|
ZeroMem (&TimeStamp, sizeof (TimeStamp));
|
|
Status = UpdateVariable (
|
|
EFI_CERT_DB_VOLATILE_NAME,
|
|
&gEfiGenericVariableGuid,
|
|
&ListSize,
|
|
sizeof (UINT32),
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
&TimeStamp,
|
|
Global
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!FeaturePcdGet (PcdH2OSecureBootSupported)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (mSmst == NULL) {
|
|
//
|
|
// Check "dbx" variable's existence.
|
|
// If it doesn't exist, then create a new empty one with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
|
|
//
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetimeInAllRegions (
|
|
EFI_IMAGE_SECURITY_DATABASE1,
|
|
&gEfiImageSecurityDatabaseGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
|
|
if (Variable.CurrPtr == NULL) {
|
|
VariableSize = APPEND_BUFF_SIZE;
|
|
Status = CreateDummyDbxData (&VariableSize, mStorageArea);
|
|
ASSERT_EFI_ERROR (Status);
|
|
VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
|
|
ZeroMem (&TimeStamp, sizeof (TimeStamp));
|
|
Status = UpdateVariable (
|
|
EFI_IMAGE_SECURITY_DATABASE1,
|
|
&gEfiImageSecurityDatabaseGuid,
|
|
mStorageArea,
|
|
VariableSize,
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
&TimeStamp,
|
|
Global
|
|
);
|
|
}
|
|
}
|
|
|
|
Status = InitializeAdministerSecureBootVariables ();
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
According to variable name and vendor GUID to check the name and GUID in certificated data
|
|
is matched.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] CertDbData Pointer to AUTH_CERT_DB_DATA instance.
|
|
|
|
@retval TRUE Variable name and variable vendor GUID is matched.
|
|
@retval FALSE Variable name and variable vendor GUID isn't matched.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsMatchedCertData (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN AUTH_CERT_DB_DATA *CertDbData
|
|
)
|
|
{
|
|
if (VariableName == NULL || VendorGuid == NULL || CertDbData == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (CompareGuid (&CertDbData->VendorGuid, VendorGuid) &&
|
|
StrCmp (VariableName, (CHAR16 *) (CertDbData + 1)) == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
Calculate SHA256 digest of SignerCert CommonName + ToplevelCert tbsCertificate
|
|
SignerCert and ToplevelCert are inside the signer certificate chain.
|
|
|
|
@param[in] SignerCert A pointer to SignerCert data.
|
|
@param[in] SignerCertSize Length of SignerCert data.
|
|
@param[in] TopLevelCert A pointer to TopLevelCert data.
|
|
@param[in] TopLevelCertSize Length of TopLevelCert data.
|
|
@param[out] Sha256Digest Sha256 digest calculated.
|
|
|
|
@return EFI_ABORTED Digest process failed.
|
|
@return EFI_SUCCESS SHA256 Digest is succesfully calculated.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
CalculatePrivAuthVarSignChainSHA256Digest (
|
|
IN UINT8 *SignerCert,
|
|
IN UINTN SignerCertSize,
|
|
IN UINT8 *TopLevelCert,
|
|
IN UINTN TopLevelCertSize,
|
|
OUT UINT8 *Sha256Digest
|
|
)
|
|
{
|
|
UINT8 *TbsCert;
|
|
UINTN TbsCertSize;
|
|
UINT8 CertCommonName[256];
|
|
UINTN CertCommonNameSize;
|
|
EFI_STATUS Status;
|
|
BOOLEAN Success;
|
|
EFI_HASH_OUTPUT Digest;
|
|
|
|
CertCommonNameSize = sizeof(CertCommonName);
|
|
|
|
//
|
|
// Get SignerCert CommonName
|
|
//
|
|
Success = mCryptoService->X509GetSubjectName (
|
|
SignerCert,
|
|
SignerCertSize,
|
|
CertCommonName,
|
|
&CertCommonNameSize
|
|
);
|
|
if (!Success) {
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
Success = mCryptoService->X509GetTBSCert (
|
|
TopLevelCert,
|
|
TopLevelCertSize,
|
|
&TbsCert,
|
|
&TbsCertSize
|
|
);
|
|
//
|
|
// Get TopLevelCert tbsCertificate
|
|
//
|
|
if (!Success) {
|
|
return EFI_ABORTED;
|
|
}
|
|
Digest.Sha256Hash = (EFI_SHA256_HASH *) Sha256Digest;
|
|
Status = mHash->Hash (
|
|
mHash,
|
|
&gEfiHashAlgorithmSha256Guid,
|
|
FALSE,
|
|
CertCommonName,
|
|
CertCommonNameSize,
|
|
(EFI_HASH_OUTPUT *) &Digest
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return EFI_ABORTED;
|
|
}
|
|
Status = mHash->Hash (
|
|
mHash,
|
|
&gEfiHashAlgorithmSha256Guid,
|
|
TRUE,
|
|
TbsCert,
|
|
TbsCertSize,
|
|
(EFI_HASH_OUTPUT *) &Digest
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Find matching signer's certificates for common authenticated variable
|
|
by corresponding VariableName and VendorGuid from "certdb" or "certdbv".
|
|
|
|
The data format of "certdb" or "certdbv":
|
|
//
|
|
// UINT32 CertDbListSize;
|
|
// /// AUTH_CERT_DB_DATA Certs1[];
|
|
// /// AUTH_CERT_DB_DATA Certs2[];
|
|
// /// ...
|
|
// /// AUTH_CERT_DB_DATA Certsn[];
|
|
//
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Vendor GUID of authenticated Variable.
|
|
@param[in] Data Pointer to variable "certdb" or "certdbv".
|
|
@param[in] DataSize Size of variable "certdb" or "certdbv".
|
|
@param[out] Variable Pointer to AUTH_CERT_DB_DATA instance.
|
|
|
|
@retval EFI_SUCCESS Find matching certs and output parameters.
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_NOT_FOUND Fail to find matching certs.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
FindCertsFromDb (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT8 *Data,
|
|
IN UINTN DataSize,
|
|
OUT AUTH_CERT_DB_DATA **CertDbData OPTIONAL
|
|
)
|
|
{
|
|
UINT32 Offset;
|
|
AUTH_CERT_DB_DATA *WorkingCert;
|
|
UINT32 CertDbListSize;
|
|
|
|
|
|
if (VariableName == NULL || VendorGuid == NULL || Data == NULL || DataSize < sizeof (UINT32)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
CertDbListSize = *((UINT32 *) Data);
|
|
if (CertDbListSize != (UINT32) DataSize) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Offset = sizeof (UINT32);
|
|
//
|
|
// Get corresponding certificates by VendorGuid and VariableName.
|
|
//
|
|
while (Offset < (UINT32) CertDbListSize) {
|
|
WorkingCert = (AUTH_CERT_DB_DATA *) (Data + Offset);
|
|
if (IsMatchedCertData (VariableName, VendorGuid, WorkingCert)) {
|
|
if (CertDbData != NULL) {
|
|
*CertDbData = WorkingCert;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
Offset += WorkingCert->CertNodeSize;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Retrieve signer's certificates for common authenticated variable
|
|
by corresponding VariableName and VendorGuid from "certdb"
|
|
or "certdbv" according to authenticated variable attributes.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] Attributes Attributes of authenticated variable.
|
|
@param[out] CertDbData Data pointer.
|
|
|
|
@retval EFI_SUCCESS Get signer's certificates successfully.
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_NOT_FOUND Fail to find matching certs.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetCertsFromDb (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT32 Attributes,
|
|
OUT AUTH_CERT_DB_DATA **CertDbData
|
|
)
|
|
{
|
|
VARIABLE_POINTER_TRACK CertDbVariable;
|
|
EFI_STATUS Status;
|
|
UINTN VariableCount;
|
|
CHAR16 *DbName;
|
|
|
|
|
|
if ((VariableName == NULL) || (VendorGuid == NULL) || (CertDbData == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
|
|
//
|
|
// Get variable "certdb".
|
|
//
|
|
DbName = EFI_CERT_DB_NAME;
|
|
} else {
|
|
//
|
|
// Get variable "certdbv".
|
|
//
|
|
DbName = EFI_CERT_DB_VOLATILE_NAME;
|
|
}
|
|
|
|
//
|
|
// Get variable "certdb".
|
|
//
|
|
Status = FindVariableByLifetime (
|
|
DbName,
|
|
&gEfiGenericVariableGuid,
|
|
&CertDbVariable,
|
|
&VariableCount,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = FindCertsFromDb (
|
|
VariableName,
|
|
VendorGuid,
|
|
GetVariableDataPtr (CertDbVariable.CurrPtr),
|
|
DataSizeOfVariable (CertDbVariable.CurrPtr),
|
|
CertDbData
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Get certificate from AUTH_CERT_DB_DATA instance.
|
|
|
|
@param[in] CertDbData Pointer to AUTH_CERT_DB_DATA instance.
|
|
|
|
@return NULL Cannot find signature in AUTH_CERT_DB_DATA instance.
|
|
@return Other The start address of certificated data.
|
|
**/
|
|
STATIC
|
|
VOID *
|
|
GetCertDbData (
|
|
IN AUTH_CERT_DB_DATA *CertDbData
|
|
)
|
|
{
|
|
UINT8 *CertData;
|
|
|
|
if (CertDbData == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
CertData = ((UINT8 *) (CertDbData + 1)) + CertDbData->NameSize;
|
|
|
|
return (VOID *) CertData;
|
|
}
|
|
|
|
/**
|
|
Delete matching signer's certificates when deleting common authenticated
|
|
variable by corresponding VariableName and VendorGuid from "certdb" or
|
|
"certdbv" according to authenticated variable attributes.
|
|
|
|
@param[in] VariableName Name of authenticated Variable.
|
|
@param[in] VendorGuid Vendor GUID of authenticated Variable.
|
|
@param[in] Attributes Attributes of authenticated variable.
|
|
|
|
@retval EFI_SUCCESS IThe operation is completed successfully.
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
|
|
@retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
DeleteCertsFromDb (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT32 Attributes
|
|
)
|
|
{
|
|
VARIABLE_POINTER_TRACK CertDbVariable;
|
|
EFI_STATUS Status;
|
|
UINT32 VarAttr;
|
|
UINT32 CertNodeOffset;
|
|
UINT8 *NewCertDb;
|
|
UINT32 NewCertDbSize;
|
|
UINTN VariableCount;
|
|
AUTH_CERT_DB_DATA *CertDbData;
|
|
EFI_TIME TimeStamp;
|
|
CHAR16 *DbName;
|
|
|
|
|
|
if ((VariableName == NULL) || (VendorGuid == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
|
|
//
|
|
// Get variable "certdb".
|
|
//
|
|
DbName = EFI_CERT_DB_NAME;
|
|
VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
|
|
} else {
|
|
//
|
|
// Get variable "certdbv".
|
|
//
|
|
DbName = EFI_CERT_DB_VOLATILE_NAME;
|
|
VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
|
|
}
|
|
|
|
Status = FindVariableByLifetime (
|
|
DbName,
|
|
&gEfiGenericVariableGuid,
|
|
&CertDbVariable,
|
|
&VariableCount,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (DataSizeOfVariable (CertDbVariable.CurrPtr) == sizeof (UINT32)) {
|
|
//
|
|
// There is no certs in "certdb" or "certdbv".
|
|
//
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Get corresponding cert node from "certdb" or "certdbv".
|
|
//
|
|
Status = FindCertsFromDb (
|
|
VariableName,
|
|
VendorGuid,
|
|
GetVariableDataPtr (CertDbVariable.CurrPtr),
|
|
DataSizeOfVariable (CertDbVariable.CurrPtr),
|
|
&CertDbData
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Construct new data content of variable "certdb" or "certdbv".
|
|
// 1.Copy the DB entries before deleting node.
|
|
// 2.Update CertDbListSize.
|
|
// 3.Copy the DB entries after deleting node.
|
|
//
|
|
NewCertDbSize = (UINT32) DataSizeOfVariable (CertDbVariable.CurrPtr) - CertDbData->CertNodeSize;
|
|
NewCertDb = mCertDbList;
|
|
CertNodeOffset = (UINT32) (UINTN) ((UINT8 *) CertDbData - GetVariableDataPtr (CertDbVariable.CurrPtr));
|
|
|
|
CopyMem (NewCertDb, GetVariableDataPtr (CertDbVariable.CurrPtr), CertNodeOffset);
|
|
CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
|
|
CopyMem(
|
|
NewCertDb + CertNodeOffset,
|
|
GetVariableDataPtr (CertDbVariable.CurrPtr) + CertNodeOffset + CertDbData->CertNodeSize,
|
|
DataSizeOfVariable (CertDbVariable.CurrPtr) - CertNodeOffset - CertDbData->CertNodeSize
|
|
);
|
|
|
|
ZeroMem (&TimeStamp, sizeof (TimeStamp));
|
|
Status = UpdateVariable (
|
|
DbName,
|
|
&gEfiGenericVariableGuid,
|
|
NewCertDb,
|
|
NewCertDbSize,
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&CertDbVariable,
|
|
&TimeStamp,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Insert signer's certificates for common authenticated variable with VariableName
|
|
and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to
|
|
time based authenticated variable attributes. CertData is the SHA256 digest of
|
|
SignerCert CommonName + TopLevelCert tbsCertificate.
|
|
|
|
@param[in] VariableName Name of authenticated Variable.
|
|
@param[in] VendorGuid Vendor GUID of authenticated Variable.
|
|
@param[in] Attributes Attributes of authenticated variable.
|
|
@param[in] SignerCert Signer certificate data.
|
|
@param[in] SignerCertSize Length of signer certificate.
|
|
@param[in] TopLevelCert Top-level certificate data.
|
|
@param[in] TopLevelCertSize Length of top-level certificate.
|
|
|
|
@retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb".
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName and VendorGuid
|
|
already exists.
|
|
@retval EFI_OUT_OF_RESOURCES Certificated database list is large than MAX_VARIABLE_SIZE.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
InsertCertsToDb (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT32 Attributes,
|
|
IN UINT8 *SignerCert,
|
|
IN UINTN SignerCertSize,
|
|
IN UINT8 *TopLevelCert,
|
|
IN UINTN TopLevelCertSize
|
|
)
|
|
{
|
|
VARIABLE_POINTER_TRACK CertDbVariable;
|
|
EFI_STATUS Status;
|
|
UINT32 VarAttr;
|
|
UINT8 *NewCertDb;
|
|
UINT32 NewCertDbSize;
|
|
UINT32 CertNodeSize;
|
|
UINT32 NameSize;
|
|
AUTH_CERT_DB_DATA *CurrentCertDbData;
|
|
UINTN VariableCount;
|
|
EFI_TIME TimeStamp;
|
|
CHAR16 *DbName;
|
|
UINT32 CertDataSize;
|
|
UINT8 Sha256Digest[SHA256_DIGEST_SIZE];
|
|
|
|
if ((VariableName == NULL) || (VendorGuid == NULL) || (SignerCert == NULL) || (TopLevelCert == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
|
|
//
|
|
// Get variable "certdb".
|
|
//
|
|
DbName = EFI_CERT_DB_NAME;
|
|
VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
|
|
} else {
|
|
//
|
|
// Get variable "certdbv".
|
|
//
|
|
DbName = EFI_CERT_DB_VOLATILE_NAME;
|
|
VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
|
|
}
|
|
|
|
//
|
|
// Get variable "certdb" or "certdbv".
|
|
//
|
|
Status = FindVariableByLifetime (
|
|
DbName,
|
|
&gEfiGenericVariableGuid,
|
|
&CertDbVariable,
|
|
&VariableCount,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Find whether matching cert node already exists in "certdb" or "certdbv".
|
|
// If yes return error.
|
|
//
|
|
Status = FindCertsFromDb (
|
|
VariableName,
|
|
VendorGuid,
|
|
GetVariableDataPtr (CertDbVariable.CurrPtr),
|
|
DataSizeOfVariable (CertDbVariable.CurrPtr),
|
|
NULL
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
ASSERT (FALSE);
|
|
return EFI_ACCESS_DENIED;
|
|
}
|
|
|
|
//
|
|
// Construct new data content of variable "certdb" or "certdbv".
|
|
//
|
|
NameSize = (UINT32) StrSize (VariableName);
|
|
CertDataSize = sizeof(Sha256Digest);
|
|
CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize;
|
|
NewCertDbSize = (UINT32) DataSizeOfVariable (CertDbVariable.CurrPtr) + CertNodeSize;
|
|
NewCertDb = mCertDbList;
|
|
if (NewCertDbSize > MAX_VARIABLE_SIZE) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
Status = CalculatePrivAuthVarSignChainSHA256Digest(
|
|
SignerCert,
|
|
SignerCertSize,
|
|
TopLevelCert,
|
|
TopLevelCertSize,
|
|
Sha256Digest
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// 1.Copy the whole original DB entries .
|
|
// 2.Update CertDbListSize.
|
|
// 3.Append new certificated database at end of original DB list.
|
|
//
|
|
CopyMem (NewCertDb, GetVariableDataPtr (CertDbVariable.CurrPtr), DataSizeOfVariable (CertDbVariable.CurrPtr));
|
|
CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
|
|
//
|
|
// Construct new cert node header.
|
|
//
|
|
CurrentCertDbData = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSizeOfVariable (CertDbVariable.CurrPtr));
|
|
CopyMem (&CurrentCertDbData->VendorGuid, VendorGuid, sizeof (EFI_GUID));
|
|
CopyMem (&CurrentCertDbData->CertNodeSize, &CertNodeSize, sizeof (UINT32));
|
|
CopyMem (&CurrentCertDbData->NameSize, &NameSize, sizeof (UINT32));
|
|
CopyMem (&CurrentCertDbData->CertDataSize, &CertDataSize, sizeof (UINT32));
|
|
|
|
CopyMem (
|
|
CurrentCertDbData + 1,
|
|
VariableName,
|
|
NameSize
|
|
);
|
|
|
|
CopyMem (
|
|
((UINT8 *) (CurrentCertDbData + 1)) + NameSize,
|
|
Sha256Digest,
|
|
CertDataSize
|
|
);
|
|
|
|
ZeroMem (&TimeStamp, sizeof (TimeStamp));
|
|
Status = UpdateVariable (
|
|
DbName,
|
|
&gEfiGenericVariableGuid,
|
|
NewCertDb,
|
|
NewCertDbSize,
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&CertDbVariable,
|
|
&TimeStamp,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
|
|
|
|
Caution: This function may receive untrusted input.
|
|
This function may be invoked in SMM mode, and datasize and data are external input.
|
|
This function will do basic validation, before parse the data.
|
|
This function will parse the authentication carefully to avoid security issues, like
|
|
buffer overflow, integer overflow.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] Data Data pointer.
|
|
@param[in] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[in] Variable The variable information which is used to keep track of variable usage.
|
|
@param[in] Attributes Attribute value of the variable.
|
|
@param[in] AuthVarType Verify against PK or KEK database or private database.
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
@param[out] VarDel Delete the variable or not.
|
|
|
|
@retval EFI_SUCCESS Variable pass validation successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
|
|
check carried out by the firmware.
|
|
@retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
|
|
of resources.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
WriteTimeBasedPayload (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN VOID *Data,
|
|
IN UINTN DataSize,
|
|
IN VARIABLE_POINTER_TRACK *Variable,
|
|
IN UINT32 Attributes,
|
|
IN VARIABLE_GLOBAL *Global,
|
|
IN AUTHVAR_TYPE AuthVarType,
|
|
OUT BOOLEAN *VarDel
|
|
)
|
|
{
|
|
UINT8 *TopLevelCert;
|
|
UINTN TopLevelCertSize;
|
|
UINT8 *SigData;
|
|
UINT8 *PayLoadPtr;
|
|
UINTN Index;
|
|
UINTN CertCount;
|
|
UINTN PayloadSize;
|
|
UINT32 Attr;
|
|
UINT32 SigDataSize;
|
|
UINT32 SigListDataSize;
|
|
BOOLEAN VerifyStatus;
|
|
EFI_STATUS Status;
|
|
EFI_SIGNATURE_LIST *CertList;
|
|
EFI_SIGNATURE_DATA *Cert;
|
|
VARIABLE_POINTER_TRACK PkVariable;
|
|
VARIABLE_POINTER_TRACK SigListData;
|
|
EFI_VARIABLE_AUTHENTICATION_2 *CertData;
|
|
UINT8 *NewData;
|
|
UINTN NewDataSize;
|
|
UINTN VariableCount;
|
|
UINT8 *SignerCerts;
|
|
UINTN CertStackSize;
|
|
AUTH_CERT_DB_DATA *CertDbData;
|
|
UINT8 Sha256Digest[SHA256_DIGEST_SIZE];
|
|
EFI_CERT_DATA *CertDataPtr;
|
|
|
|
|
|
if (mCryptoService == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
VerifyStatus = FALSE;
|
|
CertData = NULL;
|
|
NewData = NULL;
|
|
Attr = Attributes;
|
|
TopLevelCert = NULL;
|
|
SignerCerts = NULL;
|
|
|
|
//
|
|
// When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
|
|
// set, then the Data buffer shall begin with an instance of a complete (and serialized)
|
|
// EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
|
|
// variable value and DataSize shall reflect the combined size of the descriptor and the new
|
|
// variable value. The authentication descriptor is not part of the variable data and is not
|
|
// returned by subsequent calls to GetVariable().
|
|
//
|
|
CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
|
|
|
|
//
|
|
// Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
|
|
// TimeStamp value are set to zero.
|
|
//
|
|
if ((CertData->TimeStamp.Pad1 != 0) ||
|
|
(CertData->TimeStamp.Nanosecond != 0) ||
|
|
(CertData->TimeStamp.TimeZone != 0) ||
|
|
(CertData->TimeStamp.Daylight != 0) ||
|
|
(CertData->TimeStamp.Pad2 != 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
|
|
if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {
|
|
//
|
|
// TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
|
|
//
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
}
|
|
|
|
//
|
|
// wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
|
|
// Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
|
|
//
|
|
if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
|
|
!CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
|
|
//
|
|
// Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
|
|
//
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
//
|
|
// Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
|
|
// AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
|
|
//
|
|
SigData = (UINT8*) ((UINTN)Data + (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData));
|
|
SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(UINTN)(((WIN_CERTIFICATE_UEFI_GUID *) 0)->CertData);
|
|
|
|
//
|
|
// Find out the new data payload which follows Pkcs7 SignedData directly.
|
|
//
|
|
PayLoadPtr = (UINT8*) ((UINTN) SigData + (UINTN) SigDataSize);
|
|
PayloadSize = DataSize - (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData) - (UINTN) SigDataSize;
|
|
|
|
|
|
//
|
|
// Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).
|
|
//
|
|
NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
|
|
sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
|
|
NewData = (UINT8 *) mStorageArea;
|
|
if (NewData == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
CopyMem (NewData, VariableName, StrSize (VariableName) - sizeof (CHAR16));
|
|
CopyMem (NewData + StrSize (VariableName) - sizeof (CHAR16), VendorGuid, sizeof (EFI_GUID));
|
|
CopyMem (
|
|
NewData + StrSize (VariableName) - sizeof (CHAR16) + sizeof (EFI_GUID),
|
|
&Attr,
|
|
sizeof (UINT32)
|
|
);
|
|
|
|
CopyMem (
|
|
NewData + StrSize (VariableName) - sizeof (CHAR16) + sizeof (EFI_GUID) + sizeof (UINT32),
|
|
&CertData->TimeStamp,
|
|
sizeof (EFI_TIME)
|
|
);
|
|
|
|
CopyMem (NewData + (NewDataSize - PayloadSize), PayLoadPtr, PayloadSize);
|
|
|
|
if (AuthVarType == AuthVarTypePk) {
|
|
|
|
//
|
|
// Get platform key from variable.
|
|
//
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetimeInAllRegions (
|
|
EFI_PLATFORM_KEY_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&PkVariable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
|
|
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
|
|
TopLevelCert = Cert->SignatureData;
|
|
TopLevelCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
|
|
if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
|
|
//
|
|
// Verify Pkcs7 SignedData via Pkcs7Verify library.
|
|
// NOTE THAT: Since we have no Pkcs7 SignedData Parser, there is no way to know what exactly
|
|
// digestAlgorithms caller uses, here suppose SHA1 is used by caller for hash.
|
|
//
|
|
VerifyStatus = mCryptoService->Pkcs7Verify (
|
|
SigData,
|
|
SigDataSize,
|
|
TopLevelCert,
|
|
TopLevelCertSize,
|
|
NewData,
|
|
NewDataSize,
|
|
FALSE // no need to do authenticode workaround
|
|
);
|
|
if (VerifyStatus) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
} else if (AuthVarType == AuthVarTypeKek || AuthVarType == AuthVarTypeDbr){
|
|
|
|
//
|
|
// Get database from variable.
|
|
//
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetimeInAllRegions (
|
|
AuthVarType == AuthVarTypeKek ? EFI_KEY_EXCHANGE_KEY_NAME : EFI_IMAGE_SECURITY_DATABASE3,
|
|
AuthVarType == AuthVarTypeKek ? &gEfiGlobalVariableGuid : &gEfiImageSecurityDatabaseGuid,
|
|
&SigListData,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
if (EFI_ERROR (Status)){
|
|
return Status;
|
|
}
|
|
//
|
|
// Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
|
|
//
|
|
SigListDataSize = SigListData.CurrPtr->DataSize;
|
|
CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (SigListData.CurrPtr);
|
|
while ((SigListDataSize > 0) && (SigListDataSize >= CertList->SignatureListSize)) {
|
|
if (CertList->SignatureListSize < sizeof (EFI_SIGNATURE_LIST)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
|
|
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
|
|
CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
|
|
for (Index = 0; Index < CertCount; Index++) {
|
|
//
|
|
// Iterate each Signature Data Node within this CertList for a verify
|
|
//
|
|
TopLevelCert = Cert->SignatureData;
|
|
//
|
|
// SignatureSize includes the owner GUID
|
|
//
|
|
TopLevelCertSize = CertList->SignatureSize - sizeof(EFI_GUID);
|
|
|
|
//
|
|
// Verify Pkcs7 SignedData via Pkcs7Verify library.
|
|
// NOTE THAT: Since we have no Pkcs7 SignedData Parser, there is no way to know what exactly
|
|
// digestAlgorithms caller uses, here suppose SHA1 is used by caller for hash.
|
|
//
|
|
VerifyStatus = mCryptoService->Pkcs7Verify (
|
|
SigData,
|
|
SigDataSize,
|
|
TopLevelCert,
|
|
TopLevelCertSize,
|
|
NewData,
|
|
NewDataSize,
|
|
FALSE // no need for authenticode workaround
|
|
);
|
|
if (VerifyStatus) {
|
|
goto Exit;
|
|
}
|
|
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
|
|
}
|
|
}
|
|
SigListDataSize -= CertList->SignatureListSize;
|
|
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
|
|
}
|
|
} else if (AuthVarType == AuthVarTypePriv) {
|
|
|
|
//
|
|
// Process common authenticated variable except PK/KEK/db/dbx/dbt.
|
|
// Get signer's certificates from SignedData.
|
|
//
|
|
VerifyStatus = mCryptoService->Pkcs7GetSigners (
|
|
SigData,
|
|
SigDataSize,
|
|
&SignerCerts,
|
|
&CertStackSize,
|
|
&TopLevelCert,
|
|
&TopLevelCertSize
|
|
);
|
|
if (!VerifyStatus) {
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Get previously stored signer's certificates from certdb for existing
|
|
// variable. Check whether they are identical with signer's certificates
|
|
// in SignedData. If not, return error immediately.
|
|
//
|
|
if ((Variable->CurrPtr != NULL)) {
|
|
VerifyStatus = FALSE;
|
|
Status = GetCertsFromDb (VariableName, VendorGuid, Attributes, &CertDbData);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Exit;
|
|
}
|
|
if (CertDbData->CertDataSize == SHA256_DIGEST_SIZE) {
|
|
//
|
|
// Check hash of signer cert CommonName + Top-level issuer tbsCertificate against data in CertDb
|
|
//
|
|
CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1);
|
|
Status = CalculatePrivAuthVarSignChainSHA256Digest(
|
|
CertDataPtr->CertDataBuffer,
|
|
ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)),
|
|
TopLevelCert,
|
|
TopLevelCertSize,
|
|
Sha256Digest
|
|
);
|
|
if (EFI_ERROR(Status) || CompareMem (Sha256Digest, GetCertDbData (CertDbData), CertDbData->CertDataSize) != 0){
|
|
goto Exit;
|
|
}
|
|
} else {
|
|
if ((CertStackSize != CertDbData->CertDataSize) ||
|
|
(CompareMem (SignerCerts, GetCertDbData (CertDbData), CertDbData->CertDataSize) != 0)) {
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
VerifyStatus = mCryptoService->Pkcs7Verify (
|
|
SigData,
|
|
SigDataSize,
|
|
TopLevelCert,
|
|
TopLevelCertSize,
|
|
NewData,
|
|
NewDataSize,
|
|
FALSE
|
|
);
|
|
if (!VerifyStatus) {
|
|
goto Exit;
|
|
}
|
|
//
|
|
// Delete signer's certificates when delete the common authenticated variable.
|
|
//
|
|
if ((PayloadSize == 0) && (Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
|
|
Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
|
|
if (EFI_ERROR (Status)) {
|
|
VerifyStatus = FALSE;
|
|
goto Exit;
|
|
}
|
|
} else if (Variable->CurrPtr == NULL && PayloadSize != 0) {
|
|
//
|
|
// When adding a new common authenticated variable, always save Hash of cn of signer cert + tbsCertificate of Top-level issuer
|
|
//
|
|
//
|
|
CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1);
|
|
Status = InsertCertsToDb (
|
|
VariableName,
|
|
VendorGuid,
|
|
Attributes,
|
|
CertDataPtr->CertDataBuffer,
|
|
ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)),
|
|
TopLevelCert,
|
|
TopLevelCertSize
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
VerifyStatus = FALSE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
} else {
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
|
|
|
|
Exit:
|
|
|
|
if (AuthVarType == AuthVarTypePriv) {
|
|
mCryptoService->Pkcs7FreeSigners (TopLevelCert);
|
|
mCryptoService->Pkcs7FreeSigners (SignerCerts);
|
|
}
|
|
|
|
|
|
if (!VerifyStatus) {
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
|
|
if ((PayloadSize == 0) && (VarDel != NULL)) {
|
|
*VarDel = TRUE;
|
|
}
|
|
//
|
|
// Final step: Update/Append Variable if it pass Pkcs7Verify
|
|
//
|
|
return UpdateVariable (
|
|
VariableName,
|
|
VendorGuid,
|
|
PayLoadPtr,
|
|
PayloadSize,
|
|
Attributes,
|
|
0,
|
|
0,
|
|
Variable,
|
|
&CertData->TimeStamp,
|
|
Global
|
|
);
|
|
}
|
|
|
|
/**
|
|
Update platform mode.
|
|
|
|
@param[in] Mode SETUP_MODE or USER_MODE.
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
**/
|
|
VOID
|
|
UpdatePlatformMode (
|
|
IN UINT32 Mode,
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
UINT32 VarAttr;
|
|
UINTN VariableCount;
|
|
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetime (
|
|
EFI_SETUP_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
mPlatformMode = Mode;
|
|
VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
|
|
Status = UpdateVariable (
|
|
EFI_SETUP_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&mPlatformMode,
|
|
sizeof(UINT8),
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
NULL,
|
|
Global
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
|
|
/**
|
|
Function to get current DeployedMode variable value.
|
|
|
|
If this value doesn't exist, this function will return 0.
|
|
|
|
@return current DeployedMode value
|
|
**/
|
|
UINT8
|
|
DeployedModeValue (
|
|
VOID
|
|
)
|
|
{
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
EFI_STATUS Status;
|
|
UINTN VariableCount;
|
|
|
|
Status = FindVariableByLifetime (
|
|
EFI_DEPLOYED_MODE_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return 0;
|
|
}
|
|
|
|
return *(GetVariableDataPtr (Variable.CurrPtr));
|
|
}
|
|
|
|
/**
|
|
Function to get current AuditMode variable value.
|
|
|
|
If this value doesn't exist, this function will return 0.
|
|
|
|
@return current AuditMode value
|
|
**/
|
|
UINT8
|
|
AuditModeValue (
|
|
VOID
|
|
)
|
|
{
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
EFI_STATUS Status;
|
|
UINTN VariableCount;
|
|
|
|
Status = FindVariableByLifetime (
|
|
EFI_AUDIT_MODE_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
if (Status != EFI_SUCCESS) {
|
|
return 0;
|
|
}
|
|
|
|
return *(GetVariableDataPtr (Variable.CurrPtr));
|
|
}
|
|
|
|
/**
|
|
Internal function to update AuditMode variable value.
|
|
|
|
@param[in] Input value to update AuditMode variable.
|
|
|
|
@retval EFI_SUCCESS Update AuditMode Variable Successfully.
|
|
@retval EFI_INVALID_PARAMETER Input Value to update AuditMode is incorrect.
|
|
@return Other Ohter errors occurred while updating AuditMode variable.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateAuditModeValue (
|
|
IN CONST UINT8 Value
|
|
)
|
|
{
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
UINTN VariableCount;
|
|
|
|
if (Value != 0 && Value != 1) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
FindVariableByLifetime (
|
|
EFI_AUDIT_MODE_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
return UpdateVariable (
|
|
EFI_AUDIT_MODE_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Value,
|
|
sizeof (Value),
|
|
VARIABLE_ATTRIBUTE_NV_BS_RT,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
NULL,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
}
|
|
|
|
/**
|
|
Internal function to update DeployedMode variable value.
|
|
|
|
@param[in] Input value to update DeployedMode variable.
|
|
|
|
@retval EFI_SUCCESS Update DeployedMode Variable Successfully.
|
|
@retval EFI_INVALID_PARAMETER Input Value to update DeployedMode is incorrect.
|
|
@return Other Ohter errors occurred while updating DeployedMode variable.
|
|
**/
|
|
EFI_STATUS
|
|
UpdateDeployedModeValue (
|
|
IN CONST UINT8 Value
|
|
)
|
|
{
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
UINTN VariableCount;
|
|
|
|
if (Value != 0 && Value != 1) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
FindVariableByLifetime (
|
|
EFI_DEPLOYED_MODE_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
return UpdateVariable (
|
|
EFI_DEPLOYED_MODE_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Value,
|
|
sizeof (Value),
|
|
VARIABLE_ATTRIBUTE_NV_BS_RT,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
NULL,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
}
|
|
|
|
/**
|
|
Function to initialize all of secure boot related mode variables.
|
|
**/
|
|
VOID
|
|
InitializeSecureBootModesValue (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN VariableCount;
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
UINT8 AuditMode;
|
|
UINT8 DeployedMode;
|
|
UINT32 VarAttr;
|
|
EFI_STATUS Status;
|
|
|
|
if (!FeaturePcdGet (PcdH2OSecureBootSupported)) {
|
|
return;
|
|
}
|
|
SyncAuthData (&mVariableModuleGlobal->VariableBase);
|
|
//
|
|
// Check PK database's existence to determine the SetupMode value.
|
|
// Then create a new "SetupMode" with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
|
|
//
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetime (
|
|
EFI_SETUP_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
|
|
VarAttr = VARIABLE_ATTRIBUTE_NV_BS_RT_AW;
|
|
Status = UpdateVariable (
|
|
EFI_SETUP_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&mPlatformMode,
|
|
sizeof(UINT8),
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
NULL,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
ASSERT (Status == EFI_SUCCESS);
|
|
|
|
//
|
|
// Check "SecureBoot" variable existence. This variable must match the platform booting mode.
|
|
// With current code, the setting depends only on the presence of the PK variable.
|
|
// NOTE: if there is any setup option to skip secure boot, that must be checked here!!!
|
|
//
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetime (
|
|
EFI_SECURE_BOOT_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
VarAttr = VARIABLE_ATTRIBUTE_NV_BS_RT_AW;
|
|
Status = UpdateVariable (
|
|
EFI_SECURE_BOOT_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&mPlatformBootMode,
|
|
sizeof (UINT8),
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
NULL,
|
|
&mVariableModuleGlobal->VariableBase
|
|
);
|
|
ASSERT (Status == EFI_SUCCESS);
|
|
if (!FeaturePcdGet (PcdH2OCustomizedSecureBootSupported)) {
|
|
return;
|
|
}
|
|
//
|
|
// Initialize AuditMode and DeployedMode value
|
|
//
|
|
AuditMode = AuditModeValue ();
|
|
DeployedMode = DeployedModeValue ();
|
|
//
|
|
// Two steps to synchronize Deployed mode and Audit mode variable.
|
|
// 1. synchronize when PK present.
|
|
// 2. synchronize when PK doesn't present.
|
|
//
|
|
|
|
//
|
|
// System break while translating from Audit mode to Deployed mode.
|
|
// 1. Set PK -> system break -> set Deployed mode from 0 to 1 -> Set Audit mode from 1 to 0
|
|
// 2. Set PK -> set Deployed mode from 0 to 1 -> system break -> Set Audit mode from 1 to 0
|
|
// Need change Deployed mode to 1 and Audit mode to 0.
|
|
//
|
|
if (((DeployedMode == 0 && AuditMode == 1) || (DeployedMode == 1 && AuditMode == 1)) && DoesPkExist ()) {
|
|
DeployedMode = 1;
|
|
AuditMode = 0;
|
|
}
|
|
//
|
|
// System break while translating from Deployed mode to Setup mode.
|
|
// 1. Delete PK -> system break -> set Deployed mode from 1 to 0
|
|
// *2. Invalid setting if deployed mode == 1 and audit mode == 1 and PK not present
|
|
// Need change Deployed mode to 0 and Audit mode to 0.
|
|
//
|
|
if (((DeployedMode == 1 && AuditMode == 0) || (DeployedMode == 1 && AuditMode == 1))&& !DoesPkExist ()) {
|
|
DeployedMode = 0;
|
|
AuditMode = 0;
|
|
}
|
|
//
|
|
// Set AuditMode and DeployedMode variable.
|
|
//
|
|
UpdateAuditModeValue (AuditMode);
|
|
UpdateDeployedModeValue (DeployedMode);
|
|
//
|
|
// Change variable property after synchronize AuditMode and DeployedMode variable.
|
|
//
|
|
if (AuditMode == 1 || DeployedMode == 1) {
|
|
//
|
|
// AuditMode (RO) and DeployedMode (RO) in AuditMode or DeployedMode.
|
|
//
|
|
UpdateDeployedModeProperty (VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY);
|
|
UpdateAuditModeProperty (VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY);
|
|
} else if (mPlatformMode == USER_MODE) {
|
|
//
|
|
// AuditMode (RW) and DeployedMode (RW) in user mode.
|
|
//
|
|
UpdateDeployedModeProperty (0);
|
|
UpdateAuditModeProperty (0);
|
|
} else {
|
|
//
|
|
// AuditMode (RW) and DeployedMode (RO) in setup mode.
|
|
//
|
|
UpdateDeployedModeProperty (VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY);
|
|
UpdateAuditModeProperty (0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Change all of secure boot mode variables while deleting PK variable.
|
|
**/
|
|
VOID
|
|
ChangeSecureBootModeByDeletePk (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// If delete PK in user mode, need change to setup mode.
|
|
//
|
|
UpdatePlatformMode (SETUP_MODE, &mVariableModuleGlobal->VariableBase);
|
|
//
|
|
// boot mode must change at this point, as untrusted code can now be run
|
|
//
|
|
UpdatePlatformBootMode (SECURE_BOOT_MODE_DISABLE, &mVariableModuleGlobal->VariableBase);
|
|
|
|
if (!FeaturePcdGet (PcdH2OCustomizedSecureBootSupported)) {
|
|
return;
|
|
}
|
|
//
|
|
// Update related AuditMode and DeployedVariable variable
|
|
//
|
|
if (DeployedModeValue () == 0) {
|
|
//
|
|
// Update DeployedMode property to read-only if secure boot mode is changed from user mode to setup mode.
|
|
// (SetupMode = 0, SecureBoot = 0 or 1, AuditMode = 0 (R/W), DeployedMode = 0 (R/W)).
|
|
// to
|
|
// (SetupMode = 1, SecureBoot = 0, AuditMode = 0 (R/W), DeployedMode = 0 (Read-only)).
|
|
UpdateDeployedModeProperty (VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY);
|
|
} else {
|
|
//
|
|
// Update AuditMode property to R/W and change DeployedMode value to 0 if secure boot mode is changed from
|
|
// deployed mode to setup mode.
|
|
// (SetupMode = 0, SecureBoot = 0 or 1, AuditMode = 0 (Read-only), DeployedMode = 1 (Read-only)).
|
|
// to
|
|
// (SetupMode = 1, SecureBoot = 0, AuditMode = 0 (R/W), DeployedMode = 0 (Read-only)).
|
|
UpdateAuditModeProperty (0);
|
|
UpdateDeployedModeValue (0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Change all of secure boot mode variables while updating PK variable.
|
|
**/
|
|
VOID
|
|
ChangeSecureBootModeByInsertPk (
|
|
VOID
|
|
)
|
|
{
|
|
UpdatePlatformMode (USER_MODE, &mVariableModuleGlobal->VariableBase);
|
|
|
|
if (!FeaturePcdGet (PcdH2OCustomizedSecureBootSupported)) {
|
|
return;
|
|
}
|
|
//
|
|
// NOTE: boot mode does NOT change here, since the PK just was enrolled, and untrusted
|
|
// code may have run already since reset.
|
|
//
|
|
if (AuditModeValue () == 0) {
|
|
//
|
|
// Update DeployedMode property to R/W if secure boot mode is changed from setup mode to user mode.
|
|
// (SetupMode = 1, SecureBoot = 0, AuditMode = 0 (R/W), DeployedMode = 0 (Read-only)).
|
|
// to
|
|
// (SetupMode = 0, SecureBoot = 0, AuditMode = 0 (R/W), DeployedMode = 0 (R/W)).
|
|
//
|
|
UpdateDeployedModeProperty (0);
|
|
} else {
|
|
//
|
|
// Update AuditMode value to 0 and DeployedMode value to 1 if secure boot mode is changed from audit mode
|
|
// to deployed mode
|
|
// (SetupMode = 1, SecureBoot = 0, AuditMode = 1 (Read-only), DeployedMode = 0 (Read-only)).
|
|
// to
|
|
// (SetupMode = 0, SecureBoot = 0, AuditMode = 0 (Read-only), DeployedMode = 1 (Read-only)).
|
|
//
|
|
UpdateDeployedModeValue (1);
|
|
UpdateAuditModeValue (0);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
Process variable with platform key for verification.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] Data Data pointer.
|
|
@param[in] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[in] Variable The variable information which is used to keep track of variable usage.
|
|
@param[in] Attributes Attribute value of the variable
|
|
@param[in] IsPk Indicate whether it is to process pk.
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
|
|
@retval EFI_SUCCESS Variable passed validation successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
|
|
check carried out by the firmware.
|
|
**/
|
|
EFI_STATUS
|
|
ProcessVarWithPk (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN VOID *Data,
|
|
IN UINTN DataSize,
|
|
IN VARIABLE_POINTER_TRACK *Variable,
|
|
IN UINT32 Attributes OPTIONAL,
|
|
IN BOOLEAN IsPk,
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TIME *TimeStamp;
|
|
BOOLEAN Del;
|
|
|
|
if (mCryptoService == NULL && mPlatformMode == USER_MODE) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// PK does not support append.
|
|
//
|
|
if (((Attributes & EFI_VARIABLE_APPEND_WRITE) == EFI_VARIABLE_APPEND_WRITE) &&
|
|
(IsPkVariable (VariableName, VendorGuid))) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (mPlatformMode == USER_MODE) {
|
|
Del = FALSE;
|
|
Status = WriteTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, Global, AuthVarTypePk, &Del);
|
|
if (!EFI_ERROR (Status) && IsPk && Del && !DoesPkExist ()) {
|
|
ChangeSecureBootModeByDeletePk ();
|
|
}
|
|
} else {
|
|
TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;
|
|
DataSize -= AUTHINFO2_SIZE (Data);
|
|
Data = (UINT8*) Data + AUTHINFO2_SIZE (Data);
|
|
Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, TimeStamp, Global);
|
|
//
|
|
// If enroll PK in setup mode, need change to user mode.
|
|
//
|
|
if (!EFI_ERROR (Status) && IsPk && DataSize != 0) {
|
|
ChangeSecureBootModeByInsertPk ();
|
|
}
|
|
}
|
|
return Status;
|
|
|
|
}
|
|
|
|
/**
|
|
Process variable with common secure variable for verification.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] Data Data pointer.
|
|
@param[in] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[in] Variable The variable information which is used to keep track of variable usage.
|
|
@param[in] Attributes Attribute value of the variable.
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
@param[in] AuthVarType Verify against PK or KEK database or private database.
|
|
|
|
@retval EFI_SUCCESS Variable pass validation successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
|
|
check carried out by the firmware.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ProcessVarWithCommonSecureVar (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN VOID *Data,
|
|
IN UINTN DataSize,
|
|
IN VARIABLE_POINTER_TRACK *Variable,
|
|
IN UINT32 Attributes OPTIONAL,
|
|
IN VARIABLE_GLOBAL *Global,
|
|
IN AUTHVAR_TYPE AuthVarType
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TIME *TimeStamp;
|
|
|
|
if (mCryptoService == NULL && mPlatformMode == USER_MODE) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) == 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
|
|
if (mPlatformMode == USER_MODE) {
|
|
Status = WriteTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, Global, AuthVarType, NULL);
|
|
} else {
|
|
TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;
|
|
DataSize -= AUTHINFO2_SIZE (Data);
|
|
Data = (UINT8*) Data + AUTHINFO2_SIZE (Data);
|
|
Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, TimeStamp, Global);
|
|
}
|
|
|
|
return Status;
|
|
|
|
}
|
|
/**
|
|
Process variable with key exchange key for verification.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] Data Data pointer.
|
|
@param[in] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[in] Variable The variable information which is used to keep track of variable usage.
|
|
@param[in] Attributes Attribute value of the variable.
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
|
|
@retval EFI_SUCCESS Variable pass validation successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
|
|
check carried out by the firmware.
|
|
**/
|
|
EFI_STATUS
|
|
ProcessVarWithKek (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN VOID *Data,
|
|
IN UINTN DataSize,
|
|
IN VARIABLE_POINTER_TRACK *Variable,
|
|
IN UINT32 Attributes OPTIONAL,
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
return ProcessVarWithCommonSecureVar (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, Global, AuthVarTypeKek);
|
|
}
|
|
|
|
/**
|
|
Process variable with dbr for verification.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] Data Data pointer.
|
|
@param[in] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[in] Variable The variable information which is used to keep track of variable usage.
|
|
@param[in] Attributes Attribute value of the variable.
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
|
|
@retval EFI_SUCCESS Variable pass validation successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
|
|
check carried out by the firmware.
|
|
**/
|
|
EFI_STATUS
|
|
ProcessVarWithDbr (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN VOID *Data,
|
|
IN UINTN DataSize,
|
|
IN VARIABLE_POINTER_TRACK *Variable,
|
|
IN UINT32 Attributes OPTIONAL,
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
return ProcessVarWithCommonSecureVar (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, Global, AuthVarTypeDbr);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] Data Data pointer.
|
|
@param[in] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[in] Variable The variable information which is used to keep track of variable usage.
|
|
@param[in] Attributes Attribute value of the variable.
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
|
|
@retval EFI_SUCCESS Variable is not write-protected or pass validation successfully.
|
|
@retval EFI_INVALID_PARAMETER Invalid parameter.
|
|
@retval EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
|
|
EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
|
|
@retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
|
|
set, but the AuthInfo does NOT pass the validation
|
|
check carried out by the firmware.
|
|
**/
|
|
EFI_STATUS
|
|
ProcessVariable (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN VOID *Data,
|
|
IN UINTN DataSize,
|
|
IN VARIABLE_POINTER_TRACK *Variable,
|
|
IN UINT32 Attributes,
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
if (mVariableModuleGlobal->SecureBootCallbackEnabled && IsAdministerSecureVariable (VariableName, VendorGuid)) {
|
|
return UpdateAdministerSecureVariable (
|
|
VariableName,
|
|
VendorGuid,
|
|
Data,
|
|
DataSize,
|
|
Attributes
|
|
);
|
|
}
|
|
|
|
if (mCryptoService == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (IsExistingInsydeSecureVariable (Variable)) {
|
|
//
|
|
// Insyde secure variable only can update in unlocked state, so just return EFI_WRITE_PROTECTED directly.
|
|
//
|
|
return EFI_WRITE_PROTECTED;
|
|
}
|
|
//
|
|
// Process Time-based Authenticated variable.
|
|
//
|
|
if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
|
|
return WriteTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, Global, AuthVarTypePriv, NULL);
|
|
}
|
|
|
|
if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
|
|
//
|
|
// Reject Counter Based Auth Variable processing request.
|
|
//
|
|
return EFI_UNSUPPORTED;
|
|
} else if ((Variable->CurrPtr != NULL) &&
|
|
(Variable->CurrPtr->Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0) {
|
|
//
|
|
// If the variable is already write-protected, it always needs authentication before update.
|
|
//
|
|
return EFI_WRITE_PROTECTED;
|
|
}
|
|
//
|
|
// Not authenticated variable, just update variable as usual.
|
|
//
|
|
return UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL, Global);
|
|
}
|
|
|
|
|
|
/**
|
|
According to variable name, GUID to determine this variable is whether
|
|
support input secure database type.
|
|
|
|
@param[in] VariableName Name of variable.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] SupportedDatabase Supported secure database.
|
|
|
|
@retval TRUE Parameters not valid
|
|
@retval FALSE Variable store successfully updated
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsSupportedSecureDatabase (
|
|
IN CONST CHAR16 *VariableName,
|
|
IN CONST EFI_GUID *VendorGuid,
|
|
IN UINT32 SupportedDatabase
|
|
)
|
|
{
|
|
SECURE_DATABASE_TYPE_MAP MapTable[] = {
|
|
{IsDbVariable, AUTHORIZED_SIGNATURE_SUPPORT},
|
|
{IsDbxVariable, FORBIDDEN_SIGNATURE_SUPPORT},
|
|
{IsDbtVariable, TIMESTAMP_SIGNATURE_SUPPORT},
|
|
{IsPkVariable, PLATFORM_KEY_SUPPORT},
|
|
{IsKekVariable, KEY_EXCHANGE_KEY_SUPPORT}
|
|
};
|
|
UINTN Index;
|
|
UINTN TableCnt;
|
|
|
|
TableCnt = sizeof (MapTable) / sizeof (SECURE_DATABASE_TYPE_MAP);
|
|
|
|
for (Index = 0; Index < TableCnt; Index++) {
|
|
if (MapTable[Index].VariableFun (VariableName, VendorGuid) &&
|
|
(MapTable[Index].SecureDatabaseType & SupportedDatabase) != 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return (BOOLEAN) ((SupportedDatabase & NORMAL_SIGNATURE_SUPPORT) != 0);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
According to input EFI_SIGNATURE_LIST instance to check this signature is whether a
|
|
valid X509 certificate.
|
|
|
|
@param[in] SigList Pointer to the start address of signature list.
|
|
|
|
@retval TRUE Input data is a valid X509 certificate or system doesn't support check mechanism.
|
|
@retval FALSE Input data is an invalid X509 certificate.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsValidX509Cert (
|
|
IN EFI_SIGNATURE_LIST *SigList
|
|
)
|
|
{
|
|
VOID *RsaContext;
|
|
EFI_SIGNATURE_DATA *CertData;
|
|
UINTN CertLen;
|
|
|
|
if (SigList == NULL || !CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If system doesn't support RsaNew function, we have no way to check input certifcate.
|
|
// Therefore, suppose the input certificate is valid.
|
|
//
|
|
RsaContext = mCryptoService->RsaNew ();
|
|
if (RsaContext == NULL) {
|
|
return TRUE;
|
|
}
|
|
mCryptoService->RsaFree (RsaContext);
|
|
|
|
CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);
|
|
CertLen = SigList->SignatureSize - sizeof (EFI_GUID);
|
|
if (!mCryptoService->RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {
|
|
return FALSE;
|
|
}
|
|
mCryptoService->RsaFree (RsaContext);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Perform a sanity check on the data to be written to secure boot variables.
|
|
|
|
@param[in] VariableName Name of variable.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[in] Data Variable data.
|
|
@param[in] DataSize Size of data. 0 means delete.
|
|
|
|
@retval EFI_SUCCESS The sanity check operation is success.
|
|
@retval EFI_INVALID_PARAMETER Variable data has some data structure problem.
|
|
**/
|
|
EFI_STATUS
|
|
CheckSecureBootVarData (
|
|
IN CONST CHAR16 *VariableName,
|
|
IN CONST EFI_GUID *VendorGuid,
|
|
IN CONST VOID *Data,
|
|
IN UINTN DataSize
|
|
)
|
|
{
|
|
EFI_SIGNATURE_LIST *SigList;
|
|
UINTN CheckDataSize;
|
|
UINTN Index;
|
|
UINTN TableCnt;
|
|
EFI_STATUS Status;
|
|
//
|
|
// make sure there is data
|
|
//
|
|
if ((Data == NULL) || (DataSize == 0)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// walk through the lists present in the data, checking for supported types, and correct sizes
|
|
//
|
|
SigList = (EFI_SIGNATURE_LIST *)Data;
|
|
CheckDataSize = DataSize;
|
|
|
|
if (SigList->SignatureListSize > CheckDataSize) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = EFI_SUCCESS;
|
|
TableCnt = sizeof (mSupportSigItem) / sizeof (SIGNATURE_SUPPORT_INFO);
|
|
while (CheckDataSize > 0) {
|
|
//
|
|
// check the size of signature list size first to make sure signature data integrity
|
|
//
|
|
if (SigList->SignatureListSize < sizeof (EFI_SIGNATURE_LIST) || CheckDataSize < SigList->SignatureListSize) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
for (Index = 0; Index < TableCnt; Index++) {
|
|
//
|
|
// compare singnature type first
|
|
//
|
|
if (!CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SignatureType)) {
|
|
continue;
|
|
}
|
|
//
|
|
// Doesn't support to be signed hash if EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION bit is disabled.
|
|
//
|
|
if ((PcdGet64 (PcdOsIndicationsSupported) & EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION) == 0 &&
|
|
mSupportSigItem[Index].SupportedDatabase == FORBIDDEN_SIGNATURE_SUPPORT) {
|
|
continue;
|
|
}
|
|
//
|
|
// check relative variable supports this signature type or not
|
|
//
|
|
if (!IsSupportedSecureDatabase (VariableName, VendorGuid, mSupportSigItem[Index].SupportedDatabase)) {
|
|
continue;
|
|
}
|
|
//
|
|
// check signature size is correct or not.
|
|
//
|
|
if (mSupportSigItem[Index].FixedSigSize && mSupportSigItem[Index].SignatureSize != SigList->SignatureSize) {
|
|
continue;
|
|
}
|
|
//
|
|
// Check input certificate is whether a valid certificate if signature type is X509 certificate
|
|
//
|
|
if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid) && !IsValidX509Cert (SigList)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
CheckDataSize -= SigList->SignatureListSize;
|
|
SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
|
|
}
|
|
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
/**
|
|
This function used to check the signature list node is whether can merge any of the signature list.
|
|
If yes, return the pointer to the signature list which can be merged.
|
|
If no, return NULL pointer.
|
|
|
|
@param[in] SigList Pointer to the start address of whole signature list.
|
|
@param[in] BufferSize The buffer size of whole signature list.
|
|
@param[in] SigListNode Pointer to signature list node which want to check.
|
|
|
|
@retval NULL Cannot find can merged signature list.
|
|
@return EFI_SIGNATURE_LIST * Pointer to the can merged signature list.
|
|
**/
|
|
STATIC
|
|
EFI_SIGNATURE_LIST *
|
|
FindCanMergeSig (
|
|
IN EFI_SIGNATURE_LIST *SigList,
|
|
IN UINTN BufferSize,
|
|
IN EFI_SIGNATURE_LIST *SigListNode
|
|
)
|
|
{
|
|
UINTN DataOffest;
|
|
EFI_SIGNATURE_LIST *WorkingSig;
|
|
BOOLEAN SigFound;
|
|
|
|
|
|
if (SigList == NULL || BufferSize == 0 || SigListNode == NULL) {
|
|
return NULL;
|
|
}
|
|
//
|
|
// if singnature type isn't a fixed length singnature type, return NULL pointer directly.
|
|
//
|
|
if (CompareGuid (&SigListNode->SignatureType, &gEfiCertX509Guid)) {
|
|
return NULL;
|
|
}
|
|
|
|
SigFound = FALSE;
|
|
WorkingSig = SigList;
|
|
DataOffest = 0;
|
|
while (DataOffest < BufferSize) {
|
|
if (CompareGuid (&WorkingSig->SignatureType, &SigListNode->SignatureType)) {
|
|
SigFound = TRUE;
|
|
break;
|
|
}
|
|
DataOffest += WorkingSig->SignatureListSize;
|
|
WorkingSig = (EFI_SIGNATURE_LIST *) ((UINT8 *) WorkingSig + WorkingSig->SignatureListSize);
|
|
}
|
|
|
|
return SigFound ? WorkingSig : NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
Internal function to get the start address of next signature list.
|
|
|
|
@param[in] SignatureList Pointer to EFI_SIGNATURE_LIST instance.
|
|
|
|
@retval NULL SignatureList is NULL or the data in SignatureList is incorrect.
|
|
@return EFI_SIGNATURE_LIST * Pointer to next signature list.
|
|
**/
|
|
STATIC
|
|
EFI_SIGNATURE_LIST *
|
|
GetNextSignatureList (
|
|
IN EFI_SIGNATURE_LIST *SignatureList
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internal function to get the start address of next signature list.
|
|
|
|
Arguments:
|
|
|
|
SignatureList - Pointer to EFI_SIGNATURE_LIST instance.
|
|
|
|
Returns:
|
|
|
|
NULL - SignatureList is NULL of the data in SignatureList is incorrect.
|
|
EFI_SIGNATURE_LIST * - Pointer to next signature list.
|
|
|
|
--*/
|
|
{
|
|
if (SignatureList == NULL || SignatureList->SignatureListSize < sizeof (EFI_SIGNATURE_LIST)) {
|
|
return NULL;
|
|
}
|
|
|
|
return (EFI_SIGNATURE_LIST *) ((UINT8 *) SignatureList + SignatureList->SignatureListSize);
|
|
}
|
|
|
|
/**
|
|
Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA+
|
|
will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA
|
|
will be ignored.
|
|
|
|
@param[in] AppendDataSize Size of NewData buffer.
|
|
@param[in] AppendDataBuffer Pointer to new EFI_SIGNATURE_LIST to be appended.
|
|
@param[in] TotalDataBufferSize Total size of data buffer which can be used.
|
|
@param[in, out] UsedDataBufferSize [in] Used data size by byte before invoking this function.
|
|
[out] Used data size by byte after invoking this function.
|
|
@param[in, out] DataBuffer [in] Buffer to save original variable data.
|
|
[out] Buffer to save merged variable data.
|
|
|
|
@retval EFI_SUCCESS Append data to singnature list successful.
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES Total variable data size is large than maximum buffer size.
|
|
**/
|
|
EFI_STATUS
|
|
AppendSignatureList (
|
|
IN UINTN AppendDataSize,
|
|
IN CONST UINT8 *AppendDataBuffer,
|
|
IN UINTN TotalDataBufferSize,
|
|
IN OUT UINTN *UsedDataBufferSize,
|
|
IN OUT UINT8 *DataBuffer
|
|
)
|
|
{
|
|
UINTN AppendDataOffset;
|
|
UINTN CurrentUsedDataSize;
|
|
EFI_SIGNATURE_LIST *WorkingAppendSig;
|
|
EFI_SIGNATURE_LIST *WorkingSig;
|
|
EFI_SIGNATURE_LIST *NextSig;
|
|
EFI_SIGNATURE_DATA *WorkingAppendSigData;
|
|
EFI_SIGNATURE_DATA *WorkingSigData;
|
|
UINTN DataOffest;
|
|
UINTN AppendSigCount;
|
|
UINTN SigCount;
|
|
UINTN AppendIndex;
|
|
UINTN CurrentIndex;
|
|
UINT32 CurrentSigSize;
|
|
UINT32 AppendSigSize;
|
|
BOOLEAN CertFound;
|
|
|
|
|
|
if (AppendDataSize == 0) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (AppendDataBuffer == NULL || UsedDataBufferSize == NULL || DataBuffer == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
CurrentUsedDataSize = *UsedDataBufferSize;
|
|
WorkingAppendSig = (EFI_SIGNATURE_LIST *) AppendDataBuffer;
|
|
|
|
//
|
|
// Paring whole appended signature list
|
|
//
|
|
AppendDataOffset = 0;
|
|
while (AppendDataOffset < AppendDataSize) {
|
|
//
|
|
// check append singnature list is a valid signature list
|
|
//
|
|
if (WorkingAppendSig->SignatureListSize < sizeof (EFI_SIGNATURE_LIST)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
AppendSigSize = WorkingAppendSig->SignatureSize;
|
|
AppendSigCount = (WorkingAppendSig->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - WorkingAppendSig->SignatureHeaderSize) / AppendSigSize;
|
|
WorkingAppendSigData = (EFI_SIGNATURE_DATA *) (((UINT8 *) WorkingAppendSig) + sizeof (EFI_SIGNATURE_LIST) + WorkingAppendSig->SignatureHeaderSize);
|
|
//
|
|
// Parsing specific appended signature list
|
|
//
|
|
for (AppendIndex = 0; AppendIndex < AppendSigCount; AppendIndex++) {
|
|
WorkingSig = (EFI_SIGNATURE_LIST *) DataBuffer;
|
|
CertFound = FALSE;
|
|
//
|
|
// Try to find matched signature (use signature type, signature owner and signature data) from whole existed signature list
|
|
//
|
|
DataOffest = 0;
|
|
while (DataOffest < CurrentUsedDataSize) {
|
|
if (CompareGuid (&WorkingSig->SignatureType, &WorkingAppendSig->SignatureType) &&
|
|
WorkingAppendSig->SignatureSize == WorkingSig->SignatureSize) {
|
|
CurrentSigSize = WorkingSig->SignatureSize;
|
|
SigCount = (WorkingSig->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - WorkingSig->SignatureHeaderSize) / CurrentSigSize;
|
|
WorkingSigData = (EFI_SIGNATURE_DATA *) (((UINT8 *) WorkingSig) + sizeof (EFI_SIGNATURE_LIST) + WorkingSig->SignatureHeaderSize);
|
|
for (CurrentIndex = 0; CurrentIndex < SigCount; CurrentIndex++) {
|
|
//
|
|
// compare certificated data and signature owner to confirm the existence of appended signature data
|
|
//
|
|
if (CompareMem (WorkingSigData, WorkingAppendSigData, CurrentSigSize) == 0) {
|
|
CertFound = TRUE;
|
|
break;
|
|
}
|
|
WorkingSigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) WorkingSigData + CurrentSigSize);
|
|
}
|
|
}
|
|
if (CertFound) {
|
|
break;
|
|
}
|
|
DataOffest += WorkingSig->SignatureListSize;
|
|
WorkingSig = GetNextSignatureList (WorkingSig);
|
|
if (WorkingSig == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Add signature data to current signature list if can not find mathced signature data
|
|
//
|
|
if (!CertFound) {
|
|
WorkingSig = FindCanMergeSig ((EFI_SIGNATURE_LIST *) DataBuffer, CurrentUsedDataSize, WorkingAppendSig);
|
|
if (WorkingSig != NULL) {
|
|
if (CurrentUsedDataSize + AppendSigSize > TotalDataBufferSize) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// merge appended signature node to signature list
|
|
//
|
|
NextSig = GetNextSignatureList (WorkingSig);
|
|
CopyMem (
|
|
(UINT8 *) NextSig + AppendSigSize,
|
|
NextSig,
|
|
CurrentUsedDataSize - (UINTN) ((UINT8 *) NextSig - DataBuffer)
|
|
);
|
|
CopyMem (NextSig, WorkingAppendSigData, AppendSigSize);
|
|
|
|
WorkingSig->SignatureListSize += AppendSigSize;
|
|
CurrentUsedDataSize += AppendSigSize;
|
|
} else {
|
|
if (CurrentUsedDataSize + sizeof (EFI_SIGNATURE_LIST) + AppendSigSize > TotalDataBufferSize) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
//
|
|
// Append signature list to the trail of signature list.
|
|
//
|
|
WorkingSig = (EFI_SIGNATURE_LIST *) (DataBuffer + CurrentUsedDataSize);
|
|
CopyMem (WorkingSig, WorkingAppendSig, sizeof (EFI_SIGNATURE_LIST));
|
|
WorkingSig->SignatureListSize = AppendSigSize + sizeof (EFI_SIGNATURE_LIST);
|
|
WorkingSig++;
|
|
CopyMem (WorkingSig, WorkingAppendSigData, AppendSigSize);
|
|
CurrentUsedDataSize += (sizeof (EFI_SIGNATURE_LIST) + AppendSigSize);
|
|
}
|
|
}
|
|
WorkingAppendSigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) WorkingAppendSigData + AppendSigSize);
|
|
}
|
|
AppendDataOffset += WorkingAppendSig->SignatureListSize;
|
|
WorkingAppendSig = GetNextSignatureList (WorkingAppendSig);
|
|
if (WorkingAppendSig == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
*UsedDataBufferSize = CurrentUsedDataSize;
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
/**
|
|
Compare two EFI_TIME data.
|
|
|
|
@param[in] FirstTime A pointer to the first EFI_TIME data.
|
|
@param[in] 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);
|
|
}
|
|
|
|
|
|
/**
|
|
This function uses to synchronize authenticated variable data and state between
|
|
runtime and SMM.
|
|
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
|
|
@retval EFI_SUCCESS Synchronize authenticated data and state successful.
|
|
**/
|
|
EFI_STATUS
|
|
SyncAuthData (
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
UINT8 *Data;
|
|
UINTN VariableCount;
|
|
UINT8 SecureBootEnforce;
|
|
KERNEL_CONFIGURATION *SystemConfiguration;
|
|
|
|
if (!FeaturePcdGet (PcdH2OSecureBootSupported)) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// Check PK database's existence to determine the SetupMode value.
|
|
// Then create a new "SetupMode" with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
|
|
//
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetimeInAllRegions (
|
|
EFI_PLATFORM_KEY_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
if (Variable.CurrPtr == NULL) {
|
|
mPlatformMode = SETUP_MODE;
|
|
mPlatformBootMode = SECURE_BOOT_MODE_DISABLE;
|
|
} else {
|
|
mPlatformMode = USER_MODE;
|
|
mPlatformBootMode = SECURE_BOOT_MODE_ENABLE;
|
|
Status = FindVariableByLifetime (
|
|
SETUP_VARIABLE_NAME,
|
|
&gSystemConfigurationGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
//
|
|
// Disable secure boot if boot mode isn't UEFI boot mode.
|
|
//
|
|
if (!EFI_ERROR (Status)) {
|
|
SystemConfiguration = (KERNEL_CONFIGURATION *) GetVariableDataPtr (Variable.CurrPtr);
|
|
if (SystemConfiguration->BootType != EFI_BOOT_TYPE) {
|
|
mPlatformBootMode = SECURE_BOOT_MODE_DISABLE;
|
|
}
|
|
}
|
|
//
|
|
// Disable secure boot, if SecureBootEnforce is disabled
|
|
//
|
|
if (mPlatformBootMode == SECURE_BOOT_MODE_ENABLE) {
|
|
Status = FindVariableByLifetime (
|
|
EFI_SECURE_BOOT_ENFORCE_NAME,
|
|
&gEfiGenericVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
SecureBootEnforce = 1;
|
|
if (!EFI_ERROR (Status)) {
|
|
Data = GetVariableDataPtr (Variable.CurrPtr);
|
|
SecureBootEnforce = (*Data == 1) ? 1 : 0;
|
|
}
|
|
mPlatformBootMode = (SecureBootEnforce == 1) ? SECURE_BOOT_MODE_ENABLE : SECURE_BOOT_MODE_DISABLE;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function uses to find secure boot database default variable.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[out] DataSize Size of variable data by byte.
|
|
@param[out] Data Data buffer to save variable data.
|
|
|
|
@retval EFI_SUCCESS Find input secure boot database default variable successful.
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_NOT_FOUND Cannot find secure boot database default variable.
|
|
**/
|
|
EFI_STATUS
|
|
FindSecureDatabaseDefaultVariables (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINTN *DataSize OPTIONAL,
|
|
OUT VOID **Data OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN HeaderSize;
|
|
UINTN CurrentSearchedSize;
|
|
VARIABLE_HEADER *VariableHeader;
|
|
VARIABLE_HEADER *NexVariable;
|
|
UINTN Index;
|
|
UINTN MaxTableNum;
|
|
BOOLEAN CheckFunFound;
|
|
BOOLEAN VariableFound;
|
|
SPECIFIC_VARIABLE CheckFunTable[][2] = {
|
|
{IsPkVariable, IsPkDefaultVariable},
|
|
{IsKekVariable, IsKekDefaultVariable},
|
|
{IsDbVariable, IsDbDefaultVariable},
|
|
{IsDbxVariable, IsDbxDefaultVariable},
|
|
{IsDbtVariable, IsDbtDefaultVariable},
|
|
{IsDbrVariable, IsDbrDefaultVariable}
|
|
};
|
|
|
|
if (!IsSecureDatabaseDefaultVariable (VariableName, VendorGuid)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
HeaderSize = sizeof (UINT64) + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + GetVariableStoreHeaderSize ();
|
|
if (HeaderSize > mVariableModuleGlobal->FactoryDefaultSize) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
//
|
|
// Doesn't support TimestampSignatureDatabase if EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION is disabled.
|
|
//
|
|
if ((PcdGet64 (PcdOsIndicationsSupported) & EFI_OS_INDICATIONS_TIMESTAMP_REVOCATION) == 0) {
|
|
CheckFunTable[4][1] = NULL;
|
|
}
|
|
//
|
|
// Doesn't support RecoverySignatureDatabase if EFI_OS_INDICATIONS_START_OS_RECOVERY is disabled.
|
|
//
|
|
if ((PcdGet64 (PcdOsIndicationsSupported) & EFI_OS_INDICATIONS_START_OS_RECOVERY) == 0) {
|
|
CheckFunTable[5][1] = NULL;
|
|
}
|
|
|
|
MaxTableNum = sizeof (CheckFunTable) / (sizeof (SPECIFIC_VARIABLE) * 2);
|
|
CheckFunFound = FALSE;
|
|
for (Index = 0; Index < MaxTableNum; Index++) {
|
|
if (CheckFunTable[Index][1] != NULL && CheckFunTable[Index][1] (VariableName, VendorGuid)) {
|
|
CheckFunFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!CheckFunFound) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
VariableHeader = (VARIABLE_HEADER *) ((UINTN) mVariableModuleGlobal->FactoryDefaultCache + HeaderSize);
|
|
CurrentSearchedSize = HeaderSize;
|
|
VariableFound = FALSE;
|
|
while (IsValidVariableHeader (VariableHeader) && CurrentSearchedSize < mVariableModuleGlobal->FactoryDefaultSize) {
|
|
NexVariable = GetNextVariablePtr (VariableHeader);
|
|
if (VariableHeader->State == VAR_ADDED && CheckFunTable[Index][0] (GET_VARIABLE_NAME_PTR (VariableHeader), &VariableHeader->VendorGuid)) {
|
|
VariableFound = TRUE;
|
|
break;
|
|
}
|
|
CurrentSearchedSize += ((UINTN) NexVariable - (UINTN) VariableHeader);
|
|
VariableHeader = NexVariable;
|
|
}
|
|
|
|
if (!VariableFound && !IsDbxDefaultVariable (VariableName, VendorGuid)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Needn't output data size and data, so just return EFI_SUCCESS.
|
|
//
|
|
if (DataSize == NULL || Data == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Get variable data and variable size
|
|
//
|
|
if (VariableFound) {
|
|
*Data = GetVariableDataPtr (VariableHeader);
|
|
*DataSize = VariableHeader->DataSize;
|
|
} else {
|
|
*DataSize = APPEND_BUFF_SIZE;
|
|
Status = CreateDummyDbxData (DataSize, mStorageArea);
|
|
ASSERT_EFI_ERROR (Status);
|
|
*Data = mStorageArea;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function uses to get secure boot database default variable.
|
|
|
|
@param[in] VariableName Name of Variable to be found.
|
|
@param[in] VendorGuid Variable vendor GUID.
|
|
@param[out] Attributes Attribute value of the variable found.
|
|
@param[in, out] DataSize Size of Data found. If size is less than the
|
|
data, this value contains the required size.
|
|
@param[out] Data Data buffer to save variable data.
|
|
|
|
@retval EFI_SUCCESS Get secure boot database default variable successful.
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_NOT_FOUND Cannot find secure boot database default variable.
|
|
@retval EFI_BUFFER_TOO_SMALL Find Secure boot database default variable but input buffer size
|
|
is too small.
|
|
**/
|
|
EFI_STATUS
|
|
GetSecureDatabaseDefaultVariables (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
OUT UINT32 *Attributes OPTIONAL,
|
|
IN OUT UINTN *DataSize,
|
|
OUT VOID *Data
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN VariableSize;
|
|
UINT8 *VariableData;
|
|
|
|
Status = FindSecureDatabaseDefaultVariables (VariableName, VendorGuid, &VariableSize, (VOID **)&VariableData);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (VariableSize > *DataSize) {
|
|
*DataSize = VariableSize;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
if (Attributes != NULL) {
|
|
*Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
|
|
}
|
|
|
|
CopyMem (Data, VariableData, VariableSize);
|
|
*DataSize = VariableSize;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Update platform boot mode.
|
|
|
|
@param[in] Mode SECURE_BOOT_MODE_ENABLE or SECURE_BOOT_MODE_DISABLE.
|
|
@param[in] Global Pointer to VARIABLE_GLOBAL instance.
|
|
**/
|
|
VOID
|
|
UpdatePlatformBootMode (
|
|
IN UINT32 Mode,
|
|
IN VARIABLE_GLOBAL *Global
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_POINTER_TRACK Variable;
|
|
UINT32 VarAttr;
|
|
UINTN VariableCount;
|
|
|
|
|
|
if (VariableAtRuntime ()) {
|
|
//
|
|
// SecureBoot Variable indicates whether the platform firmware is operating
|
|
// in Secure boot mode (1) or not (0), so we should not change SecureBoot
|
|
// Variable in runtime.
|
|
//
|
|
return;
|
|
}
|
|
VariableCount = 0;
|
|
Status = FindVariableByLifetime (
|
|
EFI_SECURE_BOOT_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&Variable,
|
|
&VariableCount,
|
|
Global
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
mPlatformBootMode = Mode;
|
|
|
|
VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
|
|
Status = UpdateVariable (
|
|
EFI_SECURE_BOOT_MODE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
&mPlatformBootMode,
|
|
sizeof (UINT8),
|
|
VarAttr,
|
|
0,
|
|
0,
|
|
&Variable,
|
|
NULL,
|
|
Global
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|