mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
Just require PcdRequireSelfSignedPk=FALSE instead of using CustomMode to
enroll PK keys which are not self-signed.
PcdRequireSelfSignedPk=FALSE is the default configuration for OVMF since
commit 3c01a11daa ("OvmfPkg: set PcdRequireSelfSignedPk to FALSE").
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
218 lines
5.5 KiB
C
218 lines
5.5 KiB
C
/** @file
|
|
Enroll secure boot variables passed in via IGVM
|
|
|
|
Copyright (C) 2025, Red Hat, Inc.
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include <Guid/AuthenticatedVariableFormat.h>
|
|
#include <IndustryStandard/IgvmData.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
|
|
STATIC EFI_IGVM_DATA_HOB *mPK;
|
|
STATIC EFI_IGVM_DATA_HOB *mKEK;
|
|
STATIC EFI_IGVM_DATA_HOB *mDb;
|
|
STATIC EFI_IGVM_DATA_HOB *mDbx;
|
|
|
|
STATIC
|
|
EFI_STATUS
|
|
IgvmSecureBootFindBlobs (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_HOB_GUID_TYPE *Hob;
|
|
EFI_IGVM_DATA_HOB *IgvmData;
|
|
CHAR16 *Name;
|
|
|
|
for (Hob = GetFirstGuidHob (&gEfiIgvmDataHobGuid);
|
|
Hob != NULL;
|
|
Hob = GetNextGuidHob (&gEfiIgvmDataHobGuid, GET_NEXT_HOB (Hob)))
|
|
{
|
|
IgvmData = (VOID *)(Hob + 1);
|
|
|
|
switch (IgvmData->DataType) {
|
|
case 0x100:
|
|
Name = L"PK";
|
|
mPK = IgvmData;
|
|
break;
|
|
case 0x101:
|
|
Name = L"KEK";
|
|
mKEK = IgvmData;
|
|
break;
|
|
case 0x102:
|
|
Name = L"db";
|
|
mDb = IgvmData;
|
|
break;
|
|
case 0x103:
|
|
Name = L"dbx";
|
|
mDbx = IgvmData;
|
|
break;
|
|
default:
|
|
Name = NULL;
|
|
break;
|
|
}
|
|
|
|
if (Name) {
|
|
DEBUG ((
|
|
DEBUG_INFO,
|
|
"%a: address=0x%lx length=0x%lx type=0x%x name=%s\n",
|
|
__func__,
|
|
IgvmData->Address,
|
|
IgvmData->Length,
|
|
IgvmData->DataType,
|
|
Name
|
|
));
|
|
}
|
|
}
|
|
|
|
if (!mPK) {
|
|
DEBUG ((DEBUG_INFO, "%a: missing: PK\n", __func__));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (!mKEK) {
|
|
DEBUG ((DEBUG_INFO, "%a: missing: KEK\n", __func__));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (!mDb) {
|
|
DEBUG ((DEBUG_INFO, "%a: missing: db\n", __func__));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (!mDbx) {
|
|
DEBUG ((DEBUG_INFO, "%a: missing: dbx\n", __func__));
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IgvmSecureBootSetVariable (
|
|
IN CHAR16 *Name,
|
|
IN EFI_GUID *Guid,
|
|
EFI_IGVM_DATA_HOB *Hob
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 Length = Hob->Length;
|
|
VOID *Data = (VOID *)(UINTN)Hob->Address;
|
|
UINT32 Attributes = (EFI_VARIABLE_NON_VOLATILE |
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
|
EFI_VARIABLE_RUNTIME_ACCESS |
|
|
EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS);
|
|
|
|
Status = gRT->SetVariable (Name, Guid, Attributes, Length, Data);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_ERROR, "%a: set %s: %r\n", __func__, Name, Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN
|
|
EFIAPI
|
|
IgvmSecureBootIsConfigured (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN Result;
|
|
UINTN Size;
|
|
|
|
Status = gRT->GetVariable (
|
|
L"PK",
|
|
&gEfiGlobalVariableGuid,
|
|
NULL,
|
|
&Size,
|
|
NULL
|
|
);
|
|
|
|
if (Status == EFI_NOT_FOUND) {
|
|
Result = FALSE;
|
|
} else {
|
|
Result = TRUE;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%a: Result=%a\n", __func__, Result ? "Yes" : "No"));
|
|
return Result;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IgvmSecureBootDxeEntrypoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 CcAttr;
|
|
|
|
CcAttr = PcdGet64 (PcdConfidentialComputingGuestAttr);
|
|
|
|
if (!CcAttr) {
|
|
/*
|
|
* The design idea is that the pages containing the HOBs and the EFI
|
|
* security databases are part of the launch measurement of a confidential
|
|
* VM. This way the launch measurement will not only prove the guest runs
|
|
* the firmware code it is supposed to run, but also prove secure boot is
|
|
* configured the way it is supposed to be.
|
|
*
|
|
* Any code loaded by the firmware will be subject to standard secure boot
|
|
* verification:
|
|
* - Option one is to use code signing and add the x509 vertificates to
|
|
* 'db' (and revocation list to 'dbx'), which is the typical setup in
|
|
* non-confidential VMs.
|
|
* - More strict option two is to only allow specific efi binaries by
|
|
* adding the sha256 authenticode hashes to 'db'.
|
|
*
|
|
* This workflow can only work in confidential VMs, so error out otherwise.
|
|
*/
|
|
DEBUG ((DEBUG_ERROR, "%a: ERROR: not running in Confidential VM\n", __func__));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (FeaturePcdGet (PcdRequireSelfSignedPk) != FALSE) {
|
|
DEBUG ((DEBUG_ERROR, "%a: ERROR: this driver requires PcdRequireSelfSignedPk=FALSE.\n", __func__));
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (IgvmSecureBootIsConfigured ()) {
|
|
DEBUG ((DEBUG_ERROR, "%a: secure boot is already configured.\n", __func__));
|
|
return EFI_ALREADY_STARTED;
|
|
}
|
|
|
|
Status = IgvmSecureBootFindBlobs ();
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = IgvmSecureBootSetVariable (L"dbx", &gEfiImageSecurityDatabaseGuid, mDbx);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = IgvmSecureBootSetVariable (L"db", &gEfiImageSecurityDatabaseGuid, mDb);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = IgvmSecureBootSetVariable (L"KEK", &gEfiGlobalVariableGuid, mKEK);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = IgvmSecureBootSetVariable (L"PK", &gEfiGlobalVariableGuid, mPK);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "%a: secure boot setup complete\n", __func__));
|
|
return EFI_REQUEST_UNLOAD_IMAGE;
|
|
}
|