]> git.proxmox.com Git - mirror_edk2.git/commitdiff
SecurityPkg: Implement AuthVariableLib library instance
authorStar Zeng <star.zeng@intel.com>
Wed, 1 Jul 2015 03:04:59 +0000 (03:04 +0000)
committerlzeng14 <lzeng14@Edk2>
Wed, 1 Jul 2015 03:04:59 +0000 (03:04 +0000)
What to do:
1. Implement AuthVariableLib library instance.
2. Temporarily add VARIABLE_ENTRY_CONSISTENCY and
variable attribute combinations definitions to
AuthenticatedVariableFormat.h for git bisect.

Why to do:
1. Share code.
Separate auth variable service from Auth Variable driver in
SecurityPkg to AuthVariableLib. Then the AuthVariableLib could benefit
and be used by different implementation of Auth Variable drivers.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17758 6f19259b-4bc3-4df7-8a09-765794883524

SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h
SecurityPkg/Library/AuthVariableLib/AuthService.c [new file with mode: 0644]
SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h [new file with mode: 0644]
SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c [new file with mode: 0644]
SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf [new file with mode: 0644]
SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni [new file with mode: 0644]
SecurityPkg/SecurityPkg.dsc
SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h

index 66947e176536f75836594282975facfc95e5b275..c7cd34a943906c048855734f6d8ae304ab7b71c0 100644 (file)
@@ -147,6 +147,17 @@ typedef struct {
 #define VAR_ADDED                     0x3f  ///< Variable has been completely added.\r
 \r
 ///\r
+/// Variable Attribute combinations.\r
+///\r
+#define VARIABLE_ATTRIBUTE_NV_BS        (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)\r
+#define VARIABLE_ATTRIBUTE_BS_RT        (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)\r
+#define VARIABLE_ATTRIBUTE_AT_AW        (EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)\r
+#define VARIABLE_ATTRIBUTE_NV_BS_RT     (VARIABLE_ATTRIBUTE_BS_RT | EFI_VARIABLE_NON_VOLATILE)\r
+#define VARIABLE_ATTRIBUTE_NV_BS_RT_HR  (VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_HARDWARE_ERROR_RECORD)\r
+#define VARIABLE_ATTRIBUTE_NV_BS_RT_AT  (VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)\r
+#define VARIABLE_ATTRIBUTE_NV_BS_RT_AW  (VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)\r
+#define VARIABLE_ATTRIBUTE_NV_BS_RT_HR_AT_AW    (VARIABLE_ATTRIBUTE_NV_BS_RT_HR | VARIABLE_ATTRIBUTE_AT_AW)\r
+\r
 /// Single Variable Data Header Structure.\r
 ///\r
 typedef struct {\r
@@ -189,6 +200,12 @@ typedef struct {
   EFI_GUID    VendorGuid;\r
 } VARIABLE_HEADER;\r
 \r
+typedef struct {\r
+  EFI_GUID    *Guid;\r
+  CHAR16      *Name;\r
+  UINTN       VariableSize;\r
+} VARIABLE_ENTRY_CONSISTENCY;\r
+\r
 #pragma pack()\r
 \r
 typedef struct _VARIABLE_INFO_ENTRY  VARIABLE_INFO_ENTRY;\r
diff --git a/SecurityPkg/Library/AuthVariableLib/AuthService.c b/SecurityPkg/Library/AuthVariableLib/AuthService.c
new file mode 100644 (file)
index 0000000..b3e8933
--- /dev/null
@@ -0,0 +1,2432 @@
+/** @file\r
+  Implement authentication services for the authenticated variables.\r
+\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
+     The whole SMM authentication variable design relies on the integrity of flash part and SMM.\r
+  which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory\r
+  may not be modified without authorization. If platform fails to protect these resources,\r
+  the authentication service provided in this driver will be broken, and the behavior is undefined.\r
+\r
+  ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do\r
+  variable authentication.\r
+\r
+  VerifyTimeBasedPayloadAndUpdate() 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 - 2015, 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
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "AuthServiceInternal.h"\r
+\r
+//\r
+// Public Exponent of RSA Key.\r
+//\r
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
+\r
+//\r
+// Requirement for different signature type which have been defined in UEFI spec.\r
+// These data are used to perform SignatureList format check while setting PK/KEK variable.\r
+//\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
+  {EFI_CERT_X509_SHA256_GUID,     0,               48           },\r
+  {EFI_CERT_X509_SHA384_GUID,     0,               64           },\r
+  {EFI_CERT_X509_SHA512_GUID,     0,               80           }\r
+};\r
+\r
+/**\r
+  Finds variable in storage blocks of volatile and non-volatile storage areas.\r
+\r
+  This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
+  If VariableName is an empty string, then we just return the first\r
+  qualified variable without comparing VariableName and VendorGuid.\r
+\r
+  @param[in]  VariableName          Name of the variable to be found.\r
+  @param[in]  VendorGuid            Variable vendor GUID to be found.\r
+  @param[out] Data                  Pointer to data address.\r
+  @param[out] DataSize              Pointer to data size.\r
+\r
+  @retval EFI_INVALID_PARAMETER     If VariableName is not an empty string,\r
+                                    while VendorGuid is NULL.\r
+  @retval EFI_SUCCESS               Variable successfully found.\r
+  @retval EFI_NOT_FOUND             Variable not found\r
+\r
+**/\r
+EFI_STATUS\r
+AuthServiceInternalFindVariable (\r
+  IN  CHAR16            *VariableName,\r
+  IN  EFI_GUID          *VendorGuid,\r
+  OUT VOID              **Data,\r
+  OUT UINTN             *DataSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  AUTH_VARIABLE_INFO    AuthVariableInfo;\r
+\r
+  ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
+  Status = mAuthVarLibContextIn->FindVariable (\r
+           VariableName,\r
+           VendorGuid,\r
+           &AuthVariableInfo\r
+           );\r
+  *Data = AuthVariableInfo.Data;\r
+  *DataSize = AuthVariableInfo.DataSize;\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Update the variable region with Variable information.\r
+\r
+  @param[in] VariableName           Name of variable.\r
+  @param[in] VendorGuid             Guid of variable.\r
+  @param[in] Data                   Data pointer.\r
+  @param[in] DataSize               Size of Data.\r
+  @param[in] Attributes             Attribute value of the variable.\r
+\r
+  @retval EFI_SUCCESS               The update operation is success.\r
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.\r
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AuthServiceInternalUpdateVariable (\r
+  IN CHAR16             *VariableName,\r
+  IN EFI_GUID           *VendorGuid,\r
+  IN VOID               *Data,\r
+  IN UINTN              DataSize,\r
+  IN UINT32             Attributes\r
+  )\r
+{\r
+  AUTH_VARIABLE_INFO    AuthVariableInfo;\r
+\r
+  ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
+  AuthVariableInfo.VariableName = VariableName;\r
+  AuthVariableInfo.VendorGuid = VendorGuid;\r
+  AuthVariableInfo.Data = Data;\r
+  AuthVariableInfo.DataSize = DataSize;\r
+  AuthVariableInfo.Attributes = Attributes;\r
+\r
+  return mAuthVarLibContextIn->UpdateVariable (\r
+           &AuthVariableInfo\r
+           );\r
+}\r
+\r
+/**\r
+  Update the variable region with Variable information.\r
+\r
+  @param[in] VariableName           Name of variable.\r
+  @param[in] VendorGuid             Guid of variable.\r
+  @param[in] Data                   Data pointer.\r
+  @param[in] DataSize               Size of Data.\r
+  @param[in] Attributes             Attribute value of the variable.\r
+  @param[in] KeyIndex               Index of associated public key.\r
+  @param[in] MonotonicCount         Value of associated monotonic count.\r
+\r
+  @retval EFI_SUCCESS               The update operation is success.\r
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.\r
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AuthServiceInternalUpdateVariableWithMonotonicCount (\r
+  IN CHAR16             *VariableName,\r
+  IN EFI_GUID           *VendorGuid,\r
+  IN VOID               *Data,\r
+  IN UINTN              DataSize,\r
+  IN UINT32             Attributes,\r
+  IN UINT32             KeyIndex,\r
+  IN UINT64             MonotonicCount\r
+  )\r
+{\r
+  AUTH_VARIABLE_INFO    AuthVariableInfo;\r
+\r
+  ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
+  AuthVariableInfo.VariableName = VariableName;\r
+  AuthVariableInfo.VendorGuid = VendorGuid;\r
+  AuthVariableInfo.Data = Data;\r
+  AuthVariableInfo.DataSize = DataSize;\r
+  AuthVariableInfo.Attributes = Attributes;\r
+  AuthVariableInfo.PubKeyIndex = KeyIndex;\r
+  AuthVariableInfo.MonotonicCount = MonotonicCount;\r
+\r
+  return mAuthVarLibContextIn->UpdateVariable (\r
+           &AuthVariableInfo\r
+           );\r
+}\r
+\r
+/**\r
+  Update the variable region with Variable information.\r
+\r
+  @param[in] VariableName           Name of variable.\r
+  @param[in] VendorGuid             Guid of variable.\r
+  @param[in] Data                   Data pointer.\r
+  @param[in] DataSize               Size of Data.\r
+  @param[in] Attributes             Attribute value of the variable.\r
+  @param[in] TimeStamp              Value of associated TimeStamp.\r
+\r
+  @retval EFI_SUCCESS               The update operation is success.\r
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.\r
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AuthServiceInternalUpdateVariableWithTimeStamp (\r
+  IN CHAR16             *VariableName,\r
+  IN EFI_GUID           *VendorGuid,\r
+  IN VOID               *Data,\r
+  IN UINTN              DataSize,\r
+  IN UINT32             Attributes,\r
+  IN EFI_TIME           *TimeStamp\r
+  )\r
+{\r
+  EFI_STATUS            FindStatus;\r
+  VOID                  *OrgData;\r
+  UINTN                 OrgDataSize;\r
+  AUTH_VARIABLE_INFO    AuthVariableInfo;\r
+\r
+  FindStatus = AuthServiceInternalFindVariable (\r
+                 VariableName,\r
+                 VendorGuid,\r
+                 &OrgData,\r
+                 &OrgDataSize\r
+                 );\r
+\r
+  //\r
+  // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable\r
+  //\r
+  if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {\r
+    if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r
+        ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r
+        (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||\r
+        (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {\r
+      //\r
+      // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of\r
+      // EFI_SIGNATURE_DATA values that are already part of the existing variable value.\r
+      //\r
+      FilterSignatureList (\r
+        OrgData,\r
+        OrgDataSize,\r
+        Data,\r
+        &DataSize\r
+        );\r
+    }\r
+  }\r
+\r
+  ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));\r
+  AuthVariableInfo.VariableName = VariableName;\r
+  AuthVariableInfo.VendorGuid = VendorGuid;\r
+  AuthVariableInfo.Data = Data;\r
+  AuthVariableInfo.DataSize = DataSize;\r
+  AuthVariableInfo.Attributes = Attributes;\r
+  AuthVariableInfo.TimeStamp = TimeStamp;\r
+  return mAuthVarLibContextIn->UpdateVariable (\r
+           &AuthVariableInfo\r
+           );\r
+}\r
+\r
+/**\r
+  Determine whether this operation needs a physical present user.\r
+\r
+  @param[in]      VariableName            Name of the Variable.\r
+  @param[in]      VendorGuid              GUID of the Variable.\r
+\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
+  EFI_STATUS    Status;\r
+  VOID          *Data;\r
+  UINTN         DataSize;\r
+\r
+  Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize);\r
+  if (!EFI_ERROR (Status) && (*(UINT8 *) Data == CUSTOM_SECURE_BOOT_MODE)) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Get available public key index.\r
+\r
+  @param[in] PubKey     Pointer to Public Key data.\r
+\r
+  @return Public key index, 0 if no any public key index available.\r
+\r
+**/\r
+UINT32\r
+GetAvailableKeyIndex (\r
+  IN  UINT8             *PubKey\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT8                 *Data;\r
+  UINTN                 DataSize;\r
+  UINT8                 *Ptr;\r
+  UINT32                Index;\r
+  BOOLEAN               IsFound;\r
+  EFI_GUID              VendorGuid;\r
+  CHAR16                Name[1];\r
+  AUTH_VARIABLE_INFO    AuthVariableInfo;\r
+  UINT32                KeyIndex;\r
+\r
+  Status = AuthServiceInternalFindVariable (\r
+             AUTHVAR_KEYDB_NAME,\r
+             &gEfiAuthenticatedVariableGuid,\r
+             (VOID **) &Data,\r
+             &DataSize\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
+  if (mPubKeyNumber == mMaxKeyNumber) {\r
+    Name[0] = 0;\r
+    AuthVariableInfo.VariableName = Name;\r
+    ZeroMem (&VendorGuid, sizeof (VendorGuid));\r
+    AuthVariableInfo.VendorGuid = &VendorGuid;\r
+    mPubKeyNumber = 0;\r
+    //\r
+    // Collect valid key data.\r
+    //\r
+    do {\r
+      Status = mAuthVarLibContextIn->FindNextVariable (AuthVariableInfo.VariableName, AuthVariableInfo.VendorGuid, &AuthVariableInfo);\r
+      if (!EFI_ERROR (Status)) {\r
+        if (AuthVariableInfo.PubKeyIndex != 0) {\r
+          for (Ptr = Data; Ptr < (Data + DataSize); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {\r
+            if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {\r
+              //\r
+              // Check if the key data has been collected.\r
+              //\r
+              for (Index = 0; Index < mPubKeyNumber; Index++) {\r
+                if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {\r
+                  break;\r
+                }\r
+              }\r
+              if (Index == mPubKeyNumber) {\r
+                //\r
+                // New key data.\r
+                //\r
+                CopyMem ((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber, Ptr, sizeof (AUTHVAR_KEY_DB_DATA));\r
+                mPubKeyNumber++;\r
+              }\r
+              break;\r
+            }\r
+          }\r
+        }\r
+      }\r
+    } while (Status != EFI_NOT_FOUND);\r
+\r
+    //\r
+    // No available space to add new public key.\r
+    //\r
+    if (mPubKeyNumber == mMaxKeyNumber) {\r
+      return 0;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Find available public key index.\r
+  //\r
+  for (KeyIndex = 1; KeyIndex <= mMaxKeyNumber; KeyIndex++) {\r
+    IsFound = FALSE;\r
+    for (Ptr = mPubKeyStore; Ptr < (mPubKeyStore + mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA)); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {\r
+      if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == KeyIndex) {\r
+        IsFound = TRUE;\r
+        break;\r
+      }\r
+    }\r
+    if (!IsFound) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  return KeyIndex;\r
+}\r
+\r
+/**\r
+  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 public key.\r
+\r
+**/\r
+UINT32\r
+AddPubKeyInStore (\r
+  IN  UINT8                        *PubKey,\r
+  IN  VARIABLE_ENTRY_CONSISTENCY   *VariableDataEntry\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  UINT32                           Index;\r
+  VARIABLE_ENTRY_CONSISTENCY       PublicKeyEntry;\r
+  UINT32                           Attributes;\r
+  UINT32                           KeyIndex;\r
+\r
+  if (PubKey == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Check whether the public key entry does exist.\r
+  //\r
+  for (Index = 0; Index < mPubKeyNumber; Index++) {\r
+    if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
+      return ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex));\r
+    }\r
+  }\r
+\r
+  KeyIndex = GetAvailableKeyIndex (PubKey);\r
+  if (KeyIndex == 0) {\r
+    return 0;\r
+  }\r
+\r
+  //\r
+  // Check the variable space for both public key and variable data.\r
+  //\r
+  PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * sizeof (AUTHVAR_KEY_DB_DATA);\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 (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {\r
+    //\r
+    // No enough variable space.\r
+    //\r
+    return 0;\r
+  }\r
+\r
+  WriteUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyIndex), KeyIndex);\r
+  CopyMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
+  mPubKeyNumber++;\r
+\r
+  //\r
+  // Update public key database variable.\r
+  //\r
+  Status = AuthServiceInternalUpdateVariable (\r
+             AUTHVAR_KEYDB_NAME,\r
+             &gEfiAuthenticatedVariableGuid,\r
+             mPubKeyStore,\r
+             mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA),\r
+             Attributes\r
+             );\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
+  return KeyIndex;\r
+}\r
+\r
+/**\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
+  @retval EFI_INVALID_PARAMETER       Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION      If authentication failed.\r
+  @retval EFI_SUCCESS                 Authentication successful.\r
+\r
+**/\r
+EFI_STATUS\r
+VerifyCounterBasedPayload (\r
+  IN     UINT8          *Data,\r
+  IN     UINTN          DataSize,\r
+  IN     UINT8          *PubKey\r
+  )\r
+{\r
+  BOOLEAN                         Status;\r
+  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
+  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
+  UINT8                           Digest[SHA256_DIGEST_SIZE];\r
+  VOID                            *Rsa;\r
+  UINTN                           PayloadSize;\r
+\r
+  PayloadSize = DataSize - AUTHINFO_SIZE;\r
+  Rsa         = NULL;\r
+  CertData    = NULL;\r
+  CertBlock   = NULL;\r
+\r
+  if (Data == NULL || PubKey == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
+\r
+  //\r
+  // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\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, &gEfiCertTypeRsa2048Sha256Guid)) {\r
+    //\r
+    // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
+    //\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+  //\r
+  // Hash data payload with SHA256.\r
+  //\r
+  ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
+  Status  = Sha256Init (mHashCtx);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\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
+  //\r
+  // Hash Monotonic Count.\r
+  //\r
+  Status  = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  Status  = Sha256Final (mHashCtx, Digest);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Generate & Initialize RSA Context.\r
+  //\r
+  Rsa = RsaNew ();\r
+  ASSERT (Rsa != NULL);\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
+  Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Verify the signature.\r
+  //\r
+  Status = RsaPkcs1Verify (\r
+             Rsa,\r
+             Digest,\r
+             SHA256_DIGEST_SIZE,\r
+             CertBlock->Signature,\r
+             EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
+             );\r
+\r
+Done:\r
+  if (Rsa != NULL) {\r
+    RsaFree (Rsa);\r
+  }\r
+  if (Status) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+}\r
+\r
+/**\r
+  Update platform mode.\r
+\r
+  @param[in]      Mode                    SETUP_MODE or USER_MODE.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SUCCESS                     Update platform mode successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdatePlatformMode (\r
+  IN  UINT32                    Mode\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VOID                    *Data;\r
+  UINTN                   DataSize;\r
+  UINT8                   SecureBootMode;\r
+  UINT8                   SecureBootEnable;\r
+  UINTN                   VariableDataSize;\r
+\r
+  Status = AuthServiceInternalFindVariable (\r
+             EFI_SETUP_MODE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &Data,\r
+             &DataSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\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 (Data, &mPlatformMode, sizeof(UINT8));\r
+\r
+  if (mAuthVarLibContextIn->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
+  //\r
+  // Check "SecureBoot" variable's existence.\r
+  // If it doesn't exist, firmware has no capability to perform driver signing verification,\r
+  // then set "SecureBoot" to 0.\r
+  //\r
+  Status = AuthServiceInternalFindVariable (\r
+             EFI_SECURE_BOOT_MODE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &Data,\r
+             &DataSize\r
+             );\r
+  //\r
+  // If "SecureBoot" variable exists, then check "SetupMode" variable update.\r
+  // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.\r
+  // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
+  } else {\r
+    if (mPlatformMode == USER_MODE) {\r
+      SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
+    } else if (mPlatformMode == SETUP_MODE) {\r
+      SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
+    } else {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  }\r
+\r
+  Status  = AuthServiceInternalUpdateVariable (\r
+              EFI_SECURE_BOOT_MODE_NAME,\r
+              &gEfiGlobalVariableGuid,\r
+              &SecureBootMode,\r
+              sizeof(UINT8),\r
+              EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+              );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.\r
+  //\r
+  Status = AuthServiceInternalFindVariable (\r
+             EFI_SECURE_BOOT_ENABLE_NAME,\r
+             &gEfiSecureBootEnableDisableGuid,\r
+             &Data,\r
+             &DataSize\r
+             );\r
+\r
+  if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {\r
+    //\r
+    // Create the "SecureBootEnable" variable as secure boot is enabled.\r
+    //\r
+    SecureBootEnable = SECURE_BOOT_ENABLE;\r
+    VariableDataSize = sizeof (SecureBootEnable);\r
+  } else {\r
+    //\r
+    // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"\r
+    // variable is not in secure boot state.\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    SecureBootEnable = SECURE_BOOT_DISABLE;\r
+    VariableDataSize = 0;\r
+  }\r
+\r
+  Status = AuthServiceInternalUpdateVariable (\r
+             EFI_SECURE_BOOT_ENABLE_NAME,\r
+             &gEfiSecureBootEnableDisableGuid,\r
+             &SecureBootEnable,\r
+             VariableDataSize,\r
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+             );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.\r
+\r
+  @param[in]  VariableName                Name of Variable to be check.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\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
+CheckSignatureListFormat(\r
+  IN  CHAR16                    *VariableName,\r
+  IN  EFI_GUID                  *VendorGuid,\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize\r
+  )\r
+{\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
+  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
+              (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)))) {\r
+    IsPk = FALSE;\r
+  } else {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  SigCount = 0;\r
+  SigList  = (EFI_SIGNATURE_LIST *) Data;\r
+  SigDataSize  = DataSize;\r
+  RsaContext = NULL;\r
+\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 != ((UINT32) ~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
+      // Undefined signature type.\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
+      //\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
+      RsaContext = RsaNew ();\r
+      if (RsaContext == NULL) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\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
+      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
+**/\r
+EFI_STATUS\r
+VendorKeyIsModified (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  mVendorKeyState = VENDOR_KEYS_MODIFIED;\r
+\r
+  Status = AuthServiceInternalUpdateVariable (\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
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return AuthServiceInternalUpdateVariable (\r
+           EFI_VENDOR_KEYS_VARIABLE_NAME,\r
+           &gEfiGlobalVariableGuid,\r
+           &mVendorKeyState,\r
+           sizeof (UINT8),\r
+           EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\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]  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  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/dbt 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 = AuthServiceInternalUpdateVariableWithTimeStamp (\r
+               VariableName,\r
+               VendorGuid,\r
+               Payload,\r
+               PayloadSize,\r
+               Attributes,\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 = VerifyTimeBasedPayloadAndUpdate (\r
+               VariableName,\r
+               VendorGuid,\r
+               Data,\r
+               DataSize,\r
+               Attributes,\r
+               AuthVarTypePk,\r
+               &Del\r
+               );\r
+  } else {\r
+    //\r
+    // Verify against the certificate in data payload.\r
+    //\r
+    Status = VerifyTimeBasedPayloadAndUpdate (\r
+               VariableName,\r
+               VendorGuid,\r
+               Data,\r
+               DataSize,\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
+  return Status;\r
+}\r
+\r
+/**\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
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @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_SUCCESS                     Variable pass validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithKek (\r
+  IN  CHAR16                               *VariableName,\r
+  IN  EFI_GUID                             *VendorGuid,\r
+  IN  VOID                                 *Data,\r
+  IN  UINTN                                DataSize,\r
+  IN  UINT32                               Attributes OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\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
+    // DB, DBX and DBT 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
+  Status = EFI_SUCCESS;\r
+  if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {\r
+    //\r
+    // Time-based, verify against X509 Cert KEK.\r
+    //\r
+    return VerifyTimeBasedPayloadAndUpdate (\r
+             VariableName,\r
+             VendorGuid,\r
+             Data,\r
+             DataSize,\r
+             Attributes,\r
+             AuthVarTypeKek,\r
+             NULL\r
+             );\r
+  } else {\r
+    //\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 = AuthServiceInternalUpdateVariableWithTimeStamp (\r
+               VariableName,\r
+               VendorGuid,\r
+               Payload,\r
+               PayloadSize,\r
+               Attributes,\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
+}\r
+\r
+/**\r
+  Check if it is to delete auth variable.\r
+\r
+  @param[in] OrgAttributes      Original attribute value of the variable.\r
+  @param[in] Data               Data pointer.\r
+  @param[in] DataSize           Size of Data.\r
+  @param[in] Attributes         Attribute value of the variable.\r
+\r
+  @retval TRUE                  It is to delete auth variable.\r
+  @retval FALSE                 It is not to delete auth variable.\r
+\r
+**/\r
+BOOLEAN\r
+IsDeleteAuthVariable (\r
+  IN  UINT32                    OrgAttributes,\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  UINT32                    Attributes\r
+  )\r
+{\r
+  BOOLEAN                       Del;\r
+  UINTN                         PayloadSize;\r
+\r
+  Del = FALSE;\r
+\r
+  //\r
+  // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
+  // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,\r
+  // SetVariable must be used with attributes matching the existing variable\r
+  // and the DataSize set to the size of the AuthInfo descriptor.\r
+  //\r
+  if ((Attributes == OrgAttributes) &&\r
+      ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) {\r
+    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+      PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
+      if (PayloadSize == 0) {\r
+        Del = TRUE;\r
+      }\r
+    } else {\r
+      PayloadSize = DataSize - AUTHINFO_SIZE;\r
+      if (PayloadSize == 0) {\r
+        Del = TRUE;\r
+      }\r
+    }\r
+  }\r
+\r
+  return Del;\r
+}\r
+\r
+/**\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 the variable.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+\r
+  @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
+  @return EFI_SUCCESS                     Variable is not write-protected or pass validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVariable (\r
+  IN     CHAR16                             *VariableName,\r
+  IN     EFI_GUID                           *VendorGuid,\r
+  IN     VOID                               *Data,\r
+  IN     UINTN                              DataSize,\r
+  IN     UINT32                             Attributes OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  BOOLEAN                         IsDeletion;\r
+  BOOLEAN                         IsFirstTime;\r
+  UINT8                           *PubKey;\r
+  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
+  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
+  UINT32                          KeyIndex;\r
+  UINT64                          MonotonicCount;\r
+  VARIABLE_ENTRY_CONSISTENCY      VariableDataEntry;\r
+  UINT32                          Index;\r
+  AUTH_VARIABLE_INFO              OrgVariableInfo;\r
+\r
+  KeyIndex    = 0;\r
+  CertData    = NULL;\r
+  CertBlock   = NULL;\r
+  PubKey      = NULL;\r
+  IsDeletion  = FALSE;\r
+  Status      = EFI_SUCCESS;\r
+\r
+  ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));\r
+  Status = mAuthVarLibContextIn->FindVariable (\r
+             VariableName,\r
+             VendorGuid,\r
+             &OrgVariableInfo\r
+             );\r
+\r
+  if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && UserPhysicalPresent()) {\r
+    //\r
+    // Allow the delete operation of common authenticated variable at user physical presence.\r
+    //\r
+    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+      Status = DeleteCertsFromDb (VariableName, VendorGuid);\r
+    }\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = AuthServiceInternalUpdateVariable (\r
+                 VariableName,\r
+                 VendorGuid,\r
+                 NULL,\r
+                 0,\r
+                 0\r
+                 );\r
+    }\r
+    return Status;\r
+  }\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 (OrgVariableInfo.Data != NULL) {\r
+    if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&\r
+        ((OrgVariableInfo.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
+        ((OrgVariableInfo.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 VerifyTimeBasedPayloadAndUpdate (\r
+             VariableName,\r
+             VendorGuid,\r
+             Data,\r
+             DataSize,\r
+             Attributes,\r
+             AuthVarTypePriv,\r
+             NULL\r
+             );\r
+  }\r
+\r
+  //\r
+  // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
+  //\r
+  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    //\r
+    // Determine current operation type.\r
+    //\r
+    if (DataSize == AUTHINFO_SIZE) {\r
+      IsDeletion = TRUE;\r
+    }\r
+    //\r
+    // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+    //\r
+    if (OrgVariableInfo.Data == NULL) {\r
+      IsFirstTime = TRUE;\r
+    } else if ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
+      IsFirstTime = TRUE;\r
+    } else {\r
+      KeyIndex   = OrgVariableInfo.PubKeyIndex;\r
+      IsFirstTime = FALSE;\r
+    }\r
+  } else if ((OrgVariableInfo.Data != NULL) &&\r
+             ((OrgVariableInfo.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
+    return EFI_WRITE_PROTECTED;\r
+  } else {\r
+    //\r
+    // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
+    // That means it is not authenticated variable, just update variable as usual.\r
+    //\r
+    Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get PubKey and check Monotonic Count value corresponding to the variable.\r
+  //\r
+  CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
+  PubKey    = CertBlock->PublicKey;\r
+\r
+  //\r
+  // Update Monotonic Count value.\r
+  //\r
+  MonotonicCount = CertData->MonotonicCount;\r
+\r
+  if (!IsFirstTime) {\r
+    //\r
+    // 2 cases need to check here\r
+    //   1. Internal PubKey variable. PubKeyIndex is always 0\r
+    //   2. Other counter-based AuthVariable. Check input PubKey.\r
+    //\r
+    if (KeyIndex == 0) {\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+    for (Index = 0; Index < mPubKeyNumber; Index++) {\r
+      if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == KeyIndex) {\r
+        if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
+          break;\r
+        } else {\r
+          return EFI_SECURITY_VIOLATION;\r
+        }\r
+      }\r
+    }\r
+    if (Index == mPubKeyNumber) {\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+\r
+    //\r
+    // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
+    // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
+    //\r
+    if (MonotonicCount <= OrgVariableInfo.MonotonicCount) {\r
+      //\r
+      // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+      //\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+  }\r
+  //\r
+  // Verify the certificate in Data payload.\r
+  //\r
+  Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\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, &VariableDataEntry);\r
+    if (KeyIndex == 0) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Verification pass.\r
+  //\r
+  return AuthServiceInternalUpdateVariableWithMonotonicCount (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount);\r
+}\r
+\r
+/**\r
+  Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.\r
+\r
+  @param[in]        Data          Pointer to original EFI_SIGNATURE_LIST.\r
+  @param[in]        DataSize      Size of Data buffer.\r
+  @param[in, out]   NewData       Pointer to new EFI_SIGNATURE_LIST.\r
+  @param[in, out]   NewDataSize   Size of NewData buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+FilterSignatureList (\r
+  IN     VOID       *Data,\r
+  IN     UINTN      DataSize,\r
+  IN OUT VOID       *NewData,\r
+  IN OUT UINTN      *NewDataSize\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
+  UINT8                 *TempData;\r
+  UINTN                 TempDataSize;\r
+  EFI_STATUS            Status;\r
+\r
+  if (*NewDataSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  TempDataSize = *NewDataSize;\r
+  Status = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **) &TempData);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Tail = TempData;\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, keep it.\r
+        //\r
+        if (CopiedCount == 0) {\r
+          //\r
+          // Copy EFI_SIGNATURE_LIST header for only once.\r
+          //\r
+          CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);\r
+          Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;\r
+        }\r
+\r
+        CopyMem (Tail, NewCert, NewCertList->SignatureSize);\r
+        Tail += NewCertList->SignatureSize;\r
+        CopiedCount++;\r
+      }\r
+\r
+      NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);\r
+    }\r
+\r
+    //\r
+    // Update SignatureListSize in the kept 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
+  TempDataSize = (Tail - (UINT8 *) TempData);\r
+\r
+  CopyMem (NewData, TempData, TempDataSize);\r
+  *NewDataSize = TempDataSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Compare two EFI_TIME data.\r
+\r
+\r
+  @param FirstTime           A pointer to the first EFI_TIME data.\r
+  @param SecondTime          A pointer to the second EFI_TIME data.\r
+\r
+  @retval  TRUE              The FirstTime is not later than the SecondTime.\r
+  @retval  FALSE             The FirstTime is later than the SecondTime.\r
+\r
+**/\r
+BOOLEAN\r
+AuthServiceInternalCompareTimeStamp (\r
+  IN EFI_TIME               *FirstTime,\r
+  IN EFI_TIME               *SecondTime\r
+  )\r
+{\r
+  if (FirstTime->Year != SecondTime->Year) {\r
+    return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r
+  } else if (FirstTime->Month != SecondTime->Month) {\r
+    return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r
+  } else if (FirstTime->Day != SecondTime->Day) {\r
+    return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r
+  } 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 < SecondTime->Minute);\r
+  }\r
+\r
+  return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
+}\r
+\r
+/**\r
+  Find matching signer's certificates for common authenticated variable\r
+  by corresponding VariableName and VendorGuid from "certdb".\r
+\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
+  @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
+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
+  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
+  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 = AuthServiceInternalFindVariable (\r
+             EFI_CERT_DB_NAME,\r
+             &gEfiCertDbGuid,\r
+             (VOID **) &Data,\r
+             &DataSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\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
+  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 = AuthServiceInternalFindVariable (\r
+             EFI_CERT_DB_NAME,\r
+             &gEfiCertDbGuid,\r
+             (VOID **) &Data,\r
+             &DataSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\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   = AuthServiceInternalUpdateVariable (\r
+               EFI_CERT_DB_NAME,\r
+               &gEfiCertDbGuid,\r
+               NewCertDb,\r
+               NewCertDbSize,\r
+               VarAttr\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
+  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 = AuthServiceInternalFindVariable (\r
+             EFI_CERT_DB_NAME,\r
+             &gEfiCertDbGuid,\r
+             (VOID **) &Data,\r
+             &DataSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\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 > mMaxCertDbSize) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  NewCertDb     = (UINT8*) mCertDbStore;\r
+\r
+  //\r
+  // Copy the DB entries before inserting 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   = AuthServiceInternalUpdateVariable (\r
+               EFI_CERT_DB_NAME,\r
+               &gEfiCertDbGuid,\r
+               NewCertDb,\r
+               NewCertDbSize,\r
+               VarAttr\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]  Attributes                  Attribute value of the variable.\r
+  @param[in]  AuthVarType                 Verify against PK, KEK database, private database or certificate in data payload.\r
+  @param[in]  OrgTimeStamp                Pointer to original time stamp,\r
+                                          original variable is not found if NULL.\r
+  @param[out]  VarPayloadPtr              Pointer to variable payload address.\r
+  @param[out]  VarPayloadSize             Pointer to variable payload size.\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     UINT32                             Attributes,\r
+  IN     AUTHVAR_TYPE                       AuthVarType,\r
+  IN     EFI_TIME                           *OrgTimeStamp,\r
+  OUT    UINT8                              **VarPayloadPtr,\r
+  OUT    UINTN                              *VarPayloadSize\r
+  )\r
+{\r
+  EFI_VARIABLE_AUTHENTICATION_2    *CertData;\r
+  UINT8                            *SigData;\r
+  UINT32                           SigDataSize;\r
+  UINT8                            *PayloadPtr;\r
+  UINTN                            PayloadSize;\r
+  UINT32                           Attr;\r
+  BOOLEAN                          VerifyStatus;\r
+  EFI_STATUS                       Status;\r
+  EFI_SIGNATURE_LIST               *CertList;\r
+  EFI_SIGNATURE_DATA               *Cert;\r
+  UINTN                            Index;\r
+  UINTN                            CertCount;\r
+  UINT32                           KekDataSize;\r
+  UINT8                            *NewData;\r
+  UINTN                            NewDataSize;\r
+  UINT8                            *Buffer;\r
+  UINTN                            Length;\r
+  UINT8                            *RootCert;\r
+  UINTN                            RootCertSize;\r
+  UINT8                            *SignerCerts;\r
+  UINTN                            CertStackSize;\r
+  UINT8                            *CertsInCertDb;\r
+  UINT32                           CertsSizeinDb;\r
+\r
+  VerifyStatus           = FALSE;\r
+  CertData               = NULL;\r
+  NewData                = NULL;\r
+  Attr                   = Attributes;\r
+  SignerCerts            = NULL;\r
+  RootCert               = NULL;\r
+  CertsInCertDb          = NULL;\r
+\r
+  //\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
+  // returned by subsequent calls to GetVariable().\r
+  //\r
+  CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\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 ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
+    if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) {\r
+      //\r
+      // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+      //\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+  }\r
+\r
+  //\r
+  // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
+  // 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
+    // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
+    //\r
+    return EFI_SECURITY_VIOLATION;\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 = CertData->AuthInfo.CertData;\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 = SigData + SigDataSize;\r
+  PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;\r
+\r
+  //\r
+  // Construct a serialization buffer 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
+  NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
+                sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);\r
+\r
+  //\r
+  // Here is to reuse scratch data area(at the end of volatile variable store)\r
+  // to reduce SMRAM consumption for SMM variable driver.\r
+  // The scratch buffer is enough to hold the serialized data and safe to use,\r
+  // because it is only used at here to do verification temporarily first\r
+  // and then used in UpdateVariable() for a time based auth variable set.\r
+  //\r
+  Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **) &NewData);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Buffer = NewData;\r
+  Length = StrLen (VariableName) * sizeof (CHAR16);\r
+  CopyMem (Buffer, VariableName, Length);\r
+  Buffer += Length;\r
+\r
+  Length = sizeof (EFI_GUID);\r
+  CopyMem (Buffer, VendorGuid, Length);\r
+  Buffer += Length;\r
+\r
+  Length = sizeof (UINT32);\r
+  CopyMem (Buffer, &Attr, Length);\r
+  Buffer += Length;\r
+\r
+  Length = sizeof (EFI_TIME);\r
+  CopyMem (Buffer, &CertData->TimeStamp, Length);\r
+  Buffer += Length;\r
+\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
+    //\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 = AuthServiceInternalFindVariable (\r
+               EFI_PLATFORM_KEY_NAME,\r
+               &gEfiGlobalVariableGuid,\r
+               &Data,\r
+               &DataSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      VerifyStatus = FALSE;\r
+      goto Exit;\r
+    }\r
+    CertList = (EFI_SIGNATURE_LIST *) Data;\r
+    Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\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
+    //\r
+    VerifyStatus = Pkcs7Verify (\r
+                     SigData,\r
+                     SigDataSize,\r
+                     RootCert,\r
+                     RootCertSize,\r
+                     NewData,\r
+                     NewDataSize\r
+                     );\r
+\r
+  } else if (AuthVarType == AuthVarTypeKek) {\r
+\r
+    //\r
+    // Get KEK database from variable.\r
+    //\r
+    Status = AuthServiceInternalFindVariable (\r
+               EFI_KEY_EXCHANGE_KEY_NAME,\r
+               &gEfiGlobalVariableGuid,\r
+               &Data,\r
+               &DataSize\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r
+    //\r
+    KekDataSize      = (UINT32) DataSize;\r
+    CertList         = (EFI_SIGNATURE_LIST *) Data;\r
+    while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
+      if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\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 (Index = 0; Index < CertCount; Index++) {\r
+          //\r
+          // Iterate each Signature Data Node within this CertList for a verify\r
+          //\r
+          RootCert      = Cert->SignatureData;\r
+          RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
+\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
+          if (VerifyStatus) {\r
+            goto Exit;\r
+          }\r
+          Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+        }\r
+      }\r
+      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/DBT.\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 (OrgTimeStamp != 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) && (OrgTimeStamp != 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 ((OrgTimeStamp == 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
+  if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {\r
+    Pkcs7FreeSigners (RootCert);\r
+    Pkcs7FreeSigners (SignerCerts);\r
+  }\r
+\r
+  if (!VerifyStatus) {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+\r
+  Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *VarPayloadPtr = PayloadPtr;\r
+  *VarPayloadSize = PayloadSize;\r
+\r
+  return EFI_SUCCESS;\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]  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
+VerifyTimeBasedPayloadAndUpdate (\r
+  IN     CHAR16                             *VariableName,\r
+  IN     EFI_GUID                           *VendorGuid,\r
+  IN     VOID                               *Data,\r
+  IN     UINTN                              DataSize,\r
+  IN     UINT32                             Attributes,\r
+  IN     AUTHVAR_TYPE                       AuthVarType,\r
+  OUT    BOOLEAN                            *VarDel\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EFI_STATUS                       FindStatus;\r
+  UINT8                            *PayloadPtr;\r
+  UINTN                            PayloadSize;\r
+  EFI_VARIABLE_AUTHENTICATION_2    *CertData;\r
+  AUTH_VARIABLE_INFO               OrgVariableInfo;\r
+\r
+  ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));\r
+  FindStatus = mAuthVarLibContextIn->FindVariable (\r
+             VariableName,\r
+             VendorGuid,\r
+             &OrgVariableInfo\r
+             );\r
+\r
+  Status = VerifyTimeBasedPayload (\r
+             VariableName,\r
+             VendorGuid,\r
+             Data,\r
+             DataSize,\r
+             Attributes,\r
+             AuthVarType,\r
+             (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL,\r
+             &PayloadPtr,\r
+             &PayloadSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((PayloadSize == 0) && (VarDel != NULL)) {\r
+    *VarDel = TRUE;\r
+  }\r
+\r
+  CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
+\r
+  //\r
+  // Final step: Update/Append Variable if it pass Pkcs7Verify\r
+  //\r
+  return AuthServiceInternalUpdateVariableWithTimeStamp (\r
+           VariableName,\r
+           VendorGuid,\r
+           PayloadPtr,\r
+           PayloadSize,\r
+           Attributes,\r
+           &CertData->TimeStamp\r
+           );\r
+}\r
diff --git a/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h b/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h
new file mode 100644 (file)
index 0000000..08fff3f
--- /dev/null
@@ -0,0 +1,411 @@
+/** @file\r
+  The internal header file includes the common header files, defines\r
+  internal structure and functions used by AuthService module.\r
+\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
+     The whole SMM authentication variable design relies on the integrity of flash part and SMM.\r
+  which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory\r
+  may not be modified without authorization. If platform fails to protect these resources,\r
+  the authentication service provided in this driver will be broken, and the behavior is undefined.\r
+\r
+Copyright (c) 2009 - 2015, 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
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _AUTHSERVICE_INTERNAL_H_\r
+#define _AUTHSERVICE_INTERNAL_H_\r
+\r
+#include <Library/AuthVariableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include <Library/PlatformSecureLib.h>\r
+\r
+#include <Guid/AuthenticatedVariableFormat.h>\r
+#include <Guid/ImageAuthentication.h>\r
+\r
+///\r
+/// Struct to record signature requirement defined by UEFI spec.\r
+/// For SigHeaderSize and SigDataSize, ((UINT32) ~0) means NO exact length requirement for this field.\r
+///\r
+typedef struct {\r
+  EFI_GUID    SigType;\r
+  // Expected SignatureHeader size in Bytes.\r
+  UINT32      SigHeaderSize;\r
+  // Expected SignatureData size in Bytes.\r
+  UINT32      SigDataSize;\r
+} EFI_SIGNATURE_ITEM;\r
+\r
+typedef enum {\r
+  AuthVarTypePk,\r
+  AuthVarTypeKek,\r
+  AuthVarTypePriv,\r
+  AuthVarTypePayload\r
+} AUTHVAR_TYPE;\r
+\r
+///\r
+/// "AuthVarKeyDatabase" variable for the Public Key store\r
+/// of variables with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+///\r
+/// GUID: gEfiAuthenticatedVariableGuid\r
+///\r
+/// We need maintain atomicity.\r
+///\r
+/// Format:\r
+/// +----------------------------+\r
+/// | AUTHVAR_KEY_DB_DATA        | <-- First AuthVarKey\r
+/// +----------------------------+\r
+/// | ......                     |\r
+/// +----------------------------+\r
+/// | AUTHVAR_KEY_DB_DATA        | <-- Last AuthKey\r
+/// +----------------------------+\r
+///\r
+#define AUTHVAR_KEYDB_NAME      L"AuthVarKeyDatabase"\r
+\r
+#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256\r
+#define EFI_CERT_TYPE_RSA2048_SIZE        256\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT32    KeyIndex;\r
+  UINT8     KeyData[EFI_CERT_TYPE_RSA2048_SIZE];\r
+} AUTHVAR_KEY_DB_DATA;\r
+#pragma pack()\r
+\r
+///\r
+/// "certdb" variable stores the signer's certificates for non PK/KEK/DB/DBX\r
+/// variables with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.\r
+///\r
+/// GUID: gEfiCertDbGuid\r
+///\r
+/// We need maintain atomicity.\r
+///\r
+/// Format:\r
+/// +----------------------------+\r
+/// | UINT32                     | <-- CertDbListSize, including this UINT32\r
+/// +----------------------------+\r
+/// | AUTH_CERT_DB_DATA          | <-- First CERT\r
+/// +----------------------------+\r
+/// | ........                   |\r
+/// +----------------------------+\r
+/// | AUTH_CERT_DB_DATA          | <-- Last CERT\r
+/// +----------------------------+\r
+///\r
+#define EFI_CERT_DB_NAME        L"certdb"\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  EFI_GUID    VendorGuid;\r
+  UINT32      CertNodeSize;\r
+  UINT32      NameSize;\r
+  UINT32      CertDataSize;\r
+  /// CHAR16  VariableName[NameSize];\r
+  /// UINT8   CertData[CertDataSize];\r
+} AUTH_CERT_DB_DATA;\r
+#pragma pack()\r
+\r
+extern UINT8    *mPubKeyStore;\r
+extern UINT32   mPubKeyNumber;\r
+extern UINT32   mMaxKeyNumber;\r
+extern UINT32   mMaxKeyDbSize;\r
+extern UINT8    *mCertDbStore;\r
+extern UINT32   mMaxCertDbSize;\r
+extern UINT32   mPlatformMode;\r
+extern UINT8    mVendorKeyState;\r
+\r
+extern VOID     *mHashCtx;\r
+\r
+extern AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn;\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]  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
+VerifyTimeBasedPayloadAndUpdate (\r
+  IN     CHAR16                             *VariableName,\r
+  IN     EFI_GUID                           *VendorGuid,\r
+  IN     VOID                               *Data,\r
+  IN     UINTN                              DataSize,\r
+  IN     UINT32                             Attributes,\r
+  IN     AUTHVAR_TYPE                       AuthVarType,\r
+  OUT    BOOLEAN                            *VarDel\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
+/**\r
+  Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.\r
+\r
+  @param[in]        Data          Pointer to original EFI_SIGNATURE_LIST.\r
+  @param[in]        DataSize      Size of Data buffer.\r
+  @param[in, out]   NewData       Pointer to new EFI_SIGNATURE_LIST.\r
+  @param[in, out]   NewDataSize   Size of NewData buffer.\r
+\r
+**/\r
+EFI_STATUS\r
+FilterSignatureList (\r
+  IN     VOID       *Data,\r
+  IN     UINTN      DataSize,\r
+  IN OUT VOID       *NewData,\r
+  IN OUT UINTN      *NewDataSize\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]  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  UINT32                    Attributes OPTIONAL,\r
+  IN  BOOLEAN                   IsPk\r
+  );\r
+\r
+/**\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
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @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_SUCCESS                     Variable pass validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithKek (\r
+  IN  CHAR16                               *VariableName,\r
+  IN  EFI_GUID                             *VendorGuid,\r
+  IN  VOID                                 *Data,\r
+  IN  UINTN                                DataSize,\r
+  IN  UINT32                               Attributes OPTIONAL\r
+  );\r
+\r
+/**\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 the variable.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+\r
+  @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
+  @return EFI_SUCCESS                     Variable is not write-protected or pass validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVariable (\r
+  IN     CHAR16                             *VariableName,\r
+  IN     EFI_GUID                           *VendorGuid,\r
+  IN     VOID                               *Data,\r
+  IN     UINTN                              DataSize,\r
+  IN     UINT32                             Attributes OPTIONAL\r
+  );\r
+\r
+/**\r
+  Finds variable in storage blocks of volatile and non-volatile storage areas.\r
+\r
+  This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
+  If VariableName is an empty string, then we just return the first\r
+  qualified variable without comparing VariableName and VendorGuid.\r
+\r
+  @param[in]  VariableName          Name of the variable to be found.\r
+  @param[in]  VendorGuid            Variable vendor GUID to be found.\r
+  @param[out] Data                  Pointer to data address.\r
+  @param[out] DataSize              Pointer to data size.\r
+\r
+  @retval EFI_INVALID_PARAMETER     If VariableName is not an empty string,\r
+                                    while VendorGuid is NULL.\r
+  @retval EFI_SUCCESS               Variable successfully found.\r
+  @retval EFI_NOT_FOUND             Variable not found\r
+\r
+**/\r
+EFI_STATUS\r
+AuthServiceInternalFindVariable (\r
+  IN  CHAR16        *VariableName,\r
+  IN  EFI_GUID      *VendorGuid,\r
+  OUT VOID          **Data,\r
+  OUT UINTN         *DataSize\r
+  );\r
+\r
+/**\r
+  Update the variable region with Variable information.\r
+\r
+  @param[in] VariableName           Name of variable.\r
+  @param[in] VendorGuid             Guid of variable.\r
+  @param[in] Data                   Data pointer.\r
+  @param[in] DataSize               Size of Data.\r
+  @param[in] Attributes             Attribute value of the variable.\r
+\r
+  @retval EFI_SUCCESS               The update operation is success.\r
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.\r
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AuthServiceInternalUpdateVariable (\r
+  IN CHAR16         *VariableName,\r
+  IN EFI_GUID       *VendorGuid,\r
+  IN VOID           *Data,\r
+  IN UINTN          DataSize,\r
+  IN UINT32         Attributes\r
+  );\r
+\r
+/**\r
+  Update the variable region with Variable information.\r
+\r
+  @param[in] VariableName           Name of variable.\r
+  @param[in] VendorGuid             Guid of variable.\r
+  @param[in] Data                   Data pointer.\r
+  @param[in] DataSize               Size of Data.\r
+  @param[in] Attributes             Attribute value of the variable.\r
+  @param[in] KeyIndex               Index of associated public key.\r
+  @param[in] MonotonicCount         Value of associated monotonic count.\r
+\r
+  @retval EFI_SUCCESS               The update operation is success.\r
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.\r
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AuthServiceInternalUpdateVariableWithMonotonicCount (\r
+  IN CHAR16         *VariableName,\r
+  IN EFI_GUID       *VendorGuid,\r
+  IN VOID           *Data,\r
+  IN UINTN          DataSize,\r
+  IN UINT32         Attributes,\r
+  IN UINT32         KeyIndex,\r
+  IN UINT64         MonotonicCount\r
+  );\r
+\r
+/**\r
+  Update the variable region with Variable information.\r
+\r
+  @param[in] VariableName           Name of variable.\r
+  @param[in] VendorGuid             Guid of variable.\r
+  @param[in] Data                   Data pointer.\r
+  @param[in] DataSize               Size of Data.\r
+  @param[in] Attributes             Attribute value of the variable.\r
+  @param[in] TimeStamp              Value of associated TimeStamp.\r
+\r
+  @retval EFI_SUCCESS               The update operation is success.\r
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.\r
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AuthServiceInternalUpdateVariableWithTimeStamp (\r
+  IN CHAR16         *VariableName,\r
+  IN EFI_GUID       *VendorGuid,\r
+  IN VOID           *Data,\r
+  IN UINTN          DataSize,\r
+  IN UINT32         Attributes,\r
+  IN EFI_TIME       *TimeStamp\r
+  );\r
+\r
+#endif\r
diff --git a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c
new file mode 100644 (file)
index 0000000..0bb0918
--- /dev/null
@@ -0,0 +1,460 @@
+/** @file\r
+  Implement authentication services for the authenticated variables.\r
+\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
+     The whole SMM authentication variable design relies on the integrity of flash part and SMM.\r
+  which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory\r
+  may not be modified without authorization. If platform fails to protect these resources,\r
+  the authentication service provided in this driver will be broken, and the behavior is undefined.\r
+\r
+Copyright (c) 2015, 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
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "AuthServiceInternal.h"\r
+\r
+///\r
+/// Global database array for scratch\r
+///\r
+UINT8    *mPubKeyStore;\r
+UINT32   mPubKeyNumber;\r
+UINT32   mMaxKeyNumber;\r
+UINT32   mMaxKeyDbSize;\r
+UINT8    *mCertDbStore;\r
+UINT32   mMaxCertDbSize;\r
+UINT32   mPlatformMode;\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
+//\r
+// Hash context pointer\r
+//\r
+VOID  *mHashCtx = NULL;\r
+\r
+VARIABLE_ENTRY_PROPERTY mAuthVarEntry[] = {\r
+  {\r
+    &gEfiSecureBootEnableDisableGuid,\r
+    EFI_SECURE_BOOT_ENABLE_NAME,\r
+    {\r
+      VAR_CHECK_VARIABLE_PROPERTY_REVISION,\r
+      0,\r
+      VARIABLE_ATTRIBUTE_NV_BS,\r
+      sizeof (UINT8),\r
+      sizeof (UINT8)\r
+    }\r
+  },\r
+  {\r
+    &gEfiCustomModeEnableGuid,\r
+    EFI_CUSTOM_MODE_NAME,\r
+    {\r
+      VAR_CHECK_VARIABLE_PROPERTY_REVISION,\r
+      0,\r
+      VARIABLE_ATTRIBUTE_NV_BS,\r
+      sizeof (UINT8),\r
+      sizeof (UINT8)\r
+    }\r
+  },\r
+  {\r
+    &gEfiVendorKeysNvGuid,\r
+    EFI_VENDOR_KEYS_NV_VARIABLE_NAME,\r
+    {\r
+      VAR_CHECK_VARIABLE_PROPERTY_REVISION,\r
+      VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,\r
+      VARIABLE_ATTRIBUTE_NV_BS_RT_AT,\r
+      sizeof (UINT8),\r
+      sizeof (UINT8)\r
+    }\r
+  },\r
+  {\r
+    &gEfiAuthenticatedVariableGuid,\r
+    AUTHVAR_KEYDB_NAME,\r
+    {\r
+      VAR_CHECK_VARIABLE_PROPERTY_REVISION,\r
+      VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,\r
+      VARIABLE_ATTRIBUTE_NV_BS_RT_AW,\r
+      sizeof (UINT8),\r
+      MAX_UINTN\r
+    }\r
+  },\r
+  {\r
+    &gEfiCertDbGuid,\r
+    EFI_CERT_DB_NAME,\r
+    {\r
+      VAR_CHECK_VARIABLE_PROPERTY_REVISION,\r
+      VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,\r
+      VARIABLE_ATTRIBUTE_NV_BS_RT_AT,\r
+      sizeof (UINT32),\r
+      MAX_UINTN\r
+    }\r
+  },\r
+};\r
+\r
+VOID *mAddressPointer[3];\r
+\r
+AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn = NULL;\r
+\r
+/**\r
+  Initialization for authenticated varibale services.\r
+  If this initialization returns error status, other APIs will not work\r
+  and expect to be not called then.\r
+\r
+  @param[in]  AuthVarLibContextIn   Pointer to input auth variable lib context.\r
+  @param[out] AuthVarLibContextOut  Pointer to output auth variable lib context.\r
+\r
+  @retval EFI_SUCCESS               Function successfully executed.\r
+  @retval EFI_INVALID_PARAMETER     If AuthVarLibContextIn == NULL or AuthVarLibContextOut == NULL.\r
+  @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.\r
+  @retval EFI_UNSUPPORTED           Unsupported to process authenticated variable.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AuthVariableLibInitialize (\r
+  IN  AUTH_VAR_LIB_CONTEXT_IN   *AuthVarLibContextIn,\r
+  OUT AUTH_VAR_LIB_CONTEXT_OUT  *AuthVarLibContextOut\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT8                 VarValue;\r
+  UINT32                VarAttr;\r
+  UINT8                 *Data;\r
+  UINTN                 DataSize;\r
+  UINTN                 CtxSize;\r
+  UINT8                 SecureBootMode;\r
+  UINT8                 SecureBootEnable;\r
+  UINT8                 CustomMode;\r
+  UINT32                ListSize;\r
+\r
+  if ((AuthVarLibContextIn == NULL) || (AuthVarLibContextOut == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  mAuthVarLibContextIn = AuthVarLibContextIn;\r
+\r
+  //\r
+  // Initialize hash context.\r
+  //\r
+  CtxSize   = Sha256GetContextSize ();\r
+  mHashCtx  = AllocateRuntimePool (CtxSize);\r
+  if (mHashCtx == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Reserve runtime buffer for public key database. The size excludes variable header and name size.\r
+  //\r
+  mMaxKeyDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (AUTHVAR_KEYDB_NAME));\r
+  mMaxKeyNumber = mMaxKeyDbSize / sizeof (AUTHVAR_KEY_DB_DATA);\r
+  mPubKeyStore  = AllocateRuntimePool (mMaxKeyDbSize);\r
+  if (mPubKeyStore == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Reserve runtime buffer for certificate database. The size excludes variable header and name size.\r
+  //\r
+  mMaxCertDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (EFI_CERT_DB_NAME));\r
+  mCertDbStore   = AllocateRuntimePool (mMaxCertDbSize);\r
+  if (mCertDbStore == 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
+  //\r
+  Status = AuthServiceInternalFindVariable (\r
+             AUTHVAR_KEYDB_NAME,\r
+             &gEfiAuthenticatedVariableGuid,\r
+             (VOID **) &Data,\r
+             &DataSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    VarAttr       = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+    VarValue      = 0;\r
+    mPubKeyNumber = 0;\r
+    Status        = AuthServiceInternalUpdateVariable (\r
+                      AUTHVAR_KEYDB_NAME,\r
+                      &gEfiAuthenticatedVariableGuid,\r
+                      &VarValue,\r
+                      sizeof(UINT8),\r
+                      VarAttr\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    //\r
+    // Load database in global variable for cache.\r
+    //\r
+    ASSERT ((DataSize != 0) && (Data != NULL));\r
+    //\r
+    // "AuthVarKeyDatabase" is an internal variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before)\r
+    //  Therefore, there is no memory overflow in underlying CopyMem.\r
+    //\r
+    CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
+    mPubKeyNumber = (UINT32) (DataSize / sizeof (AUTHVAR_KEY_DB_DATA));\r
+  }\r
+\r
+  Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize);\r
+  if (EFI_ERROR (Status)) {\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
+  // Create "SetupMode" variable with BS+RT attribute set.\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    mPlatformMode = SETUP_MODE;\r
+  } else {\r
+    mPlatformMode = USER_MODE;\r
+  }\r
+  Status = AuthServiceInternalUpdateVariable (\r
+             EFI_SETUP_MODE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &mPlatformMode,\r
+             sizeof(UINT8),\r
+             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Create "SignatureSupport" variable with BS+RT attribute set.\r
+  //\r
+  Status  = AuthServiceInternalUpdateVariable (\r
+              EFI_SIGNATURE_SUPPORT_NAME,\r
+              &gEfiGlobalVariableGuid,\r
+              mSignatureSupport,\r
+              sizeof(mSignatureSupport),\r
+              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS\r
+              );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\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
+  Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **) &Data, &DataSize);\r
+  if (!EFI_ERROR (Status)) {\r
+    if (mPlatformMode == SETUP_MODE){\r
+      //\r
+      // PK is cleared in runtime. "SecureBootMode" is not updated before reboot\r
+      // Delete "SecureBootMode" in SetupMode\r
+      //\r
+      Status = AuthServiceInternalUpdateVariable (\r
+                 EFI_SECURE_BOOT_ENABLE_NAME,\r
+                 &gEfiSecureBootEnableDisableGuid,\r
+                 &SecureBootEnable,\r
+                 0,\r
+                 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+                 );\r
+    } else {\r
+      SecureBootEnable = *(UINT8 *) Data;\r
+    }\r
+  } else if (mPlatformMode == USER_MODE) {\r
+    //\r
+    // "SecureBootEnable" not exist, initialize it in USER_MODE.\r
+    //\r
+    SecureBootEnable = SECURE_BOOT_ENABLE;\r
+    Status = AuthServiceInternalUpdateVariable (\r
+               EFI_SECURE_BOOT_ENABLE_NAME,\r
+               &gEfiSecureBootEnableDisableGuid,\r
+               &SecureBootEnable,\r
+               sizeof (UINT8),\r
+               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\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
+    SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
+  }\r
+  Status = AuthServiceInternalUpdateVariable (\r
+             EFI_SECURE_BOOT_MODE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &SecureBootMode,\r
+             sizeof (UINT8),\r
+             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\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
+  CustomMode = STANDARD_SECURE_BOOT_MODE;\r
+  Status = AuthServiceInternalUpdateVariable (\r
+             EFI_CUSTOM_MODE_NAME,\r
+             &gEfiCustomModeEnableGuid,\r
+             &CustomMode,\r
+             sizeof (UINT8),\r
+             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\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 "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 = AuthServiceInternalFindVariable (\r
+             EFI_CERT_DB_NAME,\r
+             &gEfiCertDbGuid,\r
+             (VOID **) &Data,\r
+             &DataSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\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   = AuthServiceInternalUpdateVariable (\r
+                 EFI_CERT_DB_NAME,\r
+                 &gEfiCertDbGuid,\r
+                 &ListSize,\r
+                 sizeof (UINT32),\r
+                 VarAttr\r
+                 );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly.\r
+  //\r
+  Status = AuthServiceInternalFindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, (VOID **) &Data, &DataSize);\r
+  if (!EFI_ERROR (Status)) {\r
+    mVendorKeyState = *(UINT8 *)Data;\r
+  } else {\r
+    //\r
+    // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state.\r
+    //\r
+    mVendorKeyState = VENDOR_KEYS_VALID;\r
+    Status = AuthServiceInternalUpdateVariable (\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
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Create "VendorKeys" variable with BS+RT attribute set.\r
+  //\r
+  Status = AuthServiceInternalUpdateVariable (\r
+             EFI_VENDOR_KEYS_VARIABLE_NAME,\r
+             &gEfiGlobalVariableGuid,\r
+             &mVendorKeyState,\r
+             sizeof (UINT8),\r
+             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\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
+  AuthVarLibContextOut->StructVersion = AUTH_VAR_LIB_CONTEXT_OUT_STRUCT_VERSION;\r
+  AuthVarLibContextOut->StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_OUT);\r
+  AuthVarLibContextOut->AuthVarEntry = mAuthVarEntry;\r
+  AuthVarLibContextOut->AuthVarEntryCount = sizeof (mAuthVarEntry) / sizeof (mAuthVarEntry[0]);\r
+  mAddressPointer[0] = mHashCtx;\r
+  mAddressPointer[1] = mPubKeyStore;\r
+  mAddressPointer[2] = mCertDbStore;\r
+  AuthVarLibContextOut->AddressPointer = mAddressPointer;\r
+  AuthVarLibContextOut->AddressPointerCount = sizeof (mAddressPointer) / sizeof (mAddressPointer[0]);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.\r
+\r
+  @param[in] VariableName           Name of the variable.\r
+  @param[in] VendorGuid             Variable vendor GUID.\r
+  @param[in] Data                   Data pointer.\r
+  @param[in] DataSize               Size of Data.\r
+  @param[in] Attributes             Attribute value of the variable.\r
+\r
+  @retval EFI_SUCCESS               The firmware has successfully stored the variable and its data as\r
+                                    defined by the Attributes.\r
+  @retval EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @retval EFI_WRITE_PROTECTED       Variable is write-protected.\r
+  @retval EFI_OUT_OF_RESOURCES      There is not enough resource.\r
+  @retval EFI_SECURITY_VIOLATION    The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
+                                    or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS\r
+                                    set, but the AuthInfo does NOT pass the validation\r
+                                    check carried out by the firmware.\r
+  @retval EFI_UNSUPPORTED           Unsupported to process authenticated variable.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AuthVariableLibProcessVariable (\r
+  IN CHAR16         *VariableName,\r
+  IN EFI_GUID       *VendorGuid,\r
+  IN VOID           *Data,\r
+  IN UINTN          DataSize,\r
+  IN UINT32         Attributes\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+\r
+  if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r
+    Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, TRUE);\r
+  } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {\r
+    Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);\r
+  } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r
+             ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE)  == 0) ||\r
+              (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r
+              (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)\r
+             )) {\r
+    Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, Attributes);\r
+    }\r
+  } else {\r
+    Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
new file mode 100644 (file)
index 0000000..d0c0cc2
--- /dev/null
@@ -0,0 +1,86 @@
+## @file\r
+#  Provides authenticated variable services.\r
+#\r
+#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions\r
+#  of the BSD License which accompanies this distribution.  The\r
+#  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
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = AuthVariableLib\r
+  MODULE_UNI_FILE                = AuthVariableLib.uni\r
+  FILE_GUID                      = B23CF5FB-6FCC-4422-B145-D855DBC05457\r
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = AuthVariableLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+\r
+[Sources]\r
+  AuthVariableLib.c\r
+  AuthService.c\r
+  AuthServiceInternal.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  MemoryAllocationLib\r
+  BaseCryptLib\r
+  PlatformSecureLib\r
+\r
+[Guids]\r
+  ## CONSUMES            ## Variable:L"SetupMode"\r
+  ## PRODUCES            ## Variable:L"SetupMode"\r
+  ## SOMETIMES_CONSUMES  ## Variable:L"PK"\r
+  ## SOMETIMES_CONSUMES  ## Variable:L"KEK"\r
+  ## CONSUMES            ## Variable:L"SecureBoot"\r
+  ## PRODUCES            ## Variable:L"SecureBoot"\r
+  ## CONSUMES            ## Variable:L"SignatureSupport"\r
+  ## PRODUCES            ## Variable:L"SignatureSupport"\r
+  ## PRODUCES            ## Variable:L"VendorKeys"\r
+  gEfiGlobalVariableGuid\r
+\r
+  ## SOMETIMES_CONSUMES  ## Variable:L"DB"\r
+  ## SOMETIMES_CONSUMES  ## Variable:L"DBX"\r
+  ## SOMETIMES_CONSUMES  ## Variable:L"DBT"\r
+  gEfiImageSecurityDatabaseGuid\r
+\r
+  ## CONSUMES            ## Variable:L"SecureBootEnable"\r
+  ## PRODUCES            ## Variable:L"SecureBootEnable"\r
+  gEfiSecureBootEnableDisableGuid\r
+\r
+  ## CONSUMES            ## Variable:L"CustomMode"\r
+  ## PRODUCES            ## Variable:L"CustomMode"\r
+  gEfiCustomModeEnableGuid\r
+\r
+  ## CONSUMES            ## Variable:L"certdb"\r
+  ## PRODUCES            ## Variable:L"certdb"\r
+  gEfiCertDbGuid\r
+\r
+  ## CONSUMES            ## Variable:L"VendorKeysNv"\r
+  ## PRODUCES            ## Variable:L"VendorKeysNv"\r
+  gEfiVendorKeysNvGuid\r
+\r
+  gEfiCertTypeRsa2048Sha256Guid  ## SOMETIMES_CONSUMES   ## GUID  # Unique ID for the type of the certificate.\r
+  gEfiCertPkcs7Guid              ## SOMETIMES_CONSUMES   ## GUID  # Unique ID for the type of the certificate.\r
+  gEfiCertX509Guid               ## SOMETIMES_CONSUMES   ## GUID  # Unique ID for the type of the signature.\r
diff --git a/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni
new file mode 100644 (file)
index 0000000..2f72288
Binary files /dev/null and b/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni differ
index 35a7a51f72fb557c383a6e186173af5f0f40799b..fd74ec18657a87b72c8d9d377cd13509040f6077 100644 (file)
   #\r
   SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.inf\r
   SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.inf\r
-  \r
+\r
+  SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf\r
+\r
 [Components.IA32, Components.X64, Components.IPF]\r
 #  SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf\r
 #  SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf\r
index 4a4595fe4cb3c700eb0b6ac16cb38e3f89d2807f..20f60d4a9e2261877185f89d3603346e71a5edcf 100644 (file)
@@ -121,12 +121,6 @@ typedef struct {
   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbInstance;\r
 } VARIABLE_MODULE_GLOBAL;\r
 \r
-typedef struct {\r
-  EFI_GUID    *Guid;\r
-  CHAR16      *Name;\r
-  UINTN       VariableSize;\r
-} VARIABLE_ENTRY_CONSISTENCY;\r
-\r
 typedef struct {\r
   LIST_ENTRY  Link;\r
   EFI_GUID    Guid;\r