blob: cb362c12420f8a3c544b8c62fbf2bb7bd07c9df4 [file] [log] [blame]
/** @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;
}
EFI_STATUS
EFIAPI
IgvmSecureBootCustomMode (
UINT8 Value
)
{
EFI_STATUS Status;
Status = gRT->SetVariable (
EFI_CUSTOM_MODE_NAME,
&gEfiCustomModeEnableGuid,
(EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS),
sizeof (Value),
&Value
);
if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_ERROR,
"%a: %a CustomMode: %r\n",
__func__,
Value ? "enable" : "disable",
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 (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;
}
// allow setting a platform key (PK) which is not self-signed
Status = IgvmSecureBootCustomMode (TRUE);
if (EFI_ERROR (Status)) {
return Status;
}
Status = IgvmSecureBootSetVariable (L"PK", &gEfiGlobalVariableGuid, mPK);
if (EFI_ERROR (Status)) {
return Status;
}
Status = IgvmSecureBootCustomMode (FALSE);
if (EFI_ERROR (Status)) {
return Status;
}
DEBUG ((DEBUG_INFO, "%a: secure boot setup complete\n", __func__));
return EFI_REQUEST_UNLOAD_IMAGE;
}