]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c
SecurityPkg: SecureBootVariableLib: Added newly supported interfaces
[mirror_edk2.git] / SecurityPkg / Library / SecureBootVariableLib / SecureBootVariableLib.c
index f56f0322e9431b16093154e964f425ea4161abad..abca249c6504d78cf81ecbaf73dbd8b80a8d1c2c 100644 (file)
@@ -21,6 +21,7 @@
 #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
@@ -37,6 +38,24 @@ EFI_TIME  mMaxTimestamp = {
   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
@@ -413,6 +432,44 @@ GetSetupMode (
   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
@@ -531,3 +588,311 @@ DeletePlatformKey (
              );\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