Home | History | Annotate | Download | only in EsalVariableDxeSal
      1 /** @file
      2   Implement authentication services for the authenticated variable
      3   service in UEFI2.2.
      4 
      5 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "Variable.h"
     17 #include "AuthService.h"
     18 
     19 ///
     20 /// Global database array for scratch
     21 ///
     22 UINT32   mPubKeyNumber;
     23 UINT32   mPlatformMode;
     24 EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};
     25 //
     26 // Public Exponent of RSA Key.
     27 //
     28 CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
     29 
     30 /**
     31   Initializes for authenticated varibale service.
     32 
     33   @retval EFI_SUCCESS           The function successfully executed.
     34   @retval EFI_OUT_OF_RESOURCES  Failed to allocate enough memory resources.
     35 
     36 **/
     37 EFI_STATUS
     38 AutenticatedVariableServiceInitialize (
     39   VOID
     40   )
     41 {
     42   EFI_STATUS                        Status;
     43   VARIABLE_POINTER_TRACK            Variable;
     44   UINT8                             VarValue;
     45   UINT32                            VarAttr;
     46   UINTN                             DataSize;
     47   UINTN                             CtxSize;
     48   AUTHENTICATED_VARIABLE_HEADER     VariableHeader;
     49   BOOLEAN                           Valid;
     50 
     51   ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
     52 
     53   mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid;
     54   mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical]     = &gEfiCertRsa2048Sha256Guid;
     55   mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid;
     56 
     57   //
     58   // Initialize hash context.
     59   //
     60   CtxSize   = Sha256GetContextSize ();
     61   mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize);
     62   ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL);
     63   //
     64   // Check "AuthVarKeyDatabase" variable's existence.
     65   // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
     66   //
     67   Status = FindVariable (
     68              mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],
     69              &gEfiAuthenticatedVariableGuid,
     70              &Variable,
     71              &mVariableModuleGlobal->VariableGlobal[Physical],
     72              mVariableModuleGlobal->FvbInstance
     73              );
     74 
     75   if (Variable.CurrPtr == 0x0) {
     76     VarAttr       = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
     77     VarValue      = 0;
     78     mPubKeyNumber = 0;
     79     Status        = UpdateVariable (
     80                       mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],
     81                       &gEfiAuthenticatedVariableGuid,
     82                       &VarValue,
     83                       sizeof(UINT8),
     84                       VarAttr,
     85                       0,
     86                       0,
     87                       FALSE,
     88                       mVariableModuleGlobal,
     89                       &Variable
     90                       );
     91     if (EFI_ERROR (Status)) {
     92       return Status;
     93     }
     94   } else {
     95     //
     96     // Load database in global variable for cache.
     97     //
     98     Valid = IsValidVariableHeader (
     99               Variable.CurrPtr,
    100               Variable.Volatile,
    101               &mVariableModuleGlobal->VariableGlobal[Physical],
    102               mVariableModuleGlobal->FvbInstance,
    103               &VariableHeader
    104               );
    105     ASSERT (Valid);
    106 
    107     DataSize  = DataSizeOfVariable (&VariableHeader);
    108     ASSERT (DataSize <= MAX_KEYDB_SIZE);
    109     GetVariableDataPtr (
    110       Variable.CurrPtr,
    111       Variable.Volatile,
    112       &mVariableModuleGlobal->VariableGlobal[Physical],
    113       mVariableModuleGlobal->FvbInstance,
    114       (CHAR16 *) mVariableModuleGlobal->PubKeyStore
    115       );
    116 
    117     mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
    118   }
    119   //
    120   // Check "SetupMode" variable's existence.
    121   // If it doesn't exist, check PK database's existence to determine the value.
    122   // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
    123   //
    124   Status = FindVariable (
    125              mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],
    126              &gEfiGlobalVariableGuid,
    127              &Variable,
    128              &mVariableModuleGlobal->VariableGlobal[Physical],
    129              mVariableModuleGlobal->FvbInstance
    130              );
    131 
    132   if (Variable.CurrPtr == 0x0) {
    133     Status = FindVariable (
    134                mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY],
    135                &gEfiGlobalVariableGuid,
    136                &Variable,
    137                &mVariableModuleGlobal->VariableGlobal[Physical],
    138                mVariableModuleGlobal->FvbInstance
    139                );
    140     if (Variable.CurrPtr == 0x0) {
    141       mPlatformMode = SETUP_MODE;
    142     } else {
    143       mPlatformMode = USER_MODE;
    144     }
    145 
    146     VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
    147     Status  = UpdateVariable (
    148                 mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],
    149                 &gEfiGlobalVariableGuid,
    150                 &mPlatformMode,
    151                 sizeof(UINT8),
    152                 VarAttr,
    153                 0,
    154                 0,
    155                 FALSE,
    156                 mVariableModuleGlobal,
    157                 &Variable
    158                 );
    159     if (EFI_ERROR (Status)) {
    160       return Status;
    161     }
    162   } else {
    163     GetVariableDataPtr (
    164       Variable.CurrPtr,
    165       Variable.Volatile,
    166       &mVariableModuleGlobal->VariableGlobal[Physical],
    167       mVariableModuleGlobal->FvbInstance,
    168       (CHAR16 *) &mPlatformMode
    169       );
    170   }
    171   //
    172   // Check "SignatureSupport" variable's existence.
    173   // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
    174   //
    175   Status = FindVariable (
    176              EFI_SIGNATURE_SUPPORT_NAME,
    177              &gEfiGlobalVariableGuid,
    178              &Variable,
    179              &mVariableModuleGlobal->VariableGlobal[Physical],
    180              mVariableModuleGlobal->FvbInstance
    181              );
    182 
    183   if (Variable.CurrPtr == 0x0) {
    184     VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
    185     Status  = UpdateVariable (
    186                 EFI_SIGNATURE_SUPPORT_NAME,
    187                 &gEfiGlobalVariableGuid,
    188                 mSignatureSupport,
    189                 SIGSUPPORT_NUM * sizeof(EFI_GUID),
    190                 VarAttr,
    191                 0,
    192                 0,
    193                 FALSE,
    194                 mVariableModuleGlobal,
    195                 &Variable
    196                 );
    197   }
    198 
    199   return Status;
    200 }
    201 
    202 /**
    203   Add public key in store and return its index.
    204 
    205   @param[in]  VirtualMode             The current calling mode for this function.
    206   @param[in]  Global                  The context of this Extended SAL Variable Services Class call.
    207   @param[in]  PubKey                  The input pointer to Public Key data.
    208 
    209   @return                             The index of new added item.
    210 
    211 **/
    212 UINT32
    213 AddPubKeyInStore (
    214   IN  BOOLEAN                   VirtualMode,
    215   IN  ESAL_VARIABLE_GLOBAL      *Global,
    216   IN  UINT8                     *PubKey
    217   )
    218 {
    219   EFI_STATUS              Status;
    220   BOOLEAN                 IsFound;
    221   UINT32                  Index;
    222   VARIABLE_POINTER_TRACK  Variable;
    223   UINT8                   *Ptr;
    224 
    225   if (PubKey == NULL) {
    226     return 0;
    227   }
    228 
    229   Status = FindVariable (
    230              Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],
    231              Global->AuthenticatedVariableGuid[VirtualMode],
    232              &Variable,
    233              &Global->VariableGlobal[VirtualMode],
    234              Global->FvbInstance
    235              );
    236   ASSERT_EFI_ERROR (Status);
    237   //
    238   // Check whether the public key entry does exist.
    239   //
    240   IsFound = FALSE;
    241   for (Ptr = Global->PubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {
    242     if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
    243       IsFound = TRUE;
    244       break;
    245     }
    246     Ptr += EFI_CERT_TYPE_RSA2048_SIZE;
    247   }
    248 
    249   if (!IsFound) {
    250     //
    251     // Add public key in database.
    252     //
    253     if (mPubKeyNumber == MAX_KEY_NUM) {
    254       //
    255       // Notes: Database is full, need enhancement here, currently just return 0.
    256       //
    257       return 0;
    258     }
    259 
    260     CopyMem (Global->PubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
    261     Index = ++mPubKeyNumber;
    262     //
    263     // Update public key database variable.
    264     //
    265     Status = UpdateVariable (
    266                Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],
    267                Global->AuthenticatedVariableGuid[VirtualMode],
    268                Global->PubKeyStore,
    269                mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,
    270                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
    271                0,
    272                0,
    273                VirtualMode,
    274                Global,
    275                &Variable
    276                );
    277     ASSERT_EFI_ERROR (Status);
    278   }
    279 
    280   return Index;
    281 }
    282 
    283 /**
    284   Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
    285   Follow the steps in UEFI2.2.
    286 
    287   @param[in]  VirtualMode             The current calling mode for this function.
    288   @param[in]  Global                  The context of this Extended SAL Variable Services Class call.
    289   @param[in]  Data                    The pointer to data with AuthInfo.
    290   @param[in]  DataSize                The size of Data.
    291   @param[in]  PubKey                  The public key used for verification.
    292 
    293   @retval EFI_INVALID_PARAMETER       Invalid parameter.
    294   @retval EFI_SECURITY_VIOLATION      Authentication failed.
    295   @retval EFI_SUCCESS                 Authentication successful.
    296 
    297 **/
    298 EFI_STATUS
    299 VerifyDataPayload (
    300   IN  BOOLEAN                   VirtualMode,
    301   IN  ESAL_VARIABLE_GLOBAL      *Global,
    302   IN  UINT8                     *Data,
    303   IN  UINTN                     DataSize,
    304   IN  UINT8                     *PubKey
    305   )
    306 {
    307   BOOLEAN                         Status;
    308   EFI_VARIABLE_AUTHENTICATION     *CertData;
    309   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
    310   UINT8                           Digest[SHA256_DIGEST_SIZE];
    311   VOID                            *Rsa;
    312   VOID                            *HashContext;
    313 
    314   Rsa         = NULL;
    315   CertData    = NULL;
    316   CertBlock   = NULL;
    317 
    318   if (Data == NULL || PubKey == NULL) {
    319     return EFI_INVALID_PARAMETER;
    320   }
    321 
    322   CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
    323   CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
    324 
    325   //
    326   // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
    327   // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
    328   //
    329   if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
    330       !CompareGuid (&CertData->AuthInfo.CertType, Global->CertRsa2048Sha256Guid[VirtualMode])
    331         ) {
    332     //
    333     // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
    334     //
    335     return EFI_SECURITY_VIOLATION;
    336   }
    337 
    338   //
    339   // Hash data payload with SHA256.
    340   //
    341   ZeroMem (Digest, SHA256_DIGEST_SIZE);
    342   HashContext = Global->HashContext[VirtualMode];
    343   Status  = Sha256Init (HashContext);
    344   if (!Status) {
    345     goto Done;
    346   }
    347   Status  = Sha256Update (HashContext, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));
    348   if (!Status) {
    349     goto Done;
    350   }
    351   //
    352   // Hash Monotonic Count.
    353   //
    354   Status  = Sha256Update (HashContext, &CertData->MonotonicCount, sizeof (UINT64));
    355   if (!Status) {
    356     goto Done;
    357   }
    358   Status  = Sha256Final (HashContext, Digest);
    359   if (!Status) {
    360     goto Done;
    361   }
    362   //
    363   // Generate & Initialize RSA Context.
    364   //
    365   Rsa = RsaNew ();
    366   ASSERT (Rsa != NULL);
    367   //
    368   // Set RSA Key Components.
    369   // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
    370   //
    371   Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
    372   if (!Status) {
    373     goto Done;
    374   }
    375   Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
    376   if (!Status) {
    377     goto Done;
    378   }
    379   //
    380   // Verify the signature.
    381   //
    382   Status = RsaPkcs1Verify (
    383              Rsa,
    384              Digest,
    385              SHA256_DIGEST_SIZE,
    386              CertBlock->Signature,
    387              EFI_CERT_TYPE_RSA2048_SHA256_SIZE
    388              );
    389 
    390 Done:
    391   if (Rsa != NULL) {
    392     RsaFree (Rsa);
    393   }
    394   if (Status) {
    395     return EFI_SUCCESS;
    396   } else {
    397     return EFI_SECURITY_VIOLATION;
    398   }
    399 }
    400 
    401 
    402 /**
    403   Update platform mode.
    404 
    405   @param[in]  VirtualMode             The current calling mode for this function.
    406   @param[in]  Global                  The context of this Extended SAL Variable Services Class call.
    407   @param[in]  Mode                    SETUP_MODE or USER_MODE.
    408 
    409 **/
    410 VOID
    411 UpdatePlatformMode (
    412   IN  BOOLEAN                   VirtualMode,
    413   IN  ESAL_VARIABLE_GLOBAL      *Global,
    414   IN  UINT32                    Mode
    415   )
    416 {
    417   EFI_STATUS              Status;
    418   VARIABLE_POINTER_TRACK  Variable;
    419   UINT32                  VarAttr;
    420 
    421   Status = FindVariable (
    422              Global->VariableName[VirtualMode][VAR_SETUP_MODE],
    423              Global->GlobalVariableGuid[VirtualMode],
    424              &Variable,
    425              &Global->VariableGlobal[VirtualMode],
    426              Global->FvbInstance
    427              );
    428   ASSERT_EFI_ERROR (Status);
    429 
    430   mPlatformMode  = Mode;
    431   VarAttr        = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
    432   Status         = UpdateVariable (
    433                      Global->VariableName[VirtualMode][VAR_SETUP_MODE],
    434                      Global->GlobalVariableGuid[VirtualMode],
    435                      &mPlatformMode,
    436                      sizeof(UINT8),
    437                      VarAttr,
    438                      0,
    439                      0,
    440                      VirtualMode,
    441                      Global,
    442                      &Variable
    443                      );
    444   ASSERT_EFI_ERROR (Status);
    445 }
    446 
    447 /**
    448   Process variable with platform key for verification.
    449 
    450   @param[in]  VariableName                The name of Variable to be found.
    451   @param[in]  VendorGuid                  The variable vendor GUID.
    452   @param[in]  Data                        The data pointer.
    453   @param[in]  DataSize                    The size of Data found. If size is less than the
    454                                           data, this value contains the required size.
    455   @param[in]  VirtualMode                 The current calling mode for this function.
    456   @param[in]  Global                      The context of this Extended SAL Variable Services Class call.
    457   @param[in]  Variable                    The variable information which is used to keep track of variable usage.
    458   @param[in]  Attributes                  The attribute value of the variable.
    459   @param[in]  IsPk                        Indicates whether to process pk.
    460 
    461   @retval EFI_INVALID_PARAMETER           Invalid parameter.
    462   @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation
    463                                           check carried out by the firmware.
    464   @retval EFI_SUCCESS                     The variable passed validation successfully.
    465 
    466 **/
    467 EFI_STATUS
    468 ProcessVarWithPk (
    469   IN  CHAR16                    *VariableName,
    470   IN  EFI_GUID                  *VendorGuid,
    471   IN  VOID                      *Data,
    472   IN  UINTN                     DataSize,
    473   IN  BOOLEAN                   VirtualMode,
    474   IN  ESAL_VARIABLE_GLOBAL      *Global,
    475   IN  VARIABLE_POINTER_TRACK    *Variable,
    476   IN  UINT32                    Attributes OPTIONAL,
    477   IN  BOOLEAN                   IsPk
    478   )
    479 {
    480   EFI_STATUS                    Status;
    481   VARIABLE_POINTER_TRACK        PkVariable;
    482   EFI_SIGNATURE_LIST            *OldPkList;
    483   EFI_SIGNATURE_DATA            *OldPkData;
    484   EFI_VARIABLE_AUTHENTICATION   *CertData;
    485   AUTHENTICATED_VARIABLE_HEADER VariableHeader;
    486   BOOLEAN                       Valid;
    487 
    488   OldPkList = NULL;
    489   ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
    490 
    491   if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
    492     //
    493     // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
    494     //
    495     return EFI_INVALID_PARAMETER;
    496   }
    497 
    498   if (mPlatformMode == USER_MODE) {
    499     if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
    500       //
    501       // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
    502       //
    503       return EFI_INVALID_PARAMETER;
    504     }
    505 
    506     CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
    507 
    508     if (Variable->CurrPtr != 0x0) {
    509       Valid = IsValidVariableHeader (
    510                 Variable->CurrPtr,
    511                 Variable->Volatile,
    512                 &Global->VariableGlobal[VirtualMode],
    513                 Global->FvbInstance,
    514                 &VariableHeader
    515                 );
    516       ASSERT (Valid);
    517 
    518       if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
    519         //
    520         // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
    521         //
    522         return EFI_SECURITY_VIOLATION;
    523       }
    524     }
    525     //
    526     // Get platform key from variable.
    527     //
    528     Status = FindVariable (
    529                Global->VariableName[VirtualMode][VAR_PLATFORM_KEY],
    530                Global->GlobalVariableGuid[VirtualMode],
    531                &PkVariable,
    532                &Global->VariableGlobal[VirtualMode],
    533                Global->FvbInstance
    534                );
    535     ASSERT_EFI_ERROR (Status);
    536 
    537     ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
    538     GetVariableDataPtr (
    539       PkVariable.CurrPtr,
    540       PkVariable.Volatile,
    541       &Global->VariableGlobal[VirtualMode],
    542       Global->FvbInstance,
    543       (CHAR16 *) Global->KeyList
    544       );
    545 
    546     OldPkList = (EFI_SIGNATURE_LIST *) Global->KeyList;
    547     OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);
    548     Status    = VerifyDataPayload (VirtualMode, Global, Data, DataSize, OldPkData->SignatureData);
    549     if (!EFI_ERROR (Status)) {
    550       Status = UpdateVariable (
    551                  VariableName,
    552                  VendorGuid,
    553                  (UINT8*)Data + AUTHINFO_SIZE,
    554                  DataSize - AUTHINFO_SIZE,
    555                  Attributes,
    556                  0,
    557                  CertData->MonotonicCount,
    558                  VirtualMode,
    559                  Global,
    560                  Variable
    561                  );
    562 
    563       if (!EFI_ERROR (Status)) {
    564         //
    565         // If delete PK in user mode, need change to setup mode.
    566         //
    567         if ((DataSize == AUTHINFO_SIZE) && IsPk) {
    568           UpdatePlatformMode (VirtualMode, Global, SETUP_MODE);
    569         }
    570       }
    571     }
    572   } else {
    573     Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable);
    574     //
    575     // If enroll PK in setup mode, need change to user mode.
    576     //
    577     if ((DataSize != 0) && IsPk) {
    578       UpdatePlatformMode (VirtualMode, Global, USER_MODE);
    579     }
    580   }
    581 
    582   return Status;
    583 }
    584 
    585 /**
    586   Process variable with key exchange key for verification.
    587 
    588   @param[in]  VariableName                The name of Variable to be found.
    589   @param[in]  VendorGuid                  The variable vendor GUID.
    590   @param[in]  Data                        The data pointer.
    591   @param[in]  DataSize                    The size of Data found. If size is less than the
    592                                           data, this value contains the required size.
    593   @param[in]  VirtualMode                 The current calling mode for this function.
    594   @param[in]  Global                      The context of this Extended SAL Variable Services Class call.
    595   @param[in]  Variable                    The variable information which is used to keep track of variable usage.
    596   @param[in]  Attributes                  The attribute value of the variable.
    597 
    598   @retval EFI_INVALID_PARAMETER           Invalid parameter.
    599   @retval EFI_SECURITY_VIOLATION          The variable did NOT pass the validation
    600                                           check carried out by the firmware.
    601   @retval EFI_SUCCESS                     The variable passed validation successfully.
    602 
    603 **/
    604 EFI_STATUS
    605 ProcessVarWithKek (
    606   IN  CHAR16                               *VariableName,
    607   IN  EFI_GUID                             *VendorGuid,
    608   IN  VOID                                 *Data,
    609   IN  UINTN                                DataSize,
    610   IN  BOOLEAN                              VirtualMode,
    611   IN  ESAL_VARIABLE_GLOBAL                 *Global,
    612   IN  VARIABLE_POINTER_TRACK               *Variable,
    613   IN  UINT32                               Attributes OPTIONAL
    614   )
    615 {
    616   EFI_STATUS                      Status;
    617   VARIABLE_POINTER_TRACK          KekVariable;
    618   EFI_SIGNATURE_LIST              *KekList;
    619   EFI_SIGNATURE_DATA              *KekItem;
    620   UINT32                          KekCount;
    621   EFI_VARIABLE_AUTHENTICATION     *CertData;
    622   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
    623   BOOLEAN                         IsFound;
    624   UINT32                          Index;
    625   AUTHENTICATED_VARIABLE_HEADER   VariableHeader;
    626   BOOLEAN                         Valid;
    627 
    628   KekList = NULL;
    629   ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
    630 
    631   if (mPlatformMode == USER_MODE) {
    632     if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
    633       //
    634       // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
    635       //
    636       return EFI_INVALID_PARAMETER;
    637     }
    638 
    639     CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
    640     CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
    641     if (Variable->CurrPtr != 0x0) {
    642       Valid = IsValidVariableHeader (
    643                 Variable->CurrPtr,
    644                 Variable->Volatile,
    645                 &Global->VariableGlobal[VirtualMode],
    646                 Global->FvbInstance,
    647                 &VariableHeader
    648                 );
    649       ASSERT (Valid);
    650 
    651       if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
    652         //
    653         // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
    654         //
    655         return EFI_SECURITY_VIOLATION;
    656       }
    657     }
    658     //
    659     // Get KEK database from variable.
    660     //
    661     Status = FindVariable (
    662                Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY],
    663                Global->GlobalVariableGuid[VirtualMode],
    664                &KekVariable,
    665                &Global->VariableGlobal[VirtualMode],
    666                Global->FvbInstance
    667                );
    668     ASSERT_EFI_ERROR (Status);
    669 
    670     ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
    671     GetVariableDataPtr (
    672       KekVariable.CurrPtr,
    673       KekVariable.Volatile,
    674       &Global->VariableGlobal[VirtualMode],
    675       Global->FvbInstance,
    676       (CHAR16 *) Global->KeyList
    677       );
    678     //
    679     // Enumerate all Kek items in this list to verify the variable certificate data.
    680     // If anyone is authenticated successfully, it means the variable is correct!
    681     //
    682     KekList   = (EFI_SIGNATURE_LIST *) Global->KeyList;
    683     IsFound   = FALSE;
    684     KekCount  = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;
    685     KekItem   = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);
    686     for (Index = 0; Index < KekCount; Index++) {
    687       if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
    688         IsFound = TRUE;
    689         break;
    690       }
    691       KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
    692     }
    693 
    694     if (!IsFound) {
    695       return EFI_SECURITY_VIOLATION;
    696     }
    697 
    698     Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, CertBlock->PublicKey);
    699     if (!EFI_ERROR (Status)) {
    700       Status = UpdateVariable (
    701                  VariableName,
    702                  VendorGuid,
    703                  (UINT8*)Data + AUTHINFO_SIZE,
    704                  DataSize - AUTHINFO_SIZE,
    705                  Attributes,
    706                  0,
    707                  CertData->MonotonicCount,
    708                  VirtualMode,
    709                  Global,
    710                  Variable
    711                  );
    712     }
    713   } else {
    714     //
    715     // If in setup mode, no authentication needed.
    716     //
    717     Status = UpdateVariable (
    718                VariableName,
    719                VendorGuid,
    720                Data,
    721                DataSize,
    722                Attributes,
    723                0,
    724                0,
    725                VirtualMode,
    726                Global,
    727                Variable
    728                );
    729   }
    730 
    731   return Status;
    732 }
    733 
    734 /**
    735   Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.
    736 
    737   @param[in]  Data                        The data pointer.
    738   @param[in]  DataSize                    The size of Data found. If size is less than the
    739                                           data, this value contains the required size.
    740   @param[in]  VirtualMode                 The current calling mode for this function.
    741   @param[in]  Global                      The context of this Extended SAL Variable Services Class call.
    742   @param[in]  Variable                    The variable information which is used to keep track of variable usage.
    743   @param[in]  Attributes                  The attribute value of the variable.
    744   @param[out] KeyIndex                    The output index of corresponding public key in database.
    745   @param[out] MonotonicCount              The output value of corresponding Monotonic Count.
    746 
    747   @retval EFI_INVALID_PARAMETER           Invalid parameter.
    748   @retval EFI_WRITE_PROTECTED             The variable is write-protected and needs authentication with
    749                                           EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
    750   @retval EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
    751                                           set, but the AuthInfo does NOT pass the validation
    752                                           check carried out by the firmware.
    753   @retval EFI_SUCCESS                     The variable is not write-protected, or passed validation successfully.
    754 
    755 **/
    756 EFI_STATUS
    757 VerifyVariable (
    758   IN  VOID                      *Data,
    759   IN  UINTN                     DataSize,
    760   IN  BOOLEAN                   VirtualMode,
    761   IN  ESAL_VARIABLE_GLOBAL      *Global,
    762   IN  VARIABLE_POINTER_TRACK    *Variable,
    763   IN  UINT32                    Attributes OPTIONAL,
    764   OUT UINT32                    *KeyIndex OPTIONAL,
    765   OUT UINT64                    *MonotonicCount OPTIONAL
    766   )
    767 {
    768   EFI_STATUS                      Status;
    769   BOOLEAN                         IsDeletion;
    770   BOOLEAN                         IsFirstTime;
    771   UINT8                           *PubKey;
    772   EFI_VARIABLE_AUTHENTICATION     *CertData;
    773   EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;
    774   AUTHENTICATED_VARIABLE_HEADER   VariableHeader;
    775   BOOLEAN                         Valid;
    776 
    777   CertData    = NULL;
    778   CertBlock   = NULL;
    779   PubKey      = NULL;
    780   IsDeletion  = FALSE;
    781   Valid       = FALSE;
    782 
    783   if (KeyIndex != NULL) {
    784     *KeyIndex = 0;
    785   }
    786   //
    787   // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
    788   //
    789   ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
    790   if (Variable->CurrPtr != 0x0) {
    791     Valid = IsValidVariableHeader (
    792               Variable->CurrPtr,
    793               Variable->Volatile,
    794               &Global->VariableGlobal[VirtualMode],
    795               Global->FvbInstance,
    796               &VariableHeader
    797               );
    798     ASSERT (Valid);
    799   }
    800 
    801   if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
    802     if (KeyIndex == NULL) {
    803       return EFI_INVALID_PARAMETER;
    804     }
    805 
    806     //
    807     // Determine current operation type.
    808     //
    809     if (DataSize == AUTHINFO_SIZE) {
    810       IsDeletion = TRUE;
    811     }
    812     //
    813     // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
    814     //
    815     if (Variable->CurrPtr == 0x0) {
    816       IsFirstTime = TRUE;
    817     } else if (Valid &&(VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
    818       IsFirstTime = TRUE;
    819     } else {
    820       *KeyIndex   = VariableHeader.PubKeyIndex;
    821       IsFirstTime = FALSE;
    822     }
    823   } else if (Valid && (VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
    824       //
    825       // If the variable is already write-protected, it always needs authentication before update.
    826       //
    827       return EFI_WRITE_PROTECTED;
    828   } else {
    829     //
    830     // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
    831     // That means it is not authenticated variable, just return EFI_SUCCESS.
    832     //
    833     return EFI_SUCCESS;
    834   }
    835 
    836   //
    837   // Get PubKey and check Monotonic Count value corresponding to the variable.
    838   //
    839   CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;
    840   CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
    841   PubKey    = CertBlock->PublicKey;
    842 
    843   if (MonotonicCount != NULL) {
    844     //
    845     // Update Monotonic Count value.
    846     //
    847     *MonotonicCount = CertData->MonotonicCount;
    848   }
    849 
    850   if (!IsFirstTime) {
    851     //
    852     // Check input PubKey.
    853     //
    854     if (CompareMem (PubKey, Global->PubKeyStore + (*KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
    855       return EFI_SECURITY_VIOLATION;
    856     }
    857     //
    858     // Compare the current monotonic count and ensure that it is greater than the last SetVariable
    859     // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
    860     //
    861     if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
    862       //
    863       // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
    864       //
    865       return EFI_SECURITY_VIOLATION;
    866     }
    867   }
    868   //
    869   // Verify the certificate in Data payload.
    870   //
    871   Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, PubKey);
    872   if (!EFI_ERROR (Status)) {
    873     //
    874     // Now, the signature has been verified!
    875     //
    876     if (IsFirstTime && !IsDeletion) {
    877       //
    878       // Update public key database variable if need and return the index.
    879       //
    880       *KeyIndex = AddPubKeyInStore (VirtualMode, Global, PubKey);
    881     }
    882   }
    883 
    884   return Status;
    885 }
    886 
    887