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 - 2016, 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   Finds variable in storage blocks of volatile and non-volatile storage areas.
     61 
     62   This code finds variable in storage blocks of volatile and non-volatile storage areas.
     63   If VariableName is an empty string, then we just return the first
     64   qualified variable without comparing VariableName and VendorGuid.
     65 
     66   @param[in]  VariableName          Name of the variable to be found.
     67   @param[in]  VendorGuid            Variable vendor GUID to be found.
     68   @param[out] Data                  Pointer to data address.
     69   @param[out] DataSize              Pointer to data size.
     70 
     71   @retval EFI_INVALID_PARAMETER     If VariableName is not an empty string,
     72                                     while VendorGuid is NULL.
     73   @retval EFI_SUCCESS               Variable successfully found.
     74   @retval EFI_NOT_FOUND             Variable not found
     75 
     76 **/
     77 EFI_STATUS
     78 AuthServiceInternalFindVariable (
     79   IN  CHAR16            *VariableName,
     80   IN  EFI_GUID          *VendorGuid,
     81   OUT VOID              **Data,
     82   OUT UINTN             *DataSize
     83   )
     84 {
     85   EFI_STATUS            Status;
     86   AUTH_VARIABLE_INFO    AuthVariableInfo;
     87 
     88   ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
     89   Status = mAuthVarLibContextIn->FindVariable (
     90            VariableName,
     91            VendorGuid,
     92            &AuthVariableInfo
     93            );
     94   *Data = AuthVariableInfo.Data;
     95   *DataSize = AuthVariableInfo.DataSize;
     96   return Status;
     97 }
     98 
     99 /**
    100   Update the variable region with Variable information.
    101 
    102   @param[in] VariableName           Name of variable.
    103   @param[in] VendorGuid             Guid of variable.
    104   @param[in] Data                   Data pointer.
    105   @param[in] DataSize               Size of Data.
    106   @param[in] Attributes             Attribute value of the variable.
    107 
    108   @retval EFI_SUCCESS               The update operation is success.
    109   @retval EFI_INVALID_PARAMETER     Invalid parameter.
    110   @retval EFI_WRITE_PROTECTED       Variable is write-protected.
    111   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    112 
    113 **/
    114 EFI_STATUS
    115 AuthServiceInternalUpdateVariable (
    116   IN CHAR16             *VariableName,
    117   IN EFI_GUID           *VendorGuid,
    118   IN VOID               *Data,
    119   IN UINTN              DataSize,
    120   IN UINT32             Attributes
    121   )
    122 {
    123   AUTH_VARIABLE_INFO    AuthVariableInfo;
    124 
    125   ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
    126   AuthVariableInfo.VariableName = VariableName;
    127   AuthVariableInfo.VendorGuid = VendorGuid;
    128   AuthVariableInfo.Data = Data;
    129   AuthVariableInfo.DataSize = DataSize;
    130   AuthVariableInfo.Attributes = Attributes;
    131 
    132   return mAuthVarLibContextIn->UpdateVariable (
    133            &AuthVariableInfo
    134            );
    135 }
    136 
    137 /**
    138   Update the variable region with Variable information.
    139 
    140   @param[in] VariableName           Name of variable.
    141   @param[in] VendorGuid             Guid of variable.
    142   @param[in] Data                   Data pointer.
    143   @param[in] DataSize               Size of Data.
    144   @param[in] Attributes             Attribute value of the variable.
    145   @param[in] KeyIndex               Index of associated public key.
    146   @param[in] MonotonicCount         Value of associated monotonic count.
    147 
    148   @retval EFI_SUCCESS               The update operation is success.
    149   @retval EFI_INVALID_PARAMETER     Invalid parameter.
    150   @retval EFI_WRITE_PROTECTED       Variable is write-protected.
    151   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    152 
    153 **/
    154 EFI_STATUS
    155 AuthServiceInternalUpdateVariableWithMonotonicCount (
    156   IN CHAR16             *VariableName,
    157   IN EFI_GUID           *VendorGuid,
    158   IN VOID               *Data,
    159   IN UINTN              DataSize,
    160   IN UINT32             Attributes,
    161   IN UINT32             KeyIndex,
    162   IN UINT64             MonotonicCount
    163   )
    164 {
    165   AUTH_VARIABLE_INFO    AuthVariableInfo;
    166 
    167   ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
    168   AuthVariableInfo.VariableName = VariableName;
    169   AuthVariableInfo.VendorGuid = VendorGuid;
    170   AuthVariableInfo.Data = Data;
    171   AuthVariableInfo.DataSize = DataSize;
    172   AuthVariableInfo.Attributes = Attributes;
    173   AuthVariableInfo.PubKeyIndex = KeyIndex;
    174   AuthVariableInfo.MonotonicCount = MonotonicCount;
    175 
    176   return mAuthVarLibContextIn->UpdateVariable (
    177            &AuthVariableInfo
    178            );
    179 }
    180 
    181 /**
    182   Update the variable region with Variable information.
    183 
    184   @param[in] VariableName           Name of variable.
    185   @param[in] VendorGuid             Guid of variable.
    186   @param[in] Data                   Data pointer.
    187   @param[in] DataSize               Size of Data.
    188   @param[in] Attributes             Attribute value of the variable.
    189   @param[in] TimeStamp              Value of associated TimeStamp.
    190 
    191   @retval EFI_SUCCESS               The update operation is success.
    192   @retval EFI_INVALID_PARAMETER     Invalid parameter.
    193   @retval EFI_WRITE_PROTECTED       Variable is write-protected.
    194   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    195 
    196 **/
    197 EFI_STATUS
    198 AuthServiceInternalUpdateVariableWithTimeStamp (
    199   IN CHAR16             *VariableName,
    200   IN EFI_GUID           *VendorGuid,
    201   IN VOID               *Data,
    202   IN UINTN              DataSize,
    203   IN UINT32             Attributes,
    204   IN EFI_TIME           *TimeStamp
    205   )
    206 {
    207   EFI_STATUS            FindStatus;
    208   VOID                  *OrgData;
    209   UINTN                 OrgDataSize;
    210   AUTH_VARIABLE_INFO    AuthVariableInfo;
    211 
    212   FindStatus = AuthServiceInternalFindVariable (
    213                  VariableName,
    214                  VendorGuid,
    215                  &OrgData,
    216                  &OrgDataSize
    217                  );
    218 
    219   //
    220   // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
    221   //
    222   if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
    223     if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
    224         ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
    225         (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||
    226         (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {
    227       //
    228       // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of
    229       // EFI_SIGNATURE_DATA values that are already part of the existing variable value.
    230       //
    231       FilterSignatureList (
    232         OrgData,
    233         OrgDataSize,
    234         Data,
    235         &DataSize
    236         );
    237     }
    238   }
    239 
    240   ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
    241   AuthVariableInfo.VariableName = VariableName;
    242   AuthVariableInfo.VendorGuid = VendorGuid;
    243   AuthVariableInfo.Data = Data;
    244   AuthVariableInfo.DataSize = DataSize;
    245   AuthVariableInfo.Attributes = Attributes;
    246   AuthVariableInfo.TimeStamp = TimeStamp;
    247   return mAuthVarLibContextIn->UpdateVariable (
    248            &AuthVariableInfo
    249            );
    250 }
    251 
    252 /**
    253   Determine whether this operation needs a physical present user.
    254 
    255   @param[in]      VariableName            Name of the Variable.
    256   @param[in]      VendorGuid              GUID of the Variable.
    257 
    258   @retval TRUE      This variable is protected, only a physical present user could set this variable.
    259   @retval FALSE     This variable is not protected.
    260 
    261 **/
    262 BOOLEAN
    263 NeedPhysicallyPresent(
    264   IN     CHAR16         *VariableName,
    265   IN     EFI_GUID       *VendorGuid
    266   )
    267 {
    268   if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))
    269     || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {
    270     return TRUE;
    271   }
    272 
    273   return FALSE;
    274 }
    275 
    276 /**
    277   Determine whether the platform is operating in Custom Secure Boot mode.
    278 
    279   @retval TRUE           The platform is operating in Custom mode.
    280   @retval FALSE          The platform is operating in Standard mode.
    281 
    282 **/
    283 BOOLEAN
    284 InCustomMode (
    285   VOID
    286   )
    287 {
    288   EFI_STATUS    Status;
    289   VOID          *Data;
    290   UINTN         DataSize;
    291 
    292   Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize);
    293   if (!EFI_ERROR (Status) && (*(UINT8 *) Data == CUSTOM_SECURE_BOOT_MODE)) {
    294     return TRUE;
    295   }
    296 
    297   return FALSE;
    298 }
    299 
    300 /**
    301   Get available public key index.
    302 
    303   @param[in] PubKey     Pointer to Public Key data.
    304 
    305   @return Public key index, 0 if no any public key index available.
    306 
    307 **/
    308 UINT32
    309 GetAvailableKeyIndex (
    310   IN  UINT8             *PubKey
    311   )
    312 {
    313   EFI_STATUS            Status;
    314   UINT8                 *Data;
    315   UINTN                 DataSize;
    316   UINT8                 *Ptr;
    317   UINT32                Index;
    318   BOOLEAN               IsFound;
    319   EFI_GUID              VendorGuid;
    320   CHAR16                Name[1];
    321   AUTH_VARIABLE_INFO    AuthVariableInfo;
    322   UINT32                KeyIndex;
    323 
    324   Status = AuthServiceInternalFindVariable (
    325              AUTHVAR_KEYDB_NAME,
    326              &gEfiAuthenticatedVariableGuid,
    327              (VOID **) &Data,
    328              &DataSize
    329              );
    330   if (EFI_ERROR (Status)) {
    331     DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));
    332     return 0;
    333   }
    334 
    335   if (mPubKeyNumber == mMaxKeyNumber) {
    336     Name[0] = 0;
    337     AuthVariableInfo.VariableName = Name;
    338     ZeroMem (&VendorGuid, sizeof (VendorGuid));
    339     AuthVariableInfo.VendorGuid = &VendorGuid;
    340     mPubKeyNumber = 0;
    341     //
    342     // Collect valid key data.
    343     //
    344     do {
    345       Status = mAuthVarLibContextIn->FindNextVariable (AuthVariableInfo.VariableName, AuthVariableInfo.VendorGuid, &AuthVariableInfo);
    346       if (!EFI_ERROR (Status)) {
    347         if (AuthVariableInfo.PubKeyIndex != 0) {
    348           for (Ptr = Data; Ptr < (Data + DataSize); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {
    349             if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {
    350               //
    351               // Check if the key data has been collected.
    352               //
    353               for (Index = 0; Index < mPubKeyNumber; Index++) {
    354                 if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {
    355                   break;
    356                 }
    357               }
    358               if (Index == mPubKeyNumber) {
    359                 //
    360                 // New key data.
    361                 //
    362                 CopyMem ((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber, Ptr, sizeof (AUTHVAR_KEY_DB_DATA));
    363                 mPubKeyNumber++;
    364               }
    365               break;
    366             }
    367           }
    368         }
    369       }
    370     } while (Status != EFI_NOT_FOUND);
    371 
    372     //
    373     // No available space to add new public key.
    374     //
    375     if (mPubKeyNumber == mMaxKeyNumber) {
    376       return 0;
    377     }
    378   }
    379 
    380   //
    381   // Find available public key index.
    382   //
    383   for (KeyIndex = 1; KeyIndex <= mMaxKeyNumber; KeyIndex++) {
    384     IsFound = FALSE;
    385     for (Ptr = mPubKeyStore; Ptr < (mPubKeyStore + mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA)); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {
    386       if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == KeyIndex) {
    387         IsFound = TRUE;
    388         break;
    389       }
    390     }
    391     if (!IsFound) {
    392       break;
    393     }
    394   }
    395 
    396   return KeyIndex;
    397 }
    398 
    399 /**
    400   Add public key in store and return its index.
    401 
    402   @param[in] PubKey             Input pointer to Public Key data.
    403   @param[in] VariableDataEntry  The variable data entry.
    404 
    405   @return Index of new added public key.
    406 
    407 **/
    408 UINT32
    409 AddPubKeyInStore (
    410   IN  UINT8                        *PubKey,
    411   IN  VARIABLE_ENTRY_CONSISTENCY   *VariableDataEntry
    412   )
    413 {
    414   EFI_STATUS                       Status;
    415   UINT32                           Index;
    416   VARIABLE_ENTRY_CONSISTENCY       PublicKeyEntry;
    417   UINT32                           Attributes;
    418   UINT32                           KeyIndex;
    419 
    420   if (PubKey == NULL) {
    421     return 0;
    422   }
    423 
    424   //
    425   // Check whether the public key entry does exist.
    426   //
    427   for (Index = 0; Index < mPubKeyNumber; Index++) {
    428     if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
    429       return ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex));
    430     }
    431   }
    432 
    433   KeyIndex = GetAvailableKeyIndex (PubKey);
    434   if (KeyIndex == 0) {
    435     return 0;
    436   }
    437 
    438   //
    439   // Check the variable space for both public key and variable data.
    440   //
    441   PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * sizeof (AUTHVAR_KEY_DB_DATA);
    442   PublicKeyEntry.Guid         = &gEfiAuthenticatedVariableGuid;
    443   PublicKeyEntry.Name         = AUTHVAR_KEYDB_NAME;
    444   Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
    445 
    446   if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {
    447     //
    448     // No enough variable space.
    449     //
    450     return 0;
    451   }
    452 
    453   WriteUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyIndex), KeyIndex);
    454   CopyMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
    455   mPubKeyNumber++;
    456 
    457   //
    458   // Update public key database variable.
    459   //
    460   Status = AuthServiceInternalUpdateVariable (
    461              AUTHVAR_KEYDB_NAME,
    462              &gEfiAuthenticatedVariableGuid,
    463              mPubKeyStore,
    464              mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA),
    465              Attributes
    466              );
    467   if (EFI_ERROR (Status)) {
    468     DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));
    469     return 0;
    470   }
    471 
    472   return KeyIndex;
    473 }
    474 
    475 /**
    476   Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
    477   Follow the steps in UEFI2.2.
    478 
    479   Caution: This function may receive untrusted input.
    480   This function may be invoked in SMM mode, and datasize and data are external input.
    481   This function will do basic validation, before parse the data.
    482   This function will parse the authentication carefully to avoid security issues, like
    483   buffer overflow, integer overflow.
    484 
    485   @param[in]      Data                    Pointer to data with AuthInfo.
    486   @param[in]      DataSize                Size of Data.
    487   @param[in]      PubKey                  Public key used for verification.
    488 
    489   @retval EFI_INVALID_PARAMETER       Invalid parameter.
    490   @retval EFI_SECURITY_VIOLATION      If authentication failed.
    491   @retval EFI_SUCCESS                 Authentication successful.
    492 
    493 **/
    494 EFI_STATUS
    495 VerifyCounterBasedPayload (
    496   IN     UINT8          *Data,
    497   IN     UINTN          DataSize,
    498   IN     UINT8          *PubKey
    499   )
    500 {
    501   BOOLEAN                         Status;
    502   EFI_VARIABLE_AUTHENTICATION     *CertData;
    503   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
    504   UINT8                           Digest[SHA256_DIGEST_SIZE];
    505   VOID                            *Rsa;
    506   UINTN                           PayloadSize;
    507 
    508   PayloadSize = DataSize - AUTHINFO_SIZE;
    509   Rsa         = NULL;
    510   CertData    = NULL;
    511   CertBlock   = NULL;
    512 
    513   if (Data == NULL || PubKey == NULL) {
    514     return EFI_INVALID_PARAMETER;
    515   }
    516 
    517   CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
    518   CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
    519 
    520   //
    521   // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
    522   // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
    523   //
    524   if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
    525       !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {
    526     //
    527     // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
    528     //
    529     return EFI_SECURITY_VIOLATION;
    530   }
    531   //
    532   // Hash data payload with SHA256.
    533   //
    534   ZeroMem (Digest, SHA256_DIGEST_SIZE);
    535   Status  = Sha256Init (mHashCtx);
    536   if (!Status) {
    537     goto Done;
    538   }
    539   Status  = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);
    540   if (!Status) {
    541     goto Done;
    542   }
    543   //
    544   // Hash Size.
    545   //
    546   Status  = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));
    547   if (!Status) {
    548     goto Done;
    549   }
    550   //
    551   // Hash Monotonic Count.
    552   //
    553   Status  = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));
    554   if (!Status) {
    555     goto Done;
    556   }
    557   Status  = Sha256Final (mHashCtx, Digest);
    558   if (!Status) {
    559     goto Done;
    560   }
    561   //
    562   // Generate & Initialize RSA Context.
    563   //
    564   Rsa = RsaNew ();
    565   ASSERT (Rsa != NULL);
    566   //
    567   // Set RSA Key Components.
    568   // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
    569   //
    570   Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
    571   if (!Status) {
    572     goto Done;
    573   }
    574   Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
    575   if (!Status) {
    576     goto Done;
    577   }
    578   //
    579   // Verify the signature.
    580   //
    581   Status = RsaPkcs1Verify (
    582              Rsa,
    583              Digest,
    584              SHA256_DIGEST_SIZE,
    585              CertBlock->Signature,
    586              EFI_CERT_TYPE_RSA2048_SHA256_SIZE
    587              );
    588 
    589 Done:
    590   if (Rsa != NULL) {
    591     RsaFree (Rsa);
    592   }
    593   if (Status) {
    594     return EFI_SUCCESS;
    595   } else {
    596     return EFI_SECURITY_VIOLATION;
    597   }
    598 }
    599 
    600 /**
    601   Update platform mode.
    602 
    603   @param[in]      Mode                    SETUP_MODE or USER_MODE.
    604 
    605   @return EFI_INVALID_PARAMETER           Invalid parameter.
    606   @return EFI_SUCCESS                     Update platform mode successfully.
    607 
    608 **/
    609 EFI_STATUS
    610 UpdatePlatformMode (
    611   IN  UINT32                    Mode
    612   )
    613 {
    614   EFI_STATUS              Status;
    615   VOID                    *Data;
    616   UINTN                   DataSize;
    617   UINT8                   SecureBootMode;
    618   UINT8                   SecureBootEnable;
    619   UINTN                   VariableDataSize;
    620 
    621   Status = AuthServiceInternalFindVariable (
    622              EFI_SETUP_MODE_NAME,
    623              &gEfiGlobalVariableGuid,
    624              &Data,
    625              &DataSize
    626              );
    627   if (EFI_ERROR (Status)) {
    628     return Status;
    629   }
    630 
    631   //
    632   // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
    633   // variable storage reclaim at runtime.
    634   //
    635   mPlatformMode = (UINT8) Mode;
    636   CopyMem (Data, &mPlatformMode, sizeof(UINT8));
    637 
    638   if (mAuthVarLibContextIn->AtRuntime ()) {
    639     //
    640     // SecureBoot Variable indicates whether the platform firmware is operating
    641     // in Secure boot mode (1) or not (0), so we should not change SecureBoot
    642     // Variable in runtime.
    643     //
    644     return Status;
    645   }
    646 
    647   //
    648   // Check "SecureBoot" variable's existence.
    649   // If it doesn't exist, firmware has no capability to perform driver signing verification,
    650   // then set "SecureBoot" to 0.
    651   //
    652   Status = AuthServiceInternalFindVariable (
    653              EFI_SECURE_BOOT_MODE_NAME,
    654              &gEfiGlobalVariableGuid,
    655              &Data,
    656              &DataSize
    657              );
    658   //
    659   // If "SecureBoot" variable exists, then check "SetupMode" variable update.
    660   // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
    661   // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
    662   //
    663   if (EFI_ERROR (Status)) {
    664     SecureBootMode = SECURE_BOOT_MODE_DISABLE;
    665   } else {
    666     if (mPlatformMode == USER_MODE) {
    667       SecureBootMode = SECURE_BOOT_MODE_ENABLE;
    668     } else if (mPlatformMode == SETUP_MODE) {
    669       SecureBootMode = SECURE_BOOT_MODE_DISABLE;
    670     } else {
    671       return EFI_NOT_FOUND;
    672     }
    673   }
    674 
    675   Status  = AuthServiceInternalUpdateVariable (
    676               EFI_SECURE_BOOT_MODE_NAME,
    677               &gEfiGlobalVariableGuid,
    678               &SecureBootMode,
    679               sizeof(UINT8),
    680               EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
    681               );
    682   if (EFI_ERROR (Status)) {
    683     return Status;
    684   }
    685 
    686   //
    687   // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
    688   //
    689   Status = AuthServiceInternalFindVariable (
    690              EFI_SECURE_BOOT_ENABLE_NAME,
    691              &gEfiSecureBootEnableDisableGuid,
    692              &Data,
    693              &DataSize
    694              );
    695 
    696   if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {
    697     //
    698     // Create the "SecureBootEnable" variable as secure boot is enabled.
    699     //
    700     SecureBootEnable = SECURE_BOOT_ENABLE;
    701     VariableDataSize = sizeof (SecureBootEnable);
    702   } else {
    703     //
    704     // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
    705     // variable is not in secure boot state.
    706     //
    707     if (EFI_ERROR (Status)) {
    708       return EFI_SUCCESS;
    709     }
    710     SecureBootEnable = SECURE_BOOT_DISABLE;
    711     VariableDataSize = 0;
    712   }
    713 
    714   Status = AuthServiceInternalUpdateVariable (
    715              EFI_SECURE_BOOT_ENABLE_NAME,
    716              &gEfiSecureBootEnableDisableGuid,
    717              &SecureBootEnable,
    718              VariableDataSize,
    719              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
    720              );
    721   return Status;
    722 }
    723 
    724 /**
    725   Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.
    726 
    727   @param[in]  VariableName                Name of Variable to be check.
    728   @param[in]  VendorGuid                  Variable vendor GUID.
    729   @param[in]  Data                        Point to the variable data to be checked.
    730   @param[in]  DataSize                    Size of Data.
    731 
    732   @return EFI_INVALID_PARAMETER           Invalid signature list format.
    733   @return EFI_SUCCESS                     Passed signature list format check successfully.
    734 
    735 **/
    736 EFI_STATUS
    737 CheckSignatureListFormat(
    738   IN  CHAR16                    *VariableName,
    739   IN  EFI_GUID                  *VendorGuid,
    740   IN  VOID                      *Data,
    741   IN  UINTN                     DataSize
    742   )
    743 {
    744   EFI_SIGNATURE_LIST     *SigList;
    745   UINTN                  SigDataSize;
    746   UINT32                 Index;
    747   UINT32                 SigCount;
    748   BOOLEAN                IsPk;
    749   VOID                   *RsaContext;
    750   EFI_SIGNATURE_DATA     *CertData;
    751   UINTN                  CertLen;
    752 
    753   if (DataSize == 0) {
    754     return EFI_SUCCESS;
    755   }
    756 
    757   ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);
    758 
    759   if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
    760     IsPk = TRUE;
    761   } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) ||
    762              (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
    763              ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
    764               (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)))) {
    765     IsPk = FALSE;
    766   } else {
    767     return EFI_SUCCESS;
    768   }
    769 
    770   SigCount = 0;
    771   SigList  = (EFI_SIGNATURE_LIST *) Data;
    772   SigDataSize  = DataSize;
    773   RsaContext = NULL;
    774 
    775   //
    776   // Walk throuth the input signature list and check the data format.
    777   // If any signature is incorrectly formed, the whole check will fail.
    778   //
    779   while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {
    780     for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {
    781       if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {
    782         //
    783         // The value of SignatureSize should always be 16 (size of SignatureOwner
    784         // component) add the data length according to signature type.
    785         //
    786         if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) &&
    787           (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {
    788           return EFI_INVALID_PARAMETER;
    789         }
    790         if (mSupportSigItem[Index].SigHeaderSize != ((UINT32) ~0) &&
    791           SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {
    792           return EFI_INVALID_PARAMETER;
    793         }
    794         break;
    795       }
    796     }
    797 
    798     if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {
    799       //
    800       // Undefined signature type.
    801       //
    802       return EFI_INVALID_PARAMETER;
    803     }
    804 
    805     if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
    806       //
    807       // Try to retrieve the RSA public key from the X.509 certificate.
    808       // If this operation fails, it's not a valid certificate.
    809       //
    810       RsaContext = RsaNew ();
    811       if (RsaContext == NULL) {
    812         return EFI_INVALID_PARAMETER;
    813       }
    814       CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);
    815       CertLen = SigList->SignatureSize - sizeof (EFI_GUID);
    816       if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {
    817         RsaFree (RsaContext);
    818         return EFI_INVALID_PARAMETER;
    819       }
    820       RsaFree (RsaContext);
    821     }
    822 
    823     if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {
    824       return EFI_INVALID_PARAMETER;
    825     }
    826     SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;
    827 
    828     SigDataSize -= SigList->SignatureListSize;
    829     SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
    830   }
    831 
    832   if (((UINTN) SigList - (UINTN) Data) != DataSize) {
    833     return EFI_INVALID_PARAMETER;
    834   }
    835 
    836   if (IsPk && SigCount > 1) {
    837     return EFI_INVALID_PARAMETER;
    838   }
    839 
    840   return EFI_SUCCESS;
    841 }
    842 
    843 /**
    844   Update "VendorKeys" variable to record the out of band secure boot key modification.
    845 
    846   @return EFI_SUCCESS           Variable is updated successfully.
    847   @return Others                Failed to update variable.
    848 
    849 **/
    850 EFI_STATUS
    851 VendorKeyIsModified (
    852   VOID
    853   )
    854 {
    855   EFI_STATUS              Status;
    856 
    857   if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {
    858     return EFI_SUCCESS;
    859   }
    860   mVendorKeyState = VENDOR_KEYS_MODIFIED;
    861 
    862   Status = AuthServiceInternalUpdateVariable (
    863              EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
    864              &gEfiVendorKeysNvGuid,
    865              &mVendorKeyState,
    866              sizeof (UINT8),
    867              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
    868              );
    869   if (EFI_ERROR (Status)) {
    870     return Status;
    871   }
    872 
    873   return AuthServiceInternalUpdateVariable (
    874            EFI_VENDOR_KEYS_VARIABLE_NAME,
    875            &gEfiGlobalVariableGuid,
    876            &mVendorKeyState,
    877            sizeof (UINT8),
    878            EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
    879            );
    880 }
    881 
    882 /**
    883   Process variable with platform key for verification.
    884 
    885   Caution: This function may receive untrusted input.
    886   This function may be invoked in SMM mode, and datasize and data are external input.
    887   This function will do basic validation, before parse the data.
    888   This function will parse the authentication carefully to avoid security issues, like
    889   buffer overflow, integer overflow.
    890   This function will check attribute carefully to avoid authentication bypass.
    891 
    892   @param[in]  VariableName                Name of Variable to be found.
    893   @param[in]  VendorGuid                  Variable vendor GUID.
    894   @param[in]  Data                        Data pointer.
    895   @param[in]  DataSize                    Size of Data found. If size is less than the
    896                                           data, this value contains the required size.
    897   @param[in]  Attributes                  Attribute value of the variable
    898   @param[in]  IsPk                        Indicate whether it is to process pk.
    899 
    900   @return EFI_INVALID_PARAMETER           Invalid parameter.
    901   @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation.
    902                                           check carried out by the firmware.
    903   @return EFI_SUCCESS                     Variable passed validation successfully.
    904 
    905 **/
    906 EFI_STATUS
    907 ProcessVarWithPk (
    908   IN  CHAR16                    *VariableName,
    909   IN  EFI_GUID                  *VendorGuid,
    910   IN  VOID                      *Data,
    911   IN  UINTN                     DataSize,
    912   IN  UINT32                    Attributes OPTIONAL,
    913   IN  BOOLEAN                   IsPk
    914   )
    915 {
    916   EFI_STATUS                  Status;
    917   BOOLEAN                     Del;
    918   UINT8                       *Payload;
    919   UINTN                       PayloadSize;
    920 
    921   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
    922       (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
    923     //
    924     // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
    925     // authenticated variable.
    926     //
    927     return EFI_INVALID_PARAMETER;
    928   }
    929 
    930   //
    931   // Init state of Del. State may change due to secure check
    932   //
    933   Del = FALSE;
    934   if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) {
    935     Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
    936     PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
    937     if (PayloadSize == 0) {
    938       Del = TRUE;
    939     }
    940 
    941     Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
    942     if (EFI_ERROR (Status)) {
    943       return Status;
    944     }
    945 
    946     Status = AuthServiceInternalUpdateVariableWithTimeStamp (
    947                VariableName,
    948                VendorGuid,
    949                Payload,
    950                PayloadSize,
    951                Attributes,
    952                &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
    953                );
    954     if (EFI_ERROR(Status)) {
    955       return Status;
    956     }
    957 
    958     if ((mPlatformMode != SETUP_MODE) || IsPk) {
    959       Status = VendorKeyIsModified ();
    960     }
    961   } else if (mPlatformMode == USER_MODE) {
    962     //
    963     // Verify against X509 Cert in PK database.
    964     //
    965     Status = VerifyTimeBasedPayloadAndUpdate (
    966                VariableName,
    967                VendorGuid,
    968                Data,
    969                DataSize,
    970                Attributes,
    971                AuthVarTypePk,
    972                &Del
    973                );
    974   } else {
    975     //
    976     // Verify against the certificate in data payload.
    977     //
    978     Status = VerifyTimeBasedPayloadAndUpdate (
    979                VariableName,
    980                VendorGuid,
    981                Data,
    982                DataSize,
    983                Attributes,
    984                AuthVarTypePayload,
    985                &Del
    986                );
    987   }
    988 
    989   if (!EFI_ERROR(Status) && IsPk) {
    990     if (mPlatformMode == SETUP_MODE && !Del) {
    991       //
    992       // If enroll PK in setup mode, need change to user mode.
    993       //
    994       Status = UpdatePlatformMode (USER_MODE);
    995     } else if (mPlatformMode == USER_MODE && Del){
    996       //
    997       // If delete PK in user mode, need change to setup mode.
    998       //
    999       Status = UpdatePlatformMode (SETUP_MODE);
   1000     }
   1001   }
   1002 
   1003   return Status;
   1004 }
   1005 
   1006 /**
   1007   Process variable with key exchange key for verification.
   1008 
   1009   Caution: This function may receive untrusted input.
   1010   This function may be invoked in SMM mode, and datasize and data are external input.
   1011   This function will do basic validation, before parse the data.
   1012   This function will parse the authentication carefully to avoid security issues, like
   1013   buffer overflow, integer overflow.
   1014   This function will check attribute carefully to avoid authentication bypass.
   1015 
   1016   @param[in]  VariableName                Name of Variable to be found.
   1017   @param[in]  VendorGuid                  Variable vendor GUID.
   1018   @param[in]  Data                        Data pointer.
   1019   @param[in]  DataSize                    Size of Data found. If size is less than the
   1020                                           data, this value contains the required size.
   1021   @param[in]  Attributes                  Attribute value of the variable.
   1022 
   1023   @return EFI_INVALID_PARAMETER           Invalid parameter.
   1024   @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
   1025                                           check carried out by the firmware.
   1026   @return EFI_SUCCESS                     Variable pass validation successfully.
   1027 
   1028 **/
   1029 EFI_STATUS
   1030 ProcessVarWithKek (
   1031   IN  CHAR16                               *VariableName,
   1032   IN  EFI_GUID                             *VendorGuid,
   1033   IN  VOID                                 *Data,
   1034   IN  UINTN                                DataSize,
   1035   IN  UINT32                               Attributes OPTIONAL
   1036   )
   1037 {
   1038   EFI_STATUS                      Status;
   1039   UINT8                           *Payload;
   1040   UINTN                           PayloadSize;
   1041 
   1042   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
   1043       (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
   1044     //
   1045     // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
   1046     // authenticated variable.
   1047     //
   1048     return EFI_INVALID_PARAMETER;
   1049   }
   1050 
   1051   Status = EFI_SUCCESS;
   1052   if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {
   1053     //
   1054     // Time-based, verify against X509 Cert KEK.
   1055     //
   1056     return VerifyTimeBasedPayloadAndUpdate (
   1057              VariableName,
   1058              VendorGuid,
   1059              Data,
   1060              DataSize,
   1061              Attributes,
   1062              AuthVarTypeKek,
   1063              NULL
   1064              );
   1065   } else {
   1066     //
   1067     // If in setup mode or custom secure boot mode, no authentication needed.
   1068     //
   1069     Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
   1070     PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
   1071 
   1072     Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
   1073     if (EFI_ERROR (Status)) {
   1074       return Status;
   1075     }
   1076 
   1077     Status = AuthServiceInternalUpdateVariableWithTimeStamp (
   1078                VariableName,
   1079                VendorGuid,
   1080                Payload,
   1081                PayloadSize,
   1082                Attributes,
   1083                &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
   1084                );
   1085     if (EFI_ERROR (Status)) {
   1086       return Status;
   1087     }
   1088 
   1089     if (mPlatformMode != SETUP_MODE) {
   1090       Status = VendorKeyIsModified ();
   1091     }
   1092   }
   1093 
   1094   return Status;
   1095 }
   1096 
   1097 /**
   1098   Check if it is to delete auth variable.
   1099 
   1100   @param[in] OrgAttributes      Original attribute value of the variable.
   1101   @param[in] Data               Data pointer.
   1102   @param[in] DataSize           Size of Data.
   1103   @param[in] Attributes         Attribute value of the variable.
   1104 
   1105   @retval TRUE                  It is to delete auth variable.
   1106   @retval FALSE                 It is not to delete auth variable.
   1107 
   1108 **/
   1109 BOOLEAN
   1110 IsDeleteAuthVariable (
   1111   IN  UINT32                    OrgAttributes,
   1112   IN  VOID                      *Data,
   1113   IN  UINTN                     DataSize,
   1114   IN  UINT32                    Attributes
   1115   )
   1116 {
   1117   BOOLEAN                       Del;
   1118   UINTN                         PayloadSize;
   1119 
   1120   Del = FALSE;
   1121 
   1122   //
   1123   // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
   1124   // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,
   1125   // SetVariable must be used with attributes matching the existing variable
   1126   // and the DataSize set to the size of the AuthInfo descriptor.
   1127   //
   1128   if ((Attributes == OrgAttributes) &&
   1129       ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) {
   1130     if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
   1131       PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
   1132       if (PayloadSize == 0) {
   1133         Del = TRUE;
   1134       }
   1135     } else {
   1136       PayloadSize = DataSize - AUTHINFO_SIZE;
   1137       if (PayloadSize == 0) {
   1138         Del = TRUE;
   1139       }
   1140     }
   1141   }
   1142 
   1143   return Del;
   1144 }
   1145 
   1146 /**
   1147   Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
   1148 
   1149   Caution: This function may receive untrusted input.
   1150   This function may be invoked in SMM mode, and datasize and data are external input.
   1151   This function will do basic validation, before parse the data.
   1152   This function will parse the authentication carefully to avoid security issues, like
   1153   buffer overflow, integer overflow.
   1154   This function will check attribute carefully to avoid authentication bypass.
   1155 
   1156   @param[in]  VariableName                Name of the variable.
   1157   @param[in]  VendorGuid                  Variable vendor GUID.
   1158   @param[in]  Data                        Data pointer.
   1159   @param[in]  DataSize                    Size of Data.
   1160   @param[in]  Attributes                  Attribute value of the variable.
   1161 
   1162   @return EFI_INVALID_PARAMETER           Invalid parameter.
   1163   @return EFI_WRITE_PROTECTED             Variable is write-protected and needs authentication with
   1164                                           EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
   1165   @return EFI_OUT_OF_RESOURCES            The Database to save the public key is full.
   1166   @return EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
   1167                                           set, but the AuthInfo does NOT pass the validation
   1168                                           check carried out by the firmware.
   1169   @return EFI_SUCCESS                     Variable is not write-protected or pass validation successfully.
   1170 
   1171 **/
   1172 EFI_STATUS
   1173 ProcessVariable (
   1174   IN     CHAR16                             *VariableName,
   1175   IN     EFI_GUID                           *VendorGuid,
   1176   IN     VOID                               *Data,
   1177   IN     UINTN                              DataSize,
   1178   IN     UINT32                             Attributes
   1179   )
   1180 {
   1181   EFI_STATUS                      Status;
   1182   BOOLEAN                         IsDeletion;
   1183   BOOLEAN                         IsFirstTime;
   1184   UINT8                           *PubKey;
   1185   EFI_VARIABLE_AUTHENTICATION     *CertData;
   1186   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
   1187   UINT32                          KeyIndex;
   1188   UINT64                          MonotonicCount;
   1189   VARIABLE_ENTRY_CONSISTENCY      VariableDataEntry;
   1190   UINT32                          Index;
   1191   AUTH_VARIABLE_INFO              OrgVariableInfo;
   1192 
   1193   KeyIndex    = 0;
   1194   CertData    = NULL;
   1195   CertBlock   = NULL;
   1196   PubKey      = NULL;
   1197   IsDeletion  = FALSE;
   1198   Status      = EFI_SUCCESS;
   1199 
   1200   ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
   1201   Status = mAuthVarLibContextIn->FindVariable (
   1202              VariableName,
   1203              VendorGuid,
   1204              &OrgVariableInfo
   1205              );
   1206 
   1207   if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && UserPhysicalPresent()) {
   1208     //
   1209     // Allow the delete operation of common authenticated variable at user physical presence.
   1210     //
   1211     Status = AuthServiceInternalUpdateVariable (
   1212               VariableName,
   1213               VendorGuid,
   1214               NULL,
   1215               0,
   1216               0
   1217               );
   1218     if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
   1219       Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
   1220     }
   1221 
   1222     return Status;
   1223   }
   1224 
   1225   if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent()) {
   1226     //
   1227     // This variable is protected, only physical present user could modify its value.
   1228     //
   1229     return EFI_SECURITY_VIOLATION;
   1230   }
   1231 
   1232   //
   1233   // A time-based authenticated variable and a count-based authenticated variable
   1234   // can't be updated by each other.
   1235   //
   1236   if (OrgVariableInfo.Data != NULL) {
   1237     if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&
   1238         ((OrgVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
   1239       return EFI_SECURITY_VIOLATION;
   1240     }
   1241 
   1242     if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
   1243         ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {
   1244       return EFI_SECURITY_VIOLATION;
   1245     }
   1246   }
   1247 
   1248   //
   1249   // Process Time-based Authenticated variable.
   1250   //
   1251   if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
   1252     return VerifyTimeBasedPayloadAndUpdate (
   1253              VariableName,
   1254              VendorGuid,
   1255              Data,
   1256              DataSize,
   1257              Attributes,
   1258              AuthVarTypePriv,
   1259              NULL
   1260              );
   1261   }
   1262 
   1263   //
   1264   // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
   1265   //
   1266   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
   1267     //
   1268     // Determine current operation type.
   1269     //
   1270     if (DataSize == AUTHINFO_SIZE) {
   1271       IsDeletion = TRUE;
   1272     }
   1273     //
   1274     // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
   1275     //
   1276     if (OrgVariableInfo.Data == NULL) {
   1277       IsFirstTime = TRUE;
   1278     } else if ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
   1279       IsFirstTime = TRUE;
   1280     } else {
   1281       KeyIndex   = OrgVariableInfo.PubKeyIndex;
   1282       IsFirstTime = FALSE;
   1283     }
   1284   } else if ((OrgVariableInfo.Data != NULL) &&
   1285              ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)
   1286             ) {
   1287     //
   1288     // If the variable is already write-protected, it always needs authentication before update.
   1289     //
   1290     return EFI_WRITE_PROTECTED;
   1291   } else {
   1292     //
   1293     // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
   1294     // That means it is not authenticated variable, just update variable as usual.
   1295     //
   1296     Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
   1297     return Status;
   1298   }
   1299 
   1300   //
   1301   // Get PubKey and check Monotonic Count value corresponding to the variable.
   1302   //
   1303   CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
   1304   CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
   1305   PubKey    = CertBlock->PublicKey;
   1306 
   1307   //
   1308   // Update Monotonic Count value.
   1309   //
   1310   MonotonicCount = CertData->MonotonicCount;
   1311 
   1312   if (!IsFirstTime) {
   1313     //
   1314     // 2 cases need to check here
   1315     //   1. Internal PubKey variable. PubKeyIndex is always 0
   1316     //   2. Other counter-based AuthVariable. Check input PubKey.
   1317     //
   1318     if (KeyIndex == 0) {
   1319       return EFI_SECURITY_VIOLATION;
   1320     }
   1321     for (Index = 0; Index < mPubKeyNumber; Index++) {
   1322       if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == KeyIndex) {
   1323         if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
   1324           break;
   1325         } else {
   1326           return EFI_SECURITY_VIOLATION;
   1327         }
   1328       }
   1329     }
   1330     if (Index == mPubKeyNumber) {
   1331       return EFI_SECURITY_VIOLATION;
   1332     }
   1333 
   1334     //
   1335     // Compare the current monotonic count and ensure that it is greater than the last SetVariable
   1336     // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
   1337     //
   1338     if (MonotonicCount <= OrgVariableInfo.MonotonicCount) {
   1339       //
   1340       // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
   1341       //
   1342       return EFI_SECURITY_VIOLATION;
   1343     }
   1344   }
   1345   //
   1346   // Verify the certificate in Data payload.
   1347   //
   1348   Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
   1349   if (EFI_ERROR (Status)) {
   1350     return Status;
   1351   }
   1352 
   1353   //
   1354   // Now, the signature has been verified!
   1355   //
   1356   if (IsFirstTime && !IsDeletion) {
   1357     VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;
   1358     VariableDataEntry.Guid         = VendorGuid;
   1359     VariableDataEntry.Name         = VariableName;
   1360 
   1361     //
   1362     // Update public key database variable if need.
   1363     //
   1364     KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);
   1365     if (KeyIndex == 0) {
   1366       return EFI_OUT_OF_RESOURCES;
   1367     }
   1368   }
   1369 
   1370   //
   1371   // Verification pass.
   1372   //
   1373   return AuthServiceInternalUpdateVariableWithMonotonicCount (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount);
   1374 }
   1375 
   1376 /**
   1377   Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
   1378 
   1379   @param[in]        Data          Pointer to original EFI_SIGNATURE_LIST.
   1380   @param[in]        DataSize      Size of Data buffer.
   1381   @param[in, out]   NewData       Pointer to new EFI_SIGNATURE_LIST.
   1382   @param[in, out]   NewDataSize   Size of NewData buffer.
   1383 
   1384 **/
   1385 EFI_STATUS
   1386 FilterSignatureList (
   1387   IN     VOID       *Data,
   1388   IN     UINTN      DataSize,
   1389   IN OUT VOID       *NewData,
   1390   IN OUT UINTN      *NewDataSize
   1391   )
   1392 {
   1393   EFI_SIGNATURE_LIST    *CertList;
   1394   EFI_SIGNATURE_DATA    *Cert;
   1395   UINTN                 CertCount;
   1396   EFI_SIGNATURE_LIST    *NewCertList;
   1397   EFI_SIGNATURE_DATA    *NewCert;
   1398   UINTN                 NewCertCount;
   1399   UINTN                 Index;
   1400   UINTN                 Index2;
   1401   UINTN                 Size;
   1402   UINT8                 *Tail;
   1403   UINTN                 CopiedCount;
   1404   UINTN                 SignatureListSize;
   1405   BOOLEAN               IsNewCert;
   1406   UINT8                 *TempData;
   1407   UINTN                 TempDataSize;
   1408   EFI_STATUS            Status;
   1409 
   1410   if (*NewDataSize == 0) {
   1411     return EFI_SUCCESS;
   1412   }
   1413 
   1414   TempDataSize = *NewDataSize;
   1415   Status = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **) &TempData);
   1416   if (EFI_ERROR (Status)) {
   1417     return EFI_OUT_OF_RESOURCES;
   1418   }
   1419 
   1420   Tail = TempData;
   1421 
   1422   NewCertList = (EFI_SIGNATURE_LIST *) NewData;
   1423   while ((*NewDataSize > 0) && (*NewDataSize >= NewCertList->SignatureListSize)) {
   1424     NewCert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
   1425     NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
   1426 
   1427     CopiedCount = 0;
   1428     for (Index = 0; Index < NewCertCount; Index++) {
   1429       IsNewCert = TRUE;
   1430 
   1431       Size = DataSize;
   1432       CertList = (EFI_SIGNATURE_LIST *) Data;
   1433       while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
   1434         if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
   1435            (CertList->SignatureSize == NewCertList->SignatureSize)) {
   1436           Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
   1437           CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
   1438           for (Index2 = 0; Index2 < CertCount; Index2++) {
   1439             //
   1440             // Iterate each Signature Data in this Signature List.
   1441             //
   1442             if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
   1443               IsNewCert = FALSE;
   1444               break;
   1445             }
   1446             Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
   1447           }
   1448         }
   1449 
   1450         if (!IsNewCert) {
   1451           break;
   1452         }
   1453         Size -= CertList->SignatureListSize;
   1454         CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
   1455       }
   1456 
   1457       if (IsNewCert) {
   1458         //
   1459         // New EFI_SIGNATURE_DATA, keep it.
   1460         //
   1461         if (CopiedCount == 0) {
   1462           //
   1463           // Copy EFI_SIGNATURE_LIST header for only once.
   1464           //
   1465           CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
   1466           Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
   1467         }
   1468 
   1469         CopyMem (Tail, NewCert, NewCertList->SignatureSize);
   1470         Tail += NewCertList->SignatureSize;
   1471         CopiedCount++;
   1472       }
   1473 
   1474       NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
   1475     }
   1476 
   1477     //
   1478     // Update SignatureListSize in the kept EFI_SIGNATURE_LIST.
   1479     //
   1480     if (CopiedCount != 0) {
   1481       SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
   1482       CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
   1483       CertList->SignatureListSize = (UINT32) SignatureListSize;
   1484     }
   1485 
   1486     *NewDataSize -= NewCertList->SignatureListSize;
   1487     NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
   1488   }
   1489 
   1490   TempDataSize = (Tail - (UINT8 *) TempData);
   1491 
   1492   CopyMem (NewData, TempData, TempDataSize);
   1493   *NewDataSize = TempDataSize;
   1494 
   1495   return EFI_SUCCESS;
   1496 }
   1497 
   1498 /**
   1499   Compare two EFI_TIME data.
   1500 
   1501 
   1502   @param FirstTime           A pointer to the first EFI_TIME data.
   1503   @param SecondTime          A pointer to the second EFI_TIME data.
   1504 
   1505   @retval  TRUE              The FirstTime is not later than the SecondTime.
   1506   @retval  FALSE             The FirstTime is later than the SecondTime.
   1507 
   1508 **/
   1509 BOOLEAN
   1510 AuthServiceInternalCompareTimeStamp (
   1511   IN EFI_TIME               *FirstTime,
   1512   IN EFI_TIME               *SecondTime
   1513   )
   1514 {
   1515   if (FirstTime->Year != SecondTime->Year) {
   1516     return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
   1517   } else if (FirstTime->Month != SecondTime->Month) {
   1518     return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
   1519   } else if (FirstTime->Day != SecondTime->Day) {
   1520     return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
   1521   } else if (FirstTime->Hour != SecondTime->Hour) {
   1522     return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
   1523   } else if (FirstTime->Minute != SecondTime->Minute) {
   1524     return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
   1525   }
   1526 
   1527   return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
   1528 }
   1529 
   1530 /**
   1531   Find matching signer's certificates for common authenticated variable
   1532   by corresponding VariableName and VendorGuid from "certdb" or "certdbv".
   1533 
   1534   The data format of "certdb" or "certdbv":
   1535   //
   1536   //     UINT32 CertDbListSize;
   1537   // /// AUTH_CERT_DB_DATA Certs1[];
   1538   // /// AUTH_CERT_DB_DATA Certs2[];
   1539   // /// ...
   1540   // /// AUTH_CERT_DB_DATA Certsn[];
   1541   //
   1542 
   1543   @param[in]  VariableName   Name of authenticated Variable.
   1544   @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
   1545   @param[in]  Data           Pointer to variable "certdb" or "certdbv".
   1546   @param[in]  DataSize       Size of variable "certdb" or "certdbv".
   1547   @param[out] CertOffset     Offset of matching CertData, from starting of Data.
   1548   @param[out] CertDataSize   Length of CertData in bytes.
   1549   @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
   1550                              starting of Data.
   1551   @param[out] CertNodeSize   Length of AUTH_CERT_DB_DATA in bytes.
   1552 
   1553   @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
   1554   @retval  EFI_NOT_FOUND         Fail to find matching certs.
   1555   @retval  EFI_SUCCESS           Find matching certs and output parameters.
   1556 
   1557 **/
   1558 EFI_STATUS
   1559 FindCertsFromDb (
   1560   IN     CHAR16           *VariableName,
   1561   IN     EFI_GUID         *VendorGuid,
   1562   IN     UINT8            *Data,
   1563   IN     UINTN            DataSize,
   1564   OUT    UINT32           *CertOffset,    OPTIONAL
   1565   OUT    UINT32           *CertDataSize,  OPTIONAL
   1566   OUT    UINT32           *CertNodeOffset,OPTIONAL
   1567   OUT    UINT32           *CertNodeSize   OPTIONAL
   1568   )
   1569 {
   1570   UINT32                  Offset;
   1571   AUTH_CERT_DB_DATA       *Ptr;
   1572   UINT32                  CertSize;
   1573   UINT32                  NameSize;
   1574   UINT32                  NodeSize;
   1575   UINT32                  CertDbListSize;
   1576 
   1577   if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
   1578     return EFI_INVALID_PARAMETER;
   1579   }
   1580 
   1581   //
   1582   // Check whether DataSize matches recorded CertDbListSize.
   1583   //
   1584   if (DataSize < sizeof (UINT32)) {
   1585     return EFI_INVALID_PARAMETER;
   1586   }
   1587 
   1588   CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);
   1589 
   1590   if (CertDbListSize != (UINT32) DataSize) {
   1591     return EFI_INVALID_PARAMETER;
   1592   }
   1593 
   1594   Offset = sizeof (UINT32);
   1595 
   1596   //
   1597   // Get corresponding certificates by VendorGuid and VariableName.
   1598   //
   1599   while (Offset < (UINT32) DataSize) {
   1600     Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
   1601     //
   1602     // Check whether VendorGuid matches.
   1603     //
   1604     if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
   1605       NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
   1606       NameSize = ReadUnaligned32 (&Ptr->NameSize);
   1607       CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
   1608 
   1609       if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
   1610           sizeof (CHAR16) * NameSize) {
   1611         return EFI_INVALID_PARAMETER;
   1612       }
   1613 
   1614       Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
   1615       //
   1616       // Check whether VariableName matches.
   1617       //
   1618       if ((NameSize == StrLen (VariableName)) &&
   1619           (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {
   1620         Offset = Offset + NameSize * sizeof (CHAR16);
   1621 
   1622         if (CertOffset != NULL) {
   1623           *CertOffset = Offset;
   1624         }
   1625 
   1626         if (CertDataSize != NULL) {
   1627           *CertDataSize = CertSize;
   1628         }
   1629 
   1630         if (CertNodeOffset != NULL) {
   1631           *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);
   1632         }
   1633 
   1634         if (CertNodeSize != NULL) {
   1635           *CertNodeSize = NodeSize;
   1636         }
   1637 
   1638         return EFI_SUCCESS;
   1639       } else {
   1640         Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
   1641       }
   1642     } else {
   1643       NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
   1644       Offset   = Offset + NodeSize;
   1645     }
   1646   }
   1647 
   1648   return EFI_NOT_FOUND;
   1649 }
   1650 
   1651 /**
   1652   Retrieve signer's certificates for common authenticated variable
   1653   by corresponding VariableName and VendorGuid from "certdb"
   1654   or "certdbv" according to authenticated variable attributes.
   1655 
   1656   @param[in]  VariableName   Name of authenticated Variable.
   1657   @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
   1658   @param[in]  Attributes        Attributes of authenticated variable.
   1659   @param[out] CertData       Pointer to signer's certificates.
   1660   @param[out] CertDataSize   Length of CertData in bytes.
   1661 
   1662   @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
   1663   @retval  EFI_NOT_FOUND         Fail to find "certdb"/"certdbv" or matching certs.
   1664   @retval  EFI_SUCCESS           Get signer's certificates successfully.
   1665 
   1666 **/
   1667 EFI_STATUS
   1668 GetCertsFromDb (
   1669   IN     CHAR16           *VariableName,
   1670   IN     EFI_GUID         *VendorGuid,
   1671   IN     UINT32           Attributes,
   1672   OUT    UINT8            **CertData,
   1673   OUT    UINT32           *CertDataSize
   1674   )
   1675 {
   1676   EFI_STATUS              Status;
   1677   UINT8                   *Data;
   1678   UINTN                   DataSize;
   1679   UINT32                  CertOffset;
   1680   CHAR16                  *DbName;
   1681 
   1682   if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
   1683     return EFI_INVALID_PARAMETER;
   1684   }
   1685 
   1686 
   1687   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
   1688     //
   1689     // Get variable "certdb".
   1690     //
   1691     DbName = EFI_CERT_DB_NAME;
   1692   } else {
   1693     //
   1694     // Get variable "certdbv".
   1695     //
   1696     DbName = EFI_CERT_DB_VOLATILE_NAME;
   1697   }
   1698 
   1699   //
   1700   // Get variable "certdb" or "certdbv".
   1701   //
   1702   Status = AuthServiceInternalFindVariable (
   1703              DbName,
   1704              &gEfiCertDbGuid,
   1705              (VOID **) &Data,
   1706              &DataSize
   1707              );
   1708   if (EFI_ERROR (Status)) {
   1709     return Status;
   1710   }
   1711 
   1712   if ((DataSize == 0) || (Data == NULL)) {
   1713     ASSERT (FALSE);
   1714     return EFI_NOT_FOUND;
   1715   }
   1716 
   1717   Status = FindCertsFromDb (
   1718              VariableName,
   1719              VendorGuid,
   1720              Data,
   1721              DataSize,
   1722              &CertOffset,
   1723              CertDataSize,
   1724              NULL,
   1725              NULL
   1726              );
   1727 
   1728   if (EFI_ERROR (Status)) {
   1729     return Status;
   1730   }
   1731 
   1732   *CertData = Data + CertOffset;
   1733   return EFI_SUCCESS;
   1734 }
   1735 
   1736 /**
   1737   Delete matching signer's certificates when deleting common authenticated
   1738   variable by corresponding VariableName and VendorGuid from "certdb" or
   1739   "certdbv" according to authenticated variable attributes.
   1740 
   1741   @param[in]  VariableName   Name of authenticated Variable.
   1742   @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
   1743   @param[in]  Attributes        Attributes of authenticated variable.
   1744 
   1745   @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
   1746   @retval  EFI_NOT_FOUND         Fail to find "certdb"/"certdbv" or matching certs.
   1747   @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.
   1748   @retval  EFI_SUCCESS           The operation is completed successfully.
   1749 
   1750 **/
   1751 EFI_STATUS
   1752 DeleteCertsFromDb (
   1753   IN     CHAR16           *VariableName,
   1754   IN     EFI_GUID         *VendorGuid,
   1755   IN     UINT32           Attributes
   1756   )
   1757 {
   1758   EFI_STATUS              Status;
   1759   UINT8                   *Data;
   1760   UINTN                   DataSize;
   1761   UINT32                  VarAttr;
   1762   UINT32                  CertNodeOffset;
   1763   UINT32                  CertNodeSize;
   1764   UINT8                   *NewCertDb;
   1765   UINT32                  NewCertDbSize;
   1766   CHAR16                  *DbName;
   1767 
   1768   if ((VariableName == NULL) || (VendorGuid == NULL)) {
   1769     return EFI_INVALID_PARAMETER;
   1770   }
   1771 
   1772   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
   1773     //
   1774     // Get variable "certdb".
   1775     //
   1776     DbName = EFI_CERT_DB_NAME;
   1777     VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
   1778   } else {
   1779     //
   1780     // Get variable "certdbv".
   1781     //
   1782     DbName = EFI_CERT_DB_VOLATILE_NAME;
   1783     VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
   1784   }
   1785 
   1786   Status = AuthServiceInternalFindVariable (
   1787              DbName,
   1788              &gEfiCertDbGuid,
   1789              (VOID **) &Data,
   1790              &DataSize
   1791              );
   1792 
   1793   if (EFI_ERROR (Status)) {
   1794     return Status;
   1795   }
   1796 
   1797   if ((DataSize == 0) || (Data == NULL)) {
   1798     ASSERT (FALSE);
   1799     return EFI_NOT_FOUND;
   1800   }
   1801 
   1802   if (DataSize == sizeof (UINT32)) {
   1803     //
   1804     // There is no certs in "certdb" or "certdbv".
   1805     //
   1806     return EFI_SUCCESS;
   1807   }
   1808 
   1809   //
   1810   // Get corresponding cert node from "certdb" or "certdbv".
   1811   //
   1812   Status = FindCertsFromDb (
   1813              VariableName,
   1814              VendorGuid,
   1815              Data,
   1816              DataSize,
   1817              NULL,
   1818              NULL,
   1819              &CertNodeOffset,
   1820              &CertNodeSize
   1821              );
   1822 
   1823   if (EFI_ERROR (Status)) {
   1824     return Status;
   1825   }
   1826 
   1827   if (DataSize < (CertNodeOffset + CertNodeSize)) {
   1828     return EFI_NOT_FOUND;
   1829   }
   1830 
   1831   //
   1832   // Construct new data content of variable "certdb" or "certdbv".
   1833   //
   1834   NewCertDbSize = (UINT32) DataSize - CertNodeSize;
   1835   NewCertDb     = (UINT8*) mCertDbStore;
   1836 
   1837   //
   1838   // Copy the DB entries before deleting node.
   1839   //
   1840   CopyMem (NewCertDb, Data, CertNodeOffset);
   1841   //
   1842   // Update CertDbListSize.
   1843   //
   1844   CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
   1845   //
   1846   // Copy the DB entries after deleting node.
   1847   //
   1848   if (DataSize > (CertNodeOffset + CertNodeSize)) {
   1849     CopyMem (
   1850       NewCertDb + CertNodeOffset,
   1851       Data + CertNodeOffset + CertNodeSize,
   1852       DataSize - CertNodeOffset - CertNodeSize
   1853       );
   1854   }
   1855 
   1856   //
   1857   // Set "certdb" or "certdbv".
   1858   //
   1859   Status   = AuthServiceInternalUpdateVariable (
   1860                DbName,
   1861                &gEfiCertDbGuid,
   1862                NewCertDb,
   1863                NewCertDbSize,
   1864                VarAttr
   1865                );
   1866 
   1867   return Status;
   1868 }
   1869 
   1870 /**
   1871   Insert signer's certificates for common authenticated variable with VariableName
   1872   and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to
   1873   time based authenticated variable attributes.
   1874 
   1875   @param[in]  VariableName   Name of authenticated Variable.
   1876   @param[in]  VendorGuid     Vendor GUID of authenticated Variable.
   1877   @param[in]  Attributes     Attributes of authenticated variable.
   1878   @param[in]  CertData       Pointer to signer's certificates.
   1879   @param[in]  CertDataSize   Length of CertData in bytes.
   1880 
   1881   @retval  EFI_INVALID_PARAMETER Any input parameter is invalid.
   1882   @retval  EFI_ACCESS_DENIED     An AUTH_CERT_DB_DATA entry with same VariableName
   1883                                  and VendorGuid already exists.
   1884   @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.
   1885   @retval  EFI_SUCCESS           Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv"
   1886 
   1887 **/
   1888 EFI_STATUS
   1889 InsertCertsToDb (
   1890   IN     CHAR16           *VariableName,
   1891   IN     EFI_GUID         *VendorGuid,
   1892   IN     UINT32           Attributes,
   1893   IN     UINT8            *CertData,
   1894   IN     UINTN            CertDataSize
   1895   )
   1896 {
   1897   EFI_STATUS              Status;
   1898   UINT8                   *Data;
   1899   UINTN                   DataSize;
   1900   UINT32                  VarAttr;
   1901   UINT8                   *NewCertDb;
   1902   UINT32                  NewCertDbSize;
   1903   UINT32                  CertNodeSize;
   1904   UINT32                  NameSize;
   1905   AUTH_CERT_DB_DATA       *Ptr;
   1906   CHAR16                  *DbName;
   1907 
   1908   if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
   1909     return EFI_INVALID_PARAMETER;
   1910   }
   1911 
   1912   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
   1913     //
   1914     // Get variable "certdb".
   1915     //
   1916     DbName = EFI_CERT_DB_NAME;
   1917     VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
   1918   } else {
   1919     //
   1920     // Get variable "certdbv".
   1921     //
   1922     DbName = EFI_CERT_DB_VOLATILE_NAME;
   1923     VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
   1924   }
   1925 
   1926   //
   1927   // Get variable "certdb" or "certdbv".
   1928   //
   1929   Status = AuthServiceInternalFindVariable (
   1930              DbName,
   1931              &gEfiCertDbGuid,
   1932              (VOID **) &Data,
   1933              &DataSize
   1934              );
   1935   if (EFI_ERROR (Status)) {
   1936     return Status;
   1937   }
   1938 
   1939   if ((DataSize == 0) || (Data == NULL)) {
   1940     ASSERT (FALSE);
   1941     return EFI_NOT_FOUND;
   1942   }
   1943 
   1944   //
   1945   // Find whether matching cert node already exists in "certdb" or "certdbv".
   1946   // If yes return error.
   1947   //
   1948   Status = FindCertsFromDb (
   1949              VariableName,
   1950              VendorGuid,
   1951              Data,
   1952              DataSize,
   1953              NULL,
   1954              NULL,
   1955              NULL,
   1956              NULL
   1957              );
   1958 
   1959   if (!EFI_ERROR (Status)) {
   1960     ASSERT (FALSE);
   1961     return EFI_ACCESS_DENIED;
   1962   }
   1963 
   1964   //
   1965   // Construct new data content of variable "certdb" or "certdbv".
   1966   //
   1967   NameSize      = (UINT32) StrLen (VariableName);
   1968   CertNodeSize  = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);
   1969   NewCertDbSize = (UINT32) DataSize + CertNodeSize;
   1970   if (NewCertDbSize > mMaxCertDbSize) {
   1971     return EFI_OUT_OF_RESOURCES;
   1972   }
   1973   NewCertDb     = (UINT8*) mCertDbStore;
   1974 
   1975   //
   1976   // Copy the DB entries before inserting node.
   1977   //
   1978   CopyMem (NewCertDb, Data, DataSize);
   1979   //
   1980   // Update CertDbListSize.
   1981   //
   1982   CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
   1983   //
   1984   // Construct new cert node.
   1985   //
   1986   Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);
   1987   CopyGuid (&Ptr->VendorGuid, VendorGuid);
   1988   CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
   1989   CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
   1990   CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
   1991 
   1992   CopyMem (
   1993     (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),
   1994     VariableName,
   1995     NameSize * sizeof (CHAR16)
   1996     );
   1997 
   1998   CopyMem (
   1999     (UINT8 *) Ptr +  sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
   2000     CertData,
   2001     CertDataSize
   2002     );
   2003 
   2004   //
   2005   // Set "certdb" or "certdbv".
   2006   //
   2007   Status   = AuthServiceInternalUpdateVariable (
   2008                DbName,
   2009                &gEfiCertDbGuid,
   2010                NewCertDb,
   2011                NewCertDbSize,
   2012                VarAttr
   2013                );
   2014 
   2015   return Status;
   2016 }
   2017 
   2018 /**
   2019   Clean up signer's certificates for common authenticated variable
   2020   by corresponding VariableName and VendorGuid from "certdb".
   2021   System may break down during Timebased Variable update & certdb update,
   2022   make them inconsistent,  this function is called in AuthVariable Init
   2023   to ensure consistency.
   2024 
   2025   @retval  EFI_NOT_FOUND         Fail to find variable "certdb".
   2026   @retval  EFI_OUT_OF_RESOURCES  The operation is failed due to lack of resources.
   2027   @retval  EFI_SUCCESS           The operation is completed successfully.
   2028 
   2029 **/
   2030 EFI_STATUS
   2031 CleanCertsFromDb (
   2032   VOID
   2033   )
   2034 {
   2035   UINT32                  Offset;
   2036   AUTH_CERT_DB_DATA       *Ptr;
   2037   UINT32                  NameSize;
   2038   UINT32                  NodeSize;
   2039   CHAR16                  *VariableName;
   2040   EFI_STATUS              Status;
   2041   BOOLEAN                 CertCleaned;
   2042   UINT8                   *Data;
   2043   UINTN                   DataSize;
   2044   EFI_GUID                AuthVarGuid;
   2045   AUTH_VARIABLE_INFO      AuthVariableInfo;
   2046 
   2047   Status = EFI_SUCCESS;
   2048 
   2049   //
   2050   // Get corresponding certificates by VendorGuid and VariableName.
   2051   //
   2052   do {
   2053     CertCleaned = FALSE;
   2054 
   2055     //
   2056     // Get latest variable "certdb"
   2057     //
   2058     Status = AuthServiceInternalFindVariable (
   2059                EFI_CERT_DB_NAME,
   2060                &gEfiCertDbGuid,
   2061                (VOID **) &Data,
   2062                &DataSize
   2063                );
   2064     if (EFI_ERROR (Status)) {
   2065       return Status;
   2066     }
   2067 
   2068     if ((DataSize == 0) || (Data == NULL)) {
   2069       ASSERT (FALSE);
   2070       return EFI_NOT_FOUND;
   2071     }
   2072 
   2073     Offset = sizeof (UINT32);
   2074 
   2075     while (Offset < (UINT32) DataSize) {
   2076       Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
   2077       NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
   2078       NameSize = ReadUnaligned32 (&Ptr->NameSize);
   2079 
   2080       //
   2081       // Get VarName tailed with '\0'
   2082       //
   2083       VariableName = AllocateZeroPool((NameSize + 1) * sizeof(CHAR16));
   2084       if (VariableName == NULL) {
   2085         return EFI_OUT_OF_RESOURCES;
   2086       }
   2087       CopyMem (VariableName, (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof(CHAR16));
   2088       //
   2089       // Keep VarGuid  aligned
   2090       //
   2091       CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof(EFI_GUID));
   2092 
   2093       //
   2094       // Find corresponding time auth variable
   2095       //
   2096       ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
   2097       Status = mAuthVarLibContextIn->FindVariable (
   2098                                        VariableName,
   2099                                        &AuthVarGuid,
   2100                                        &AuthVariableInfo
   2101                                        );
   2102 
   2103       if (EFI_ERROR(Status) || (AuthVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
   2104         Status      = DeleteCertsFromDb(
   2105                         VariableName,
   2106                         &AuthVarGuid,
   2107                         AuthVariableInfo.Attributes
   2108                         );
   2109         CertCleaned = TRUE;
   2110         DEBUG((EFI_D_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid));
   2111         FreePool(VariableName);
   2112         break;
   2113       }
   2114 
   2115       FreePool(VariableName);
   2116       Offset = Offset + NodeSize;
   2117     }
   2118   } while (CertCleaned);
   2119 
   2120   return Status;
   2121 }
   2122 
   2123 /**
   2124   Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
   2125 
   2126   Caution: This function may receive untrusted input.
   2127   This function may be invoked in SMM mode, and datasize and data are external input.
   2128   This function will do basic validation, before parse the data.
   2129   This function will parse the authentication carefully to avoid security issues, like
   2130   buffer overflow, integer overflow.
   2131 
   2132   @param[in]  VariableName                Name of Variable to be found.
   2133   @param[in]  VendorGuid                  Variable vendor GUID.
   2134   @param[in]  Data                        Data pointer.
   2135   @param[in]  DataSize                    Size of Data found. If size is less than the
   2136                                           data, this value contains the required size.
   2137   @param[in]  Attributes                  Attribute value of the variable.
   2138   @param[in]  AuthVarType                 Verify against PK, KEK database, private database or certificate in data payload.
   2139   @param[in]  OrgTimeStamp                Pointer to original time stamp,
   2140                                           original variable is not found if NULL.
   2141   @param[out]  VarPayloadPtr              Pointer to variable payload address.
   2142   @param[out]  VarPayloadSize             Pointer to variable payload size.
   2143 
   2144   @retval EFI_INVALID_PARAMETER           Invalid parameter.
   2145   @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
   2146                                           check carried out by the firmware.
   2147   @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack
   2148                                           of resources.
   2149   @retval EFI_SUCCESS                     Variable pass validation successfully.
   2150 
   2151 **/
   2152 EFI_STATUS
   2153 VerifyTimeBasedPayload (
   2154   IN     CHAR16                             *VariableName,
   2155   IN     EFI_GUID                           *VendorGuid,
   2156   IN     VOID                               *Data,
   2157   IN     UINTN                              DataSize,
   2158   IN     UINT32                             Attributes,
   2159   IN     AUTHVAR_TYPE                       AuthVarType,
   2160   IN     EFI_TIME                           *OrgTimeStamp,
   2161   OUT    UINT8                              **VarPayloadPtr,
   2162   OUT    UINTN                              *VarPayloadSize
   2163   )
   2164 {
   2165   EFI_VARIABLE_AUTHENTICATION_2    *CertData;
   2166   UINT8                            *SigData;
   2167   UINT32                           SigDataSize;
   2168   UINT8                            *PayloadPtr;
   2169   UINTN                            PayloadSize;
   2170   UINT32                           Attr;
   2171   BOOLEAN                          VerifyStatus;
   2172   EFI_STATUS                       Status;
   2173   EFI_SIGNATURE_LIST               *CertList;
   2174   EFI_SIGNATURE_DATA               *Cert;
   2175   UINTN                            Index;
   2176   UINTN                            CertCount;
   2177   UINT32                           KekDataSize;
   2178   UINT8                            *NewData;
   2179   UINTN                            NewDataSize;
   2180   UINT8                            *Buffer;
   2181   UINTN                            Length;
   2182   UINT8                            *RootCert;
   2183   UINTN                            RootCertSize;
   2184   UINT8                            *SignerCerts;
   2185   UINTN                            CertStackSize;
   2186   UINT8                            *CertsInCertDb;
   2187   UINT32                           CertsSizeinDb;
   2188 
   2189   VerifyStatus           = FALSE;
   2190   CertData               = NULL;
   2191   NewData                = NULL;
   2192   Attr                   = Attributes;
   2193   SignerCerts            = NULL;
   2194   RootCert               = NULL;
   2195   CertsInCertDb          = NULL;
   2196 
   2197   //
   2198   // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
   2199   // set, then the Data buffer shall begin with an instance of a complete (and serialized)
   2200   // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
   2201   // variable value and DataSize shall reflect the combined size of the descriptor and the new
   2202   // variable value. The authentication descriptor is not part of the variable data and is not
   2203   // returned by subsequent calls to GetVariable().
   2204   //
   2205   CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
   2206 
   2207   //
   2208   // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
   2209   // TimeStamp value are set to zero.
   2210   //
   2211   if ((CertData->TimeStamp.Pad1 != 0) ||
   2212       (CertData->TimeStamp.Nanosecond != 0) ||
   2213       (CertData->TimeStamp.TimeZone != 0) ||
   2214       (CertData->TimeStamp.Daylight != 0) ||
   2215       (CertData->TimeStamp.Pad2 != 0)) {
   2216     return EFI_SECURITY_VIOLATION;
   2217   }
   2218 
   2219   if ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
   2220     if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) {
   2221       //
   2222       // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
   2223       //
   2224       return EFI_SECURITY_VIOLATION;
   2225     }
   2226   }
   2227 
   2228   //
   2229   // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
   2230   // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
   2231   //
   2232   if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
   2233       !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
   2234     //
   2235     // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
   2236     //
   2237     return EFI_SECURITY_VIOLATION;
   2238   }
   2239 
   2240   //
   2241   // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
   2242   // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
   2243   //
   2244   SigData = CertData->AuthInfo.CertData;
   2245   SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
   2246 
   2247   //
   2248   // Find out the new data payload which follows Pkcs7 SignedData directly.
   2249   //
   2250   PayloadPtr = SigData + SigDataSize;
   2251   PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
   2252 
   2253   //
   2254   // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes
   2255   // parameters of the SetVariable() call and the TimeStamp component of the
   2256   // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
   2257   // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
   2258   //
   2259   NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
   2260                 sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
   2261 
   2262   //
   2263   // Here is to reuse scratch data area(at the end of volatile variable store)
   2264   // to reduce SMRAM consumption for SMM variable driver.
   2265   // The scratch buffer is enough to hold the serialized data and safe to use,
   2266   // because it is only used at here to do verification temporarily first
   2267   // and then used in UpdateVariable() for a time based auth variable set.
   2268   //
   2269   Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **) &NewData);
   2270   if (EFI_ERROR (Status)) {
   2271     return EFI_OUT_OF_RESOURCES;
   2272   }
   2273 
   2274   Buffer = NewData;
   2275   Length = StrLen (VariableName) * sizeof (CHAR16);
   2276   CopyMem (Buffer, VariableName, Length);
   2277   Buffer += Length;
   2278 
   2279   Length = sizeof (EFI_GUID);
   2280   CopyMem (Buffer, VendorGuid, Length);
   2281   Buffer += Length;
   2282 
   2283   Length = sizeof (UINT32);
   2284   CopyMem (Buffer, &Attr, Length);
   2285   Buffer += Length;
   2286 
   2287   Length = sizeof (EFI_TIME);
   2288   CopyMem (Buffer, &CertData->TimeStamp, Length);
   2289   Buffer += Length;
   2290 
   2291   CopyMem (Buffer, PayloadPtr, PayloadSize);
   2292 
   2293   if (AuthVarType == AuthVarTypePk) {
   2294     //
   2295     // Verify that the signature has been made with the current Platform Key (no chaining for PK).
   2296     // First, get signer's certificates from SignedData.
   2297     //
   2298     VerifyStatus = Pkcs7GetSigners (
   2299                      SigData,
   2300                      SigDataSize,
   2301                      &SignerCerts,
   2302                      &CertStackSize,
   2303                      &RootCert,
   2304                      &RootCertSize
   2305                      );
   2306     if (!VerifyStatus) {
   2307       goto Exit;
   2308     }
   2309 
   2310     //
   2311     // Second, get the current platform key from variable. Check whether it's identical with signer's certificates
   2312     // in SignedData. If not, return error immediately.
   2313     //
   2314     Status = AuthServiceInternalFindVariable (
   2315                EFI_PLATFORM_KEY_NAME,
   2316                &gEfiGlobalVariableGuid,
   2317                &Data,
   2318                &DataSize
   2319                );
   2320     if (EFI_ERROR (Status)) {
   2321       VerifyStatus = FALSE;
   2322       goto Exit;
   2323     }
   2324     CertList = (EFI_SIGNATURE_LIST *) Data;
   2325     Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
   2326     if ((RootCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||
   2327         (CompareMem (Cert->SignatureData, RootCert, RootCertSize) != 0)) {
   2328       VerifyStatus = FALSE;
   2329       goto Exit;
   2330     }
   2331 
   2332     //
   2333     // Verify Pkcs7 SignedData via Pkcs7Verify library.
   2334     //
   2335     VerifyStatus = Pkcs7Verify (
   2336                      SigData,
   2337                      SigDataSize,
   2338                      RootCert,
   2339                      RootCertSize,
   2340                      NewData,
   2341                      NewDataSize
   2342                      );
   2343 
   2344   } else if (AuthVarType == AuthVarTypeKek) {
   2345 
   2346     //
   2347     // Get KEK database from variable.
   2348     //
   2349     Status = AuthServiceInternalFindVariable (
   2350                EFI_KEY_EXCHANGE_KEY_NAME,
   2351                &gEfiGlobalVariableGuid,
   2352                &Data,
   2353                &DataSize
   2354                );
   2355     if (EFI_ERROR (Status)) {
   2356       return Status;
   2357     }
   2358 
   2359     //
   2360     // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
   2361     //
   2362     KekDataSize      = (UINT32) DataSize;
   2363     CertList         = (EFI_SIGNATURE_LIST *) Data;
   2364     while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
   2365       if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
   2366         Cert       = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
   2367         CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
   2368         for (Index = 0; Index < CertCount; Index++) {
   2369           //
   2370           // Iterate each Signature Data Node within this CertList for a verify
   2371           //
   2372           RootCert      = Cert->SignatureData;
   2373           RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
   2374 
   2375           //
   2376           // Verify Pkcs7 SignedData via Pkcs7Verify library.
   2377           //
   2378           VerifyStatus = Pkcs7Verify (
   2379                            SigData,
   2380                            SigDataSize,
   2381                            RootCert,
   2382                            RootCertSize,
   2383                            NewData,
   2384                            NewDataSize
   2385                            );
   2386           if (VerifyStatus) {
   2387             goto Exit;
   2388           }
   2389           Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
   2390         }
   2391       }
   2392       KekDataSize -= CertList->SignatureListSize;
   2393       CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
   2394     }
   2395   } else if (AuthVarType == AuthVarTypePriv) {
   2396 
   2397     //
   2398     // Process common authenticated variable except PK/KEK/DB/DBX/DBT.
   2399     // Get signer's certificates from SignedData.
   2400     //
   2401     VerifyStatus = Pkcs7GetSigners (
   2402                      SigData,
   2403                      SigDataSize,
   2404                      &SignerCerts,
   2405                      &CertStackSize,
   2406                      &RootCert,
   2407                      &RootCertSize
   2408                      );
   2409     if (!VerifyStatus) {
   2410       goto Exit;
   2411     }
   2412 
   2413     //
   2414     // Get previously stored signer's certificates from certdb or certdbv for existing
   2415     // variable. Check whether they are identical with signer's certificates
   2416     // in SignedData. If not, return error immediately.
   2417     //
   2418     if (OrgTimeStamp != NULL) {
   2419       VerifyStatus = FALSE;
   2420 
   2421       Status = GetCertsFromDb (VariableName, VendorGuid, Attributes, &CertsInCertDb, &CertsSizeinDb);
   2422       if (EFI_ERROR (Status)) {
   2423         goto Exit;
   2424       }
   2425 
   2426       if ((CertStackSize != CertsSizeinDb) ||
   2427           (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {
   2428         goto Exit;
   2429       }
   2430     }
   2431 
   2432     VerifyStatus = Pkcs7Verify (
   2433                      SigData,
   2434                      SigDataSize,
   2435                      RootCert,
   2436                      RootCertSize,
   2437                      NewData,
   2438                      NewDataSize
   2439                      );
   2440     if (!VerifyStatus) {
   2441       goto Exit;
   2442     }
   2443 
   2444     if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {
   2445       //
   2446       // Insert signer's certificates when adding a new common authenticated variable.
   2447       //
   2448       Status = InsertCertsToDb (VariableName, VendorGuid, Attributes, SignerCerts, CertStackSize);
   2449       if (EFI_ERROR (Status)) {
   2450         VerifyStatus = FALSE;
   2451         goto Exit;
   2452       }
   2453     }
   2454   } else if (AuthVarType == AuthVarTypePayload) {
   2455     CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;
   2456     Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
   2457     RootCert      = Cert->SignatureData;
   2458     RootCertSize  = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
   2459     //
   2460     // Verify Pkcs7 SignedData via Pkcs7Verify library.
   2461     //
   2462     VerifyStatus = Pkcs7Verify (
   2463                      SigData,
   2464                      SigDataSize,
   2465                      RootCert,
   2466                      RootCertSize,
   2467                      NewData,
   2468                      NewDataSize
   2469                      );
   2470   } else {
   2471     return EFI_SECURITY_VIOLATION;
   2472   }
   2473 
   2474 Exit:
   2475 
   2476   if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {
   2477     Pkcs7FreeSigners (RootCert);
   2478     Pkcs7FreeSigners (SignerCerts);
   2479   }
   2480 
   2481   if (!VerifyStatus) {
   2482     return EFI_SECURITY_VIOLATION;
   2483   }
   2484 
   2485   Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);
   2486   if (EFI_ERROR (Status)) {
   2487     return Status;
   2488   }
   2489 
   2490   *VarPayloadPtr = PayloadPtr;
   2491   *VarPayloadSize = PayloadSize;
   2492 
   2493   return EFI_SUCCESS;
   2494 }
   2495 
   2496 /**
   2497   Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
   2498 
   2499   Caution: This function may receive untrusted input.
   2500   This function may be invoked in SMM mode, and datasize and data are external input.
   2501   This function will do basic validation, before parse the data.
   2502   This function will parse the authentication carefully to avoid security issues, like
   2503   buffer overflow, integer overflow.
   2504 
   2505   @param[in]  VariableName                Name of Variable to be found.
   2506   @param[in]  VendorGuid                  Variable vendor GUID.
   2507   @param[in]  Data                        Data pointer.
   2508   @param[in]  DataSize                    Size of Data found. If size is less than the
   2509                                           data, this value contains the required size.
   2510   @param[in]  Attributes                  Attribute value of the variable.
   2511   @param[in]  AuthVarType                 Verify against PK, KEK database, private database or certificate in data payload.
   2512   @param[out] VarDel                      Delete the variable or not.
   2513 
   2514   @retval EFI_INVALID_PARAMETER           Invalid parameter.
   2515   @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
   2516                                           check carried out by the firmware.
   2517   @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack
   2518                                           of resources.
   2519   @retval EFI_SUCCESS                     Variable pass validation successfully.
   2520 
   2521 **/
   2522 EFI_STATUS
   2523 VerifyTimeBasedPayloadAndUpdate (
   2524   IN     CHAR16                             *VariableName,
   2525   IN     EFI_GUID                           *VendorGuid,
   2526   IN     VOID                               *Data,
   2527   IN     UINTN                              DataSize,
   2528   IN     UINT32                             Attributes,
   2529   IN     AUTHVAR_TYPE                       AuthVarType,
   2530   OUT    BOOLEAN                            *VarDel
   2531   )
   2532 {
   2533   EFI_STATUS                       Status;
   2534   EFI_STATUS                       FindStatus;
   2535   UINT8                            *PayloadPtr;
   2536   UINTN                            PayloadSize;
   2537   EFI_VARIABLE_AUTHENTICATION_2    *CertData;
   2538   AUTH_VARIABLE_INFO               OrgVariableInfo;
   2539   BOOLEAN                          IsDel;
   2540 
   2541   ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
   2542   FindStatus = mAuthVarLibContextIn->FindVariable (
   2543              VariableName,
   2544              VendorGuid,
   2545              &OrgVariableInfo
   2546              );
   2547 
   2548   Status = VerifyTimeBasedPayload (
   2549              VariableName,
   2550              VendorGuid,
   2551              Data,
   2552              DataSize,
   2553              Attributes,
   2554              AuthVarType,
   2555              (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL,
   2556              &PayloadPtr,
   2557              &PayloadSize
   2558              );
   2559   if (EFI_ERROR (Status)) {
   2560     return Status;
   2561   }
   2562 
   2563   if (!EFI_ERROR(FindStatus)
   2564    && (PayloadSize == 0)
   2565    && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
   2566     IsDel = TRUE;
   2567   } else {
   2568     IsDel = FALSE;
   2569   }
   2570 
   2571   CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
   2572 
   2573   //
   2574   // Final step: Update/Append Variable if it pass Pkcs7Verify
   2575   //
   2576   Status = AuthServiceInternalUpdateVariableWithTimeStamp (
   2577              VariableName,
   2578              VendorGuid,
   2579              PayloadPtr,
   2580              PayloadSize,
   2581              Attributes,
   2582              &CertData->TimeStamp
   2583              );
   2584 
   2585   //
   2586   // Delete signer's certificates when delete the common authenticated variable.
   2587   //
   2588   if (IsDel && AuthVarType == AuthVarTypePriv && !EFI_ERROR(Status) ) {
   2589     Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
   2590   }
   2591 
   2592   if (VarDel != NULL) {
   2593     if (IsDel && !EFI_ERROR(Status)) {
   2594       *VarDel = TRUE;
   2595     } else {
   2596       *VarDel = FALSE;
   2597     }
   2598   }
   2599 
   2600   return Status;
   2601 }
   2602