]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Library/AuthVariableLib/AuthService.c
SecurityPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / SecurityPkg / Library / AuthVariableLib / AuthService.c
index 6e1e284801124cb71c1982aea8ee27becd7d3968..7493a2ed9cf8c44099bad3f7c0f2fa5d91b9ee55 100644 (file)
   They will do basic validation for authentication data structure, then call crypto library\r
   to verify the signature.\r
 \r
-Copyright (c) 2009 - 2016, 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
+Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -36,6 +30,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 //\r
 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
 \r
+CONST UINT8 mSha256OidValue[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 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
@@ -134,50 +130,6 @@ AuthServiceInternalUpdateVariable (
            );\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
@@ -297,306 +249,6 @@ InCustomMode (
   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
@@ -1144,7 +796,7 @@ IsDeleteAuthVariable (
 }\r
 \r
 /**\r
-  Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\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
@@ -1161,9 +813,9 @@ IsDeleteAuthVariable (
 \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
+                                          EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS or EFI_VARIABLE_TIME_BASED_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
+  @return EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_TIME_BASED_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
@@ -1179,22 +831,8 @@ ProcessVariable (
   )\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
@@ -1206,7 +844,7 @@ ProcessVariable (
 \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
+    // Allow the delete operation of common authenticated variable(AT or AW) at user physical presence.\r
     //\r
     Status = AuthServiceInternalUpdateVariable (\r
               VariableName,\r
@@ -1230,25 +868,15 @@ ProcessVariable (
   }\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
+  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    //\r
+    // Reject Counter Based Auth Variable processing request.\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    //\r
+    // Process Time-based Authenticated variable.\r
+    //\r
     return VerifyTimeBasedPayloadAndUpdate (\r
              VariableName,\r
              VendorGuid,\r
@@ -1260,117 +888,20 @@ ProcessVariable (
              );\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
+  if ((OrgVariableInfo.Data != NULL) &&\r
+     ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) {\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
+  // Not authenticated variable, just update variable as usual.\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
+  Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);\r
+  return Status;\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
@@ -1527,6 +1058,89 @@ AuthServiceInternalCompareTimeStamp (
   return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
 }\r
 \r
+/**\r
+  Calculate SHA256 digest of SignerCert CommonName + ToplevelCert tbsCertificate\r
+  SignerCert and ToplevelCert are inside the signer certificate chain.\r
+\r
+  @param[in]  SignerCert          A pointer to SignerCert data.\r
+  @param[in]  SignerCertSize      Length of SignerCert data.\r
+  @param[in]  TopLevelCert        A pointer to TopLevelCert data.\r
+  @param[in]  TopLevelCertSize    Length of TopLevelCert data.\r
+  @param[out] Sha256Digest       Sha256 digest calculated.\r
+\r
+  @return EFI_ABORTED          Digest process failed.\r
+  @return EFI_SUCCESS          SHA256 Digest is succesfully calculated.\r
+\r
+**/\r
+EFI_STATUS\r
+CalculatePrivAuthVarSignChainSHA256Digest(\r
+  IN     UINT8            *SignerCert,\r
+  IN     UINTN            SignerCertSize,\r
+  IN     UINT8            *TopLevelCert,\r
+  IN     UINTN            TopLevelCertSize,\r
+  OUT    UINT8            *Sha256Digest\r
+  )\r
+{\r
+  UINT8                   *TbsCert;\r
+  UINTN                   TbsCertSize;\r
+  CHAR8                   CertCommonName[128];\r
+  UINTN                   CertCommonNameSize;\r
+  BOOLEAN                 CryptoStatus;\r
+  EFI_STATUS              Status;\r
+\r
+  CertCommonNameSize = sizeof(CertCommonName);\r
+\r
+  //\r
+  // Get SignerCert CommonName\r
+  //\r
+  Status = X509GetCommonName(SignerCert, SignerCertSize, CertCommonName, &CertCommonNameSize);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG((DEBUG_INFO, "%a Get SignerCert CommonName failed with status %x\n", __FUNCTION__, Status));\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  //\r
+  // Get TopLevelCert tbsCertificate\r
+  //\r
+  if (!X509GetTBSCert(TopLevelCert, TopLevelCertSize, &TbsCert, &TbsCertSize)) {\r
+    DEBUG((DEBUG_INFO, "%a Get Top-level Cert tbsCertificate failed!\n", __FUNCTION__));\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  //\r
+  // Digest SignerCert CN + TopLevelCert tbsCertificate\r
+  //\r
+  ZeroMem (Sha256Digest, SHA256_DIGEST_SIZE);\r
+  CryptoStatus = Sha256Init (mHashCtx);\r
+  if (!CryptoStatus) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  //\r
+  // '\0' is forced in CertCommonName. No overflow issue\r
+  //\r
+  CryptoStatus = Sha256Update (\r
+                   mHashCtx,\r
+                   CertCommonName,\r
+                   AsciiStrLen (CertCommonName)\r
+                   );\r
+  if (!CryptoStatus) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  CryptoStatus = Sha256Update (mHashCtx, TbsCert, TbsCertSize);\r
+  if (!CryptoStatus) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  CryptoStatus  = Sha256Final (mHashCtx, Sha256Digest);\r
+  if (!CryptoStatus) {\r
+    return EFI_ABORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Find matching signer's certificates for common authenticated variable\r
   by corresponding VariableName and VendorGuid from "certdb" or "certdbv".\r
@@ -1683,7 +1297,7 @@ GetCertsFromDb (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  \r
+\r
   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
     //\r
     // Get variable "certdb".\r
@@ -1735,7 +1349,7 @@ GetCertsFromDb (
 \r
 /**\r
   Delete matching signer's certificates when deleting common authenticated\r
-  variable by corresponding VariableName and VendorGuid from "certdb" or \r
+  variable by corresponding VariableName and VendorGuid from "certdb" or\r
   "certdbv" according to authenticated variable attributes.\r
 \r
   @param[in]  VariableName   Name of authenticated Variable.\r
@@ -1870,13 +1484,16 @@ DeleteCertsFromDb (
 /**\r
   Insert signer's certificates for common authenticated variable with VariableName\r
   and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to\r
-  time based authenticated variable attributes.\r
+  time based authenticated variable attributes. CertData is the SHA256 digest of\r
+  SignerCert CommonName + TopLevelCert tbsCertificate.\r
 \r
-  @param[in]  VariableName   Name of authenticated Variable.\r
-  @param[in]  VendorGuid     Vendor GUID of authenticated Variable.\r
-  @param[in]  Attributes     Attributes of authenticated variable.\r
-  @param[in]  CertData       Pointer to signer's certificates.\r
-  @param[in]  CertDataSize   Length of CertData in bytes.\r
+  @param[in]  VariableName      Name of authenticated Variable.\r
+  @param[in]  VendorGuid        Vendor GUID of authenticated Variable.\r
+  @param[in]  Attributes        Attributes of authenticated variable.\r
+  @param[in]  SignerCert        Signer certificate data.\r
+  @param[in]  SignerCertSize    Length of signer certificate.\r
+  @param[in]  TopLevelCert      Top-level certificate data.\r
+  @param[in]  TopLevelCertSize  Length of top-level certificate.\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
@@ -1890,8 +1507,10 @@ InsertCertsToDb (
   IN     CHAR16           *VariableName,\r
   IN     EFI_GUID         *VendorGuid,\r
   IN     UINT32           Attributes,\r
-  IN     UINT8            *CertData,\r
-  IN     UINTN            CertDataSize\r
+  IN     UINT8            *SignerCert,\r
+  IN     UINTN            SignerCertSize,\r
+  IN     UINT8            *TopLevelCert,\r
+  IN     UINTN            TopLevelCertSize\r
   )\r
 {\r
   EFI_STATUS              Status;\r
@@ -1902,10 +1521,12 @@ InsertCertsToDb (
   UINT32                  NewCertDbSize;\r
   UINT32                  CertNodeSize;\r
   UINT32                  NameSize;\r
+  UINT32                  CertDataSize;\r
   AUTH_CERT_DB_DATA       *Ptr;\r
   CHAR16                  *DbName;\r
+  UINT8                   Sha256Digest[SHA256_DIGEST_SIZE];\r
 \r
-  if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {\r
+  if ((VariableName == NULL) || (VendorGuid == NULL) || (SignerCert == NULL) ||(TopLevelCert == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
@@ -1965,11 +1586,24 @@ InsertCertsToDb (
   // Construct new data content of variable "certdb" or "certdbv".\r
   //\r
   NameSize      = (UINT32) StrLen (VariableName);\r
+  CertDataSize  = sizeof(Sha256Digest);\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
+\r
+  Status = CalculatePrivAuthVarSignChainSHA256Digest(\r
+             SignerCert,\r
+             SignerCertSize,\r
+             TopLevelCert,\r
+             TopLevelCertSize,\r
+             Sha256Digest\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   NewCertDb     = (UINT8*) mCertDbStore;\r
 \r
   //\r
@@ -1997,7 +1631,7 @@ InsertCertsToDb (
 \r
   CopyMem (\r
     (UINT8 *) Ptr +  sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),\r
-    CertData,\r
+    Sha256Digest,\r
     CertDataSize\r
     );\r
 \r
@@ -2100,7 +1734,7 @@ CleanCertsFromDb (
                                        &AuthVariableInfo\r
                                        );\r
 \r
-      if (EFI_ERROR(Status)) {\r
+      if (EFI_ERROR(Status) || (AuthVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
         Status      = DeleteCertsFromDb(\r
                         VariableName,\r
                         &AuthVarGuid,\r
@@ -2179,20 +1813,30 @@ VerifyTimeBasedPayload (
   UINTN                            NewDataSize;\r
   UINT8                            *Buffer;\r
   UINTN                            Length;\r
-  UINT8                            *RootCert;\r
-  UINTN                            RootCertSize;\r
+  UINT8                            *TopLevelCert;\r
+  UINTN                            TopLevelCertSize;\r
+  UINT8                            *TrustedCert;\r
+  UINTN                            TrustedCertSize;\r
   UINT8                            *SignerCerts;\r
   UINTN                            CertStackSize;\r
   UINT8                            *CertsInCertDb;\r
   UINT32                           CertsSizeinDb;\r
+  UINT8                            Sha256Digest[SHA256_DIGEST_SIZE];\r
+  EFI_CERT_DATA                    *CertDataPtr;\r
 \r
+  //\r
+  // 1. TopLevelCert is the top-level issuer certificate in signature Signer Cert Chain\r
+  // 2. TrustedCert is the certificate which firmware trusts. It could be saved in protected\r
+  //     storage or PK payload on PK init\r
+  //\r
   VerifyStatus           = FALSE;\r
   CertData               = NULL;\r
   NewData                = NULL;\r
   Attr                   = Attributes;\r
   SignerCerts            = NULL;\r
-  RootCert               = NULL;\r
+  TopLevelCert           = NULL;\r
   CertsInCertDb          = NULL;\r
+  CertDataPtr            = NULL;\r
 \r
   //\r
   // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is\r
@@ -2244,6 +1888,29 @@ VerifyTimeBasedPayload (
   SigData = CertData->AuthInfo.CertData;\r
   SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));\r
 \r
+  //\r
+  // SignedData.digestAlgorithms shall contain the digest algorithm used when preparing the\r
+  // signature. Only a digest algorithm of SHA-256 is accepted.\r
+  //\r
+  //    According to PKCS#7 Definition:\r
+  //        SignedData ::= SEQUENCE {\r
+  //            version Version,\r
+  //            digestAlgorithms DigestAlgorithmIdentifiers,\r
+  //            contentInfo ContentInfo,\r
+  //            .... }\r
+  //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm\r
+  //    in VARIABLE_AUTHENTICATION_2 descriptor.\r
+  //    This field has the fixed offset (+13) and be calculated based on two bytes of length encoding.\r
+  //\r
+  if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    if (SigDataSize >= (13 + sizeof (mSha256OidValue))) {\r
+      if (((*(SigData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) ||\r
+           (CompareMem (SigData + 13, &mSha256OidValue, sizeof (mSha256OidValue)) != 0)) {\r
+          return EFI_SECURITY_VIOLATION;\r
+        }\r
+    }\r
+  }\r
+\r
   //\r
   // Find out the new data payload which follows Pkcs7 SignedData directly.\r
   //\r
@@ -2300,8 +1967,8 @@ VerifyTimeBasedPayload (
                      SigDataSize,\r
                      &SignerCerts,\r
                      &CertStackSize,\r
-                     &RootCert,\r
-                     &RootCertSize\r
+                     &TopLevelCert,\r
+                     &TopLevelCertSize\r
                      );\r
     if (!VerifyStatus) {\r
       goto Exit;\r
@@ -2323,8 +1990,8 @@ VerifyTimeBasedPayload (
     }\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
+    if ((TopLevelCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||\r
+        (CompareMem (Cert->SignatureData, TopLevelCert, TopLevelCertSize) != 0)) {\r
       VerifyStatus = FALSE;\r
       goto Exit;\r
     }\r
@@ -2335,8 +2002,8 @@ VerifyTimeBasedPayload (
     VerifyStatus = Pkcs7Verify (\r
                      SigData,\r
                      SigDataSize,\r
-                     RootCert,\r
-                     RootCertSize,\r
+                     TopLevelCert,\r
+                     TopLevelCertSize,\r
                      NewData,\r
                      NewDataSize\r
                      );\r
@@ -2369,8 +2036,8 @@ VerifyTimeBasedPayload (
           //\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
+          TrustedCert      = Cert->SignatureData;\r
+          TrustedCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
 \r
           //\r
           // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
@@ -2378,8 +2045,8 @@ VerifyTimeBasedPayload (
           VerifyStatus = Pkcs7Verify (\r
                            SigData,\r
                            SigDataSize,\r
-                           RootCert,\r
-                           RootCertSize,\r
+                           TrustedCert,\r
+                           TrustedCertSize,\r
                            NewData,\r
                            NewDataSize\r
                            );\r
@@ -2403,8 +2070,8 @@ VerifyTimeBasedPayload (
                      SigDataSize,\r
                      &SignerCerts,\r
                      &CertStackSize,\r
-                     &RootCert,\r
-                     &RootCertSize\r
+                     &TopLevelCert,\r
+                     &TopLevelCertSize\r
                      );\r
     if (!VerifyStatus) {\r
       goto Exit;\r
@@ -2423,17 +2090,37 @@ VerifyTimeBasedPayload (
         goto Exit;\r
       }\r
 \r
-      if ((CertStackSize != CertsSizeinDb) ||\r
-          (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {\r
-        goto Exit;\r
+      if (CertsSizeinDb == SHA256_DIGEST_SIZE) {\r
+        //\r
+        // Check hash of signer cert CommonName + Top-level issuer tbsCertificate against data in CertDb\r
+        //\r
+        CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1);\r
+        Status = CalculatePrivAuthVarSignChainSHA256Digest(\r
+                   CertDataPtr->CertDataBuffer,\r
+                   ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)),\r
+                   TopLevelCert,\r
+                   TopLevelCertSize,\r
+                   Sha256Digest\r
+                   );\r
+        if (EFI_ERROR(Status) || CompareMem (Sha256Digest, CertsInCertDb, CertsSizeinDb) != 0){\r
+          goto Exit;\r
+        }\r
+      } else {\r
+         //\r
+         // Keep backward compatible with previous solution which saves whole signer certs stack in CertDb\r
+         //\r
+         if ((CertStackSize != CertsSizeinDb) ||\r
+             (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {\r
+              goto Exit;\r
+         }\r
       }\r
     }\r
 \r
     VerifyStatus = Pkcs7Verify (\r
                      SigData,\r
                      SigDataSize,\r
-                     RootCert,\r
-                     RootCertSize,\r
+                     TopLevelCert,\r
+                     TopLevelCertSize,\r
                      NewData,\r
                      NewDataSize\r
                      );\r
@@ -2443,9 +2130,18 @@ VerifyTimeBasedPayload (
 \r
     if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {\r
       //\r
-      // Insert signer's certificates when adding a new common authenticated variable.\r
+      // When adding a new common authenticated variable, always save Hash of cn of signer cert + tbsCertificate of Top-level issuer\r
       //\r
-      Status = InsertCertsToDb (VariableName, VendorGuid, Attributes, SignerCerts, CertStackSize);\r
+      CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1);\r
+      Status = InsertCertsToDb (\r
+                 VariableName,\r
+                 VendorGuid,\r
+                 Attributes,\r
+                 CertDataPtr->CertDataBuffer,\r
+                 ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)),\r
+                 TopLevelCert,\r
+                 TopLevelCertSize\r
+                 );\r
       if (EFI_ERROR (Status)) {\r
         VerifyStatus = FALSE;\r
         goto Exit;\r
@@ -2454,16 +2150,16 @@ VerifyTimeBasedPayload (
   } 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
+    TrustedCert     = Cert->SignatureData;\r
+    TrustedCertSize = 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
+                     TrustedCert,\r
+                     TrustedCertSize,\r
                      NewData,\r
                      NewDataSize\r
                      );\r
@@ -2474,7 +2170,7 @@ VerifyTimeBasedPayload (
 Exit:\r
 \r
   if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {\r
-    Pkcs7FreeSigners (RootCert);\r
+    Pkcs7FreeSigners (TopLevelCert);\r
     Pkcs7FreeSigners (SignerCerts);\r
   }\r
 \r