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 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
     15 This program and the accompanying materials
     16 are licensed and made available under the terms and conditions of the BSD License
     17 which accompanies this distribution.  The full text of the license may be found at
     18 http://opensource.org/licenses/bsd-license.php
     19 
     20 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     21 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     22 
     23 **/
     24 
     25 #include "AuthServiceInternal.h"
     26 
     27 ///
     28 /// Global database array for scratch
     29 ///
     30 UINT8    *mPubKeyStore;
     31 UINT32   mPubKeyNumber;
     32 UINT32   mMaxKeyNumber;
     33 UINT32   mMaxKeyDbSize;
     34 UINT8    *mCertDbStore;
     35 UINT32   mMaxCertDbSize;
     36 UINT8    mVendorKeyState;
     37 
     38 EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};
     39 
     40 //
     41 // Hash context pointer
     42 //
     43 VOID  *mHashCtx = NULL;
     44 
     45 VARIABLE_ENTRY_PROPERTY mAuthVarEntry[] = {
     46   {
     47     &gEfiSecureBootEnableDisableGuid,
     48     EFI_SECURE_BOOT_ENABLE_NAME,
     49     {
     50       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
     51       0,
     52       VARIABLE_ATTRIBUTE_NV_BS,
     53       sizeof (UINT8),
     54       sizeof (UINT8)
     55     }
     56   },
     57   {
     58     &gEfiCustomModeEnableGuid,
     59     EFI_CUSTOM_MODE_NAME,
     60     {
     61       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
     62       0,
     63       VARIABLE_ATTRIBUTE_NV_BS,
     64       sizeof (UINT8),
     65       sizeof (UINT8)
     66     }
     67   },
     68   {
     69     &gEfiVendorKeysNvGuid,
     70     EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
     71     {
     72       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
     73       VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
     74       VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
     75       sizeof (UINT8),
     76       sizeof (UINT8)
     77     }
     78   },
     79   {
     80     &gEfiAuthenticatedVariableGuid,
     81     AUTHVAR_KEYDB_NAME,
     82     {
     83       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
     84       VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
     85       VARIABLE_ATTRIBUTE_NV_BS_RT_AW,
     86       sizeof (UINT8),
     87       MAX_UINTN
     88     }
     89   },
     90   {
     91     &gEfiCertDbGuid,
     92     EFI_CERT_DB_NAME,
     93     {
     94       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
     95       VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
     96       VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
     97       sizeof (UINT32),
     98       MAX_UINTN
     99     }
    100   },
    101   {
    102     &gEdkiiSecureBootModeGuid,
    103     L"SecureBootMode",
    104     {
    105       VAR_CHECK_VARIABLE_PROPERTY_REVISION,
    106       VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
    107       VARIABLE_ATTRIBUTE_NV_BS_RT,
    108       sizeof (UINT8),
    109       sizeof (UINT8)
    110     }
    111   }
    112 };
    113 
    114 VOID **mAuthVarAddressPointer[10];
    115 
    116 AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn = NULL;
    117 
    118 /**
    119   Initialization for authenticated varibale services.
    120   If this initialization returns error status, other APIs will not work
    121   and expect to be not called then.
    122 
    123   @param[in]  AuthVarLibContextIn   Pointer to input auth variable lib context.
    124   @param[out] AuthVarLibContextOut  Pointer to output auth variable lib context.
    125 
    126   @retval EFI_SUCCESS               Function successfully executed.
    127   @retval EFI_INVALID_PARAMETER     If AuthVarLibContextIn == NULL or AuthVarLibContextOut == NULL.
    128   @retval EFI_OUT_OF_RESOURCES      Fail to allocate enough resource.
    129   @retval EFI_UNSUPPORTED           Unsupported to process authenticated variable.
    130 
    131 **/
    132 EFI_STATUS
    133 EFIAPI
    134 AuthVariableLibInitialize (
    135   IN  AUTH_VAR_LIB_CONTEXT_IN   *AuthVarLibContextIn,
    136   OUT AUTH_VAR_LIB_CONTEXT_OUT  *AuthVarLibContextOut
    137   )
    138 {
    139   EFI_STATUS            Status;
    140   UINT8                 VarValue;
    141   UINT32                VarAttr;
    142   UINT8                 *Data;
    143   UINTN                 DataSize;
    144   UINTN                 CtxSize;
    145   UINT8                 CustomMode;
    146   UINT32                ListSize;
    147 
    148   if ((AuthVarLibContextIn == NULL) || (AuthVarLibContextOut == NULL)) {
    149     return EFI_INVALID_PARAMETER;
    150   }
    151 
    152   mAuthVarLibContextIn = AuthVarLibContextIn;
    153 
    154   //
    155   // Initialize hash context.
    156   //
    157   CtxSize   = Sha256GetContextSize ();
    158   mHashCtx  = AllocateRuntimePool (CtxSize);
    159   if (mHashCtx == NULL) {
    160     return EFI_OUT_OF_RESOURCES;
    161   }
    162 
    163   //
    164   // Reserve runtime buffer for public key database. The size excludes variable header and name size.
    165   //
    166   mMaxKeyDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (AUTHVAR_KEYDB_NAME));
    167   mMaxKeyNumber = mMaxKeyDbSize / sizeof (AUTHVAR_KEY_DB_DATA);
    168   mPubKeyStore  = AllocateRuntimePool (mMaxKeyDbSize);
    169   if (mPubKeyStore == NULL) {
    170     return EFI_OUT_OF_RESOURCES;
    171   }
    172 
    173   //
    174   // Reserve runtime buffer for certificate database. The size excludes variable header and name size.
    175   //
    176   mMaxCertDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (EFI_CERT_DB_NAME));
    177   mCertDbStore   = AllocateRuntimePool (mMaxCertDbSize);
    178   if (mCertDbStore == NULL) {
    179     return EFI_OUT_OF_RESOURCES;
    180   }
    181 
    182   //
    183   // Check "AuthVarKeyDatabase" variable's existence.
    184   // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
    185   //
    186   Status = AuthServiceInternalFindVariable (
    187              AUTHVAR_KEYDB_NAME,
    188              &gEfiAuthenticatedVariableGuid,
    189              (VOID **) &Data,
    190              &DataSize
    191              );
    192   if (EFI_ERROR (Status)) {
    193     VarAttr       = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
    194     VarValue      = 0;
    195     mPubKeyNumber = 0;
    196     Status        = AuthServiceInternalUpdateVariable (
    197                       AUTHVAR_KEYDB_NAME,
    198                       &gEfiAuthenticatedVariableGuid,
    199                       &VarValue,
    200                       sizeof(UINT8),
    201                       VarAttr
    202                       );
    203     if (EFI_ERROR (Status)) {
    204       return Status;
    205     }
    206   } else {
    207     //
    208     // Load database in global variable for cache.
    209     //
    210     ASSERT ((DataSize != 0) && (Data != NULL));
    211     //
    212     // "AuthVarKeyDatabase" is an internal variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before)
    213     //  Therefore, there is no memory overflow in underlying CopyMem.
    214     //
    215     CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
    216     mPubKeyNumber = (UINT32) (DataSize / sizeof (AUTHVAR_KEY_DB_DATA));
    217   }
    218 
    219   //
    220   // Init Secure Boot variables
    221   //
    222   Status = InitSecureBootVariables ();
    223 
    224 
    225   //
    226   // Create "SignatureSupport" variable with BS+RT attribute set.
    227   //
    228   Status  = AuthServiceInternalUpdateVariable (
    229               EFI_SIGNATURE_SUPPORT_NAME,
    230               &gEfiGlobalVariableGuid,
    231               mSignatureSupport,
    232               sizeof(mSignatureSupport),
    233               EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
    234               );
    235   if (EFI_ERROR (Status)) {
    236     return Status;
    237   }
    238 
    239   //
    240   // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state.
    241   //
    242   CustomMode = STANDARD_SECURE_BOOT_MODE;
    243   Status = AuthServiceInternalUpdateVariable (
    244              EFI_CUSTOM_MODE_NAME,
    245              &gEfiCustomModeEnableGuid,
    246              &CustomMode,
    247              sizeof (UINT8),
    248              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
    249              );
    250   if (EFI_ERROR (Status)) {
    251     return Status;
    252   }
    253 
    254   DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));
    255 
    256   //
    257   // Check "certdb" variable's existence.
    258   // If it doesn't exist, then create a new one with
    259   // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
    260   //
    261   Status = AuthServiceInternalFindVariable (
    262              EFI_CERT_DB_NAME,
    263              &gEfiCertDbGuid,
    264              (VOID **) &Data,
    265              &DataSize
    266              );
    267   if (EFI_ERROR (Status)) {
    268     VarAttr  = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
    269     ListSize = sizeof (UINT32);
    270     Status   = AuthServiceInternalUpdateVariable (
    271                  EFI_CERT_DB_NAME,
    272                  &gEfiCertDbGuid,
    273                  &ListSize,
    274                  sizeof (UINT32),
    275                  VarAttr
    276                  );
    277     if (EFI_ERROR (Status)) {
    278       return Status;
    279     }
    280   } else {
    281     //
    282     // Clean up Certs to make certDB & Time based auth variable consistent
    283     //
    284     Status = CleanCertsFromDb();
    285     if (EFI_ERROR (Status)) {
    286       DEBUG ((EFI_D_ERROR, "Clean up CertDB fail! Status %x\n", Status));
    287       return Status;
    288     }
    289   }
    290 
    291   //
    292   // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly.
    293   //
    294   Status = AuthServiceInternalFindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, (VOID **) &Data, &DataSize);
    295   if (!EFI_ERROR (Status)) {
    296     mVendorKeyState = *(UINT8 *)Data;
    297   } else {
    298     //
    299     // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state.
    300     //
    301     mVendorKeyState = VENDOR_KEYS_VALID;
    302     Status = AuthServiceInternalUpdateVariable (
    303                EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
    304                &gEfiVendorKeysNvGuid,
    305                &mVendorKeyState,
    306                sizeof (UINT8),
    307                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
    308                );
    309     if (EFI_ERROR (Status)) {
    310       return Status;
    311     }
    312   }
    313 
    314   //
    315   // Create "VendorKeys" variable with BS+RT attribute set.
    316   //
    317   Status = AuthServiceInternalUpdateVariable (
    318              EFI_VENDOR_KEYS_VARIABLE_NAME,
    319              &gEfiGlobalVariableGuid,
    320              &mVendorKeyState,
    321              sizeof (UINT8),
    322              EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
    323              );
    324   if (EFI_ERROR (Status)) {
    325     return Status;
    326   }
    327 
    328   DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_VENDOR_KEYS_VARIABLE_NAME, mVendorKeyState));
    329 
    330   AuthVarLibContextOut->StructVersion = AUTH_VAR_LIB_CONTEXT_OUT_STRUCT_VERSION;
    331   AuthVarLibContextOut->StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_OUT);
    332   AuthVarLibContextOut->AuthVarEntry = mAuthVarEntry;
    333   AuthVarLibContextOut->AuthVarEntryCount = sizeof (mAuthVarEntry) / sizeof (mAuthVarEntry[0]);
    334   mAuthVarAddressPointer[0] = (VOID **) &mPubKeyStore;
    335   mAuthVarAddressPointer[1] = (VOID **) &mCertDbStore;
    336   mAuthVarAddressPointer[2] = (VOID **) &mHashCtx;
    337   mAuthVarAddressPointer[3] = (VOID **) &mAuthVarLibContextIn;
    338   mAuthVarAddressPointer[4] = (VOID **) &(mAuthVarLibContextIn->FindVariable),
    339   mAuthVarAddressPointer[5] = (VOID **) &(mAuthVarLibContextIn->FindNextVariable),
    340   mAuthVarAddressPointer[6] = (VOID **) &(mAuthVarLibContextIn->UpdateVariable),
    341   mAuthVarAddressPointer[7] = (VOID **) &(mAuthVarLibContextIn->GetScratchBuffer),
    342   mAuthVarAddressPointer[8] = (VOID **) &(mAuthVarLibContextIn->CheckRemainingSpaceForConsistency),
    343   mAuthVarAddressPointer[9] = (VOID **) &(mAuthVarLibContextIn->AtRuntime),
    344   AuthVarLibContextOut->AddressPointer = mAuthVarAddressPointer;
    345   AuthVarLibContextOut->AddressPointerCount = sizeof (mAuthVarAddressPointer) / sizeof (mAuthVarAddressPointer[0]);
    346 
    347   return Status;
    348 }
    349 
    350 /**
    351   Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
    352 
    353   @param[in] VariableName           Name of the variable.
    354   @param[in] VendorGuid             Variable vendor GUID.
    355   @param[in] Data                   Data pointer.
    356   @param[in] DataSize               Size of Data.
    357   @param[in] Attributes             Attribute value of the variable.
    358 
    359   @retval EFI_SUCCESS               The firmware has successfully stored the variable and its data as
    360                                     defined by the Attributes.
    361   @retval EFI_INVALID_PARAMETER     Invalid parameter.
    362   @retval EFI_WRITE_PROTECTED       Variable is write-protected.
    363   @retval EFI_OUT_OF_RESOURCES      There is not enough resource.
    364   @retval EFI_SECURITY_VIOLATION    The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
    365                                     or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS
    366                                     set, but the AuthInfo does NOT pass the validation
    367                                     check carried out by the firmware.
    368   @retval EFI_UNSUPPORTED           Unsupported to process authenticated variable.
    369 
    370 **/
    371 EFI_STATUS
    372 EFIAPI
    373 AuthVariableLibProcessVariable (
    374   IN CHAR16         *VariableName,
    375   IN EFI_GUID       *VendorGuid,
    376   IN VOID           *Data,
    377   IN UINTN          DataSize,
    378   IN UINT32         Attributes
    379   )
    380 {
    381   EFI_STATUS        Status;
    382 
    383   //
    384   // Process PK, KEK, Sigdb, AuditMode, DeployedMode separately.
    385   //
    386   if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
    387     Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, TRUE);
    388   } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {
    389     Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);
    390   } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)
    391           && (StrCmp (VariableName, EFI_AUDIT_MODE_NAME) == 0 || StrCmp (VariableName, EFI_DEPLOYED_MODE_NAME) == 0)) {
    392     Status = ProcessSecureBootModeVar(VariableName, VendorGuid, Data, DataSize, Attributes);
    393   } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
    394              ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE)  == 0) ||
    395               (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
    396               (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)
    397              )) {
    398     Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);
    399     if (EFI_ERROR (Status)) {
    400       Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, Attributes);
    401     }
    402   } else {
    403     Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
    404   }
    405 
    406   return Status;
    407 }
    408