+++ /dev/null
-/** @file\r
- Implement authentication services for the authenticated variable\r
- service in UEFI2.2.\r
-\r
-Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include "Variable.h"\r
-#include "AuthService.h"\r
-\r
-///\r
-/// Global database array for scratch\r
-///\r
-UINT32 mPubKeyNumber;\r
-UINT32 mPlatformMode;\r
-EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};\r
-//\r
-// Public Exponent of RSA Key.\r
-//\r
-CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
-\r
-/**\r
- Initializes for authenticated varibale service.\r
-\r
- @retval EFI_SUCCESS The function successfully executed.\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resources.\r
-\r
-**/\r
-EFI_STATUS\r
-AutenticatedVariableServiceInitialize (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- VARIABLE_POINTER_TRACK Variable;\r
- UINT8 VarValue;\r
- UINT32 VarAttr;\r
- UINTN DataSize;\r
- UINTN CtxSize;\r
- AUTHENTICATED_VARIABLE_HEADER VariableHeader;\r
- BOOLEAN Valid;\r
-\r
- ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));\r
-\r
- mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid;\r
- mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical] = &gEfiCertRsa2048Sha256Guid;\r
- mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid;\r
-\r
- //\r
- // Initialize hash context.\r
- //\r
- CtxSize = Sha256GetContextSize ();\r
- mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize);\r
- ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL);\r
- //\r
- // Check "AuthVarKeyDatabase" variable's existence.\r
- // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
- //\r
- Status = FindVariable (\r
- mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],\r
- &gEfiAuthenticatedVariableGuid,\r
- &Variable,\r
- &mVariableModuleGlobal->VariableGlobal[Physical],\r
- mVariableModuleGlobal->FvbInstance\r
- );\r
-\r
- if (Variable.CurrPtr == 0x0) {\r
- VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
- VarValue = 0;\r
- mPubKeyNumber = 0;\r
- Status = UpdateVariable (\r
- mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],\r
- &gEfiAuthenticatedVariableGuid,\r
- &VarValue,\r
- sizeof(UINT8),\r
- VarAttr,\r
- 0,\r
- 0,\r
- FALSE,\r
- mVariableModuleGlobal,\r
- &Variable\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- } else {\r
- //\r
- // Load database in global variable for cache.\r
- //\r
- Valid = IsValidVariableHeader (\r
- Variable.CurrPtr,\r
- Variable.Volatile,\r
- &mVariableModuleGlobal->VariableGlobal[Physical],\r
- mVariableModuleGlobal->FvbInstance,\r
- &VariableHeader\r
- );\r
- ASSERT (Valid);\r
-\r
- DataSize = DataSizeOfVariable (&VariableHeader);\r
- ASSERT (DataSize <= MAX_KEYDB_SIZE);\r
- GetVariableDataPtr (\r
- Variable.CurrPtr,\r
- Variable.Volatile,\r
- &mVariableModuleGlobal->VariableGlobal[Physical],\r
- mVariableModuleGlobal->FvbInstance,\r
- (CHAR16 *) mVariableModuleGlobal->PubKeyStore\r
- );\r
-\r
- mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
- }\r
- //\r
- // Check "SetupMode" variable's existence.\r
- // If it doesn't exist, check PK database's existence to determine the value.\r
- // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
- //\r
- Status = FindVariable (\r
- mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],\r
- &gEfiGlobalVariableGuid,\r
- &Variable,\r
- &mVariableModuleGlobal->VariableGlobal[Physical],\r
- mVariableModuleGlobal->FvbInstance\r
- );\r
-\r
- if (Variable.CurrPtr == 0x0) {\r
- Status = FindVariable (\r
- mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY],\r
- &gEfiGlobalVariableGuid,\r
- &Variable,\r
- &mVariableModuleGlobal->VariableGlobal[Physical],\r
- mVariableModuleGlobal->FvbInstance\r
- );\r
- if (Variable.CurrPtr == 0x0) {\r
- mPlatformMode = SETUP_MODE;\r
- } else {\r
- mPlatformMode = USER_MODE;\r
- }\r
-\r
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
- Status = UpdateVariable (\r
- mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],\r
- &gEfiGlobalVariableGuid,\r
- &mPlatformMode,\r
- sizeof(UINT8),\r
- VarAttr,\r
- 0,\r
- 0,\r
- FALSE,\r
- mVariableModuleGlobal,\r
- &Variable\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- } else {\r
- GetVariableDataPtr (\r
- Variable.CurrPtr,\r
- Variable.Volatile,\r
- &mVariableModuleGlobal->VariableGlobal[Physical],\r
- mVariableModuleGlobal->FvbInstance,\r
- (CHAR16 *) &mPlatformMode\r
- );\r
- }\r
- //\r
- // Check "SignatureSupport" variable's existence.\r
- // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
- //\r
- Status = FindVariable (\r
- EFI_SIGNATURE_SUPPORT_NAME,\r
- &gEfiGlobalVariableGuid,\r
- &Variable,\r
- &mVariableModuleGlobal->VariableGlobal[Physical],\r
- mVariableModuleGlobal->FvbInstance\r
- );\r
-\r
- if (Variable.CurrPtr == 0x0) {\r
- VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
- Status = UpdateVariable (\r
- EFI_SIGNATURE_SUPPORT_NAME,\r
- &gEfiGlobalVariableGuid,\r
- mSignatureSupport,\r
- SIGSUPPORT_NUM * sizeof(EFI_GUID),\r
- VarAttr,\r
- 0,\r
- 0,\r
- FALSE,\r
- mVariableModuleGlobal,\r
- &Variable\r
- );\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Add public key in store and return its index.\r
-\r
- @param[in] VirtualMode The current calling mode for this function.\r
- @param[in] Global The context of this Extended SAL Variable Services Class call.\r
- @param[in] PubKey The input pointer to Public Key data.\r
-\r
- @return The index of new added item.\r
-\r
-**/\r
-UINT32\r
-AddPubKeyInStore (\r
- IN BOOLEAN VirtualMode,\r
- IN ESAL_VARIABLE_GLOBAL *Global,\r
- IN UINT8 *PubKey\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BOOLEAN IsFound;\r
- UINT32 Index;\r
- VARIABLE_POINTER_TRACK Variable;\r
- UINT8 *Ptr;\r
-\r
- if (PubKey == NULL) {\r
- return 0;\r
- }\r
-\r
- Status = FindVariable (\r
- Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],\r
- Global->AuthenticatedVariableGuid[VirtualMode],\r
- &Variable,\r
- &Global->VariableGlobal[VirtualMode],\r
- Global->FvbInstance\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- //\r
- // Check whether the public key entry does exist.\r
- //\r
- IsFound = FALSE;\r
- for (Ptr = Global->PubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {\r
- if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
- IsFound = TRUE;\r
- break;\r
- }\r
- Ptr += EFI_CERT_TYPE_RSA2048_SIZE;\r
- }\r
-\r
- if (!IsFound) {\r
- //\r
- // Add public key in database.\r
- //\r
- if (mPubKeyNumber == MAX_KEY_NUM) {\r
- //\r
- // Notes: Database is full, need enhancement here, currently just return 0.\r
- //\r
- return 0;\r
- }\r
-\r
- CopyMem (Global->PubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
- Index = ++mPubKeyNumber;\r
- //\r
- // Update public key database variable.\r
- //\r
- Status = UpdateVariable (\r
- Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],\r
- Global->AuthenticatedVariableGuid[VirtualMode],\r
- Global->PubKeyStore,\r
- mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
- 0,\r
- 0,\r
- VirtualMode,\r
- Global,\r
- &Variable\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- return Index;\r
-}\r
-\r
-/**\r
- Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.\r
- Follow the steps in UEFI2.2.\r
-\r
- @param[in] VirtualMode The current calling mode for this function.\r
- @param[in] Global The context of this Extended SAL Variable Services Class call.\r
- @param[in] Data The pointer to data with AuthInfo.\r
- @param[in] DataSize The size of Data.\r
- @param[in] PubKey The public key used for verification.\r
-\r
- @retval EFI_INVALID_PARAMETER Invalid parameter.\r
- @retval EFI_SECURITY_VIOLATION Authentication failed.\r
- @retval EFI_SUCCESS Authentication successful.\r
-\r
-**/\r
-EFI_STATUS\r
-VerifyDataPayload (\r
- IN BOOLEAN VirtualMode,\r
- IN ESAL_VARIABLE_GLOBAL *Global,\r
- IN UINT8 *Data,\r
- IN UINTN DataSize,\r
- IN UINT8 *PubKey\r
- )\r
-{\r
- BOOLEAN Status;\r
- EFI_VARIABLE_AUTHENTICATION *CertData;\r
- EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
- UINT8 Digest[SHA256_DIGEST_SIZE];\r
- VOID *Rsa;\r
- VOID *HashContext;\r
-\r
- Rsa = NULL;\r
- CertData = NULL;\r
- CertBlock = NULL;\r
-\r
- if (Data == NULL || PubKey == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
- CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
-\r
- //\r
- // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
- // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.\r
- //\r
- if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
- !CompareGuid (&CertData->AuthInfo.CertType, Global->CertRsa2048Sha256Guid[VirtualMode])\r
- ) {\r
- //\r
- // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
- //\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
-\r
- //\r
- // Hash data payload with SHA256.\r
- //\r
- ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
- HashContext = Global->HashContext[VirtualMode];\r
- Status = Sha256Init (HashContext);\r
- if (!Status) {\r
- goto Done;\r
- }\r
- Status = Sha256Update (HashContext, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));\r
- if (!Status) {\r
- goto Done;\r
- }\r
- //\r
- // Hash Monotonic Count.\r
- //\r
- Status = Sha256Update (HashContext, &CertData->MonotonicCount, sizeof (UINT64));\r
- if (!Status) {\r
- goto Done;\r
- }\r
- Status = Sha256Final (HashContext, Digest);\r
- if (!Status) {\r
- goto Done;\r
- }\r
- //\r
- // Generate & Initialize RSA Context.\r
- //\r
- Rsa = RsaNew ();\r
- ASSERT (Rsa != NULL);\r
- //\r
- // Set RSA Key Components.\r
- // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
- //\r
- Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
- if (!Status) {\r
- goto Done;\r
- }\r
- Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
- if (!Status) {\r
- goto Done;\r
- }\r
- //\r
- // Verify the signature.\r
- //\r
- Status = RsaPkcs1Verify (\r
- Rsa,\r
- Digest,\r
- SHA256_DIGEST_SIZE,\r
- CertBlock->Signature,\r
- EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
- );\r
-\r
-Done:\r
- if (Rsa != NULL) {\r
- RsaFree (Rsa);\r
- }\r
- if (Status) {\r
- return EFI_SUCCESS;\r
- } else {\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
-}\r
-\r
-\r
-/**\r
- Update platform mode.\r
-\r
- @param[in] VirtualMode The current calling mode for this function.\r
- @param[in] Global The context of this Extended SAL Variable Services Class call.\r
- @param[in] Mode SETUP_MODE or USER_MODE.\r
-\r
-**/\r
-VOID\r
-UpdatePlatformMode (\r
- IN BOOLEAN VirtualMode,\r
- IN ESAL_VARIABLE_GLOBAL *Global,\r
- IN UINT32 Mode\r
- )\r
-{\r
- EFI_STATUS Status;\r
- VARIABLE_POINTER_TRACK Variable;\r
- UINT32 VarAttr;\r
-\r
- Status = FindVariable (\r
- Global->VariableName[VirtualMode][VAR_SETUP_MODE],\r
- Global->GlobalVariableGuid[VirtualMode],\r
- &Variable,\r
- &Global->VariableGlobal[VirtualMode],\r
- Global->FvbInstance\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- mPlatformMode = Mode;\r
- VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
- Status = UpdateVariable (\r
- Global->VariableName[VirtualMode][VAR_SETUP_MODE],\r
- Global->GlobalVariableGuid[VirtualMode],\r
- &mPlatformMode,\r
- sizeof(UINT8),\r
- VarAttr,\r
- 0,\r
- 0,\r
- VirtualMode,\r
- Global,\r
- &Variable\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-}\r
-\r
-/**\r
- Process variable with platform key for verification.\r
-\r
- @param[in] VariableName The name of Variable to be found.\r
- @param[in] VendorGuid The variable vendor GUID.\r
- @param[in] Data The data pointer.\r
- @param[in] DataSize The size of Data found. If size is less than the\r
- data, this value contains the required size.\r
- @param[in] VirtualMode The current calling mode for this function.\r
- @param[in] Global The context of this Extended SAL Variable Services Class call.\r
- @param[in] Variable The variable information which is used to keep track of variable usage.\r
- @param[in] Attributes The attribute value of the variable.\r
- @param[in] IsPk Indicates whether to process pk.\r
-\r
- @retval EFI_INVALID_PARAMETER Invalid parameter.\r
- @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation\r
- check carried out by the firmware.\r
- @retval EFI_SUCCESS The variable passed validation successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-ProcessVarWithPk (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid,\r
- IN VOID *Data,\r
- IN UINTN DataSize,\r
- IN BOOLEAN VirtualMode,\r
- IN ESAL_VARIABLE_GLOBAL *Global,\r
- IN VARIABLE_POINTER_TRACK *Variable,\r
- IN UINT32 Attributes OPTIONAL,\r
- IN BOOLEAN IsPk\r
- )\r
-{\r
- EFI_STATUS Status;\r
- VARIABLE_POINTER_TRACK PkVariable;\r
- EFI_SIGNATURE_LIST *OldPkList;\r
- EFI_SIGNATURE_DATA *OldPkData;\r
- EFI_VARIABLE_AUTHENTICATION *CertData;\r
- AUTHENTICATED_VARIABLE_HEADER VariableHeader;\r
- BOOLEAN Valid;\r
-\r
- OldPkList = NULL;\r
- ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));\r
-\r
- if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
- //\r
- // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
- //\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (mPlatformMode == USER_MODE) {\r
- if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
- //\r
- // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
- //\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
-\r
- if (Variable->CurrPtr != 0x0) {\r
- Valid = IsValidVariableHeader (\r
- Variable->CurrPtr,\r
- Variable->Volatile,\r
- &Global->VariableGlobal[VirtualMode],\r
- Global->FvbInstance,\r
- &VariableHeader\r
- );\r
- ASSERT (Valid);\r
-\r
- if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {\r
- //\r
- // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
- //\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
- }\r
- //\r
- // Get platform key from variable.\r
- //\r
- Status = FindVariable (\r
- Global->VariableName[VirtualMode][VAR_PLATFORM_KEY],\r
- Global->GlobalVariableGuid[VirtualMode],\r
- &PkVariable,\r
- &Global->VariableGlobal[VirtualMode],\r
- Global->FvbInstance\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);\r
- GetVariableDataPtr (\r
- PkVariable.CurrPtr,\r
- PkVariable.Volatile,\r
- &Global->VariableGlobal[VirtualMode],\r
- Global->FvbInstance,\r
- (CHAR16 *) Global->KeyList\r
- );\r
-\r
- OldPkList = (EFI_SIGNATURE_LIST *) Global->KeyList;\r
- OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
- Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, OldPkData->SignatureData);\r
- if (!EFI_ERROR (Status)) {\r
- Status = UpdateVariable (\r
- VariableName,\r
- VendorGuid,\r
- (UINT8*)Data + AUTHINFO_SIZE,\r
- DataSize - AUTHINFO_SIZE,\r
- Attributes,\r
- 0,\r
- CertData->MonotonicCount,\r
- VirtualMode,\r
- Global,\r
- Variable\r
- );\r
-\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // If delete PK in user mode, need change to setup mode.\r
- //\r
- if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
- UpdatePlatformMode (VirtualMode, Global, SETUP_MODE);\r
- }\r
- }\r
- }\r
- } else {\r
- Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable);\r
- //\r
- // If enroll PK in setup mode, need change to user mode.\r
- //\r
- if ((DataSize != 0) && IsPk) {\r
- UpdatePlatformMode (VirtualMode, Global, USER_MODE);\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Process variable with key exchange key for verification.\r
-\r
- @param[in] VariableName The name of Variable to be found.\r
- @param[in] VendorGuid The variable vendor GUID.\r
- @param[in] Data The data pointer.\r
- @param[in] DataSize The size of Data found. If size is less than the\r
- data, this value contains the required size.\r
- @param[in] VirtualMode The current calling mode for this function.\r
- @param[in] Global The context of this Extended SAL Variable Services Class call.\r
- @param[in] Variable The variable information which is used to keep track of variable usage.\r
- @param[in] Attributes The attribute value of the variable.\r
-\r
- @retval EFI_INVALID_PARAMETER Invalid parameter.\r
- @retval EFI_SECURITY_VIOLATION The variable did NOT pass the validation\r
- check carried out by the firmware.\r
- @retval EFI_SUCCESS The variable passed validation successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-ProcessVarWithKek (\r
- IN CHAR16 *VariableName,\r
- IN EFI_GUID *VendorGuid,\r
- IN VOID *Data,\r
- IN UINTN DataSize,\r
- IN BOOLEAN VirtualMode,\r
- IN ESAL_VARIABLE_GLOBAL *Global,\r
- IN VARIABLE_POINTER_TRACK *Variable,\r
- IN UINT32 Attributes OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- VARIABLE_POINTER_TRACK KekVariable;\r
- EFI_SIGNATURE_LIST *KekList;\r
- EFI_SIGNATURE_DATA *KekItem;\r
- UINT32 KekCount;\r
- EFI_VARIABLE_AUTHENTICATION *CertData;\r
- EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
- BOOLEAN IsFound;\r
- UINT32 Index;\r
- AUTHENTICATED_VARIABLE_HEADER VariableHeader;\r
- BOOLEAN Valid;\r
-\r
- KekList = NULL;\r
- ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));\r
-\r
- if (mPlatformMode == USER_MODE) {\r
- if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
- //\r
- // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
- //\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
- CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
- if (Variable->CurrPtr != 0x0) {\r
- Valid = IsValidVariableHeader (\r
- Variable->CurrPtr,\r
- Variable->Volatile,\r
- &Global->VariableGlobal[VirtualMode],\r
- Global->FvbInstance,\r
- &VariableHeader\r
- );\r
- ASSERT (Valid);\r
-\r
- if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {\r
- //\r
- // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
- //\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
- }\r
- //\r
- // Get KEK database from variable.\r
- //\r
- Status = FindVariable (\r
- Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY],\r
- Global->GlobalVariableGuid[VirtualMode],\r
- &KekVariable,\r
- &Global->VariableGlobal[VirtualMode],\r
- Global->FvbInstance\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);\r
- GetVariableDataPtr (\r
- KekVariable.CurrPtr,\r
- KekVariable.Volatile,\r
- &Global->VariableGlobal[VirtualMode],\r
- Global->FvbInstance,\r
- (CHAR16 *) Global->KeyList\r
- );\r
- //\r
- // Enumerate all Kek items in this list to verify the variable certificate data.\r
- // If anyone is authenticated successfully, it means the variable is correct!\r
- //\r
- KekList = (EFI_SIGNATURE_LIST *) Global->KeyList;\r
- IsFound = FALSE;\r
- KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
- KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
- for (Index = 0; Index < KekCount; Index++) {\r
- if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
- IsFound = TRUE;\r
- break;\r
- }\r
- KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
- }\r
-\r
- if (!IsFound) {\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
-\r
- Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, CertBlock->PublicKey);\r
- if (!EFI_ERROR (Status)) {\r
- Status = UpdateVariable (\r
- VariableName,\r
- VendorGuid,\r
- (UINT8*)Data + AUTHINFO_SIZE,\r
- DataSize - AUTHINFO_SIZE,\r
- Attributes,\r
- 0,\r
- CertData->MonotonicCount,\r
- VirtualMode,\r
- Global,\r
- Variable\r
- );\r
- }\r
- } else {\r
- //\r
- // If in setup mode, no authentication needed.\r
- //\r
- Status = UpdateVariable (\r
- VariableName,\r
- VendorGuid,\r
- Data,\r
- DataSize,\r
- Attributes,\r
- 0,\r
- 0,\r
- VirtualMode,\r
- Global,\r
- Variable\r
- );\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.\r
-\r
- @param[in] Data The data pointer.\r
- @param[in] DataSize The size of Data found. If size is less than the\r
- data, this value contains the required size.\r
- @param[in] VirtualMode The current calling mode for this function.\r
- @param[in] Global The context of this Extended SAL Variable Services Class call.\r
- @param[in] Variable The variable information which is used to keep track of variable usage.\r
- @param[in] Attributes The attribute value of the variable.\r
- @param[out] KeyIndex The output index of corresponding public key in database.\r
- @param[out] MonotonicCount The output value of corresponding Monotonic Count.\r
-\r
- @retval EFI_INVALID_PARAMETER Invalid parameter.\r
- @retval EFI_WRITE_PROTECTED The variable is write-protected and needs authentication with\r
- EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
- @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
- set, but the AuthInfo does NOT pass the validation\r
- check carried out by the firmware.\r
- @retval EFI_SUCCESS The variable is not write-protected, or passed validation successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-VerifyVariable (\r
- IN VOID *Data,\r
- IN UINTN DataSize,\r
- IN BOOLEAN VirtualMode,\r
- IN ESAL_VARIABLE_GLOBAL *Global,\r
- IN VARIABLE_POINTER_TRACK *Variable,\r
- IN UINT32 Attributes OPTIONAL,\r
- OUT UINT32 *KeyIndex OPTIONAL,\r
- OUT UINT64 *MonotonicCount OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- BOOLEAN IsDeletion;\r
- BOOLEAN IsFirstTime;\r
- UINT8 *PubKey;\r
- EFI_VARIABLE_AUTHENTICATION *CertData;\r
- EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;\r
- AUTHENTICATED_VARIABLE_HEADER VariableHeader;\r
- BOOLEAN Valid;\r
-\r
- CertData = NULL;\r
- CertBlock = NULL;\r
- PubKey = NULL;\r
- IsDeletion = FALSE;\r
- Valid = FALSE;\r
-\r
- if (KeyIndex != NULL) {\r
- *KeyIndex = 0;\r
- }\r
- //\r
- // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
- //\r
- ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));\r
- if (Variable->CurrPtr != 0x0) {\r
- Valid = IsValidVariableHeader (\r
- Variable->CurrPtr,\r
- Variable->Volatile,\r
- &Global->VariableGlobal[VirtualMode],\r
- Global->FvbInstance,\r
- &VariableHeader\r
- );\r
- ASSERT (Valid);\r
- }\r
-\r
- if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
- if (KeyIndex == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Determine current operation type.\r
- //\r
- if (DataSize == AUTHINFO_SIZE) {\r
- IsDeletion = TRUE;\r
- }\r
- //\r
- // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
- //\r
- if (Variable->CurrPtr == 0x0) {\r
- IsFirstTime = TRUE;\r
- } else if (Valid &&(VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
- IsFirstTime = TRUE;\r
- } else {\r
- *KeyIndex = VariableHeader.PubKeyIndex;\r
- IsFirstTime = FALSE;\r
- }\r
- } else if (Valid && (VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
- //\r
- // If the variable is already write-protected, it always needs authentication before update.\r
- //\r
- return EFI_WRITE_PROTECTED;\r
- } else {\r
- //\r
- // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
- // That means it is not authenticated variable, just return EFI_SUCCESS.\r
- //\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // Get PubKey and check Monotonic Count value corresponding to the variable.\r
- //\r
- CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
- CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
- PubKey = CertBlock->PublicKey;\r
-\r
- if (MonotonicCount != NULL) {\r
- //\r
- // Update Monotonic Count value.\r
- //\r
- *MonotonicCount = CertData->MonotonicCount;\r
- }\r
-\r
- if (!IsFirstTime) {\r
- //\r
- // Check input PubKey.\r
- //\r
- if (CompareMem (PubKey, Global->PubKeyStore + (*KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
- //\r
- // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
- // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
- //\r
- if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {\r
- //\r
- // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
- //\r
- return EFI_SECURITY_VIOLATION;\r
- }\r
- }\r
- //\r
- // Verify the certificate in Data payload.\r
- //\r
- Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, PubKey);\r
- if (!EFI_ERROR (Status)) {\r
- //\r
- // Now, the signature has been verified!\r
- //\r
- if (IsFirstTime && !IsDeletion) {\r
- //\r
- // Update public key database variable if need and return the index.\r
- //\r
- *KeyIndex = AddPubKeyInStore (VirtualMode, Global, PubKey);\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r