]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
Add missing parameter comment in AddPubKeyInStore()
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / AuthService.c
index ff5c6539125af152a47bedfaf276107c492fec22..07a41b06f8ad01a52d5e232d63cc4357d0986d66 100644 (file)
@@ -2,13 +2,26 @@
   Implement authentication services for the authenticated variable\r
   service in UEFI2.2.\r
 \r
-Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution.  The full text of the license may be found at \r
+  Caution: This module requires additional review when modified.\r
+  This driver will have external input - variable data. It may be input in SMM mode.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+  Variable attribute should also be checked to avoid authentication bypass.\r
+\r
+  ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do\r
+  variable authentication.\r
+\r
+  VerifyTimeBasedPayload() and VerifyCounterBasedPayload() are sub function to do verification.\r
+  They will do basic validation for authentication data structure, then call crypto library\r
+  to verify the signature.\r
+\r
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
 http://opensource.org/licenses/bsd-license.php\r
 \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 \r
 **/\r
@@ -18,11 +31,14 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 \r
 ///\r
 /// Global database array for scratch\r
-/// \r
+///\r
 UINT8    mPubKeyStore[MAX_KEYDB_SIZE];\r
 UINT32   mPubKeyNumber;\r
+UINT8    mCertDbStore[MAX_CERTDB_SIZE];\r
 UINT32   mPlatformMode;\r
-EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};\r
+UINT8    mVendorKeyState;\r
+\r
+EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};\r
 //\r
 // Public Exponent of RSA Key.\r
 //\r
@@ -32,28 +48,106 @@ CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
 //\r
 VOID  *mHashCtx = NULL;\r
 \r
+//\r
+// The serialization of the values of the VariableName, VendorGuid and Attributes\r
+// parameters of the SetVariable() call and the TimeStamp component of the\r
+// EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value\r
+// i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)\r
+//\r
+UINT8 *mSerializationRuntimeBuffer = NULL;\r
 \r
 //\r
-// Pointer to runtime buffer. \r
-// For "Append" operation to an existing variable, a read/modify/write operation \r
-// is supported by firmware internally. Reserve runtime buffer to cache previous \r
-// variable data in runtime phase because memory allocation is forbidden in virtual mode.\r
+// Requirement for different signature type which have been defined in UEFI spec.\r
+// These data are used to peform SignatureList format check while setting PK/KEK variable.\r
 //\r
-VOID  *mStorageArea = NULL;\r
+EFI_SIGNATURE_ITEM mSupportSigItem[] = {\r
+//{SigType,                       SigHeaderSize,   SigDataSize  }\r
+  {EFI_CERT_SHA256_GUID,          0,               32           },\r
+  {EFI_CERT_RSA2048_GUID,         0,               256          },\r
+  {EFI_CERT_RSA2048_SHA256_GUID,  0,               256          },\r
+  {EFI_CERT_SHA1_GUID,            0,               20           },\r
+  {EFI_CERT_RSA2048_SHA1_GUID,    0,               256          },\r
+  {EFI_CERT_X509_GUID,            0,               ((UINT32) ~0)},\r
+  {EFI_CERT_SHA224_GUID,          0,               28           },\r
+  {EFI_CERT_SHA384_GUID,          0,               48           },\r
+  {EFI_CERT_SHA512_GUID,          0,               64           }\r
+};\r
 \r
 /**\r
-  Update platform mode.\r
+  Determine whether this operation needs a physical present user.\r
 \r
-  @param[in]      Mode                    SETUP_MODE or USER_MODE.\r
+  @param[in]      VariableName            Name of the Variable.\r
+  @param[in]      VendorGuid              GUID of the Variable.\r
 \r
-  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
-  @return EFI_SUCCESS                     Update platform mode successfully.\r
+  @retval TRUE      This variable is protected, only a physical present user could set this variable.\r
+  @retval FALSE     This variable is not protected.\r
+  \r
+**/\r
+BOOLEAN\r
+NeedPhysicallyPresent(\r
+  IN     CHAR16         *VariableName,\r
+  IN     EFI_GUID       *VendorGuid\r
+  )\r
+{\r
+  if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))\r
+    || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {\r
+    return TRUE;\r
+  }\r
+  \r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Determine whether the platform is operating in Custom Secure Boot mode.\r
+\r
+  @retval TRUE           The platform is operating in Custom mode.\r
+  @retval FALSE          The platform is operating in Standard mode.\r
+\r
+**/\r
+BOOLEAN\r
+InCustomMode (\r
+  VOID\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+\r
+  FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  if (Variable.CurrPtr != NULL && *(GetVariableDataPtr (Variable.CurrPtr)) == CUSTOM_SECURE_BOOT_MODE) {\r
+    return TRUE;\r
+  }\r
+  \r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Internal function to delete a Variable given its name and GUID, no authentication\r
+  required.\r
+\r
+  @param[in]      VariableName            Name of the Variable.\r
+  @param[in]      VendorGuid              GUID of the Variable.\r
+\r
+  @retval EFI_SUCCESS              Variable deleted successfully.\r
+  @retval Others                   The driver failded to start the device.\r
 \r
 **/\r
 EFI_STATUS\r
-UpdatePlatformMode (\r
-  IN  UINT32                    Mode\r
-  );\r
+DeleteVariable (\r
+  IN  CHAR16                    *VariableName,\r
+  IN  EFI_GUID                  *VendorGuid\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ASSERT (Variable.CurrPtr != NULL);\r
+  return UpdateVariable (VariableName, VendorGuid, NULL, 0, 0, 0, 0, &Variable, NULL);\r
+}\r
 \r
 /**\r
   Initializes for authenticated varibale service.\r
@@ -69,7 +163,7 @@ AutenticatedVariableServiceInitialize (
 {\r
   EFI_STATUS              Status;\r
   VARIABLE_POINTER_TRACK  Variable;\r
-  VARIABLE_POINTER_TRACK  Variable2;\r
+  VARIABLE_POINTER_TRACK  PkVariable;\r
   UINT8                   VarValue;\r
   UINT32                  VarAttr;\r
   UINT8                   *Data;\r
@@ -77,7 +171,9 @@ AutenticatedVariableServiceInitialize (
   UINTN                   CtxSize;\r
   UINT8                   SecureBootMode;\r
   UINT8                   SecureBootEnable;\r
-  \r
+  UINT8                   CustomMode;\r
+  UINT32                  ListSize;\r
+\r
   //\r
   // Initialize hash context.\r
   //\r
@@ -88,22 +184,24 @@ AutenticatedVariableServiceInitialize (
   }\r
 \r
   //\r
-  // Reserved runtime buffer for "Append" operation in virtual mode.\r
+  // Prepare runtime buffer for serialized data of time-based authenticated\r
+  // Variable, i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
   //\r
-  mStorageArea  = AllocateRuntimePool (PcdGet32 (PcdMaxAppendVariableSize));\r
-  if (mStorageArea == NULL) {\r
+  mSerializationRuntimeBuffer = AllocateRuntimePool (PcdGet32 (PcdMaxVariableSize) + sizeof (EFI_GUID) + sizeof (UINT32) + sizeof (EFI_TIME));\r
+  if (mSerializationRuntimeBuffer == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   //\r
-  // Check "AuthVarKeyDatabase" variable's existence. \r
-  // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+  // Check "AuthVarKeyDatabase" variable's existence.\r
+  // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
   //\r
   Status = FindVariable (\r
-             AUTHVAR_KEYDB_NAME, \r
-             &gEfiAuthenticatedVariableGuid, \r
-             &Variable, \r
-             &mVariableModuleGlobal->VariableGlobal\r
+             AUTHVAR_KEYDB_NAME,\r
+             &gEfiAuthenticatedVariableGuid,\r
+             &Variable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
              );\r
 \r
   if (Variable.CurrPtr == NULL) {\r
@@ -134,98 +232,188 @@ AutenticatedVariableServiceInitialize (
     CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
     mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
   }\r
+\r
+  FindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, &PkVariable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  if (PkVariable.CurrPtr == NULL) {\r
+    DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));\r
+  } else {\r
+    DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));\r
+  }\r
+  \r
   //\r
-  // Check "SetupMode" variable's existence. \r
-  // If it doesn't exist, check PK database's existence to determine the value.\r
-  // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+  // Create "SetupMode" variable with BS+RT attribute set.\r
   //\r
-  Status = FindVariable (\r
-             EFI_SETUP_MODE_NAME, \r
-             &gEfiGlobalVariableGuid, \r
-             &Variable, \r
-             &mVariableModuleGlobal->VariableGlobal\r
+  FindVariable (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  if (PkVariable.CurrPtr == NULL) {\r
+    mPlatformMode = SETUP_MODE;\r
+  } else {\r
+    mPlatformMode = USER_MODE;\r
+  }\r
+  Status = UpdateVariable (\r
+             EFI_SETUP_MODE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &mPlatformMode,\r
+             sizeof(UINT8),\r
+             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+             0,\r
+             0,\r
+             &Variable,\r
+             NULL\r
              );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Create "SignatureSupport" variable with BS+RT attribute set.\r
+  //\r
+  FindVariable (EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  Status  = UpdateVariable (\r
+              EFI_SIGNATURE_SUPPORT_NAME,\r
+              &gEfiGlobalVariableGuid,\r
+              mSignatureSupport,\r
+              sizeof(mSignatureSupport),\r
+              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+              0,\r
+              0,\r
+              &Variable,\r
+              NULL\r
+              );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
-  if (Variable.CurrPtr == NULL) {\r
-    Status = FindVariable (\r
-               EFI_PLATFORM_KEY_NAME, \r
-               &gEfiGlobalVariableGuid, \r
-               &Variable2, \r
-               &mVariableModuleGlobal->VariableGlobal\r
+  //\r
+  // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.\r
+  // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.\r
+  // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.\r
+  //\r
+  SecureBootEnable = SECURE_BOOT_DISABLE;\r
+  FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  if (Variable.CurrPtr != NULL) {\r
+    SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));\r
+  } else if (mPlatformMode == USER_MODE) {\r
+    //\r
+    // "SecureBootEnable" not exist, initialize it in USER_MODE.\r
+    //\r
+    SecureBootEnable = SECURE_BOOT_ENABLE;\r
+    Status = UpdateVariable (\r
+               EFI_SECURE_BOOT_ENABLE_NAME,\r
+               &gEfiSecureBootEnableDisableGuid,\r
+               &SecureBootEnable,\r
+               sizeof (UINT8),\r
+               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+               0,\r
+               0,\r
+               &Variable,\r
+               NULL\r
                );\r
-    if (Variable2.CurrPtr == NULL) {\r
-      mPlatformMode = SETUP_MODE;\r
-    } else {\r
-      mPlatformMode = USER_MODE;\r
-    }\r
-\r
-    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
-    Status  = UpdateVariable (\r
-                EFI_SETUP_MODE_NAME,\r
-                &gEfiGlobalVariableGuid,\r
-                &mPlatformMode,\r
-                sizeof(UINT8),\r
-                VarAttr,\r
-                0,\r
-                0,\r
-                &Variable,\r
-                NULL\r
-                );\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
+  }\r
+\r
+  //\r
+  // Create "SecureBoot" variable with BS+RT attribute set.\r
+  //\r
+  if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {\r
+    SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
   } else {\r
-    mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
+    SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
+  }\r
+  FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  Status = UpdateVariable (\r
+             EFI_SECURE_BOOT_MODE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &SecureBootMode,\r
+             sizeof (UINT8),\r
+             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+             0,\r
+             0,\r
+             &Variable,\r
+             NULL\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));\r
+  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));\r
+  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));\r
+\r
+  //\r
+  // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state.\r
+  //\r
+  FindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  CustomMode = STANDARD_SECURE_BOOT_MODE;\r
+  Status = UpdateVariable (\r
+             EFI_CUSTOM_MODE_NAME,\r
+             &gEfiCustomModeEnableGuid,\r
+             &CustomMode,\r
+             sizeof (UINT8),\r
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+             0,\r
+             0,\r
+             &Variable,\r
+             NULL\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
+  \r
+  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));\r
+\r
   //\r
-  // Check "SignatureSupport" variable's existence. \r
-  // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+  // Check "certdb" variable's existence.\r
+  // If it doesn't exist, then create a new one with \r
+  // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.\r
   //\r
   Status = FindVariable (\r
-             EFI_SIGNATURE_SUPPORT_NAME, \r
-             &gEfiGlobalVariableGuid, \r
-             &Variable, \r
-             &mVariableModuleGlobal->VariableGlobal\r
+             EFI_CERT_DB_NAME,\r
+             &gEfiCertDbGuid,\r
+             &Variable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
              );\r
 \r
-\r
   if (Variable.CurrPtr == NULL) {\r
-    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
-    Status  = UpdateVariable (\r
-                EFI_SIGNATURE_SUPPORT_NAME,\r
-                &gEfiGlobalVariableGuid,\r
-                mSignatureSupport,\r
-                SIGSUPPORT_NUM * sizeof(EFI_GUID),\r
-                VarAttr,\r
-                0,\r
-                0,\r
-                &Variable,\r
-                NULL\r
-                );\r
-  }\r
+    VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
+    ListSize = sizeof (UINT32);\r
+    Status   = UpdateVariable (\r
+                 EFI_CERT_DB_NAME,\r
+                 &gEfiCertDbGuid,\r
+                 &ListSize,\r
+                 sizeof (UINT32),\r
+                 VarAttr,\r
+                 0,\r
+                 0,\r
+                 &Variable,\r
+                 NULL\r
+                 );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }  \r
 \r
   //\r
-  // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.\r
-  // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.\r
-  // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.\r
+  // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly.\r
   //\r
-  FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+  FindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
   if (Variable.CurrPtr != NULL) {\r
-    SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));\r
-    if (SecureBootEnable == SECURE_BOOT_ENABLE) {\r
-      SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
-    } else {\r
-      SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
-    }\r
-    FindVariable (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+    mVendorKeyState = *(GetVariableDataPtr (Variable.CurrPtr));\r
+  } else {\r
+    //\r
+    // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state.\r
+    //\r
+    mVendorKeyState = VENDOR_KEYS_VALID;\r
     Status = UpdateVariable (\r
-               EFI_SECURE_BOOT_MODE_NAME, \r
-               &gEfiGlobalVariableGuid, \r
-               &SecureBootMode, \r
-               sizeof(UINT8), \r
-               EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, \r
-               0, \r
-               0, \r
+               EFI_VENDOR_KEYS_NV_VARIABLE_NAME,\r
+               &gEfiVendorKeysNvGuid,\r
+               &mVendorKeyState,\r
+               sizeof (UINT8),\r
+               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,\r
+               0,\r
+               0,\r
                &Variable,\r
                NULL\r
                );\r
@@ -235,43 +423,26 @@ AutenticatedVariableServiceInitialize (
   }\r
 \r
   //\r
-  // Detect whether a secure platform-specific method to clear PK(Platform Key)\r
-  // is configured by platform owner. This method is provided for users force to clear PK \r
-  // in case incorrect enrollment mis-haps.\r
+  // Create "VendorKeys" variable with BS+RT attribute set.\r
   //\r
-  if (ForceClearPK ()) {\r
-    //\r
-    // 1. Check whether PK is existing, and clear PK if existing\r
-    //\r
-    FindVariable (\r
-      EFI_PLATFORM_KEY_NAME, \r
-      &gEfiGlobalVariableGuid, \r
-      &Variable, \r
-      &mVariableModuleGlobal->VariableGlobal\r
-      );\r
-    if (Variable.CurrPtr != NULL) {\r
-      VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
-      Status  = UpdateVariable (\r
-                  EFI_PLATFORM_KEY_NAME,\r
-                  &gEfiGlobalVariableGuid,\r
-                  NULL,\r
-                  0,\r
-                  VarAttr,\r
-                  0,\r
-                  0,\r
-                  &Variable,\r
-                  NULL\r
-                  );\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-    }\r
-\r
-    //\r
-    // 2. Update "SetupMode" variable to SETUP_MODE\r
-    //\r
-    UpdatePlatformMode (SETUP_MODE);\r
+  FindVariable (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  Status = UpdateVariable (\r
+             EFI_VENDOR_KEYS_VARIABLE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &mVendorKeyState,\r
+             sizeof (UINT8),\r
+             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+             0,\r
+             0,\r
+             &Variable,\r
+             NULL\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
+\r
+  DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_VENDOR_KEYS_VARIABLE_NAME, mVendorKeyState));\r
+\r
   return Status;\r
 }\r
 \r
@@ -279,20 +450,26 @@ AutenticatedVariableServiceInitialize (
   Add public key in store and return its index.\r
 \r
   @param[in]  PubKey                  Input pointer to Public Key data\r
+  @param[in]  VariableDataEntry       The variable data entry \r
 \r
   @return                             Index of new added item\r
 \r
 **/\r
 UINT32\r
 AddPubKeyInStore (\r
-  IN  UINT8               *PubKey\r
+  IN  UINT8                        *PubKey,\r
+  IN  VARIABLE_ENTRY_CONSISTENCY   *VariableDataEntry\r
   )\r
 {\r
-  EFI_STATUS              Status;\r
-  BOOLEAN                 IsFound;\r
-  UINT32                  Index;\r
-  VARIABLE_POINTER_TRACK  Variable;\r
-  UINT8                   *Ptr;\r
+  EFI_STATUS                       Status;\r
+  BOOLEAN                          IsFound;\r
+  UINT32                           Index;\r
+  VARIABLE_POINTER_TRACK           Variable;\r
+  UINT8                            *Ptr;\r
+  UINT8                            *Data;\r
+  UINTN                            DataSize;\r
+  VARIABLE_ENTRY_CONSISTENCY       PublicKeyEntry;\r
+  UINT32                           Attributes;\r
 \r
   if (PubKey == NULL) {\r
     return 0;\r
@@ -302,9 +479,14 @@ AddPubKeyInStore (
              AUTHVAR_KEYDB_NAME,\r
              &gEfiAuthenticatedVariableGuid,\r
              &Variable,\r
-             &mVariableModuleGlobal->VariableGlobal\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
              );\r
-  ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));\r
+    return 0;\r
+  }\r
+\r
   //\r
   // Check whether the public key entry does exist.\r
   //\r
@@ -323,7 +505,62 @@ AddPubKeyInStore (
     //\r
     if (mPubKeyNumber == MAX_KEY_NUM) {\r
       //\r
-      // Notes: Database is full, need enhancement here, currently just return 0.\r
+      // Public key dadatase is full, try to reclaim invalid key.\r
+      //\r
+      if (AtRuntime ()) {\r
+        //\r
+        // NV storage can't reclaim at runtime.\r
+        //\r
+        return 0;\r
+      }\r
+      \r
+      Status = Reclaim (\r
+                 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+                 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+                 FALSE,\r
+                 NULL,\r
+                 NULL,\r
+                 0,\r
+                 TRUE\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        return 0;\r
+      }\r
+\r
+      Status = FindVariable (\r
+                 AUTHVAR_KEYDB_NAME,\r
+                 &gEfiAuthenticatedVariableGuid,\r
+                 &Variable,\r
+                 &mVariableModuleGlobal->VariableGlobal,\r
+                 FALSE\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));\r
+        return 0;\r
+      }\r
+\r
+      DataSize  = DataSizeOfVariable (Variable.CurrPtr);\r
+      Data      = GetVariableDataPtr (Variable.CurrPtr);\r
+      ASSERT ((DataSize != 0) && (Data != NULL));\r
+      CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
+      mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
+\r
+      if (mPubKeyNumber == MAX_KEY_NUM) {\r
+        return 0;\r
+      }     \r
+    }\r
+\r
+    //\r
+    // Check the variable space for both public key and variable data.\r
+    //\r
+    PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * EFI_CERT_TYPE_RSA2048_SIZE;\r
+    PublicKeyEntry.Guid         = &gEfiAuthenticatedVariableGuid;\r
+    PublicKeyEntry.Name         = AUTHVAR_KEYDB_NAME;\r
+    Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+\r
+    if (!CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {\r
+      //\r
+      // No enough variable space.\r
       //\r
       return 0;\r
     }\r
@@ -338,29 +575,38 @@ AddPubKeyInStore (
                &gEfiAuthenticatedVariableGuid,\r
                mPubKeyStore,\r
                mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
-               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
+               Attributes,\r
                0,\r
                0,\r
                &Variable,\r
                NULL\r
                );\r
-    ASSERT_EFI_ERROR (Status);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));\r
+      return 0;\r
+    }\r
   }\r
 \r
   return Index;\r
 }\r
 \r
 /**\r
-  Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.\r
+  Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.\r
   Follow the steps in UEFI2.2.\r
 \r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode, and datasize and data are external input.\r
+  This function will do basic validation, before parse the data.\r
+  This function will parse the authentication carefully to avoid security issues, like\r
+  buffer overflow, integer overflow.\r
+\r
   @param[in]      Data                    Pointer to data with AuthInfo.\r
   @param[in]      DataSize                Size of Data.\r
   @param[in]      PubKey                  Public key used for verification.\r
 \r
-  @return EFI_INVALID_PARAMETER       Invalid parameter.\r
+  @retval EFI_INVALID_PARAMETER       Invalid parameter.\r
   @retval EFI_SECURITY_VIOLATION      If authentication failed.\r
-  @return EFI_SUCCESS                 Authentication successful.\r
+  @retval EFI_SUCCESS                 Authentication successful.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -375,7 +621,9 @@ VerifyCounterBasedPayload (
   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
   UINT8                           Digest[SHA256_DIGEST_SIZE];\r
   VOID                            *Rsa;\r
-\r
+  UINTN                           PayloadSize;\r
+  \r
+  PayloadSize = DataSize - AUTHINFO_SIZE;\r
   Rsa         = NULL;\r
   CertData    = NULL;\r
   CertBlock   = NULL;\r
@@ -389,10 +637,10 @@ VerifyCounterBasedPayload (
 \r
   //\r
   // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
-  // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.\r
+  // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.\r
   //\r
   if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
-      !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid)\r
+      !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)\r
         ) {\r
     //\r
     // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
@@ -407,7 +655,14 @@ VerifyCounterBasedPayload (
   if (!Status) {\r
     goto Done;\r
   }\r
-  Status  = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));\r
+  Status  = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Hash Size.\r
+  //\r
+  Status  = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));\r
   if (!Status) {\r
     goto Done;\r
   }\r
@@ -427,7 +682,7 @@ VerifyCounterBasedPayload (
   //\r
   Rsa = RsaNew ();\r
   ASSERT (Rsa != NULL);\r
-  // \r
+  //\r
   // Set RSA Key Components.\r
   // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
   //\r
@@ -443,10 +698,10 @@ VerifyCounterBasedPayload (
   // Verify the signature.\r
   //\r
   Status = RsaPkcs1Verify (\r
-             Rsa, \r
-             Digest, \r
-             SHA256_DIGEST_SIZE, \r
-             CertBlock->Signature, \r
+             Rsa,\r
+             Digest,\r
+             SHA256_DIGEST_SIZE,\r
+             CertBlock->Signature,\r
              EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
              );\r
 \r
@@ -461,7 +716,6 @@ Done:
   }\r
 }\r
 \r
-\r
 /**\r
   Update platform mode.\r
 \r
@@ -478,35 +732,34 @@ UpdatePlatformMode (
 {\r
   EFI_STATUS              Status;\r
   VARIABLE_POINTER_TRACK  Variable;\r
-  UINT32                  VarAttr;\r
   UINT8                   SecureBootMode;\r
   UINT8                   SecureBootEnable;\r
   UINTN                   VariableDataSize;\r
-  \r
+\r
   Status = FindVariable (\r
-             EFI_SETUP_MODE_NAME, \r
-             &gEfiGlobalVariableGuid, \r
-             &Variable, \r
-             &mVariableModuleGlobal->VariableGlobal\r
+             EFI_SETUP_MODE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &Variable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
              );\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  mPlatformMode  = Mode;\r
-  VarAttr        = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
-  Status         = UpdateVariable (\r
-                     EFI_SETUP_MODE_NAME,\r
-                     &gEfiGlobalVariableGuid,\r
-                     &mPlatformMode,\r
-                     sizeof(UINT8),\r
-                     VarAttr,\r
-                     0,\r
-                     0,\r
-                     &Variable,\r
-                     NULL\r
-                     );\r
-  if (EFI_ERROR (Status)) {\r
+  //\r
+  // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r
+  // variable storage reclaim at runtime.\r
+  //\r
+  mPlatformMode = (UINT8) Mode;\r
+  CopyMem (GetVariableDataPtr (Variable.CurrPtr), &mPlatformMode, sizeof(UINT8));\r
+\r
+  if (AtRuntime ()) {\r
+    //\r
+    // SecureBoot Variable indicates whether the platform firmware is operating\r
+    // in Secure boot mode (1) or not (0), so we should not change SecureBoot\r
+    // Variable in runtime.\r
+    //\r
     return Status;\r
   }\r
 \r
@@ -516,10 +769,11 @@ UpdatePlatformMode (
   // then set "SecureBoot" to 0.\r
   //\r
   Status = FindVariable (\r
-             EFI_SECURE_BOOT_MODE_NAME, \r
-             &gEfiGlobalVariableGuid, \r
-             &Variable, \r
-             &mVariableModuleGlobal->VariableGlobal\r
+             EFI_SECURE_BOOT_MODE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &Variable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
              );\r
   //\r
   // If "SecureBoot" variable exists, then check "SetupMode" variable update.\r
@@ -538,19 +792,17 @@ UpdatePlatformMode (
     }\r
   }\r
 \r
-  VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
   Status  = UpdateVariable (\r
               EFI_SECURE_BOOT_MODE_NAME,\r
               &gEfiGlobalVariableGuid,\r
               &SecureBootMode,\r
               sizeof(UINT8),\r
-              VarAttr,\r
+              EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
               0,\r
               0,\r
               &Variable,\r
               NULL\r
               );\r
-\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -559,12 +811,13 @@ UpdatePlatformMode (
   // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.\r
   //\r
   Status = FindVariable (\r
-             EFI_SECURE_BOOT_ENABLE_NAME, \r
-             &gEfiSecureBootEnableDisableGuid, \r
-             &Variable, \r
-             &mVariableModuleGlobal->VariableGlobal\r
+             EFI_SECURE_BOOT_ENABLE_NAME,\r
+             &gEfiSecureBootEnableDisableGuid,\r
+             &Variable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
              );\r
\r
+\r
   if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {\r
     //\r
     // Create the "SecureBootEnable" variable as secure boot is enabled.\r
@@ -573,7 +826,7 @@ UpdatePlatformMode (
     VariableDataSize = sizeof (SecureBootEnable);\r
   } else {\r
     //\r
-    // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot" \r
+    // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"\r
     // variable is not in secure boot state.\r
     //\r
     if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
@@ -582,15 +835,15 @@ UpdatePlatformMode (
     SecureBootEnable = SECURE_BOOT_DISABLE;\r
     VariableDataSize = 0;\r
   }\r
-  \r
+\r
   Status = UpdateVariable (\r
-             EFI_SECURE_BOOT_ENABLE_NAME, \r
-             &gEfiSecureBootEnableDisableGuid, \r
-             &SecureBootEnable, \r
-             VariableDataSize, \r
-             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, \r
-             0, \r
-             0, \r
+             EFI_SECURE_BOOT_ENABLE_NAME,\r
+             &gEfiSecureBootEnableDisableGuid,\r
+             &SecureBootEnable,\r
+             VariableDataSize,\r
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+             0,\r
+             0,\r
              &Variable,\r
              NULL\r
              );\r
@@ -598,135 +851,295 @@ UpdatePlatformMode (
 }\r
 \r
 /**\r
-  Process variable with platform key for verification.\r
+  Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx variable.\r
 \r
-  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VariableName                Name of Variable to be check.\r
   @param[in]  VendorGuid                  Variable vendor GUID.\r
-  @param[in]  Data                        Data pointer.\r
-  @param[in]  DataSize                    Size of Data found. If size is less than the\r
-                                          data, this value contains the required size.\r
-  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
-  @param[in]  Attributes                  Attribute value of the variable\r
-  @param[in]  IsPk                        Indicate whether it is to process pk.\r
-\r
-  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
-  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation. \r
-                                          check carried out by the firmware. \r
-  @return EFI_SUCCESS                     Variable passed validation successfully.\r
+  @param[in]  Data                        Point to the variable data to be checked.\r
+  @param[in]  DataSize                    Size of Data.\r
 \r
+  @return EFI_INVALID_PARAMETER           Invalid signature list format.\r
+  @return EFI_SUCCESS                     Passed signature list format check successfully.\r
+  \r
 **/\r
 EFI_STATUS\r
-ProcessVarWithPk (\r
+CheckSignatureListFormat(\r
   IN  CHAR16                    *VariableName,\r
   IN  EFI_GUID                  *VendorGuid,\r
   IN  VOID                      *Data,\r
-  IN  UINTN                     DataSize,\r
-  IN  VARIABLE_POINTER_TRACK    *Variable,\r
-  IN  UINT32                    Attributes OPTIONAL,\r
-  IN  BOOLEAN                   IsPk\r
+  IN  UINTN                     DataSize\r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
-  VARIABLE_POINTER_TRACK      PkVariable;\r
-  EFI_SIGNATURE_LIST          *OldPkList;\r
-  EFI_SIGNATURE_DATA          *OldPkData;\r
-  EFI_VARIABLE_AUTHENTICATION *CertData;\r
-  BOOLEAN                     TimeBase;\r
-  BOOLEAN                     Del;\r
+  EFI_SIGNATURE_LIST     *SigList;\r
+  UINTN                  SigDataSize;\r
+  UINT32                 Index;\r
+  UINT32                 SigCount;\r
+  BOOLEAN                IsPk;\r
+  VOID                   *RsaContext;\r
+  EFI_SIGNATURE_DATA     *CertData;\r
+  UINTN                  CertLen;\r
+\r
+  if (DataSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
-  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
-    //\r
-    // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
-    //\r
-    return EFI_INVALID_PARAMETER;\r
+  ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);\r
+\r
+  if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r
+    IsPk = TRUE;\r
+  } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0) ||\r
+             (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && \r
+              (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0 || StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))){\r
+    IsPk = FALSE;\r
+  } else {\r
+    return EFI_SUCCESS;\r
   }\r
 \r
-  if (mPlatformMode == USER_MODE) {\r
+  SigCount = 0;\r
+  SigList  = (EFI_SIGNATURE_LIST *) Data;\r
+  SigDataSize  = DataSize;\r
+  RsaContext = NULL;\r
 \r
-    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-      //\r
-      // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.\r
-      //\r
-      TimeBase = TRUE;\r
-    } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+  //\r
+  // Walk throuth the input signature list and check the data format.\r
+  // If any signature is incorrectly formed, the whole check will fail.\r
+  //\r
+  while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {\r
+    for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {\r
+      if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {\r
+        //\r
+        // The value of SignatureSize should always be 16 (size of SignatureOwner \r
+        // component) add the data length according to signature type.\r
+        //\r
+        if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) && \r
+          (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {\r
+          return EFI_INVALID_PARAMETER;\r
+        }\r
+        if (mSupportSigItem[Index].SigHeaderSize != ((UINTN) ~0) &&\r
+          SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {\r
+          return EFI_INVALID_PARAMETER;\r
+        }\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {\r
       //\r
-      // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.\r
+      // Undefined signature type.\r
       //\r
-      TimeBase = FALSE;\r
-    } else {\r
       return EFI_INVALID_PARAMETER;\r
     }\r
 \r
-    if (TimeBase) {\r
+    if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
       //\r
-      // Verify against X509 Cert PK.\r
+      // Try to retrieve the RSA public key from the X.509 certificate.\r
+      // If this operation fails, it's not a valid certificate.\r
       //\r
-      Del    = FALSE;\r
-      Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del);\r
-      if (!EFI_ERROR (Status)) {\r
-        //\r
-        // If delete PK in user mode, need change to setup mode.\r
-        //\r
-        if (Del && IsPk) {\r
-          Status = UpdatePlatformMode (SETUP_MODE);\r
-        }\r
+      RsaContext = RsaNew ();\r
+      if (RsaContext == NULL) {\r
+        return EFI_INVALID_PARAMETER;\r
       }\r
-      return Status;\r
-    } else {\r
-      //\r
-      // Verify against RSA2048 Cert PK.\r
-      //\r
-      CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
-      if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
-        //\r
-        // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
-        //\r
-        return EFI_SECURITY_VIOLATION;\r
+      CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);\r
+      CertLen = SigList->SignatureSize - sizeof (EFI_GUID);\r
+      if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {\r
+        RsaFree (RsaContext);\r
+        return EFI_INVALID_PARAMETER;\r
       }\r
-      //\r
-      // Get platform key from variable.\r
-      //\r
-      Status = FindVariable (\r
-                 EFI_PLATFORM_KEY_NAME, \r
-                 &gEfiGlobalVariableGuid, \r
-                 &PkVariable, \r
-                 &mVariableModuleGlobal->VariableGlobal\r
-                 );\r
-      ASSERT_EFI_ERROR (Status);\r
+      RsaFree (RsaContext);\r
+    }\r
+\r
+    if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;\r
+    \r
+    SigDataSize -= SigList->SignatureListSize;\r
+    SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);\r
+  }\r
+\r
+  if (((UINTN) SigList - (UINTN) Data) != DataSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (IsPk && SigCount > 1) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Update "VendorKeys" variable to record the out of band secure boot key modification.\r
+\r
+  @return EFI_SUCCESS           Variable is updated successfully.\r
+  @return Others                Failed to update variable.\r
   \r
-      OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
-      OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
-      Status    = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);\r
-      if (!EFI_ERROR (Status)) {\r
-        Status = UpdateVariable (\r
-                   VariableName, \r
-                   VendorGuid, \r
-                   (UINT8*)Data + AUTHINFO_SIZE, \r
-                   DataSize - AUTHINFO_SIZE, \r
-                   Attributes, \r
-                   0, \r
-                   CertData->MonotonicCount, \r
-                   Variable,\r
-                   NULL\r
-                   );\r
+**/\r
+EFI_STATUS\r
+VendorKeyIsModified (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+\r
+  if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  mVendorKeyState = VENDOR_KEYS_MODIFIED;\r
   \r
-        if (!EFI_ERROR (Status)) {\r
-          //\r
-          // If delete PK in user mode, need change to setup mode.\r
-          //\r
-          if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
-            Status = UpdatePlatformMode (SETUP_MODE);\r
-          }\r
-        }\r
-      }\r
+  FindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  Status = UpdateVariable (\r
+             EFI_VENDOR_KEYS_NV_VARIABLE_NAME,\r
+             &gEfiVendorKeysNvGuid,\r
+             &mVendorKeyState,\r
+             sizeof (UINT8),\r
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,\r
+             0,\r
+             0,\r
+             &Variable,\r
+             NULL\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FindVariable (EFI_VENDOR_KEYS_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  return UpdateVariable (\r
+           EFI_VENDOR_KEYS_VARIABLE_NAME,\r
+           &gEfiGlobalVariableGuid,\r
+           &mVendorKeyState,\r
+           sizeof (UINT8),\r
+           EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+           0,\r
+           0,\r
+           &Variable,\r
+           NULL\r
+           );\r
+}\r
+\r
+/**\r
+  Process variable with platform key for verification.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode, and datasize and data are external input.\r
+  This function will do basic validation, before parse the data.\r
+  This function will parse the authentication carefully to avoid security issues, like\r
+  buffer overflow, integer overflow.\r
+  This function will check attribute carefully to avoid authentication bypass.\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable\r
+  @param[in]  IsPk                        Indicate whether it is to process pk.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation.\r
+                                          check carried out by the firmware.\r
+  @return EFI_SUCCESS                     Variable passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithPk (\r
+  IN  CHAR16                    *VariableName,\r
+  IN  EFI_GUID                  *VendorGuid,\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  VARIABLE_POINTER_TRACK    *Variable,\r
+  IN  UINT32                    Attributes OPTIONAL,\r
+  IN  BOOLEAN                   IsPk\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  BOOLEAN                     Del;\r
+  UINT8                       *Payload;\r
+  UINTN                       PayloadSize;\r
+\r
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 || \r
+      (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
+    //\r
+    // PK, KEK and db/dbx should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
+    // authenticated variable.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Del = FALSE;\r
+  if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) {\r
+    Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
+    PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
+    if (PayloadSize == 0) {\r
+      Del = TRUE;\r
+    }\r
+\r
+    Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
     }\r
+\r
+    Status = UpdateVariable (\r
+               VariableName,\r
+               VendorGuid,\r
+               Payload,\r
+               PayloadSize,\r
+               Attributes,\r
+               0,\r
+               0,\r
+               Variable,\r
+               &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
+               );\r
+    if (EFI_ERROR(Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if ((mPlatformMode != SETUP_MODE) || IsPk) {\r
+      Status = VendorKeyIsModified ();\r
+    }\r
+  } else if (mPlatformMode == USER_MODE) {\r
+    //\r
+    // Verify against X509 Cert in PK database.\r
+    //\r
+    Status = VerifyTimeBasedPayload (\r
+               VariableName,\r
+               VendorGuid,\r
+               Data,\r
+               DataSize,\r
+               Variable,\r
+               Attributes,\r
+               AuthVarTypePk,\r
+               &Del\r
+               );\r
   } else {\r
-    Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);\r
     //\r
-    // If enroll PK in setup mode, need change to user mode.\r
+    // Verify against the certificate in data payload.\r
     //\r
-    if ((DataSize != 0) && IsPk) {\r
+    Status = VerifyTimeBasedPayload (\r
+               VariableName,\r
+               VendorGuid,\r
+               Data,\r
+               DataSize,\r
+               Variable,\r
+               Attributes,\r
+               AuthVarTypePayload,\r
+               &Del\r
+               );\r
+  }\r
+\r
+  if (!EFI_ERROR(Status) && IsPk) {\r
+    if (mPlatformMode == SETUP_MODE && !Del) {\r
+      //\r
+      // If enroll PK in setup mode, need change to user mode.\r
+      //\r
       Status = UpdatePlatformMode (USER_MODE);\r
+    } else if (mPlatformMode == USER_MODE && Del){\r
+      //\r
+      // If delete PK in user mode, need change to setup mode.\r
+      //\r
+      Status = UpdatePlatformMode (SETUP_MODE);\r
     }\r
   }\r
 \r
@@ -736,6 +1149,13 @@ ProcessVarWithPk (
 /**\r
   Process variable with key exchange key for verification.\r
 \r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode, and datasize and data are external input.\r
+  This function will do basic validation, before parse the data.\r
+  This function will parse the authentication carefully to avoid security issues, like\r
+  buffer overflow, integer overflow.\r
+  This function will check attribute carefully to avoid authentication bypass.\r
+\r
   @param[in]  VariableName                Name of Variable to be found.\r
   @param[in]  VendorGuid                  Variable vendor GUID.\r
   @param[in]  Data                        Data pointer.\r
@@ -745,8 +1165,8 @@ ProcessVarWithPk (
   @param[in]  Attributes                  Attribute value of the variable.\r
 \r
   @return EFI_INVALID_PARAMETER           Invalid parameter.\r
-  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
-                                          check carried out by the firmware. \r
+  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation\r
+                                          check carried out by the firmware.\r
   @return EFI_SUCCESS                     Variable pass validation successfully.\r
 \r
 **/\r
@@ -761,100 +1181,63 @@ ProcessVarWithKek (
   )\r
 {\r
   EFI_STATUS                      Status;\r
-  VARIABLE_POINTER_TRACK          KekVariable;\r
-  EFI_SIGNATURE_LIST              *KekList;\r
-  EFI_SIGNATURE_DATA              *KekItem;\r
-  UINT32                          KekCount;\r
-  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
-  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
-  BOOLEAN                         IsFound;\r
-  UINT32                          Index;\r
-  UINT32                          KekDataSize;\r
-\r
-  if (mPlatformMode == USER_MODE) {\r
-    if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
-      //\r
-      // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
-      //\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
+  UINT8                           *Payload;\r
+  UINTN                           PayloadSize;\r
 \r
-    CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
-    CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
-    if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
-      //\r
-      // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
-      //\r
-      return EFI_SECURITY_VIOLATION;\r
-    }\r
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||\r
+      (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
     //\r
-    // Get KEK database from variable.\r
+    // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
+    // authenticated variable.\r
     //\r
-    Status = FindVariable (\r
-               EFI_KEY_EXCHANGE_KEY_NAME, \r
-               &gEfiGlobalVariableGuid, \r
-               &KekVariable, \r
-               &mVariableModuleGlobal->VariableGlobal\r
-               );\r
-    ASSERT_EFI_ERROR (Status);\r
-\r
-    KekDataSize = KekVariable.CurrPtr->DataSize;\r
-    KekList     = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
+  Status = EFI_SUCCESS;\r
+  if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {\r
     //\r
-    // Enumerate all Kek items in this list to verify the variable certificate data.\r
-    // If anyone is authenticated successfully, it means the variable is correct!\r
+    // Time-based, verify against X509 Cert KEK.\r
     //\r
-    IsFound   = FALSE;\r
-    while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
-      if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
-        KekItem   = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
-        KekCount  = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
-        for (Index = 0; Index < KekCount; Index++) {\r
-          if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
-            IsFound = TRUE;\r
-            break;\r
-          }\r
-          KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
-        }\r
-      }\r
-      KekDataSize -= KekList->SignatureListSize;\r
-      KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
-    }\r
-    \r
-    if (!IsFound) {\r
-      return EFI_SECURITY_VIOLATION;\r
-    }\r
-\r
-    Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);\r
-    if (!EFI_ERROR (Status)) {\r
-      Status = UpdateVariable (\r
-                 VariableName, \r
-                 VendorGuid, \r
-                 (UINT8*)Data + AUTHINFO_SIZE, \r
-                 DataSize - AUTHINFO_SIZE, \r
-                 Attributes, \r
-                 0, \r
-                 CertData->MonotonicCount, \r
-                 Variable,\r
-                 NULL\r
-                 );\r
-    }\r
+    return VerifyTimeBasedPayload (\r
+             VariableName,\r
+             VendorGuid,\r
+             Data,\r
+             DataSize,\r
+             Variable,\r
+             Attributes,\r
+             AuthVarTypeKek,\r
+             NULL\r
+             );\r
   } else {\r
     //\r
-    // If in setup mode, no authentication needed.\r
+    // If in setup mode or custom secure boot mode, no authentication needed.\r
     //\r
+    Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
+    PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
+\r
+    Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
     Status = UpdateVariable (\r
-               VariableName, \r
-               VendorGuid, \r
-               Data, \r
-               DataSize, \r
-               Attributes, \r
-               0, \r
-               0, \r
+               VariableName,\r
+               VendorGuid,\r
+               Payload,\r
+               PayloadSize,\r
+               Attributes,\r
+               0,\r
+               0,\r
                Variable,\r
-               NULL\r
+               &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
                );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (mPlatformMode != SETUP_MODE) {\r
+      Status = VendorKeyIsModified ();\r
+    }\r
   }\r
 \r
   return Status;\r
@@ -863,6 +1246,13 @@ ProcessVarWithKek (
 /**\r
   Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
 \r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode, and datasize and data are external input.\r
+  This function will do basic validation, before parse the data.\r
+  This function will parse the authentication carefully to avoid security issues, like\r
+  buffer overflow, integer overflow.\r
+  This function will check attribute carefully to avoid authentication bypass.\r
+\r
   @param[in]  VariableName                Name of Variable to be found.\r
   @param[in]  VendorGuid                  Variable vendor GUID.\r
 \r
@@ -875,9 +1265,10 @@ ProcessVarWithKek (
   @return EFI_INVALID_PARAMETER           Invalid parameter.\r
   @return EFI_WRITE_PROTECTED             Variable is write-protected and needs authentication with\r
                                           EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+  @return EFI_OUT_OF_RESOURCES            The Database to save the public key is full.\r
   @return EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
-                                          set, but the AuthInfo does NOT pass the validation \r
-                                          check carried out by the firmware. \r
+                                          set, but the AuthInfo does NOT pass the validation\r
+                                          check carried out by the firmware.\r
   @return EFI_SUCCESS                     Variable is not write-protected or pass validation successfully.\r
 \r
 **/\r
@@ -899,20 +1290,53 @@ ProcessVariable (
   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
   UINT32                          KeyIndex;\r
   UINT64                          MonotonicCount;\r
+  VARIABLE_ENTRY_CONSISTENCY      VariableDataEntry;\r
 \r
-  KeyIndex    = 0;  \r
+  KeyIndex    = 0;\r
   CertData    = NULL;\r
   CertBlock   = NULL;\r
   PubKey      = NULL;\r
   IsDeletion  = FALSE;\r
 \r
+  if (NeedPhysicallyPresent(VariableName, VendorGuid) && !UserPhysicalPresent()) {\r
+    //\r
+    // This variable is protected, only physical present user could modify its value.\r
+    //\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+  \r
+  //\r
+  // A time-based authenticated variable and a count-based authenticated variable\r
+  // can't be updated by each other.\r
+  // \r
+  if (Variable->CurrPtr != NULL) {    \r
+    if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&\r
+        ((Variable->CurrPtr->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r
+      return EFI_SECURITY_VIOLATION;      \r
+    }\r
+    \r
+    if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) && \r
+        ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r
+      return EFI_SECURITY_VIOLATION;      \r
+    }\r
+  }\r
+    \r
   //\r
   // Process Time-based Authenticated variable.\r
   //\r
   if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-    return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL);\r
+    return VerifyTimeBasedPayload (\r
+             VariableName,\r
+             VendorGuid,\r
+             Data,\r
+             DataSize,\r
+             Variable,\r
+             Attributes,\r
+             AuthVarTypePriv,\r
+             NULL\r
+             );\r
   }\r
-  \r
+\r
   //\r
   // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
   //\r
@@ -934,9 +1358,9 @@ ProcessVariable (
       KeyIndex   = Variable->CurrPtr->PubKeyIndex;\r
       IsFirstTime = FALSE;\r
     }\r
-  } else if ((Variable->CurrPtr != NULL) &&\r
-           (Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0\r
-          ) {\r
+  } else if ((Variable->CurrPtr != NULL) && \r
+             ((Variable->CurrPtr->Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)\r
+            ) {\r
     //\r
     // If the variable is already write-protected, it always needs authentication before update.\r
     //\r
@@ -979,7 +1403,7 @@ ProcessVariable (
       //\r
       return EFI_SECURITY_VIOLATION;\r
     }\r
-  } \r
+  }\r
   //\r
   // Verify the certificate in Data payload.\r
   //\r
@@ -987,15 +1411,22 @@ ProcessVariable (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
-  \r
+\r
   //\r
   // Now, the signature has been verified!\r
   //\r
   if (IsFirstTime && !IsDeletion) {\r
+    VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;\r
+    VariableDataEntry.Guid         = VendorGuid;\r
+    VariableDataEntry.Name         = VariableName;\r
+\r
     //\r
     // Update public key database variable if need.\r
     //\r
-    KeyIndex = AddPubKeyInStore (PubKey);\r
+    KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);\r
+    if (KeyIndex == 0) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
   }\r
 \r
   //\r
@@ -1004,6 +1435,129 @@ ProcessVariable (
   return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);\r
 }\r
 \r
+/**\r
+  Merge two buffers which formatted as EFI_SIGNATURE_LIST. Only the new EFI_SIGNATURE_DATA\r
+  will be appended to the original EFI_SIGNATURE_LIST, duplicate EFI_SIGNATURE_DATA\r
+  will be ignored.\r
+\r
+  @param[in, out]  Data              Pointer to original EFI_SIGNATURE_LIST.\r
+  @param[in]       DataSize          Size of Data buffer.\r
+  @param[in]       FreeBufSize       Size of free data buffer \r
+  @param[in]       NewData           Pointer to new EFI_SIGNATURE_LIST to be appended.\r
+  @param[in]       NewDataSize       Size of NewData buffer.\r
+  @param[out]      MergedBufSize     Size of the merged buffer\r
+\r
+  @return EFI_BUFFER_TOO_SMALL if input Data buffer overflowed\r
+\r
+**/\r
+EFI_STATUS\r
+AppendSignatureList (\r
+  IN  OUT VOID            *Data,\r
+  IN  UINTN               DataSize,\r
+  IN  UINTN               FreeBufSize,\r
+  IN  VOID                *NewData,\r
+  IN  UINTN               NewDataSize,\r
+  OUT UINTN               *MergedBufSize\r
+  )\r
+{\r
+  EFI_SIGNATURE_LIST  *CertList;\r
+  EFI_SIGNATURE_DATA  *Cert;\r
+  UINTN               CertCount;\r
+  EFI_SIGNATURE_LIST  *NewCertList;\r
+  EFI_SIGNATURE_DATA  *NewCert;\r
+  UINTN               NewCertCount;\r
+  UINTN               Index;\r
+  UINTN               Index2;\r
+  UINTN               Size;\r
+  UINT8               *Tail;\r
+  UINTN               CopiedCount;\r
+  UINTN               SignatureListSize;\r
+  BOOLEAN             IsNewCert;\r
+\r
+  Tail = (UINT8 *) Data + DataSize;\r
+\r
+  NewCertList = (EFI_SIGNATURE_LIST *) NewData;\r
+  while ((NewDataSize > 0) && (NewDataSize >= NewCertList->SignatureListSize)) {\r
+    NewCert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
+    NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;\r
+\r
+    CopiedCount = 0;\r
+    for (Index = 0; Index < NewCertCount; Index++) {\r
+      IsNewCert = TRUE;\r
+\r
+      Size = DataSize;\r
+      CertList = (EFI_SIGNATURE_LIST *) Data;\r
+      while ((Size > 0) && (Size >= CertList->SignatureListSize)) {\r
+        if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&\r
+           (CertList->SignatureSize == NewCertList->SignatureSize)) {\r
+          Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+          CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+          for (Index2 = 0; Index2 < CertCount; Index2++) {\r
+            //\r
+            // Iterate each Signature Data in this Signature List.\r
+            //\r
+            if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {\r
+              IsNewCert = FALSE;\r
+              break;\r
+            }\r
+            Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+          }\r
+        }\r
+\r
+        if (!IsNewCert) {\r
+          break;\r
+        }\r
+        Size -= CertList->SignatureListSize;\r
+        CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+      }\r
+\r
+      if (IsNewCert) {\r
+        //\r
+        // New EFI_SIGNATURE_DATA, append it.\r
+        //\r
+        if (CopiedCount == 0) {\r
+          if (FreeBufSize < sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize) {\r
+            return EFI_BUFFER_TOO_SMALL;\r
+          }\r
+\r
+          //\r
+          // Copy EFI_SIGNATURE_LIST header for only once.\r
+          //\r
+\r
+          CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
+          Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;\r
+          FreeBufSize -= sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;\r
+        }\r
+\r
+        if (FreeBufSize < NewCertList->SignatureSize) {\r
+          return EFI_BUFFER_TOO_SMALL;\r
+        }\r
+        CopyMem (Tail, NewCert, NewCertList->SignatureSize);\r
+        Tail += NewCertList->SignatureSize;\r
+        FreeBufSize -= NewCertList->SignatureSize;\r
+        CopiedCount++;\r
+      }\r
+\r
+      NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);\r
+    }\r
+\r
+    //\r
+    // Update SignatureListSize in newly appended EFI_SIGNATURE_LIST.\r
+    //\r
+    if (CopiedCount != 0) {\r
+      SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);\r
+      CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);\r
+      CertList->SignatureListSize = (UINT32) SignatureListSize;\r
+    }\r
+\r
+    NewDataSize -= NewCertList->SignatureListSize;\r
+    NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);\r
+  }\r
+\r
+  *MergedBufSize = (Tail - (UINT8 *) Data);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Compare two EFI_TIME data.\r
 \r
@@ -1030,56 +1584,520 @@ CompareTimeStamp (
   } else if (FirstTime->Hour != SecondTime->Hour) {\r
     return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
   } else if (FirstTime->Minute != SecondTime->Minute) {\r
-    return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);\r
-  } \r
+    return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);\r
+  }\r
 \r
   return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
 }\r
 \r
 /**\r
-  Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
+  Find matching signer's certificates for common authenticated variable\r
+  by corresponding VariableName and VendorGuid from "certdb".\r
 \r
-  @param[in]  VariableName                Name of Variable to be found.\r
-  @param[in]  VendorGuid                  Variable vendor GUID.\r
-  @param[in]  Data                        Data pointer.\r
-  @param[in]  DataSize                    Size of Data found. If size is less than the\r
-                                          data, this value contains the required size.\r
-  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
-  @param[in]  Attributes                  Attribute value of the variable.\r
-  @param[in]  Pk                          Verify against PK or KEK database.\r
-  @param[out] VarDel                      Delete the variable or not.\r
+  The data format of "certdb":\r
+  //\r
+  //     UINT32 CertDbListSize;\r
+  // /// AUTH_CERT_DB_DATA Certs1[];\r
+  // /// AUTH_CERT_DB_DATA Certs2[];\r
+  // /// ...\r
+  // /// AUTH_CERT_DB_DATA Certsn[];\r
+  //\r
 \r
-  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
-  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
-                                          check carried out by the firmware. \r
-  @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack\r
-                                          of resources.\r
-  @retval EFI_SUCCESS                     Variable pass validation successfully.\r
+  @param[in]  VariableName   Name of authenticated Variable.\r
+  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.\r
+  @param[in]  Data           Pointer to variable "certdb".\r
+  @param[in]  DataSize       Size of variable "certdb".\r
+  @param[out] CertOffset     Offset of matching CertData, from starting of Data.\r
+  @param[out] CertDataSize   Length of CertData in bytes.\r
+  @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from\r
+                             starting of Data.\r
+  @param[out] CertNodeSize   Length of AUTH_CERT_DB_DATA in bytes.\r
+\r
+  @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+  @retval  EFI_NOT_FOUND         Fail to find matching certs.\r
+  @retval  EFI_SUCCESS           Find matching certs and output parameters.\r
 \r
 **/\r
 EFI_STATUS\r
-VerifyTimeBasedPayload (\r
-  IN     CHAR16                             *VariableName,\r
-  IN     EFI_GUID                           *VendorGuid,\r
-  IN     VOID                               *Data,\r
-  IN     UINTN                              DataSize,\r
-  IN     VARIABLE_POINTER_TRACK             *Variable,\r
-  IN     UINT32                             Attributes,\r
-  IN     BOOLEAN                            Pk,\r
-  OUT    BOOLEAN                            *VarDel\r
+FindCertsFromDb (\r
+  IN     CHAR16           *VariableName,\r
+  IN     EFI_GUID         *VendorGuid,\r
+  IN     UINT8            *Data,\r
+  IN     UINTN            DataSize,\r
+  OUT    UINT32           *CertOffset,    OPTIONAL\r
+  OUT    UINT32           *CertDataSize,  OPTIONAL\r
+  OUT    UINT32           *CertNodeOffset,OPTIONAL\r
+  OUT    UINT32           *CertNodeSize   OPTIONAL\r
   )\r
 {\r
-  UINT8                            *RootCert;\r
-  UINT8                            *SigData;\r
-  UINT8                            *PayLoadPtr;\r
-  UINTN                            RootCertSize;\r
-  UINTN                            Index;\r
-  UINTN                            CertCount;  \r
-  UINTN                            PayLoadSize;  \r
-  UINT32                           Attr;\r
-  UINT32                           SigDataSize;\r
-  UINT32                           KekDataSize;\r
-  BOOLEAN                          Result;\r
+  UINT32                  Offset;\r
+  AUTH_CERT_DB_DATA       *Ptr;\r
+  UINT32                  CertSize;\r
+  UINT32                  NameSize;\r
+  UINT32                  NodeSize;\r
+  UINT32                  CertDbListSize;\r
+\r
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether DataSize matches recorded CertDbListSize.\r
+  //\r
+  if (DataSize < sizeof (UINT32)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);\r
+\r
+  if (CertDbListSize != (UINT32) DataSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Offset = sizeof (UINT32);\r
+\r
+  //\r
+  // Get corresponding certificates by VendorGuid and VariableName.\r
+  //\r
+  while (Offset < (UINT32) DataSize) {\r
+    Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);\r
+    //\r
+    // Check whether VendorGuid matches.\r
+    //\r
+    if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {\r
+      NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r
+      NameSize = ReadUnaligned32 (&Ptr->NameSize);\r
+      CertSize = ReadUnaligned32 (&Ptr->CertDataSize);\r
+\r
+      if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +\r
+          sizeof (CHAR16) * NameSize) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+\r
+      Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;\r
+      //\r
+      // Check whether VariableName matches.\r
+      //\r
+      if ((NameSize == StrLen (VariableName)) && \r
+          (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {\r
+        Offset = Offset + NameSize * sizeof (CHAR16);\r
+\r
+        if (CertOffset != NULL) {\r
+          *CertOffset = Offset;\r
+        }\r
+\r
+        if (CertDataSize != NULL) {\r
+          *CertDataSize = CertSize;        \r
+        }\r
+\r
+        if (CertNodeOffset != NULL) {\r
+          *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);\r
+        }\r
+\r
+        if (CertNodeSize != NULL) {\r
+          *CertNodeSize = NodeSize;\r
+        }\r
+\r
+        return EFI_SUCCESS;\r
+      } else {\r
+        Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;\r
+      }\r
+    } else {\r
+      NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);\r
+      Offset   = Offset + NodeSize;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;  \r
+}\r
+\r
+/**\r
+  Retrieve signer's certificates for common authenticated variable\r
+  by corresponding VariableName and VendorGuid from "certdb".\r
+\r
+  @param[in]  VariableName   Name of authenticated Variable.\r
+  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.\r
+  @param[out] CertData       Pointer to signer's certificates.\r
+  @param[out] CertDataSize   Length of CertData in bytes.\r
+\r
+  @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+  @retval  EFI_NOT_FOUND         Fail to find "certdb" or matching certs.\r
+  @retval  EFI_SUCCESS           Get signer's certificates successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetCertsFromDb (\r
+  IN     CHAR16           *VariableName,\r
+  IN     EFI_GUID         *VendorGuid,\r
+  OUT    UINT8            **CertData,\r
+  OUT    UINT32           *CertDataSize\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  CertDbVariable;\r
+  EFI_STATUS              Status;\r
+  UINT8                   *Data;\r
+  UINTN                   DataSize;\r
+  UINT32                  CertOffset;\r
+\r
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Get variable "certdb".\r
+  //\r
+  Status = FindVariable (\r
+             EFI_CERT_DB_NAME,\r
+             &gEfiCertDbGuid,\r
+             &CertDbVariable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
+             );      \r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DataSize  = DataSizeOfVariable (CertDbVariable.CurrPtr);\r
+  Data      = GetVariableDataPtr (CertDbVariable.CurrPtr);\r
+  if ((DataSize == 0) || (Data == NULL)) {\r
+    ASSERT (FALSE);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Status = FindCertsFromDb (\r
+             VariableName,\r
+             VendorGuid,\r
+             Data,\r
+             DataSize,\r
+             &CertOffset,\r
+             CertDataSize,\r
+             NULL,\r
+             NULL\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *CertData = Data + CertOffset;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Delete matching signer's certificates when deleting common authenticated\r
+  variable by corresponding VariableName and VendorGuid from "certdb".\r
+\r
+  @param[in]  VariableName   Name of authenticated Variable.\r
+  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.\r
+\r
+  @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+  @retval  EFI_NOT_FOUND         Fail to find "certdb" or matching certs.\r
+  @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.\r
+  @retval  EFI_SUCCESS           The operation is completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+DeleteCertsFromDb (\r
+  IN     CHAR16           *VariableName,\r
+  IN     EFI_GUID         *VendorGuid\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  CertDbVariable;\r
+  EFI_STATUS              Status;\r
+  UINT8                   *Data;\r
+  UINTN                   DataSize;\r
+  UINT32                  VarAttr;\r
+  UINT32                  CertNodeOffset;\r
+  UINT32                  CertNodeSize;\r
+  UINT8                   *NewCertDb;\r
+  UINT32                  NewCertDbSize;\r
+\r
+  if ((VariableName == NULL) || (VendorGuid == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Get variable "certdb".\r
+  //\r
+  Status = FindVariable (\r
+             EFI_CERT_DB_NAME,\r
+             &gEfiCertDbGuid,\r
+             &CertDbVariable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
+             );      \r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DataSize  = DataSizeOfVariable (CertDbVariable.CurrPtr);\r
+  Data      = GetVariableDataPtr (CertDbVariable.CurrPtr);\r
+  if ((DataSize == 0) || (Data == NULL)) {\r
+    ASSERT (FALSE);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (DataSize == sizeof (UINT32)) {\r
+    //\r
+    // There is no certs in certdb.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Get corresponding cert node from certdb.\r
+  //\r
+  Status = FindCertsFromDb (\r
+             VariableName,\r
+             VendorGuid,\r
+             Data,\r
+             DataSize,\r
+             NULL,\r
+             NULL,\r
+             &CertNodeOffset,\r
+             &CertNodeSize\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (DataSize < (CertNodeOffset + CertNodeSize)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Construct new data content of variable "certdb".\r
+  //\r
+  NewCertDbSize = (UINT32) DataSize - CertNodeSize;\r
+  NewCertDb     = (UINT8*) mCertDbStore;\r
+\r
+  //\r
+  // Copy the DB entries before deleting node.\r
+  //\r
+  CopyMem (NewCertDb, Data, CertNodeOffset);\r
+  //\r
+  // Update CertDbListSize.\r
+  //\r
+  CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r
+  //\r
+  // Copy the DB entries after deleting node.\r
+  //\r
+  if (DataSize > (CertNodeOffset + CertNodeSize)) {\r
+    CopyMem (\r
+      NewCertDb + CertNodeOffset,\r
+      Data + CertNodeOffset + CertNodeSize,\r
+      DataSize - CertNodeOffset - CertNodeSize\r
+      );\r
+  }\r
+\r
+  //\r
+  // Set "certdb".\r
+  // \r
+  VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;  \r
+  Status   = UpdateVariable (\r
+               EFI_CERT_DB_NAME,\r
+               &gEfiCertDbGuid,\r
+               NewCertDb,\r
+               NewCertDbSize,\r
+               VarAttr,\r
+               0,\r
+               0,\r
+               &CertDbVariable,\r
+               NULL\r
+               );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Insert signer's certificates for common authenticated variable with VariableName\r
+  and VendorGuid in AUTH_CERT_DB_DATA to "certdb".\r
+\r
+  @param[in]  VariableName   Name of authenticated Variable.\r
+  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.\r
+  @param[in]  CertData       Pointer to signer's certificates.\r
+  @param[in]  CertDataSize   Length of CertData in bytes.\r
+\r
+  @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.\r
+  @retval  EFI_ACCESS_DENIED     An AUTH_CERT_DB_DATA entry with same VariableName\r
+                                 and VendorGuid already exists.\r
+  @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.\r
+  @retval  EFI_SUCCESS           Insert an AUTH_CERT_DB_DATA entry to "certdb"\r
+\r
+**/\r
+EFI_STATUS\r
+InsertCertsToDb (\r
+  IN     CHAR16           *VariableName,\r
+  IN     EFI_GUID         *VendorGuid,\r
+  IN     UINT8            *CertData,\r
+  IN     UINTN            CertDataSize\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  CertDbVariable;\r
+  EFI_STATUS              Status;\r
+  UINT8                   *Data;\r
+  UINTN                   DataSize;\r
+  UINT32                  VarAttr;\r
+  UINT8                   *NewCertDb;\r
+  UINT32                  NewCertDbSize;\r
+  UINT32                  CertNodeSize;\r
+  UINT32                  NameSize;\r
+  AUTH_CERT_DB_DATA       *Ptr;\r
+\r
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Get variable "certdb".\r
+  //\r
+  Status = FindVariable (\r
+             EFI_CERT_DB_NAME,\r
+             &gEfiCertDbGuid,\r
+             &CertDbVariable,\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             FALSE\r
+             );      \r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  DataSize  = DataSizeOfVariable (CertDbVariable.CurrPtr);\r
+  Data      = GetVariableDataPtr (CertDbVariable.CurrPtr);\r
+  if ((DataSize == 0) || (Data == NULL)) {\r
+    ASSERT (FALSE);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Find whether matching cert node already exists in "certdb".\r
+  // If yes return error.\r
+  //\r
+  Status = FindCertsFromDb (\r
+             VariableName,\r
+             VendorGuid,\r
+             Data,\r
+             DataSize,\r
+             NULL,\r
+             NULL,\r
+             NULL,\r
+             NULL\r
+             );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    ASSERT (FALSE);\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Construct new data content of variable "certdb".\r
+  //\r
+  NameSize      = (UINT32) StrLen (VariableName);\r
+  CertNodeSize  = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16); \r
+  NewCertDbSize = (UINT32) DataSize + CertNodeSize;\r
+  if (NewCertDbSize > MAX_CERTDB_SIZE) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  NewCertDb     = (UINT8*) mCertDbStore;\r
+\r
+  //\r
+  // Copy the DB entries before deleting node.\r
+  //\r
+  CopyMem (NewCertDb, Data, DataSize);\r
+  //\r
+  // Update CertDbListSize.\r
+  //\r
+  CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));\r
+  //\r
+  // Construct new cert node.\r
+  //\r
+  Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);\r
+  CopyGuid (&Ptr->VendorGuid, VendorGuid);\r
+  CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));\r
+  CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));\r
+  CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));\r
+  \r
+  CopyMem (\r
+    (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),\r
+    VariableName,\r
+    NameSize * sizeof (CHAR16)\r
+    );\r
+\r
+  CopyMem (\r
+    (UINT8 *) Ptr +  sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),\r
+    CertData,\r
+    CertDataSize\r
+    );\r
+  \r
+  //\r
+  // Set "certdb".\r
+  // \r
+  VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;  \r
+  Status   = UpdateVariable (\r
+               EFI_CERT_DB_NAME,\r
+               &gEfiCertDbGuid,\r
+               NewCertDb,\r
+               NewCertDbSize,\r
+               VarAttr,\r
+               0,\r
+               0,\r
+               &CertDbVariable,\r
+               NULL\r
+               );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
+\r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode, and datasize and data are external input.\r
+  This function will do basic validation, before parse the data.\r
+  This function will parse the authentication carefully to avoid security issues, like\r
+  buffer overflow, integer overflow.\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+  @param[in]  AuthVarType                 Verify against PK, KEK database, private database or certificate in data payload.\r
+  @param[out] VarDel                      Delete the variable or not.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation\r
+                                          check carried out by the firmware.\r
+  @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack\r
+                                          of resources.\r
+  @retval EFI_SUCCESS                     Variable pass validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+VerifyTimeBasedPayload (\r
+  IN     CHAR16                             *VariableName,\r
+  IN     EFI_GUID                           *VendorGuid,\r
+  IN     VOID                               *Data,\r
+  IN     UINTN                              DataSize,\r
+  IN     VARIABLE_POINTER_TRACK             *Variable,\r
+  IN     UINT32                             Attributes,\r
+  IN     AUTHVAR_TYPE                       AuthVarType,\r
+  OUT    BOOLEAN                            *VarDel\r
+  )\r
+{\r
+  UINT8                            *RootCert;\r
+  UINT8                            *SigData;\r
+  UINT8                            *PayloadPtr;\r
+  UINTN                            RootCertSize;\r
+  UINTN                            Index;\r
+  UINTN                            CertCount;\r
+  UINTN                            PayloadSize;\r
+  UINT32                           Attr;\r
+  UINT32                           SigDataSize;\r
+  UINT32                           KekDataSize;\r
   BOOLEAN                          VerifyStatus;\r
   EFI_STATUS                       Status;\r
   EFI_SIGNATURE_LIST               *CertList;\r
@@ -1089,24 +2107,44 @@ VerifyTimeBasedPayload (
   UINT8                            *NewData;\r
   UINTN                            NewDataSize;\r
   VARIABLE_POINTER_TRACK           PkVariable;\r
+  UINT8                            *Buffer;\r
+  UINTN                            Length;\r
+  UINT8                            *SignerCerts;\r
+  UINT8                            *WrapSigData;\r
+  UINTN                            CertStackSize;\r
+  UINT8                            *CertsInCertDb;\r
+  UINT32                           CertsSizeinDb;\r
 \r
-\r
-  Result                 = FALSE;\r
   VerifyStatus           = FALSE;\r
   CertData               = NULL;\r
   NewData                = NULL;\r
   Attr                   = Attributes;\r
+  WrapSigData            = NULL;\r
+  SignerCerts            = NULL;\r
+  RootCert               = NULL;\r
 \r
   //\r
-  // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is \r
+  // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is\r
   // set, then the Data buffer shall begin with an instance of a complete (and serialized)\r
-  // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new \r
-  // variable value and DataSize shall reflect the combined size of the descriptor and the new \r
-  // variable value. The authentication descriptor is not part of the variable data and is not \r
+  // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new\r
+  // variable value and DataSize shall reflect the combined size of the descriptor and the new\r
+  // variable value. The authentication descriptor is not part of the variable data and is not\r
   // returned by subsequent calls to GetVariable().\r
   //\r
   CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
-  \r
+\r
+  //\r
+  // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the\r
+  // TimeStamp value are set to zero.\r
+  //\r
+  if ((CertData->TimeStamp.Pad1 != 0) ||\r
+      (CertData->TimeStamp.Nanosecond != 0) ||\r
+      (CertData->TimeStamp.TimeZone != 0) ||\r
+      (CertData->TimeStamp.Daylight != 0) ||\r
+      (CertData->TimeStamp.Pad2 != 0)) {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+\r
   if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
     if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
       //\r
@@ -1121,95 +2159,91 @@ VerifyTimeBasedPayload (
   // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.\r
   //\r
   if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
-      !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)\r
-        ) {\r
+      !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {\r
     //\r
     // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
     //\r
     return EFI_SECURITY_VIOLATION;\r
   }\r
\r
+\r
   //\r
   // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
   // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.\r
   //\r
-  SigData = (UINT8*) ((UINTN)Data + OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r
+  SigData = CertData->AuthInfo.CertData;\r
+  SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r
 \r
-  //\r
-  // Sanity check to avoid corrupted certificate input.\r
-  //\r
-  if (CertData->AuthInfo.Hdr.dwLength < (UINT32)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData))) {\r
-    return EFI_SECURITY_VIOLATION;\r
-  }\r
-\r
-\r
-\r
-  SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r
-  \r
   //\r
   // Find out the new data payload which follows Pkcs7 SignedData directly.\r
   //\r
-  PayLoadPtr = (UINT8*) ((UINTN) SigData + (UINTN) SigDataSize);\r
-\r
-  //\r
-  // Sanity check to avoid corrupted certificate input.\r
-  //\r
-  if (DataSize < (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)+ (UINTN) SigDataSize)) {\r
-    return EFI_SECURITY_VIOLATION;\r
-  }\r
-  \r
-  PayLoadSize = DataSize - OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) - OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData) - (UINTN) SigDataSize;\r
-\r
+  PayloadPtr = SigData + SigDataSize;\r
+  PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;\r
 \r
   //\r
   // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
   //\r
-  NewDataSize = PayLoadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
-                sizeof (EFI_GUID) + StrSize (VariableName);\r
-  NewData     = (UINT8 *) AllocateZeroPool (NewDataSize);\r
+  NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
+                sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);\r
+  NewData = mSerializationRuntimeBuffer;\r
 \r
-  if (NewData == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+  Buffer = NewData;\r
+  Length = StrLen (VariableName) * sizeof (CHAR16);\r
+  CopyMem (Buffer, VariableName, Length);\r
+  Buffer += Length;\r
 \r
-  CopyMem (NewData, VariableName, StrSize (VariableName));\r
+  Length = sizeof (EFI_GUID);\r
+  CopyMem (Buffer, VendorGuid, Length);\r
+  Buffer += Length;\r
 \r
-  CopyMem (NewData + StrSize (VariableName), VendorGuid, sizeof (EFI_GUID));\r
+  Length = sizeof (UINT32);\r
+  CopyMem (Buffer, &Attr, Length);\r
+  Buffer += Length;\r
 \r
-  CopyMem (\r
-    NewData + StrSize (VariableName) + sizeof (EFI_GUID),\r
-    &Attr,\r
-    sizeof (UINT32)\r
-    );\r
+  Length = sizeof (EFI_TIME);\r
+  CopyMem (Buffer, &CertData->TimeStamp, Length);\r
+  Buffer += Length;\r
 \r
-  CopyMem (\r
-    NewData + StrSize (VariableName) + sizeof (EFI_GUID) + sizeof (UINT32),\r
-    &CertData->TimeStamp,\r
-    sizeof (EFI_TIME)\r
-    );\r
-\r
-  CopyMem (NewData + (NewDataSize - PayLoadSize), PayLoadPtr, PayLoadSize);\r
+  CopyMem (Buffer, PayloadPtr, PayloadSize);\r
 \r
+  if (AuthVarType == AuthVarTypePk) {\r
+    //\r
+    // Verify that the signature has been made with the current Platform Key (no chaining for PK).\r
+    // First, get signer's certificates from SignedData.\r
+    //\r
+    VerifyStatus = Pkcs7GetSigners (\r
+                     SigData,\r
+                     SigDataSize,\r
+                     &SignerCerts,\r
+                     &CertStackSize,\r
+                     &RootCert,\r
+                     &RootCertSize\r
+                     );\r
+    if (!VerifyStatus) {\r
+      goto Exit;\r
+    }\r
 \r
-  if (Pk) {\r
     //\r
-    // Get platform key from variable.\r
+    // Second, get the current platform key from variable. Check whether it's identical with signer's certificates\r
+    // in SignedData. If not, return error immediately.\r
     //\r
     Status = FindVariable (\r
-               EFI_PLATFORM_KEY_NAME, \r
-               &gEfiGlobalVariableGuid, \r
-               &PkVariable, \r
-               &mVariableModuleGlobal->VariableGlobal\r
+               EFI_PLATFORM_KEY_NAME,\r
+               &gEfiGlobalVariableGuid,\r
+               &PkVariable,\r
+               &mVariableModuleGlobal->VariableGlobal,\r
+               FALSE\r
                );\r
     if (EFI_ERROR (Status)) {\r
-      return Status;\r
+      VerifyStatus = FALSE;\r
+      goto Exit;\r
     }\r
-\r
     CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
     Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
-    RootCert      = Cert->SignatureData;\r
-    RootCertSize  = CertList->SignatureSize;\r
-\r
+    if ((RootCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||\r
+        (CompareMem (Cert->SignatureData, RootCert, RootCertSize) != 0)) {\r
+      VerifyStatus = FALSE;\r
+      goto Exit;\r
+    }\r
 \r
     //\r
     // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
@@ -1223,16 +2257,17 @@ VerifyTimeBasedPayload (
                      NewDataSize\r
                      );\r
 \r
-  } else {\r
-  \r
+  } else if (AuthVarType == AuthVarTypeKek) {\r
+\r
     //\r
     // Get KEK database from variable.\r
     //\r
     Status = FindVariable (\r
-               EFI_KEY_EXCHANGE_KEY_NAME, \r
-               &gEfiGlobalVariableGuid, \r
-               &KekVariable, \r
-               &mVariableModuleGlobal->VariableGlobal\r
+               EFI_KEY_EXCHANGE_KEY_NAME,\r
+               &gEfiGlobalVariableGuid,\r
+               &KekVariable,\r
+               &mVariableModuleGlobal->VariableGlobal,\r
+               FALSE\r
                );\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
@@ -1240,7 +2275,7 @@ VerifyTimeBasedPayload (
 \r
     //\r
     // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r
-    // \r
+    //\r
     KekDataSize      = KekVariable.CurrPtr->DataSize;\r
     CertList         = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
     while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
@@ -1252,8 +2287,8 @@ VerifyTimeBasedPayload (
           // Iterate each Signature Data Node within this CertList for a verify\r
           //\r
           RootCert      = Cert->SignatureData;\r
-          RootCertSize  = CertList->SignatureSize;\r
-       \r
+          RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
+\r
           //\r
           // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
           //\r
@@ -1274,32 +2309,127 @@ VerifyTimeBasedPayload (
       KekDataSize -= CertList->SignatureListSize;\r
       CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
     }\r
+  } else if (AuthVarType == AuthVarTypePriv) {\r
+\r
+    //\r
+    // Process common authenticated variable except PK/KEK/DB/DBX.\r
+    // Get signer's certificates from SignedData.\r
+    //\r
+    VerifyStatus = Pkcs7GetSigners (\r
+                     SigData,\r
+                     SigDataSize,\r
+                     &SignerCerts,\r
+                     &CertStackSize,\r
+                     &RootCert,\r
+                     &RootCertSize\r
+                     );\r
+    if (!VerifyStatus) {\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // Get previously stored signer's certificates from certdb for existing\r
+    // variable. Check whether they are identical with signer's certificates\r
+    // in SignedData. If not, return error immediately.\r
+    //\r
+    if ((Variable->CurrPtr != NULL)) {\r
+      VerifyStatus = FALSE;\r
+\r
+      Status = GetCertsFromDb (VariableName, VendorGuid, &CertsInCertDb, &CertsSizeinDb);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Exit;\r
+      }\r
+    \r
+      if ((CertStackSize != CertsSizeinDb) ||\r
+          (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {\r
+        goto Exit;\r
+      }\r
+    }\r
+\r
+    VerifyStatus = Pkcs7Verify (\r
+                     SigData,\r
+                     SigDataSize,\r
+                     RootCert,\r
+                     RootCertSize,\r
+                     NewData,\r
+                     NewDataSize\r
+                     );\r
+    if (!VerifyStatus) {\r
+      goto Exit;\r
+    }\r
+\r
+    //\r
+    // Delete signer's certificates when delete the common authenticated variable.\r
+    //\r
+    if ((PayloadSize == 0) && (Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
+      Status = DeleteCertsFromDb (VariableName, VendorGuid);\r
+      if (EFI_ERROR (Status)) {\r
+        VerifyStatus = FALSE;\r
+        goto Exit;\r
+      }\r
+    } else if (Variable->CurrPtr == NULL && PayloadSize != 0) {\r
+      //\r
+      // Insert signer's certificates when adding a new common authenticated variable.\r
+      //\r
+      Status = InsertCertsToDb (VariableName, VendorGuid, SignerCerts, CertStackSize);\r
+      if (EFI_ERROR (Status)) {\r
+        VerifyStatus = FALSE;\r
+        goto Exit;\r
+      }\r
+    }\r
+  } else if (AuthVarType == AuthVarTypePayload) {\r
+    CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;\r
+    Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+    RootCert      = Cert->SignatureData;\r
+    RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
+    \r
+    // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
+    //\r
+    VerifyStatus = Pkcs7Verify (\r
+                     SigData,\r
+                     SigDataSize,\r
+                     RootCert,\r
+                     RootCertSize,\r
+                     NewData,\r
+                     NewDataSize\r
+                     );\r
+  } else {\r
+    return EFI_SECURITY_VIOLATION;\r
   }\r
 \r
 Exit:\r
 \r
-  FreePool (NewData);\r
+  if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {\r
+    Pkcs7FreeSigners (RootCert);\r
+    Pkcs7FreeSigners (SignerCerts);\r
+  }\r
 \r
   if (!VerifyStatus) {\r
     return EFI_SECURITY_VIOLATION;\r
   }\r
 \r
-  if ((PayLoadSize == 0) && (VarDel != NULL)) {\r
+  Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((PayloadSize == 0) && (VarDel != NULL)) {\r
     *VarDel = TRUE;\r
   }\r
-  \r
+\r
   //\r
   // Final step: Update/Append Variable if it pass Pkcs7Verify\r
   //\r
-  return   UpdateVariable (\r
-             VariableName, \r
-             VendorGuid, \r
-             PayLoadPtr, \r
-             PayLoadSize, \r
-             Attributes, \r
-             0, \r
-             0, \r
-             Variable,\r
-             &CertData->TimeStamp\r
-             );\r
+  return UpdateVariable (\r
+           VariableName,\r
+           VendorGuid,\r
+           PayloadPtr,\r
+           PayloadSize,\r
+           Attributes,\r
+           0,\r
+           0,\r
+           Variable,\r
+           &CertData->TimeStamp\r
+           );\r
 }\r
+\r