Home | History | Annotate | Download | only in AuthVariableLib
      1 /** @file
      2   Implement authentication services for the authenticated variables.
      3 
      4   Caution: This module requires additional review when modified.
      5   This driver will have external input - variable data. It may be input in SMM mode.
      6   This external input must be validated carefully to avoid security issue like
      7   buffer overflow, integer overflow.
      8   Variable attribute should also be checked to avoid authentication bypass.
      9      The whole SMM authentication variable design relies on the integrity of flash part and SMM.
     10   which is assumed to be protected by platform.  All variable code and metadata in flash/SMM Memory
     11   may not be modified without authorization. If platform fails to protect these resources,
     12   the authentication service provided in this driver will be broken, and the behavior is undefined.
     13 
     14   ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do
     15   variable authentication.
     16 
     17   VerifyTimeBasedPayloadAndUpdate() and VerifyCounterBasedPayload() are sub function to do verification.
     18   They will do basic validation for authentication data structure, then call crypto library
     19   to verify the signature.
     20 
     21 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
     22 This program and the accompanying materials
     23 are licensed and made available under the terms and conditions of the BSD License
     24 which accompanies this distribution.  The full text of the license may be found at
     25 http://opensource.org/licenses/bsd-license.php
     26 
     27 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     28 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     29 
     30 **/
     31 
     32 #include "AuthServiceInternal.h"
     33 
     34 //
     35 // Public Exponent of RSA Key.
     36 //
     37 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
     38 
     39 //
     40 // Requirement for different signature type which have been defined in UEFI spec.
     41 // These data are used to perform SignatureList format check while setting PK/KEK variable.
     42 //
     43 EFI_SIGNATURE_ITEM mSupportSigItem[] = {
     44 //{SigType,                       SigHeaderSize,   SigDataSize  }
     45   {EFI_CERT_SHA256_GUID,          0,               32           },
     46   {EFI_CERT_RSA2048_GUID,         0,               256          },
     47   {EFI_CERT_RSA2048_SHA256_GUID,  0,               256          },
     48   {EFI_CERT_SHA1_GUID,            0,               20           },
     49   {EFI_CERT_RSA2048_SHA1_GUID,    0,               256          },
     50   {EFI_CERT_X509_GUID,            0,               ((UINT32) ~0)},
     51   {EFI_CERT_SHA224_GUID,          0,               28           },
     52   {EFI_CERT_SHA384_GUID,          0,               48           },
     53   {EFI_CERT_SHA512_GUID,          0,               64           },
     54   {EFI_CERT_X509_SHA256_GUID,     0,               48           },
     55   {EFI_CERT_X509_SHA384_GUID,     0,               64           },
     56   {EFI_CERT_X509_SHA512_GUID,     0,               80           }
     57 };
     58 
     59 //
     60 // Secure Boot Mode state machine
     61 //
     62 SECURE_BOOT_MODE mSecureBootState[SecureBootModeTypeMax] = {
     63   // USER MODE
     64   {
     65       AUDIT_MODE_DISABLE,                        // AuditMode
     66       FALSE,                                     // IsAuditModeRO, AuditMode is RW
     67       DEPLOYED_MODE_DISABLE,                     // DeployedMode
     68       FALSE,                                     // IsDeployedModeRO, DeployedMode is RW
     69       SETUP_MODE_DISABLE,                        // SetupMode
     70                                                  // SetupMode is always RO
     71       SECURE_BOOT_MODE_ENABLE                    // SecureBoot
     72   },
     73   // SETUP MODE
     74   {
     75       AUDIT_MODE_DISABLE,                        // AuditMode
     76       FALSE,                                     // IsAuditModeRO, AuditMode is RW
     77       DEPLOYED_MODE_DISABLE,                     // DeployedMode
     78       TRUE,                                      // IsDeployedModeRO, DeployedMode is RO
     79       SETUP_MODE_ENABLE,                         // SetupMode
     80                                                  // SetupMode is always RO
     81       SECURE_BOOT_MODE_DISABLE                   // SecureBoot
     82   },
     83   // AUDIT MODE
     84   {
     85       AUDIT_MODE_ENABLE,                         // AuditMode
     86       TRUE,                                      // AuditModeValAttr RO, AuditMode is RO
     87       DEPLOYED_MODE_DISABLE,                     // DeployedMode
     88       TRUE,                                      // DeployedModeValAttr RO, DeployedMode is RO
     89       SETUP_MODE_ENABLE,                         // SetupMode
     90                                                  // SetupMode is always RO
     91       SECURE_BOOT_MODE_DISABLE                   // SecureBoot
     92   },
     93   // DEPLOYED MODE
     94   {
     95       AUDIT_MODE_DISABLE,                        // AuditMode, AuditMode is RO
     96       TRUE,                                      // AuditModeValAttr RO
     97       DEPLOYED_MODE_ENABLE,                      // DeployedMode
     98       TRUE,                                      // DeployedModeValAttr RO, DeployedMode is RO
     99       SETUP_MODE_DISABLE,                        // SetupMode
    100                                                  // SetupMode is always RO
    101       SECURE_BOOT_MODE_ENABLE                    // SecureBoot
    102   }
    103 };
    104 
    105 SECURE_BOOT_MODE_TYPE  mSecureBootMode;
    106 
    107 /**
    108   Finds variable in storage blocks of volatile and non-volatile storage areas.
    109 
    110   This code finds variable in storage blocks of volatile and non-volatile storage areas.
    111   If VariableName is an empty string, then we just return the first
    112   qualified variable without comparing VariableName and VendorGuid.
    113 
    114   @param[in]  VariableName          Name of the variable to be found.
    115   @param[in]  VendorGuid            Variable vendor GUID to be found.
    116   @param[out] Data                  Pointer to data address.
    117   @param[out] DataSize              Pointer to data size.
    118 
    119   @retval EFI_INVALID_PARAMETER     If VariableName is not an empty string,
    120                                     while VendorGuid is NULL.
    121   @retval EFI_SUCCESS               Variable successfully found.
    122   @retval EFI_NOT_FOUND             Variable not found
    123 
    124 **/
    125 EFI_STATUS
    126 AuthServiceInternalFindVariable (
    127   IN  CHAR16            *VariableName,
    128   IN  EFI_GUID          *VendorGuid,
    129   OUT VOID              **Data,
    130   OUT UINTN             *DataSize
    131   )
    132 {
    133   EFI_STATUS            Status;
    134   AUTH_VARIABLE_INFO    AuthVariableInfo;
    135 
    136   ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
    137   Status = mAuthVarLibContextIn->FindVariable (
    138            VariableName,
    139            VendorGuid,
    140            &AuthVariableInfo
    141            );
    142   *Data = AuthVariableInfo.Data;
    143   *DataSize = AuthVariableInfo.DataSize;
    144   return Status;
    145 }
    146 
    147 /**
    148   Update the variable region with Variable information.
    149 
    150   @param[in] VariableName           Name of variable.
    151   @param[in] VendorGuid             Guid of variable.
    152   @param[in] Data                   Data pointer.
    153   @param[in] DataSize               Size of Data.
    154   @param[in] Attributes             Attribute value of the variable.
    155 
    156   @retval EFI_SUCCESS               The update operation is success.
    157   @retval EFI_INVALID_PARAMETER     Invalid parameter.
    158   @retval EFI_WRITE_PROTECTED       Variable is write-protected.
    159   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    160 
    161 **/
    162 EFI_STATUS
    163 AuthServiceInternalUpdateVariable (
    164   IN CHAR16             *VariableName,
    165   IN EFI_GUID           *VendorGuid,
    166   IN VOID               *Data,
    167   IN UINTN              DataSize,
    168   IN UINT32             Attributes
    169   )
    170 {
    171   AUTH_VARIABLE_INFO    AuthVariableInfo;
    172 
    173   ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
    174   AuthVariableInfo.VariableName = VariableName;
    175   AuthVariableInfo.VendorGuid = VendorGuid;
    176   AuthVariableInfo.Data = Data;
    177   AuthVariableInfo.DataSize = DataSize;
    178   AuthVariableInfo.Attributes = Attributes;
    179 
    180   return mAuthVarLibContextIn->UpdateVariable (
    181            &AuthVariableInfo
    182            );
    183 }
    184 
    185 /**
    186   Update the variable region with Variable information.
    187 
    188   @param[in] VariableName           Name of variable.
    189   @param[in] VendorGuid             Guid of variable.
    190   @param[in] Data                   Data pointer.
    191   @param[in] DataSize               Size of Data.
    192   @param[in] Attributes             Attribute value of the variable.
    193   @param[in] KeyIndex               Index of associated public key.
    194   @param[in] MonotonicCount         Value of associated monotonic count.
    195 
    196   @retval EFI_SUCCESS               The update operation is success.
    197   @retval EFI_INVALID_PARAMETER     Invalid parameter.
    198   @retval EFI_WRITE_PROTECTED       Variable is write-protected.
    199   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    200 
    201 **/
    202 EFI_STATUS
    203 AuthServiceInternalUpdateVariableWithMonotonicCount (
    204   IN CHAR16             *VariableName,
    205   IN EFI_GUID           *VendorGuid,
    206   IN VOID               *Data,
    207   IN UINTN              DataSize,
    208   IN UINT32             Attributes,
    209   IN UINT32             KeyIndex,
    210   IN UINT64             MonotonicCount
    211   )
    212 {
    213   AUTH_VARIABLE_INFO    AuthVariableInfo;
    214 
    215   ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
    216   AuthVariableInfo.VariableName = VariableName;
    217   AuthVariableInfo.VendorGuid = VendorGuid;
    218   AuthVariableInfo.Data = Data;
    219   AuthVariableInfo.DataSize = DataSize;
    220   AuthVariableInfo.Attributes = Attributes;
    221   AuthVariableInfo.PubKeyIndex = KeyIndex;
    222   AuthVariableInfo.MonotonicCount = MonotonicCount;
    223 
    224   return mAuthVarLibContextIn->UpdateVariable (
    225            &AuthVariableInfo
    226            );
    227 }
    228 
    229 /**
    230   Update the variable region with Variable information.
    231 
    232   @param[in] VariableName           Name of variable.
    233   @param[in] VendorGuid             Guid of variable.
    234   @param[in] Data                   Data pointer.
    235   @param[in] DataSize               Size of Data.
    236   @param[in] Attributes             Attribute value of the variable.
    237   @param[in] TimeStamp              Value of associated TimeStamp.
    238 
    239   @retval EFI_SUCCESS               The update operation is success.
    240   @retval EFI_INVALID_PARAMETER     Invalid parameter.
    241   @retval EFI_WRITE_PROTECTED       Variable is write-protected.
    242   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    243 
    244 **/
    245 EFI_STATUS
    246 AuthServiceInternalUpdateVariableWithTimeStamp (
    247   IN CHAR16             *VariableName,
    248   IN EFI_GUID           *VendorGuid,
    249   IN VOID               *Data,
    250   IN UINTN              DataSize,
    251   IN UINT32             Attributes,
    252   IN EFI_TIME           *TimeStamp
    253   )
    254 {
    255   EFI_STATUS            FindStatus;
    256   VOID                  *OrgData;
    257   UINTN                 OrgDataSize;
    258   AUTH_VARIABLE_INFO    AuthVariableInfo;
    259 
    260   FindStatus = AuthServiceInternalFindVariable (
    261                  VariableName,
    262                  VendorGuid,
    263                  &OrgData,
    264                  &OrgDataSize
    265                  );
    266 
    267   //
    268   // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
    269   //
    270   if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
    271     if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
    272         ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
    273         (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||
    274         (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {
    275       //
    276       // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of
    277       // EFI_SIGNATURE_DATA values that are already part of the existing variable value.
    278       //
    279       FilterSignatureList (
    280         OrgData,
    281         OrgDataSize,
    282         Data,
    283         &DataSize
    284         );
    285     }
    286   }
    287 
    288   ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
    289   AuthVariableInfo.VariableName = VariableName;
    290   AuthVariableInfo.VendorGuid = VendorGuid;
    291   AuthVariableInfo.Data = Data;
    292   AuthVariableInfo.DataSize = DataSize;
    293   AuthVariableInfo.Attributes = Attributes;
    294   AuthVariableInfo.TimeStamp = TimeStamp;
    295   return mAuthVarLibContextIn->UpdateVariable (
    296            &AuthVariableInfo
    297            );
    298 }
    299 
    300 /**
    301   Initialize Secure Boot variables.
    302 
    303   @retval EFI_SUCCESS               The initialization operation is successful.
    304   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    305 
    306 **/
    307 EFI_STATUS
    308 InitSecureBootVariables (
    309   VOID
    310   )
    311 {
    312   EFI_STATUS             Status;
    313   UINT8                  *Data;
    314   UINTN                  DataSize;
    315   UINT32                 SecureBoot;
    316   UINT8                  SecureBootEnable;
    317   SECURE_BOOT_MODE_TYPE  SecureBootMode;
    318   BOOLEAN                IsPkPresent;
    319 
    320   //
    321   // Find "PK" variable
    322   //
    323   Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize);
    324   if (EFI_ERROR (Status)) {
    325     IsPkPresent = FALSE;
    326     DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));
    327   } else {
    328     IsPkPresent = TRUE;
    329     DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
    330   }
    331 
    332   //
    333   // Init "SecureBootMode" variable.
    334   // Initial case
    335   //   SecureBootMode doesn't exist. Init it with PK state
    336   // 3 inconsistency cases need to sync
    337   //   1.1 Add PK     -> system break -> update SecureBootMode Var
    338   //   1.2 Delete PK  -> system break -> update SecureBootMode Var
    339   //   1.3 Set AuditMode ->Delete PK  -> system break -> Update SecureBootMode Var
    340   //
    341   Status = AuthServiceInternalFindVariable (EDKII_SECURE_BOOT_MODE_NAME, &gEdkiiSecureBootModeGuid, (VOID **)&Data, &DataSize);
    342   if (EFI_ERROR(Status)) {
    343     //
    344     // Variable driver Initial Case
    345     //
    346     if (IsPkPresent) {
    347       SecureBootMode = SecureBootModeTypeUserMode;
    348     } else {
    349       SecureBootMode = SecureBootModeTypeSetupMode;
    350     }
    351   } else {
    352     //
    353     // 3 inconsistency cases need to sync
    354     //
    355     SecureBootMode = (SECURE_BOOT_MODE_TYPE)*Data;
    356     ASSERT(SecureBootMode < SecureBootModeTypeMax);
    357 
    358     if (IsPkPresent) {
    359       //
    360       // 3.1 Add PK     -> system break -> update SecureBootMode Var
    361       //
    362       if (SecureBootMode == SecureBootModeTypeSetupMode) {
    363         SecureBootMode = SecureBootModeTypeUserMode;
    364       } else if (SecureBootMode == SecureBootModeTypeAuditMode) {
    365         SecureBootMode = SecureBootModeTypeDeployedMode;
    366       }
    367     } else {
    368       //
    369       // 3.2 Delete PK -> system break -> update SecureBootMode Var
    370       // 3.3 Set AuditMode ->Delete PK  -> system break -> Update SecureBootMode Var. Reinit to be SetupMode
    371       //
    372       if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) {
    373         SecureBootMode = SecureBootModeTypeSetupMode;
    374       }
    375     }
    376   }
    377 
    378   if (EFI_ERROR(Status) || (SecureBootMode != (SECURE_BOOT_MODE_TYPE)*Data)) {
    379     //
    380     // Update SecureBootMode Var
    381     //
    382     Status = AuthServiceInternalUpdateVariable (
    383                EDKII_SECURE_BOOT_MODE_NAME,
    384                &gEdkiiSecureBootModeGuid,
    385                &SecureBootMode,
    386                sizeof (UINT8),
    387                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
    388                );
    389     if (EFI_ERROR(Status)) {
    390       return Status;
    391     }
    392   }
    393 
    394   //
    395   // Init "AuditMode"
    396   //
    397   Status = AuthServiceInternalUpdateVariable (
    398              EFI_AUDIT_MODE_NAME,
    399              &gEfiGlobalVariableGuid,
    400              &mSecureBootState[SecureBootMode].AuditMode,
    401              sizeof(UINT8),
    402              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
    403              );
    404   if (EFI_ERROR(Status)) {
    405     return Status;
    406   }
    407 
    408   //
    409   // Init "DeployedMode"
    410   //
    411   Status = AuthServiceInternalUpdateVariable (
    412              EFI_DEPLOYED_MODE_NAME,
    413              &gEfiGlobalVariableGuid,
    414              &mSecureBootState[SecureBootMode].DeployedMode,
    415              sizeof(UINT8),
    416              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
    417              );
    418   if (EFI_ERROR(Status)) {
    419     return Status;
    420   }
    421 
    422   //
    423   // Init "SetupMode"
    424   //
    425   Status = AuthServiceInternalUpdateVariable (
    426              EFI_SETUP_MODE_NAME,
    427              &gEfiGlobalVariableGuid,
    428              &mSecureBootState[SecureBootMode].SetupMode,
    429              sizeof(UINT8),
    430              EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
    431              );
    432   if (EFI_ERROR(Status)) {
    433     return Status;
    434   }
    435 
    436   //
    437   // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
    438   // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in User Mode or Deployed Mode, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
    439   // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
    440   //
    441   SecureBootEnable = SECURE_BOOT_DISABLE;
    442   Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **)&Data, &DataSize);
    443   if (!EFI_ERROR(Status)) {
    444     if (!IsPkPresent) {
    445       //
    446       // PK is cleared in runtime. "SecureBootMode" is not updated before reboot
    447       // Delete "SecureBootMode"
    448       //
    449       Status = AuthServiceInternalUpdateVariable (
    450                  EFI_SECURE_BOOT_ENABLE_NAME,
    451                  &gEfiSecureBootEnableDisableGuid,
    452                  &SecureBootEnable,
    453                  0,
    454                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
    455                  );
    456     } else {
    457       SecureBootEnable = *Data;
    458     }
    459   } else if ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode)) {
    460     //
    461     // "SecureBootEnable" not exist, initialize it in User Mode or Deployed Mode.
    462     //
    463     SecureBootEnable = SECURE_BOOT_ENABLE;
    464     Status = AuthServiceInternalUpdateVariable (
    465                EFI_SECURE_BOOT_ENABLE_NAME,
    466                &gEfiSecureBootEnableDisableGuid,
    467                &SecureBootEnable,
    468                sizeof (UINT8),
    469                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
    470                );
    471     if (EFI_ERROR (Status)) {
    472       return Status;
    473     }
    474   }
    475 
    476   //
    477   // Create "SecureBoot" variable with BS+RT attribute set.
    478   //
    479   if ((SecureBootEnable == SECURE_BOOT_ENABLE)
    480   && ((SecureBootMode == SecureBootModeTypeUserMode) || (SecureBootMode == SecureBootModeTypeDeployedMode))) {
    481     SecureBoot = SECURE_BOOT_MODE_ENABLE;
    482   } else {
    483     SecureBoot = SECURE_BOOT_MODE_DISABLE;
    484   }
    485   Status = AuthServiceInternalUpdateVariable (
    486              EFI_SECURE_BOOT_MODE_NAME,
    487              &gEfiGlobalVariableGuid,
    488              &SecureBoot,
    489              sizeof (UINT8),
    490              EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
    491              );
    492 
    493   DEBUG ((EFI_D_INFO, "SecureBootMode is %x\n", SecureBootMode));
    494   DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBoot));
    495   DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));
    496 
    497   //
    498   // Save SecureBootMode in global space
    499   //
    500   mSecureBootMode = SecureBootMode;
    501 
    502   return Status;
    503 }
    504 
    505 /**
    506   Update SecureBootMode variable.
    507 
    508   @param[in] NewMode                New Secure Boot Mode.
    509 
    510   @retval EFI_SUCCESS               The initialization operation is successful.
    511   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    512 
    513 **/
    514 EFI_STATUS
    515 UpdateSecureBootMode(
    516   IN  SECURE_BOOT_MODE_TYPE  NewMode
    517   )
    518 {
    519   EFI_STATUS              Status;
    520 
    521   //
    522   // Update "SecureBootMode" variable to new Secure Boot Mode
    523   //
    524   Status = AuthServiceInternalUpdateVariable (
    525              EDKII_SECURE_BOOT_MODE_NAME,
    526              &gEdkiiSecureBootModeGuid,
    527              &NewMode,
    528              sizeof (UINT8),
    529              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
    530              );
    531 
    532   if (!EFI_ERROR(Status)) {
    533     DEBUG((EFI_D_INFO, "SecureBootMode Update to %x\n", NewMode));
    534     mSecureBootMode = NewMode;
    535   } else {
    536     DEBUG((EFI_D_ERROR, "SecureBootMode Update failure %x\n", Status));
    537   }
    538 
    539   return Status;
    540 }
    541 
    542 /**
    543   Current secure boot mode is AuditMode. This function performs secure boot mode transition
    544   to a new mode.
    545 
    546   @param[in] NewMode                New Secure Boot Mode.
    547 
    548   @retval EFI_SUCCESS               The initialization operation is successful.
    549   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    550 
    551 **/
    552 EFI_STATUS
    553 TransitionFromAuditMode(
    554   IN  SECURE_BOOT_MODE_TYPE               NewMode
    555   )
    556 {
    557   EFI_STATUS  Status;
    558   VOID        *AuditVarData;
    559   VOID        *DeployedVarData;
    560   VOID        *SetupVarData;
    561   VOID        *SecureBootVarData;
    562   UINT8       SecureBootEnable;
    563   UINTN       DataSize;
    564 
    565   //
    566   // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
    567   // they can be RW. but can't be deleted. so they can always be found.
    568   //
    569   Status = AuthServiceInternalFindVariable (
    570              EFI_AUDIT_MODE_NAME,
    571              &gEfiGlobalVariableGuid,
    572              &AuditVarData,
    573              &DataSize
    574              );
    575   if (EFI_ERROR (Status)) {
    576     ASSERT(FALSE);
    577   }
    578 
    579   Status = AuthServiceInternalFindVariable (
    580              EFI_DEPLOYED_MODE_NAME,
    581              &gEfiGlobalVariableGuid,
    582              &DeployedVarData,
    583              &DataSize
    584              );
    585   if (EFI_ERROR (Status)) {
    586     ASSERT(FALSE);
    587   }
    588 
    589   Status = AuthServiceInternalFindVariable (
    590              EFI_SETUP_MODE_NAME,
    591              &gEfiGlobalVariableGuid,
    592              &SetupVarData,
    593              &DataSize
    594              );
    595   if (EFI_ERROR (Status)) {
    596     ASSERT(FALSE);
    597   }
    598 
    599   Status = AuthServiceInternalFindVariable (
    600              EFI_SECURE_BOOT_MODE_NAME,
    601              &gEfiGlobalVariableGuid,
    602              &SecureBootVarData,
    603              &DataSize
    604              );
    605   if (EFI_ERROR (Status)) {
    606     ASSERT(FALSE);
    607   }
    608 
    609   //
    610   // Make Secure Boot Mode transition ATOMIC
    611   // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
    612   // other tranisition logic are all memory operations.
    613   //
    614   Status = UpdateSecureBootMode(NewMode);
    615   if (EFI_ERROR(Status)) {
    616     DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
    617   }
    618 
    619   if (NewMode == SecureBootModeTypeDeployedMode) {
    620     //
    621     // Since PK is enrolled, can't rollback, always update SecureBootMode in memory
    622     //
    623     mSecureBootMode = NewMode;
    624     Status          = EFI_SUCCESS;
    625 
    626     //
    627     // AuditMode ----> DeployedMode
    628     // Side Effects
    629     //   AuditMode =: 0 / DeployedMode := 1 / SetupMode := 0
    630     //
    631     // Update the value of AuditMode variable by a simple mem copy, this could avoid possible
    632     // variable storage reclaim at runtime.
    633     //
    634     CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));
    635     //
    636     // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible
    637     // variable storage reclaim at runtime.
    638     //
    639     CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));
    640     //
    641     // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
    642     // variable storage reclaim at runtime.
    643     //
    644     CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));
    645 
    646     if (mAuthVarLibContextIn->AtRuntime ()) {
    647       //
    648       // SecureBoot Variable indicates whether the platform firmware is operating
    649       // in Secure boot mode (1) or not (0), so we should not change SecureBoot
    650       // Variable in runtime.
    651       //
    652       return Status;
    653     }
    654 
    655     //
    656     // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
    657     // variable storage reclaim at runtime.
    658     //
    659     CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));
    660 
    661     //
    662     // Create "SecureBootEnable" variable  as secure boot is enabled.
    663     //
    664     SecureBootEnable = SECURE_BOOT_ENABLE;
    665     AuthServiceInternalUpdateVariable (
    666       EFI_SECURE_BOOT_ENABLE_NAME,
    667       &gEfiSecureBootEnableDisableGuid,
    668       &SecureBootEnable,
    669       sizeof (SecureBootEnable),
    670       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
    671       );
    672   } else {
    673     DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeAuditMode, NewMode));
    674     ASSERT(FALSE);
    675   }
    676 
    677   return Status;
    678 }
    679 
    680 /**
    681   Current secure boot mode is DeployedMode. This function performs secure boot mode transition
    682   to a new mode.
    683 
    684   @param[in] NewMode                New Secure Boot Mode.
    685 
    686   @retval EFI_SUCCESS               The initialization operation is successful.
    687   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    688 
    689 **/
    690 EFI_STATUS
    691 TransitionFromDeployedMode(
    692   IN  SECURE_BOOT_MODE_TYPE               NewMode
    693   )
    694 {
    695   EFI_STATUS  Status;
    696   VOID        *DeployedVarData;
    697   VOID        *SetupVarData;
    698   VOID        *SecureBootVarData;
    699   UINT8       SecureBootEnable;
    700   UINTN       DataSize;
    701 
    702   //
    703   // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
    704   // they can be RW. but can't be deleted. so they can always be found.
    705   //
    706   Status = AuthServiceInternalFindVariable (
    707              EFI_DEPLOYED_MODE_NAME,
    708              &gEfiGlobalVariableGuid,
    709              &DeployedVarData,
    710              &DataSize
    711              );
    712   if (EFI_ERROR (Status)) {
    713     ASSERT(FALSE);
    714   }
    715 
    716   Status = AuthServiceInternalFindVariable (
    717              EFI_SETUP_MODE_NAME,
    718              &gEfiGlobalVariableGuid,
    719              &SetupVarData,
    720              &DataSize
    721              );
    722   if (EFI_ERROR (Status)) {
    723     ASSERT(FALSE);
    724   }
    725 
    726   Status = AuthServiceInternalFindVariable (
    727              EFI_SECURE_BOOT_MODE_NAME,
    728              &gEfiGlobalVariableGuid,
    729              &SecureBootVarData,
    730              &DataSize
    731              );
    732   if (EFI_ERROR (Status)) {
    733     ASSERT(FALSE);
    734   }
    735 
    736   //
    737   // Make Secure Boot Mode transition ATOMIC
    738   // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
    739   // other tranisition logic are all memory operations.
    740   //
    741   Status = UpdateSecureBootMode(NewMode);
    742   if (EFI_ERROR(Status)) {
    743     DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
    744   }
    745 
    746   switch(NewMode) {
    747     case SecureBootModeTypeUserMode:
    748       //
    749       // DeployedMode ----> UserMode
    750       // Side Effects
    751       //   DeployedMode := 0
    752       //
    753       // Platform Specific DeployedMode clear. UpdateSecureBootMode fails and no other variables are updated before. rollback this transition
    754       //
    755       if (EFI_ERROR(Status)) {
    756         return Status;
    757       }
    758       CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));
    759 
    760       break;
    761 
    762     case SecureBootModeTypeSetupMode:
    763       //
    764       // Since PK is processed before, can't rollback, still update SecureBootMode in memory
    765       //
    766       mSecureBootMode = NewMode;
    767       Status          = EFI_SUCCESS;
    768 
    769       //
    770       // DeployedMode ----> SetupMode
    771       //
    772       // Platform Specific PKpub clear or Delete Pkpub
    773       // Side Effects
    774       //   DeployedMode := 0 / SetupMode := 1 / SecureBoot := 0
    775       //
    776       // Update the value of DeployedMode variable by a simple mem copy, this could avoid possible
    777       // variable storage reclaim at runtime.
    778       //
    779       CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));
    780       //
    781       // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
    782       // variable storage reclaim at runtime.
    783       //
    784       CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));
    785 
    786       if (mAuthVarLibContextIn->AtRuntime ()) {
    787         //
    788         // SecureBoot Variable indicates whether the platform firmware is operating
    789         // in Secure boot mode (1) or not (0), so we should not change SecureBoot
    790         // Variable in runtime.
    791         //
    792         return Status;
    793       }
    794 
    795       //
    796       // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
    797       // variable storage reclaim at runtime.
    798       //
    799       CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));
    800 
    801       //
    802       // Delete the "SecureBootEnable" variable as secure boot is Disabled.
    803       //
    804       SecureBootEnable = SECURE_BOOT_DISABLE;
    805       AuthServiceInternalUpdateVariable (
    806         EFI_SECURE_BOOT_ENABLE_NAME,
    807         &gEfiSecureBootEnableDisableGuid,
    808         &SecureBootEnable,
    809         0,
    810         EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
    811         );
    812       break;
    813 
    814     default:
    815       DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeDeployedMode, NewMode));
    816       ASSERT(FALSE);
    817   }
    818 
    819   return Status;
    820 }
    821 
    822 /**
    823   Current secure boot mode is UserMode. This function performs secure boot mode transition
    824   to a new mode.
    825 
    826   @param[in] NewMode                New Secure Boot Mode.
    827 
    828   @retval EFI_SUCCESS               The initialization operation is successful.
    829   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    830 
    831 **/
    832 EFI_STATUS
    833 TransitionFromUserMode(
    834   IN  SECURE_BOOT_MODE_TYPE               NewMode
    835   )
    836 {
    837   EFI_STATUS   Status;
    838   VOID         *AuditVarData;
    839   VOID         *DeployedVarData;
    840   VOID         *SetupVarData;
    841   VOID         *PkVarData;
    842   VOID         *SecureBootVarData;
    843   UINT8        SecureBootEnable;
    844   UINTN        DataSize;
    845   VARIABLE_ENTRY_CONSISTENCY  VariableEntry;
    846 
    847   //
    848   // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
    849   // they can be RW. but can't be deleted. so they can always be found.
    850   //
    851   Status = AuthServiceInternalFindVariable (
    852              EFI_AUDIT_MODE_NAME,
    853              &gEfiGlobalVariableGuid,
    854              &AuditVarData,
    855              &DataSize
    856              );
    857   if (EFI_ERROR (Status)) {
    858     ASSERT(FALSE);
    859   }
    860 
    861   Status = AuthServiceInternalFindVariable (
    862              EFI_DEPLOYED_MODE_NAME,
    863              &gEfiGlobalVariableGuid,
    864              &DeployedVarData,
    865              &DataSize
    866              );
    867   if (EFI_ERROR (Status)) {
    868     ASSERT(FALSE);
    869   }
    870 
    871   Status = AuthServiceInternalFindVariable (
    872              EFI_SETUP_MODE_NAME,
    873              &gEfiGlobalVariableGuid,
    874              &SetupVarData,
    875              &DataSize
    876              );
    877   if (EFI_ERROR (Status)) {
    878     ASSERT(FALSE);
    879   }
    880 
    881   Status = AuthServiceInternalFindVariable (
    882              EFI_SECURE_BOOT_MODE_NAME,
    883              &gEfiGlobalVariableGuid,
    884              &SecureBootVarData,
    885              &DataSize
    886              );
    887   if (EFI_ERROR (Status)) {
    888     ASSERT(FALSE);
    889   }
    890 
    891   //
    892   // Make Secure Boot Mode transition ATOMIC
    893   // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
    894   // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.
    895   //
    896   if (NewMode != SecureBootModeTypeAuditMode) {
    897     Status = UpdateSecureBootMode(NewMode);
    898     if (EFI_ERROR(Status)) {
    899       DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
    900     }
    901   } else {
    902     //
    903     // UserMode -----> AuditMode. Check RemainingSpace for SecureBootMode var first.
    904     // Will update SecureBootMode after DeletePK logic
    905     //
    906     VariableEntry.VariableSize = sizeof(UINT8);
    907     VariableEntry.Guid         = &gEdkiiSecureBootModeGuid;
    908     VariableEntry.Name         = EDKII_SECURE_BOOT_MODE_NAME;
    909     if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry, NULL)) {
    910       return EFI_OUT_OF_RESOURCES;
    911     }
    912   }
    913 
    914   switch(NewMode) {
    915     case SecureBootModeTypeDeployedMode:
    916       //
    917       // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition
    918       //
    919       if (EFI_ERROR(Status)) {
    920         return Status;
    921       }
    922 
    923       //
    924       // UserMode ----> DeployedMode
    925       // Side Effects
    926       //   DeployedMode := 1
    927       //
    928       CopyMem (DeployedVarData, &mSecureBootState[NewMode].DeployedMode, sizeof(UINT8));
    929       break;
    930 
    931     case SecureBootModeTypeAuditMode:
    932       //
    933       // UserMode ----> AuditMode
    934       // Side Effects
    935       //   Delete PKpub / SetupMode := 1 / SecureBoot := 0
    936       //
    937       // Delete PKpub without verification. Should always succeed.
    938       //
    939       PkVarData = NULL;
    940       Status = AuthServiceInternalUpdateVariable (
    941                  EFI_PLATFORM_KEY_NAME,
    942                  &gEfiGlobalVariableGuid,
    943                  PkVarData,
    944                  0,
    945                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
    946                  );
    947       if (EFI_ERROR(Status)) {
    948         DEBUG((EFI_D_ERROR, "UserMode -> AuditMode. Delete PK fail %x\n", Status));
    949         ASSERT(FALSE);
    950       }
    951 
    952       //
    953       // Update Private NV SecureBootMode Variable
    954       //
    955       Status = UpdateSecureBootMode(NewMode);
    956       if (EFI_ERROR(Status)) {
    957         //
    958         // Since PK is deleted successfully, Doesn't break, continue to update other variable.
    959         //
    960         DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
    961       }
    962       CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));
    963 
    964       //
    965       // Fall into SetupMode logic
    966       //
    967     case SecureBootModeTypeSetupMode:
    968       //
    969       // Since PK is deleted before , can't rollback, still update SecureBootMode in memory
    970       //
    971       mSecureBootMode = NewMode;
    972       Status          = EFI_SUCCESS;
    973 
    974       //
    975       // UserMode ----> SetupMode
    976       //  Side Effects
    977       //    DeployedMode :=0 / SetupMode :=1 / SecureBoot :=0
    978       //
    979       // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
    980       // variable storage reclaim at runtime.
    981       //
    982       CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));
    983 
    984       if (mAuthVarLibContextIn->AtRuntime ()) {
    985         //
    986         // SecureBoot Variable indicates whether the platform firmware is operating
    987         // in Secure boot mode (1) or not (0), so we should not change SecureBoot
    988         // Variable in runtime.
    989         //
    990         return Status;
    991       }
    992 
    993       //
    994       // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
    995       // variable storage reclaim at runtime.
    996       //
    997       CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));
    998 
    999       //
   1000       // Delete the "SecureBootEnable" variable as secure boot is Disabled.
   1001       //
   1002       SecureBootEnable = SECURE_BOOT_DISABLE;
   1003       AuthServiceInternalUpdateVariable (
   1004         EFI_SECURE_BOOT_ENABLE_NAME,
   1005         &gEfiSecureBootEnableDisableGuid,
   1006         &SecureBootEnable,
   1007         0,
   1008         EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
   1009         );
   1010 
   1011       break;
   1012 
   1013     default:
   1014       DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeUserMode, NewMode));
   1015       ASSERT(FALSE);
   1016   }
   1017 
   1018   return Status;
   1019 }
   1020 
   1021 /**
   1022   Current secure boot mode is SetupMode. This function performs secure boot mode transition
   1023   to a new mode.
   1024 
   1025   @param[in] NewMode                New Secure Boot Mode.
   1026 
   1027   @retval EFI_SUCCESS               The initialization operation is successful.
   1028   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
   1029 
   1030 **/
   1031 EFI_STATUS
   1032 TransitionFromSetupMode(
   1033   IN  SECURE_BOOT_MODE_TYPE              NewMode
   1034   )
   1035 {
   1036   EFI_STATUS   Status;
   1037   VOID         *AuditVarData;
   1038   VOID         *SetupVarData;
   1039   VOID         *SecureBootVarData;
   1040   UINT8        SecureBootEnable;
   1041   UINTN        DataSize;
   1042 
   1043   //
   1044   // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
   1045   // they can be RW. but can't be deleted. so they can always be found.
   1046   //
   1047   Status = AuthServiceInternalFindVariable (
   1048              EFI_AUDIT_MODE_NAME,
   1049              &gEfiGlobalVariableGuid,
   1050              &AuditVarData,
   1051              &DataSize
   1052              );
   1053   if (EFI_ERROR (Status)) {
   1054     ASSERT(FALSE);
   1055   }
   1056 
   1057   Status = AuthServiceInternalFindVariable (
   1058              EFI_SETUP_MODE_NAME,
   1059              &gEfiGlobalVariableGuid,
   1060              &SetupVarData,
   1061              &DataSize
   1062              );
   1063   if (EFI_ERROR (Status)) {
   1064     ASSERT(FALSE);
   1065   }
   1066 
   1067   Status = AuthServiceInternalFindVariable (
   1068              EFI_SECURE_BOOT_MODE_NAME,
   1069              &gEfiGlobalVariableGuid,
   1070              &SecureBootVarData,
   1071              &DataSize
   1072              );
   1073   if (EFI_ERROR (Status)) {
   1074     ASSERT(FALSE);
   1075   }
   1076 
   1077   //
   1078   // Make Secure Boot Mode transition ATOMIC
   1079   // Update Private NV SecureBootMode Variable first, because it may fail due to NV range overflow.
   1080   // Other tranisition logic are all memory operations and PK delete is assumed to be always successful.
   1081   //
   1082   Status = UpdateSecureBootMode(NewMode);
   1083   if (EFI_ERROR(Status)) {
   1084     DEBUG((EFI_D_ERROR, "Update SecureBootMode Variable fail %x\n", Status));
   1085   }
   1086 
   1087   switch(NewMode) {
   1088     case SecureBootModeTypeAuditMode:
   1089       //
   1090       // UpdateSecureBootMode fails and no other variables are updated before. rollback this transition
   1091       //
   1092       if (EFI_ERROR(Status)) {
   1093         return Status;
   1094       }
   1095 
   1096       //
   1097       // SetupMode ----> AuditMode
   1098       // Side Effects
   1099       //   AuditMode := 1
   1100       //
   1101       // Update the value of AuditMode variable by a simple mem copy, this could avoid possible
   1102       // variable storage reclaim at runtime.
   1103       //
   1104       CopyMem (AuditVarData, &mSecureBootState[NewMode].AuditMode, sizeof(UINT8));
   1105       break;
   1106 
   1107     case SecureBootModeTypeUserMode:
   1108       //
   1109       // Since PK is enrolled before, can't rollback, still update SecureBootMode in memory
   1110       //
   1111       mSecureBootMode = NewMode;
   1112       Status          = EFI_SUCCESS;
   1113 
   1114       //
   1115       // SetupMode ----> UserMode
   1116       // Side Effects
   1117       //   SetupMode := 0 / SecureBoot := 1
   1118       //
   1119       // Update the value of AuditMode variable by a simple mem copy, this could avoid possible
   1120       // variable storage reclaim at runtime.
   1121       //
   1122       CopyMem (SetupVarData, &mSecureBootState[NewMode].SetupMode, sizeof(UINT8));
   1123 
   1124       if (mAuthVarLibContextIn->AtRuntime ()) {
   1125         //
   1126         // SecureBoot Variable indicates whether the platform firmware is operating
   1127         // in Secure boot mode (1) or not (0), so we should not change SecureBoot
   1128         // Variable in runtime.
   1129         //
   1130         return Status;
   1131       }
   1132 
   1133       //
   1134       // Update the value of SecureBoot variable by a simple mem copy, this could avoid possible
   1135       // variable storage reclaim at runtime.
   1136       //
   1137       CopyMem (SecureBootVarData, &mSecureBootState[NewMode].SecureBoot, sizeof(UINT8));
   1138 
   1139       //
   1140       // Create the "SecureBootEnable" variable as secure boot is enabled.
   1141       //
   1142       SecureBootEnable = SECURE_BOOT_ENABLE;
   1143       AuthServiceInternalUpdateVariable (
   1144         EFI_SECURE_BOOT_ENABLE_NAME,
   1145         &gEfiSecureBootEnableDisableGuid,
   1146         &SecureBootEnable,
   1147         sizeof (SecureBootEnable),
   1148         EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
   1149         );
   1150       break;
   1151 
   1152     default:
   1153       DEBUG((EFI_D_ERROR, "Invalid state tranition from %x to %x\n", SecureBootModeTypeSetupMode, NewMode));
   1154       ASSERT(FALSE);
   1155   }
   1156 
   1157   return Status;
   1158 }
   1159 
   1160 /**
   1161   This function performs main secure boot mode transition logic.
   1162 
   1163   @param[in] CurMode                Current Secure Boot Mode.
   1164   @param[in] NewMode                New Secure Boot Mode.
   1165 
   1166   @retval EFI_SUCCESS               The initialization operation is successful.
   1167   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
   1168   @retval EFI_INVALID_PARAMETER     The Current Secure Boot Mode is wrong.
   1169 
   1170 **/
   1171 EFI_STATUS
   1172 SecureBootModeTransition(
   1173   IN  SECURE_BOOT_MODE_TYPE  CurMode,
   1174   IN  SECURE_BOOT_MODE_TYPE  NewMode
   1175   )
   1176 {
   1177   EFI_STATUS Status;
   1178 
   1179   //
   1180   // SecureBootMode transition
   1181   //
   1182   switch (CurMode) {
   1183     case SecureBootModeTypeUserMode:
   1184       Status = TransitionFromUserMode(NewMode);
   1185       break;
   1186 
   1187     case SecureBootModeTypeSetupMode:
   1188       Status = TransitionFromSetupMode(NewMode);
   1189       break;
   1190 
   1191     case SecureBootModeTypeAuditMode:
   1192       Status = TransitionFromAuditMode(NewMode);
   1193       break;
   1194 
   1195     case SecureBootModeTypeDeployedMode:
   1196       Status = TransitionFromDeployedMode(NewMode);
   1197       break;
   1198 
   1199     default:
   1200       Status = EFI_INVALID_PARAMETER;
   1201       ASSERT(FALSE);
   1202   }
   1203 
   1204   return Status;
   1205 
   1206 }
   1207 
   1208 /**
   1209   Determine whether this operation needs a physical present user.
   1210 
   1211   @param[in]      VariableName            Name of the Variable.
   1212   @param[in]      VendorGuid              GUID of the Variable.
   1213 
   1214   @retval TRUE      This variable is protected, only a physical present user could set this variable.
   1215   @retval FALSE     This variable is not protected.
   1216 
   1217 **/
   1218 BOOLEAN
   1219 NeedPhysicallyPresent(
   1220   IN     CHAR16         *VariableName,
   1221   IN     EFI_GUID       *VendorGuid
   1222   )
   1223 {
   1224   if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))
   1225     || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {
   1226     return TRUE;
   1227   }
   1228 
   1229   return FALSE;
   1230 }
   1231 
   1232 /**
   1233   Determine whether the platform is operating in Custom Secure Boot mode.
   1234 
   1235   @retval TRUE           The platform is operating in Custom mode.
   1236   @retval FALSE          The platform is operating in Standard mode.
   1237 
   1238 **/
   1239 BOOLEAN
   1240 InCustomMode (
   1241   VOID
   1242   )
   1243 {
   1244   EFI_STATUS    Status;
   1245   VOID          *Data;
   1246   UINTN         DataSize;
   1247 
   1248   Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize);
   1249   if (!EFI_ERROR (Status) && (*(UINT8 *) Data == CUSTOM_SECURE_BOOT_MODE)) {
   1250     return TRUE;
   1251   }
   1252 
   1253   return FALSE;
   1254 }
   1255 
   1256 /**
   1257   Get available public key index.
   1258 
   1259   @param[in] PubKey     Pointer to Public Key data.
   1260 
   1261   @return Public key index, 0 if no any public key index available.
   1262 
   1263 **/
   1264 UINT32
   1265 GetAvailableKeyIndex (
   1266   IN  UINT8             *PubKey
   1267   )
   1268 {
   1269   EFI_STATUS            Status;
   1270   UINT8                 *Data;
   1271   UINTN                 DataSize;
   1272   UINT8                 *Ptr;
   1273   UINT32                Index;
   1274   BOOLEAN               IsFound;
   1275   EFI_GUID              VendorGuid;
   1276   CHAR16                Name[1];
   1277   AUTH_VARIABLE_INFO    AuthVariableInfo;
   1278   UINT32                KeyIndex;
   1279 
   1280   Status = AuthServiceInternalFindVariable (
   1281              AUTHVAR_KEYDB_NAME,
   1282              &gEfiAuthenticatedVariableGuid,
   1283              (VOID **) &Data,
   1284              &DataSize
   1285              );
   1286   if (EFI_ERROR (Status)) {
   1287     DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));
   1288     return 0;
   1289   }
   1290 
   1291   if (mPubKeyNumber == mMaxKeyNumber) {
   1292     Name[0] = 0;
   1293     AuthVariableInfo.VariableName = Name;
   1294     ZeroMem (&VendorGuid, sizeof (VendorGuid));
   1295     AuthVariableInfo.VendorGuid = &VendorGuid;
   1296     mPubKeyNumber = 0;
   1297     //
   1298     // Collect valid key data.
   1299     //
   1300     do {
   1301       Status = mAuthVarLibContextIn->FindNextVariable (AuthVariableInfo.VariableName, AuthVariableInfo.VendorGuid, &AuthVariableInfo);
   1302       if (!EFI_ERROR (Status)) {
   1303         if (AuthVariableInfo.PubKeyIndex != 0) {
   1304           for (Ptr = Data; Ptr < (Data + DataSize); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {
   1305             if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {
   1306               //
   1307               // Check if the key data has been collected.
   1308               //
   1309               for (Index = 0; Index < mPubKeyNumber; Index++) {
   1310                 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {
   1311                   break;
   1312                 }
   1313               }
   1314               if (Index == mPubKeyNumber) {
   1315                 //
   1316                 // New key data.
   1317                 //
   1318                 CopyMem ((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber, Ptr, sizeof (AUTHVAR_KEY_DB_DATA));
   1319                 mPubKeyNumber++;
   1320               }
   1321               break;
   1322             }
   1323           }
   1324         }
   1325       }
   1326     } while (Status != EFI_NOT_FOUND);
   1327 
   1328     //
   1329     // No available space to add new public key.
   1330     //
   1331     if (mPubKeyNumber == mMaxKeyNumber) {
   1332       return 0;
   1333     }
   1334   }
   1335 
   1336   //
   1337   // Find available public key index.
   1338   //
   1339   for (KeyIndex = 1; KeyIndex <= mMaxKeyNumber; KeyIndex++) {
   1340     IsFound = FALSE;
   1341     for (Ptr = mPubKeyStore; Ptr < (mPubKeyStore + mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA)); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {
   1342       if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == KeyIndex) {
   1343         IsFound = TRUE;
   1344         break;
   1345       }
   1346     }
   1347     if (!IsFound) {
   1348       break;
   1349     }
   1350   }
   1351 
   1352   return KeyIndex;
   1353 }
   1354 
   1355 /**
   1356   Add public key in store and return its index.
   1357 
   1358   @param[in] PubKey             Input pointer to Public Key data.
   1359   @param[in] VariableDataEntry  The variable data entry.
   1360 
   1361   @return Index of new added public key.
   1362 
   1363 **/
   1364 UINT32
   1365 AddPubKeyInStore (
   1366   IN  UINT8                        *PubKey,
   1367   IN  VARIABLE_ENTRY_CONSISTENCY   *VariableDataEntry
   1368   )
   1369 {
   1370   EFI_STATUS                       Status;
   1371   UINT32                           Index;
   1372   VARIABLE_ENTRY_CONSISTENCY       PublicKeyEntry;
   1373   UINT32                           Attributes;
   1374   UINT32                           KeyIndex;
   1375 
   1376   if (PubKey == NULL) {
   1377     return 0;
   1378   }
   1379 
   1380   //
   1381   // Check whether the public key entry does exist.
   1382   //
   1383   for (Index = 0; Index < mPubKeyNumber; Index++) {
   1384     if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
   1385       return ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex));
   1386     }
   1387   }
   1388 
   1389   KeyIndex = GetAvailableKeyIndex (PubKey);
   1390   if (KeyIndex == 0) {
   1391     return 0;
   1392   }
   1393 
   1394   //
   1395   // Check the variable space for both public key and variable data.
   1396   //
   1397   PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * sizeof (AUTHVAR_KEY_DB_DATA);
   1398   PublicKeyEntry.Guid         = &gEfiAuthenticatedVariableGuid;
   1399   PublicKeyEntry.Name         = AUTHVAR_KEYDB_NAME;
   1400   Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
   1401 
   1402   if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {
   1403     //
   1404     // No enough variable space.
   1405     //
   1406     return 0;
   1407   }
   1408 
   1409   WriteUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyIndex), KeyIndex);
   1410   CopyMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
   1411   mPubKeyNumber++;
   1412 
   1413   //
   1414   // Update public key database variable.
   1415   //
   1416   Status = AuthServiceInternalUpdateVariable (
   1417              AUTHVAR_KEYDB_NAME,
   1418              &gEfiAuthenticatedVariableGuid,
   1419              mPubKeyStore,
   1420              mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA),
   1421              Attributes
   1422              );
   1423   if (EFI_ERROR (Status)) {
   1424     DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));
   1425     return 0;
   1426   }
   1427 
   1428   return KeyIndex;
   1429 }
   1430 
   1431 /**
   1432   Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
   1433   Follow the steps in UEFI2.2.
   1434 
   1435   Caution: This function may receive untrusted input.
   1436   This function may be invoked in SMM mode, and datasize and data are external input.
   1437   This function will do basic validation, before parse the data.
   1438   This function will parse the authentication carefully to avoid security issues, like
   1439   buffer overflow, integer overflow.
   1440 
   1441   @param[in]      Data                    Pointer to data with AuthInfo.
   1442   @param[in]      DataSize                Size of Data.
   1443   @param[in]      PubKey                  Public key used for verification.
   1444 
   1445   @retval EFI_INVALID_PARAMETER       Invalid parameter.
   1446   @retval EFI_SECURITY_VIOLATION      If authentication failed.
   1447   @retval EFI_SUCCESS                 Authentication successful.
   1448 
   1449 **/
   1450 EFI_STATUS
   1451 VerifyCounterBasedPayload (
   1452   IN     UINT8          *Data,
   1453   IN     UINTN          DataSize,
   1454   IN     UINT8          *PubKey
   1455   )
   1456 {
   1457   BOOLEAN                         Status;
   1458   EFI_VARIABLE_AUTHENTICATION     *CertData;
   1459   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
   1460   UINT8                           Digest[SHA256_DIGEST_SIZE];
   1461   VOID                            *Rsa;
   1462   UINTN                           PayloadSize;
   1463 
   1464   PayloadSize = DataSize - AUTHINFO_SIZE;
   1465   Rsa         = NULL;
   1466   CertData    = NULL;
   1467   CertBlock   = NULL;
   1468 
   1469   if (Data == NULL || PubKey == NULL) {
   1470     return EFI_INVALID_PARAMETER;
   1471   }
   1472 
   1473   CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
   1474   CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
   1475 
   1476   //
   1477   // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
   1478   // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
   1479   //
   1480   if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
   1481       !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {
   1482     //
   1483     // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
   1484     //
   1485     return EFI_SECURITY_VIOLATION;
   1486   }
   1487   //
   1488   // Hash data payload with SHA256.
   1489   //
   1490   ZeroMem (Digest, SHA256_DIGEST_SIZE);
   1491   Status  = Sha256Init (mHashCtx);
   1492   if (!Status) {
   1493     goto Done;
   1494   }
   1495   Status  = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);
   1496   if (!Status) {
   1497     goto Done;
   1498   }
   1499   //
   1500   // Hash Size.
   1501   //
   1502   Status  = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));
   1503   if (!Status) {
   1504     goto Done;
   1505   }
   1506   //
   1507   // Hash Monotonic Count.
   1508   //
   1509   Status  = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));
   1510   if (!Status) {
   1511     goto Done;
   1512   }
   1513   Status  = Sha256Final (mHashCtx, Digest);
   1514   if (!Status) {
   1515     goto Done;
   1516   }
   1517   //
   1518   // Generate & Initialize RSA Context.
   1519   //
   1520   Rsa = RsaNew ();
   1521   ASSERT (Rsa != NULL);
   1522   //
   1523   // Set RSA Key Components.
   1524   // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
   1525   //
   1526   Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
   1527   if (!Status) {
   1528     goto Done;
   1529   }
   1530   Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
   1531   if (!Status) {
   1532     goto Done;
   1533   }
   1534   //
   1535   // Verify the signature.
   1536   //
   1537   Status = RsaPkcs1Verify (
   1538              Rsa,
   1539              Digest,
   1540              SHA256_DIGEST_SIZE,
   1541              CertBlock->Signature,
   1542              EFI_CERT_TYPE_RSA2048_SHA256_SIZE
   1543              );
   1544 
   1545 Done:
   1546   if (Rsa != NULL) {
   1547     RsaFree (Rsa);
   1548   }
   1549   if (Status) {
   1550     return EFI_SUCCESS;
   1551   } else {
   1552     return EFI_SECURITY_VIOLATION;
   1553   }
   1554 }
   1555 
   1556 
   1557 /**
   1558   Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.
   1559 
   1560   @param[in]  VariableName                Name of Variable to be check.
   1561   @param[in]  VendorGuid                  Variable vendor GUID.
   1562   @param[in]  Data                        Point to the variable data to be checked.
   1563   @param[in]  DataSize                    Size of Data.
   1564 
   1565   @return EFI_INVALID_PARAMETER           Invalid signature list format.
   1566   @return EFI_SUCCESS                     Passed signature list format check successfully.
   1567 
   1568 **/
   1569 EFI_STATUS
   1570 CheckSignatureListFormat(
   1571   IN  CHAR16                    *VariableName,
   1572   IN  EFI_GUID                  *VendorGuid,
   1573   IN  VOID                      *Data,
   1574   IN  UINTN                     DataSize
   1575   )
   1576 {
   1577   EFI_SIGNATURE_LIST     *SigList;
   1578   UINTN                  SigDataSize;
   1579   UINT32                 Index;
   1580   UINT32                 SigCount;
   1581   BOOLEAN                IsPk;
   1582   VOID                   *RsaContext;
   1583   EFI_SIGNATURE_DATA     *CertData;
   1584   UINTN                  CertLen;
   1585 
   1586   if (DataSize == 0) {
   1587     return EFI_SUCCESS;
   1588   }
   1589 
   1590   ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);
   1591 
   1592   if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
   1593     IsPk = TRUE;
   1594   } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) ||
   1595              (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
   1596              ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
   1597               (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)))) {
   1598     IsPk = FALSE;
   1599   } else {
   1600     return EFI_SUCCESS;
   1601   }
   1602 
   1603   SigCount = 0;
   1604   SigList  = (EFI_SIGNATURE_LIST *) Data;
   1605   SigDataSize  = DataSize;
   1606   RsaContext = NULL;
   1607 
   1608   //
   1609   // Walk throuth the input signature list and check the data format.
   1610   // If any signature is incorrectly formed, the whole check will fail.
   1611   //
   1612   while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {
   1613     for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {
   1614       if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {
   1615         //
   1616         // The value of SignatureSize should always be 16 (size of SignatureOwner
   1617         // component) add the data length according to signature type.
   1618         //
   1619         if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) &&
   1620           (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {
   1621           return EFI_INVALID_PARAMETER;
   1622         }
   1623         if (mSupportSigItem[Index].SigHeaderSize != ((UINT32) ~0) &&
   1624           SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {
   1625           return EFI_INVALID_PARAMETER;
   1626         }
   1627         break;
   1628       }
   1629     }
   1630 
   1631     if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {
   1632       //
   1633       // Undefined signature type.
   1634       //
   1635       return EFI_INVALID_PARAMETER;
   1636     }
   1637 
   1638     if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
   1639       //
   1640       // Try to retrieve the RSA public key from the X.509 certificate.
   1641       // If this operation fails, it's not a valid certificate.
   1642       //
   1643       RsaContext = RsaNew ();
   1644       if (RsaContext == NULL) {
   1645         return EFI_INVALID_PARAMETER;
   1646       }
   1647       CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);
   1648       CertLen = SigList->SignatureSize - sizeof (EFI_GUID);
   1649       if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {
   1650         RsaFree (RsaContext);
   1651         return EFI_INVALID_PARAMETER;
   1652       }
   1653       RsaFree (RsaContext);
   1654     }
   1655 
   1656     if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {
   1657       return EFI_INVALID_PARAMETER;
   1658     }
   1659     SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;
   1660 
   1661     SigDataSize -= SigList->SignatureListSize;
   1662     SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
   1663   }
   1664 
   1665   if (((UINTN) SigList - (UINTN) Data) != DataSize) {
   1666     return EFI_INVALID_PARAMETER;
   1667   }
   1668 
   1669   if (IsPk && SigCount > 1) {
   1670     return EFI_INVALID_PARAMETER;
   1671   }
   1672 
   1673   return EFI_SUCCESS;
   1674 }
   1675 
   1676 /**
   1677   Update "VendorKeys" variable to record the out of band secure boot key modification.
   1678 
   1679   @return EFI_SUCCESS           Variable is updated successfully.
   1680   @return Others                Failed to update variable.
   1681 
   1682 **/
   1683 EFI_STATUS
   1684 VendorKeyIsModified (
   1685   VOID
   1686   )
   1687 {
   1688   EFI_STATUS              Status;
   1689 
   1690   if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {
   1691     return EFI_SUCCESS;
   1692   }
   1693   mVendorKeyState = VENDOR_KEYS_MODIFIED;
   1694 
   1695   Status = AuthServiceInternalUpdateVariable (
   1696              EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
   1697              &gEfiVendorKeysNvGuid,
   1698              &mVendorKeyState,
   1699              sizeof (UINT8),
   1700              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
   1701              );
   1702   if (EFI_ERROR (Status)) {
   1703     return Status;
   1704   }
   1705 
   1706   return AuthServiceInternalUpdateVariable (
   1707            EFI_VENDOR_KEYS_VARIABLE_NAME,
   1708            &gEfiGlobalVariableGuid,
   1709            &mVendorKeyState,
   1710            sizeof (UINT8),
   1711            EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
   1712            );
   1713 }
   1714 
   1715 /**
   1716   Process Secure Boot Mode variable.
   1717 
   1718   Caution: This function may receive untrusted input.
   1719   This function may be invoked in SMM mode, and datasize and data are external input.
   1720   This function will do basic validation, before parse the data.
   1721   This function will parse the authentication carefully to avoid security issues, like
   1722   buffer overflow, integer overflow.
   1723   This function will check attribute carefully to avoid authentication bypass.
   1724 
   1725   @param[in]  VariableName                Name of Variable to be found.
   1726   @param[in]  VendorGuid                  Variable vendor GUID.
   1727   @param[in]  Data                        Data pointer.
   1728   @param[in]  DataSize                    Size of Data found. If size is less than the
   1729                                           data, this value contains the required size.
   1730   @param[in]  Attributes                  Attribute value of the variable
   1731 
   1732   @return EFI_INVALID_PARAMETER           Invalid parameter
   1733   @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
   1734                                           check carried out by the firmware.
   1735   @return EFI_WRITE_PROTECTED             Variable is Read-Only.
   1736   @return EFI_SUCCESS                     Variable passed validation successfully.
   1737 
   1738 **/
   1739 EFI_STATUS
   1740 ProcessSecureBootModeVar (
   1741   IN  CHAR16         *VariableName,
   1742   IN  EFI_GUID       *VendorGuid,
   1743   IN  VOID           *Data,
   1744   IN  UINTN          DataSize,
   1745   IN  UINT32         Attributes OPTIONAL
   1746   )
   1747 {
   1748   EFI_STATUS    Status;
   1749   VOID          *VarData;
   1750   UINTN         VarDataSize;
   1751 
   1752   //
   1753   // Check "AuditMode", "DeployedMode" Variable ReadWrite Attributes
   1754   //  if in Runtime,  Always RO
   1755   //  if in Boottime, Depends on current Secure Boot Mode
   1756   //
   1757   if (mAuthVarLibContextIn->AtRuntime()) {
   1758     return EFI_WRITE_PROTECTED;
   1759   }
   1760 
   1761   //
   1762   // Delete not OK
   1763   //
   1764   if ((DataSize != sizeof(UINT8)) || (Attributes == 0)) {
   1765     return EFI_INVALID_PARAMETER;
   1766   }
   1767 
   1768   if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) {
   1769     if(mSecureBootState[mSecureBootMode].IsAuditModeRO) {
   1770       return EFI_WRITE_PROTECTED;
   1771     }
   1772   } else {
   1773     //
   1774     // Platform specific deployedMode clear. Set DeployedMode = RW
   1775     //
   1776     if (!InCustomMode() || !UserPhysicalPresent() || mSecureBootMode != SecureBootModeTypeDeployedMode) {
   1777       if(mSecureBootState[mSecureBootMode].IsDeployedModeRO) {
   1778         return EFI_WRITE_PROTECTED;
   1779       }
   1780     }
   1781   }
   1782 
   1783   if (*(UINT8 *)Data != 0 && *(UINT8 *)Data != 1) {
   1784     return EFI_INVALID_PARAMETER;
   1785   }
   1786 
   1787   //
   1788   // AuditMode/DeployedMode/SetupMode/SecureBoot are all NON_NV variable maintained by Variable driver
   1789   // they can be RW. but can't be deleted. so they can always be found.
   1790   //
   1791   Status = AuthServiceInternalFindVariable (
   1792              VariableName,
   1793              VendorGuid,
   1794              &VarData,
   1795              &VarDataSize
   1796              );
   1797   if (EFI_ERROR(Status)) {
   1798     ASSERT(FALSE);
   1799   }
   1800 
   1801   //
   1802   // If AuditMode/DeployedMode is assigned same value. Simply return EFI_SUCCESS
   1803   //
   1804   if (*(UINT8 *)VarData == *(UINT8 *)Data) {
   1805     return EFI_SUCCESS;
   1806   }
   1807 
   1808   //
   1809   // Perform SecureBootMode transition
   1810   //
   1811   if (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0) {
   1812     DEBUG((EFI_D_INFO, "Current SecureBootMode %x Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeAuditMode));
   1813     return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeAuditMode);
   1814   } else if (StrCmp (VariableName, EFI_DEPLOYED_MODE_NAME) == 0) {
   1815     if (mSecureBootMode == SecureBootModeTypeDeployedMode) {
   1816       //
   1817       // Platform specific DeployedMode clear. InCustomMode() && UserPhysicalPresent() is checked before
   1818       //
   1819       DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeUserMode));
   1820       return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeUserMode);
   1821     } else {
   1822       DEBUG((EFI_D_INFO, "Current SecureBootMode %x. Transfer to SecureBootMode %x\n", mSecureBootMode, SecureBootModeTypeDeployedMode));
   1823       return SecureBootModeTransition(mSecureBootMode, SecureBootModeTypeDeployedMode);
   1824     }
   1825   }
   1826 
   1827   return EFI_INVALID_PARAMETER;
   1828 }
   1829 
   1830 /**
   1831   Process variable with platform key for verification.
   1832 
   1833   Caution: This function may receive untrusted input.
   1834   This function may be invoked in SMM mode, and datasize and data are external input.
   1835   This function will do basic validation, before parse the data.
   1836   This function will parse the authentication carefully to avoid security issues, like
   1837   buffer overflow, integer overflow.
   1838   This function will check attribute carefully to avoid authentication bypass.
   1839 
   1840   @param[in]  VariableName                Name of Variable to be found.
   1841   @param[in]  VendorGuid                  Variable vendor GUID.
   1842   @param[in]  Data                        Data pointer.
   1843   @param[in]  DataSize                    Size of Data found. If size is less than the
   1844                                           data, this value contains the required size.
   1845   @param[in]  Attributes                  Attribute value of the variable
   1846   @param[in]  IsPk                        Indicate whether it is to process pk.
   1847 
   1848   @return EFI_INVALID_PARAMETER           Invalid parameter.
   1849   @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation.
   1850                                           check carried out by the firmware.
   1851   @return EFI_SUCCESS                     Variable passed validation successfully.
   1852 
   1853 **/
   1854 EFI_STATUS
   1855 ProcessVarWithPk (
   1856   IN  CHAR16                    *VariableName,
   1857   IN  EFI_GUID                  *VendorGuid,
   1858   IN  VOID                      *Data,
   1859   IN  UINTN                     DataSize,
   1860   IN  UINT32                    Attributes OPTIONAL,
   1861   IN  BOOLEAN                   IsPk
   1862   )
   1863 {
   1864   EFI_STATUS                  Status;
   1865   BOOLEAN                     Del;
   1866   UINT8                       *Payload;
   1867   UINTN                       PayloadSize;
   1868   VARIABLE_ENTRY_CONSISTENCY  VariableEntry[2];
   1869 
   1870   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
   1871       (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
   1872     //
   1873     // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
   1874     // authenticated variable.
   1875     //
   1876     return EFI_INVALID_PARAMETER;
   1877   }
   1878 
   1879   //
   1880   // Init state of Del. State may change due to secure check
   1881   //
   1882   Del = FALSE;
   1883   Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
   1884   PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
   1885   if (PayloadSize == 0) {
   1886     Del = TRUE;
   1887   }
   1888 
   1889   //
   1890   // Check the variable space for both PKpub and SecureBootMode variable.
   1891   //
   1892   VariableEntry[0].VariableSize = PayloadSize;
   1893   VariableEntry[0].Guid         = &gEfiGlobalVariableGuid;
   1894   VariableEntry[0].Name         = EFI_PLATFORM_KEY_NAME;
   1895 
   1896   VariableEntry[1].VariableSize = sizeof(UINT8);
   1897   VariableEntry[1].Guid         = &gEdkiiSecureBootModeGuid;
   1898   VariableEntry[1].Name         = EDKII_SECURE_BOOT_MODE_NAME;
   1899 
   1900   if ((InCustomMode() && UserPhysicalPresent()) ||
   1901       (((mSecureBootMode == SecureBootModeTypeSetupMode) || (mSecureBootMode == SecureBootModeTypeAuditMode)) && !IsPk)) {
   1902 
   1903     Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
   1904     if (EFI_ERROR (Status)) {
   1905       return Status;
   1906     }
   1907 
   1908     //
   1909     // If delete PKpub, only check for "SecureBootMode" only
   1910     // if update / add PKpub, check both NewPKpub & "SecureBootMode"
   1911     //
   1912     if (IsPk) {
   1913       //
   1914       // Delete PKpub
   1915       //
   1916       if (Del && ((mSecureBootMode == SecureBootModeTypeUserMode) || (mSecureBootMode == SecureBootModeTypeDeployedMode))
   1917           && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[1], NULL)){
   1918         return EFI_OUT_OF_RESOURCES;
   1919       //
   1920       // Add PKpub
   1921       //
   1922       } else if (!Del && ((mSecureBootMode == SecureBootModeTypeSetupMode) || (mSecureBootMode == SecureBootModeTypeAuditMode))
   1923                  && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
   1924         return EFI_OUT_OF_RESOURCES;
   1925       }
   1926     }
   1927 
   1928     Status = AuthServiceInternalUpdateVariableWithTimeStamp (
   1929                VariableName,
   1930                VendorGuid,
   1931                Payload,
   1932                PayloadSize,
   1933                Attributes,
   1934                &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
   1935                );
   1936     if (EFI_ERROR(Status)) {
   1937       return Status;
   1938     }
   1939 
   1940     if (((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode != SecureBootModeTypeAuditMode)) || IsPk) {
   1941       Status = VendorKeyIsModified ();
   1942     }
   1943   } else if (mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode == SecureBootModeTypeDeployedMode) {
   1944     //
   1945     // If delete PKpub, check "SecureBootMode" only
   1946     //
   1947     if (IsPk && Del && !mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[1], NULL)){
   1948       return EFI_OUT_OF_RESOURCES;
   1949     }
   1950 
   1951     //
   1952     // Verify against X509 Cert in PK database.
   1953     //
   1954     Status = VerifyTimeBasedPayloadAndUpdate (
   1955                VariableName,
   1956                VendorGuid,
   1957                Data,
   1958                DataSize,
   1959                Attributes,
   1960                AuthVarTypePk,
   1961                &Del
   1962                );
   1963   } else {
   1964     //
   1965     // SetupMode or  AuditMode to add PK
   1966     // Verify against the certificate in data payload.
   1967     //
   1968     //
   1969     // Check PKpub & SecureBootMode variable space consistency
   1970     //
   1971     if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
   1972       //
   1973       // No enough variable space to set PK successfully.
   1974       //
   1975       return EFI_OUT_OF_RESOURCES;
   1976     }
   1977 
   1978     Status = VerifyTimeBasedPayloadAndUpdate (
   1979                VariableName,
   1980                VendorGuid,
   1981                Data,
   1982                DataSize,
   1983                Attributes,
   1984                AuthVarTypePayload,
   1985                &Del
   1986                );
   1987   }
   1988 
   1989   if (!EFI_ERROR(Status) && IsPk) {
   1990     //
   1991     // Delete or Enroll PK causes SecureBootMode change
   1992     //
   1993     if (!Del) {
   1994       if (mSecureBootMode == SecureBootModeTypeSetupMode) {
   1995         //
   1996         // If enroll PK in setup mode,  change to user mode.
   1997         //
   1998         Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeUserMode);
   1999       } else if (mSecureBootMode == SecureBootModeTypeAuditMode) {
   2000         //
   2001         // If enroll PK in Audit mode,  change to Deployed mode.
   2002         //
   2003         Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeDeployedMode);
   2004       } else {
   2005         DEBUG((EFI_D_INFO, "PK is updated in %x mode. No SecureBootMode change.\n", mSecureBootMode));
   2006       }
   2007     } else {
   2008       if ((mSecureBootMode == SecureBootModeTypeUserMode) || (mSecureBootMode == SecureBootModeTypeDeployedMode)) {
   2009         //
   2010         // If delete PK in User Mode or DeployedMode,  change to Setup Mode.
   2011         //
   2012         Status = SecureBootModeTransition (mSecureBootMode, SecureBootModeTypeSetupMode);
   2013       }
   2014     }
   2015   }
   2016 
   2017   return Status;
   2018 }
   2019 
   2020 /**
   2021   Process variable with key exchange key for verification.
   2022 
   2023   Caution: This function may receive untrusted input.
   2024   This function may be invoked in SMM mode, and datasize and data are external input.
   2025   This function will do basic validation, before parse the data.
   2026   This function will parse the authentication carefully to avoid security issues, like
   2027   buffer overflow, integer overflow.
   2028   This function will check attribute carefully to avoid authentication bypass.
   2029 
   2030   @param[in]  VariableName                Name of Variable to be found.
   2031   @param[in]  VendorGuid                  Variable vendor GUID.
   2032   @param[in]  Data                        Data pointer.
   2033   @param[in]  DataSize                    Size of Data found. If size is less than the
   2034                                           data, this value contains the required size.
   2035   @param[in]  Attributes                  Attribute value of the variable.
   2036 
   2037   @return EFI_INVALID_PARAMETER           Invalid parameter.
   2038   @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
   2039                                           check carried out by the firmware.
   2040   @return EFI_SUCCESS                     Variable pass validation successfully.
   2041 
   2042 **/
   2043 EFI_STATUS
   2044 ProcessVarWithKek (
   2045   IN  CHAR16                               *VariableName,
   2046   IN  EFI_GUID                             *VendorGuid,
   2047   IN  VOID                                 *Data,
   2048   IN  UINTN                                DataSize,
   2049   IN  UINT32                               Attributes OPTIONAL
   2050   )
   2051 {
   2052   EFI_STATUS                      Status;
   2053   UINT8                           *Payload;
   2054   UINTN                           PayloadSize;
   2055 
   2056   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
   2057       (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
   2058     //
   2059     // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
   2060     // authenticated variable.
   2061     //
   2062     return EFI_INVALID_PARAMETER;
   2063   }
   2064 
   2065   Status = EFI_SUCCESS;
   2066   if ((mSecureBootMode == SecureBootModeTypeUserMode || mSecureBootMode == SecureBootModeTypeDeployedMode)
   2067    && !(InCustomMode() && UserPhysicalPresent())) {
   2068     //
   2069     // Time-based, verify against X509 Cert KEK.
   2070     //
   2071     return VerifyTimeBasedPayloadAndUpdate (
   2072              VariableName,
   2073              VendorGuid,
   2074              Data,
   2075              DataSize,
   2076              Attributes,
   2077              AuthVarTypeKek,
   2078              NULL
   2079              );
   2080   } else {
   2081     //
   2082     // If in setup mode or custom secure boot mode, no authentication needed.
   2083     //
   2084     Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
   2085     PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
   2086 
   2087     Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
   2088     if (EFI_ERROR (Status)) {
   2089       return Status;
   2090     }
   2091 
   2092     Status = AuthServiceInternalUpdateVariableWithTimeStamp (
   2093                VariableName,
   2094                VendorGuid,
   2095                Payload,
   2096                PayloadSize,
   2097                Attributes,
   2098                &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
   2099                );
   2100     if (EFI_ERROR (Status)) {
   2101       return Status;
   2102     }
   2103 
   2104     if ((mSecureBootMode != SecureBootModeTypeSetupMode) && (mSecureBootMode != SecureBootModeTypeAuditMode)) {
   2105       Status = VendorKeyIsModified ();
   2106     }
   2107   }
   2108 
   2109   return Status;
   2110 }
   2111 
   2112 /**
   2113   Check if it is to delete auth variable.
   2114 
   2115   @param[in] OrgAttributes      Original attribute value of the variable.
   2116   @param[in] Data               Data pointer.
   2117   @param[in] DataSize           Size of Data.
   2118   @param[in] Attributes         Attribute value of the variable.
   2119 
   2120   @retval TRUE                  It is to delete auth variable.
   2121   @retval FALSE                 It is not to delete auth variable.
   2122 
   2123 **/
   2124 BOOLEAN
   2125 IsDeleteAuthVariable (
   2126   IN  UINT32                    OrgAttributes,
   2127   IN  VOID                      *Data,
   2128   IN  UINTN                     DataSize,
   2129   IN  UINT32                    Attributes
   2130   )
   2131 {
   2132   BOOLEAN                       Del;
   2133   UINTN                         PayloadSize;
   2134 
   2135   Del = FALSE;
   2136 
   2137   //
   2138   // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
   2139   // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,
   2140   // SetVariable must be used with attributes matching the existing variable
   2141   // and the DataSize set to the size of the AuthInfo descriptor.
   2142   //
   2143   if ((Attributes == OrgAttributes) &&
   2144       ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) {
   2145     if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
   2146       PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
   2147       if (PayloadSize == 0) {
   2148         Del = TRUE;
   2149       }
   2150     } else {
   2151       PayloadSize = DataSize - AUTHINFO_SIZE;
   2152       if (PayloadSize == 0) {
   2153         Del = TRUE;
   2154       }
   2155     }
   2156   }
   2157 
   2158   return Del;
   2159 }
   2160 
   2161 /**
   2162   Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
   2163 
   2164   Caution: This function may receive untrusted input.
   2165   This function may be invoked in SMM mode, and datasize and data are external input.
   2166   This function will do basic validation, before parse the data.
   2167   This function will parse the authentication carefully to avoid security issues, like
   2168   buffer overflow, integer overflow.
   2169   This function will check attribute carefully to avoid authentication bypass.
   2170 
   2171   @param[in]  VariableName                Name of the variable.
   2172   @param[in]  VendorGuid                  Variable vendor GUID.
   2173   @param[in]  Data                        Data pointer.
   2174   @param[in]  DataSize                    Size of Data.
   2175   @param[in]  Attributes                  Attribute value of the variable.
   2176 
   2177   @return EFI_INVALID_PARAMETER           Invalid parameter.
   2178   @return EFI_WRITE_PROTECTED             Variable is write-protected and needs authentication with
   2179                                           EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
   2180   @return EFI_OUT_OF_RESOURCES            The Database to save the public key is full.
   2181   @return EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
   2182                                           set, but the AuthInfo does NOT pass the validation
   2183                                           check carried out by the firmware.
   2184   @return EFI_SUCCESS                     Variable is not write-protected or pass validation successfully.
   2185 
   2186 **/
   2187 EFI_STATUS
   2188 ProcessVariable (
   2189   IN     CHAR16                             *VariableName,
   2190   IN     EFI_GUID                           *VendorGuid,
   2191   IN     VOID                               *Data,
   2192   IN     UINTN                              DataSize,
   2193   IN     UINT32                             Attributes OPTIONAL
   2194   )
   2195 {
   2196   EFI_STATUS                      Status;
   2197   BOOLEAN                         IsDeletion;
   2198   BOOLEAN                         IsFirstTime;
   2199   UINT8                           *PubKey;
   2200   EFI_VARIABLE_AUTHENTICATION     *CertData;
   2201   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
   2202   UINT32                          KeyIndex;
   2203   UINT64                          MonotonicCount;
   2204   VARIABLE_ENTRY_CONSISTENCY      VariableDataEntry;
   2205   UINT32                          Index;
   2206   AUTH_VARIABLE_INFO              OrgVariableInfo;
   2207 
   2208   KeyIndex    = 0;
   2209   CertData    = NULL;
   2210   CertBlock   = NULL;
   2211   PubKey      = NULL;
   2212   IsDeletion  = FALSE;
   2213   Status      = EFI_SUCCESS;
   2214 
   2215   ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
   2216   Status = mAuthVarLibContextIn->FindVariable (
   2217              VariableName,
   2218              VendorGuid,
   2219              &OrgVariableInfo
   2220              );
   2221 
   2222   if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && UserPhysicalPresent()) {
   2223     //
   2224     // Allow the delete operation of common authenticated variable at user physical presence.
   2225     //
   2226     Status = AuthServiceInternalUpdateVariable (
   2227               VariableName,
   2228               VendorGuid,
   2229               NULL,
   2230               0,
   2231               0
   2232               );
   2233     if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
   2234       Status = DeleteCertsFromDb (VariableName, VendorGuid);
   2235     }
   2236 
   2237     return Status;
   2238   }
   2239 
   2240   if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent()) {
   2241     //
   2242     // This variable is protected, only physical present user could modify its value.
   2243     //
   2244     return EFI_SECURITY_VIOLATION;
   2245   }
   2246 
   2247   //
   2248   // A time-based authenticated variable and a count-based authenticated variable
   2249   // can't be updated by each other.
   2250   //
   2251   if (OrgVariableInfo.Data != NULL) {
   2252     if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&
   2253         ((OrgVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
   2254       return EFI_SECURITY_VIOLATION;
   2255     }
   2256 
   2257     if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
   2258         ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {
   2259       return EFI_SECURITY_VIOLATION;
   2260     }
   2261   }
   2262 
   2263   //
   2264   // Process Time-based Authenticated variable.
   2265   //
   2266   if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
   2267     return VerifyTimeBasedPayloadAndUpdate (
   2268              VariableName,
   2269              VendorGuid,
   2270              Data,
   2271              DataSize,
   2272              Attributes,
   2273              AuthVarTypePriv,
   2274              NULL
   2275              );
   2276   }
   2277 
   2278   //
   2279   // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
   2280   //
   2281   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
   2282     //
   2283     // Determine current operation type.
   2284     //
   2285     if (DataSize == AUTHINFO_SIZE) {
   2286       IsDeletion = TRUE;
   2287     }
   2288     //
   2289     // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
   2290     //
   2291     if (OrgVariableInfo.Data == NULL) {
   2292       IsFirstTime = TRUE;
   2293     } else if ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
   2294       IsFirstTime = TRUE;
   2295     } else {
   2296       KeyIndex   = OrgVariableInfo.PubKeyIndex;
   2297       IsFirstTime = FALSE;
   2298     }
   2299   } else if ((OrgVariableInfo.Data != NULL) &&
   2300              ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)
   2301             ) {
   2302     //
   2303     // If the variable is already write-protected, it always needs authentication before update.
   2304     //
   2305     return EFI_WRITE_PROTECTED;
   2306   } else {
   2307     //
   2308     // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
   2309     // That means it is not authenticated variable, just update variable as usual.
   2310     //
   2311     Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
   2312     return Status;
   2313   }
   2314 
   2315   //
   2316   // Get PubKey and check Monotonic Count value corresponding to the variable.
   2317   //
   2318   CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
   2319   CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
   2320   PubKey    = CertBlock->PublicKey;
   2321 
   2322   //
   2323   // Update Monotonic Count value.
   2324   //
   2325   MonotonicCount = CertData->MonotonicCount;
   2326 
   2327   if (!IsFirstTime) {
   2328     //
   2329     // 2 cases need to check here
   2330     //   1. Internal PubKey variable. PubKeyIndex is always 0
   2331     //   2. Other counter-based AuthVariable. Check input PubKey.
   2332     //
   2333     if (KeyIndex == 0) {
   2334       return EFI_SECURITY_VIOLATION;
   2335     }
   2336     for (Index = 0; Index < mPubKeyNumber; Index++) {
   2337       if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == KeyIndex) {
   2338         if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
   2339           break;
   2340         } else {
   2341           return EFI_SECURITY_VIOLATION;
   2342         }
   2343       }
   2344     }
   2345     if (Index == mPubKeyNumber) {
   2346       return EFI_SECURITY_VIOLATION;
   2347     }
   2348 
   2349     //
   2350     // Compare the current monotonic count and ensure that it is greater than the last SetVariable
   2351     // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
   2352     //
   2353     if (MonotonicCount <= OrgVariableInfo.MonotonicCount) {
   2354       //
   2355       // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
   2356       //
   2357       return EFI_SECURITY_VIOLATION;
   2358     }
   2359   }
   2360   //
   2361   // Verify the certificate in Data payload.
   2362   //
   2363   Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
   2364   if (EFI_ERROR (Status)) {
   2365     return Status;
   2366   }
   2367 
   2368   //
   2369   // Now, the signature has been verified!
   2370   //
   2371   if (IsFirstTime && !IsDeletion) {
   2372     VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;
   2373     VariableDataEntry.Guid         = VendorGuid;
   2374     VariableDataEntry.Name         = VariableName;
   2375 
   2376     //
   2377     // Update public key database variable if need.
   2378     //
   2379     KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);
   2380     if (KeyIndex == 0) {
   2381       return EFI_OUT_OF_RESOURCES;
   2382     }
   2383   }
   2384 
   2385   //
   2386   // Verification pass.
   2387   //
   2388   return AuthServiceInternalUpdateVariableWithMonotonicCount (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount);
   2389 }
   2390 
   2391 /**
   2392   Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
   2393 
   2394   @param[in]        Data          Pointer to original EFI_SIGNATURE_LIST.
   2395   @param[in]        DataSize      Size of Data buffer.
   2396   @param[in, out]   NewData       Pointer to new EFI_SIGNATURE_LIST.
   2397   @param[in, out]   NewDataSize   Size of NewData buffer.
   2398 
   2399 **/
   2400 EFI_STATUS
   2401 FilterSignatureList (
   2402   IN     VOID       *Data,
   2403   IN     UINTN      DataSize,
   2404   IN OUT VOID       *NewData,
   2405   IN OUT UINTN      *NewDataSize
   2406   )
   2407 {
   2408   EFI_SIGNATURE_LIST    *CertList;
   2409   EFI_SIGNATURE_DATA    *Cert;
   2410   UINTN                 CertCount;
   2411   EFI_SIGNATURE_LIST    *NewCertList;
   2412   EFI_SIGNATURE_DATA    *NewCert;
   2413   UINTN                 NewCertCount;
   2414   UINTN                 Index;
   2415   UINTN                 Index2;
   2416   UINTN                 Size;
   2417   UINT8                 *Tail;
   2418   UINTN                 CopiedCount;
   2419   UINTN                 SignatureListSize;
   2420   BOOLEAN               IsNewCert;
   2421   UINT8                 *TempData;
   2422   UINTN                 TempDataSize;
   2423   EFI_STATUS            Status;
   2424 
   2425   if (*NewDataSize == 0) {
   2426     return EFI_SUCCESS;
   2427   }
   2428 
   2429   TempDataSize = *NewDataSize;
   2430   Status = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **) &TempData);
   2431   if (EFI_ERROR (Status)) {
   2432     return EFI_OUT_OF_RESOURCES;
   2433   }
   2434 
   2435   Tail = TempData;
   2436 
   2437   NewCertList = (EFI_SIGNATURE_LIST *) NewData;
   2438   while ((*NewDataSize > 0) && (*NewDataSize >= NewCertList->SignatureListSize)) {
   2439     NewCert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
   2440     NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
   2441 
   2442     CopiedCount = 0;
   2443     for (Index = 0; Index < NewCertCount; Index++) {
   2444       IsNewCert = TRUE;
   2445 
   2446       Size = DataSize;
   2447       CertList = (EFI_SIGNATURE_LIST *) Data;
   2448       while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
   2449         if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
   2450            (CertList->SignatureSize == NewCertList->SignatureSize)) {
   2451           Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
   2452           CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
   2453           for (Index2 = 0; Index2 < CertCount; Index2++) {
   2454             //
   2455             // Iterate each Signature Data in this Signature List.
   2456             //
   2457             if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
   2458               IsNewCert = FALSE;
   2459               break;
   2460             }
   2461             Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
   2462           }
   2463         }
   2464 
   2465         if (!IsNewCert) {
   2466           break;
   2467         }
   2468         Size -= CertList->SignatureListSize;
   2469         CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
   2470       }
   2471 
   2472       if (IsNewCert) {
   2473         //
   2474         // New EFI_SIGNATURE_DATA, keep it.
   2475         //
   2476         if (CopiedCount == 0) {
   2477           //
   2478           // Copy EFI_SIGNATURE_LIST header for only once.
   2479           //
   2480           CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
   2481           Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
   2482         }
   2483 
   2484         CopyMem (Tail, NewCert, NewCertList->SignatureSize);
   2485         Tail += NewCertList->SignatureSize;
   2486         CopiedCount++;
   2487       }
   2488 
   2489       NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
   2490     }
   2491 
   2492     //
   2493     // Update SignatureListSize in the kept EFI_SIGNATURE_LIST.
   2494     //
   2495     if (CopiedCount != 0) {
   2496       SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
   2497       CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
   2498       CertList->SignatureListSize = (UINT32) SignatureListSize;
   2499     }
   2500 
   2501     *NewDataSize -= NewCertList->SignatureListSize;
   2502     NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
   2503   }
   2504 
   2505   TempDataSize = (Tail - (UINT8 *) TempData);
   2506 
   2507   CopyMem (NewData, TempData, TempDataSize);
   2508   *NewDataSize = TempDataSize;
   2509 
   2510   return EFI_SUCCESS;
   2511 }
   2512 
   2513 /**
   2514   Compare two EFI_TIME data.
   2515 
   2516 
   2517   @param FirstTime           A pointer to the first EFI_TIME data.
   2518   @param SecondTime          A pointer to the second EFI_TIME data.
   2519 
   2520   @retval  TRUE              The FirstTime is not later than the SecondTime.
   2521   @retval  FALSE             The FirstTime is later than the SecondTime.
   2522 
   2523 **/
   2524 BOOLEAN
   2525 AuthServiceInternalCompareTimeStamp (
   2526   IN EFI_TIME               *FirstTime,
   2527   IN EFI_TIME               *SecondTime
   2528   )
   2529 {
   2530   if (FirstTime->Year != SecondTime->Year) {
   2531     return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
   2532   } else if (FirstTime->Month != SecondTime->Month) {
   2533     return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
   2534   } else if (FirstTime->Day != SecondTime->Day) {
   2535     return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
   2536   } else if (FirstTime->Hour != SecondTime->Hour) {
   2537     return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
   2538   } else if (FirstTime->Minute != SecondTime->Minute) {
   2539     return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
   2540   }
   2541 
   2542   return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
   2543 }
   2544 
   2545 /**
   2546   Find matching signer's certificates for common authenticated variable
   2547   by corresponding VariableName and VendorGuid from "certdb".
   2548 
   2549   The data format of "certdb":
   2550   //
   2551   //     UINT32 CertDbListSize;
   2552   // /// AUTH_CERT_DB_DATA Certs1[];
   2553   // /// AUTH_CERT_DB_DATA Certs2[];
   2554   // /// ...
   2555   // /// AUTH_CERT_DB_DATA Certsn[];
   2556   //
   2557 
   2558   @param[in]  VariableName   Name of authenticated Variable.
   2559   @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
   2560   @param[in]  Data           Pointer to variable "certdb".
   2561   @param[in]  DataSize       Size of variable "certdb".
   2562   @param[out] CertOffset     Offset of matching CertData, from starting of Data.
   2563   @param[out] CertDataSize   Length of CertData in bytes.
   2564   @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
   2565                              starting of Data.
   2566   @param[out] CertNodeSize   Length of AUTH_CERT_DB_DATA in bytes.
   2567 
   2568   @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
   2569   @retval  EFI_NOT_FOUND         Fail to find matching certs.
   2570   @retval  EFI_SUCCESS           Find matching certs and output parameters.
   2571 
   2572 **/
   2573 EFI_STATUS
   2574 FindCertsFromDb (
   2575   IN     CHAR16           *VariableName,
   2576   IN     EFI_GUID         *VendorGuid,
   2577   IN     UINT8            *Data,
   2578   IN     UINTN            DataSize,
   2579   OUT    UINT32           *CertOffset,    OPTIONAL
   2580   OUT    UINT32           *CertDataSize,  OPTIONAL
   2581   OUT    UINT32           *CertNodeOffset,OPTIONAL
   2582   OUT    UINT32           *CertNodeSize   OPTIONAL
   2583   )
   2584 {
   2585   UINT32                  Offset;
   2586   AUTH_CERT_DB_DATA       *Ptr;
   2587   UINT32                  CertSize;
   2588   UINT32                  NameSize;
   2589   UINT32                  NodeSize;
   2590   UINT32                  CertDbListSize;
   2591 
   2592   if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
   2593     return EFI_INVALID_PARAMETER;
   2594   }
   2595 
   2596   //
   2597   // Check whether DataSize matches recorded CertDbListSize.
   2598   //
   2599   if (DataSize < sizeof (UINT32)) {
   2600     return EFI_INVALID_PARAMETER;
   2601   }
   2602 
   2603   CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);
   2604 
   2605   if (CertDbListSize != (UINT32) DataSize) {
   2606     return EFI_INVALID_PARAMETER;
   2607   }
   2608 
   2609   Offset = sizeof (UINT32);
   2610 
   2611   //
   2612   // Get corresponding certificates by VendorGuid and VariableName.
   2613   //
   2614   while (Offset < (UINT32) DataSize) {
   2615     Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
   2616     //
   2617     // Check whether VendorGuid matches.
   2618     //
   2619     if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
   2620       NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
   2621       NameSize = ReadUnaligned32 (&Ptr->NameSize);
   2622       CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
   2623 
   2624       if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
   2625           sizeof (CHAR16) * NameSize) {
   2626         return EFI_INVALID_PARAMETER;
   2627       }
   2628 
   2629       Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
   2630       //
   2631       // Check whether VariableName matches.
   2632       //
   2633       if ((NameSize == StrLen (VariableName)) &&
   2634           (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {
   2635         Offset = Offset + NameSize * sizeof (CHAR16);
   2636 
   2637         if (CertOffset != NULL) {
   2638           *CertOffset = Offset;
   2639         }
   2640 
   2641         if (CertDataSize != NULL) {
   2642           *CertDataSize = CertSize;
   2643         }
   2644 
   2645         if (CertNodeOffset != NULL) {
   2646           *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);
   2647         }
   2648 
   2649         if (CertNodeSize != NULL) {
   2650           *CertNodeSize = NodeSize;
   2651         }
   2652 
   2653         return EFI_SUCCESS;
   2654       } else {
   2655         Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
   2656       }
   2657     } else {
   2658       NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
   2659       Offset   = Offset + NodeSize;
   2660     }
   2661   }
   2662 
   2663   return EFI_NOT_FOUND;
   2664 }
   2665 
   2666 /**
   2667   Retrieve signer's certificates for common authenticated variable
   2668   by corresponding VariableName and VendorGuid from "certdb".
   2669 
   2670   @param[in]  VariableName   Name of authenticated Variable.
   2671   @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
   2672   @param[out] CertData       Pointer to signer's certificates.
   2673   @param[out] CertDataSize   Length of CertData in bytes.
   2674 
   2675   @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
   2676   @retval  EFI_NOT_FOUND         Fail to find "certdb" or matching certs.
   2677   @retval  EFI_SUCCESS           Get signer's certificates successfully.
   2678 
   2679 **/
   2680 EFI_STATUS
   2681 GetCertsFromDb (
   2682   IN     CHAR16           *VariableName,
   2683   IN     EFI_GUID         *VendorGuid,
   2684   OUT    UINT8            **CertData,
   2685   OUT    UINT32           *CertDataSize
   2686   )
   2687 {
   2688   EFI_STATUS              Status;
   2689   UINT8                   *Data;
   2690   UINTN                   DataSize;
   2691   UINT32                  CertOffset;
   2692 
   2693   if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
   2694     return EFI_INVALID_PARAMETER;
   2695   }
   2696 
   2697   //
   2698   // Get variable "certdb".
   2699   //
   2700   Status = AuthServiceInternalFindVariable (
   2701              EFI_CERT_DB_NAME,
   2702              &gEfiCertDbGuid,
   2703              (VOID **) &Data,
   2704              &DataSize
   2705              );
   2706   if (EFI_ERROR (Status)) {
   2707     return Status;
   2708   }
   2709 
   2710   if ((DataSize == 0) || (Data == NULL)) {
   2711     ASSERT (FALSE);
   2712     return EFI_NOT_FOUND;
   2713   }
   2714 
   2715   Status = FindCertsFromDb (
   2716              VariableName,
   2717              VendorGuid,
   2718              Data,
   2719              DataSize,
   2720              &CertOffset,
   2721              CertDataSize,
   2722              NULL,
   2723              NULL
   2724              );
   2725 
   2726   if (EFI_ERROR (Status)) {
   2727     return Status;
   2728   }
   2729 
   2730   *CertData = Data + CertOffset;
   2731   return EFI_SUCCESS;
   2732 }
   2733 
   2734 /**
   2735   Delete matching signer's certificates when deleting common authenticated
   2736   variable by corresponding VariableName and VendorGuid from "certdb".
   2737 
   2738   @param[in]  VariableName   Name of authenticated Variable.
   2739   @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
   2740 
   2741   @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
   2742   @retval  EFI_NOT_FOUND         Fail to find "certdb" or matching certs.
   2743   @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.
   2744   @retval  EFI_SUCCESS           The operation is completed successfully.
   2745 
   2746 **/
   2747 EFI_STATUS
   2748 DeleteCertsFromDb (
   2749   IN     CHAR16           *VariableName,
   2750   IN     EFI_GUID         *VendorGuid
   2751   )
   2752 {
   2753   EFI_STATUS              Status;
   2754   UINT8                   *Data;
   2755   UINTN                   DataSize;
   2756   UINT32                  VarAttr;
   2757   UINT32                  CertNodeOffset;
   2758   UINT32                  CertNodeSize;
   2759   UINT8                   *NewCertDb;
   2760   UINT32                  NewCertDbSize;
   2761 
   2762   if ((VariableName == NULL) || (VendorGuid == NULL)) {
   2763     return EFI_INVALID_PARAMETER;
   2764   }
   2765 
   2766   //
   2767   // Get variable "certdb".
   2768   //
   2769   Status = AuthServiceInternalFindVariable (
   2770              EFI_CERT_DB_NAME,
   2771              &gEfiCertDbGuid,
   2772              (VOID **) &Data,
   2773              &DataSize
   2774              );
   2775   if (EFI_ERROR (Status)) {
   2776     return Status;
   2777   }
   2778 
   2779   if ((DataSize == 0) || (Data == NULL)) {
   2780     ASSERT (FALSE);
   2781     return EFI_NOT_FOUND;
   2782   }
   2783 
   2784   if (DataSize == sizeof (UINT32)) {
   2785     //
   2786     // There is no certs in certdb.
   2787     //
   2788     return EFI_SUCCESS;
   2789   }
   2790 
   2791   //
   2792   // Get corresponding cert node from certdb.
   2793   //
   2794   Status = FindCertsFromDb (
   2795              VariableName,
   2796              VendorGuid,
   2797              Data,
   2798              DataSize,
   2799              NULL,
   2800              NULL,
   2801              &CertNodeOffset,
   2802              &CertNodeSize
   2803              );
   2804 
   2805   if (EFI_ERROR (Status)) {
   2806     return Status;
   2807   }
   2808 
   2809   if (DataSize < (CertNodeOffset + CertNodeSize)) {
   2810     return EFI_NOT_FOUND;
   2811   }
   2812 
   2813   //
   2814   // Construct new data content of variable "certdb".
   2815   //
   2816   NewCertDbSize = (UINT32) DataSize - CertNodeSize;
   2817   NewCertDb     = (UINT8*) mCertDbStore;
   2818 
   2819   //
   2820   // Copy the DB entries before deleting node.
   2821   //
   2822   CopyMem (NewCertDb, Data, CertNodeOffset);
   2823   //
   2824   // Update CertDbListSize.
   2825   //
   2826   CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
   2827   //
   2828   // Copy the DB entries after deleting node.
   2829   //
   2830   if (DataSize > (CertNodeOffset + CertNodeSize)) {
   2831     CopyMem (
   2832       NewCertDb + CertNodeOffset,
   2833       Data + CertNodeOffset + CertNodeSize,
   2834       DataSize - CertNodeOffset - CertNodeSize
   2835       );
   2836   }
   2837 
   2838   //
   2839   // Set "certdb".
   2840   //
   2841   VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
   2842   Status   = AuthServiceInternalUpdateVariable (
   2843                EFI_CERT_DB_NAME,
   2844                &gEfiCertDbGuid,
   2845                NewCertDb,
   2846                NewCertDbSize,
   2847                VarAttr
   2848                );
   2849 
   2850   return Status;
   2851 }
   2852 
   2853 /**
   2854   Insert signer's certificates for common authenticated variable with VariableName
   2855   and VendorGuid in AUTH_CERT_DB_DATA to "certdb".
   2856 
   2857   @param[in]  VariableName   Name of authenticated Variable.
   2858   @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
   2859   @param[in]  CertData       Pointer to signer's certificates.
   2860   @param[in]  CertDataSize   Length of CertData in bytes.
   2861 
   2862   @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
   2863   @retval  EFI_ACCESS_DENIED     An AUTH_CERT_DB_DATA entry with same VariableName
   2864                                  and VendorGuid already exists.
   2865   @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.
   2866   @retval  EFI_SUCCESS           Insert an AUTH_CERT_DB_DATA entry to "certdb"
   2867 
   2868 **/
   2869 EFI_STATUS
   2870 InsertCertsToDb (
   2871   IN     CHAR16           *VariableName,
   2872   IN     EFI_GUID         *VendorGuid,
   2873   IN     UINT8            *CertData,
   2874   IN     UINTN            CertDataSize
   2875   )
   2876 {
   2877   EFI_STATUS              Status;
   2878   UINT8                   *Data;
   2879   UINTN                   DataSize;
   2880   UINT32                  VarAttr;
   2881   UINT8                   *NewCertDb;
   2882   UINT32                  NewCertDbSize;
   2883   UINT32                  CertNodeSize;
   2884   UINT32                  NameSize;
   2885   AUTH_CERT_DB_DATA       *Ptr;
   2886 
   2887   if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
   2888     return EFI_INVALID_PARAMETER;
   2889   }
   2890 
   2891   //
   2892   // Get variable "certdb".
   2893   //
   2894   Status = AuthServiceInternalFindVariable (
   2895              EFI_CERT_DB_NAME,
   2896              &gEfiCertDbGuid,
   2897              (VOID **) &Data,
   2898              &DataSize
   2899              );
   2900   if (EFI_ERROR (Status)) {
   2901     return Status;
   2902   }
   2903 
   2904   if ((DataSize == 0) || (Data == NULL)) {
   2905     ASSERT (FALSE);
   2906     return EFI_NOT_FOUND;
   2907   }
   2908 
   2909   //
   2910   // Find whether matching cert node already exists in "certdb".
   2911   // If yes return error.
   2912   //
   2913   Status = FindCertsFromDb (
   2914              VariableName,
   2915              VendorGuid,
   2916              Data,
   2917              DataSize,
   2918              NULL,
   2919              NULL,
   2920              NULL,
   2921              NULL
   2922              );
   2923 
   2924   if (!EFI_ERROR (Status)) {
   2925     ASSERT (FALSE);
   2926     return EFI_ACCESS_DENIED;
   2927   }
   2928 
   2929   //
   2930   // Construct new data content of variable "certdb".
   2931   //
   2932   NameSize      = (UINT32) StrLen (VariableName);
   2933   CertNodeSize  = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);
   2934   NewCertDbSize = (UINT32) DataSize + CertNodeSize;
   2935   if (NewCertDbSize > mMaxCertDbSize) {
   2936     return EFI_OUT_OF_RESOURCES;
   2937   }
   2938   NewCertDb     = (UINT8*) mCertDbStore;
   2939 
   2940   //
   2941   // Copy the DB entries before inserting node.
   2942   //
   2943   CopyMem (NewCertDb, Data, DataSize);
   2944   //
   2945   // Update CertDbListSize.
   2946   //
   2947   CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
   2948   //
   2949   // Construct new cert node.
   2950   //
   2951   Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);
   2952   CopyGuid (&Ptr->VendorGuid, VendorGuid);
   2953   CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
   2954   CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
   2955   CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
   2956 
   2957   CopyMem (
   2958     (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),
   2959     VariableName,
   2960     NameSize * sizeof (CHAR16)
   2961     );
   2962 
   2963   CopyMem (
   2964     (UINT8 *) Ptr +  sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
   2965     CertData,
   2966     CertDataSize
   2967     );
   2968 
   2969   //
   2970   // Set "certdb".
   2971   //
   2972   VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
   2973   Status   = AuthServiceInternalUpdateVariable (
   2974                EFI_CERT_DB_NAME,
   2975                &gEfiCertDbGuid,
   2976                NewCertDb,
   2977                NewCertDbSize,
   2978                VarAttr
   2979                );
   2980 
   2981   return Status;
   2982 }
   2983 
   2984 /**
   2985   Clean up signer's certificates for common authenticated variable
   2986   by corresponding VariableName and VendorGuid from "certdb".
   2987   System may break down during Timebased Variable update & certdb update,
   2988   make them inconsistent,  this function is called in AuthVariable Init
   2989   to ensure consistency.
   2990 
   2991   @retval  EFI_NOT_FOUND         Fail to find variable "certdb".
   2992   @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.
   2993   @retval  EFI_SUCCESS           The operation is completed successfully.
   2994 
   2995 **/
   2996 EFI_STATUS
   2997 CleanCertsFromDb (
   2998   VOID
   2999   )
   3000 {
   3001   UINT32                  Offset;
   3002   AUTH_CERT_DB_DATA       *Ptr;
   3003   UINT32                  NameSize;
   3004   UINT32                  NodeSize;
   3005   CHAR16                  *VariableName;
   3006   EFI_STATUS              Status;
   3007   BOOLEAN                 CertCleaned;
   3008   UINT8                   *Data;
   3009   UINTN                   DataSize;
   3010   UINT8                   *AuthVarData;
   3011   UINTN                   AuthVarDataSize;
   3012   EFI_GUID                AuthVarGuid;
   3013 
   3014   Status = EFI_SUCCESS;
   3015 
   3016   //
   3017   // Get corresponding certificates by VendorGuid and VariableName.
   3018   //
   3019   do {
   3020     CertCleaned = FALSE;
   3021 
   3022     //
   3023     // Get latest variable "certdb"
   3024     //
   3025     Status = AuthServiceInternalFindVariable (
   3026                EFI_CERT_DB_NAME,
   3027                &gEfiCertDbGuid,
   3028                (VOID **) &Data,
   3029                &DataSize
   3030                );
   3031     if (EFI_ERROR (Status)) {
   3032       return Status;
   3033     }
   3034 
   3035     if ((DataSize == 0) || (Data == NULL)) {
   3036       ASSERT (FALSE);
   3037       return EFI_NOT_FOUND;
   3038     }
   3039 
   3040     Offset = sizeof (UINT32);
   3041 
   3042     while (Offset < (UINT32) DataSize) {
   3043       Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
   3044       NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
   3045       NameSize = ReadUnaligned32 (&Ptr->NameSize);
   3046 
   3047       //
   3048       // Get VarName tailed with '\0'
   3049       //
   3050       VariableName = AllocateZeroPool((NameSize + 1) * sizeof(CHAR16));
   3051       if (VariableName == NULL) {
   3052         return EFI_OUT_OF_RESOURCES;
   3053       }
   3054       CopyMem (VariableName, (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof(CHAR16));
   3055       //
   3056       // Keep VarGuid  aligned
   3057       //
   3058       CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof(EFI_GUID));
   3059 
   3060       //
   3061       // Find corresponding time auth variable
   3062       //
   3063       Status = AuthServiceInternalFindVariable (
   3064                  VariableName,
   3065                  &AuthVarGuid,
   3066                  (VOID **) &AuthVarData,
   3067                  &AuthVarDataSize
   3068                  );
   3069 
   3070       if (EFI_ERROR(Status)) {
   3071         Status      = DeleteCertsFromDb(VariableName, &AuthVarGuid);
   3072         CertCleaned = TRUE;
   3073         DEBUG((EFI_D_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid));
   3074         FreePool(VariableName);
   3075         break;
   3076       }
   3077 
   3078       FreePool(VariableName);
   3079       Offset = Offset + NodeSize;
   3080     }
   3081   } while (CertCleaned);
   3082 
   3083   return Status;
   3084 }
   3085 
   3086 /**
   3087   Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
   3088 
   3089   Caution: This function may receive untrusted input.
   3090   This function may be invoked in SMM mode, and datasize and data are external input.
   3091   This function will do basic validation, before parse the data.
   3092   This function will parse the authentication carefully to avoid security issues, like
   3093   buffer overflow, integer overflow.
   3094 
   3095   @param[in]  VariableName                Name of Variable to be found.
   3096   @param[in]  VendorGuid                  Variable vendor GUID.
   3097   @param[in]  Data                        Data pointer.
   3098   @param[in]  DataSize                    Size of Data found. If size is less than the
   3099                                           data, this value contains the required size.
   3100   @param[in]  Attributes                  Attribute value of the variable.
   3101   @param[in]  AuthVarType                 Verify against PK, KEK database, private database or certificate in data payload.
   3102   @param[in]  OrgTimeStamp                Pointer to original time stamp,
   3103                                           original variable is not found if NULL.
   3104   @param[out]  VarPayloadPtr              Pointer to variable payload address.
   3105   @param[out]  VarPayloadSize             Pointer to variable payload size.
   3106 
   3107   @retval EFI_INVALID_PARAMETER           Invalid parameter.
   3108   @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
   3109                                           check carried out by the firmware.
   3110   @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack
   3111                                           of resources.
   3112   @retval EFI_SUCCESS                     Variable pass validation successfully.
   3113 
   3114 **/
   3115 EFI_STATUS
   3116 VerifyTimeBasedPayload (
   3117   IN     CHAR16                             *VariableName,
   3118   IN     EFI_GUID                           *VendorGuid,
   3119   IN     VOID                               *Data,
   3120   IN     UINTN                              DataSize,
   3121   IN     UINT32                             Attributes,
   3122   IN     AUTHVAR_TYPE                       AuthVarType,
   3123   IN     EFI_TIME                           *OrgTimeStamp,
   3124   OUT    UINT8                              **VarPayloadPtr,
   3125   OUT    UINTN                              *VarPayloadSize
   3126   )
   3127 {
   3128   EFI_VARIABLE_AUTHENTICATION_2    *CertData;
   3129   UINT8                            *SigData;
   3130   UINT32                           SigDataSize;
   3131   UINT8                            *PayloadPtr;
   3132   UINTN                            PayloadSize;
   3133   UINT32                           Attr;
   3134   BOOLEAN                          VerifyStatus;
   3135   EFI_STATUS                       Status;
   3136   EFI_SIGNATURE_LIST               *CertList;
   3137   EFI_SIGNATURE_DATA               *Cert;
   3138   UINTN                            Index;
   3139   UINTN                            CertCount;
   3140   UINT32                           KekDataSize;
   3141   UINT8                            *NewData;
   3142   UINTN                            NewDataSize;
   3143   UINT8                            *Buffer;
   3144   UINTN                            Length;
   3145   UINT8                            *RootCert;
   3146   UINTN                            RootCertSize;
   3147   UINT8                            *SignerCerts;
   3148   UINTN                            CertStackSize;
   3149   UINT8                            *CertsInCertDb;
   3150   UINT32                           CertsSizeinDb;
   3151 
   3152   VerifyStatus           = FALSE;
   3153   CertData               = NULL;
   3154   NewData                = NULL;
   3155   Attr                   = Attributes;
   3156   SignerCerts            = NULL;
   3157   RootCert               = NULL;
   3158   CertsInCertDb          = NULL;
   3159 
   3160   //
   3161   // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
   3162   // set, then the Data buffer shall begin with an instance of a complete (and serialized)
   3163   // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
   3164   // variable value and DataSize shall reflect the combined size of the descriptor and the new
   3165   // variable value. The authentication descriptor is not part of the variable data and is not
   3166   // returned by subsequent calls to GetVariable().
   3167   //
   3168   CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
   3169 
   3170   //
   3171   // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
   3172   // TimeStamp value are set to zero.
   3173   //
   3174   if ((CertData->TimeStamp.Pad1 != 0) ||
   3175       (CertData->TimeStamp.Nanosecond != 0) ||
   3176       (CertData->TimeStamp.TimeZone != 0) ||
   3177       (CertData->TimeStamp.Daylight != 0) ||
   3178       (CertData->TimeStamp.Pad2 != 0)) {
   3179     return EFI_SECURITY_VIOLATION;
   3180   }
   3181 
   3182   if ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
   3183     if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) {
   3184       //
   3185       // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
   3186       //
   3187       return EFI_SECURITY_VIOLATION;
   3188     }
   3189   }
   3190 
   3191   //
   3192   // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
   3193   // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
   3194   //
   3195   if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
   3196       !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
   3197     //
   3198     // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
   3199     //
   3200     return EFI_SECURITY_VIOLATION;
   3201   }
   3202 
   3203   //
   3204   // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
   3205   // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
   3206   //
   3207   SigData = CertData->AuthInfo.CertData;
   3208   SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
   3209 
   3210   //
   3211   // Find out the new data payload which follows Pkcs7 SignedData directly.
   3212   //
   3213   PayloadPtr = SigData + SigDataSize;
   3214   PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
   3215 
   3216   //
   3217   // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes
   3218   // parameters of the SetVariable() call and the TimeStamp component of the
   3219   // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
   3220   // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
   3221   //
   3222   NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
   3223                 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
   3224 
   3225   //
   3226   // Here is to reuse scratch data area(at the end of volatile variable store)
   3227   // to reduce SMRAM consumption for SMM variable driver.
   3228   // The scratch buffer is enough to hold the serialized data and safe to use,
   3229   // because it is only used at here to do verification temporarily first
   3230   // and then used in UpdateVariable() for a time based auth variable set.
   3231   //
   3232   Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **) &NewData);
   3233   if (EFI_ERROR (Status)) {
   3234     return EFI_OUT_OF_RESOURCES;
   3235   }
   3236 
   3237   Buffer = NewData;
   3238   Length = StrLen (VariableName) * sizeof (CHAR16);
   3239   CopyMem (Buffer, VariableName, Length);
   3240   Buffer += Length;
   3241 
   3242   Length = sizeof (EFI_GUID);
   3243   CopyMem (Buffer, VendorGuid, Length);
   3244   Buffer += Length;
   3245 
   3246   Length = sizeof (UINT32);
   3247   CopyMem (Buffer, &Attr, Length);
   3248   Buffer += Length;
   3249 
   3250   Length = sizeof (EFI_TIME);
   3251   CopyMem (Buffer, &CertData->TimeStamp, Length);
   3252   Buffer += Length;
   3253 
   3254   CopyMem (Buffer, PayloadPtr, PayloadSize);
   3255 
   3256   if (AuthVarType == AuthVarTypePk) {
   3257     //
   3258     // Verify that the signature has been made with the current Platform Key (no chaining for PK).
   3259     // First, get signer's certificates from SignedData.
   3260     //
   3261     VerifyStatus = Pkcs7GetSigners (
   3262                      SigData,
   3263                      SigDataSize,
   3264                      &SignerCerts,
   3265                      &CertStackSize,
   3266                      &RootCert,
   3267                      &RootCertSize
   3268                      );
   3269     if (!VerifyStatus) {
   3270       goto Exit;
   3271     }
   3272 
   3273     //
   3274     // Second, get the current platform key from variable. Check whether it's identical with signer's certificates
   3275     // in SignedData. If not, return error immediately.
   3276     //
   3277     Status = AuthServiceInternalFindVariable (
   3278                EFI_PLATFORM_KEY_NAME,
   3279                &gEfiGlobalVariableGuid,
   3280                &Data,
   3281                &DataSize
   3282                );
   3283     if (EFI_ERROR (Status)) {
   3284       VerifyStatus = FALSE;
   3285       goto Exit;
   3286     }
   3287     CertList = (EFI_SIGNATURE_LIST *) Data;
   3288     Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
   3289     if ((RootCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||
   3290         (CompareMem (Cert->SignatureData, RootCert, RootCertSize) != 0)) {
   3291       VerifyStatus = FALSE;
   3292       goto Exit;
   3293     }
   3294 
   3295     //
   3296     // Verify Pkcs7 SignedData via Pkcs7Verify library.
   3297     //
   3298     VerifyStatus = Pkcs7Verify (
   3299                      SigData,
   3300                      SigDataSize,
   3301                      RootCert,
   3302                      RootCertSize,
   3303                      NewData,
   3304                      NewDataSize
   3305                      );
   3306 
   3307   } else if (AuthVarType == AuthVarTypeKek) {
   3308 
   3309     //
   3310     // Get KEK database from variable.
   3311     //
   3312     Status = AuthServiceInternalFindVariable (
   3313                EFI_KEY_EXCHANGE_KEY_NAME,
   3314                &gEfiGlobalVariableGuid,
   3315                &Data,
   3316                &DataSize
   3317                );
   3318     if (EFI_ERROR (Status)) {
   3319       return Status;
   3320     }
   3321 
   3322     //
   3323     // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
   3324     //
   3325     KekDataSize      = (UINT32) DataSize;
   3326     CertList         = (EFI_SIGNATURE_LIST *) Data;
   3327     while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
   3328       if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
   3329         Cert       = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
   3330         CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
   3331         for (Index = 0; Index < CertCount; Index++) {
   3332           //
   3333           // Iterate each Signature Data Node within this CertList for a verify
   3334           //
   3335           RootCert      = Cert->SignatureData;
   3336           RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
   3337 
   3338           //
   3339           // Verify Pkcs7 SignedData via Pkcs7Verify library.
   3340           //
   3341           VerifyStatus = Pkcs7Verify (
   3342                            SigData,
   3343                            SigDataSize,
   3344                            RootCert,
   3345                            RootCertSize,
   3346                            NewData,
   3347                            NewDataSize
   3348                            );
   3349           if (VerifyStatus) {
   3350             goto Exit;
   3351           }
   3352           Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
   3353         }
   3354       }
   3355       KekDataSize -= CertList->SignatureListSize;
   3356       CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
   3357     }
   3358   } else if (AuthVarType == AuthVarTypePriv) {
   3359 
   3360     //
   3361     // Process common authenticated variable except PK/KEK/DB/DBX/DBT.
   3362     // Get signer's certificates from SignedData.
   3363     //
   3364     VerifyStatus = Pkcs7GetSigners (
   3365                      SigData,
   3366                      SigDataSize,
   3367                      &SignerCerts,
   3368                      &CertStackSize,
   3369                      &RootCert,
   3370                      &RootCertSize
   3371                      );
   3372     if (!VerifyStatus) {
   3373       goto Exit;
   3374     }
   3375 
   3376     //
   3377     // Get previously stored signer's certificates from certdb for existing
   3378     // variable. Check whether they are identical with signer's certificates
   3379     // in SignedData. If not, return error immediately.
   3380     //
   3381     if (OrgTimeStamp != NULL) {
   3382       VerifyStatus = FALSE;
   3383 
   3384       Status = GetCertsFromDb (VariableName, VendorGuid, &CertsInCertDb, &CertsSizeinDb);
   3385       if (EFI_ERROR (Status)) {
   3386         goto Exit;
   3387       }
   3388 
   3389       if ((CertStackSize != CertsSizeinDb) ||
   3390           (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {
   3391         goto Exit;
   3392       }
   3393     }
   3394 
   3395     VerifyStatus = Pkcs7Verify (
   3396                      SigData,
   3397                      SigDataSize,
   3398                      RootCert,
   3399                      RootCertSize,
   3400                      NewData,
   3401                      NewDataSize
   3402                      );
   3403     if (!VerifyStatus) {
   3404       goto Exit;
   3405     }
   3406 
   3407     if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {
   3408       //
   3409       // Insert signer's certificates when adding a new common authenticated variable.
   3410       //
   3411       Status = InsertCertsToDb (VariableName, VendorGuid, SignerCerts, CertStackSize);
   3412       if (EFI_ERROR (Status)) {
   3413         VerifyStatus = FALSE;
   3414         goto Exit;
   3415       }
   3416     }
   3417   } else if (AuthVarType == AuthVarTypePayload) {
   3418     CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;
   3419     Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
   3420     RootCert      = Cert->SignatureData;
   3421     RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
   3422     //
   3423     // Verify Pkcs7 SignedData via Pkcs7Verify library.
   3424     //
   3425     VerifyStatus = Pkcs7Verify (
   3426                      SigData,
   3427                      SigDataSize,
   3428                      RootCert,
   3429                      RootCertSize,
   3430                      NewData,
   3431                      NewDataSize
   3432                      );
   3433   } else {
   3434     return EFI_SECURITY_VIOLATION;
   3435   }
   3436 
   3437 Exit:
   3438 
   3439   if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {
   3440     Pkcs7FreeSigners (RootCert);
   3441     Pkcs7FreeSigners (SignerCerts);
   3442   }
   3443 
   3444   if (!VerifyStatus) {
   3445     return EFI_SECURITY_VIOLATION;
   3446   }
   3447 
   3448   Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);
   3449   if (EFI_ERROR (Status)) {
   3450     return Status;
   3451   }
   3452 
   3453   *VarPayloadPtr = PayloadPtr;
   3454   *VarPayloadSize = PayloadSize;
   3455 
   3456   return EFI_SUCCESS;
   3457 }
   3458 
   3459 /**
   3460   Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
   3461 
   3462   Caution: This function may receive untrusted input.
   3463   This function may be invoked in SMM mode, and datasize and data are external input.
   3464   This function will do basic validation, before parse the data.
   3465   This function will parse the authentication carefully to avoid security issues, like
   3466   buffer overflow, integer overflow.
   3467 
   3468   @param[in]  VariableName                Name of Variable to be found.
   3469   @param[in]  VendorGuid                  Variable vendor GUID.
   3470   @param[in]  Data                        Data pointer.
   3471   @param[in]  DataSize                    Size of Data found. If size is less than the
   3472                                           data, this value contains the required size.
   3473   @param[in]  Attributes                  Attribute value of the variable.
   3474   @param[in]  AuthVarType                 Verify against PK, KEK database, private database or certificate in data payload.
   3475   @param[out] VarDel                      Delete the variable or not.
   3476 
   3477   @retval EFI_INVALID_PARAMETER           Invalid parameter.
   3478   @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
   3479                                           check carried out by the firmware.
   3480   @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack
   3481                                           of resources.
   3482   @retval EFI_SUCCESS                     Variable pass validation successfully.
   3483 
   3484 **/
   3485 EFI_STATUS
   3486 VerifyTimeBasedPayloadAndUpdate (
   3487   IN     CHAR16                             *VariableName,
   3488   IN     EFI_GUID                           *VendorGuid,
   3489   IN     VOID                               *Data,
   3490   IN     UINTN                              DataSize,
   3491   IN     UINT32                             Attributes,
   3492   IN     AUTHVAR_TYPE                       AuthVarType,
   3493   OUT    BOOLEAN                            *VarDel
   3494   )
   3495 {
   3496   EFI_STATUS                       Status;
   3497   EFI_STATUS                       FindStatus;
   3498   UINT8                            *PayloadPtr;
   3499   UINTN                            PayloadSize;
   3500   EFI_VARIABLE_AUTHENTICATION_2    *CertData;
   3501   AUTH_VARIABLE_INFO               OrgVariableInfo;
   3502   BOOLEAN                          IsDel;
   3503 
   3504   ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
   3505   FindStatus = mAuthVarLibContextIn->FindVariable (
   3506              VariableName,
   3507              VendorGuid,
   3508              &OrgVariableInfo
   3509              );
   3510 
   3511   Status = VerifyTimeBasedPayload (
   3512              VariableName,
   3513              VendorGuid,
   3514              Data,
   3515              DataSize,
   3516              Attributes,
   3517              AuthVarType,
   3518              (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL,
   3519              &PayloadPtr,
   3520              &PayloadSize
   3521              );
   3522   if (EFI_ERROR (Status)) {
   3523     return Status;
   3524   }
   3525 
   3526   if (!EFI_ERROR(FindStatus)
   3527    && (PayloadSize == 0)
   3528    && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
   3529     IsDel = TRUE;
   3530   } else {
   3531     IsDel = FALSE;
   3532   }
   3533 
   3534   CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
   3535 
   3536   //
   3537   // Final step: Update/Append Variable if it pass Pkcs7Verify
   3538   //
   3539   Status = AuthServiceInternalUpdateVariableWithTimeStamp (
   3540              VariableName,
   3541              VendorGuid,
   3542              PayloadPtr,
   3543              PayloadSize,
   3544              Attributes,
   3545              &CertData->TimeStamp
   3546              );
   3547 
   3548   //
   3549   // Delete signer's certificates when delete the common authenticated variable.
   3550   //
   3551   if (IsDel && AuthVarType == AuthVarTypePriv && !EFI_ERROR(Status) ) {
   3552     Status = DeleteCertsFromDb (VariableName, VendorGuid);
   3553   }
   3554 
   3555   if (VarDel != NULL) {
   3556     if (IsDel && !EFI_ERROR(Status)) {
   3557       *VarDel = TRUE;
   3558     } else {
   3559       *VarDel = FALSE;
   3560     }
   3561   }
   3562 
   3563   return Status;
   3564 }
   3565