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 v1 05/11] SecurityPkg: SecureBootVariableLib: Added newly supported interfaces
Date: Wed, 4 May 2022 11:04:31 -0700 [thread overview]
Message-ID: <20220504180438.1321-6-kuqin12@gmail.com> (raw)
In-Reply-To: <20220504180438.1321-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 | 364 ++++++++++++++++++++
SecurityPkg/Include/Library/SecureBootVariableLib.h | 69 ++++
SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf | 2 +
3 files changed, 435 insertions(+)
diff --git a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c
index f56f0322e943..8167e58ca84c 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,309 @@ 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;
+
+ 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..ac8e4bf5cd6a 100644
--- a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
+++ b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf
@@ -38,6 +38,8 @@ [LibraryClasses]
BaseMemoryLib
DebugLib
MemoryAllocationLib
+ PlatformPKProtectionLib
+ UefiRuntimeServicesTableLib
[Guids]
## CONSUMES ## Variable:L"SetupMode"
--
2.34.1.windows.1
next prev parent reply other threads:[~2022-05-04 18:04 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-04 18:04 [PATCH v1 00/11] Enhance Secure Boot Variable Libraries Kun Qin
2022-05-04 18:04 ` [PATCH v1 01/11] SecurityPkg: UefiSecureBoot: Definitions of cert and payload structures Kun Qin
2022-05-04 18:04 ` [PATCH v1 02/11] SecurityPkg: PlatformPKProtectionLib: Added PK protection interface Kun Qin
2022-05-04 18:04 ` [PATCH v1 03/11] SecurityPkg: SecureBootVariableLib: Updated time based payload creator Kun Qin
2022-05-04 18:04 ` [PATCH v1 04/11] SecurityPkg: SecureBootVariableLib: Updated signature list creator Kun Qin
2022-05-04 18:04 ` Kun Qin [this message]
2022-05-04 18:04 ` [PATCH v1 06/11] SecurityPkg: SecureBootVariableProvisionLib: Updated implementation Kun Qin
2022-05-04 18:04 ` [PATCH v1 07/11] SecurityPkg: Secure Boot Drivers: Added common header files Kun Qin
2022-05-04 18:04 ` [PATCH v1 08/11] SecurityPkg: SecureBootConfigDxe: Updated invocation pattern Kun Qin
2022-05-04 18:04 ` [PATCH v1 09/11] SecurityPkg: SecureBootVariableLib: Added unit tests Kun Qin
2022-05-04 18:04 ` [PATCH v1 10/11] OvmfPkg: Pipeline: Resolve SecureBootVariableLib dependency Kun Qin
2022-05-04 18:04 ` [PATCH v1 11/11] EmulatorPkg: " Kun Qin
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=20220504180438.1321-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