[edk2-devel] [PATCH v2 05/11] SecurityPkg: SecureBootVariableLib: Added newly supported interfaces

Kun Qin kuqin12 at gmail.com
Mon Jun 13 20:39:36 UTC 2022


From: kuqin <kuqin at 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 at intel.com>
Cc: Jian J Wang <jian.j.wang at intel.com>
Cc: Min Xu <min.m.xu at intel.com>

Signed-off-by: Kun Qin <kun.qin at 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



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#90496): https://edk2.groups.io/g/devel/message/90496
Mute This Topic: https://groups.io/mt/91735873/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list