/** @file Common secure boot relative supports functions ;****************************************************************************** ;* Copyright (c) 2012 - 2017, Insyde Software Corp. All Rights Reserved. ;* ;* You may not reproduce, distribute, publish, display, perform, modify, adapt, ;* transmit, broadcast, present, recite, release, license or otherwise exploit ;* any part of this publication in any form, by any means, without the prior ;* written permission of Insyde Software Corporation. ;* ;****************************************************************************** */ #include #include #include #include #include #include #include #include /** According to variable name and GUID to Determine the variable is secure database relative variable. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is secure database relative variable. @retval FALSE This isn't secure database relative variable. --*/ BOOLEAN IsSecureDatabaseVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (IsPkVariable (VariableName, VendorGuid) || IsKekVariable (VariableName, VendorGuid) || IsImageSecureDatabaseVariable (VariableName, VendorGuid)) { return TRUE; } return FALSE; } /** According to variable name and GUID to Determine the variable is image secure database relative variable. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is image secure database relative variable. @retval FALSE This isn't image secure database relative variable. --*/ BOOLEAN IsImageSecureDatabaseVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (IsDbVariable (VariableName, VendorGuid) || IsDbxVariable (VariableName, VendorGuid) || IsDbtVariable (VariableName, VendorGuid)|| IsDbrVariable (VariableName, VendorGuid)) { return TRUE; } return FALSE; } /** According to variable name and GUID to Determine the variable is AuditMode or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is AuditMode variable. @retval FALSE This isn't AuditMode variable. --*/ BOOLEAN IsAuditModeVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_AUDIT_MODE_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is DeployedMode or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is DeployedMode variable. @retval FALSE This isn't DeployedMode variable. --*/ BOOLEAN IsDeployedModeVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_DEPLOYED_MODE_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is PK or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is PK variable. @retval FALSE This isn't PK variable. --*/ BOOLEAN IsPkVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is KEK or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is KEK variable. @retval FALSE This isn't KEK variable. --*/ BOOLEAN IsKekVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is db or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is db variable. @retval FALSE This isn't db variable. --*/ BOOLEAN IsDbVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0 && CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is dbx or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is dbx variable. @retval FALSE This isn't dbx variable. --*/ BOOLEAN IsDbxVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0 && CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is dbt or not. @param VariableName Name of Variable to be found. @param VendorGuid Variable vendor GUID. @retval TRUE This is dbt variable. @retval FALSE This isn't dbt variable. --*/ BOOLEAN IsDbtVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0 && CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is dbr or not. @param VariableName Name of Variable to be found. @param VendorGuid Variable vendor GUID. @retval TRUE This is dbr variable. @retval FALSE This isn't dbt variable. --*/ BOOLEAN IsDbrVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE3) == 0 && CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid)) { return TRUE; } } return FALSE; } /** Check if a Unicode character is a hexadecimal character. This function checks if a Unicode character is a hexadecimal character. The valid hexadecimal character is L'0' to L'9', L'a' to L'f', or L'A' to L'F'. @param[in] Char The character to check against. @retval TRUE If the Char is a hexadecmial character. @retval FALSE If the Char is not a hexadecmial character. **/ STATIC BOOLEAN EFIAPI IsHexaDecimalDigitCharacter ( IN CHAR16 Char ) { return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F')); } /** According to variable name and GUID to Determine the variable is OsRecovery#### or not. @param VariableName Name of Variable to be found. @retval TRUE This is OsRecovery#### variable. @retval FALSE This isn't OsRecovery#### variable. --*/ BOOLEAN IsOsRecoveryVariable ( IN CONST CHAR16 *VariableName ) { UINTN NameLength; if (VariableName == NULL) { return FALSE; } NameLength = StrLen (L"OsRecovery"); if (StrLen (VariableName) == StrLen (L"OsRecovery####") && StrnCmp (VariableName, L"OsRecovery", StrLen (L"OsRecovery")) == 0 && IsHexaDecimalDigitCharacter (VariableName[NameLength]) && IsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) && IsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) && IsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) { return TRUE; } return FALSE; } /** According to variable name and GUID to Determine the variable is OsRecoveryOrder or not. @param VariableName Name of Variable to be found. @param VendorGuid Variable vendor GUID. @retval TRUE This is OsRecoveryOrder variable. @retval FALSE This isn't OsRecoveryOrder variable. --*/ BOOLEAN IsOsRecoveryOrderVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_OS_RECOVERY_ORDER_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is secure boot policy variable or not. @param VariableName Name of Variable to be found. @param VendorGuid Variable vendor GUID. @retval TRUE This is secure boot policy variable variable. @retval FALSE This isn't secure boot policy variable variable. --*/ BOOLEAN IsSecureBootPolicyVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName == NULL || VendorGuid == NULL) { return FALSE; } if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) || IsPkVariable (VariableName, VendorGuid) || IsKekVariable (VariableName, VendorGuid) || IsOsRecoveryOrderVariable (VariableName, VendorGuid) || IsOsRecoveryVariable (VariableName)) { return TRUE; } return FALSE; } /** According to variable name and GUID to Determine the variable is secure database default relative variable. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is secure database default relative variable. @retval FALSE This isn't secure database default relative variable. --*/ BOOLEAN IsSecureDatabaseDefaultVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (IsPkDefaultVariable (VariableName, VendorGuid) || IsKekDefaultVariable (VariableName, VendorGuid) || IsImageSecureDatabaseDefaultVariable (VariableName, VendorGuid)) { return TRUE; } return FALSE; } /** According to variable name and GUID to Determine the variable is image secure database default relative variable. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is image secure database default relative variable. @retval FALSE This isn't image secure database default relative variable. --*/ BOOLEAN IsImageSecureDatabaseDefaultVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (IsDbDefaultVariable (VariableName, VendorGuid) || IsDbxDefaultVariable (VariableName, VendorGuid) || IsDbtDefaultVariable (VariableName, VendorGuid)|| IsDbrDefaultVariable (VariableName, VendorGuid)) { return TRUE; } return FALSE; } /** According to variable name and GUID to Determine the variable is PKDefault or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is PKDefault variable. @retval FALSE This isn't PKDefault variable. --*/ BOOLEAN IsPkDefaultVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_PK_DEFAULT_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is KEKDefault or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is KEKDefault variable. @retval FALSE This isn't KEKDefault variable. --*/ BOOLEAN IsKekDefaultVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_KEK_DEFAULT_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is dbDefault or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is dbDefault variable. @retval FALSE This isn't dbDefault variable. --*/ BOOLEAN IsDbDefaultVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_DB_DEFAULT_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is dbxDefault or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is dbxDefault variable. @retval FALSE This isn't dbxDefault variable. --*/ BOOLEAN IsDbxDefaultVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_DBX_DEFAULT_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is dbtDefault or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is dbtDefault variable. @retval FALSE This isn't dbtDefault variable. --*/ BOOLEAN IsDbtDefaultVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_DBT_DEFAULT_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is dbrDefault or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is dbrDefault variable. @retval FALSE This isn't dbrDefault variable. --*/ BOOLEAN IsDbrDefaultVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_DBR_DEFAULT_VARIABLE_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine the variable is CustomSecurity or not. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is CustomSecurity variable. @retval FALSE This isn't CustomSecurity variable. --*/ STATIC BOOLEAN IsCustomSecurityVariable ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { if (VariableName != NULL && VendorGuid != NULL) { if (StrCmp (VariableName, EFI_CUSTOM_SECURITY_NAME) == 0 && CompareGuid (VendorGuid, &gEfiGenericVariableGuid)) { return TRUE; } } return FALSE; } /** According to variable name and GUID to Determine this variable whether need reserve during restore factory default process. @param[in] VariableName Name of Variable to be found. @param[in] VendorGuid Variable vendor GUID. @retval TRUE This is CustomSecurity variable. @retval FALSE This isn't CustomSecurity variable. --*/ STATIC BOOLEAN VariableNeedReserve ( IN CONST CHAR16 *VariableName, IN CONST EFI_GUID *VendorGuid ) { // // Needn't reserve EFI_CUSTOM_SECURITY_NAME, and then system will create new variable to indicate system is in // standard mode. // if (IsSecureDatabaseVariable (VariableName, VendorGuid) || IsCustomSecurityVariable (VariableName, VendorGuid)) { return FALSE; } return TRUE; } /** Merge all of variables aren't secure boot relative variables and doesn't saved in factory copy region from variable store to factory copy region. @param[in, out] FactorycopyBuffer [in]:The buffer contained all of factory copy data. [out]:The buffer has been appended data from VariableBuffer. @param[in, out] FactoryBufferLength [in]:The size of FactorycopyBuffer. [out]:The total used size in FactorycopyBuffer. @param[in] VariableBuffer Buffer to save all of variable data. @param[in] VariableBufferLength The size of VariableBuffer. @retval EFI_SUCCESS Merge varialbe data to factory copy region successful. @retval EFI_INVALID_PARAMETER FactorycopyBuffer, FactoryBufferLength or VariableBuffer is NULL. The data in FactorycopyBuffer in incorrect. @retval EFI_BUFFER_TOO_SMALL FactoryBufferLength is too small to contain merged data. --*/ EFI_STATUS MergeVariableToFactoryCopy ( IN OUT UINT8 *FactorycopyBuffer, IN OUT UINTN *FactoryBufferLength, IN CONST UINT8 *VariableBuffer, IN UINTN VariableBufferLength ) { UINTN LastVariableOffset; UINTN VariableSize; UINTN HeaderSize; VARIABLE_HEADER *VariableHeader; VARIABLE_HEADER *NextVariable; EFI_STATUS Status; if (FactorycopyBuffer == NULL || FactoryBufferLength == NULL || VariableBuffer == NULL) { return EFI_INVALID_PARAMETER; } // // Check the factory defualt data is whether valid // for (LastVariableOffset = *FactoryBufferLength; LastVariableOffset > 0; LastVariableOffset--) { if (FactorycopyBuffer[LastVariableOffset - 1] != 0xFF) { break; } } HeaderSize = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + GetVariableStoreHeaderSize (); if (LastVariableOffset + 1 < HeaderSize) { return EFI_INVALID_PARAMETER; } // // Find last variable offset in working buffer // NextVariable = (VARIABLE_HEADER *) (FactorycopyBuffer + HeaderSize); while (IsValidVariableHeader (NextVariable)) { NextVariable = GetNextVariablePtr (NextVariable); } LastVariableOffset = (UINTN) NextVariable - (UINTN) FactorycopyBuffer; // // Copy original firmware volume and variable store header information to exported factory default buffer. // This action can prevent from the information of firmware volume header and variable store header in // factory default region is incorrect. // CopyMem (FactorycopyBuffer, VariableBuffer, HeaderSize); // // merge variable data to working buffer // Status = EFI_SUCCESS; VariableHeader = (VARIABLE_HEADER *) (VariableBuffer + HeaderSize); while (IsValidVariableHeader (VariableHeader)) { NextVariable = GetNextVariablePtr (VariableHeader); // // Collect all of valid variables. these variables should include variable state in added state and in deleted transition state. // We also can remove the variable with deleted transition if variable store has the variable with added state. // For current design, variable should do this check, so we needn't do this check here. // if (VariableHeader->State == VAR_ADDED || VariableHeader->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) { if (VariableNeedReserve ((CHAR16 *) (VariableHeader + 1), &VariableHeader->VendorGuid) && !DoesVariableExist ((CHAR16 *) (VariableHeader + 1), &VariableHeader->VendorGuid, FactorycopyBuffer, *FactoryBufferLength)) { VariableSize = (UINTN) NextVariable - (UINTN) VariableHeader; if (LastVariableOffset + VariableSize <= VariableBufferLength - 1) { CopyMem (&FactorycopyBuffer[LastVariableOffset], VariableHeader, VariableSize); } LastVariableOffset += VariableSize; } } VariableHeader = NextVariable; } if (LastVariableOffset > VariableBufferLength) { Status = EFI_BUFFER_TOO_SMALL; } *FactoryBufferLength = LastVariableOffset; return Status; }