mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-03 21:17:23 +01:00 
			
		
		
		
	1. If PcdMaxAuthVariableSize is set to 0, keep current behavior as is and PcdMaxVariableSize used. 2. If PcdMaxAuthVariableSize is set to non 0, it will work on authenticated variables. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17610 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2533 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2533 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Implement authentication services for the authenticated variable
 | 
						|
  service in UEFI2.2.
 | 
						|
 | 
						|
  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.
 | 
						|
 | 
						|
  VerifyTimeBasedPayload() 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 - 2015, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Variable.h"
 | 
						|
#include "AuthService.h"
 | 
						|
 | 
						|
///
 | 
						|
/// Global database array for scratch
 | 
						|
///
 | 
						|
UINT8    *mPubKeyStore;
 | 
						|
UINT32   mPubKeyNumber;
 | 
						|
UINT32   mMaxKeyNumber;
 | 
						|
UINT32   mMaxKeyDbSize;
 | 
						|
UINT8    *mCertDbStore;
 | 
						|
UINT32   mMaxCertDbSize;
 | 
						|
UINT32   mPlatformMode;
 | 
						|
UINT8    mVendorKeyState;
 | 
						|
 | 
						|
EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};
 | 
						|
//
 | 
						|
// Public Exponent of RSA Key.
 | 
						|
//
 | 
						|
CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
 | 
						|
//
 | 
						|
// Hash context pointer
 | 
						|
//
 | 
						|
VOID  *mHashCtx = NULL;
 | 
						|
 | 
						|
//
 | 
						|
// Requirement for different signature type which have been defined in UEFI spec.
 | 
						|
// These data are used to peform 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           }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  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 ((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
 | 
						|
  )
 | 
						|
{
 | 
						|
  VARIABLE_POINTER_TRACK  Variable;
 | 
						|
 | 
						|
  FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  if (Variable.CurrPtr != NULL && *(GetVariableDataPtr (Variable.CurrPtr)) == CUSTOM_SECURE_BOOT_MODE) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initializes for authenticated varibale service.
 | 
						|
 | 
						|
  @param[in] MaxAuthVariableSize    Reflect the overhead associated with the saving
 | 
						|
                                    of a single EFI authenticated variable with the exception
 | 
						|
                                    of the overhead associated with the length
 | 
						|
                                    of the string name of the EFI variable.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           Function successfully executed.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resources.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AutenticatedVariableServiceInitialize (
 | 
						|
  IN UINTN      MaxAuthVariableSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  VARIABLE_POINTER_TRACK  Variable;
 | 
						|
  VARIABLE_POINTER_TRACK  PkVariable;
 | 
						|
  UINT8                   VarValue;
 | 
						|
  UINT32                  VarAttr;
 | 
						|
  UINT8                   *Data;
 | 
						|
  UINTN                   DataSize;
 | 
						|
  UINTN                   CtxSize;
 | 
						|
  UINT8                   SecureBootMode;
 | 
						|
  UINT8                   SecureBootEnable;
 | 
						|
  UINT8                   CustomMode;
 | 
						|
  UINT32                  ListSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize hash context.
 | 
						|
  //
 | 
						|
  CtxSize   = Sha256GetContextSize ();
 | 
						|
  mHashCtx  = AllocateRuntimePool (CtxSize);
 | 
						|
  if (mHashCtx == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Reserve runtime buffer for public key database. The size excludes variable header and name size.
 | 
						|
  //
 | 
						|
  mMaxKeyDbSize = (UINT32) (MaxAuthVariableSize - sizeof (AUTHVAR_KEYDB_NAME));
 | 
						|
  mMaxKeyNumber = mMaxKeyDbSize / EFI_CERT_TYPE_RSA2048_SIZE;
 | 
						|
  mPubKeyStore  = AllocateRuntimePool (mMaxKeyDbSize);
 | 
						|
  if (mPubKeyStore == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Reserve runtime buffer for certificate database. The size excludes variable header and name size.
 | 
						|
  //
 | 
						|
  mMaxCertDbSize = (UINT32) (MaxAuthVariableSize - sizeof (EFI_CERT_DB_NAME));
 | 
						|
  mCertDbStore   = AllocateRuntimePool (mMaxCertDbSize);
 | 
						|
  if (mCertDbStore == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check "AuthVarKeyDatabase" variable's existence.
 | 
						|
  // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
 | 
						|
  //
 | 
						|
  Status = FindVariable (
 | 
						|
             AUTHVAR_KEYDB_NAME,
 | 
						|
             &gEfiAuthenticatedVariableGuid,
 | 
						|
             &Variable,
 | 
						|
             &mVariableModuleGlobal->VariableGlobal,
 | 
						|
             FALSE
 | 
						|
             );
 | 
						|
 | 
						|
  if (Variable.CurrPtr == NULL) {
 | 
						|
    VarAttr       = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
    VarValue      = 0;
 | 
						|
    mPubKeyNumber = 0;
 | 
						|
    Status        = UpdateVariable (
 | 
						|
                      AUTHVAR_KEYDB_NAME,
 | 
						|
                      &gEfiAuthenticatedVariableGuid,
 | 
						|
                      &VarValue,
 | 
						|
                      sizeof(UINT8),
 | 
						|
                      VarAttr,
 | 
						|
                      0,
 | 
						|
                      0,
 | 
						|
                      &Variable,
 | 
						|
                      NULL
 | 
						|
                      );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Load database in global variable for cache.
 | 
						|
    //
 | 
						|
    DataSize  = DataSizeOfVariable (Variable.CurrPtr);
 | 
						|
    Data      = GetVariableDataPtr (Variable.CurrPtr);
 | 
						|
    ASSERT ((DataSize != 0) && (Data != NULL));
 | 
						|
    //
 | 
						|
    // "AuthVarKeyDatabase" is an internal variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before)
 | 
						|
    //  Therefore, there is no memory overflow in underlying CopyMem.
 | 
						|
    //
 | 
						|
    CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
 | 
						|
    mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
 | 
						|
  }
 | 
						|
 | 
						|
  FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  if (PkVariable.CurrPtr == NULL) {
 | 
						|
    DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));
 | 
						|
  } else {
 | 
						|
    DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Create "SetupMode" variable with BS+RT attribute set.
 | 
						|
  //
 | 
						|
  FindVariable (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  if (PkVariable.CurrPtr == NULL) {
 | 
						|
    mPlatformMode = SETUP_MODE;
 | 
						|
  } else {
 | 
						|
    mPlatformMode = USER_MODE;
 | 
						|
  }
 | 
						|
  Status = UpdateVariable (
 | 
						|
             EFI_SETUP_MODE_NAME,
 | 
						|
             &gEfiGlobalVariableGuid,
 | 
						|
             &mPlatformMode,
 | 
						|
             sizeof(UINT8),
 | 
						|
             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | 
						|
             0,
 | 
						|
             0,
 | 
						|
             &Variable,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Create "SignatureSupport" variable with BS+RT attribute set.
 | 
						|
  //
 | 
						|
  FindVariable (EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  Status  = UpdateVariable (
 | 
						|
              EFI_SIGNATURE_SUPPORT_NAME,
 | 
						|
              &gEfiGlobalVariableGuid,
 | 
						|
              mSignatureSupport,
 | 
						|
              sizeof(mSignatureSupport),
 | 
						|
              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | 
						|
              0,
 | 
						|
              0,
 | 
						|
              &Variable,
 | 
						|
              NULL
 | 
						|
              );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
 | 
						|
  // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
 | 
						|
  // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
 | 
						|
  //
 | 
						|
  SecureBootEnable = SECURE_BOOT_DISABLE;
 | 
						|
  FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  if (Variable.CurrPtr != NULL) {
 | 
						|
    if (mPlatformMode == SETUP_MODE){
 | 
						|
      //
 | 
						|
      // PK is cleared in runtime. "SecureBootMode" is not updated before reboot 
 | 
						|
      // Delete "SecureBootMode" in SetupMode
 | 
						|
      //
 | 
						|
      Status = UpdateVariable (
 | 
						|
                 EFI_SECURE_BOOT_ENABLE_NAME,
 | 
						|
                 &gEfiSecureBootEnableDisableGuid,
 | 
						|
                 &SecureBootEnable,
 | 
						|
                 0,
 | 
						|
                 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
                 0,
 | 
						|
                 0,
 | 
						|
                 &Variable,
 | 
						|
                 NULL
 | 
						|
                 );
 | 
						|
    } else {
 | 
						|
      SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));
 | 
						|
    }
 | 
						|
  } else if (mPlatformMode == USER_MODE) {
 | 
						|
    //
 | 
						|
    // "SecureBootEnable" not exist, initialize it in USER_MODE.
 | 
						|
    //
 | 
						|
    SecureBootEnable = SECURE_BOOT_ENABLE;
 | 
						|
    Status = UpdateVariable (
 | 
						|
               EFI_SECURE_BOOT_ENABLE_NAME,
 | 
						|
               &gEfiSecureBootEnableDisableGuid,
 | 
						|
               &SecureBootEnable,
 | 
						|
               sizeof (UINT8),
 | 
						|
               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
               0,
 | 
						|
               0,
 | 
						|
               &Variable,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Create "SecureBoot" variable with BS+RT attribute set.
 | 
						|
  //
 | 
						|
  if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {
 | 
						|
    SecureBootMode = SECURE_BOOT_MODE_ENABLE;
 | 
						|
  } else {
 | 
						|
    SecureBootMode = SECURE_BOOT_MODE_DISABLE;
 | 
						|
  }
 | 
						|
  FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  Status = UpdateVariable (
 | 
						|
             EFI_SECURE_BOOT_MODE_NAME,
 | 
						|
             &gEfiGlobalVariableGuid,
 | 
						|
             &SecureBootMode,
 | 
						|
             sizeof (UINT8),
 | 
						|
             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
             0,
 | 
						|
             0,
 | 
						|
             &Variable,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));
 | 
						|
  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));
 | 
						|
  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state.
 | 
						|
  //
 | 
						|
  FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  CustomMode = STANDARD_SECURE_BOOT_MODE;
 | 
						|
  Status = UpdateVariable (
 | 
						|
             EFI_CUSTOM_MODE_NAME,
 | 
						|
             &gEfiCustomModeEnableGuid,
 | 
						|
             &CustomMode,
 | 
						|
             sizeof (UINT8),
 | 
						|
             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
             0,
 | 
						|
             0,
 | 
						|
             &Variable,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));
 | 
						|
 | 
						|
  //
 | 
						|
  // Check "certdb" variable's existence.
 | 
						|
  // If it doesn't exist, then create a new one with
 | 
						|
  // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
 | 
						|
  //
 | 
						|
  Status = FindVariable (
 | 
						|
             EFI_CERT_DB_NAME,
 | 
						|
             &gEfiCertDbGuid,
 | 
						|
             &Variable,
 | 
						|
             &mVariableModuleGlobal->VariableGlobal,
 | 
						|
             FALSE
 | 
						|
             );
 | 
						|
 | 
						|
  if (Variable.CurrPtr == NULL) {
 | 
						|
    VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
    ListSize = sizeof (UINT32);
 | 
						|
    Status   = UpdateVariable (
 | 
						|
                 EFI_CERT_DB_NAME,
 | 
						|
                 &gEfiCertDbGuid,
 | 
						|
                 &ListSize,
 | 
						|
                 sizeof (UINT32),
 | 
						|
                 VarAttr,
 | 
						|
                 0,
 | 
						|
                 0,
 | 
						|
                 &Variable,
 | 
						|
                 NULL
 | 
						|
                 );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly.
 | 
						|
  //
 | 
						|
  FindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  if (Variable.CurrPtr != NULL) {
 | 
						|
    mVendorKeyState = *(GetVariableDataPtr (Variable.CurrPtr));
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state.
 | 
						|
    //
 | 
						|
    mVendorKeyState = VENDOR_KEYS_VALID;
 | 
						|
    Status = UpdateVariable (
 | 
						|
               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,
 | 
						|
               0,
 | 
						|
               0,
 | 
						|
               &Variable,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Create "VendorKeys" variable with BS+RT attribute set.
 | 
						|
  //
 | 
						|
  FindVariable (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  Status = UpdateVariable (
 | 
						|
             EFI_VENDOR_KEYS_VARIABLE_NAME,
 | 
						|
             &gEfiGlobalVariableGuid,
 | 
						|
             &mVendorKeyState,
 | 
						|
             sizeof (UINT8),
 | 
						|
             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
             0,
 | 
						|
             0,
 | 
						|
             &Variable,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_VENDOR_KEYS_VARIABLE_NAME, mVendorKeyState));
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Add public key in store and return its index.
 | 
						|
 | 
						|
  @param[in]  PubKey                  Input pointer to Public Key data
 | 
						|
  @param[in]  VariableDataEntry       The variable data entry
 | 
						|
 | 
						|
  @return                             Index of new added item
 | 
						|
 | 
						|
**/
 | 
						|
UINT32
 | 
						|
AddPubKeyInStore (
 | 
						|
  IN  UINT8                        *PubKey,
 | 
						|
  IN  VARIABLE_ENTRY_CONSISTENCY   *VariableDataEntry
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  BOOLEAN                          IsFound;
 | 
						|
  UINT32                           Index;
 | 
						|
  VARIABLE_POINTER_TRACK           Variable;
 | 
						|
  UINT8                            *Ptr;
 | 
						|
  UINT8                            *Data;
 | 
						|
  UINTN                            DataSize;
 | 
						|
  VARIABLE_ENTRY_CONSISTENCY       PublicKeyEntry;
 | 
						|
  UINT32                           Attributes;
 | 
						|
 | 
						|
  if (PubKey == NULL) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FindVariable (
 | 
						|
             AUTHVAR_KEYDB_NAME,
 | 
						|
             &gEfiAuthenticatedVariableGuid,
 | 
						|
             &Variable,
 | 
						|
             &mVariableModuleGlobal->VariableGlobal,
 | 
						|
             FALSE
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether the public key entry does exist.
 | 
						|
  //
 | 
						|
  IsFound = FALSE;
 | 
						|
  for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {
 | 
						|
    if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
 | 
						|
      IsFound = TRUE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    Ptr += EFI_CERT_TYPE_RSA2048_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!IsFound) {
 | 
						|
    //
 | 
						|
    // Add public key in database.
 | 
						|
    //
 | 
						|
    if (mPubKeyNumber == mMaxKeyNumber) {
 | 
						|
      //
 | 
						|
      // Public key dadatase is full, try to reclaim invalid key.
 | 
						|
      //
 | 
						|
      if (AtRuntime ()) {
 | 
						|
        //
 | 
						|
        // NV storage can't reclaim at runtime.
 | 
						|
        //
 | 
						|
        return 0;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = Reclaim (
 | 
						|
                 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
 | 
						|
                 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
 | 
						|
                 FALSE,
 | 
						|
                 NULL,
 | 
						|
                 NULL,
 | 
						|
                 0,
 | 
						|
                 TRUE
 | 
						|
                 );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return 0;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = FindVariable (
 | 
						|
                 AUTHVAR_KEYDB_NAME,
 | 
						|
                 &gEfiAuthenticatedVariableGuid,
 | 
						|
                 &Variable,
 | 
						|
                 &mVariableModuleGlobal->VariableGlobal,
 | 
						|
                 FALSE
 | 
						|
                 );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));
 | 
						|
        return 0;
 | 
						|
      }
 | 
						|
 | 
						|
      DataSize  = DataSizeOfVariable (Variable.CurrPtr);
 | 
						|
      Data      = GetVariableDataPtr (Variable.CurrPtr);
 | 
						|
      ASSERT ((DataSize != 0) && (Data != NULL));
 | 
						|
      //
 | 
						|
      // "AuthVarKeyDatabase" is an internal used variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before)
 | 
						|
      //  Therefore, there is no memory overflow in underlying CopyMem.
 | 
						|
      //
 | 
						|
      CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
 | 
						|
      mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
 | 
						|
 | 
						|
      if (mPubKeyNumber == mMaxKeyNumber) {
 | 
						|
        return 0;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Check the variable space for both public key and variable data.
 | 
						|
    //
 | 
						|
    PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * EFI_CERT_TYPE_RSA2048_SIZE;
 | 
						|
    PublicKeyEntry.Guid         = &gEfiAuthenticatedVariableGuid;
 | 
						|
    PublicKeyEntry.Name         = AUTHVAR_KEYDB_NAME;
 | 
						|
    Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
 | 
						|
    if (!CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {
 | 
						|
      //
 | 
						|
      // No enough variable space.
 | 
						|
      //
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
 | 
						|
    Index = ++mPubKeyNumber;
 | 
						|
    //
 | 
						|
    // Update public key database variable.
 | 
						|
    //
 | 
						|
    Status = UpdateVariable (
 | 
						|
               AUTHVAR_KEYDB_NAME,
 | 
						|
               &gEfiAuthenticatedVariableGuid,
 | 
						|
               mPubKeyStore,
 | 
						|
               mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,
 | 
						|
               Attributes,
 | 
						|
               0,
 | 
						|
               0,
 | 
						|
               &Variable,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return Index;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
 | 
						|
  Follow the steps in UEFI2.2.
 | 
						|
 | 
						|
  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]      Data                    Pointer to data with AuthInfo.
 | 
						|
  @param[in]      DataSize                Size of Data.
 | 
						|
  @param[in]      PubKey                  Public key used for verification.
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER       Invalid parameter.
 | 
						|
  @retval EFI_SECURITY_VIOLATION      If authentication failed.
 | 
						|
  @retval EFI_SUCCESS                 Authentication successful.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
VerifyCounterBasedPayload (
 | 
						|
  IN     UINT8          *Data,
 | 
						|
  IN     UINTN          DataSize,
 | 
						|
  IN     UINT8          *PubKey
 | 
						|
  )
 | 
						|
{
 | 
						|
  BOOLEAN                         Status;
 | 
						|
  EFI_VARIABLE_AUTHENTICATION     *CertData;
 | 
						|
  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
 | 
						|
  UINT8                           Digest[SHA256_DIGEST_SIZE];
 | 
						|
  VOID                            *Rsa;
 | 
						|
  UINTN                           PayloadSize;
 | 
						|
 | 
						|
  PayloadSize = DataSize - AUTHINFO_SIZE;
 | 
						|
  Rsa         = NULL;
 | 
						|
  CertData    = NULL;
 | 
						|
  CertBlock   = NULL;
 | 
						|
 | 
						|
  if (Data == NULL || PubKey == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
 | 
						|
  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
 | 
						|
 | 
						|
  //
 | 
						|
  // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
 | 
						|
  // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
 | 
						|
  //
 | 
						|
  if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
 | 
						|
      !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)
 | 
						|
        ) {
 | 
						|
    //
 | 
						|
    // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
 | 
						|
    //
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Hash data payload with SHA256.
 | 
						|
  //
 | 
						|
  ZeroMem (Digest, SHA256_DIGEST_SIZE);
 | 
						|
  Status  = Sha256Init (mHashCtx);
 | 
						|
  if (!Status) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  Status  = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);
 | 
						|
  if (!Status) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Hash Size.
 | 
						|
  //
 | 
						|
  Status  = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));
 | 
						|
  if (!Status) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Hash Monotonic Count.
 | 
						|
  //
 | 
						|
  Status  = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));
 | 
						|
  if (!Status) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  Status  = Sha256Final (mHashCtx, Digest);
 | 
						|
  if (!Status) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Generate & Initialize RSA Context.
 | 
						|
  //
 | 
						|
  Rsa = RsaNew ();
 | 
						|
  ASSERT (Rsa != NULL);
 | 
						|
  //
 | 
						|
  // Set RSA Key Components.
 | 
						|
  // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
 | 
						|
  //
 | 
						|
  Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
 | 
						|
  if (!Status) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
 | 
						|
  if (!Status) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Verify the signature.
 | 
						|
  //
 | 
						|
  Status = RsaPkcs1Verify (
 | 
						|
             Rsa,
 | 
						|
             Digest,
 | 
						|
             SHA256_DIGEST_SIZE,
 | 
						|
             CertBlock->Signature,
 | 
						|
             EFI_CERT_TYPE_RSA2048_SHA256_SIZE
 | 
						|
             );
 | 
						|
 | 
						|
Done:
 | 
						|
  if (Rsa != NULL) {
 | 
						|
    RsaFree (Rsa);
 | 
						|
  }
 | 
						|
  if (Status) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  } else {
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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;
 | 
						|
  VARIABLE_POINTER_TRACK  Variable;
 | 
						|
  UINT8                   SecureBootMode;
 | 
						|
  UINT8                   SecureBootEnable;
 | 
						|
  UINTN                   VariableDataSize;
 | 
						|
 | 
						|
  Status = FindVariable (
 | 
						|
             EFI_SETUP_MODE_NAME,
 | 
						|
             &gEfiGlobalVariableGuid,
 | 
						|
             &Variable,
 | 
						|
             &mVariableModuleGlobal->VariableGlobal,
 | 
						|
             FALSE
 | 
						|
             );
 | 
						|
  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 (GetVariableDataPtr (Variable.CurrPtr), &mPlatformMode, sizeof(UINT8));
 | 
						|
 | 
						|
  if (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 = FindVariable (
 | 
						|
             EFI_SECURE_BOOT_MODE_NAME,
 | 
						|
             &gEfiGlobalVariableGuid,
 | 
						|
             &Variable,
 | 
						|
             &mVariableModuleGlobal->VariableGlobal,
 | 
						|
             FALSE
 | 
						|
             );
 | 
						|
  //
 | 
						|
  // 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 (Variable.CurrPtr == NULL) {
 | 
						|
    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  = UpdateVariable (
 | 
						|
              EFI_SECURE_BOOT_MODE_NAME,
 | 
						|
              &gEfiGlobalVariableGuid,
 | 
						|
              &SecureBootMode,
 | 
						|
              sizeof(UINT8),
 | 
						|
              EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
              0,
 | 
						|
              0,
 | 
						|
              &Variable,
 | 
						|
              NULL
 | 
						|
              );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
 | 
						|
  //
 | 
						|
  Status = FindVariable (
 | 
						|
             EFI_SECURE_BOOT_ENABLE_NAME,
 | 
						|
             &gEfiSecureBootEnableDisableGuid,
 | 
						|
             &Variable,
 | 
						|
             &mVariableModuleGlobal->VariableGlobal,
 | 
						|
             FALSE
 | 
						|
             );
 | 
						|
 | 
						|
  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 (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
    SecureBootEnable = SECURE_BOOT_DISABLE;
 | 
						|
    VariableDataSize = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = UpdateVariable (
 | 
						|
             EFI_SECURE_BOOT_ENABLE_NAME,
 | 
						|
             &gEfiSecureBootEnableDisableGuid,
 | 
						|
             &SecureBootEnable,
 | 
						|
             VariableDataSize,
 | 
						|
             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
             0,
 | 
						|
             0,
 | 
						|
             &Variable,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  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 throuth 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 != ((UINTN) ~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;
 | 
						|
  VARIABLE_POINTER_TRACK  Variable;
 | 
						|
 | 
						|
  if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  mVendorKeyState = VENDOR_KEYS_MODIFIED;
 | 
						|
 | 
						|
  FindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  Status = UpdateVariable (
 | 
						|
             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,
 | 
						|
             0,
 | 
						|
             0,
 | 
						|
             &Variable,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  FindVariable (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
 | 
						|
  return UpdateVariable (
 | 
						|
           EFI_VENDOR_KEYS_VARIABLE_NAME,
 | 
						|
           &gEfiGlobalVariableGuid,
 | 
						|
           &mVendorKeyState,
 | 
						|
           sizeof (UINT8),
 | 
						|
           EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
 | 
						|
           0,
 | 
						|
           0,
 | 
						|
           &Variable,
 | 
						|
           NULL
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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]  Variable                    The variable information which is used to keep track of variable usage.
 | 
						|
  @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  VARIABLE_POINTER_TRACK    *Variable,
 | 
						|
  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;
 | 
						|
  }
 | 
						|
 | 
						|
  Del = FALSE;
 | 
						|
  if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !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 = UpdateVariable (
 | 
						|
               VariableName,
 | 
						|
               VendorGuid,
 | 
						|
               Payload,
 | 
						|
               PayloadSize,
 | 
						|
               Attributes,
 | 
						|
               0,
 | 
						|
               0,
 | 
						|
               Variable,
 | 
						|
               &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
 | 
						|
               );
 | 
						|
    if (EFI_ERROR(Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((mPlatformMode != SETUP_MODE) || IsPk) {
 | 
						|
      Status = VendorKeyIsModified ();
 | 
						|
    }
 | 
						|
  } else if (mPlatformMode == USER_MODE) {
 | 
						|
    //
 | 
						|
    // Verify against X509 Cert in PK database.
 | 
						|
    //
 | 
						|
    Status = VerifyTimeBasedPayload (
 | 
						|
               VariableName,
 | 
						|
               VendorGuid,
 | 
						|
               Data,
 | 
						|
               DataSize,
 | 
						|
               Variable,
 | 
						|
               Attributes,
 | 
						|
               AuthVarTypePk,
 | 
						|
               &Del
 | 
						|
               );
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Verify against the certificate in data payload.
 | 
						|
    //
 | 
						|
    Status = VerifyTimeBasedPayload (
 | 
						|
               VariableName,
 | 
						|
               VendorGuid,
 | 
						|
               Data,
 | 
						|
               DataSize,
 | 
						|
               Variable,
 | 
						|
               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]  Variable                    The variable information which is used to keep track of variable usage.
 | 
						|
  @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  VARIABLE_POINTER_TRACK               *Variable,
 | 
						|
  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 VerifyTimeBasedPayload (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             Data,
 | 
						|
             DataSize,
 | 
						|
             Variable,
 | 
						|
             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 = UpdateVariable (
 | 
						|
               VariableName,
 | 
						|
               VendorGuid,
 | 
						|
               Payload,
 | 
						|
               PayloadSize,
 | 
						|
               Attributes,
 | 
						|
               0,
 | 
						|
               0,
 | 
						|
               Variable,
 | 
						|
               &((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] Data               Data pointer.
 | 
						|
  @param[in] DataSize           Size of Data.
 | 
						|
  @param[in] Variable           The variable information which is used to keep track of variable usage.
 | 
						|
  @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  VOID                      *Data,
 | 
						|
  IN  UINTN                     DataSize,
 | 
						|
  IN  VARIABLE_POINTER_TRACK    *Variable,
 | 
						|
  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 ((Variable->CurrPtr != NULL) &&
 | 
						|
      (Attributes == Variable->CurrPtr->Attributes) &&
 | 
						|
      ((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_AUTHENTICATED_WRITE_ACCESS/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 Variable to be found.
 | 
						|
  @param[in]  VendorGuid                  Variable vendor GUID.
 | 
						|
 | 
						|
  @param[in]  Data                        Data pointer.
 | 
						|
  @param[in]  DataSize                    Size of Data.
 | 
						|
  @param[in]  Variable                    The variable information which is used to keep track of variable usage.
 | 
						|
  @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 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_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     VARIABLE_POINTER_TRACK             *Variable,
 | 
						|
  IN     UINT32                             Attributes
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  BOOLEAN                         IsDeletion;
 | 
						|
  BOOLEAN                         IsFirstTime;
 | 
						|
  UINT8                           *PubKey;
 | 
						|
  EFI_VARIABLE_AUTHENTICATION     *CertData;
 | 
						|
  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
 | 
						|
  UINT32                          KeyIndex;
 | 
						|
  UINT64                          MonotonicCount;
 | 
						|
  VARIABLE_ENTRY_CONSISTENCY      VariableDataEntry;
 | 
						|
 | 
						|
  KeyIndex    = 0;
 | 
						|
  CertData    = NULL;
 | 
						|
  CertBlock   = NULL;
 | 
						|
  PubKey      = NULL;
 | 
						|
  IsDeletion  = FALSE;
 | 
						|
  Status      = EFI_SUCCESS;
 | 
						|
 | 
						|
  if (IsDeleteAuthVariable (Data, DataSize, Variable, Attributes) && UserPhysicalPresent()) {
 | 
						|
    //
 | 
						|
    // Allow the delete operation of common authenticated variable at user physical presence.
 | 
						|
    //
 | 
						|
    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
 | 
						|
      Status = DeleteCertsFromDb (VariableName, VendorGuid);
 | 
						|
    }
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Status = UpdateVariable (
 | 
						|
                 VariableName,
 | 
						|
                 VendorGuid,
 | 
						|
                 NULL,
 | 
						|
                 0,
 | 
						|
                 0,
 | 
						|
                 0,
 | 
						|
                 0,
 | 
						|
                 Variable,
 | 
						|
                 NULL
 | 
						|
                 );
 | 
						|
    }
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent()) {
 | 
						|
    //
 | 
						|
    // This variable is protected, only physical present user could modify its value.
 | 
						|
    //
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // A time-based authenticated variable and a count-based authenticated variable
 | 
						|
  // can't be updated by each other.
 | 
						|
  //
 | 
						|
  if (Variable->CurrPtr != NULL) {
 | 
						|
    if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&
 | 
						|
        ((Variable->CurrPtr->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
 | 
						|
      return EFI_SECURITY_VIOLATION;
 | 
						|
    }
 | 
						|
 | 
						|
    if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
 | 
						|
        ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {
 | 
						|
      return EFI_SECURITY_VIOLATION;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Process Time-based Authenticated variable.
 | 
						|
  //
 | 
						|
  if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
 | 
						|
    return VerifyTimeBasedPayload (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             Data,
 | 
						|
             DataSize,
 | 
						|
             Variable,
 | 
						|
             Attributes,
 | 
						|
             AuthVarTypePriv,
 | 
						|
             NULL
 | 
						|
             );
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
 | 
						|
  //
 | 
						|
  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
 | 
						|
    //
 | 
						|
    // Determine current operation type.
 | 
						|
    //
 | 
						|
    if (DataSize == AUTHINFO_SIZE) {
 | 
						|
      IsDeletion = TRUE;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
 | 
						|
    //
 | 
						|
    if (Variable->CurrPtr == NULL) {
 | 
						|
      IsFirstTime = TRUE;
 | 
						|
    } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
 | 
						|
      IsFirstTime = TRUE;
 | 
						|
    } else {
 | 
						|
      KeyIndex   = Variable->CurrPtr->PubKeyIndex;
 | 
						|
      IsFirstTime = FALSE;
 | 
						|
    }
 | 
						|
  } else if ((Variable->CurrPtr != NULL) &&
 | 
						|
             ((Variable->CurrPtr->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;
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
 | 
						|
    // That means it is not authenticated variable, just update variable as usual.
 | 
						|
    //
 | 
						|
    Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get PubKey and check Monotonic Count value corresponding to the variable.
 | 
						|
  //
 | 
						|
  CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
 | 
						|
  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
 | 
						|
  PubKey    = CertBlock->PublicKey;
 | 
						|
 | 
						|
  //
 | 
						|
  // Update Monotonic Count value.
 | 
						|
  //
 | 
						|
  MonotonicCount = CertData->MonotonicCount;
 | 
						|
 | 
						|
  if (!IsFirstTime) {
 | 
						|
    //
 | 
						|
    // 2 cases need to check here
 | 
						|
    //   1. Internal PubKey variable. PubKeyIndex is always 0
 | 
						|
    //   2. Other counter-based AuthVariable. Check input PubKey.
 | 
						|
    //
 | 
						|
    if (KeyIndex == 0 || CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
 | 
						|
      return EFI_SECURITY_VIOLATION;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Compare the current monotonic count and ensure that it is greater than the last SetVariable
 | 
						|
    // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
 | 
						|
    //
 | 
						|
    if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {
 | 
						|
      //
 | 
						|
      // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
 | 
						|
      //
 | 
						|
      return EFI_SECURITY_VIOLATION;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Verify the certificate in Data payload.
 | 
						|
  //
 | 
						|
  Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Now, the signature has been verified!
 | 
						|
  //
 | 
						|
  if (IsFirstTime && !IsDeletion) {
 | 
						|
    VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;
 | 
						|
    VariableDataEntry.Guid         = VendorGuid;
 | 
						|
    VariableDataEntry.Name         = VariableName;
 | 
						|
 | 
						|
    //
 | 
						|
    // Update public key database variable if need.
 | 
						|
    //
 | 
						|
    KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);
 | 
						|
    if (KeyIndex == 0) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Verification pass.
 | 
						|
  //
 | 
						|
  return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA
 | 
						|
  will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA
 | 
						|
  will be ignored.
 | 
						|
 | 
						|
  @param[in, out]  Data              Pointer to original EFI_SIGNATURE_LIST.
 | 
						|
  @param[in]       DataSize          Size of Data buffer.
 | 
						|
  @param[in]       FreeBufSize       Size of free data buffer
 | 
						|
  @param[in]       NewData           Pointer to new EFI_SIGNATURE_LIST to be appended.
 | 
						|
  @param[in]       NewDataSize       Size of NewData buffer.
 | 
						|
  @param[out]      MergedBufSize     Size of the merged buffer
 | 
						|
 | 
						|
  @return EFI_BUFFER_TOO_SMALL if input Data buffer overflowed
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
AppendSignatureList (
 | 
						|
  IN  OUT VOID            *Data,
 | 
						|
  IN  UINTN               DataSize,
 | 
						|
  IN  UINTN               FreeBufSize,
 | 
						|
  IN  VOID                *NewData,
 | 
						|
  IN  UINTN               NewDataSize,
 | 
						|
  OUT UINTN               *MergedBufSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  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;
 | 
						|
 | 
						|
  Tail = (UINT8 *) Data + DataSize;
 | 
						|
 | 
						|
  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, append it.
 | 
						|
        //
 | 
						|
        if (CopiedCount == 0) {
 | 
						|
          if (FreeBufSize < sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize) {
 | 
						|
            return EFI_BUFFER_TOO_SMALL;
 | 
						|
          }
 | 
						|
 | 
						|
          //
 | 
						|
          // 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;
 | 
						|
          FreeBufSize -= sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
 | 
						|
        }
 | 
						|
 | 
						|
        if (FreeBufSize < NewCertList->SignatureSize) {
 | 
						|
          return EFI_BUFFER_TOO_SMALL;
 | 
						|
        }
 | 
						|
        CopyMem (Tail, NewCert, NewCertList->SignatureSize);
 | 
						|
        Tail += NewCertList->SignatureSize;
 | 
						|
        FreeBufSize -= NewCertList->SignatureSize;
 | 
						|
        CopiedCount++;
 | 
						|
      }
 | 
						|
 | 
						|
      NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Update SignatureListSize in newly appended 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);
 | 
						|
  }
 | 
						|
 | 
						|
  *MergedBufSize = (Tail - (UINT8 *) Data);
 | 
						|
  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
 | 
						|
CompareTimeStamp (
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Find matching signer's certificates for common authenticated variable
 | 
						|
  by corresponding VariableName and VendorGuid from "certdb".
 | 
						|
 | 
						|
  The data format of "certdb":
 | 
						|
  //
 | 
						|
  //     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".
 | 
						|
  @param[in]  DataSize       Size of variable "certdb".
 | 
						|
  @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".
 | 
						|
 | 
						|
  @param[in]  VariableName   Name of authenticated Variable.
 | 
						|
  @param[in]  VendorGuid     Vendor GUID 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" or matching certs.
 | 
						|
  @retval  EFI_SUCCESS           Get signer's certificates successfully.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
GetCertsFromDb (
 | 
						|
  IN     CHAR16           *VariableName,
 | 
						|
  IN     EFI_GUID         *VendorGuid,
 | 
						|
  OUT    UINT8            **CertData,
 | 
						|
  OUT    UINT32           *CertDataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  VARIABLE_POINTER_TRACK  CertDbVariable;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINT8                   *Data;
 | 
						|
  UINTN                   DataSize;
 | 
						|
  UINT32                  CertOffset;
 | 
						|
 | 
						|
  if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get variable "certdb".
 | 
						|
  //
 | 
						|
  Status = FindVariable (
 | 
						|
             EFI_CERT_DB_NAME,
 | 
						|
             &gEfiCertDbGuid,
 | 
						|
             &CertDbVariable,
 | 
						|
             &mVariableModuleGlobal->VariableGlobal,
 | 
						|
             FALSE
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DataSize  = DataSizeOfVariable (CertDbVariable.CurrPtr);
 | 
						|
  Data      = GetVariableDataPtr (CertDbVariable.CurrPtr);
 | 
						|
  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".
 | 
						|
 | 
						|
  @param[in]  VariableName   Name of authenticated Variable.
 | 
						|
  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
 | 
						|
 | 
						|
  @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
 | 
						|
  @retval  EFI_NOT_FOUND         Fail to find "certdb" 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
 | 
						|
  )
 | 
						|
{
 | 
						|
  VARIABLE_POINTER_TRACK  CertDbVariable;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINT8                   *Data;
 | 
						|
  UINTN                   DataSize;
 | 
						|
  UINT32                  VarAttr;
 | 
						|
  UINT32                  CertNodeOffset;
 | 
						|
  UINT32                  CertNodeSize;
 | 
						|
  UINT8                   *NewCertDb;
 | 
						|
  UINT32                  NewCertDbSize;
 | 
						|
 | 
						|
  if ((VariableName == NULL) || (VendorGuid == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get variable "certdb".
 | 
						|
  //
 | 
						|
  Status = FindVariable (
 | 
						|
             EFI_CERT_DB_NAME,
 | 
						|
             &gEfiCertDbGuid,
 | 
						|
             &CertDbVariable,
 | 
						|
             &mVariableModuleGlobal->VariableGlobal,
 | 
						|
             FALSE
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DataSize  = DataSizeOfVariable (CertDbVariable.CurrPtr);
 | 
						|
  Data      = GetVariableDataPtr (CertDbVariable.CurrPtr);
 | 
						|
  if ((DataSize == 0) || (Data == NULL)) {
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DataSize == sizeof (UINT32)) {
 | 
						|
    //
 | 
						|
    // There is no certs in certdb.
 | 
						|
    //
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get corresponding cert node from certdb.
 | 
						|
  //
 | 
						|
  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".
 | 
						|
  //
 | 
						|
  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".
 | 
						|
  //
 | 
						|
  VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
  Status   = UpdateVariable (
 | 
						|
               EFI_CERT_DB_NAME,
 | 
						|
               &gEfiCertDbGuid,
 | 
						|
               NewCertDb,
 | 
						|
               NewCertDbSize,
 | 
						|
               VarAttr,
 | 
						|
               0,
 | 
						|
               0,
 | 
						|
               &CertDbVariable,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Insert signer's certificates for common authenticated variable with VariableName
 | 
						|
  and VendorGuid in AUTH_CERT_DB_DATA to "certdb".
 | 
						|
 | 
						|
  @param[in]  VariableName   Name of authenticated Variable.
 | 
						|
  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
 | 
						|
  @param[in]  CertData       Pointer to signer's certificates.
 | 
						|
  @param[in]  CertDataSize   Length of CertData in bytes.
 | 
						|
 | 
						|
  @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"
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
InsertCertsToDb (
 | 
						|
  IN     CHAR16           *VariableName,
 | 
						|
  IN     EFI_GUID         *VendorGuid,
 | 
						|
  IN     UINT8            *CertData,
 | 
						|
  IN     UINTN            CertDataSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  VARIABLE_POINTER_TRACK  CertDbVariable;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  UINT8                   *Data;
 | 
						|
  UINTN                   DataSize;
 | 
						|
  UINT32                  VarAttr;
 | 
						|
  UINT8                   *NewCertDb;
 | 
						|
  UINT32                  NewCertDbSize;
 | 
						|
  UINT32                  CertNodeSize;
 | 
						|
  UINT32                  NameSize;
 | 
						|
  AUTH_CERT_DB_DATA       *Ptr;
 | 
						|
 | 
						|
  if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Get variable "certdb".
 | 
						|
  //
 | 
						|
  Status = FindVariable (
 | 
						|
             EFI_CERT_DB_NAME,
 | 
						|
             &gEfiCertDbGuid,
 | 
						|
             &CertDbVariable,
 | 
						|
             &mVariableModuleGlobal->VariableGlobal,
 | 
						|
             FALSE
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  DataSize  = DataSizeOfVariable (CertDbVariable.CurrPtr);
 | 
						|
  Data      = GetVariableDataPtr (CertDbVariable.CurrPtr);
 | 
						|
  if ((DataSize == 0) || (Data == NULL)) {
 | 
						|
    ASSERT (FALSE);
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Find whether matching cert node already exists in "certdb".
 | 
						|
  // 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".
 | 
						|
  //
 | 
						|
  NameSize      = (UINT32) StrLen (VariableName);
 | 
						|
  CertNodeSize  = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);
 | 
						|
  NewCertDbSize = (UINT32) DataSize + CertNodeSize;
 | 
						|
  if (NewCertDbSize > mMaxCertDbSize) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  NewCertDb     = (UINT8*) mCertDbStore;
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy the DB entries before deleting 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),
 | 
						|
    CertData,
 | 
						|
    CertDataSize
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Set "certdb".
 | 
						|
  //
 | 
						|
  VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
  Status   = UpdateVariable (
 | 
						|
               EFI_CERT_DB_NAME,
 | 
						|
               &gEfiCertDbGuid,
 | 
						|
               NewCertDb,
 | 
						|
               NewCertDbSize,
 | 
						|
               VarAttr,
 | 
						|
               0,
 | 
						|
               0,
 | 
						|
               &CertDbVariable,
 | 
						|
               NULL
 | 
						|
               );
 | 
						|
 | 
						|
  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]  Variable                    The variable information which is used to keep track of variable usage.
 | 
						|
  @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
 | 
						|
VerifyTimeBasedPayload (
 | 
						|
  IN     CHAR16                             *VariableName,
 | 
						|
  IN     EFI_GUID                           *VendorGuid,
 | 
						|
  IN     VOID                               *Data,
 | 
						|
  IN     UINTN                              DataSize,
 | 
						|
  IN     VARIABLE_POINTER_TRACK             *Variable,
 | 
						|
  IN     UINT32                             Attributes,
 | 
						|
  IN     AUTHVAR_TYPE                       AuthVarType,
 | 
						|
  OUT    BOOLEAN                            *VarDel
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                            *RootCert;
 | 
						|
  UINT8                            *SigData;
 | 
						|
  UINT8                            *PayloadPtr;
 | 
						|
  UINTN                            RootCertSize;
 | 
						|
  UINTN                            Index;
 | 
						|
  UINTN                            CertCount;
 | 
						|
  UINTN                            PayloadSize;
 | 
						|
  UINT32                           Attr;
 | 
						|
  UINT32                           SigDataSize;
 | 
						|
  UINT32                           KekDataSize;
 | 
						|
  BOOLEAN                          VerifyStatus;
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  EFI_SIGNATURE_LIST               *CertList;
 | 
						|
  EFI_SIGNATURE_DATA               *Cert;
 | 
						|
  VARIABLE_POINTER_TRACK           KekVariable;
 | 
						|
  EFI_VARIABLE_AUTHENTICATION_2    *CertData;
 | 
						|
  UINT8                            *NewData;
 | 
						|
  UINTN                            NewDataSize;
 | 
						|
  VARIABLE_POINTER_TRACK           PkVariable;
 | 
						|
  UINT8                            *Buffer;
 | 
						|
  UINTN                            Length;
 | 
						|
  UINT8                            *SignerCerts;
 | 
						|
  UINTN                            CertStackSize;
 | 
						|
  UINT8                            *CertsInCertDb;
 | 
						|
  UINT32                           CertsSizeinDb;
 | 
						|
 | 
						|
  VerifyStatus           = FALSE;
 | 
						|
  CertData               = NULL;
 | 
						|
  NewData                = NULL;
 | 
						|
  Attr                   = Attributes;
 | 
						|
  SignerCerts            = NULL;
 | 
						|
  RootCert               = NULL;
 | 
						|
  CertsInCertDb          = 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 ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
 | 
						|
    if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {
 | 
						|
      //
 | 
						|
      // 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));
 | 
						|
 | 
						|
  //
 | 
						|
  // Find out the new data payload which follows Pkcs7 SignedData directly.
 | 
						|
  //
 | 
						|
  PayloadPtr = SigData + SigDataSize;
 | 
						|
  PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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 will be used at here to do verification only first
 | 
						|
  // and then used in UpdateVariable() for a time based auth variable set.
 | 
						|
  //
 | 
						|
  NewData = (UINT8 *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
 | 
						|
 | 
						|
  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,
 | 
						|
                     &RootCert,
 | 
						|
                     &RootCertSize
 | 
						|
                     );
 | 
						|
    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 = FindVariable (
 | 
						|
               EFI_PLATFORM_KEY_NAME,
 | 
						|
               &gEfiGlobalVariableGuid,
 | 
						|
               &PkVariable,
 | 
						|
               &mVariableModuleGlobal->VariableGlobal,
 | 
						|
               FALSE
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      VerifyStatus = FALSE;
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
    CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);
 | 
						|
    Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
 | 
						|
    if ((RootCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||
 | 
						|
        (CompareMem (Cert->SignatureData, RootCert, RootCertSize) != 0)) {
 | 
						|
      VerifyStatus = FALSE;
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Verify Pkcs7 SignedData via Pkcs7Verify library.
 | 
						|
    //
 | 
						|
    VerifyStatus = Pkcs7Verify (
 | 
						|
                     SigData,
 | 
						|
                     SigDataSize,
 | 
						|
                     RootCert,
 | 
						|
                     RootCertSize,
 | 
						|
                     NewData,
 | 
						|
                     NewDataSize
 | 
						|
                     );
 | 
						|
 | 
						|
  } else if (AuthVarType == AuthVarTypeKek) {
 | 
						|
 | 
						|
    //
 | 
						|
    // Get KEK database from variable.
 | 
						|
    //
 | 
						|
    Status = FindVariable (
 | 
						|
               EFI_KEY_EXCHANGE_KEY_NAME,
 | 
						|
               &gEfiGlobalVariableGuid,
 | 
						|
               &KekVariable,
 | 
						|
               &mVariableModuleGlobal->VariableGlobal,
 | 
						|
               FALSE
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
 | 
						|
    //
 | 
						|
    KekDataSize      = KekVariable.CurrPtr->DataSize;
 | 
						|
    CertList         = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);
 | 
						|
    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
 | 
						|
          //
 | 
						|
          RootCert      = Cert->SignatureData;
 | 
						|
          RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
 | 
						|
 | 
						|
          //
 | 
						|
          // Verify Pkcs7 SignedData via Pkcs7Verify library.
 | 
						|
          //
 | 
						|
          VerifyStatus = Pkcs7Verify (
 | 
						|
                           SigData,
 | 
						|
                           SigDataSize,
 | 
						|
                           RootCert,
 | 
						|
                           RootCertSize,
 | 
						|
                           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,
 | 
						|
                     &RootCert,
 | 
						|
                     &RootCertSize
 | 
						|
                     );
 | 
						|
    if (!VerifyStatus) {
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Get previously stored signer's certificates from certdb for existing
 | 
						|
    // variable. Check whether they are identical with signer's certificates
 | 
						|
    // in SignedData. If not, return error immediately.
 | 
						|
    //
 | 
						|
    if ((Variable->CurrPtr != NULL)) {
 | 
						|
      VerifyStatus = FALSE;
 | 
						|
 | 
						|
      Status = GetCertsFromDb (VariableName, VendorGuid, &CertsInCertDb, &CertsSizeinDb);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        goto Exit;
 | 
						|
      }
 | 
						|
 | 
						|
      if ((CertStackSize != CertsSizeinDb) ||
 | 
						|
          (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {
 | 
						|
        goto Exit;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    VerifyStatus = Pkcs7Verify (
 | 
						|
                     SigData,
 | 
						|
                     SigDataSize,
 | 
						|
                     RootCert,
 | 
						|
                     RootCertSize,
 | 
						|
                     NewData,
 | 
						|
                     NewDataSize
 | 
						|
                     );
 | 
						|
    if (!VerifyStatus) {
 | 
						|
      goto Exit;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Delete signer's certificates when delete the common authenticated variable.
 | 
						|
    //
 | 
						|
    if ((PayloadSize == 0) && (Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
 | 
						|
      Status = DeleteCertsFromDb (VariableName, VendorGuid);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        VerifyStatus = FALSE;
 | 
						|
        goto Exit;
 | 
						|
      }
 | 
						|
    } else if (Variable->CurrPtr == NULL && PayloadSize != 0) {
 | 
						|
      //
 | 
						|
      // Insert signer's certificates when adding a new common authenticated variable.
 | 
						|
      //
 | 
						|
      Status = InsertCertsToDb (VariableName, VendorGuid, SignerCerts, CertStackSize);
 | 
						|
      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);
 | 
						|
    RootCert      = Cert->SignatureData;
 | 
						|
    RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
 | 
						|
 | 
						|
    // Verify Pkcs7 SignedData via Pkcs7Verify library.
 | 
						|
    //
 | 
						|
    VerifyStatus = Pkcs7Verify (
 | 
						|
                     SigData,
 | 
						|
                     SigDataSize,
 | 
						|
                     RootCert,
 | 
						|
                     RootCertSize,
 | 
						|
                     NewData,
 | 
						|
                     NewDataSize
 | 
						|
                     );
 | 
						|
  } else {
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
Exit:
 | 
						|
 | 
						|
  if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {
 | 
						|
    Pkcs7FreeSigners (RootCert);
 | 
						|
    Pkcs7FreeSigners (SignerCerts);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!VerifyStatus) {
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((PayloadSize == 0) && (VarDel != NULL)) {
 | 
						|
    *VarDel = TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Final step: Update/Append Variable if it pass Pkcs7Verify
 | 
						|
  //
 | 
						|
  return UpdateVariable (
 | 
						|
           VariableName,
 | 
						|
           VendorGuid,
 | 
						|
           PayloadPtr,
 | 
						|
           PayloadSize,
 | 
						|
           Attributes,
 | 
						|
           0,
 | 
						|
           0,
 | 
						|
           Variable,
 | 
						|
           &CertData->TimeStamp
 | 
						|
           );
 | 
						|
}
 |