]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
1. Initialize certdb variable with correct value of list size.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / AuthService.c
index 6d41de904b698e8842b1ac99f03603badf022286..fd5bf12bba253d7e3c1c8f41cbcb3df69ff5f05d 100644 (file)
@@ -2,6 +2,19 @@
   Implement authentication services for the authenticated variable\r
   service in UEFI2.2.\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
+\r
+  ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do\r
+  variable authentication.\r
+\r
+  VerifyTimeBasedPayload() and VerifyCounterBasedPayload() are sub function to do verification.\r
+  They will do basic validation for authentication data structure, then call crypto library\r
+  to verify the signature.\r
+\r
 Copyright (c) 2009 - 2012, 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
@@ -21,6 +34,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 ///\r
 UINT8    mPubKeyStore[MAX_KEYDB_SIZE];\r
 UINT32   mPubKeyNumber;\r
+UINT8    mCertDbStore[MAX_CERTDB_SIZE];\r
 UINT32   mPlatformMode;\r
 EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};\r
 //\r
@@ -241,68 +255,46 @@ AutenticatedVariableServiceInitialize (
   }\r
   \r
   //\r
-  // Check "SetupMode" variable's existence.\r
-  // If it doesn't exist, check PK database's existence to determine the value.\r
-  // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+  // Create "SetupMode" varable with BS+RT attribute set.\r
   //\r
-  Status = FindVariable (\r
+  FindVariable (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  if (PkVariable.CurrPtr == NULL) {\r
+    mPlatformMode = SETUP_MODE;\r
+  } else {\r
+    mPlatformMode = USER_MODE;\r
+  }\r
+  Status = UpdateVariable (\r
              EFI_SETUP_MODE_NAME,\r
              &gEfiGlobalVariableGuid,\r
+             &mPlatformMode,\r
+             sizeof(UINT8),\r
+             EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+             0,\r
+             0,\r
              &Variable,\r
-             &mVariableModuleGlobal->VariableGlobal,\r
-             FALSE\r
+             NULL\r
              );\r
-\r
-  if (Variable.CurrPtr == NULL) {\r
-    if (PkVariable.CurrPtr == NULL) {\r
-      mPlatformMode = SETUP_MODE;\r
-    } else {\r
-      mPlatformMode = USER_MODE;\r
-    }\r
-\r
-    VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
-    Status  = UpdateVariable (\r
-                EFI_SETUP_MODE_NAME,\r
-                &gEfiGlobalVariableGuid,\r
-                &mPlatformMode,\r
-                sizeof(UINT8),\r
-                VarAttr,\r
-                0,\r
-                0,\r
-                &Variable,\r
-                NULL\r
-                );\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-  } else {\r
-    mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
+  \r
   //\r
-  // Check "SignatureSupport" variable's existence.\r
-  // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+  // Create "SignatureSupport" varable with BS+RT attribute set.\r
   //\r
-  Status = FindVariable (\r
-             EFI_SIGNATURE_SUPPORT_NAME,\r
-             &gEfiGlobalVariableGuid,\r
-             &Variable,\r
-             &mVariableModuleGlobal->VariableGlobal,\r
-             FALSE\r
-             );\r
-\r
-  if (Variable.CurrPtr == NULL) {\r
-    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
-    Status  = UpdateVariable (\r
-                EFI_SIGNATURE_SUPPORT_NAME,\r
-                &gEfiGlobalVariableGuid,\r
-                mSignatureSupport,\r
-                sizeof(mSignatureSupport),\r
-                VarAttr,\r
-                0,\r
-                0,\r
-                &Variable,\r
-                NULL\r
-                );\r
+  FindVariable (EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
+  Status  = UpdateVariable (\r
+              EFI_SIGNATURE_SUPPORT_NAME,\r
+              &gEfiGlobalVariableGuid,\r
+              mSignatureSupport,\r
+              sizeof(mSignatureSupport),\r
+              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+              0,\r
+              0,\r
+              &Variable,\r
+              NULL\r
+              );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
 \r
   //\r
@@ -310,7 +302,7 @@ AutenticatedVariableServiceInitialize (
   // 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_MODE_DISABLE;\r
+  SecureBootEnable = SECURE_BOOT_DISABLE;\r
   FindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
   if (Variable.CurrPtr != NULL) {\r
     SecureBootEnable = *(GetVariableDataPtr (Variable.CurrPtr));\r
@@ -318,7 +310,7 @@ AutenticatedVariableServiceInitialize (
     //\r
     // "SecureBootEnable" not exist, initialize it in USER_MODE.\r
     //\r
-    SecureBootEnable = SECURE_BOOT_MODE_ENABLE;\r
+    SecureBootEnable = SECURE_BOOT_ENABLE;\r
     Status = UpdateVariable (\r
                EFI_SECURE_BOOT_ENABLE_NAME,\r
                &gEfiSecureBootEnableDisableGuid,\r
@@ -335,6 +327,9 @@ AutenticatedVariableServiceInitialize (
     }\r
   }\r
 \r
+  //\r
+  // Create "SecureBoot" varable with BS+RT attribute set.\r
+  //\r
   if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {\r
     SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
   } else {\r
@@ -346,7 +341,7 @@ AutenticatedVariableServiceInitialize (
              &gEfiGlobalVariableGuid,\r
              &SecureBootMode,\r
              sizeof (UINT8),\r
-             EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
+             EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
              0,\r
              0,\r
              &Variable,\r
@@ -404,7 +399,7 @@ AutenticatedVariableServiceInitialize (
 \r
   if (Variable.CurrPtr == NULL) {\r
     VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
-    ListSize = 0;\r
+    ListSize = sizeof (UINT32);\r
     Status   = UpdateVariable (\r
                  EFI_CERT_DB_NAME,\r
                  &gEfiCertDbGuid,\r
@@ -416,7 +411,9 @@ AutenticatedVariableServiceInitialize (
                  &Variable,\r
                  NULL\r
                  );\r
-\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }  \r
 \r
   return Status;\r
@@ -502,6 +499,12 @@ AddPubKeyInStore (
   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
@@ -641,22 +644,12 @@ UpdatePlatformMode (
     return Status;\r
   }\r
 \r
-  mPlatformMode  = Mode;\r
-  VarAttr        = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
-  Status         = UpdateVariable (\r
-                     EFI_SETUP_MODE_NAME,\r
-                     &gEfiGlobalVariableGuid,\r
-                     &mPlatformMode,\r
-                     sizeof(UINT8),\r
-                     VarAttr,\r
-                     0,\r
-                     0,\r
-                     &Variable,\r
-                     NULL\r
-                     );\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+  //\r
+  // Update the value of SetupMode variable by a simple mem copy, this could avoid possible\r
+  // variable storage reclaim at runtime.\r
+  //\r
+  mPlatformMode = (UINT8) Mode;\r
+  CopyMem (GetVariableDataPtr (Variable.CurrPtr), &mPlatformMode, sizeof(UINT8));\r
 \r
   if (AtRuntime ()) {\r
     //\r
@@ -756,7 +749,7 @@ UpdatePlatformMode (
 }\r
 \r
 /**\r
-  Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK variable.\r
+  Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx variable.\r
 \r
   @param[in]  VariableName                Name of Variable to be check.\r
   @param[in]  VendorGuid                  Variable vendor GUID.\r
@@ -780,6 +773,9 @@ CheckSignatureListFormat(
   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
@@ -789,7 +785,9 @@ CheckSignatureListFormat(
 \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
+  } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0) ||\r
+             (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && \r
+              (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0 || StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))){\r
     IsPk = FALSE;\r
   } else {\r
     return EFI_SUCCESS;\r
@@ -798,6 +796,7 @@ CheckSignatureListFormat(
   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
@@ -829,6 +828,24 @@ CheckSignatureListFormat(
       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
@@ -852,6 +869,13 @@ CheckSignatureListFormat(
 /**\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
@@ -879,150 +903,25 @@ ProcessVarWithPk (
   )\r
 {\r
   EFI_STATUS                  Status;\r
-  VARIABLE_POINTER_TRACK      PkVariable;\r
-  EFI_SIGNATURE_LIST          *OldPkList;\r
-  EFI_SIGNATURE_DATA          *OldPkData;\r
-  EFI_VARIABLE_AUTHENTICATION *CertData;\r
-  BOOLEAN                     TimeBase;\r
   BOOLEAN                     Del;\r
   UINT8                       *Payload;\r
   UINTN                       PayloadSize;\r
-  UINT64                      MonotonicCount;\r
-  EFI_TIME                    *TimeStamp;\r
 \r
-  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 || \r
+      (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
     //\r
-    // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
+    // PK, KEK and db/dbx should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
+    // authenticated variable.\r
     //\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {\r
-\r
-    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-      //\r
-      // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.\r
-      //\r
-      TimeBase = TRUE;\r
-    } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-      //\r
-      // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.\r
-      //\r
-      TimeBase = FALSE;\r
-    } else {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-    if (TimeBase) {\r
-      //\r
-      // Verify against X509 Cert PK.\r
-      //\r
-      Del    = FALSE;\r
-      Status = VerifyTimeBasedPayload (\r
-                 VariableName,\r
-                 VendorGuid,\r
-                 Data,\r
-                 DataSize,\r
-                 Variable,\r
-                 Attributes,\r
-                 AuthVarTypePk,\r
-                 &Del\r
-                 );\r
-      if (!EFI_ERROR (Status)) {\r
-        //\r
-        // If delete PK in user mode, need change to setup mode.\r
-        //\r
-        if (Del && IsPk) {\r
-          Status = UpdatePlatformMode (SETUP_MODE);\r
-        }\r
-      }\r
-      return Status;\r
-    } else {\r
-      //\r
-      // Verify against RSA2048 Cert PK.\r
-      //\r
-      CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
-      if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
-        //\r
-        // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
-        //\r
-        return EFI_SECURITY_VIOLATION;\r
-      }\r
-      //\r
-      // Get platform key from variable.\r
-      //\r
-      Status = FindVariable (\r
-                 EFI_PLATFORM_KEY_NAME,\r
-                 &gEfiGlobalVariableGuid,\r
-                 &PkVariable,\r
-                 &mVariableModuleGlobal->VariableGlobal,\r
-                 FALSE\r
-                 );\r
-      ASSERT_EFI_ERROR (Status);\r
-\r
-      OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
-      OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
-      Status    = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);\r
-      if (!EFI_ERROR (Status)) {\r
-        Status = CheckSignatureListFormat(\r
-                   VariableName,\r
-                   VendorGuid,\r
-                   (UINT8*)Data + AUTHINFO_SIZE,\r
-                   DataSize - AUTHINFO_SIZE);\r
-        if (EFI_ERROR (Status)) {\r
-          return Status;\r
-        }\r
-        \r
-        Status = UpdateVariable (\r
-                   VariableName,\r
-                   VendorGuid,\r
-                   (UINT8*)Data + AUTHINFO_SIZE,\r
-                   DataSize - AUTHINFO_SIZE,\r
-                   Attributes,\r
-                   0,\r
-                   CertData->MonotonicCount,\r
-                   Variable,\r
-                   NULL\r
-                   );\r
-\r
-        if (!EFI_ERROR (Status)) {\r
-          //\r
-          // If delete PK in user mode, need change to setup mode.\r
-          //\r
-          if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
-            Status = UpdatePlatformMode (SETUP_MODE);\r
-          }\r
-        }\r
-      }\r
-    }\r
-  } else {\r
-    //\r
-    // Process PK or KEK in Setup mode or Custom Secure Boot mode.\r
-    //\r
-    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-      //\r
-      // Time-based Authentication descriptor.\r
-      //\r
-      MonotonicCount = 0;\r
-      TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;\r
-      Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
-      PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
-    } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-      //\r
-      // Counter-based Authentication descriptor.\r
-      //\r
-      MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;\r
-      TimeStamp = NULL;\r
-      Payload = (UINT8*) Data + AUTHINFO_SIZE;\r
-      PayloadSize = DataSize - AUTHINFO_SIZE;\r
-    } else {\r
-      //\r
-      // No Authentication descriptor.\r
-      //\r
-      MonotonicCount = 0;\r
-      TimeStamp = NULL;\r
-      Payload = Data;\r
-      PayloadSize = DataSize;\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
@@ -1037,24 +936,52 @@ ProcessVarWithPk (
                PayloadSize,\r
                Attributes,\r
                0,\r
-               MonotonicCount,\r
+               0,\r
                Variable,\r
-               TimeStamp\r
+               &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
                );\r
+  } else if (mPlatformMode == USER_MODE) {\r
+    //\r
+    // Verify against X509 Cert in PK database.\r
+    //\r
+    Status = VerifyTimeBasedPayload (\r
+               VariableName,\r
+               VendorGuid,\r
+               Data,\r
+               DataSize,\r
+               Variable,\r
+               Attributes,\r
+               AuthVarTypePk,\r
+               &Del\r
+               );\r
+  } else {\r
+    //\r
+    // Verify against the certificate in data payload.\r
+    //\r
+    Status = VerifyTimeBasedPayload (\r
+               VariableName,\r
+               VendorGuid,\r
+               Data,\r
+               DataSize,\r
+               Variable,\r
+               Attributes,\r
+               AuthVarTypePayload,\r
+               &Del\r
+               );\r
+  }\r
 \r
-    if (IsPk) {\r
-      if (PayloadSize != 0) {\r
-        //\r
-        // If enroll PK in setup mode, need change to user mode.\r
-        //\r
-        Status = UpdatePlatformMode (USER_MODE);\r
-      } else {\r
-        //\r
-        // If delete PK in custom mode, need change to setup mode.\r
-        //\r
-        UpdatePlatformMode (SETUP_MODE);\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
@@ -1063,6 +990,13 @@ ProcessVarWithPk (
 /**\r
   Process variable with key exchange key for verification.\r
 \r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode, and datasize and data are external input.\r
+  This function will do basic validation, before parse the data.\r
+  This function will parse the authentication carefully to avoid security issues, like\r
+  buffer overflow, integer overflow.\r
+  This function will check attribute carefully to avoid authentication bypass.\r
+\r
   @param[in]  VariableName                Name of Variable to be found.\r
   @param[in]  VendorGuid                  Variable vendor GUID.\r
   @param[in]  Data                        Data pointer.\r
@@ -1088,149 +1022,45 @@ ProcessVarWithKek (
   )\r
 {\r
   EFI_STATUS                      Status;\r
-  VARIABLE_POINTER_TRACK          KekVariable;\r
-  EFI_SIGNATURE_LIST              *KekList;\r
-  EFI_SIGNATURE_DATA              *KekItem;\r
-  UINT32                          KekCount;\r
-  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
-  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
-  BOOLEAN                         IsFound;\r
-  UINT32                          Index;\r
-  UINT32                          KekDataSize;\r
   UINT8                           *Payload;\r
   UINTN                           PayloadSize;\r
-  UINT64                          MonotonicCount;\r
-  EFI_TIME                        *TimeStamp;\r
 \r
-  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||\r
+      (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
     //\r
-    // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute.\r
+    // DB and DBX should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based\r
+    // authenticated variable.\r
     //\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   Status = EFI_SUCCESS;\r
   if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {\r
-    if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) &&\r
-        ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0)){\r
-      //\r
-      // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS or\r
-      // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute.\r
-      //\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-\r
-    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-      //\r
-      // Time-based, verify against X509 Cert KEK.\r
-      //\r
-      return VerifyTimeBasedPayload (\r
-               VariableName,\r
-               VendorGuid,\r
-               Data,\r
-               DataSize,\r
-               Variable,\r
-               Attributes,\r
-               AuthVarTypeKek,\r
-               NULL\r
-               );\r
-    } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-      //\r
-      // Counter-based, verify against RSA2048 Cert KEK.\r
-      //\r
-      CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
-      CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
-      if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
-        //\r
-        // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
-        //\r
-        return EFI_SECURITY_VIOLATION;\r
-      }\r
-      //\r
-      // Get KEK database from variable.\r
-      //\r
-      Status = FindVariable (\r
-                 EFI_KEY_EXCHANGE_KEY_NAME,\r
-                 &gEfiGlobalVariableGuid,\r
-                 &KekVariable,\r
-                 &mVariableModuleGlobal->VariableGlobal,\r
-                 FALSE\r
-                 );\r
-      ASSERT_EFI_ERROR (Status);\r
-\r
-      KekDataSize = KekVariable.CurrPtr->DataSize;\r
-      KekList     = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
-\r
-      //\r
-      // Enumerate all Kek items in this list to verify the variable certificate data.\r
-      // If anyone is authenticated successfully, it means the variable is correct!\r
-      //\r
-      IsFound   = FALSE;\r
-      while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
-        if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
-          KekItem   = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
-          KekCount  = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
-          for (Index = 0; Index < KekCount; Index++) {\r
-            if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
-              IsFound = TRUE;\r
-              break;\r
-            }\r
-            KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
-          }\r
-        }\r
-        KekDataSize -= KekList->SignatureListSize;\r
-        KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
-      }\r
-\r
-      if (!IsFound) {\r
-        return EFI_SECURITY_VIOLATION;\r
-      }\r
-\r
-      Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);\r
-      if (!EFI_ERROR (Status)) {\r
-        Status = UpdateVariable (\r
-                   VariableName,\r
-                   VendorGuid,\r
-                   (UINT8*)Data + AUTHINFO_SIZE,\r
-                   DataSize - AUTHINFO_SIZE,\r
-                   Attributes,\r
-                   0,\r
-                   CertData->MonotonicCount,\r
-                   Variable,\r
-                   NULL\r
-                   );\r
-      }\r
-    }\r
+    //\r
+    // Time-based, verify against X509 Cert KEK.\r
+    //\r
+    return VerifyTimeBasedPayload (\r
+             VariableName,\r
+             VendorGuid,\r
+             Data,\r
+             DataSize,\r
+             Variable,\r
+             Attributes,\r
+             AuthVarTypeKek,\r
+             NULL\r
+             );\r
   } else {\r
     //\r
     // If in setup mode or custom secure boot mode, no authentication needed.\r
     //\r
-    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-      //\r
-      // Time-based Authentication descriptor.\r
-      //\r
-      MonotonicCount = 0;\r
-      TimeStamp = &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp;\r
-      Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
-      PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
-    } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
-      //\r
-      // Counter-based Authentication descriptor.\r
-      //\r
-      MonotonicCount = ((EFI_VARIABLE_AUTHENTICATION *) Data)->MonotonicCount;\r
-      TimeStamp = NULL;\r
-      Payload = (UINT8*) Data + AUTHINFO_SIZE;\r
-      PayloadSize = DataSize - AUTHINFO_SIZE;\r
-    } else {\r
-      //\r
-      // No Authentication descriptor.\r
-      //\r
-      MonotonicCount = 0;\r
-      TimeStamp = NULL;\r
-      Payload = Data;\r
-      PayloadSize = DataSize;\r
-    }\r
+    Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);\r
+    PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
 \r
+    Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    \r
     Status = UpdateVariable (\r
                VariableName,\r
                VendorGuid,\r
@@ -1238,9 +1068,9 @@ ProcessVarWithKek (
                PayloadSize,\r
                Attributes,\r
                0,\r
-               MonotonicCount,\r
+               0,\r
                Variable,\r
-               TimeStamp\r
+               &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp\r
                );\r
   }\r
 \r
@@ -1250,6 +1080,13 @@ ProcessVarWithKek (
 /**\r
   Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
 \r
+  Caution: This function may receive untrusted input.\r
+  This function may be invoked in SMM mode, and datasize and data are external input.\r
+  This function will do basic validation, before parse the data.\r
+  This function will parse the authentication carefully to avoid security issues, like\r
+  buffer overflow, integer overflow.\r
+  This function will check attribute carefully to avoid authentication bypass.\r
+\r
   @param[in]  VariableName                Name of Variable to be found.\r
   @param[in]  VendorGuid                  Variable vendor GUID.\r
 \r
@@ -1399,6 +1236,9 @@ ProcessVariable (
     // Update public key database variable if need.\r
     //\r
     KeyIndex = AddPubKeyInStore (PubKey);\r
+    if (KeyIndex == 0) {\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
   }\r
 \r
   //\r
@@ -1827,10 +1667,7 @@ DeleteCertsFromDb (
   // Construct new data content of variable "certdb".\r
   //\r
   NewCertDbSize = (UINT32) DataSize - CertNodeSize;\r
-  NewCertDb     = AllocateZeroPool (NewCertDbSize);\r
-  if (NewCertDb == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
+  NewCertDb     = (UINT8*) mCertDbStore;\r
 \r
   //\r
   // Copy the DB entries before deleting node.\r
@@ -1867,7 +1704,6 @@ DeleteCertsFromDb (
                NULL\r
                );\r
 \r
-  FreePool (NewCertDb);\r
   return Status;\r
 }\r
 \r
@@ -1956,11 +1792,11 @@ InsertCertsToDb (
   //\r
   NameSize      = (UINT32) StrLen (VariableName);\r
   CertNodeSize  = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16); \r
-  NewCertDbSize = (UINT32) DataSize + CertNodeSize;                  \r
-  NewCertDb     = AllocateZeroPool (NewCertDbSize);\r
-  if (NewCertDb == NULL) {\r
+  NewCertDbSize = (UINT32) DataSize + CertNodeSize;\r
+  if (NewCertDbSize > MAX_CERTDB_SIZE) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+  NewCertDb     = (UINT8*) mCertDbStore;\r
 \r
   //\r
   // Copy the DB entries before deleting node.\r
@@ -2007,13 +1843,18 @@ InsertCertsToDb (
                NULL\r
                );\r
 \r
-  FreePool (NewCertDb);\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
@@ -2021,7 +1862,7 @@ InsertCertsToDb (
                                           data, this value contains the required size.\r
   @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
   @param[in]  Attributes                  Attribute value of the variable.\r
-  @param[in]  AuthVarType                 Verify against PK or KEK database or private database.\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
@@ -2179,7 +2020,7 @@ VerifyTimeBasedPayload (
     CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
     Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
     RootCert      = Cert->SignatureData;\r
-    RootCertSize  = CertList->SignatureSize;\r
+    RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
 \r
 \r
     //\r
@@ -2224,7 +2065,7 @@ VerifyTimeBasedPayload (
           // Iterate each Signature Data Node within this CertList for a verify\r
           //\r
           RootCert      = Cert->SignatureData;\r
-          RootCertSize  = CertList->SignatureSize;\r
+          RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);\r
 \r
           //\r
           // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
@@ -2314,6 +2155,22 @@ VerifyTimeBasedPayload (
         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