aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c')
-rw-r--r--roms/edk2/OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c732
1 files changed, 732 insertions, 0 deletions
diff --git a/roms/edk2/OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c b/roms/edk2/OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c
new file mode 100644
index 000000000..302b80d97
--- /dev/null
+++ b/roms/edk2/OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.c
@@ -0,0 +1,732 @@
+/** @file
+ Enroll default PK, KEK, db, dbx.
+
+ Copyright (C) 2014-2019, Red Hat, Inc.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+#include <Guid/AuthenticatedVariableFormat.h> // gEfiCustomModeEnableGuid
+#include <Guid/GlobalVariable.h> // EFI_SETUP_MODE_NAME
+#include <Guid/ImageAuthentication.h> // EFI_IMAGE_SECURITY_DATABASE
+#include <Guid/MicrosoftVendor.h> // gMicrosoftVendorGuid
+#include <Guid/OvmfPkKek1AppPrefix.h> // gOvmfPkKek1AppPrefixGuid
+#include <IndustryStandard/SmBios.h> // SMBIOS_HANDLE_PI_RESERVED
+#include <Library/BaseLib.h> // GUID_STRING_LENGTH
+#include <Library/BaseMemoryLib.h> // CopyGuid()
+#include <Library/DebugLib.h> // ASSERT()
+#include <Library/MemoryAllocationLib.h> // FreePool()
+#include <Library/PrintLib.h> // AsciiSPrint()
+#include <Library/ShellCEntryLib.h> // ShellAppMain()
+#include <Library/UefiBootServicesTableLib.h> // gBS
+#include <Library/UefiLib.h> // AsciiPrint()
+#include <Library/UefiRuntimeServicesTableLib.h> // gRT
+#include <Protocol/Smbios.h> // EFI_SMBIOS_PROTOCOL
+
+#include "EnrollDefaultKeys.h"
+
+
+/**
+ Fetch the X509 certificate (to be used as Platform Key and first Key Exchange
+ Key) from SMBIOS.
+
+ @param[out] PkKek1 The X509 certificate in DER encoding from the
+ hypervisor, to be enrolled as PK and first KEK
+ entry. On success, the caller is responsible for
+ releasing PkKek1 with FreePool().
+
+ @param[out] SizeOfPkKek1 The size of PkKek1 in bytes.
+
+ @retval EFI_SUCCESS PkKek1 and SizeOfPkKek1 have been set
+ successfully.
+
+ @retval EFI_NOT_FOUND An OEM String matching
+ OVMF_PK_KEK1_APP_PREFIX_GUID has not been
+ found.
+
+ @retval EFI_PROTOCOL_ERROR In the OEM String matching
+ OVMF_PK_KEK1_APP_PREFIX_GUID, the certificate
+ is empty, or it has invalid base64 encoding.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+
+ @return Error codes from gBS->LocateProtocol().
+**/
+STATIC
+EFI_STATUS
+GetPkKek1 (
+ OUT UINT8 **PkKek1,
+ OUT UINTN *SizeOfPkKek1
+ )
+{
+ CONST CHAR8 *Base64Cert;
+ CHAR8 OvmfPkKek1AppPrefix[GUID_STRING_LENGTH + 1 + 1];
+ EFI_STATUS Status;
+ EFI_SMBIOS_PROTOCOL *Smbios;
+ EFI_SMBIOS_HANDLE Handle;
+ EFI_SMBIOS_TYPE Type;
+ EFI_SMBIOS_TABLE_HEADER *Header;
+ SMBIOS_TABLE_TYPE11 *OemStringsTable;
+ UINTN Base64CertLen;
+ UINTN DecodedCertSize;
+ UINT8 *DecodedCert;
+
+ Base64Cert = NULL;
+
+ //
+ // Format the application prefix, for OEM String matching.
+ //
+ AsciiSPrint (OvmfPkKek1AppPrefix, sizeof OvmfPkKek1AppPrefix, "%g:",
+ &gOvmfPkKek1AppPrefixGuid);
+
+ //
+ // Scan all "OEM Strings" tables.
+ //
+ Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL,
+ (VOID **)&Smbios);
+ if (EFI_ERROR (Status)) {
+ AsciiPrint ("error: failed to locate EFI_SMBIOS_PROTOCOL: %r\n", Status);
+ return Status;
+ }
+
+ Handle = SMBIOS_HANDLE_PI_RESERVED;
+ Type = SMBIOS_TYPE_OEM_STRINGS;
+ for (Status = Smbios->GetNext (Smbios, &Handle, &Type, &Header, NULL);
+ !EFI_ERROR (Status);
+ Status = Smbios->GetNext (Smbios, &Handle, &Type, &Header, NULL)) {
+ CONST CHAR8 *OemString;
+ UINTN Idx;
+
+ if (Header->Length < sizeof *OemStringsTable) {
+ //
+ // Malformed table header, skip to next.
+ //
+ continue;
+ }
+ OemStringsTable = (SMBIOS_TABLE_TYPE11 *)Header;
+
+ //
+ // Scan all strings in the unformatted area of the current "OEM Strings"
+ // table.
+ //
+ OemString = (CONST CHAR8 *)(OemStringsTable + 1);
+ for (Idx = 0; Idx < OemStringsTable->StringCount; ++Idx) {
+ CHAR8 CandidatePrefix[sizeof OvmfPkKek1AppPrefix];
+
+ //
+ // NUL-terminate the candidate prefix for case-insensitive comparison.
+ //
+ AsciiStrnCpyS (CandidatePrefix, sizeof CandidatePrefix, OemString,
+ GUID_STRING_LENGTH + 1);
+ if (AsciiStriCmp (OvmfPkKek1AppPrefix, CandidatePrefix) == 0) {
+ //
+ // The current string matches the prefix.
+ //
+ Base64Cert = OemString + GUID_STRING_LENGTH + 1;
+ break;
+ }
+ OemString += AsciiStrSize (OemString);
+ }
+
+ if (Idx < OemStringsTable->StringCount) {
+ //
+ // The current table has a matching string.
+ //
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // No table with a matching string has been found.
+ //
+ AsciiPrint ("error: OEM String with app prefix %g not found: %r\n",
+ &gOvmfPkKek1AppPrefixGuid, Status);
+ return EFI_NOT_FOUND;
+ }
+
+ ASSERT (Base64Cert != NULL);
+ Base64CertLen = AsciiStrLen (Base64Cert);
+
+ //
+ // Verify the base64 encoding, and determine the decoded size.
+ //
+ DecodedCertSize = 0;
+ Status = Base64Decode (Base64Cert, Base64CertLen, NULL, &DecodedCertSize);
+ switch (Status) {
+ case EFI_BUFFER_TOO_SMALL:
+ ASSERT (DecodedCertSize > 0);
+ break;
+ case EFI_SUCCESS:
+ AsciiPrint ("error: empty certificate after app prefix %g\n",
+ &gOvmfPkKek1AppPrefixGuid);
+ return EFI_PROTOCOL_ERROR;
+ default:
+ AsciiPrint ("error: invalid base64 string after app prefix %g\n",
+ &gOvmfPkKek1AppPrefixGuid);
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ //
+ // Allocate the output buffer.
+ //
+ DecodedCert = AllocatePool (DecodedCertSize);
+ if (DecodedCert == NULL) {
+ AsciiPrint ("error: failed to allocate memory\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Decoding will succeed at this point.
+ //
+ Status = Base64Decode (Base64Cert, Base64CertLen, DecodedCert,
+ &DecodedCertSize);
+ ASSERT_EFI_ERROR (Status);
+
+ *PkKek1 = DecodedCert;
+ *SizeOfPkKek1 = DecodedCertSize;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enroll a set of certificates in a global variable, overwriting it.
+
+ The variable will be rewritten with NV+BS+RT+AT attributes.
+
+ @param[in] VariableName The name of the variable to overwrite.
+
+ @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable to
+ overwrite.
+
+ @param[in] CertType The GUID determining the type of all the
+ certificates in the set that is passed in. For
+ example, gEfiCertX509Guid stands for DER-encoded
+ X.509 certificates, while gEfiCertSha256Guid stands
+ for SHA256 image hashes.
+
+ @param[in] ... A list of
+
+ IN CONST UINT8 *Cert,
+ IN UINTN CertSize,
+ IN CONST EFI_GUID *OwnerGuid
+
+ triplets. If the first component of a triplet is
+ NULL, then the other two components are not
+ accessed, and processing is terminated. The list of
+ certificates is enrolled in the variable specified,
+ overwriting it. The OwnerGuid component identifies
+ the agent installing the certificate.
+
+ @retval EFI_INVALID_PARAMETER The triplet list is empty (ie. the first Cert
+ value is NULL), or one of the CertSize values
+ is 0, or one of the CertSize values would
+ overflow the accumulated UINT32 data size.
+
+ @retval EFI_OUT_OF_RESOURCES Out of memory while formatting variable
+ payload.
+
+ @retval EFI_SUCCESS Enrollment successful; the variable has been
+ overwritten (or created).
+
+ @return Error codes from gRT->GetTime() and
+ gRT->SetVariable().
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+EnrollListOfCerts (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN EFI_GUID *CertType,
+ ...
+ )
+{
+ UINTN DataSize;
+ SINGLE_HEADER *SingleHeader;
+ REPEATING_HEADER *RepeatingHeader;
+ VA_LIST Marker;
+ CONST UINT8 *Cert;
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINT8 *Position;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // compute total size first, for UINT32 range check, and allocation
+ //
+ DataSize = sizeof *SingleHeader;
+ VA_START (Marker, CertType);
+ for (Cert = VA_ARG (Marker, CONST UINT8 *);
+ Cert != NULL;
+ Cert = VA_ARG (Marker, CONST UINT8 *)) {
+ UINTN CertSize;
+
+ CertSize = VA_ARG (Marker, UINTN);
+ (VOID)VA_ARG (Marker, CONST EFI_GUID *);
+
+ if (CertSize == 0 ||
+ CertSize > MAX_UINT32 - sizeof *RepeatingHeader ||
+ DataSize > MAX_UINT32 - sizeof *RepeatingHeader - CertSize) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+ DataSize += sizeof *RepeatingHeader + CertSize;
+ }
+ VA_END (Marker);
+
+ if (DataSize == sizeof *SingleHeader) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ if (EFI_ERROR (Status)) {
+ goto Out;
+ }
+
+ Data = AllocatePool (DataSize);
+ if (Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Out;
+ }
+
+ Position = Data;
+
+ SingleHeader = (SINGLE_HEADER *)Position;
+ Status = gRT->GetTime (&SingleHeader->TimeStamp, NULL);
+ if (EFI_ERROR (Status)) {
+ goto FreeData;
+ }
+ SingleHeader->TimeStamp.Pad1 = 0;
+ SingleHeader->TimeStamp.Nanosecond = 0;
+ SingleHeader->TimeStamp.TimeZone = 0;
+ SingleHeader->TimeStamp.Daylight = 0;
+ SingleHeader->TimeStamp.Pad2 = 0;
+#if 0
+ SingleHeader->dwLength = DataSize - sizeof SingleHeader->TimeStamp;
+#else
+ //
+ // This looks like a bug in edk2. According to the UEFI specification,
+ // dwLength is "The length of the entire certificate, including the length of
+ // the header, in bytes". That shouldn't stop right after CertType -- it
+ // should include everything below it.
+ //
+ SingleHeader->dwLength = sizeof *SingleHeader
+ - sizeof SingleHeader->TimeStamp;
+#endif
+ SingleHeader->wRevision = 0x0200;
+ SingleHeader->wCertificateType = WIN_CERT_TYPE_EFI_GUID;
+ CopyGuid (&SingleHeader->CertType, &gEfiCertPkcs7Guid);
+ Position += sizeof *SingleHeader;
+
+ VA_START (Marker, CertType);
+ for (Cert = VA_ARG (Marker, CONST UINT8 *);
+ Cert != NULL;
+ Cert = VA_ARG (Marker, CONST UINT8 *)) {
+ UINTN CertSize;
+ CONST EFI_GUID *OwnerGuid;
+
+ CertSize = VA_ARG (Marker, UINTN);
+ OwnerGuid = VA_ARG (Marker, CONST EFI_GUID *);
+
+ RepeatingHeader = (REPEATING_HEADER *)Position;
+ CopyGuid (&RepeatingHeader->SignatureType, CertType);
+ RepeatingHeader->SignatureListSize =
+ (UINT32)(sizeof *RepeatingHeader + CertSize);
+ RepeatingHeader->SignatureHeaderSize = 0;
+ RepeatingHeader->SignatureSize =
+ (UINT32)(sizeof RepeatingHeader->SignatureOwner + CertSize);
+ CopyGuid (&RepeatingHeader->SignatureOwner, OwnerGuid);
+ Position += sizeof *RepeatingHeader;
+
+ CopyMem (Position, Cert, CertSize);
+ Position += CertSize;
+ }
+ VA_END (Marker);
+
+ ASSERT (Data + DataSize == Position);
+
+ Status = gRT->SetVariable (VariableName, VendorGuid,
+ (EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS),
+ DataSize, Data);
+
+FreeData:
+ FreePool (Data);
+
+Out:
+ if (EFI_ERROR (Status)) {
+ AsciiPrint ("error: %a(\"%s\", %g): %r\n", __FUNCTION__, VariableName,
+ VendorGuid, Status);
+ }
+ return Status;
+}
+
+
+/**
+ Read a UEFI variable into a caller-allocated buffer, enforcing an exact size.
+
+ @param[in] VariableName The name of the variable to read; passed to
+ gRT->GetVariable().
+
+ @param[in] VendorGuid The vendor (namespace) GUID of the variable to read;
+ passed to gRT->GetVariable().
+
+ @param[out] Data The caller-allocated buffer that is supposed to
+ receive the variable's contents. On error, the
+ contents of Data are indeterminate.
+
+ @param[in] DataSize The size in bytes that the caller requires the UEFI
+ variable to have. The caller is responsible for
+ providing room for DataSize bytes in Data.
+
+ @param[in] AllowMissing If FALSE, the variable is required to exist. If
+ TRUE, the variable is permitted to be missing.
+
+ @retval EFI_SUCCESS The UEFI variable exists, has the required size
+ (DataSize), and has been read into Data.
+
+ @retval EFI_SUCCESS The UEFI variable doesn't exist, and
+ AllowMissing is TRUE. DataSize bytes in Data
+ have been zeroed out.
+
+ @retval EFI_NOT_FOUND The UEFI variable doesn't exist, and
+ AllowMissing is FALSE.
+
+ @retval EFI_BUFFER_TOO_SMALL The UEFI variable exists, but its size is
+ greater than DataSize.
+
+ @retval EFI_PROTOCOL_ERROR The UEFI variable exists, but its size is
+ smaller than DataSize.
+
+ @return Error codes propagated from gRT->GetVariable().
+**/
+STATIC
+EFI_STATUS
+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;
+ }
+
+ AsciiPrint ("error: GetVariable(\"%s\", %g): %r\n", VariableName,
+ VendorGuid, Status);
+ return Status;
+ }
+
+ if (Size != DataSize) {
+ AsciiPrint ("error: GetVariable(\"%s\", %g): expected size 0x%Lx, "
+ "got 0x%Lx\n", VariableName, VendorGuid, (UINT64)DataSize, (UINT64)Size);
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Populate a SETTINGS structure from the underlying UEFI variables.
+
+ The following UEFI variables are standard variables:
+ - L"SetupMode" (EFI_SETUP_MODE_NAME)
+ - L"SecureBoot" (EFI_SECURE_BOOT_MODE_NAME)
+ - L"VendorKeys" (EFI_VENDOR_KEYS_VARIABLE_NAME)
+
+ The following UEFI variables are edk2 extensions:
+ - L"SecureBootEnable" (EFI_SECURE_BOOT_ENABLE_NAME)
+ - L"CustomMode" (EFI_CUSTOM_MODE_NAME)
+
+ The L"SecureBootEnable" UEFI variable is permitted to be missing, in which
+ case the corresponding field in the SETTINGS object will be zeroed out. The
+ rest of the covered UEFI variables are required to exist; otherwise, the
+ function will fail.
+
+ @param[out] Settings The SETTINGS object to fill.
+
+ @retval EFI_SUCCESS Settings has been populated.
+
+ @return Error codes propagated from the GetExact() function. The
+ contents of Settings are indeterminate.
+**/
+STATIC
+EFI_STATUS
+GetSettings (
+ OUT SETTINGS *Settings
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetExact (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid,
+ &Settings->SetupMode, sizeof Settings->SetupMode, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GetExact (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid,
+ &Settings->SecureBoot, sizeof Settings->SecureBoot, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GetExact (EFI_SECURE_BOOT_ENABLE_NAME,
+ &gEfiSecureBootEnableDisableGuid, &Settings->SecureBootEnable,
+ sizeof Settings->SecureBootEnable, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GetExact (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,
+ &Settings->CustomMode, sizeof Settings->CustomMode, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GetExact (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid,
+ &Settings->VendorKeys, sizeof Settings->VendorKeys, FALSE);
+ return Status;
+}
+
+
+/**
+ Print the contents of a SETTINGS structure to the UEFI console.
+
+ @param[in] Settings The SETTINGS object to print the contents of.
+**/
+STATIC
+VOID
+PrintSettings (
+ IN CONST SETTINGS *Settings
+ )
+{
+ AsciiPrint ("info: SetupMode=%d SecureBoot=%d SecureBootEnable=%d "
+ "CustomMode=%d VendorKeys=%d\n", Settings->SetupMode, Settings->SecureBoot,
+ Settings->SecureBootEnable, Settings->CustomMode, Settings->VendorKeys);
+}
+
+
+/**
+ Entry point function of this shell application.
+**/
+INTN
+EFIAPI
+ShellAppMain (
+ IN UINTN Argc,
+ IN CHAR16 **Argv
+ )
+{
+ INTN RetVal;
+ EFI_STATUS Status;
+ SETTINGS Settings;
+ UINT8 *PkKek1;
+ UINTN SizeOfPkKek1;
+ BOOLEAN NoDefault;
+
+ if (Argc == 2 && StrCmp (Argv[1], L"--no-default") == 0) {
+ NoDefault = TRUE;
+ } else {
+ NoDefault = FALSE;
+ }
+
+ //
+ // Prepare for failure.
+ //
+ RetVal = 1;
+
+ //
+ // If we're not in Setup Mode, we can't do anything.
+ //
+ Status = GetSettings (&Settings);
+ if (EFI_ERROR (Status)) {
+ return RetVal;
+ }
+ PrintSettings (&Settings);
+
+ if (Settings.SetupMode != 1) {
+ AsciiPrint ("error: already in User Mode\n");
+ return RetVal;
+ }
+
+ //
+ // Set PkKek1 and SizeOfPkKek1 to suppress incorrect compiler/analyzer
+ // warnings.
+ //
+ PkKek1 = NULL;
+ SizeOfPkKek1 = 0;
+
+ //
+ // Fetch the X509 certificate (to be used as Platform Key and first Key
+ // Exchange Key) from SMBIOS.
+ //
+ Status = GetPkKek1 (&PkKek1, &SizeOfPkKek1);
+ if (EFI_ERROR (Status)) {
+ return RetVal;
+ }
+
+ //
+ // Enter Custom Mode so we can enroll PK, KEK, db, and dbx without signature
+ // checks on those variable writes.
+ //
+ 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)) {
+ AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,
+ &gEfiCustomModeEnableGuid, Status);
+ goto FreePkKek1;
+ }
+ }
+
+ //
+ // Enroll db.
+ //
+ if (NoDefault) {
+ Status = EnrollListOfCerts (
+ EFI_IMAGE_SECURITY_DATABASE,
+ &gEfiImageSecurityDatabaseGuid,
+ &gEfiCertX509Guid,
+ PkKek1, SizeOfPkKek1, &gEfiCallerIdGuid,
+ NULL);
+ } else {
+ Status = EnrollListOfCerts (
+ EFI_IMAGE_SECURITY_DATABASE,
+ &gEfiImageSecurityDatabaseGuid,
+ &gEfiCertX509Guid,
+ mMicrosoftPca, mSizeOfMicrosoftPca, &gMicrosoftVendorGuid,
+ mMicrosoftUefiCa, mSizeOfMicrosoftUefiCa, &gMicrosoftVendorGuid,
+ NULL);
+ }
+ if (EFI_ERROR (Status)) {
+ goto FreePkKek1;
+ }
+
+ //
+ // Enroll dbx.
+ //
+ Status = EnrollListOfCerts (
+ EFI_IMAGE_SECURITY_DATABASE1,
+ &gEfiImageSecurityDatabaseGuid,
+ &gEfiCertSha256Guid,
+ mSha256OfDevNull, mSizeOfSha256OfDevNull, &gEfiCallerIdGuid,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ goto FreePkKek1;
+ }
+
+ //
+ // Enroll KEK.
+ //
+ if (NoDefault) {
+ Status = EnrollListOfCerts (
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ &gEfiCertX509Guid,
+ PkKek1, SizeOfPkKek1, &gEfiCallerIdGuid,
+ NULL);
+ } else {
+ Status = EnrollListOfCerts (
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ &gEfiCertX509Guid,
+ PkKek1, SizeOfPkKek1, &gEfiCallerIdGuid,
+ mMicrosoftKek, mSizeOfMicrosoftKek, &gMicrosoftVendorGuid,
+ NULL);
+ }
+ if (EFI_ERROR (Status)) {
+ goto FreePkKek1;
+ }
+
+ //
+ // Enroll PK, leaving Setup Mode (entering User Mode) at once.
+ //
+ Status = EnrollListOfCerts (
+ EFI_PLATFORM_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ &gEfiCertX509Guid,
+ PkKek1, SizeOfPkKek1, &gEfiGlobalVariableGuid,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ goto FreePkKek1;
+ }
+
+ //
+ // Leave Custom Mode, so that updates to PK, KEK, db, and dbx require valid
+ // signatures.
+ //
+ Settings.CustomMode = STANDARD_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)) {
+ AsciiPrint ("error: SetVariable(\"%s\", %g): %r\n", EFI_CUSTOM_MODE_NAME,
+ &gEfiCustomModeEnableGuid, Status);
+ goto FreePkKek1;
+ }
+
+ //
+ // 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
+ //
+ Status = GetSettings (&Settings);
+ if (EFI_ERROR (Status)) {
+ goto FreePkKek1;
+ }
+ PrintSettings (&Settings);
+
+ if (Settings.SetupMode != 0 || Settings.SecureBoot != 1 ||
+ Settings.SecureBootEnable != 1 || Settings.CustomMode != 0 ||
+ Settings.VendorKeys != 0) {
+ AsciiPrint ("error: unexpected\n");
+ goto FreePkKek1;
+ }
+
+ AsciiPrint ("info: success\n");
+ RetVal = 0;
+
+FreePkKek1:
+ FreePool (PkKek1);
+
+ return RetVal;
+}