__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout SecurityPkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
		
			
				
	
	
		
			899 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			899 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This library provides helper functions to set/clear Secure Boot
 | 
						|
  keys and databases.
 | 
						|
 | 
						|
  Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
  (C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
 | 
						|
  Copyright (c) 2021, ARM Ltd. All rights reserved.<BR>
 | 
						|
  Copyright (c) 2021, Semihalf All rights reserved.<BR>
 | 
						|
  Copyright (c) Microsoft Corporation.
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
**/
 | 
						|
#include <Uefi.h>
 | 
						|
#include <UefiSecureBoot.h>
 | 
						|
#include <Guid/GlobalVariable.h>
 | 
						|
#include <Guid/AuthenticatedVariableFormat.h>
 | 
						|
#include <Guid/ImageAuthentication.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/UefiLib.h>
 | 
						|
#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 = {
 | 
						|
  0xFFFF,     // Year
 | 
						|
  0xFF,       // Month
 | 
						|
  0xFF,       // Day
 | 
						|
  0xFF,       // Hour
 | 
						|
  0xFF,       // Minute
 | 
						|
  0xFF,       // Second
 | 
						|
  0x00,
 | 
						|
  0x00000000, // Nanosecond
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0x00
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// This epoch time 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 = {
 | 
						|
  1970, // Year (1970)
 | 
						|
  1,    // Month (Jan)
 | 
						|
  1,    // Day (1)
 | 
						|
  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.
 | 
						|
  @param[in]      Size     Size of signature data.
 | 
						|
  @param[out]     SigList  Created Signature List.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS           Signature List was created successfully.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES  Failed to allocate memory.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
CreateSigList (
 | 
						|
  IN VOID                 *Data,
 | 
						|
  IN UINTN                Size,
 | 
						|
  OUT EFI_SIGNATURE_LIST  **SigList
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN               SigListSize;
 | 
						|
  EFI_SIGNATURE_LIST  *TmpSigList;
 | 
						|
  EFI_SIGNATURE_DATA  *SigData;
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate data for Signature Database
 | 
						|
  //
 | 
						|
  SigListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + Size;
 | 
						|
  TmpSigList  = (EFI_SIGNATURE_LIST *)AllocateZeroPool (SigListSize);
 | 
						|
  if (TmpSigList == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Only gEfiCertX509Guid type is supported
 | 
						|
  //
 | 
						|
  TmpSigList->SignatureListSize   = (UINT32)SigListSize;
 | 
						|
  TmpSigList->SignatureSize       = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + Size);
 | 
						|
  TmpSigList->SignatureHeaderSize = 0;
 | 
						|
  CopyGuid (&TmpSigList->SignatureType, &gEfiCertX509Guid);
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy key data
 | 
						|
  //
 | 
						|
  SigData = (EFI_SIGNATURE_DATA *)(TmpSigList + 1);
 | 
						|
  CopyGuid (&SigData->SignatureOwner, &gEfiGlobalVariableGuid);
 | 
						|
  CopyMem (&SigData->SignatureData[0], Data, Size);
 | 
						|
 | 
						|
  *SigList = TmpSigList;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/** Adds new signature list to signature database.
 | 
						|
 | 
						|
  @param[in]      SigLists        A pointer to signature database.
 | 
						|
  @param[in]      SigListAppend  A signature list to be added.
 | 
						|
  @param[out]     *SigListOut     Created signature database.
 | 
						|
  @param[in, out] SigListsSize    A size of created signature database.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS           Signature List was added successfully.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES  Failed to allocate memory.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
ConcatenateSigList (
 | 
						|
  IN  EFI_SIGNATURE_LIST  *SigLists,
 | 
						|
  IN  EFI_SIGNATURE_LIST  *SigListAppend,
 | 
						|
  OUT EFI_SIGNATURE_LIST  **SigListOut,
 | 
						|
  IN OUT UINTN            *SigListsSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_SIGNATURE_LIST  *TmpSigList;
 | 
						|
  UINT8               *Offset;
 | 
						|
  UINTN               NewSigListsSize;
 | 
						|
 | 
						|
  NewSigListsSize = *SigListsSize + SigListAppend->SignatureListSize;
 | 
						|
 | 
						|
  TmpSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (NewSigListsSize);
 | 
						|
  if (TmpSigList == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (TmpSigList, SigLists, *SigListsSize);
 | 
						|
 | 
						|
  Offset  = (UINT8 *)TmpSigList;
 | 
						|
  Offset += *SigListsSize;
 | 
						|
  CopyMem ((VOID *)Offset, SigListAppend, SigListAppend->SignatureListSize);
 | 
						|
 | 
						|
  *SigListsSize = NewSigListsSize;
 | 
						|
  *SigListOut   = TmpSigList;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create a EFI Signature List with data supplied from input argument.
 | 
						|
  The input certificates from KeyInfo parameter should be DER-encoded
 | 
						|
  format.
 | 
						|
 | 
						|
  @param[out]       SigListsSize   A pointer to size of signature list
 | 
						|
  @param[out]       SigListOut     A pointer to a callee-allocated buffer with signature lists
 | 
						|
  @param[in]        KeyInfoCount   The number of certificate pointer and size pairs inside KeyInfo.
 | 
						|
  @param[in]        KeyInfo        A pointer to all certificates, in the format of DER-encoded,
 | 
						|
                                   to be concatenated into signature lists.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              Created signature list from payload successfully.
 | 
						|
  @retval EFI_NOT_FOUND            Section with key has not been found.
 | 
						|
  @retval EFI_INVALID_PARAMETER    Embedded key has a wrong format or input pointers are NULL.
 | 
						|
  @retval Others                   Unexpected error happens.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SecureBootCreateDataFromInput (
 | 
						|
  OUT UINTN                               *SigListsSize,
 | 
						|
  OUT EFI_SIGNATURE_LIST                  **SigListOut,
 | 
						|
  IN  UINTN                               KeyInfoCount,
 | 
						|
  IN  CONST SECURE_BOOT_CERTIFICATE_INFO  *KeyInfo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_SIGNATURE_LIST  *EfiSig;
 | 
						|
  EFI_SIGNATURE_LIST  *TmpEfiSig;
 | 
						|
  EFI_SIGNATURE_LIST  *TmpEfiSig2;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  VOID                *Buffer;
 | 
						|
  UINTN               Size;
 | 
						|
  UINTN               InputIndex;
 | 
						|
  UINTN               KeyIndex;
 | 
						|
 | 
						|
  if ((SigListOut == NULL) || (SigListsSize == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((KeyInfoCount == 0) || (KeyInfo == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  InputIndex    = 0;
 | 
						|
  KeyIndex      = 0;
 | 
						|
  EfiSig        = NULL;
 | 
						|
  *SigListsSize = 0;
 | 
						|
  while (InputIndex < KeyInfoCount) {
 | 
						|
    if (KeyInfo[InputIndex].Data != NULL) {
 | 
						|
      Size   = KeyInfo[InputIndex].DataSize;
 | 
						|
      Buffer = AllocateCopyPool (Size, KeyInfo[InputIndex].Data);
 | 
						|
      if (Buffer == NULL) {
 | 
						|
        if (EfiSig != NULL) {
 | 
						|
          FreePool (EfiSig);
 | 
						|
        }
 | 
						|
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = CreateSigList (Buffer, Size, &TmpEfiSig);
 | 
						|
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        FreePool (Buffer);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Concatenate lists if more than one section found
 | 
						|
      //
 | 
						|
      if (KeyIndex == 0) {
 | 
						|
        EfiSig        = TmpEfiSig;
 | 
						|
        *SigListsSize = TmpEfiSig->SignatureListSize;
 | 
						|
      } else {
 | 
						|
        ConcatenateSigList (EfiSig, TmpEfiSig, &TmpEfiSig2, SigListsSize);
 | 
						|
        FreePool (EfiSig);
 | 
						|
        FreePool (TmpEfiSig);
 | 
						|
        EfiSig = TmpEfiSig2;
 | 
						|
      }
 | 
						|
 | 
						|
      KeyIndex++;
 | 
						|
      FreePool (Buffer);
 | 
						|
    }
 | 
						|
 | 
						|
    InputIndex++;
 | 
						|
  }
 | 
						|
 | 
						|
  if (KeyIndex == 0) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  *SigListOut = EfiSig;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
 | 
						|
  descriptor with the input data. NO authentication is required in this function.
 | 
						|
 | 
						|
  @param[in, out]   DataSize       On input, the size of Data buffer in bytes.
 | 
						|
                                   On output, the size of data returned in Data
 | 
						|
                                   buffer in bytes.
 | 
						|
  @param[in, out]   Data           On input, Pointer to data buffer to be wrapped or
 | 
						|
                                   pointer to NULL to wrap an empty payload.
 | 
						|
                                   On output, Pointer to the new payload date buffer allocated from pool,
 | 
						|
                                   it's caller's responsibility to free the memory when finish using it.
 | 
						|
  @param[in]        Time           Pointer to time information to created time based payload.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              Create time based payload successfully.
 | 
						|
  @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
 | 
						|
CreateTimeBasedPayload (
 | 
						|
  IN OUT UINTN     *DataSize,
 | 
						|
  IN OUT UINT8     **Data,
 | 
						|
  IN     EFI_TIME  *Time
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                          *NewData;
 | 
						|
  UINT8                          *Payload;
 | 
						|
  UINTN                          PayloadSize;
 | 
						|
  EFI_VARIABLE_AUTHENTICATION_2  *DescriptorData;
 | 
						|
  UINTN                          DescriptorSize;
 | 
						|
 | 
						|
  if ((Data == NULL) || (DataSize == NULL) || (Time == NULL)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "%a(), invalid arg\n", __func__));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // In Setup mode or Custom mode, the variable does not need to be signed but the
 | 
						|
  // parameters to the SetVariable() call still need to be prepared as authenticated
 | 
						|
  // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
 | 
						|
  // data in it.
 | 
						|
  //
 | 
						|
  Payload     = *Data;
 | 
						|
  PayloadSize = *DataSize;
 | 
						|
 | 
						|
  DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
 | 
						|
  NewData        = (UINT8 *)AllocateZeroPool (DescriptorSize + PayloadSize);
 | 
						|
  if (NewData == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "%a() Out of resources.\n", __func__));
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Payload != NULL) && (PayloadSize != 0)) {
 | 
						|
    CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
 | 
						|
  }
 | 
						|
 | 
						|
  DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *)(NewData);
 | 
						|
 | 
						|
  CopyMem (&DescriptorData->TimeStamp, Time, sizeof (EFI_TIME));
 | 
						|
 | 
						|
  DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
 | 
						|
  DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;
 | 
						|
  DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
 | 
						|
  CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
 | 
						|
 | 
						|
  if (Payload != NULL) {
 | 
						|
    FreePool (Payload);
 | 
						|
    Payload = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  *DataSize = DescriptorSize + PayloadSize;
 | 
						|
  *Data     = NewData;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Internal helper function to delete a Variable given its name and GUID, NO authentication
 | 
						|
  required.
 | 
						|
 | 
						|
  @param[in]      VariableName            Name of the Variable.
 | 
						|
  @param[in]      VendorGuid              GUID of the Variable.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS              Variable deleted successfully.
 | 
						|
  @retval Others                   The driver failed to start the device.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DeleteVariable (
 | 
						|
  IN  CHAR16    *VariableName,
 | 
						|
  IN  EFI_GUID  *VendorGuid
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  VOID        *Variable;
 | 
						|
  UINT8       *Data;
 | 
						|
  UINTN       DataSize;
 | 
						|
  UINT32      Attr;
 | 
						|
 | 
						|
  GetVariable2 (VariableName, VendorGuid, &Variable, NULL);
 | 
						|
  if (Variable == NULL) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Variable);
 | 
						|
 | 
						|
  Data     = NULL;
 | 
						|
  DataSize = 0;
 | 
						|
  Attr     = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
 | 
						|
             | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
 | 
						|
  Status = CreateTimeBasedPayload (&DataSize, &Data, &mMaxTimestamp);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r", Status));
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  VariableName,
 | 
						|
                  VendorGuid,
 | 
						|
                  Attr,
 | 
						|
                  DataSize,
 | 
						|
                  Data
 | 
						|
                  );
 | 
						|
  if (Data != NULL) {
 | 
						|
    FreePool (Data);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Set the platform secure boot mode into "Custom" or "Standard" mode.
 | 
						|
 | 
						|
  @param[in]   SecureBootMode        New secure boot mode: STANDARD_SECURE_BOOT_MODE or
 | 
						|
                                     CUSTOM_SECURE_BOOT_MODE.
 | 
						|
 | 
						|
  @return EFI_SUCCESS                The platform has switched to the special mode successfully.
 | 
						|
  @return other                      Fail to operate the secure boot mode.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SetSecureBootMode (
 | 
						|
  IN  UINT8  SecureBootMode
 | 
						|
  )
 | 
						|
{
 | 
						|
  return gRT->SetVariable (
 | 
						|
                EFI_CUSTOM_MODE_NAME,
 | 
						|
                &gEfiCustomModeEnableGuid,
 | 
						|
                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
                sizeof (UINT8),
 | 
						|
                &SecureBootMode
 | 
						|
                );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Fetches the value of SetupMode variable.
 | 
						|
 | 
						|
  @param[out] SetupMode             Pointer to UINT8 for SetupMode output
 | 
						|
 | 
						|
  @retval other                     Retval from GetVariable.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
GetSetupMode (
 | 
						|
  OUT UINT8  *SetupMode
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN       Size;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Size   = sizeof (*SetupMode);
 | 
						|
  Status = gRT->GetVariable (
 | 
						|
                  EFI_SETUP_MODE_NAME,
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  NULL,
 | 
						|
                  &Size,
 | 
						|
                  SetupMode
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  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.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES      If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
 | 
						|
                                    while VendorGuid is NULL.
 | 
						|
  @retval other                     Errors from GetVariable2 (), GetTime () and SetVariable ()
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DeleteDb (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = DeleteVariable (
 | 
						|
             EFI_IMAGE_SECURITY_DATABASE,
 | 
						|
             &gEfiImageSecurityDatabaseGuid
 | 
						|
             );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clears the content of the 'dbx' variable.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES      If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
 | 
						|
                                    while VendorGuid is NULL.
 | 
						|
  @retval other                     Errors from GetVariable2 (), GetTime () and SetVariable ()
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DeleteDbx (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = DeleteVariable (
 | 
						|
             EFI_IMAGE_SECURITY_DATABASE1,
 | 
						|
             &gEfiImageSecurityDatabaseGuid
 | 
						|
             );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clears the content of the 'dbt' variable.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES      If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
 | 
						|
                                    while VendorGuid is NULL.
 | 
						|
  @retval other                     Errors from GetVariable2 (), GetTime () and SetVariable ()
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DeleteDbt (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = DeleteVariable (
 | 
						|
             EFI_IMAGE_SECURITY_DATABASE2,
 | 
						|
             &gEfiImageSecurityDatabaseGuid
 | 
						|
             );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clears the content of the 'KEK' variable.
 | 
						|
 | 
						|
  @retval EFI_OUT_OF_RESOURCES      If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails
 | 
						|
                                    while VendorGuid is NULL.
 | 
						|
  @retval other                     Errors from GetVariable2 (), GetTime () and SetVariable ()
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DeleteKEK (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = DeleteVariable (
 | 
						|
             EFI_KEY_EXCHANGE_KEY_NAME,
 | 
						|
             &gEfiGlobalVariableGuid
 | 
						|
             );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Remove the PK variable.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS    Delete PK successfully.
 | 
						|
  @retval Others         Could not allow to delete PK.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
DeletePlatformKey (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = DeleteVariable (
 | 
						|
             EFI_PLATFORM_KEY_NAME,
 | 
						|
             &gEfiGlobalVariableGuid
 | 
						|
             );
 | 
						|
  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", __func__));
 | 
						|
 | 
						|
  //
 | 
						|
  // 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", __func__, 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", __func__, 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", __func__, TempStatus));
 | 
						|
    if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {
 | 
						|
      Status = EFI_ACCESS_DENIED;
 | 
						|
    }
 | 
						|
 | 
						|
    TempStatus = DeleteDb ();
 | 
						|
    DEBUG ((DEBUG_INFO, "%a - db Delete = %r\n", __func__, TempStatus));
 | 
						|
    if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {
 | 
						|
      Status = EFI_ACCESS_DENIED;
 | 
						|
    }
 | 
						|
 | 
						|
    TempStatus = DeleteDbx ();
 | 
						|
    DEBUG ((DEBUG_INFO, "%a - dbx Delete = %r\n", __func__, TempStatus));
 | 
						|
    if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) {
 | 
						|
      Status = EFI_ACCESS_DENIED;
 | 
						|
    }
 | 
						|
 | 
						|
    TempStatus = DeleteDbt ();
 | 
						|
    DEBUG ((DEBUG_INFO, "%a - dbt Delete = %r\n", __func__, 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;
 | 
						|
 | 
						|
  Payload = NULL;
 | 
						|
 | 
						|
  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",
 | 
						|
      __func__,
 | 
						|
      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", __func__));
 | 
						|
 | 
						|
  if (SecureBootPayload == NULL) {
 | 
						|
    DEBUG ((DEBUG_ERROR, "%a - Invalid SecureBoot payload is supplied!\n", __func__));
 | 
						|
    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", __func__));
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((DEBUG_INFO, "%a - Setting up key %s!\n", __func__, 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", __func__, Status));
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBX %r!\n", __func__, 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", __func__, 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", __func__, 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", __func__, Status));
 | 
						|
      Status = EFI_SECURITY_VIOLATION;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |