/** Update the variable region with Variable information. @param[in] AuthVariableInfo Pointer AUTH_VARIABLE_INFO structure for input of the variable. @retval EFI_SUCCESS The update operation is success. @retval EFI_INVALID_PARAMETER Invalid parameter. @retval EFI_WRITE_PROTECTED Variable is write-protected. @retval EFI_OUT_OF_RESOURCES There is not enough resource. **/ EFI_STATUS EFIAPI VariableExLibUpdateVariable ( IN AUTH_VARIABLE_INFO *AuthVariableInfo ) { VARIABLE_POINTER_TRACK Variable; FindVariable (AuthVariableInfo->VariableName, AuthVariableInfo->VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE); return UpdateVariable ( AuthVariableInfo->VariableName, AuthVariableInfo->VendorGuid, AuthVariableInfo->Data, AuthVariableInfo->DataSize, AuthVariableInfo->Attributes, AuthVariableInfo->PubKeyIndex, AuthVariableInfo->MonotonicCount, &Variable, AuthVariableInfo->TimeStamp ); }
/** Update platform mode. @param[in] VirtualMode The current calling mode for this function. @param[in] Global The context of this Extended SAL Variable Services Class call. @param[in] Mode SETUP_MODE or USER_MODE. **/ VOID UpdatePlatformMode ( IN BOOLEAN VirtualMode, IN ESAL_VARIABLE_GLOBAL *Global, IN UINT32 Mode ) { EFI_STATUS Status; VARIABLE_POINTER_TRACK Variable; UINT32 VarAttr; Status = FindVariable ( Global->VariableName[VirtualMode][VAR_SETUP_MODE], Global->GlobalVariableGuid[VirtualMode], &Variable, &Global->VariableGlobal[VirtualMode], Global->FvbInstance ); ASSERT_EFI_ERROR (Status); mPlatformMode = Mode; VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; Status = UpdateVariable ( Global->VariableName[VirtualMode][VAR_SETUP_MODE], Global->GlobalVariableGuid[VirtualMode], &mPlatformMode, sizeof(UINT8), VarAttr, 0, 0, VirtualMode, Global, &Variable ); ASSERT_EFI_ERROR (Status); }
/** Process variable with key exchange key for verification. @param[in] VariableName The name of Variable to be found. @param[in] VendorGuid The variable vendor GUID. @param[in] Data The data pointer. @param[in] DataSize The size of Data found. If size is less than the data, this value contains the required size. @param[in] VirtualMode The current calling mode for this function. @param[in] Global The context of this Extended SAL Variable Services Class call. @param[in] Variable The variable information which is used to keep track of variable usage. @param[in] Attributes The attribute value of the variable. @retval EFI_INVALID_PARAMETER Invalid parameter. @retval EFI_SECURITY_VIOLATION The variable did NOT pass the validation check carried out by the firmware. @retval EFI_SUCCESS The variable passed validation successfully. **/ EFI_STATUS ProcessVarWithKek ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN VOID *Data, IN UINTN DataSize, IN BOOLEAN VirtualMode, IN ESAL_VARIABLE_GLOBAL *Global, IN VARIABLE_POINTER_TRACK *Variable, IN UINT32 Attributes OPTIONAL ) { EFI_STATUS Status; VARIABLE_POINTER_TRACK KekVariable; EFI_SIGNATURE_LIST *KekList; EFI_SIGNATURE_DATA *KekItem; UINT32 KekCount; EFI_VARIABLE_AUTHENTICATION *CertData; EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock; BOOLEAN IsFound; UINT32 Index; VARIABLE_HEADER VariableHeader; BOOLEAN Valid; KekList = NULL; ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER)); if (mPlatformMode == USER_MODE) { if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) { // // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute. // return EFI_INVALID_PARAMETER; } CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData); if (Variable->CurrPtr != 0x0) { Valid = IsValidVariableHeader ( Variable->CurrPtr, Variable->Volatile, &Global->VariableGlobal[VirtualMode], Global->FvbInstance, &VariableHeader ); ASSERT (Valid); if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) { // // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION. // return EFI_SECURITY_VIOLATION; } } // // Get KEK database from variable. // Status = FindVariable ( Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY], Global->GlobalVariableGuid[VirtualMode], &KekVariable, &Global->VariableGlobal[VirtualMode], Global->FvbInstance ); ASSERT_EFI_ERROR (Status); ZeroMem (Global->KeyList, MAX_KEYDB_SIZE); GetVariableDataPtr ( KekVariable.CurrPtr, KekVariable.Volatile, &Global->VariableGlobal[VirtualMode], Global->FvbInstance, (CHAR16 *) Global->KeyList ); // // Enumerate all Kek items in this list to verify the variable certificate data. // If anyone is authenticated successfully, it means the variable is correct! // KekList = (EFI_SIGNATURE_LIST *) Global->KeyList; IsFound = FALSE; KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize; KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize); for (Index = 0; Index < KekCount; Index++) { if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) { IsFound = TRUE; break; } KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize); } if (!IsFound) { return EFI_SECURITY_VIOLATION; } Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, CertBlock->PublicKey); if (!EFI_ERROR (Status)) { Status = UpdateVariable ( VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, 0, CertData->MonotonicCount, VirtualMode, Global, Variable ); } } else { // // If in setup mode, no authentication needed. // Status = UpdateVariable ( VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable ); } return Status; }
/** Process variable with platform key for verification. @param[in] VariableName The name of Variable to be found. @param[in] VendorGuid The variable vendor GUID. @param[in] Data The data pointer. @param[in] DataSize The size of Data found. If size is less than the data, this value contains the required size. @param[in] VirtualMode The current calling mode for this function. @param[in] Global The context of this Extended SAL Variable Services Class call. @param[in] Variable The variable information which is used to keep track of variable usage. @param[in] Attributes The attribute value of the variable. @param[in] IsPk Indicates whether to process pk. @retval EFI_INVALID_PARAMETER Invalid parameter. @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation check carried out by the firmware. @retval EFI_SUCCESS The variable passed validation successfully. **/ EFI_STATUS ProcessVarWithPk ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN VOID *Data, IN UINTN DataSize, IN BOOLEAN VirtualMode, IN ESAL_VARIABLE_GLOBAL *Global, IN VARIABLE_POINTER_TRACK *Variable, IN UINT32 Attributes OPTIONAL, IN BOOLEAN IsPk ) { EFI_STATUS Status; VARIABLE_POINTER_TRACK PkVariable; EFI_SIGNATURE_LIST *OldPkList; EFI_SIGNATURE_DATA *OldPkData; EFI_VARIABLE_AUTHENTICATION *CertData; VARIABLE_HEADER VariableHeader; BOOLEAN Valid; OldPkList = NULL; ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER)); if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { // // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute. // return EFI_INVALID_PARAMETER; } if (mPlatformMode == USER_MODE) { if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) { // // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute. // return EFI_INVALID_PARAMETER; } CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; if (Variable->CurrPtr != 0x0) { Valid = IsValidVariableHeader ( Variable->CurrPtr, Variable->Volatile, &Global->VariableGlobal[VirtualMode], Global->FvbInstance, &VariableHeader ); ASSERT (Valid); if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) { // // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION. // return EFI_SECURITY_VIOLATION; } } // // Get platform key from variable. // Status = FindVariable ( Global->VariableName[VirtualMode][VAR_PLATFORM_KEY], Global->GlobalVariableGuid[VirtualMode], &PkVariable, &Global->VariableGlobal[VirtualMode], Global->FvbInstance ); ASSERT_EFI_ERROR (Status); ZeroMem (Global->KeyList, MAX_KEYDB_SIZE); GetVariableDataPtr ( PkVariable.CurrPtr, PkVariable.Volatile, &Global->VariableGlobal[VirtualMode], Global->FvbInstance, (CHAR16 *) Global->KeyList ); OldPkList = (EFI_SIGNATURE_LIST *) Global->KeyList; OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize); Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, OldPkData->SignatureData); if (!EFI_ERROR (Status)) { Status = UpdateVariable ( VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, 0, CertData->MonotonicCount, VirtualMode, Global, Variable ); if (!EFI_ERROR (Status)) { // // If delete PK in user mode, need change to setup mode. // if ((DataSize == AUTHINFO_SIZE) && IsPk) { UpdatePlatformMode (VirtualMode, Global, SETUP_MODE); } } } } else { Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable); // // If enroll PK in setup mode, need change to user mode. // if ((DataSize != 0) && IsPk) { UpdatePlatformMode (VirtualMode, Global, USER_MODE); } } return Status; }
/** Initializes for authenticated varibale service. @retval EFI_SUCCESS The function successfully executed. @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resources. **/ EFI_STATUS AutenticatedVariableServiceInitialize ( VOID ) { EFI_STATUS Status; VARIABLE_POINTER_TRACK Variable; UINT8 VarValue; UINT32 VarAttr; UINTN DataSize; UINTN CtxSize; VARIABLE_HEADER VariableHeader; BOOLEAN Valid; ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER)); mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid; mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical] = &gEfiCertRsa2048Sha256Guid; mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid; // // Initialize hash context. // CtxSize = Sha256GetContextSize (); mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize); ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL); // // Check "AuthVarKeyDatabase" variable's existence. // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. // Status = FindVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB], &gEfiAuthenticatedVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance ); if (Variable.CurrPtr == 0x0) { VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; VarValue = 0; mPubKeyNumber = 0; Status = UpdateVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB], &gEfiAuthenticatedVariableGuid, &VarValue, sizeof(UINT8), VarAttr, 0, 0, FALSE, mVariableModuleGlobal, &Variable ); if (EFI_ERROR (Status)) { return Status; } } else { // // Load database in global variable for cache. // Valid = IsValidVariableHeader ( Variable.CurrPtr, Variable.Volatile, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance, &VariableHeader ); ASSERT (Valid); DataSize = DataSizeOfVariable (&VariableHeader); ASSERT (DataSize <= MAX_KEYDB_SIZE); GetVariableDataPtr ( Variable.CurrPtr, Variable.Volatile, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance, (CHAR16 *) mVariableModuleGlobal->PubKeyStore ); mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE); } // // Check "SetupMode" variable's existence. // If it doesn't exist, check PK database's existence to determine the value. // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. // Status = FindVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE], &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance ); if (Variable.CurrPtr == 0x0) { Status = FindVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY], &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance ); if (Variable.CurrPtr == 0x0) { mPlatformMode = SETUP_MODE; } else { mPlatformMode = USER_MODE; } VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; Status = UpdateVariable ( mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE], &gEfiGlobalVariableGuid, &mPlatformMode, sizeof(UINT8), VarAttr, 0, 0, FALSE, mVariableModuleGlobal, &Variable ); if (EFI_ERROR (Status)) { return Status; } } else { GetVariableDataPtr ( Variable.CurrPtr, Variable.Volatile, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance, (CHAR16 *) &mPlatformMode ); } // // Check "SignatureSupport" variable's existence. // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. // Status = FindVariable ( EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal[Physical], mVariableModuleGlobal->FvbInstance ); if (Variable.CurrPtr == 0x0) { VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; Status = UpdateVariable ( EFI_SIGNATURE_SUPPORT_NAME, &gEfiGlobalVariableGuid, mSignatureSupport, SIGSUPPORT_NUM * sizeof(EFI_GUID), VarAttr, 0, 0, FALSE, mVariableModuleGlobal, &Variable ); } return Status; }
/** Add public key in store and return its index. @param[in] VirtualMode The current calling mode for this function. @param[in] Global The context of this Extended SAL Variable Services Class call. @param[in] PubKey The input pointer to Public Key data. @return The index of new added item. **/ UINT32 AddPubKeyInStore ( IN BOOLEAN VirtualMode, IN ESAL_VARIABLE_GLOBAL *Global, IN UINT8 *PubKey ) { EFI_STATUS Status; BOOLEAN IsFound; UINT32 Index; VARIABLE_POINTER_TRACK Variable; UINT8 *Ptr; if (PubKey == NULL) { return 0; } Status = FindVariable ( Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB], Global->AuthenticatedVariableGuid[VirtualMode], &Variable, &Global->VariableGlobal[VirtualMode], Global->FvbInstance ); ASSERT_EFI_ERROR (Status); // // Check whether the public key entry does exist. // IsFound = FALSE; for (Ptr = Global->PubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) { if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) { IsFound = TRUE; break; } Ptr += EFI_CERT_TYPE_RSA2048_SIZE; } if (!IsFound) { // // Add public key in database. // if (mPubKeyNumber == MAX_KEY_NUM) { // // Notes: Database is full, need enhancement here, currently just return 0. // return 0; } CopyMem (Global->PubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE); Index = ++mPubKeyNumber; // // Update public key database variable. // Status = UpdateVariable ( Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB], Global->AuthenticatedVariableGuid[VirtualMode], Global->PubKeyStore, mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, 0, 0, VirtualMode, Global, &Variable ); ASSERT_EFI_ERROR (Status); } return Index; }
void VRSDClient::HandleDebuggingMessage(VMessage* pMessage) { if(!pMessage || !m_pClientLanguageImplementation) return; // Handle debugging messages here switch(pMessage->GetMessageType()) { case 'RSRN': HandleScriptReloadMessage(pMessage); break; case 'GCST': { // get the callstack from the scripting language implementation DynArray_cl<VRSDClientCallstackEntry> Callstack(16); unsigned int CallstackEntryCount = 0; m_pClientLanguageImplementation->GetCallstack(Callstack, CallstackEntryCount); // send it SendCallstack(Callstack, CallstackEntryCount); } break; case 'GGSY': { // get the global symbol collection from the scripting language implementation DynArray_cl<VRSDScriptSymbol> globalSymbols(32, VRSDScriptSymbol()); unsigned int iGlobalSymbolCount = 0; m_pClientLanguageImplementation->GetGlobalSymbols(globalSymbols, iGlobalSymbolCount); // send it SendSymbols('GSYC', globalSymbols, iGlobalSymbolCount); } break; case 'GLSY': { // get the local symbol collection from the scripting language implementation DynArray_cl<VRSDScriptSymbol> localSymbols(16, VRSDScriptSymbol()); unsigned int iLocalSymbolCount = 0; m_pClientLanguageImplementation->GetLocalSymbols(localSymbols, iLocalSymbolCount); // send it SendSymbols('LSYC', localSymbols, iLocalSymbolCount); } break; case 'GSFG': { // read the symbol name for which the subsymbols are requested char* pSymbolName = NULL; if(pMessage->ReadString(&pSymbolName)) { // get the global symbol collection from the scripting language implementation DynArray_cl<VRSDScriptSymbol> globalSymbols(16, VRSDScriptSymbol()); unsigned int iGlobalSymbolCount = 0; if(m_pClientLanguageImplementation->GetSubSymbolsForGlobal(pSymbolName, globalSymbols, iGlobalSymbolCount)) { // send it SendSymbols('GSSC', globalSymbols, iGlobalSymbolCount, pSymbolName); } } } break; case 'GSFL': { // read the symbol name for which the subsymbols are requested char* pSymbolName = NULL; if(pMessage->ReadString(&pSymbolName)) { // get the global symbol collection from the scripting language implementation DynArray_cl<VRSDScriptSymbol> localSymbols(16, VRSDScriptSymbol()); unsigned int iLocalSymbolCount = 0; if(m_pClientLanguageImplementation->GetSubSymbolsForLocal(pSymbolName, localSymbols, iLocalSymbolCount)) { // send it SendSymbols('LSSC', localSymbols, iLocalSymbolCount, pSymbolName); } } } break; // get userdata type (local / global) case 'GUDT': case 'LUDT': { // read first the variable name we should check char* pVariableName = NULL; if(!pMessage->ReadString(&pVariableName)) break; char pUserDataTypeName[512]; bool success; if(pMessage->GetMessageType() == 'GUDT') success = m_pClientLanguageImplementation->GetGlobalType(pVariableName, pUserDataTypeName); else success = m_pClientLanguageImplementation->GetLocalType(pVariableName, pUserDataTypeName); if(success) { VMessage msg('VUDT', (int)strlen(pUserDataTypeName) + 5); msg.Write(pUserDataTypeName); VMutexLocker lock(m_ConnectionMutex); if(m_pConnection) m_pConnection->Send(&msg); } else { // if no type is found submit that VMessage msg('VUDT', 5); msg.Write(""); VMutexLocker lock(m_ConnectionMutex); if(m_pConnection) m_pConnection->Send(&msg); } } break; // update the value of a variable (non userdata = strings, bools, numbers) case 'LVCU': case 'GVCU': UpdateVariable(pMessage); break; // request for user data update case 'LUDU': case 'GUDU': UpdateUserDataVariable(pMessage); break; // request for local user data members case 'LUDM': case 'GUDM': HandleUserDataMemberRequest(pMessage); break; } }