mirror of https://github.com/acidanthera/audk.git
574 lines
16 KiB
C
574 lines
16 KiB
C
/** @file
|
|
This library provides functions to set/clear Secure Boot
|
|
keys and databases.
|
|
|
|
Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
|
|
Copyright (c) 2021, ARM Ltd. All rights reserved.<BR>
|
|
Copyright (c) 2021, Semihalf All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
#include <Uefi.h>
|
|
#include <UefiSecureBoot.h>
|
|
#include <Guid/GlobalVariable.h>
|
|
#include <Guid/AuthenticatedVariableFormat.h>
|
|
#include <Guid/ImageAuthentication.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseCryptLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Library/SecureBootVariableLib.h>
|
|
#include <Library/SecureBootVariableProvisionLib.h>
|
|
#include <Library/DxeServicesLib.h>
|
|
|
|
/**
|
|
Create a EFI Signature List with data fetched from section specified as a argument.
|
|
Found keys are verified using RsaGetPublicKeyFromX509().
|
|
|
|
@param[in] KeyFileGuid A pointer to to the FFS filename GUID
|
|
@param[out] SigListsSize A pointer to size of signature list
|
|
@param[out] SigListOut a pointer to a callee-allocated buffer with signature lists
|
|
|
|
@retval EFI_SUCCESS Create time based payload successfully.
|
|
@retval EFI_NOT_FOUND Section with key has not been found.
|
|
@retval EFI_INVALID_PARAMETER Embedded key has a wrong format.
|
|
@retval Others Unexpected error happens.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
SecureBootFetchData (
|
|
IN EFI_GUID *KeyFileGuid,
|
|
OUT UINTN *SigListsSize,
|
|
OUT EFI_SIGNATURE_LIST **SigListOut
|
|
)
|
|
{
|
|
EFI_SIGNATURE_LIST *EfiSig;
|
|
EFI_STATUS Status;
|
|
VOID *Buffer;
|
|
VOID *RsaPubKey;
|
|
UINTN Size;
|
|
UINTN KeyIndex;
|
|
UINTN Index;
|
|
SECURE_BOOT_CERTIFICATE_INFO *CertInfo;
|
|
SECURE_BOOT_CERTIFICATE_INFO *NewCertInfo;
|
|
|
|
KeyIndex = 0;
|
|
EfiSig = NULL;
|
|
*SigListOut = NULL;
|
|
*SigListsSize = 0;
|
|
CertInfo = AllocatePool (sizeof (SECURE_BOOT_CERTIFICATE_INFO));
|
|
NewCertInfo = CertInfo;
|
|
while (1) {
|
|
if (NewCertInfo == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
break;
|
|
} else {
|
|
CertInfo = NewCertInfo;
|
|
}
|
|
|
|
Status = GetSectionFromAnyFv (
|
|
KeyFileGuid,
|
|
EFI_SECTION_RAW,
|
|
KeyIndex,
|
|
&Buffer,
|
|
&Size
|
|
);
|
|
|
|
if (Status == EFI_SUCCESS) {
|
|
RsaPubKey = NULL;
|
|
if (RsaGetPublicKeyFromX509 (Buffer, Size, &RsaPubKey) == FALSE) {
|
|
DEBUG ((DEBUG_ERROR, "%a: Invalid key format: %d\n", __func__, KeyIndex));
|
|
if (EfiSig != NULL) {
|
|
FreePool (EfiSig);
|
|
}
|
|
|
|
FreePool (Buffer);
|
|
Status = EFI_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
CertInfo[KeyIndex].Data = Buffer;
|
|
CertInfo[KeyIndex].DataSize = Size;
|
|
KeyIndex++;
|
|
NewCertInfo = ReallocatePool (
|
|
sizeof (SECURE_BOOT_CERTIFICATE_INFO) * KeyIndex,
|
|
sizeof (SECURE_BOOT_CERTIFICATE_INFO) * (KeyIndex + 1),
|
|
CertInfo
|
|
);
|
|
}
|
|
|
|
if (Status == EFI_NOT_FOUND) {
|
|
Status = EFI_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (KeyIndex == 0) {
|
|
Status = EFI_NOT_FOUND;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Now that we collected all certs from FV, convert it into sig list
|
|
Status = SecureBootCreateDataFromInput (SigListsSize, SigListOut, KeyIndex, CertInfo);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
if (CertInfo) {
|
|
for (Index = 0; Index < KeyIndex; Index++) {
|
|
FreePool ((VOID *)CertInfo[Index].Data);
|
|
}
|
|
|
|
FreePool (CertInfo);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Enroll a key/certificate based on a default variable.
|
|
|
|
@param[in] VariableName The name of the key/database.
|
|
@param[in] DefaultName The name of the default variable.
|
|
@param[in] VendorGuid The namespace (ie. vendor GUID) of the variable
|
|
|
|
@retval EFI_OUT_OF_RESOURCES Out of memory while allocating AuthHeader.
|
|
@retval EFI_SUCCESS Successful enrollment.
|
|
@return Error codes from GetTime () and SetVariable ().
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EnrollFromDefault (
|
|
IN CHAR16 *VariableName,
|
|
IN CHAR16 *DefaultName,
|
|
IN EFI_GUID *VendorGuid
|
|
)
|
|
{
|
|
VOID *Data;
|
|
UINTN DataSize;
|
|
EFI_STATUS Status;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
DataSize = 0;
|
|
Status = GetVariable2 (DefaultName, &gEfiGlobalVariableGuid, &Data, &DataSize);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "error: GetVariable (\"%s): %r\n", DefaultName, Status));
|
|
return Status;
|
|
}
|
|
|
|
Status = EnrollFromInput (VariableName, VendorGuid, DataSize, Data);
|
|
|
|
if (Data != NULL) {
|
|
FreePool (Data);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Initializes PKDefault variable with data from FFS section.
|
|
|
|
@retval EFI_SUCCESS Variable was initialized successfully.
|
|
@retval EFI_UNSUPPORTED Variable already exists.
|
|
**/
|
|
EFI_STATUS
|
|
SecureBootInitPKDefault (
|
|
IN VOID
|
|
)
|
|
{
|
|
EFI_SIGNATURE_LIST *EfiSig;
|
|
UINTN SigListsSize;
|
|
EFI_STATUS Status;
|
|
UINT8 *Data;
|
|
UINTN DataSize;
|
|
|
|
//
|
|
// Check if variable exists, if so do not change it
|
|
//
|
|
Status = GetVariable2 (EFI_PK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize);
|
|
if (Status == EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_PK_DEFAULT_VARIABLE_NAME));
|
|
FreePool (Data);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Variable does not exist, can be initialized
|
|
//
|
|
DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_PK_DEFAULT_VARIABLE_NAME));
|
|
|
|
Status = SecureBootFetchData (&gDefaultPKFileGuid, &SigListsSize, &EfiSig);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Content for %s not found\n", EFI_PK_DEFAULT_VARIABLE_NAME));
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
EFI_PK_DEFAULT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
SigListsSize,
|
|
(VOID *)EfiSig
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_PK_DEFAULT_VARIABLE_NAME));
|
|
}
|
|
|
|
FreePool (EfiSig);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Initializes KEKDefault variable with data from FFS section.
|
|
|
|
@retval EFI_SUCCESS Variable was initialized successfully.
|
|
@retval EFI_UNSUPPORTED Variable already exists.
|
|
**/
|
|
EFI_STATUS
|
|
SecureBootInitKEKDefault (
|
|
IN VOID
|
|
)
|
|
{
|
|
EFI_SIGNATURE_LIST *EfiSig;
|
|
UINTN SigListsSize;
|
|
EFI_STATUS Status;
|
|
UINT8 *Data;
|
|
UINTN DataSize;
|
|
|
|
//
|
|
// Check if variable exists, if so do not change it
|
|
//
|
|
Status = GetVariable2 (EFI_KEK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize);
|
|
if (Status == EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_KEK_DEFAULT_VARIABLE_NAME));
|
|
FreePool (Data);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Variable does not exist, can be initialized
|
|
//
|
|
DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_KEK_DEFAULT_VARIABLE_NAME));
|
|
|
|
Status = SecureBootFetchData (&gDefaultKEKFileGuid, &SigListsSize, &EfiSig);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Content for %s not found\n", EFI_KEK_DEFAULT_VARIABLE_NAME));
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
EFI_KEK_DEFAULT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
SigListsSize,
|
|
(VOID *)EfiSig
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_KEK_DEFAULT_VARIABLE_NAME));
|
|
}
|
|
|
|
FreePool (EfiSig);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Initializes dbDefault variable with data from FFS section.
|
|
|
|
@retval EFI_SUCCESS Variable was initialized successfully.
|
|
@retval EFI_UNSUPPORTED Variable already exists.
|
|
**/
|
|
EFI_STATUS
|
|
SecureBootInitDbDefault (
|
|
IN VOID
|
|
)
|
|
{
|
|
EFI_SIGNATURE_LIST *EfiSig;
|
|
UINTN SigListsSize;
|
|
EFI_STATUS Status;
|
|
UINT8 *Data;
|
|
UINTN DataSize;
|
|
|
|
Status = GetVariable2 (EFI_DB_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize);
|
|
if (Status == EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_DB_DEFAULT_VARIABLE_NAME));
|
|
FreePool (Data);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
|
|
return Status;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_DB_DEFAULT_VARIABLE_NAME));
|
|
|
|
Status = SecureBootFetchData (&gDefaultdbFileGuid, &SigListsSize, &EfiSig);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
EFI_DB_DEFAULT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
SigListsSize,
|
|
(VOID *)EfiSig
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_DB_DEFAULT_VARIABLE_NAME));
|
|
}
|
|
|
|
FreePool (EfiSig);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Initializes dbxDefault variable with data from FFS section.
|
|
|
|
@retval EFI_SUCCESS Variable was initialized successfully.
|
|
@retval EFI_UNSUPPORTED Variable already exists.
|
|
**/
|
|
EFI_STATUS
|
|
SecureBootInitDbxDefault (
|
|
IN VOID
|
|
)
|
|
{
|
|
EFI_SIGNATURE_LIST *EfiSig;
|
|
UINTN SigListsSize;
|
|
EFI_STATUS Status;
|
|
UINT8 *Data;
|
|
UINTN DataSize;
|
|
|
|
//
|
|
// Check if variable exists, if so do not change it
|
|
//
|
|
Status = GetVariable2 (EFI_DBX_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize);
|
|
if (Status == EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_DBX_DEFAULT_VARIABLE_NAME));
|
|
FreePool (Data);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Variable does not exist, can be initialized
|
|
//
|
|
DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_DBX_DEFAULT_VARIABLE_NAME));
|
|
|
|
Status = SecureBootFetchData (&gDefaultdbxFileGuid, &SigListsSize, &EfiSig);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Content for %s not found\n", EFI_DBX_DEFAULT_VARIABLE_NAME));
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
EFI_DBX_DEFAULT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
SigListsSize,
|
|
(VOID *)EfiSig
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_DBX_DEFAULT_VARIABLE_NAME));
|
|
}
|
|
|
|
FreePool (EfiSig);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Initializes dbtDefault variable with data from FFS section.
|
|
|
|
@retval EFI_SUCCESS Variable was initialized successfully.
|
|
@retval EFI_UNSUPPORTED Variable already exists.
|
|
**/
|
|
EFI_STATUS
|
|
SecureBootInitDbtDefault (
|
|
IN VOID
|
|
)
|
|
{
|
|
EFI_SIGNATURE_LIST *EfiSig;
|
|
UINTN SigListsSize;
|
|
EFI_STATUS Status;
|
|
UINT8 *Data;
|
|
UINTN DataSize;
|
|
|
|
//
|
|
// Check if variable exists, if so do not change it
|
|
//
|
|
Status = GetVariable2 (EFI_DBT_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize);
|
|
if (Status == EFI_SUCCESS) {
|
|
DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_DBT_DEFAULT_VARIABLE_NAME));
|
|
FreePool (Data);
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Variable does not exist, can be initialized
|
|
//
|
|
DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_DBT_DEFAULT_VARIABLE_NAME));
|
|
|
|
Status = SecureBootFetchData (&gDefaultdbtFileGuid, &SigListsSize, &EfiSig);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gRT->SetVariable (
|
|
EFI_DBT_DEFAULT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid,
|
|
EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
|
SigListsSize,
|
|
(VOID *)EfiSig
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_DBT_DEFAULT_VARIABLE_NAME));
|
|
}
|
|
|
|
FreePool (EfiSig);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Sets the content of the 'db' variable based on 'dbDefault' variable content.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
|
|
while VendorGuid is NULL.
|
|
@retval other Errors from GetVariable2 (), GetTime () and SetVariable ()
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EnrollDbFromDefault (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EnrollFromDefault (
|
|
EFI_IMAGE_SECURITY_DATABASE,
|
|
EFI_DB_DEFAULT_VARIABLE_NAME,
|
|
&gEfiImageSecurityDatabaseGuid
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Sets the content of the 'dbx' variable based on 'dbxDefault' variable content.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
|
|
while VendorGuid is NULL.
|
|
@retval other Errors from GetVariable2 (), GetTime () and SetVariable ()
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EnrollDbxFromDefault (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EnrollFromDefault (
|
|
EFI_IMAGE_SECURITY_DATABASE1,
|
|
EFI_DBX_DEFAULT_VARIABLE_NAME,
|
|
&gEfiImageSecurityDatabaseGuid
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Sets the content of the 'dbt' variable based on 'dbtDefault' variable content.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
|
|
while VendorGuid is NULL.
|
|
@retval other Errors from GetVariable2 (), GetTime () and SetVariable ()
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EnrollDbtFromDefault (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EnrollFromDefault (
|
|
EFI_IMAGE_SECURITY_DATABASE2,
|
|
EFI_DBT_DEFAULT_VARIABLE_NAME,
|
|
&gEfiImageSecurityDatabaseGuid
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Sets the content of the 'KEK' variable based on 'KEKDefault' variable content.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
|
|
while VendorGuid is NULL.
|
|
@retval other Errors from GetVariable2 (), GetTime () and SetVariable ()
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EnrollKEKFromDefault (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EnrollFromDefault (
|
|
EFI_KEY_EXCHANGE_KEY_NAME,
|
|
EFI_KEK_DEFAULT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Sets the content of the 'KEK' variable based on 'KEKDefault' variable content.
|
|
|
|
@retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
|
|
while VendorGuid is NULL.
|
|
@retval other Errors from GetVariable2 (), GetTime () and SetVariable ()
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
EnrollPKFromDefault (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EnrollFromDefault (
|
|
EFI_PLATFORM_KEY_NAME,
|
|
EFI_PK_DEFAULT_VARIABLE_NAME,
|
|
&gEfiGlobalVariableGuid
|
|
);
|
|
|
|
return Status;
|
|
}
|