[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 |
|