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