public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Kun Qin" <kuqin12@gmail.com>
To: devel@edk2.groups.io
Cc: Jiewen Yao <jiewen.yao@intel.com>,
	Jian J Wang <jian.j.wang@intel.com>, Min Xu <min.m.xu@intel.com>
Subject: [PATCH v2 05/11] SecurityPkg: SecureBootVariableLib: Added newly supported interfaces
Date: Mon, 13 Jun 2022 13:39:36 -0700	[thread overview]
Message-ID: <20220613203943.704-6-kuqin12@gmail.com> (raw)
In-Reply-To: <20220613203943.704-1-kuqin12@gmail.com>

From: kuqin <kuqin@microsoft.com>

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3911

This change updated the interfaces provided by SecureBootVariableLib.

The new additions provided interfaces to enroll single authenticated
variable from input, a helper function to query secure boot status,
enroll all secure boot variables from UefiSecureBoot.h defined data
structures, a as well as a routine that deletes all secure boot related
variables.

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Min Xu <min.m.xu@intel.com>

Signed-off-by: Kun Qin <kun.qin@microsoft.com>
---
 SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c   | 366 ++++++++++++++++++++
 SecurityPkg/Include/Library/SecureBootVariableLib.h                 |  69 ++++
 SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf |   3 +
 3 files changed, 438 insertions(+)

diff --git a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c
index f56f0322e943..6718133aa6e4 100644
--- a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c
+++ b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c
@@ -21,6 +21,7 @@
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiRuntimeServicesTableLib.h>
 #include <Library/SecureBootVariableLib.h>
+#include <Library/PlatformPKProtectionLib.h>
 
 // This time can be used when deleting variables, as it should be greater than any variable time.
 EFI_TIME  mMaxTimestamp = {
@@ -37,6 +38,25 @@ EFI_TIME  mMaxTimestamp = {
   0x00
 };
 
+//
+// MS Default Time-Based Payload Creation Date
+// This is the date that is used when creating SecureBoot default variables.
+// NOTE: This is a placeholder date that doesn't correspond to anything else.
+//
+EFI_TIME  mDefaultPayloadTimestamp = {
+  15,   // Year (2015)
+  8,    // Month (Aug)
+  28,   // Day (28)
+  0,    // Hour
+  0,    // Minute
+  0,    // Second
+  0,    // Pad1
+  0,    // Nanosecond
+  0,    // Timezone (Dummy value)
+  0,    // Daylight (Dummy value)
+  0     // Pad2
+};
+
 /** Creates EFI Signature List structure.
 
   @param[in]      Data     A pointer to signature data.
@@ -413,6 +433,44 @@ GetSetupMode (
   return EFI_SUCCESS;
 }
 
+/**
+  Helper function to quickly determine whether SecureBoot is enabled.
+
+  @retval     TRUE    SecureBoot is verifiably enabled.
+  @retval     FALSE   SecureBoot is either disabled or an error prevented checking.
+
+**/
+BOOLEAN
+EFIAPI
+IsSecureBootEnabled (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *SecureBoot;
+
+  SecureBoot = NULL;
+
+  Status = GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID **)&SecureBoot, NULL);
+  //
+  // Skip verification if SecureBoot variable doesn't exist.
+  //
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Cannot check SecureBoot variable %r \n ", Status));
+    return FALSE;
+  }
+
+  //
+  // Skip verification if SecureBoot is disabled but not AuditMode
+  //
+  if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {
+    FreePool (SecureBoot);
+    return FALSE;
+  } else {
+    return TRUE;
+  }
+}
+
 /**
   Clears the content of the 'db' variable.
 
@@ -531,3 +589,311 @@ DeletePlatformKey (
              );
   return Status;
 }
+
+/**
+  This function will delete the secure boot keys, thus
+  disabling secure boot.
+
+  @return EFI_SUCCESS or underlying failure code.
+**/
+EFI_STATUS
+EFIAPI
+DeleteSecureBootVariables (
+  VOID
+  )
+{
+  EFI_STATUS  Status, TempStatus;
+
+  DEBUG ((DEBUG_INFO, "%a - Attempting to delete the Secure Boot variables.\n", __FUNCTION__));
+
+  //
+  // Step 1: Notify that a PK update is coming shortly...
+  Status = DisablePKProtection ();
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to signal PK update start! %r\n", __FUNCTION__, Status));
+    // Classify this as a PK deletion error.
+    Status = EFI_ABORTED;
+  }
+
+  //
+  // Step 2: Attempt to delete the PK.
+  // Let's try to nuke the PK, why not...
+  if (!EFI_ERROR (Status)) {
+    Status = DeletePlatformKey ();
+    DEBUG ((DEBUG_INFO, "%a - PK Delete = %r\n", __FUNCTION__, Status));
+    // If the PK is not found, then our work here is done.
+    if (Status == EFI_NOT_FOUND) {
+      Status = EFI_SUCCESS;
+    }
+    // If any other error occurred, let's inform the caller that the PK delete in particular failed.
+    else if (EFI_ERROR (Status)) {
+      Status = EFI_ABORTED;
+    }
+  }
+
+  //
+  // Step 3: Attempt to delete remaining keys/databases...
+  // Now that the PK is deleted (assuming Status == EFI_SUCCESS) the system is in SETUP_MODE.
+  // Arguably we could leave these variables in place and let them be deleted by whoever wants to
+  // update all the SecureBoot variables. However, for cleanliness sake, let's try to
+  // get rid of them here.
+  if (!EFI_ERROR (Status)) {
+    //
+    // If any of THESE steps have an error, report the error but attempt to delete all keys.
+    // Using TempStatus will prevent an error from being trampled by an EFI_SUCCESS.
+    // Overwrite Status ONLY if TempStatus is an error.
+    //
+    // If the error is EFI_NOT_FOUND, we can safely ignore it since we were trying to delete
+    // the variables anyway.
+    //
+    TempStatus = DeleteKEK ();
+    DEBUG ((DEBUG_INFO, "%a - KEK Delete = %r\n", __FUNCTION__, TempStatus));
+    if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {
+      Status = EFI_ACCESS_DENIED;
+    }
+
+    TempStatus = DeleteDb ();
+    DEBUG ((DEBUG_INFO, "%a - db Delete = %r\n", __FUNCTION__, TempStatus));
+    if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {
+      Status = EFI_ACCESS_DENIED;
+    }
+
+    TempStatus = DeleteDbx ();
+    DEBUG ((DEBUG_INFO, "%a - dbx Delete = %r\n", __FUNCTION__, TempStatus));
+    if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {
+      Status = EFI_ACCESS_DENIED;
+    }
+
+    TempStatus = DeleteDbt ();
+    DEBUG ((DEBUG_INFO, "%a - dbt Delete = %r\n", __FUNCTION__, TempStatus));
+    if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {
+      Status = EFI_ACCESS_DENIED;
+    }
+  }
+
+  return Status;
+}// DeleteSecureBootVariables()
+
+/**
+  A helper function to take in a variable payload, wrap it in the
+  proper authenticated variable structure, and install it in the
+  EFI variable space.
+
+  @param[in]  VariableName  The name of the key/database.
+  @param[in]  VendorGuid    The namespace (ie. vendor GUID) of the variable
+  @param[in]  DataSize      Size parameter for target secure boot variable.
+  @param[in]  Data          Pointer to signature list formatted secure boot variable content.
+
+  @retval EFI_SUCCESS              The enrollment for authenticated variable was successful.
+  @retval EFI_OUT_OF_RESOURCES     There are not enough memory resources to create time based payload.
+  @retval EFI_INVALID_PARAMETER    The parameter is invalid.
+  @retval Others                   Unexpected error happens.
+**/
+EFI_STATUS
+EFIAPI
+EnrollFromInput (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  )
+{
+  VOID        *Payload;
+  UINTN       PayloadSize;
+  EFI_STATUS  Status;
+
+  Payload = NULL;
+
+  if ((VariableName == NULL) || (VendorGuid == 0)) {
+    DEBUG ((DEBUG_ERROR, "Input vendor variable invalid: %p and %p\n", VariableName, VendorGuid));
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  if ((Data == NULL) || (DataSize == 0)) {
+    // You might as well just use DeleteVariable...
+    DEBUG ((DEBUG_ERROR, "Input argument invalid: %p: %x\n", Data, DataSize));
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  // Bring in the noise...
+  PayloadSize = DataSize;
+  Payload     = AllocateZeroPool (DataSize);
+  // Bring in the funk...
+  if (Payload == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  } else {
+    CopyMem (Payload, Data, DataSize);
+  }
+
+  Status = CreateTimeBasedPayload (&PayloadSize, (UINT8 **)&Payload, &mDefaultPayloadTimestamp);
+  if (EFI_ERROR (Status) || (Payload == NULL)) {
+    DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r\n", Status));
+    Payload = NULL;
+    Status  = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  //
+  // Allocate memory for auth variable
+  //
+  Status = gRT->SetVariable (
+                  VariableName,
+                  VendorGuid,
+                  (EFI_VARIABLE_NON_VOLATILE |
+                   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+                   EFI_VARIABLE_RUNTIME_ACCESS |
+                   EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS),
+                  PayloadSize,
+                  Payload
+                  );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "error: %a (\"%s\", %g): %r\n",
+      __FUNCTION__,
+      VariableName,
+      VendorGuid,
+      Status
+      ));
+  }
+
+Exit:
+  //
+  // Always Put Away Your Toys
+  // Payload will be reassigned by CreateTimeBasedPayload()...
+  if (Payload != NULL) {
+    FreePool (Payload);
+    Payload = NULL;
+  }
+
+  return Status;
+}
+
+/**
+  Similar to DeleteSecureBootVariables, this function is used to unilaterally
+  force the state of related SB variables (db, dbx, dbt, KEK, PK, etc.) to be
+  the built-in, hardcoded default vars.
+
+  @param[in]  SecureBootPayload  Payload information for secure boot related keys.
+
+  @retval     EFI_SUCCESS               SecureBoot keys are now set to defaults.
+  @retval     EFI_ABORTED               SecureBoot keys are not empty. Please delete keys first
+                                        or follow standard methods of altering keys (ie. use the signing system).
+  @retval     EFI_SECURITY_VIOLATION    Failed to create the PK.
+  @retval     Others                    Something failed in one of the subfunctions.
+
+**/
+EFI_STATUS
+EFIAPI
+SetSecureBootVariablesToDefault (
+  IN  CONST SECURE_BOOT_PAYLOAD_INFO  *SecureBootPayload
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       *Data;
+  UINTN       DataSize;
+
+  DEBUG ((DEBUG_INFO, "%a() Entry\n", __FUNCTION__));
+
+  if (SecureBootPayload == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a - Invalid SecureBoot payload is supplied!\n", __FUNCTION__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Right off the bat, if SecureBoot is currently enabled, bail.
+  if (IsSecureBootEnabled ()) {
+    DEBUG ((DEBUG_ERROR, "%a - Cannot set default keys while SecureBoot is enabled!\n", __FUNCTION__));
+    return EFI_ABORTED;
+  }
+
+  DEBUG ((DEBUG_INFO, "%a - Setting up key %s!\n", __FUNCTION__, SecureBootPayload->SecureBootKeyName));
+
+  //
+  // Start running down the list, creating variables in our wake.
+  // dbx is a good place to start.
+  Data     = (UINT8 *)SecureBootPayload->DbxPtr;
+  DataSize = SecureBootPayload->DbxSize;
+  Status   = EnrollFromInput (
+               EFI_IMAGE_SECURITY_DATABASE1,
+               &gEfiImageSecurityDatabaseGuid,
+               DataSize,
+               Data
+               );
+
+  // If that went well, try the db (make sure to pick the right one!).
+  if (!EFI_ERROR (Status)) {
+    Data     = (UINT8 *)SecureBootPayload->DbPtr;
+    DataSize = SecureBootPayload->DbSize;
+    Status   = EnrollFromInput (
+                 EFI_IMAGE_SECURITY_DATABASE,
+                 &gEfiImageSecurityDatabaseGuid,
+                 DataSize,
+                 Data
+                 );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DB %r!\n", __FUNCTION__, Status));
+    }
+  } else {
+    DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBX %r!\n", __FUNCTION__, Status));
+  }
+
+  // Keep it going. Keep it going. dbt if supplied...
+  if (!EFI_ERROR (Status) && (SecureBootPayload->DbtPtr != NULL)) {
+    Data     = (UINT8 *)SecureBootPayload->DbtPtr;
+    DataSize = SecureBootPayload->DbtSize;
+    Status   = EnrollFromInput (
+                 EFI_IMAGE_SECURITY_DATABASE2,
+                 &gEfiImageSecurityDatabaseGuid,
+                 DataSize,
+                 Data
+                 );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBT %r!\n", __FUNCTION__, Status));
+    }
+  }
+
+  // Keep it going. Keep it going. KEK...
+  if (!EFI_ERROR (Status)) {
+    Data     = (UINT8 *)SecureBootPayload->KekPtr;
+    DataSize = SecureBootPayload->KekSize;
+    Status   = EnrollFromInput (
+                 EFI_KEY_EXCHANGE_KEY_NAME,
+                 &gEfiGlobalVariableGuid,
+                 DataSize,
+                 Data
+                 );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a - Failed to enroll KEK %r!\n", __FUNCTION__, Status));
+    }
+  }
+
+  //
+  // Finally! The Big Daddy of them all.
+  // The PK!
+  //
+  if (!EFI_ERROR (Status)) {
+    //
+    // Finally, install the key.
+    Data     = (UINT8 *)SecureBootPayload->PkPtr;
+    DataSize = SecureBootPayload->PkSize;
+    Status   = EnrollFromInput (
+                 EFI_PLATFORM_KEY_NAME,
+                 &gEfiGlobalVariableGuid,
+                 DataSize,
+                 Data
+                 );
+
+    //
+    // Report PK creation errors.
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a - Failed to update the PK! - %r\n", __FUNCTION__, Status));
+      Status = EFI_SECURITY_VIOLATION;
+    }
+  }
+
+  return Status;
+}
diff --git a/SecurityPkg/Include/Library/SecureBootVariableLib.h b/SecurityPkg/Include/Library/SecureBootVariableLib.h
index 24ff0df067fa..c486801c318b 100644
--- a/SecurityPkg/Include/Library/SecureBootVariableLib.h
+++ b/SecurityPkg/Include/Library/SecureBootVariableLib.h
@@ -43,6 +43,19 @@ GetSetupMode (
   OUT UINT8  *SetupMode
   );
 
+/**
+  Helper function to quickly determine whether SecureBoot is enabled.
+
+  @retval     TRUE    SecureBoot is verifiably enabled.
+  @retval     FALSE   SecureBoot is either disabled or an error prevented checking.
+
+**/
+BOOLEAN
+EFIAPI
+IsSecureBootEnabled (
+  VOID
+  );
+
 /**
   Create a EFI Signature List with data supplied from input argument.
   The input certificates from KeyInfo parameter should be DER-encoded
@@ -161,4 +174,60 @@ DeletePlatformKey (
   VOID
   );
 
+/**
+  This function will delete the secure boot keys, thus
+  disabling secure boot.
+
+  @return EFI_SUCCESS or underlying failure code.
+**/
+EFI_STATUS
+EFIAPI
+DeleteSecureBootVariables (
+  VOID
+  );
+
+/**
+  A helper function to take in a variable payload, wrap it in the
+  proper authenticated variable structure, and install it in the
+  EFI variable space.
+
+  @param[in]  VariableName  The name of the key/database.
+  @param[in]  VendorGuid    The namespace (ie. vendor GUID) of the variable
+  @param[in]  DataSize      Size parameter for target secure boot variable.
+  @param[in]  Data          Pointer to signature list formatted secure boot variable content.
+
+  @retval EFI_SUCCESS              The enrollment for authenticated variable was successful.
+  @retval EFI_OUT_OF_RESOURCES     There are not enough memory resources to create time based payload.
+  @retval EFI_INVALID_PARAMETER    The parameter is invalid.
+  @retval Others                   Unexpected error happens.
+**/
+EFI_STATUS
+EFIAPI
+EnrollFromInput (
+  IN CHAR16    *VariableName,
+  IN EFI_GUID  *VendorGuid,
+  IN UINTN     DataSize,
+  IN VOID      *Data
+  );
+
+/**
+  Similar to DeleteSecureBootVariables, this function is used to unilaterally
+  force the state of related SB variables (db, dbx, dbt, KEK, PK, etc.) to be
+  the built-in, hardcoded default vars.
+
+  @param[in]  SecureBootPayload  Payload information for secure boot related keys.
+
+  @retval     EFI_SUCCESS               SecureBoot keys are now set to defaults.
+  @retval     EFI_ABORTED               SecureBoot keys are not empty. Please delete keys first
+                                        or follow standard methods of altering keys (ie. use the signing system).
+  @retval     EFI_SECURITY_VIOLATION    Failed to create the PK.
+  @retval     Others                    Something failed in one of the subfunctions.
+
+**/
+EFI_STATUS
+EFIAPI
+SetSecureBootVariablesToDefault (
+  IN  CONST SECURE_BOOT_PAYLOAD_INFO  *SecureBootPayload
+  );
+
 #endif
diff --git a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
index 3d4b77cfb073..eabe9db6c93f 100644
--- a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
+++ b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
@@ -38,6 +38,9 @@ [LibraryClasses]
   BaseMemoryLib
   DebugLib
   MemoryAllocationLib
+  PlatformPKProtectionLib
+  UefiLib
+  UefiRuntimeServicesTableLib
 
 [Guids]
   ## CONSUMES            ## Variable:L"SetupMode"
-- 
2.35.1.windows.2


  parent reply	other threads:[~2022-06-13 20:40 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-13 20:39 [PATCH v2 00/11] Enhance Secure Boot Variable Libraries Kun Qin
2022-06-13 20:39 ` [PATCH v2 01/11] SecurityPkg: UefiSecureBoot: Definitions of cert and payload structures Kun Qin
2022-06-13 20:39 ` [PATCH v2 02/11] SecurityPkg: PlatformPKProtectionLib: Added PK protection interface Kun Qin
2022-06-13 20:39 ` [PATCH v2 03/11] SecurityPkg: SecureBootVariableLib: Updated time based payload creator Kun Qin
2022-06-13 20:39 ` [PATCH v2 04/11] SecurityPkg: SecureBootVariableLib: Updated signature list creator Kun Qin
2022-06-13 20:39 ` Kun Qin [this message]
2022-06-13 20:39 ` [PATCH v2 06/11] SecurityPkg: SecureBootVariableProvisionLib: Updated implementation Kun Qin
2022-06-13 20:39 ` [PATCH v2 07/11] SecurityPkg: Secure Boot Drivers: Added common header files Kun Qin
2022-06-13 20:39 ` [PATCH v2 08/11] SecurityPkg: SecureBootConfigDxe: Updated invocation pattern Kun Qin
2022-06-13 20:39 ` [PATCH v2 09/11] SecurityPkg: SecureBootVariableLib: Added unit tests Kun Qin
2022-06-13 20:39 ` [PATCH v2 10/11] OvmfPkg: Pipeline: Resolve SecureBootVariableLib dependency Kun Qin
2022-06-13 20:39 ` [PATCH v2 11/11] EmulatorPkg: " Kun Qin
2022-06-24  9:08   ` Ni, Ray
2022-06-30 19:44 ` [edk2-devel] [PATCH v2 00/11] Enhance Secure Boot Variable Libraries Michael Kubacki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220613203943.704-6-kuqin12@gmail.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox