[PATCH v3 05/11] SecurityPkg: SecureBootVariableLib: Added newly supported interfaces


Kun Qin
 

From: kuqin <kuqin@...>

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

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@...>
Cc: Jian J Wang <jian.j.wang@...>
Cc: Min Xu <min.m.xu@...>

Signed-off-by: Kun Qin <kun.qin@...>
Reviewed-by: Jiewen Yao <Jiewen.yao@...>
Acked-by: Michael Kubacki <michael.kubacki@...>
---

Notes:
v3:
- Updated default timestamp to epoch time [Jiewen]
- Added reviewed-by tag [Jiewen]
- Added acked-by tag [Michael Kubacki]

SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c | 365 =
++++++++++++++++++++
SecurityPkg/Include/Library/SecureBootVariableLib.h | 69 =
++++
SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf | 3 +
3 files changed, 437 insertions(+)

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