__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>
		
			
				
	
	
		
			2385 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2385 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Implement authentication services for the authenticated variables.
 | 
						|
 | 
						|
  Caution: This module requires additional review when modified.
 | 
						|
  This driver will have external input - variable data. It may be input in SMM mode.
 | 
						|
  This external input must be validated carefully to avoid security issue like
 | 
						|
  buffer overflow, integer overflow.
 | 
						|
  Variable attribute should also be checked to avoid authentication bypass.
 | 
						|
     The whole SMM authentication variable design relies on the integrity of flash part and SMM.
 | 
						|
  which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory
 | 
						|
  may not be modified without authorization. If platform fails to protect these resources,
 | 
						|
  the authentication service provided in this driver will be broken, and the behavior is undefined.
 | 
						|
 | 
						|
  ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do
 | 
						|
  variable authentication.
 | 
						|
 | 
						|
  VerifyTimeBasedPayloadAndUpdate() and VerifyCounterBasedPayload() are sub function to do verification.
 | 
						|
  They will do basic validation for authentication data structure, then call crypto library
 | 
						|
  to verify the signature.
 | 
						|
 | 
						|
Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>
 | 
						|
Copyright (c) Microsoft Corporation.
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "AuthServiceInternal.h"
 | 
						|
 | 
						|
#include <Protocol/VariablePolicy.h>
 | 
						|
#include <Library/VariablePolicyLib.h>
 | 
						|
 | 
						|
//
 | 
						|
// Public Exponent of RSA Key.
 | 
						|
//
 | 
						|
CONST UINT8  mRsaE[] = { 0x01, 0x00, 0x01 };
 | 
						|
 | 
						|
CONST UINT8  mSha256OidValue[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };
 | 
						|
 | 
						|
//
 | 
						|
// Requirement for different signature type which have been defined in UEFI spec.
 | 
						|
// These data are used to perform SignatureList format check while setting PK/KEK variable.
 | 
						|
//
 | 
						|
EFI_SIGNATURE_ITEM  mSupportSigItem[] = {
 | 
						|
  // {SigType,                       SigHeaderSize,   SigDataSize  }
 | 
						|
  { EFI_CERT_SHA256_GUID,         0, 32            },
 | 
						|
  { EFI_CERT_RSA2048_GUID,        0, 256           },
 | 
						|
  { EFI_CERT_RSA2048_SHA256_GUID, 0, 256           },
 | 
						|
  { EFI_CERT_SHA1_GUID,           0, 20            },
 | 
						|
  { EFI_CERT_RSA2048_SHA1_GUID,   0, 256           },
 | 
						|
  { EFI_CERT_X509_GUID,           0, ((UINT32) ~0) },
 | 
						|
  { EFI_CERT_SHA224_GUID,         0, 28            },
 | 
						|
  { EFI_CERT_SHA384_GUID,         0, 48            },
 | 
						|
  { EFI_CERT_SHA512_GUID,         0, 64            },
 | 
						|
  { EFI_CERT_X509_SHA256_GUID,    0, 48            },
 | 
						|
  { EFI_CERT_X509_SHA384_GUID,    0, 64            },
 | 
						|
  { EFI_CERT_X509_SHA512_GUID,    0, 80            }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Finds variable in storage blocks of volatile and non-volatile storage areas.
 | 
						|
 | 
						|
  This code finds variable in storage blocks of volatile and non-volatile storage areas.
 | 
						|
  If VariableName is an empty string, then we just return the first
 | 
						|
  qualified variable without comparing VariableName and VendorGuid.
 | 
						|
 | 
						|
  @param[in]  VariableName          Name of the variable to be found.
 | 
						|
  @param[in]  VendorGuid            Variable vendor GUID to be found.
 | 
						|
  @param[out] Data                  Pointer to data address.
 | 
						|
  @param[out] DataSize              Pointer to data size.
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER     If VariableName is not an empty string,
 | 
						|
                                    while VendorGuid is NULL.
 | 
						|
  @retval EFI_SUCCESS               Variable successfully found.
 | 
						|
  @retval EFI_NOT_FOUND             Variable not found
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AuthServiceInternalFindVariable (
 | 
						|
  IN  CHAR16    *VariableName,
 | 
						|
  IN  EFI_GUID  *VendorGuid,
 | 
						|
  OUT VOID      **Data,
 | 
						|
  OUT UINTN     *DataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  AUTH_VARIABLE_INFO  AuthVariableInfo;
 | 
						|
 | 
						|
  ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
 | 
						|
  Status = mAuthVarLibContextIn->FindVariable (
 | 
						|
                                   VariableName,
 | 
						|
                                   VendorGuid,
 | 
						|
                                   &AuthVariableInfo
 | 
						|
                                   );
 | 
						|
  *Data     = AuthVariableInfo.Data;
 | 
						|
  *DataSize = AuthVariableInfo.DataSize;
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Update the variable region with Variable information.
 | 
						|
 | 
						|
  @param[in] VariableName           Name of variable.
 | 
						|
  @param[in] VendorGuid             Guid of variable.
 | 
						|
  @param[in] Data                   Data pointer.
 | 
						|
  @param[in] DataSize               Size of Data.
 | 
						|
  @param[in] Attributes             Attribute value of the variable.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS               The update operation is success.
 | 
						|
  @retval EFI_INVALID_PARAMETER     Invalid parameter.
 | 
						|
  @retval EFI_WRITE_PROTECTED       Variable is write-protected.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AuthServiceInternalUpdateVariable (
 | 
						|
  IN CHAR16    *VariableName,
 | 
						|
  IN EFI_GUID  *VendorGuid,
 | 
						|
  IN VOID      *Data,
 | 
						|
  IN UINTN     DataSize,
 | 
						|
  IN UINT32    Attributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  AUTH_VARIABLE_INFO  AuthVariableInfo;
 | 
						|
 | 
						|
  ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
 | 
						|
  AuthVariableInfo.VariableName = VariableName;
 | 
						|
  AuthVariableInfo.VendorGuid   = VendorGuid;
 | 
						|
  AuthVariableInfo.Data         = Data;
 | 
						|
  AuthVariableInfo.DataSize     = DataSize;
 | 
						|
  AuthVariableInfo.Attributes   = Attributes;
 | 
						|
 | 
						|
  return mAuthVarLibContextIn->UpdateVariable (
 | 
						|
                                 &AuthVariableInfo
 | 
						|
                                 );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Update the variable region with Variable information.
 | 
						|
 | 
						|
  @param[in] VariableName           Name of variable.
 | 
						|
  @param[in] VendorGuid             Guid of variable.
 | 
						|
  @param[in] Data                   Data pointer.
 | 
						|
  @param[in] DataSize               Size of Data.
 | 
						|
  @param[in] Attributes             Attribute value of the variable.
 | 
						|
  @param[in] TimeStamp              Value of associated TimeStamp.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS               The update operation is success.
 | 
						|
  @retval EFI_INVALID_PARAMETER     Invalid parameter.
 | 
						|
  @retval EFI_WRITE_PROTECTED       Variable is write-protected.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AuthServiceInternalUpdateVariableWithTimeStamp (
 | 
						|
  IN CHAR16    *VariableName,
 | 
						|
  IN EFI_GUID  *VendorGuid,
 | 
						|
  IN VOID      *Data,
 | 
						|
  IN UINTN     DataSize,
 | 
						|
  IN UINT32    Attributes,
 | 
						|
  IN EFI_TIME  *TimeStamp
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          FindStatus;
 | 
						|
  VOID                *OrgData;
 | 
						|
  UINTN               OrgDataSize;
 | 
						|
  AUTH_VARIABLE_INFO  AuthVariableInfo;
 | 
						|
 | 
						|
  FindStatus = AuthServiceInternalFindVariable (
 | 
						|
                 VariableName,
 | 
						|
                 VendorGuid,
 | 
						|
                 &OrgData,
 | 
						|
                 &OrgDataSize
 | 
						|
                 );
 | 
						|
 | 
						|
  //
 | 
						|
  // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
 | 
						|
  //
 | 
						|
  if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
 | 
						|
    if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
 | 
						|
         ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
 | 
						|
          (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||
 | 
						|
        (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)))
 | 
						|
    {
 | 
						|
      //
 | 
						|
      // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of
 | 
						|
      // EFI_SIGNATURE_DATA values that are already part of the existing variable value.
 | 
						|
      //
 | 
						|
      FilterSignatureList (
 | 
						|
        OrgData,
 | 
						|
        OrgDataSize,
 | 
						|
        Data,
 | 
						|
        &DataSize
 | 
						|
        );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
 | 
						|
  AuthVariableInfo.VariableName = VariableName;
 | 
						|
  AuthVariableInfo.VendorGuid   = VendorGuid;
 | 
						|
  AuthVariableInfo.Data         = Data;
 | 
						|
  AuthVariableInfo.DataSize     = DataSize;
 | 
						|
  AuthVariableInfo.Attributes   = Attributes;
 | 
						|
  AuthVariableInfo.TimeStamp    = TimeStamp;
 | 
						|
  return mAuthVarLibContextIn->UpdateVariable (
 | 
						|
                                 &AuthVariableInfo
 | 
						|
                                 );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Determine whether this operation needs a physical present user.
 | 
						|
 | 
						|
  @param[in]      VariableName            Name of the Variable.
 | 
						|
  @param[in]      VendorGuid              GUID of the Variable.
 | 
						|
 | 
						|
  @retval TRUE      This variable is protected, only a physical present user could set this variable.
 | 
						|
  @retval FALSE     This variable is not protected.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
NeedPhysicallyPresent (
 | 
						|
  IN     CHAR16    *VariableName,
 | 
						|
  IN     EFI_GUID  *VendorGuid
 | 
						|
  )
 | 
						|
{
 | 
						|
  // If the VariablePolicy engine is disabled, allow deletion of any authenticated variables.
 | 
						|
  if (IsVariablePolicyEnabled ()) {
 | 
						|
    if (  (CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))
 | 
						|
       || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0)))
 | 
						|
    {
 | 
						|
      return TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Determine whether the platform is operating in Custom Secure Boot mode.
 | 
						|
 | 
						|
  @retval TRUE           The platform is operating in Custom mode.
 | 
						|
  @retval FALSE          The platform is operating in Standard mode.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
InCustomMode (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  VOID        *Data;
 | 
						|
  UINTN       DataSize;
 | 
						|
 | 
						|
  Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize);
 | 
						|
  if (!EFI_ERROR (Status) && (*(UINT8 *)Data == CUSTOM_SECURE_BOOT_MODE)) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Update platform mode.
 | 
						|
 | 
						|
  @param[in]      Mode                    SETUP_MODE or USER_MODE.
 | 
						|
 | 
						|
  @return EFI_INVALID_PARAMETER           Invalid parameter.
 | 
						|
  @return EFI_SUCCESS                     Update platform mode successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
UpdatePlatformMode (
 | 
						|
  IN  UINT32  Mode
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  VOID        *Data;
 | 
						|
  UINTN       DataSize;
 | 
						|
  UINT8       SecureBootMode;
 | 
						|
  UINT8       SecureBootEnable;
 | 
						|
  UINTN       VariableDataSize;
 | 
						|
 | 
						|
  Status = AuthServiceInternalFindVariable (
 | 
						|
             EFI_SETUP_MODE_NAME,
 | 
						|
             &gEfiGlobalVariableGuid,
 | 
						|
             &Data,
 | 
						|
             &DataSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
 | 
						|
  // variable storage reclaim at runtime.
 | 
						|
  //
 | 
						|
  mPlatformMode = (UINT8)Mode;
 | 
						|
  CopyMem (Data, &mPlatformMode, sizeof (UINT8));
 | 
						|
 | 
						|
  if (mAuthVarLibContextIn->AtRuntime ()) {
 | 
						|
    //
 | 
						|
    // SecureBoot Variable indicates whether the platform firmware is operating
 | 
						|
    // in Secure boot mode (1) or not (0), so we should not change SecureBoot
 | 
						|
    // Variable in runtime.
 | 
						|
    //
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check "SecureBoot" variable's existence.
 | 
						|
  // If it doesn't exist, firmware has no capability to perform driver signing verification,
 | 
						|
  // then set "SecureBoot" to 0.
 | 
						|
  //
 | 
						|
  Status = AuthServiceInternalFindVariable (
 | 
						|
             EFI_SECURE_BOOT_MODE_NAME,
 | 
						|
             &gEfiGlobalVariableGuid,
 | 
						|
             &Data,
 | 
						|
             &DataSize
 | 
						|
             );
 | 
						|
  //
 | 
						|
  // If "SecureBoot" variable exists, then check "SetupMode" variable update.
 | 
						|
  // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
 | 
						|
  // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
 | 
						|
  //
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    SecureBootMode = SECURE_BOOT_MODE_DISABLE;
 | 
						|
  } else {
 | 
						|
    if (mPlatformMode == USER_MODE) {
 | 
						|
      SecureBootMode = SECURE_BOOT_MODE_ENABLE;
 | 
						|
    } else if (mPlatformMode == SETUP_MODE) {
 | 
						|
      SecureBootMode = SECURE_BOOT_MODE_DISABLE;
 | 
						|
    } else {
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Status = AuthServiceInternalUpdateVariable (
 | 
						|
             EFI_SECURE_BOOT_MODE_NAME,
 | 
						|
             &gEfiGlobalVariableGuid,
 | 
						|
             &SecureBootMode,
 | 
						|
             sizeof (UINT8),
 | 
						|
             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
 | 
						|
  //
 | 
						|
  Status = AuthServiceInternalFindVariable (
 | 
						|
             EFI_SECURE_BOOT_ENABLE_NAME,
 | 
						|
             &gEfiSecureBootEnableDisableGuid,
 | 
						|
             &Data,
 | 
						|
             &DataSize
 | 
						|
             );
 | 
						|
 | 
						|
  if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {
 | 
						|
    //
 | 
						|
    // Create the "SecureBootEnable" variable as secure boot is enabled.
 | 
						|
    //
 | 
						|
    SecureBootEnable = SECURE_BOOT_ENABLE;
 | 
						|
    VariableDataSize = sizeof (SecureBootEnable);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
 | 
						|
    // variable is not in secure boot state.
 | 
						|
    //
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    SecureBootEnable = SECURE_BOOT_DISABLE;
 | 
						|
    VariableDataSize = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = AuthServiceInternalUpdateVariable (
 | 
						|
             EFI_SECURE_BOOT_ENABLE_NAME,
 | 
						|
             &gEfiSecureBootEnableDisableGuid,
 | 
						|
             &SecureBootEnable,
 | 
						|
             VariableDataSize,
 | 
						|
             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
 | 
						|
             );
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.
 | 
						|
 | 
						|
  @param[in]  VariableName                Name of Variable to be check.
 | 
						|
  @param[in]  VendorGuid                  Variable vendor GUID.
 | 
						|
  @param[in]  Data                        Point to the variable data to be checked.
 | 
						|
  @param[in]  DataSize                    Size of Data.
 | 
						|
 | 
						|
  @return EFI_INVALID_PARAMETER           Invalid signature list format.
 | 
						|
  @return EFI_SUCCESS                     Passed signature list format check successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CheckSignatureListFormat (
 | 
						|
  IN  CHAR16    *VariableName,
 | 
						|
  IN  EFI_GUID  *VendorGuid,
 | 
						|
  IN  VOID      *Data,
 | 
						|
  IN  UINTN     DataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_SIGNATURE_LIST  *SigList;
 | 
						|
  UINTN               SigDataSize;
 | 
						|
  UINT32              Index;
 | 
						|
  UINT32              SigCount;
 | 
						|
  BOOLEAN             IsPk;
 | 
						|
  VOID                *RsaContext;
 | 
						|
  EFI_SIGNATURE_DATA  *CertData;
 | 
						|
  UINTN               CertLen;
 | 
						|
 | 
						|
  if (DataSize == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);
 | 
						|
 | 
						|
  if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)) {
 | 
						|
    IsPk = TRUE;
 | 
						|
  } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) ||
 | 
						|
             (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
 | 
						|
              ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
 | 
						|
               (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))))
 | 
						|
  {
 | 
						|
    IsPk = FALSE;
 | 
						|
  } else {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  SigCount    = 0;
 | 
						|
  SigList     = (EFI_SIGNATURE_LIST *)Data;
 | 
						|
  SigDataSize = DataSize;
 | 
						|
  RsaContext  = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Walk through the input signature list and check the data format.
 | 
						|
  // If any signature is incorrectly formed, the whole check will fail.
 | 
						|
  //
 | 
						|
  while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {
 | 
						|
    for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {
 | 
						|
      if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {
 | 
						|
        //
 | 
						|
        // The value of SignatureSize should always be 16 (size of SignatureOwner
 | 
						|
        // component) add the data length according to signature type.
 | 
						|
        //
 | 
						|
        if ((mSupportSigItem[Index].SigDataSize != ((UINT32) ~0)) &&
 | 
						|
            ((SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize))
 | 
						|
        {
 | 
						|
          return EFI_INVALID_PARAMETER;
 | 
						|
        }
 | 
						|
 | 
						|
        if ((mSupportSigItem[Index].SigHeaderSize != ((UINT32) ~0)) &&
 | 
						|
            (SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize))
 | 
						|
        {
 | 
						|
          return EFI_INVALID_PARAMETER;
 | 
						|
        }
 | 
						|
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {
 | 
						|
      //
 | 
						|
      // Undefined signature type.
 | 
						|
      //
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
 | 
						|
      //
 | 
						|
      // Try to retrieve the RSA public key from the X.509 certificate.
 | 
						|
      // If this operation fails, it's not a valid certificate.
 | 
						|
      //
 | 
						|
      RsaContext = RsaNew ();
 | 
						|
      if (RsaContext == NULL) {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      CertData = (EFI_SIGNATURE_DATA *)((UINT8 *)SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);
 | 
						|
      CertLen  = SigList->SignatureSize - sizeof (EFI_GUID);
 | 
						|
      if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {
 | 
						|
        RsaFree (RsaContext);
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      RsaFree (RsaContext);
 | 
						|
    }
 | 
						|
 | 
						|
    if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;
 | 
						|
 | 
						|
    SigDataSize -= SigList->SignatureListSize;
 | 
						|
    SigList      = (EFI_SIGNATURE_LIST *)((UINT8 *)SigList + SigList->SignatureListSize);
 | 
						|
  }
 | 
						|
 | 
						|
  if (((UINTN)SigList - (UINTN)Data) != DataSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (IsPk && (SigCount > 1)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Update "VendorKeys" variable to record the out of band secure boot key modification.
 | 
						|
 | 
						|
  @return EFI_SUCCESS           Variable is updated successfully.
 | 
						|
  @return Others                Failed to update variable.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
VendorKeyIsModified (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  mVendorKeyState = VENDOR_KEYS_MODIFIED;
 | 
						|
 | 
						|
  Status = AuthServiceInternalUpdateVariable (
 | 
						|
             EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
 | 
						|
             &gEfiVendorKeysNvGuid,
 | 
						|
             &mVendorKeyState,
 | 
						|
             sizeof (UINT8),
 | 
						|
             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  return AuthServiceInternalUpdateVariable (
 | 
						|
           EFI_VENDOR_KEYS_VARIABLE_NAME,
 | 
						|
           &gEfiGlobalVariableGuid,
 | 
						|
           &mVendorKeyState,
 | 
						|
           sizeof (UINT8),
 | 
						|
           EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process variable with platform key for verification.
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
  This function may be invoked in SMM mode, and datasize and data are external input.
 | 
						|
  This function will do basic validation, before parse the data.
 | 
						|
  This function will parse the authentication carefully to avoid security issues, like
 | 
						|
  buffer overflow, integer overflow.
 | 
						|
  This function will check attribute carefully to avoid authentication bypass.
 | 
						|
 | 
						|
  @param[in]  VariableName                Name of Variable to be found.
 | 
						|
  @param[in]  VendorGuid                  Variable vendor GUID.
 | 
						|
  @param[in]  Data                        Data pointer.
 | 
						|
  @param[in]  DataSize                    Size of Data found. If size is less than the
 | 
						|
                                          data, this value contains the required size.
 | 
						|
  @param[in]  Attributes                  Attribute value of the variable
 | 
						|
  @param[in]  IsPk                        Indicate whether it is to process pk.
 | 
						|
 | 
						|
  @return EFI_INVALID_PARAMETER           Invalid parameter.
 | 
						|
  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation.
 | 
						|
                                          check carried out by the firmware.
 | 
						|
  @return EFI_SUCCESS                     Variable passed validation successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ProcessVarWithPk (
 | 
						|
  IN  CHAR16    *VariableName,
 | 
						|
  IN  EFI_GUID  *VendorGuid,
 | 
						|
  IN  VOID      *Data,
 | 
						|
  IN  UINTN     DataSize,
 | 
						|
  IN  UINT32    Attributes OPTIONAL,
 | 
						|
  IN  BOOLEAN   IsPk
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  BOOLEAN     Del;
 | 
						|
  UINT8       *Payload;
 | 
						|
  UINTN       PayloadSize;
 | 
						|
 | 
						|
  if (((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) ||
 | 
						|
      ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0))
 | 
						|
  {
 | 
						|
    //
 | 
						|
    // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
 | 
						|
    // authenticated variable.
 | 
						|
    //
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Init state of Del. State may change due to secure check
 | 
						|
  //
 | 
						|
  Del = FALSE;
 | 
						|
  if (  (InCustomMode () && UserPhysicalPresent ())
 | 
						|
     || (  (mPlatformMode == SETUP_MODE)
 | 
						|
        && !(FeaturePcdGet (PcdRequireSelfSignedPk) && IsPk)))
 | 
						|
  {
 | 
						|
    Payload     = (UINT8 *)Data + AUTHINFO2_SIZE (Data);
 | 
						|
    PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
 | 
						|
    if (PayloadSize == 0) {
 | 
						|
      Del = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = CheckSignatureListFormat (VariableName, VendorGuid, Payload, PayloadSize);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = AuthServiceInternalUpdateVariableWithTimeStamp (
 | 
						|
               VariableName,
 | 
						|
               VendorGuid,
 | 
						|
               Payload,
 | 
						|
               PayloadSize,
 | 
						|
               Attributes,
 | 
						|
               &((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->TimeStamp
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if (  (mPlatformMode != SETUP_MODE)
 | 
						|
       || (FeaturePcdGet (PcdRequireSelfSignedPk) && IsPk))
 | 
						|
    {
 | 
						|
      Status = VendorKeyIsModified ();
 | 
						|
    }
 | 
						|
  } else if (mPlatformMode == USER_MODE) {
 | 
						|
    //
 | 
						|
    // Verify against X509 Cert in PK database.
 | 
						|
    //
 | 
						|
    Status = VerifyTimeBasedPayloadAndUpdate (
 | 
						|
               VariableName,
 | 
						|
               VendorGuid,
 | 
						|
               Data,
 | 
						|
               DataSize,
 | 
						|
               Attributes,
 | 
						|
               AuthVarTypePk,
 | 
						|
               &Del
 | 
						|
               );
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Verify against the certificate in data payload.
 | 
						|
    //
 | 
						|
    Status = VerifyTimeBasedPayloadAndUpdate (
 | 
						|
               VariableName,
 | 
						|
               VendorGuid,
 | 
						|
               Data,
 | 
						|
               DataSize,
 | 
						|
               Attributes,
 | 
						|
               AuthVarTypePayload,
 | 
						|
               &Del
 | 
						|
               );
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status) && IsPk) {
 | 
						|
    if ((mPlatformMode == SETUP_MODE) && !Del) {
 | 
						|
      //
 | 
						|
      // If enroll PK in setup mode, need change to user mode.
 | 
						|
      //
 | 
						|
      Status = UpdatePlatformMode (USER_MODE);
 | 
						|
    } else if ((mPlatformMode == USER_MODE) && Del) {
 | 
						|
      //
 | 
						|
      // If delete PK in user mode, need change to setup mode.
 | 
						|
      //
 | 
						|
      Status = UpdatePlatformMode (SETUP_MODE);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process variable with key exchange key for verification.
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
  This function may be invoked in SMM mode, and datasize and data are external input.
 | 
						|
  This function will do basic validation, before parse the data.
 | 
						|
  This function will parse the authentication carefully to avoid security issues, like
 | 
						|
  buffer overflow, integer overflow.
 | 
						|
  This function will check attribute carefully to avoid authentication bypass.
 | 
						|
 | 
						|
  @param[in]  VariableName                Name of Variable to be found.
 | 
						|
  @param[in]  VendorGuid                  Variable vendor GUID.
 | 
						|
  @param[in]  Data                        Data pointer.
 | 
						|
  @param[in]  DataSize                    Size of Data found. If size is less than the
 | 
						|
                                          data, this value contains the required size.
 | 
						|
  @param[in]  Attributes                  Attribute value of the variable.
 | 
						|
 | 
						|
  @return EFI_INVALID_PARAMETER           Invalid parameter.
 | 
						|
  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
 | 
						|
                                          check carried out by the firmware.
 | 
						|
  @return EFI_SUCCESS                     Variable pass validation successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ProcessVarWithKek (
 | 
						|
  IN  CHAR16    *VariableName,
 | 
						|
  IN  EFI_GUID  *VendorGuid,
 | 
						|
  IN  VOID      *Data,
 | 
						|
  IN  UINTN     DataSize,
 | 
						|
  IN  UINT32    Attributes OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT8       *Payload;
 | 
						|
  UINTN       PayloadSize;
 | 
						|
 | 
						|
  if (((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) ||
 | 
						|
      ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0))
 | 
						|
  {
 | 
						|
    //
 | 
						|
    // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
 | 
						|
    // authenticated variable.
 | 
						|
    //
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  if ((mPlatformMode == USER_MODE) && !(InCustomMode () && UserPhysicalPresent ())) {
 | 
						|
    //
 | 
						|
    // Time-based, verify against X509 Cert KEK.
 | 
						|
    //
 | 
						|
    return VerifyTimeBasedPayloadAndUpdate (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             Data,
 | 
						|
             DataSize,
 | 
						|
             Attributes,
 | 
						|
             AuthVarTypeKek,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // If in setup mode or custom secure boot mode, no authentication needed.
 | 
						|
    //
 | 
						|
    Payload     = (UINT8 *)Data + AUTHINFO2_SIZE (Data);
 | 
						|
    PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
 | 
						|
 | 
						|
    Status = CheckSignatureListFormat (VariableName, VendorGuid, Payload, PayloadSize);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = AuthServiceInternalUpdateVariableWithTimeStamp (
 | 
						|
               VariableName,
 | 
						|
               VendorGuid,
 | 
						|
               Payload,
 | 
						|
               PayloadSize,
 | 
						|
               Attributes,
 | 
						|
               &((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->TimeStamp
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if (mPlatformMode != SETUP_MODE) {
 | 
						|
      Status = VendorKeyIsModified ();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Check if it is to delete auth variable.
 | 
						|
 | 
						|
  @param[in] OrgAttributes      Original attribute value of the variable.
 | 
						|
  @param[in] Data               Data pointer.
 | 
						|
  @param[in] DataSize           Size of Data.
 | 
						|
  @param[in] Attributes         Attribute value of the variable.
 | 
						|
 | 
						|
  @retval TRUE                  It is to delete auth variable.
 | 
						|
  @retval FALSE                 It is not to delete auth variable.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
IsDeleteAuthVariable (
 | 
						|
  IN  UINT32  OrgAttributes,
 | 
						|
  IN  VOID    *Data,
 | 
						|
  IN  UINTN   DataSize,
 | 
						|
  IN  UINT32  Attributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN  Del;
 | 
						|
  UINTN    PayloadSize;
 | 
						|
 | 
						|
  Del = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
 | 
						|
  // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,
 | 
						|
  // SetVariable must be used with attributes matching the existing variable
 | 
						|
  // and the DataSize set to the size of the AuthInfo descriptor.
 | 
						|
  //
 | 
						|
  if ((Attributes == OrgAttributes) &&
 | 
						|
      ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0))
 | 
						|
  {
 | 
						|
    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
 | 
						|
      PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
 | 
						|
      if (PayloadSize == 0) {
 | 
						|
        Del = TRUE;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      PayloadSize = DataSize - AUTHINFO_SIZE;
 | 
						|
      if (PayloadSize == 0) {
 | 
						|
        Del = TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Del;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
  This function may be invoked in SMM mode, and datasize and data are external input.
 | 
						|
  This function will do basic validation, before parse the data.
 | 
						|
  This function will parse the authentication carefully to avoid security issues, like
 | 
						|
  buffer overflow, integer overflow.
 | 
						|
  This function will check attribute carefully to avoid authentication bypass.
 | 
						|
 | 
						|
  @param[in]  VariableName                Name of the variable.
 | 
						|
  @param[in]  VendorGuid                  Variable vendor GUID.
 | 
						|
  @param[in]  Data                        Data pointer.
 | 
						|
  @param[in]  DataSize                    Size of Data.
 | 
						|
  @param[in]  Attributes                  Attribute value of the variable.
 | 
						|
 | 
						|
  @return EFI_INVALID_PARAMETER           Invalid parameter.
 | 
						|
  @return EFI_WRITE_PROTECTED             Variable is write-protected and needs authentication with
 | 
						|
                                          EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
 | 
						|
  @return EFI_OUT_OF_RESOURCES            The Database to save the public key is full.
 | 
						|
  @return EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
 | 
						|
                                          set, but the AuthInfo does NOT pass the validation
 | 
						|
                                          check carried out by the firmware.
 | 
						|
  @return EFI_SUCCESS                     Variable is not write-protected or pass validation successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
ProcessVariable (
 | 
						|
  IN     CHAR16    *VariableName,
 | 
						|
  IN     EFI_GUID  *VendorGuid,
 | 
						|
  IN     VOID      *Data,
 | 
						|
  IN     UINTN     DataSize,
 | 
						|
  IN     UINT32    Attributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  AUTH_VARIABLE_INFO  OrgVariableInfo;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
 | 
						|
  Status = mAuthVarLibContextIn->FindVariable (
 | 
						|
                                   VariableName,
 | 
						|
                                   VendorGuid,
 | 
						|
                                   &OrgVariableInfo
 | 
						|
                                   );
 | 
						|
 | 
						|
  // If the VariablePolicy engine is disabled, allow deletion of any authenticated variables.
 | 
						|
  if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && (UserPhysicalPresent () || !IsVariablePolicyEnabled ())) {
 | 
						|
    //
 | 
						|
    // Allow the delete operation of common authenticated variable(AT or AW) at user physical presence.
 | 
						|
    //
 | 
						|
    Status = AuthServiceInternalUpdateVariable (
 | 
						|
               VariableName,
 | 
						|
               VendorGuid,
 | 
						|
               NULL,
 | 
						|
               0,
 | 
						|
               0
 | 
						|
               );
 | 
						|
    if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
 | 
						|
      Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
 | 
						|
    }
 | 
						|
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent ()) {
 | 
						|
    //
 | 
						|
    // This variable is protected, only physical present user could modify its value.
 | 
						|
    //
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
 | 
						|
    //
 | 
						|
    // Reject Counter Based Auth Variable processing request.
 | 
						|
    //
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
 | 
						|
    //
 | 
						|
    // Process Time-based Authenticated variable.
 | 
						|
    //
 | 
						|
    return VerifyTimeBasedPayloadAndUpdate (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             Data,
 | 
						|
             DataSize,
 | 
						|
             Attributes,
 | 
						|
             AuthVarTypePriv,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  }
 | 
						|
 | 
						|
  if ((OrgVariableInfo.Data != NULL) &&
 | 
						|
      ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0))
 | 
						|
  {
 | 
						|
    //
 | 
						|
    // If the variable is already write-protected, it always needs authentication before update.
 | 
						|
    //
 | 
						|
    return EFI_WRITE_PROTECTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Not authenticated variable, just update variable as usual.
 | 
						|
  //
 | 
						|
  Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
 | 
						|
 | 
						|
  @param[in]        Data          Pointer to original EFI_SIGNATURE_LIST.
 | 
						|
  @param[in]        DataSize      Size of Data buffer.
 | 
						|
  @param[in, out]   NewData       Pointer to new EFI_SIGNATURE_LIST.
 | 
						|
  @param[in, out]   NewDataSize   Size of NewData buffer.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FilterSignatureList (
 | 
						|
  IN     VOID   *Data,
 | 
						|
  IN     UINTN  DataSize,
 | 
						|
  IN OUT VOID   *NewData,
 | 
						|
  IN OUT UINTN  *NewDataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_SIGNATURE_LIST  *CertList;
 | 
						|
  EFI_SIGNATURE_DATA  *Cert;
 | 
						|
  UINTN               CertCount;
 | 
						|
  EFI_SIGNATURE_LIST  *NewCertList;
 | 
						|
  EFI_SIGNATURE_DATA  *NewCert;
 | 
						|
  UINTN               NewCertCount;
 | 
						|
  UINTN               Index;
 | 
						|
  UINTN               Index2;
 | 
						|
  UINTN               Size;
 | 
						|
  UINT8               *Tail;
 | 
						|
  UINTN               CopiedCount;
 | 
						|
  UINTN               SignatureListSize;
 | 
						|
  BOOLEAN             IsNewCert;
 | 
						|
  UINT8               *TempData;
 | 
						|
  UINTN               TempDataSize;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
 | 
						|
  if (*NewDataSize == 0) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  TempDataSize = *NewDataSize;
 | 
						|
  Status       = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **)&TempData);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Tail = TempData;
 | 
						|
 | 
						|
  NewCertList = (EFI_SIGNATURE_LIST *)NewData;
 | 
						|
  while ((*NewDataSize > 0) && (*NewDataSize >= NewCertList->SignatureListSize)) {
 | 
						|
    NewCert      = (EFI_SIGNATURE_DATA *)((UINT8 *)NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
 | 
						|
    NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
 | 
						|
 | 
						|
    CopiedCount = 0;
 | 
						|
    for (Index = 0; Index < NewCertCount; Index++) {
 | 
						|
      IsNewCert = TRUE;
 | 
						|
 | 
						|
      Size     = DataSize;
 | 
						|
      CertList = (EFI_SIGNATURE_LIST *)Data;
 | 
						|
      while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
 | 
						|
        if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
 | 
						|
            (CertList->SignatureSize == NewCertList->SignatureSize))
 | 
						|
        {
 | 
						|
          Cert      = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
 | 
						|
          CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
 | 
						|
          for (Index2 = 0; Index2 < CertCount; Index2++) {
 | 
						|
            //
 | 
						|
            // Iterate each Signature Data in this Signature List.
 | 
						|
            //
 | 
						|
            if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
 | 
						|
              IsNewCert = FALSE;
 | 
						|
              break;
 | 
						|
            }
 | 
						|
 | 
						|
            Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + CertList->SignatureSize);
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        if (!IsNewCert) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
        Size    -= CertList->SignatureListSize;
 | 
						|
        CertList = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);
 | 
						|
      }
 | 
						|
 | 
						|
      if (IsNewCert) {
 | 
						|
        //
 | 
						|
        // New EFI_SIGNATURE_DATA, keep it.
 | 
						|
        //
 | 
						|
        if (CopiedCount == 0) {
 | 
						|
          //
 | 
						|
          // Copy EFI_SIGNATURE_LIST header for only once.
 | 
						|
          //
 | 
						|
          CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
 | 
						|
          Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
 | 
						|
        }
 | 
						|
 | 
						|
        CopyMem (Tail, NewCert, NewCertList->SignatureSize);
 | 
						|
        Tail += NewCertList->SignatureSize;
 | 
						|
        CopiedCount++;
 | 
						|
      }
 | 
						|
 | 
						|
      NewCert = (EFI_SIGNATURE_DATA *)((UINT8 *)NewCert + NewCertList->SignatureSize);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Update SignatureListSize in the kept EFI_SIGNATURE_LIST.
 | 
						|
    //
 | 
						|
    if (CopiedCount != 0) {
 | 
						|
      SignatureListSize           = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
 | 
						|
      CertList                    = (EFI_SIGNATURE_LIST *)(Tail - SignatureListSize);
 | 
						|
      CertList->SignatureListSize = (UINT32)SignatureListSize;
 | 
						|
    }
 | 
						|
 | 
						|
    *NewDataSize -= NewCertList->SignatureListSize;
 | 
						|
    NewCertList   = (EFI_SIGNATURE_LIST *)((UINT8 *)NewCertList + NewCertList->SignatureListSize);
 | 
						|
  }
 | 
						|
 | 
						|
  TempDataSize = (Tail - (UINT8 *)TempData);
 | 
						|
 | 
						|
  CopyMem (NewData, TempData, TempDataSize);
 | 
						|
  *NewDataSize = TempDataSize;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Compare two EFI_TIME data.
 | 
						|
 | 
						|
 | 
						|
  @param FirstTime           A pointer to the first EFI_TIME data.
 | 
						|
  @param SecondTime          A pointer to the second EFI_TIME data.
 | 
						|
 | 
						|
  @retval  TRUE              The FirstTime is not later than the SecondTime.
 | 
						|
  @retval  FALSE             The FirstTime is later than the SecondTime.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
AuthServiceInternalCompareTimeStamp (
 | 
						|
  IN EFI_TIME  *FirstTime,
 | 
						|
  IN EFI_TIME  *SecondTime
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (FirstTime->Year != SecondTime->Year) {
 | 
						|
    return (BOOLEAN)(FirstTime->Year < SecondTime->Year);
 | 
						|
  } else if (FirstTime->Month != SecondTime->Month) {
 | 
						|
    return (BOOLEAN)(FirstTime->Month < SecondTime->Month);
 | 
						|
  } else if (FirstTime->Day != SecondTime->Day) {
 | 
						|
    return (BOOLEAN)(FirstTime->Day < SecondTime->Day);
 | 
						|
  } else if (FirstTime->Hour != SecondTime->Hour) {
 | 
						|
    return (BOOLEAN)(FirstTime->Hour < SecondTime->Hour);
 | 
						|
  } else if (FirstTime->Minute != SecondTime->Minute) {
 | 
						|
    return (BOOLEAN)(FirstTime->Minute < SecondTime->Minute);
 | 
						|
  }
 | 
						|
 | 
						|
  return (BOOLEAN)(FirstTime->Second <= SecondTime->Second);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Calculate SHA256 digest of SignerCert CommonName + ToplevelCert tbsCertificate
 | 
						|
  SignerCert and ToplevelCert are inside the signer certificate chain.
 | 
						|
 | 
						|
  @param[in]  SignerCert          A pointer to SignerCert data.
 | 
						|
  @param[in]  SignerCertSize      Length of SignerCert data.
 | 
						|
  @param[in]  TopLevelCert        A pointer to TopLevelCert data.
 | 
						|
  @param[in]  TopLevelCertSize    Length of TopLevelCert data.
 | 
						|
  @param[out] Sha256Digest       Sha256 digest calculated.
 | 
						|
 | 
						|
  @return EFI_ABORTED          Digest process failed.
 | 
						|
  @return EFI_SUCCESS          SHA256 Digest is successfully calculated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CalculatePrivAuthVarSignChainSHA256Digest (
 | 
						|
  IN     UINT8  *SignerCert,
 | 
						|
  IN     UINTN  SignerCertSize,
 | 
						|
  IN     UINT8  *TopLevelCert,
 | 
						|
  IN     UINTN  TopLevelCertSize,
 | 
						|
  OUT    UINT8  *Sha256Digest
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8       *TbsCert;
 | 
						|
  UINTN       TbsCertSize;
 | 
						|
  CHAR8       CertCommonName[128];
 | 
						|
  UINTN       CertCommonNameSize;
 | 
						|
  BOOLEAN     CryptoStatus;
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  CertCommonNameSize = sizeof (CertCommonName);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get SignerCert CommonName
 | 
						|
  //
 | 
						|
  Status = X509GetCommonName (SignerCert, SignerCertSize, CertCommonName, &CertCommonNameSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((DEBUG_INFO, "%a Get SignerCert CommonName failed with status %x\n", __func__, Status));
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get TopLevelCert tbsCertificate
 | 
						|
  //
 | 
						|
  if (!X509GetTBSCert (TopLevelCert, TopLevelCertSize, &TbsCert, &TbsCertSize)) {
 | 
						|
    DEBUG ((DEBUG_INFO, "%a Get Top-level Cert tbsCertificate failed!\n", __func__));
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Digest SignerCert CN + TopLevelCert tbsCertificate
 | 
						|
  //
 | 
						|
  ZeroMem (Sha256Digest, SHA256_DIGEST_SIZE);
 | 
						|
  CryptoStatus = Sha256Init (mHashCtx);
 | 
						|
  if (!CryptoStatus) {
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // '\0' is forced in CertCommonName. No overflow issue
 | 
						|
  //
 | 
						|
  CryptoStatus = Sha256Update (
 | 
						|
                   mHashCtx,
 | 
						|
                   CertCommonName,
 | 
						|
                   AsciiStrLen (CertCommonName)
 | 
						|
                   );
 | 
						|
  if (!CryptoStatus) {
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  CryptoStatus = Sha256Update (mHashCtx, TbsCert, TbsCertSize);
 | 
						|
  if (!CryptoStatus) {
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  CryptoStatus = Sha256Final (mHashCtx, Sha256Digest);
 | 
						|
  if (!CryptoStatus) {
 | 
						|
    return EFI_ABORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find matching signer's certificates for common authenticated variable
 | 
						|
  by corresponding VariableName and VendorGuid from "certdb" or "certdbv".
 | 
						|
 | 
						|
  The data format of "certdb" or "certdbv":
 | 
						|
  //
 | 
						|
  //     UINT32 CertDbListSize;
 | 
						|
  // /// AUTH_CERT_DB_DATA Certs1[];
 | 
						|
  // /// AUTH_CERT_DB_DATA Certs2[];
 | 
						|
  // /// ...
 | 
						|
  // /// AUTH_CERT_DB_DATA Certsn[];
 | 
						|
  //
 | 
						|
 | 
						|
  @param[in]  VariableName   Name of authenticated Variable.
 | 
						|
  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
 | 
						|
  @param[in]  Data           Pointer to variable "certdb" or "certdbv".
 | 
						|
  @param[in]  DataSize       Size of variable "certdb" or "certdbv".
 | 
						|
  @param[out] CertOffset     Offset of matching CertData, from starting of Data.
 | 
						|
  @param[out] CertDataSize   Length of CertData in bytes.
 | 
						|
  @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
 | 
						|
                             starting of Data.
 | 
						|
  @param[out] CertNodeSize   Length of AUTH_CERT_DB_DATA in bytes.
 | 
						|
 | 
						|
  @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
 | 
						|
  @retval  EFI_NOT_FOUND         Fail to find matching certs.
 | 
						|
  @retval  EFI_SUCCESS           Find matching certs and output parameters.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
FindCertsFromDb (
 | 
						|
  IN     CHAR16    *VariableName,
 | 
						|
  IN     EFI_GUID  *VendorGuid,
 | 
						|
  IN     UINT8     *Data,
 | 
						|
  IN     UINTN     DataSize,
 | 
						|
  OUT    UINT32    *CertOffset     OPTIONAL,
 | 
						|
  OUT    UINT32    *CertDataSize   OPTIONAL,
 | 
						|
  OUT    UINT32    *CertNodeOffset OPTIONAL,
 | 
						|
  OUT    UINT32    *CertNodeSize   OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32             Offset;
 | 
						|
  AUTH_CERT_DB_DATA  *Ptr;
 | 
						|
  UINT32             CertSize;
 | 
						|
  UINT32             NameSize;
 | 
						|
  UINT32             NodeSize;
 | 
						|
  UINT32             CertDbListSize;
 | 
						|
 | 
						|
  if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether DataSize matches recorded CertDbListSize.
 | 
						|
  //
 | 
						|
  if (DataSize < sizeof (UINT32)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  CertDbListSize = ReadUnaligned32 ((UINT32 *)Data);
 | 
						|
 | 
						|
  if (CertDbListSize != (UINT32)DataSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Offset = sizeof (UINT32);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get corresponding certificates by VendorGuid and VariableName.
 | 
						|
  //
 | 
						|
  while (Offset < (UINT32)DataSize) {
 | 
						|
    Ptr = (AUTH_CERT_DB_DATA *)(Data + Offset);
 | 
						|
    //
 | 
						|
    // Check whether VendorGuid matches.
 | 
						|
    //
 | 
						|
    if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
 | 
						|
      NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
 | 
						|
      NameSize = ReadUnaligned32 (&Ptr->NameSize);
 | 
						|
      CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
 | 
						|
 | 
						|
      if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
 | 
						|
          sizeof (CHAR16) * NameSize)
 | 
						|
      {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
 | 
						|
      //
 | 
						|
      // Check whether VariableName matches.
 | 
						|
      //
 | 
						|
      if ((NameSize == StrLen (VariableName)) &&
 | 
						|
          (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0))
 | 
						|
      {
 | 
						|
        Offset = Offset + NameSize * sizeof (CHAR16);
 | 
						|
 | 
						|
        if (CertOffset != NULL) {
 | 
						|
          *CertOffset = Offset;
 | 
						|
        }
 | 
						|
 | 
						|
        if (CertDataSize != NULL) {
 | 
						|
          *CertDataSize = CertSize;
 | 
						|
        }
 | 
						|
 | 
						|
        if (CertNodeOffset != NULL) {
 | 
						|
          *CertNodeOffset = (UINT32)((UINT8 *)Ptr - Data);
 | 
						|
        }
 | 
						|
 | 
						|
        if (CertNodeSize != NULL) {
 | 
						|
          *CertNodeSize = NodeSize;
 | 
						|
        }
 | 
						|
 | 
						|
        return EFI_SUCCESS;
 | 
						|
      } else {
 | 
						|
        Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
 | 
						|
      Offset   = Offset + NodeSize;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieve signer's certificates for common authenticated variable
 | 
						|
  by corresponding VariableName and VendorGuid from "certdb"
 | 
						|
  or "certdbv" according to authenticated variable attributes.
 | 
						|
 | 
						|
  @param[in]  VariableName   Name of authenticated Variable.
 | 
						|
  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
 | 
						|
  @param[in]  Attributes        Attributes of authenticated variable.
 | 
						|
  @param[out] CertData       Pointer to signer's certificates.
 | 
						|
  @param[out] CertDataSize   Length of CertData in bytes.
 | 
						|
 | 
						|
  @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
 | 
						|
  @retval  EFI_NOT_FOUND         Fail to find "certdb"/"certdbv" or matching certs.
 | 
						|
  @retval  EFI_SUCCESS           Get signer's certificates successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetCertsFromDb (
 | 
						|
  IN     CHAR16    *VariableName,
 | 
						|
  IN     EFI_GUID  *VendorGuid,
 | 
						|
  IN     UINT32    Attributes,
 | 
						|
  OUT    UINT8     **CertData,
 | 
						|
  OUT    UINT32    *CertDataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT8       *Data;
 | 
						|
  UINTN       DataSize;
 | 
						|
  UINT32      CertOffset;
 | 
						|
  CHAR16      *DbName;
 | 
						|
 | 
						|
  if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
 | 
						|
    //
 | 
						|
    // Get variable "certdb".
 | 
						|
    //
 | 
						|
    DbName = EFI_CERT_DB_NAME;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Get variable "certdbv".
 | 
						|
    //
 | 
						|
    DbName = EFI_CERT_DB_VOLATILE_NAME;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get variable "certdb" or "certdbv".
 | 
						|
  //
 | 
						|
  Status = AuthServiceInternalFindVariable (
 | 
						|
             DbName,
 | 
						|
             &gEfiCertDbGuid,
 | 
						|
             (VOID **)&Data,
 | 
						|
             &DataSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DataSize == 0) || (Data == NULL)) {
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FindCertsFromDb (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             Data,
 | 
						|
             DataSize,
 | 
						|
             &CertOffset,
 | 
						|
             CertDataSize,
 | 
						|
             NULL,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  *CertData = Data + CertOffset;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Delete matching signer's certificates when deleting common authenticated
 | 
						|
  variable by corresponding VariableName and VendorGuid from "certdb" or
 | 
						|
  "certdbv" according to authenticated variable attributes.
 | 
						|
 | 
						|
  @param[in]  VariableName   Name of authenticated Variable.
 | 
						|
  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
 | 
						|
  @param[in]  Attributes        Attributes of authenticated variable.
 | 
						|
 | 
						|
  @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
 | 
						|
  @retval  EFI_NOT_FOUND         Fail to find "certdb"/"certdbv" or matching certs.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.
 | 
						|
  @retval  EFI_SUCCESS           The operation is completed successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
DeleteCertsFromDb (
 | 
						|
  IN     CHAR16    *VariableName,
 | 
						|
  IN     EFI_GUID  *VendorGuid,
 | 
						|
  IN     UINT32    Attributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT8       *Data;
 | 
						|
  UINTN       DataSize;
 | 
						|
  UINT32      VarAttr;
 | 
						|
  UINT32      CertNodeOffset;
 | 
						|
  UINT32      CertNodeSize;
 | 
						|
  UINT8       *NewCertDb;
 | 
						|
  UINT32      NewCertDbSize;
 | 
						|
  CHAR16      *DbName;
 | 
						|
 | 
						|
  if ((VariableName == NULL) || (VendorGuid == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
 | 
						|
    //
 | 
						|
    // Get variable "certdb".
 | 
						|
    //
 | 
						|
    DbName  = EFI_CERT_DB_NAME;
 | 
						|
    VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Get variable "certdbv".
 | 
						|
    //
 | 
						|
    DbName  = EFI_CERT_DB_VOLATILE_NAME;
 | 
						|
    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = AuthServiceInternalFindVariable (
 | 
						|
             DbName,
 | 
						|
             &gEfiCertDbGuid,
 | 
						|
             (VOID **)&Data,
 | 
						|
             &DataSize
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DataSize == 0) || (Data == NULL)) {
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DataSize == sizeof (UINT32)) {
 | 
						|
    //
 | 
						|
    // There is no certs in "certdb" or "certdbv".
 | 
						|
    //
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get corresponding cert node from "certdb" or "certdbv".
 | 
						|
  //
 | 
						|
  Status = FindCertsFromDb (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             Data,
 | 
						|
             DataSize,
 | 
						|
             NULL,
 | 
						|
             NULL,
 | 
						|
             &CertNodeOffset,
 | 
						|
             &CertNodeSize
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DataSize < (CertNodeOffset + CertNodeSize)) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Construct new data content of variable "certdb" or "certdbv".
 | 
						|
  //
 | 
						|
  NewCertDbSize = (UINT32)DataSize - CertNodeSize;
 | 
						|
  NewCertDb     = (UINT8 *)mCertDbStore;
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy the DB entries before deleting node.
 | 
						|
  //
 | 
						|
  CopyMem (NewCertDb, Data, CertNodeOffset);
 | 
						|
  //
 | 
						|
  // Update CertDbListSize.
 | 
						|
  //
 | 
						|
  CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
 | 
						|
  //
 | 
						|
  // Copy the DB entries after deleting node.
 | 
						|
  //
 | 
						|
  if (DataSize > (CertNodeOffset + CertNodeSize)) {
 | 
						|
    CopyMem (
 | 
						|
      NewCertDb + CertNodeOffset,
 | 
						|
      Data + CertNodeOffset + CertNodeSize,
 | 
						|
      DataSize - CertNodeOffset - CertNodeSize
 | 
						|
      );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Set "certdb" or "certdbv".
 | 
						|
  //
 | 
						|
  Status = AuthServiceInternalUpdateVariable (
 | 
						|
             DbName,
 | 
						|
             &gEfiCertDbGuid,
 | 
						|
             NewCertDb,
 | 
						|
             NewCertDbSize,
 | 
						|
             VarAttr
 | 
						|
             );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Insert signer's certificates for common authenticated variable with VariableName
 | 
						|
  and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to
 | 
						|
  time based authenticated variable attributes. CertData is the SHA256 digest of
 | 
						|
  SignerCert CommonName + TopLevelCert tbsCertificate.
 | 
						|
 | 
						|
  @param[in]  VariableName      Name of authenticated Variable.
 | 
						|
  @param[in]  VendorGuid        Vendor GUID of authenticated Variable.
 | 
						|
  @param[in]  Attributes        Attributes of authenticated variable.
 | 
						|
  @param[in]  SignerCert        Signer certificate data.
 | 
						|
  @param[in]  SignerCertSize    Length of signer certificate.
 | 
						|
  @param[in]  TopLevelCert      Top-level certificate data.
 | 
						|
  @param[in]  TopLevelCertSize  Length of top-level certificate.
 | 
						|
 | 
						|
  @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
 | 
						|
  @retval  EFI_ACCESS_DENIED     An AUTH_CERT_DB_DATA entry with same VariableName
 | 
						|
                                 and VendorGuid already exists.
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.
 | 
						|
  @retval  EFI_SUCCESS           Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv"
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
InsertCertsToDb (
 | 
						|
  IN     CHAR16    *VariableName,
 | 
						|
  IN     EFI_GUID  *VendorGuid,
 | 
						|
  IN     UINT32    Attributes,
 | 
						|
  IN     UINT8     *SignerCert,
 | 
						|
  IN     UINTN     SignerCertSize,
 | 
						|
  IN     UINT8     *TopLevelCert,
 | 
						|
  IN     UINTN     TopLevelCertSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS         Status;
 | 
						|
  UINT8              *Data;
 | 
						|
  UINTN              DataSize;
 | 
						|
  UINT32             VarAttr;
 | 
						|
  UINT8              *NewCertDb;
 | 
						|
  UINT32             NewCertDbSize;
 | 
						|
  UINT32             CertNodeSize;
 | 
						|
  UINT32             NameSize;
 | 
						|
  UINT32             CertDataSize;
 | 
						|
  AUTH_CERT_DB_DATA  *Ptr;
 | 
						|
  CHAR16             *DbName;
 | 
						|
  UINT8              Sha256Digest[SHA256_DIGEST_SIZE];
 | 
						|
 | 
						|
  if ((VariableName == NULL) || (VendorGuid == NULL) || (SignerCert == NULL) || (TopLevelCert == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
 | 
						|
    //
 | 
						|
    // Get variable "certdb".
 | 
						|
    //
 | 
						|
    DbName  = EFI_CERT_DB_NAME;
 | 
						|
    VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Get variable "certdbv".
 | 
						|
    //
 | 
						|
    DbName  = EFI_CERT_DB_VOLATILE_NAME;
 | 
						|
    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get variable "certdb" or "certdbv".
 | 
						|
  //
 | 
						|
  Status = AuthServiceInternalFindVariable (
 | 
						|
             DbName,
 | 
						|
             &gEfiCertDbGuid,
 | 
						|
             (VOID **)&Data,
 | 
						|
             &DataSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DataSize == 0) || (Data == NULL)) {
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Find whether matching cert node already exists in "certdb" or "certdbv".
 | 
						|
  // If yes return error.
 | 
						|
  //
 | 
						|
  Status = FindCertsFromDb (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             Data,
 | 
						|
             DataSize,
 | 
						|
             NULL,
 | 
						|
             NULL,
 | 
						|
             NULL,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return EFI_ACCESS_DENIED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Construct new data content of variable "certdb" or "certdbv".
 | 
						|
  //
 | 
						|
  NameSize      = (UINT32)StrLen (VariableName);
 | 
						|
  CertDataSize  = sizeof (Sha256Digest);
 | 
						|
  CertNodeSize  = sizeof (AUTH_CERT_DB_DATA) + (UINT32)CertDataSize + NameSize * sizeof (CHAR16);
 | 
						|
  NewCertDbSize = (UINT32)DataSize + CertNodeSize;
 | 
						|
  if (NewCertDbSize > mMaxCertDbSize) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = CalculatePrivAuthVarSignChainSHA256Digest (
 | 
						|
             SignerCert,
 | 
						|
             SignerCertSize,
 | 
						|
             TopLevelCert,
 | 
						|
             TopLevelCertSize,
 | 
						|
             Sha256Digest
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  NewCertDb = (UINT8 *)mCertDbStore;
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy the DB entries before inserting node.
 | 
						|
  //
 | 
						|
  CopyMem (NewCertDb, Data, DataSize);
 | 
						|
  //
 | 
						|
  // Update CertDbListSize.
 | 
						|
  //
 | 
						|
  CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
 | 
						|
  //
 | 
						|
  // Construct new cert node.
 | 
						|
  //
 | 
						|
  Ptr = (AUTH_CERT_DB_DATA *)(NewCertDb + DataSize);
 | 
						|
  CopyGuid (&Ptr->VendorGuid, VendorGuid);
 | 
						|
  CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
 | 
						|
  CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
 | 
						|
  CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    (UINT8 *)Ptr + sizeof (AUTH_CERT_DB_DATA),
 | 
						|
    VariableName,
 | 
						|
    NameSize * sizeof (CHAR16)
 | 
						|
    );
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    (UINT8 *)Ptr +  sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
 | 
						|
    Sha256Digest,
 | 
						|
    CertDataSize
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Set "certdb" or "certdbv".
 | 
						|
  //
 | 
						|
  Status = AuthServiceInternalUpdateVariable (
 | 
						|
             DbName,
 | 
						|
             &gEfiCertDbGuid,
 | 
						|
             NewCertDb,
 | 
						|
             NewCertDbSize,
 | 
						|
             VarAttr
 | 
						|
             );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Clean up signer's certificates for common authenticated variable
 | 
						|
  by corresponding VariableName and VendorGuid from "certdb".
 | 
						|
  System may break down during Timebased Variable update & certdb update,
 | 
						|
  make them inconsistent,  this function is called in AuthVariable Init
 | 
						|
  to ensure consistency.
 | 
						|
 | 
						|
  @retval  EFI_NOT_FOUND         Fail to find variable "certdb".
 | 
						|
  @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.
 | 
						|
  @retval  EFI_SUCCESS           The operation is completed successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
CleanCertsFromDb (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32              Offset;
 | 
						|
  AUTH_CERT_DB_DATA   *Ptr;
 | 
						|
  UINT32              NameSize;
 | 
						|
  UINT32              NodeSize;
 | 
						|
  CHAR16              *VariableName;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  BOOLEAN             CertCleaned;
 | 
						|
  UINT8               *Data;
 | 
						|
  UINTN               DataSize;
 | 
						|
  EFI_GUID            AuthVarGuid;
 | 
						|
  AUTH_VARIABLE_INFO  AuthVariableInfo;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get corresponding certificates by VendorGuid and VariableName.
 | 
						|
  //
 | 
						|
  do {
 | 
						|
    CertCleaned = FALSE;
 | 
						|
 | 
						|
    //
 | 
						|
    // Get latest variable "certdb"
 | 
						|
    //
 | 
						|
    Status = AuthServiceInternalFindVariable (
 | 
						|
               EFI_CERT_DB_NAME,
 | 
						|
               &gEfiCertDbGuid,
 | 
						|
               (VOID **)&Data,
 | 
						|
               &DataSize
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((DataSize == 0) || (Data == NULL)) {
 | 
						|
      ASSERT (FALSE);
 | 
						|
      return EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
 | 
						|
    Offset = sizeof (UINT32);
 | 
						|
 | 
						|
    while (Offset < (UINT32)DataSize) {
 | 
						|
      Ptr      = (AUTH_CERT_DB_DATA *)(Data + Offset);
 | 
						|
      NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
 | 
						|
      NameSize = ReadUnaligned32 (&Ptr->NameSize);
 | 
						|
 | 
						|
      //
 | 
						|
      // Get VarName tailed with '\0'
 | 
						|
      //
 | 
						|
      VariableName = AllocateZeroPool ((NameSize + 1) * sizeof (CHAR16));
 | 
						|
      if (VariableName == NULL) {
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
 | 
						|
      CopyMem (VariableName, (UINT8 *)Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof (CHAR16));
 | 
						|
      //
 | 
						|
      // Keep VarGuid  aligned
 | 
						|
      //
 | 
						|
      CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof (EFI_GUID));
 | 
						|
 | 
						|
      //
 | 
						|
      // Find corresponding time auth variable
 | 
						|
      //
 | 
						|
      ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
 | 
						|
      Status = mAuthVarLibContextIn->FindVariable (
 | 
						|
                                       VariableName,
 | 
						|
                                       &AuthVarGuid,
 | 
						|
                                       &AuthVariableInfo
 | 
						|
                                       );
 | 
						|
 | 
						|
      if (EFI_ERROR (Status) || ((AuthVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0)) {
 | 
						|
        //
 | 
						|
        // While cleaning certdb, always delete the variable in certdb regardless of it attributes.
 | 
						|
        //
 | 
						|
        Status = DeleteCertsFromDb (
 | 
						|
                   VariableName,
 | 
						|
                   &AuthVarGuid,
 | 
						|
                   AuthVariableInfo.Attributes | EFI_VARIABLE_NON_VOLATILE
 | 
						|
                   );
 | 
						|
        CertCleaned = TRUE;
 | 
						|
        DEBUG ((DEBUG_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid));
 | 
						|
        FreePool (VariableName);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      FreePool (VariableName);
 | 
						|
      Offset = Offset + NodeSize;
 | 
						|
    }
 | 
						|
  } while (CertCleaned);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
  This function may be invoked in SMM mode, and datasize and data are external input.
 | 
						|
  This function will do basic validation, before parse the data.
 | 
						|
  This function will parse the authentication carefully to avoid security issues, like
 | 
						|
  buffer overflow, integer overflow.
 | 
						|
 | 
						|
  @param[in]  VariableName                Name of Variable to be found.
 | 
						|
  @param[in]  VendorGuid                  Variable vendor GUID.
 | 
						|
  @param[in]  Data                        Data pointer.
 | 
						|
  @param[in]  DataSize                    Size of Data found. If size is less than the
 | 
						|
                                          data, this value contains the required size.
 | 
						|
  @param[in]  Attributes                  Attribute value of the variable.
 | 
						|
  @param[in]  AuthVarType                 Verify against PK, KEK database, private database or certificate in data payload.
 | 
						|
  @param[in]  OrgTimeStamp                Pointer to original time stamp,
 | 
						|
                                          original variable is not found if NULL.
 | 
						|
  @param[out]  VarPayloadPtr              Pointer to variable payload address.
 | 
						|
  @param[out]  VarPayloadSize             Pointer to variable payload size.
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER           Invalid parameter.
 | 
						|
  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
 | 
						|
                                          check carried out by the firmware.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack
 | 
						|
                                          of resources.
 | 
						|
  @retval EFI_SUCCESS                     Variable pass validation successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
VerifyTimeBasedPayload (
 | 
						|
  IN     CHAR16        *VariableName,
 | 
						|
  IN     EFI_GUID      *VendorGuid,
 | 
						|
  IN     VOID          *Data,
 | 
						|
  IN     UINTN         DataSize,
 | 
						|
  IN     UINT32        Attributes,
 | 
						|
  IN     AUTHVAR_TYPE  AuthVarType,
 | 
						|
  IN     EFI_TIME      *OrgTimeStamp,
 | 
						|
  OUT    UINT8         **VarPayloadPtr,
 | 
						|
  OUT    UINTN         *VarPayloadSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_VARIABLE_AUTHENTICATION_2  *CertData;
 | 
						|
  UINT8                          *SigData;
 | 
						|
  UINT32                         SigDataSize;
 | 
						|
  UINT8                          *PayloadPtr;
 | 
						|
  UINTN                          PayloadSize;
 | 
						|
  UINT32                         Attr;
 | 
						|
  BOOLEAN                        VerifyStatus;
 | 
						|
  EFI_STATUS                     Status;
 | 
						|
  EFI_SIGNATURE_LIST             *CertList;
 | 
						|
  EFI_SIGNATURE_DATA             *Cert;
 | 
						|
  UINTN                          Index;
 | 
						|
  UINTN                          CertCount;
 | 
						|
  UINT32                         KekDataSize;
 | 
						|
  UINT8                          *NewData;
 | 
						|
  UINTN                          NewDataSize;
 | 
						|
  UINT8                          *Buffer;
 | 
						|
  UINTN                          Length;
 | 
						|
  UINT8                          *TopLevelCert;
 | 
						|
  UINTN                          TopLevelCertSize;
 | 
						|
  UINT8                          *TrustedCert;
 | 
						|
  UINTN                          TrustedCertSize;
 | 
						|
  UINT8                          *SignerCerts;
 | 
						|
  UINTN                          CertStackSize;
 | 
						|
  UINT8                          *CertsInCertDb;
 | 
						|
  UINT32                         CertsSizeinDb;
 | 
						|
  UINT8                          Sha256Digest[SHA256_DIGEST_SIZE];
 | 
						|
  EFI_CERT_DATA                  *CertDataPtr;
 | 
						|
 | 
						|
  //
 | 
						|
  // 1. TopLevelCert is the top-level issuer certificate in signature Signer Cert Chain
 | 
						|
  // 2. TrustedCert is the certificate which firmware trusts. It could be saved in protected
 | 
						|
  //     storage or PK payload on PK init
 | 
						|
  //
 | 
						|
  VerifyStatus  = FALSE;
 | 
						|
  CertData      = NULL;
 | 
						|
  NewData       = NULL;
 | 
						|
  Attr          = Attributes;
 | 
						|
  SignerCerts   = NULL;
 | 
						|
  TopLevelCert  = NULL;
 | 
						|
  CertsInCertDb = NULL;
 | 
						|
  CertDataPtr   = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
 | 
						|
  // set, then the Data buffer shall begin with an instance of a complete (and serialized)
 | 
						|
  // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
 | 
						|
  // variable value and DataSize shall reflect the combined size of the descriptor and the new
 | 
						|
  // variable value. The authentication descriptor is not part of the variable data and is not
 | 
						|
  // returned by subsequent calls to GetVariable().
 | 
						|
  //
 | 
						|
  CertData = (EFI_VARIABLE_AUTHENTICATION_2 *)Data;
 | 
						|
 | 
						|
  //
 | 
						|
  // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
 | 
						|
  // TimeStamp value are set to zero.
 | 
						|
  //
 | 
						|
  if ((CertData->TimeStamp.Pad1 != 0) ||
 | 
						|
      (CertData->TimeStamp.Nanosecond != 0) ||
 | 
						|
      (CertData->TimeStamp.TimeZone != 0) ||
 | 
						|
      (CertData->TimeStamp.Daylight != 0) ||
 | 
						|
      (CertData->TimeStamp.Pad2 != 0))
 | 
						|
  {
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
 | 
						|
    if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) {
 | 
						|
      //
 | 
						|
      // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
 | 
						|
      //
 | 
						|
      return EFI_SECURITY_VIOLATION;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
 | 
						|
  // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
 | 
						|
  //
 | 
						|
  if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
 | 
						|
      !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid))
 | 
						|
  {
 | 
						|
    //
 | 
						|
    // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
 | 
						|
    //
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
 | 
						|
  // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
 | 
						|
  //
 | 
						|
  SigData     = CertData->AuthInfo.CertData;
 | 
						|
  SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
 | 
						|
 | 
						|
  //
 | 
						|
  // SignedData.digestAlgorithms shall contain the digest algorithm used when preparing the
 | 
						|
  // signature. Only a digest algorithm of SHA-256 is accepted.
 | 
						|
  //
 | 
						|
  //    According to PKCS#7 Definition (https://www.rfc-editor.org/rfc/rfc2315):
 | 
						|
  //        SignedData ::= SEQUENCE {
 | 
						|
  //            version Version,
 | 
						|
  //            digestAlgorithms DigestAlgorithmIdentifiers,
 | 
						|
  //            contentInfo ContentInfo,
 | 
						|
  //            .... }
 | 
						|
  //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm
 | 
						|
  //    in VARIABLE_AUTHENTICATION_2 descriptor.
 | 
						|
  //    This field has the fixed offset (+13) or (+32) based on whether the DER-encoded
 | 
						|
  //    ContentInfo structure is present or not, and can be calculated based on two
 | 
						|
  //    bytes of length encoding.
 | 
						|
  //
 | 
						|
  //    Both condition can be handled in WrapPkcs7Data() in CryptPkcs7VerifyCommon.c.
 | 
						|
  //
 | 
						|
  //    See below examples:
 | 
						|
  //
 | 
						|
  // 1. Without ContentInfo
 | 
						|
  //    30 82 0c da // SEQUENCE (5 element) (3294 BYTES) -- SignedData
 | 
						|
  //       02 01 01 // INTEGER 1 -- Version
 | 
						|
  //       31 0f // SET (1 element) (15 BYTES) -- DigestAlgorithmIdentifiers
 | 
						|
  //          30 0d // SEQUENCE (2 element) (13 BYTES) -- AlgorithmIdentifier
 | 
						|
  //             06 09 // OBJECT-IDENTIFIER (9 BYTES) -- algorithm
 | 
						|
  //                60 86 48 01 65 03 04 02 01 // sha256 [2.16.840.1.101.3.4.2.1]
 | 
						|
  //             05 00 // NULL (0 BYTES) -- parameters
 | 
						|
  //
 | 
						|
  // Example from: https://uefi.org/revocationlistfile
 | 
						|
  //
 | 
						|
  // 2. With ContentInfo
 | 
						|
  //    30 82 05 90 // SEQUENCE (1424 BYTES) -- ContentInfo
 | 
						|
  //       06 09 // OBJECT-IDENTIFIER (9 BYTES) -- ContentType
 | 
						|
  //          2a 86 48 86 f7 0d 01 07 02 // signedData [1.2.840.113549.1.7.2]
 | 
						|
  //       a0 82 05 81 // CONTEXT-SPECIFIC CONSTRUCTED TAG 0 (1409 BYTES) -- content
 | 
						|
  //          30 82 05 7d // SEQUENCE (1405 BYTES) -- SignedData
 | 
						|
  //             02 01 01 // INTEGER 1 -- Version
 | 
						|
  //             31 0f // SET (1 element) (15 BYTES) -- DigestAlgorithmIdentifiers
 | 
						|
  //                30 0d // SEQUENCE (13 BYTES) -- AlgorithmIdentifier
 | 
						|
  //                   06 09 // OBJECT-IDENTIFIER (9 BYTES) -- algorithm
 | 
						|
  //                      60 86 48 01 65 03 04 02 01 // sha256 [2.16.840.1.101.3.4.2.1]
 | 
						|
  //                   05 00 // NULL (0 BYTES) -- parameters
 | 
						|
  //
 | 
						|
  // Example generated with: https://wiki.archlinux.org/title/Unified_Extensible_Firmware_Interface/Secure_Boot#Manual_process
 | 
						|
  //
 | 
						|
  if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
 | 
						|
    if (  (  (SigDataSize >= (13 + sizeof (mSha256OidValue)))
 | 
						|
          && (  ((*(SigData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE)
 | 
						|
             || (CompareMem (SigData + 13, &mSha256OidValue, sizeof (mSha256OidValue)) != 0)))
 | 
						|
       && (  (SigDataSize >= (32 + sizeof (mSha256OidValue)))
 | 
						|
          && (  ((*(SigData + 20) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE)
 | 
						|
             || (CompareMem (SigData + 32, &mSha256OidValue, sizeof (mSha256OidValue)) != 0))))
 | 
						|
    {
 | 
						|
      return EFI_SECURITY_VIOLATION;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out the new data payload which follows Pkcs7 SignedData directly.
 | 
						|
  //
 | 
						|
  PayloadPtr  = SigData + SigDataSize;
 | 
						|
  PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN)SigDataSize;
 | 
						|
 | 
						|
  // If the VariablePolicy engine is disabled, allow deletion of any authenticated variables.
 | 
						|
  if ((PayloadSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && !IsVariablePolicyEnabled ()) {
 | 
						|
    VerifyStatus = TRUE;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes
 | 
						|
  // parameters of the SetVariable() call and the TimeStamp component of the
 | 
						|
  // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
 | 
						|
  // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
 | 
						|
  //
 | 
						|
  NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
 | 
						|
                sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
 | 
						|
 | 
						|
  //
 | 
						|
  // Here is to reuse scratch data area(at the end of volatile variable store)
 | 
						|
  // to reduce SMRAM consumption for SMM variable driver.
 | 
						|
  // The scratch buffer is enough to hold the serialized data and safe to use,
 | 
						|
  // because it is only used at here to do verification temporarily first
 | 
						|
  // and then used in UpdateVariable() for a time based auth variable set.
 | 
						|
  //
 | 
						|
  Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **)&NewData);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Buffer = NewData;
 | 
						|
  Length = StrLen (VariableName) * sizeof (CHAR16);
 | 
						|
  CopyMem (Buffer, VariableName, Length);
 | 
						|
  Buffer += Length;
 | 
						|
 | 
						|
  Length = sizeof (EFI_GUID);
 | 
						|
  CopyMem (Buffer, VendorGuid, Length);
 | 
						|
  Buffer += Length;
 | 
						|
 | 
						|
  Length = sizeof (UINT32);
 | 
						|
  CopyMem (Buffer, &Attr, Length);
 | 
						|
  Buffer += Length;
 | 
						|
 | 
						|
  Length = sizeof (EFI_TIME);
 | 
						|
  CopyMem (Buffer, &CertData->TimeStamp, Length);
 | 
						|
  Buffer += Length;
 | 
						|
 | 
						|
  CopyMem (Buffer, PayloadPtr, PayloadSize);
 | 
						|
 | 
						|
  if (AuthVarType == AuthVarTypePk) {
 | 
						|
    //
 | 
						|
    // Verify that the signature has been made with the current Platform Key (no chaining for PK).
 | 
						|
    // First, get signer's certificates from SignedData.
 | 
						|
    //
 | 
						|
    VerifyStatus = Pkcs7GetSigners (
 | 
						|
                     SigData,
 | 
						|
                     SigDataSize,
 | 
						|
                     &SignerCerts,
 | 
						|
                     &CertStackSize,
 | 
						|
                     &TopLevelCert,
 | 
						|
                     &TopLevelCertSize
 | 
						|
                     );
 | 
						|
    if (!VerifyStatus) {
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Second, get the current platform key from variable. Check whether it's identical with signer's certificates
 | 
						|
    // in SignedData. If not, return error immediately.
 | 
						|
    //
 | 
						|
    Status = AuthServiceInternalFindVariable (
 | 
						|
               EFI_PLATFORM_KEY_NAME,
 | 
						|
               &gEfiGlobalVariableGuid,
 | 
						|
               &Data,
 | 
						|
               &DataSize
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      VerifyStatus = FALSE;
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
 | 
						|
    CertList = (EFI_SIGNATURE_LIST *)Data;
 | 
						|
    Cert     = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
 | 
						|
    if ((TopLevelCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||
 | 
						|
        (CompareMem (Cert->SignatureData, TopLevelCert, TopLevelCertSize) != 0))
 | 
						|
    {
 | 
						|
      VerifyStatus = FALSE;
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Verify Pkcs7 SignedData via Pkcs7Verify library.
 | 
						|
    //
 | 
						|
    VerifyStatus = Pkcs7Verify (
 | 
						|
                     SigData,
 | 
						|
                     SigDataSize,
 | 
						|
                     TopLevelCert,
 | 
						|
                     TopLevelCertSize,
 | 
						|
                     NewData,
 | 
						|
                     NewDataSize
 | 
						|
                     );
 | 
						|
  } else if (AuthVarType == AuthVarTypeKek) {
 | 
						|
    //
 | 
						|
    // Get KEK database from variable.
 | 
						|
    //
 | 
						|
    Status = AuthServiceInternalFindVariable (
 | 
						|
               EFI_KEY_EXCHANGE_KEY_NAME,
 | 
						|
               &gEfiGlobalVariableGuid,
 | 
						|
               &Data,
 | 
						|
               &DataSize
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
 | 
						|
    //
 | 
						|
    KekDataSize = (UINT32)DataSize;
 | 
						|
    CertList    = (EFI_SIGNATURE_LIST *)Data;
 | 
						|
    while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
 | 
						|
      if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
 | 
						|
        Cert      = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
 | 
						|
        CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
 | 
						|
        for (Index = 0; Index < CertCount; Index++) {
 | 
						|
          //
 | 
						|
          // Iterate each Signature Data Node within this CertList for a verify
 | 
						|
          //
 | 
						|
          TrustedCert     = Cert->SignatureData;
 | 
						|
          TrustedCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
 | 
						|
 | 
						|
          //
 | 
						|
          // Verify Pkcs7 SignedData via Pkcs7Verify library.
 | 
						|
          //
 | 
						|
          VerifyStatus = Pkcs7Verify (
 | 
						|
                           SigData,
 | 
						|
                           SigDataSize,
 | 
						|
                           TrustedCert,
 | 
						|
                           TrustedCertSize,
 | 
						|
                           NewData,
 | 
						|
                           NewDataSize
 | 
						|
                           );
 | 
						|
          if (VerifyStatus) {
 | 
						|
            goto Exit;
 | 
						|
          }
 | 
						|
 | 
						|
          Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + CertList->SignatureSize);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      KekDataSize -= CertList->SignatureListSize;
 | 
						|
      CertList     = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);
 | 
						|
    }
 | 
						|
  } else if (AuthVarType == AuthVarTypePriv) {
 | 
						|
    //
 | 
						|
    // Process common authenticated variable except PK/KEK/DB/DBX/DBT.
 | 
						|
    // Get signer's certificates from SignedData.
 | 
						|
    //
 | 
						|
    VerifyStatus = Pkcs7GetSigners (
 | 
						|
                     SigData,
 | 
						|
                     SigDataSize,
 | 
						|
                     &SignerCerts,
 | 
						|
                     &CertStackSize,
 | 
						|
                     &TopLevelCert,
 | 
						|
                     &TopLevelCertSize
 | 
						|
                     );
 | 
						|
    if (!VerifyStatus) {
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Get previously stored signer's certificates from certdb or certdbv for existing
 | 
						|
    // variable. Check whether they are identical with signer's certificates
 | 
						|
    // in SignedData. If not, return error immediately.
 | 
						|
    //
 | 
						|
    if (OrgTimeStamp != NULL) {
 | 
						|
      VerifyStatus = FALSE;
 | 
						|
 | 
						|
      Status = GetCertsFromDb (VariableName, VendorGuid, Attributes, &CertsInCertDb, &CertsSizeinDb);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        goto Exit;
 | 
						|
      }
 | 
						|
 | 
						|
      if (CertsSizeinDb == SHA256_DIGEST_SIZE) {
 | 
						|
        //
 | 
						|
        // Check hash of signer cert CommonName + Top-level issuer tbsCertificate against data in CertDb
 | 
						|
        //
 | 
						|
        CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1);
 | 
						|
        Status      = CalculatePrivAuthVarSignChainSHA256Digest (
 | 
						|
                        CertDataPtr->CertDataBuffer,
 | 
						|
                        ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)),
 | 
						|
                        TopLevelCert,
 | 
						|
                        TopLevelCertSize,
 | 
						|
                        Sha256Digest
 | 
						|
                        );
 | 
						|
        if (EFI_ERROR (Status) || (CompareMem (Sha256Digest, CertsInCertDb, CertsSizeinDb) != 0)) {
 | 
						|
          goto Exit;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Keep backward compatible with previous solution which saves whole signer certs stack in CertDb
 | 
						|
        //
 | 
						|
        if ((CertStackSize != CertsSizeinDb) ||
 | 
						|
            (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0))
 | 
						|
        {
 | 
						|
          goto Exit;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyStatus = Pkcs7Verify (
 | 
						|
                     SigData,
 | 
						|
                     SigDataSize,
 | 
						|
                     TopLevelCert,
 | 
						|
                     TopLevelCertSize,
 | 
						|
                     NewData,
 | 
						|
                     NewDataSize
 | 
						|
                     );
 | 
						|
    if (!VerifyStatus) {
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {
 | 
						|
      //
 | 
						|
      // When adding a new common authenticated variable, always save Hash of cn of signer cert + tbsCertificate of Top-level issuer
 | 
						|
      //
 | 
						|
      CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1);
 | 
						|
      Status      = InsertCertsToDb (
 | 
						|
                      VariableName,
 | 
						|
                      VendorGuid,
 | 
						|
                      Attributes,
 | 
						|
                      CertDataPtr->CertDataBuffer,
 | 
						|
                      ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)),
 | 
						|
                      TopLevelCert,
 | 
						|
                      TopLevelCertSize
 | 
						|
                      );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        VerifyStatus = FALSE;
 | 
						|
        goto Exit;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else if (AuthVarType == AuthVarTypePayload) {
 | 
						|
    CertList        = (EFI_SIGNATURE_LIST *)PayloadPtr;
 | 
						|
    Cert            = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
 | 
						|
    TrustedCert     = Cert->SignatureData;
 | 
						|
    TrustedCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
 | 
						|
    //
 | 
						|
    // Verify Pkcs7 SignedData via Pkcs7Verify library.
 | 
						|
    //
 | 
						|
    VerifyStatus = Pkcs7Verify (
 | 
						|
                     SigData,
 | 
						|
                     SigDataSize,
 | 
						|
                     TrustedCert,
 | 
						|
                     TrustedCertSize,
 | 
						|
                     NewData,
 | 
						|
                     NewDataSize
 | 
						|
                     );
 | 
						|
  } else {
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
Exit:
 | 
						|
 | 
						|
  if ((AuthVarType == AuthVarTypePk) || (AuthVarType == AuthVarTypePriv)) {
 | 
						|
    if (TopLevelCert != NULL) {
 | 
						|
      Pkcs7FreeSigners (TopLevelCert);
 | 
						|
    }
 | 
						|
 | 
						|
    if (SignerCerts != NULL) {
 | 
						|
      Pkcs7FreeSigners (SignerCerts);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!VerifyStatus) {
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = CheckSignatureListFormat (VariableName, VendorGuid, PayloadPtr, PayloadSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  *VarPayloadPtr  = PayloadPtr;
 | 
						|
  *VarPayloadSize = PayloadSize;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
 | 
						|
 | 
						|
  Caution: This function may receive untrusted input.
 | 
						|
  This function may be invoked in SMM mode, and datasize and data are external input.
 | 
						|
  This function will do basic validation, before parse the data.
 | 
						|
  This function will parse the authentication carefully to avoid security issues, like
 | 
						|
  buffer overflow, integer overflow.
 | 
						|
 | 
						|
  @param[in]  VariableName                Name of Variable to be found.
 | 
						|
  @param[in]  VendorGuid                  Variable vendor GUID.
 | 
						|
  @param[in]  Data                        Data pointer.
 | 
						|
  @param[in]  DataSize                    Size of Data found. If size is less than the
 | 
						|
                                          data, this value contains the required size.
 | 
						|
  @param[in]  Attributes                  Attribute value of the variable.
 | 
						|
  @param[in]  AuthVarType                 Verify against PK, KEK database, private database or certificate in data payload.
 | 
						|
  @param[out] VarDel                      Delete the variable or not.
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER           Invalid parameter.
 | 
						|
  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
 | 
						|
                                          check carried out by the firmware.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack
 | 
						|
                                          of resources.
 | 
						|
  @retval EFI_SUCCESS                     Variable pass validation successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
VerifyTimeBasedPayloadAndUpdate (
 | 
						|
  IN     CHAR16        *VariableName,
 | 
						|
  IN     EFI_GUID      *VendorGuid,
 | 
						|
  IN     VOID          *Data,
 | 
						|
  IN     UINTN         DataSize,
 | 
						|
  IN     UINT32        Attributes,
 | 
						|
  IN     AUTHVAR_TYPE  AuthVarType,
 | 
						|
  OUT    BOOLEAN       *VarDel
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                     Status;
 | 
						|
  EFI_STATUS                     FindStatus;
 | 
						|
  UINT8                          *PayloadPtr;
 | 
						|
  UINTN                          PayloadSize;
 | 
						|
  EFI_VARIABLE_AUTHENTICATION_2  *CertData;
 | 
						|
  AUTH_VARIABLE_INFO             OrgVariableInfo;
 | 
						|
  BOOLEAN                        IsDel;
 | 
						|
 | 
						|
  ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
 | 
						|
  FindStatus = mAuthVarLibContextIn->FindVariable (
 | 
						|
                                       VariableName,
 | 
						|
                                       VendorGuid,
 | 
						|
                                       &OrgVariableInfo
 | 
						|
                                       );
 | 
						|
 | 
						|
  Status = VerifyTimeBasedPayload (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             Data,
 | 
						|
             DataSize,
 | 
						|
             Attributes,
 | 
						|
             AuthVarType,
 | 
						|
             (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL,
 | 
						|
             &PayloadPtr,
 | 
						|
             &PayloadSize
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (  !EFI_ERROR (FindStatus)
 | 
						|
     && (PayloadSize == 0)
 | 
						|
     && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0))
 | 
						|
  {
 | 
						|
    IsDel = TRUE;
 | 
						|
  } else {
 | 
						|
    IsDel = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  CertData = (EFI_VARIABLE_AUTHENTICATION_2 *)Data;
 | 
						|
 | 
						|
  //
 | 
						|
  // Final step: Update/Append Variable if it pass Pkcs7Verify
 | 
						|
  //
 | 
						|
  Status = AuthServiceInternalUpdateVariableWithTimeStamp (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             PayloadPtr,
 | 
						|
             PayloadSize,
 | 
						|
             Attributes,
 | 
						|
             &CertData->TimeStamp
 | 
						|
             );
 | 
						|
 | 
						|
  //
 | 
						|
  // Delete signer's certificates when delete the common authenticated variable.
 | 
						|
  //
 | 
						|
  if (IsDel && (AuthVarType == AuthVarTypePriv) && !EFI_ERROR (Status)) {
 | 
						|
    Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
 | 
						|
  }
 | 
						|
 | 
						|
  if (VarDel != NULL) {
 | 
						|
    if (IsDel && !EFI_ERROR (Status)) {
 | 
						|
      *VarDel = TRUE;
 | 
						|
    } else {
 | 
						|
      *VarDel = FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |