From 2dc1e515930d3fe2610fb1deaa1164033c2da4e9 Mon Sep 17 00:00:00 2001 From: Sean Rhodes Date: Mon, 3 Jan 2022 15:56:05 +0000 Subject: [PATCH] UefiPayloadPkg: Add Secure Boot support Cc: Guo Dong Cc: Ray Ni Cc: Maurice Ma Cc: Benjamin You Signed-off-by: Sean Rhodes Change-Id: I4f44e29bc967b7d2208193e21aeeef8b96afcc69 --- .../SecureBootVariableProvisionLib.c | 22 +- .../SecureBootSetup.c | 410 ++++++++++++++++++ .../SecureBootSetup.inf | 56 +++ .../SecureBootSetup.uni | 21 + .../SecureBootSetupExtra.uni | 17 + UefiPayloadPkg/UefiPayloadPkg.dsc | 68 ++- UefiPayloadPkg/UefiPayloadPkg.fdf | 33 +- UefiVariableBinary/UefiVariableBinary.dsc | 20 + UefiVariableBinary/UefiVariableBinary.fdf | 31 ++ .../keys/MicCorKEKCA2011_2011-06-24.crt | Bin 0 -> 1516 bytes .../keys/MicWinProPCA2011_2011-10-19.crt | Bin 0 -> 1499 bytes UefiVariableBinary/keys/README | 8 + UefiVariableBinary/keys/dbxupdate_x64.bin | Bin 0 -> 13501 bytes UefiVariableBinary/keys/pk.crt | Bin 0 -> 1005 bytes 14 files changed, 674 insertions(+), 12 deletions(-) create mode 100644 UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.c create mode 100644 UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.inf create mode 100644 UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.uni create mode 100644 UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetupExtra.uni create mode 100644 UefiVariableBinary/UefiVariableBinary.dsc create mode 100644 UefiVariableBinary/UefiVariableBinary.fdf create mode 100644 UefiVariableBinary/keys/MicCorKEKCA2011_2011-06-24.crt create mode 100644 UefiVariableBinary/keys/MicWinProPCA2011_2011-10-19.crt create mode 100644 UefiVariableBinary/keys/README create mode 100644 UefiVariableBinary/keys/dbxupdate_x64.bin create mode 100644 UefiVariableBinary/keys/pk.crt diff --git a/SecurityPkg/Library/SecureBootVariableProvisionLib/SecureBootVariableProvisionLib.c b/SecurityPkg/Library/SecureBootVariableProvisionLib/SecureBootVariableProvisionLib.c index 536b0f3699..e8f0805e1f 100644 --- a/SecurityPkg/Library/SecureBootVariableProvisionLib/SecureBootVariableProvisionLib.c +++ b/SecurityPkg/Library/SecureBootVariableProvisionLib/SecureBootVariableProvisionLib.c @@ -19,6 +19,7 @@ #include #include #include +#include /** Enroll a key/certificate based on a default variable. @@ -117,6 +118,7 @@ SecureBootInitPKDefault ( } if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + DEBUG ((DEBUG_INFO, "Variable %s read error.\n", EFI_PK_DEFAULT_VARIABLE_NAME)); return Status; } @@ -264,10 +266,10 @@ SecureBootInitDbxDefault ( IN VOID ) { - EFI_SIGNATURE_LIST *EfiSig; - UINTN SigListsSize; + UINTN Size; EFI_STATUS Status; - UINT8 *Data; + UINT8 *Data; + VOID *Buffer; UINTN DataSize; // @@ -289,7 +291,13 @@ SecureBootInitDbxDefault ( // DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_DBX_DEFAULT_VARIABLE_NAME)); - Status = SecureBootFetchData (&gDefaultdbxFileGuid, &SigListsSize, &EfiSig); + Status = GetSectionFromAnyFv ( + &gDefaultdbxFileGuid, + EFI_SECTION_RAW, + 0, + &Buffer, + &Size + ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Content for %s not found\n", EFI_DBX_DEFAULT_VARIABLE_NAME)); return Status; @@ -299,15 +307,13 @@ SecureBootInitDbxDefault ( EFI_DBX_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, - SigListsSize, - (VOID *)EfiSig + Size, + (VOID *)Buffer ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_DBX_DEFAULT_VARIABLE_NAME)); } - FreePool (EfiSig); - return Status; } diff --git a/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.c b/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.c new file mode 100644 index 0000000000..bec0ad6077 --- /dev/null +++ b/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.c @@ -0,0 +1,410 @@ +/** @file + Enroll default PK, KEK, DB and DBX + + Copyright (C) 2014, Red Hat, Inc. + + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + **/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +STATIC +EFI_STATUS +EFIAPI +GetExact ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VOID *Data, + IN UINTN DataSize, + IN BOOLEAN AllowMissing + ) +{ + UINTN Size; + EFI_STATUS Status; + + Size = DataSize; + Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &Size, Data); + if (EFI_ERROR (Status)) { + if ((Status == EFI_NOT_FOUND) && AllowMissing) { + ZeroMem (Data, DataSize); + return EFI_SUCCESS; + } + + DEBUG (( + EFI_D_ERROR, + "SecureBootSetup: GetVariable(\"%s\", %g): %r\n", + VariableName, + VendorGuid, + Status + )); + return Status; + } + + if (Size != DataSize) { + DEBUG (( + EFI_D_INFO, + "SecureBootSetup: GetVariable(\"%s\", %g): expected size 0x%Lx, " + "got 0x%Lx\n", + VariableName, + VendorGuid, + (UINT64)DataSize, + (UINT64)Size + )); + return EFI_PROTOCOL_ERROR; + } + + return EFI_SUCCESS; +} + +typedef struct { + UINT8 SetupMode; + UINT8 SecureBoot; + UINT8 SecureBootEnable; + UINT8 CustomMode; + UINT8 VendorKeys; +} SETTINGS; + +STATIC +EFI_STATUS +EFIAPI +GetSettings ( + OUT SETTINGS *Settings, + BOOLEAN AllowMissing + ) +{ + EFI_STATUS Status; + + ZeroMem (Settings, sizeof (SETTINGS)); + + Status = GetExact ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &Settings->SetupMode, + sizeof Settings->SetupMode, + AllowMissing + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GetExact ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &Settings->SecureBoot, + sizeof Settings->SecureBoot, + AllowMissing + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GetExact ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &Settings->SecureBootEnable, + sizeof Settings->SecureBootEnable, + AllowMissing + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GetExact ( + EFI_CUSTOM_MODE_NAME, + &gEfiCustomModeEnableGuid, + &Settings->CustomMode, + sizeof Settings->CustomMode, + AllowMissing + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GetExact ( + EFI_VENDOR_KEYS_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + &Settings->VendorKeys, + sizeof Settings->VendorKeys, + AllowMissing + ); + return Status; +} + +STATIC +VOID +EFIAPI +PrintSettings ( + IN CONST SETTINGS *Settings + ) +{ + DEBUG (( + EFI_D_INFO, + "SecureBootSetup: SetupMode=%d SecureBoot=%d SecureBootEnable=%d " + "CustomMode=%d VendorKeys=%d\n", + Settings->SetupMode, + Settings->SecureBoot, + Settings->SecureBootEnable, + Settings->CustomMode, + Settings->VendorKeys + )); +} + +/** + Install SecureBoot certificates once the VariableDriver is running. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context +**/ +VOID +EFIAPI +InstallSecureBootHook ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *Protocol; + SETTINGS Settings; + + Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol); + if (EFI_ERROR (Status)) { + return; + } + + Status = GetSettings (&Settings, TRUE); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "SecureBootSetup: Failed to get current settings\n")); + return; + } + + if (Settings.SetupMode != SETUP_MODE) { + DEBUG ((EFI_D_ERROR, "SecureBootSetup: already in User Mode\n")); + return; + } + + if (Settings.SecureBootEnable != SECURE_BOOT_MODE_ENABLE) { + DEBUG ((EFI_D_ERROR, "SecureBootSetup: SecureBootEnable is disabled.\n")); + return; + } + + PrintSettings (&Settings); + + if (Settings.CustomMode != CUSTOM_SECURE_BOOT_MODE) { + Settings.CustomMode = CUSTOM_SECURE_BOOT_MODE; + Status = gRT->SetVariable ( + EFI_CUSTOM_MODE_NAME, + &gEfiCustomModeEnableGuid, + (EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS), + sizeof Settings.CustomMode, + &Settings.CustomMode + ); + if (EFI_ERROR (Status)) { + DEBUG (( + EFI_D_ERROR, + "SecureBootSetup: SetVariable(\"%s\", %g): %r\n", + EFI_CUSTOM_MODE_NAME, + &gEfiCustomModeEnableGuid, + Status + )); + ASSERT_EFI_ERROR (Status); + } + } + + // Enroll all the keys from default variables + Status = EnrollDbFromDefault (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Cannot enroll db: %r\n", Status)); + goto error; + } + + Status = EnrollDbxFromDefault (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Cannot enroll dbx: %r\n", Status)); + } + + Status = EnrollDbtFromDefault (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Cannot enroll dbt: %r\n", Status)); + } + + Status = EnrollKEKFromDefault (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Cannot enroll KEK: %r\n", Status)); + goto cleardbs; + } + + Status = EnrollPKFromDefault (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Cannot enroll PK: %r\n", Status)); + goto clearKEK; + } + + Status = SetSecureBootMode (STANDARD_SECURE_BOOT_MODE); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "Cannot set CustomMode to STANDARD_SECURE_BOOT_MODE\n" + "Please do it manually, otherwise system can be easily compromised\n" + )); + } + + // FIXME: Force SecureBoot to ON. The AuthService will do this if authenticated variables + // are supported, which aren't as the SMM handler isn't able to verify them. + + Settings.SecureBootEnable = SECURE_BOOT_ENABLE; + Status = gRT->SetVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof Settings.SecureBootEnable, + &Settings.SecureBootEnable + ); + if (EFI_ERROR (Status)) { + DEBUG (( + EFI_D_ERROR, + "SecureBootSetup: SetVariable(\"%s\", %g): %r\n", + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + Status + )); + ASSERT_EFI_ERROR (Status); + } + + Settings.SecureBoot = SECURE_BOOT_ENABLE; + Status = gRT->SetVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof Settings.SecureBoot, + &Settings.SecureBoot + ); + if (EFI_ERROR (Status)) { + DEBUG (( + EFI_D_ERROR, + "SecureBootSetup: SetVariable(\"%s\", %g): %r\n", + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + Status + )); + ASSERT_EFI_ERROR (Status); + } + + Status = GetSettings (&Settings, FALSE); + ASSERT_EFI_ERROR (Status); + + // + // Final sanity check: + // + // [SetupMode] + // (read-only, standardized by UEFI) + // / \_ + // 0 1, default + // / \_ + // PK enrolled no PK enrolled yet, + // (this is called "User Mode") PK enrollment possible + // | + // | + // [SecureBootEnable] + // (read-write, edk2-specific, boot service only) + // / \_ + // 0 1, default + // / \_ + // [SecureBoot]=0 [SecureBoot]=1 + // (read-only, standardized by UEFI) (read-only, standardized by UEFI) + // images are not verified images are verified, platform is + // operating in Secure Boot mode + // | + // | + // [CustomMode] + // (read-write, edk2-specific, boot service only) + // / \_ + // 0, default 1 + // / \_ + // PK, KEK, db, dbx PK, KEK, db, dbx + // updates are verified updates are not verified + // + + PrintSettings (&Settings); + + if ((Settings.SetupMode != 0) || (Settings.SecureBoot != 1) || + (Settings.SecureBootEnable != 1) || (Settings.CustomMode != 0) || + (Settings.VendorKeys != 0)) + { + DEBUG ((EFI_D_ERROR, "SecureBootSetup: disabled\n")); + return; + } + + DEBUG ((EFI_D_INFO, "SecureBootSetup: SecureBoot enabled\n")); + return; + +clearKEK: + DeleteKEK (); + +cleardbs: + DeleteDbt (); + DeleteDbx (); + DeleteDb (); + +error: + if (SetSecureBootMode (STANDARD_SECURE_BOOT_MODE) != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Cannot set mode to Secure: %r\n", Status)); + } + + DEBUG ((EFI_D_ERROR, "SecureBootSetup: disabled\n")); +} + +EFI_STATUS +EFIAPI +DriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + VOID *TcgProtocol; + VOID *Registration; + + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol); + if (!EFI_ERROR (Status)) { + DEBUG (( + EFI_D_ERROR, + "SecureBootSetup: Started too late." + "TPM is already running!\n" + )); + return EFI_DEVICE_ERROR; + } + + // + // Create event callback, because we need access variable on SecureBootPolicyVariable + // We should use VariableWriteArch instead of VariableArch, because Variable driver + // may update SecureBoot value based on last setting. + // + EfiCreateProtocolNotifyEvent ( + &gEfiVariableWriteArchProtocolGuid, + TPL_CALLBACK, + InstallSecureBootHook, + NULL, + &Registration + ); + + return EFI_SUCCESS; +} diff --git a/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.inf b/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.inf new file mode 100644 index 0000000000..fefbdb136b --- /dev/null +++ b/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.inf @@ -0,0 +1,56 @@ +## @file +# This file handels SecureBoot setup. +# +# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SecureBootSetup + MODULE_UNI_FILE = SecureBootSetup.uni + FILE_GUID = 14693BD4-D114-4177-979E-37F279BAD620 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 0.1 + ENTRY_POINT = DriverEntry + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + SecureBootSetup.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[Guids] + gEfiCertPkcs7Guid + gEfiCertX509Guid + gEfiCustomModeEnableGuid + gEfiGlobalVariableGuid + gEfiImageSecurityDatabaseGuid + gEfiSecureBootEnableDisableGuid + +[LibraryClasses] + BaseMemoryLib + DebugLib + MemoryAllocationLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + DxeServicesLib + UefiBootServicesTableLib + SecureBootVariableProvisionLib + SecureBootVariableLib + +[Protocols] + gEfiTcgProtocolGuid ## CONSUMES + gEfiVariableWriteArchProtocolGuid ## CONSUMES + +[Depex] + TRUE diff --git a/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.uni b/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.uni new file mode 100644 index 0000000000..0ea5d32872 --- /dev/null +++ b/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.uni @@ -0,0 +1,21 @@ +// /** @file +// Provides authenticated variable service for IPF platform +// +// This module installs variable arch protocol and variable write arch protocol to provide +// four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo. +// +// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Provides authenticated variable service for IPF platform" + +#string STR_MODULE_DESCRIPTION #language en-US "This module installs variable arch protocol and variable write arch protocol to provide four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo." diff --git a/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetupExtra.uni b/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetupExtra.uni new file mode 100644 index 0000000000..9811340573 --- /dev/null +++ b/UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetupExtra.uni @@ -0,0 +1,17 @@ +// /** @file +// EsalVariableDxeSal Localized Strings and Content +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"9elements Secure Boot DXE" diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index 51f18050f6..3c173192ce 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -99,6 +99,11 @@ # DEFINE SHELL_TYPE = BUILD_SHELL + # + # Security options: + # + DEFINE SECURE_BOOT_ENABLE = FALSE + # # EMU: UEFI payload with EMU variable # SPI: UEFI payload with SPI NV variable support @@ -186,6 +191,10 @@ CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf DxeHobListLib|UefiPayloadPkg/Library/DxeHobListLib/DxeHobListLib.inf +!if $(SECURE_BOOT_ENABLE) == TRUE + SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf + SecureBootVariableProvisionLib|SecurityPkg/Library/SecureBootVariableProvisionLib/SecureBootVariableProvisionLib.inf +!endif BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf TlsLib|CryptoPkg/Library/TlsLib/TlsLib.inf IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf @@ -272,7 +281,6 @@ DebugLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf - AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf !if $(VARIABLE_SUPPORT) == "EMU" TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf !elseif $(VARIABLE_SUPPORT) == "SMMSTORE" @@ -291,6 +299,9 @@ VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf +[LibraryClasses.common] + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf + [LibraryClasses.common.SEC] HobLib|UefiPayloadPkg/Library/PayloadEntryHobLib/HobLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf @@ -311,6 +322,18 @@ !if $(PERFORMANCE_MEASUREMENT_ENABLE) PerformanceLib|MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf !endif + SmbusLib|MdePkg/Library/DxeSmbusLib/DxeSmbusLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLibCrypto.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf + +!if $(SECURE_BOOT_ENABLE) == TRUE + AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf + # re-use the UserPhysicalPresent() dummy implementation from the ovmf tree + PlatformSecureLib|OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf +!else + AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf +!endif [LibraryClasses.common.DXE_DRIVER] PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf @@ -325,6 +348,17 @@ !if $(PERFORMANCE_MEASUREMENT_ENABLE) PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf !endif + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLibCrypto.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf + +!if $(SECURE_BOOT_ENABLE) == TRUE + AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf + # re-use the UserPhysicalPresent() dummy implementation from the ovmf tree + PlatformSecureLib|OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf +!else + AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf +!endif [LibraryClasses.common.DXE_RUNTIME_DRIVER] PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf @@ -334,6 +368,19 @@ !if $(PERFORMANCE_MEASUREMENT_ENABLE) PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf !endif + SmbusLib|MdePkg/Library/DxeSmbusLib/DxeSmbusLib.inf + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLibCrypto.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + RngLib|MdePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf + +!if $(SECURE_BOOT_ENABLE) == TRUE + AuthVariableLib|SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf + # re-use the UserPhysicalPresent() dummy implementation from the ovmf tree + PlatformSecureLib|OvmfPkg/Library/PlatformSecureLib/PlatformSecureLib.inf +!else + AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf +!endif [LibraryClasses.common.UEFI_DRIVER,LibraryClasses.common.UEFI_APPLICATION] PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf @@ -573,7 +620,19 @@ # Components that produce the architectural protocols # !if $(SECURITY_STUB_ENABLE) == TRUE - MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf + MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf { + +!if $(SECURE_BOOT_ENABLE) == TRUE + NULL|SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf +!endif + } + +!if $(SECURE_BOOT_ENABLE) == TRUE + SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + SecurityPkg/VariableAuthenticated/SecureBootDefaultKeysDxe/SecureBootDefaultKeysDxe.inf + UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.inf +!endif + !endif UefiCpuPkg/CpuDxe/CpuDxe.inf MdeModulePkg/Universal/BdsDxe/BdsDxe.inf @@ -598,7 +657,10 @@ !endif PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf !if $(EMU_VARIABLE_ENABLE) == TRUE - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf + MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf { + + NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf + } !endif # # Following are the DXE drivers diff --git a/UefiPayloadPkg/UefiPayloadPkg.fdf b/UefiPayloadPkg/UefiPayloadPkg.fdf index 6630fcfde5..07f6d57b8a 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.fdf +++ b/UefiPayloadPkg/UefiPayloadPkg.fdf @@ -61,7 +61,6 @@ FILE FV_IMAGE = 4E35FD93-9C72-4c15-8C4B-E77F1DB2D793 { } ################################################################################ - [FV.DXEFV] FvNameGuid = 8063C21A-8E58-4576-95CE-089E87975D23 BlockSize = $(FD_BLOCK_SIZE) @@ -89,6 +88,11 @@ APRIORI DXE { INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf INF UefiPayloadPkg/BlSupportDxe/BlSupportDxe.inf +!if $(SECURE_BOOT_ENABLE) == TRUE + INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf + INF SecurityPkg/VariableAuthenticated/SecureBootDefaultKeysDxe/SecureBootDefaultKeysDxe.inf # After SMBusConfigLoader and PcatRealTimeClockRuntimeDxe, before Tcg2Dxe + INF UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.inf +!endif } # @@ -272,6 +276,19 @@ INF SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf !include NetworkPkg/Network.fdf.inc !endif +# +# Security +# +!if $(SECURE_BOOT_ENABLE) == TRUE + INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + INF SecurityPkg/VariableAuthenticated/SecureBootDefaultKeysDxe/SecureBootDefaultKeysDxe.inf + INF UefiPayloadPkg/SecureBootEnrollDefaultKeys/SecureBootSetup.inf + + FILE FREEFORM = PCD(gUefiPayloadPkgTokenSpaceGuid.PcdNvsDataFile) { + SECTION RAW = UefiVariableBinary/SECUREBOOT.Fv + } +!endif + # # Shell # @@ -415,3 +432,17 @@ INF ShellPkg/Application/Shell/Shell.inf UI STRING="Enter Setup" VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } + +[RULE.COMMON.USER_DEFINED] + FILE FREEFORM = $(NAMED_GUID) { + RAW BIN |.crt + RAW BIN |.bin + } + +[RULE.COMMON.USER_DEFINED.BINARY] + FILE FREEFORM = $(NAMED_GUID) { + RAW BIN |.crt + RAW BIN |.bin + UI STRING="$(MODULE_NAME)" Optional + } + diff --git a/UefiVariableBinary/UefiVariableBinary.dsc b/UefiVariableBinary/UefiVariableBinary.dsc new file mode 100644 index 0000000000..6c5af32628 --- /dev/null +++ b/UefiVariableBinary/UefiVariableBinary.dsc @@ -0,0 +1,20 @@ +## @file +# Secure Boot Variable File +# +# Builds a firmware volume to contain Secure Boot keys +# +# Copyright (c) 2021, Star Labs Online Limited. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + PLATFORM_NAME = SecureBoot + PLATFORM_GUID = 1035eeff-543e-4abb-ac7e-bcd68cb530f8 + PLATFORM_VERSION = 0.1 + OUTPUT_DIRECTORY = Build/UefiVariableBinary + SUPPORTED_ARCHITECTURES = IA32|X64 + BUILD_TARGETS = DEBUG|RELEASE|NOOPT + SKUID_IDENTIFIER = DEFAULT + FLASH_DEFINITION = UefiVariableBinary/UefiVariableBinary.fdf + + diff --git a/UefiVariableBinary/UefiVariableBinary.fdf b/UefiVariableBinary/UefiVariableBinary.fdf new file mode 100644 index 0000000000..0495a26267 --- /dev/null +++ b/UefiVariableBinary/UefiVariableBinary.fdf @@ -0,0 +1,31 @@ +## @file +# FDF include file which allows to embed Secure Boot keys +# +# Copyright (c) 2021, Star Labs Online Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +[Defines] +DEFINE FD_SIZE = 0x00850000 +DEFINE NUM_BLOCKS = 0x850 + +[FV.SecureBoot] +FILE FREEFORM = 85254ea7-4759-4fc4-82d4-5eed5fb0a4a0 { + SECTION RAW = UefiVariableBinary/keys/pk.crt + SECTION UI = "PK Default" +} + +FILE FREEFORM = 6f64916e-9f7a-4c35-b952-cd041efb05a3 { + SECTION RAW = UefiVariableBinary/keys/MicCorKEKCA2011_2011-06-24.crt + SECTION UI = "KEK Default" +} + +FILE FREEFORM = c491d352-7623-4843-accc-2791a7574421 { + SECTION RAW = UefiVariableBinary/keys/MicWinProPCA2011_2011-10-19.crt + SECTION UI = "DB Default" +} + +FILE FREEFORM = 5740766a-718e-4dc0-9935-c36f7d3f884f { + SECTION RAW = UefiVariableBinary/keys/dbxupdate_x64.bin + SECTION UI = "DBX Default" +} diff --git a/UefiVariableBinary/keys/MicCorKEKCA2011_2011-06-24.crt b/UefiVariableBinary/keys/MicCorKEKCA2011_2011-06-24.crt new file mode 100644 index 0000000000000000000000000000000000000000..2787083e0cb615ff8c7beaac3b0a598ff5ec5870 GIT binary patch literal 1516 zcmXqLVtrxI#C%}^GZP~d6IUYF#SR7#U^d`oQxhX2!;u$TyY{aQSKFX=_|@~@;Z-h7vFyCJyq=b5 zJ=?(lCinH5`kjxXl8tHv#r^pnb1%0Lo!ocq>w}h!vu5i&|GItRHO_~R4zR3PV<2R91&S9_(-|4 zw_y7cS>HG7p3eCtcIf)S(^p;`(SJJgok}H`B=nQM3VkEpIuxws!gliCC zV&ReFVhCm^Wk_OhW^gp%2I=Hy0U6U~zz^aGGcx{XVKra|QU>xM0c92m1F;4X*R&w# zhjkHx`>*-UQx4^@wo=MkVGsjSAkPwN5Nr^*z<+^nn|DS@Nr9EVesWQcUM?&x>m}#s z>K9~Zf<*NTitQ<3X)E3>+FDvQfnk;IlCr2*mD_ikX9ZRZqL6?=D`>xf9< zxfXsxa&bKCwcE!oWS;ZzHroC=_L9NZ17COSs$gHN{crYdldzUIO{dm5sus-2e)(?# z|Mh9|PoGbb-=xLU>-}FtQ=t0$^_ry@%XYG!sC>&mVbYvK|L*74oX7zgh@9nG?To0`c7HO3KZNRe1+$`~ySEjVd zjf}U~n9k=+;kkT1N2zk{#t(a#7r7;@Ji>lRvFYRAPcJHs687I%vs6jM`_#c3-mh!z z!%a6m^Do`9A%R&bc-_QG*=w^MBvrw&v?L?HD6^ze z!N|bSz(7u%*U-?=z|hjr!o<+TC`z2y$PB_Y1#t};TWI1`Jp&zxQ&ka84bRL=$uBQf z2q?-=DNP3XNFl)45#&rmgC<5L{yk8AUeRmzWhZyaSqGceJiYuzeP_GO zznv$QIrCSzO+1)4&BpQa>BaW3Oj*8fGUZh@V$A;kbr$8C@<4LS`TK{29vzBSf2Uqy z&>gMCnXS|roFJxiAVW5I*Bj5za}#@7GdPP~Vrv(LXy2{;E_&WHHb+J~=G>k+%H8>S zTh(rw2_N>qroL{ck+tI_orlNImcLjP;`cpmjt1Nyo%}2yW7-V(K^$R5#{Vp=2FyUpKprHZ z%pzeR)*y2ATiEIT7mH$&GA`OqnGk*b+$@PB24Nrt@+|%az6Rb4JQujPxn`7<6jrfX!Z2UKJb#l`{j zA}cF9BO{BSfscU~jBmiyW(T#Ryu2Kn6~N4Z&+HQ9ga*v5%uT=m6!}wA7`U|ZP~N8Z zmUeq=g81{a?FEF3|EFLizEK78Zu;`nWUQnsi*c*pB~ z$qyde8m4Y&eEMn4S+OPaZC7lZeaPv;gqHXa+5erdcFDR=$lp-x=Q!VCe*DvgTAKtX z7I!IXd^mTn*fQR3bxgvW`^*9>E_1&8@@-n{w)()1Ge@>ec3(c~3GG&F?i{ z{8lQ-ntpk5c$}uR<%xH?56?bvEsnl$>0H%nG07&khzoIZ8#kw~&oTY9=c&EQBhy7( zrEK3M!e(Bn(7DJe{rW-&EB)G3mq&^vrrU323H zMVl`&2aoQYFqyBzb#mLwjS4gO%{YB@>XO)`YYUP&6!w-1l-JsRcHKFD`ux-34f)0^ NScZc8>APEWX7BmE1^3(73 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 literal 0 HcmV?d00001