From 0c18794ea4289f03fefc7117b56740414cc0536c Mon Sep 17 00:00:00 2001 From: gdong1 Date: Fri, 2 Sep 2011 07:49:32 +0000 Subject: [PATCH] Add security package to repository. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12261 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Application/VariableInfo/VariableInfo.c | 268 + .../Application/VariableInfo/VariableInfo.inf | 54 + .../Guid/AuthenticatedVariableFormat.h | 174 + .../Include/Guid/PhysicalPresenceData.h | 76 + .../Include/Guid/SecurityPkgTokenSpace.h | 25 + SecurityPkg/Include/Guid/TcgEventHob.h | 30 + .../Include/Library/PlatformSecureLib.h | 42 + SecurityPkg/Include/Library/TpmCommLib.h | 286 ++ .../Include/Ppi/LockPhysicalPresence.h | 60 + SecurityPkg/Include/Ppi/TpmInitialized.h | 30 + .../DxeDeferImageLoadLib.c | 858 ++++ .../DxeDeferImageLoadLib.h | 106 + .../DxeDeferImageLoadLib.inf | 62 + .../DxeImageVerificationLib.c | 1368 +++++ .../DxeImageVerificationLib.h | 201 + .../DxeImageVerificationLib.inf | 73 + .../DxeTpmMeasureBootLib.c | 830 ++++ .../DxeTpmMeasureBootLib.inf | 54 + .../PlatformSecureLibNull.c | 39 + .../PlatformSecureLibNull.inf | 33 + SecurityPkg/Library/TpmCommLib/CommonHeader.h | 29 + SecurityPkg/Library/TpmCommLib/TisPc.c | 180 + SecurityPkg/Library/TpmCommLib/TpmComm.c | 50 + SecurityPkg/Library/TpmCommLib/TpmCommLib.inf | 46 + SecurityPkg/SecurityPkg.dec | 122 + SecurityPkg/SecurityPkg.dsc | 125 + .../Tcg/MemoryOverwriteControl/TcgMor.c | 82 + .../Tcg/MemoryOverwriteControl/TcgMor.h | 27 + .../Tcg/MemoryOverwriteControl/TcgMor.inf | 50 + .../PhysicalPresenceDxe/PhysicalPresence.c | 1115 +++++ .../PhysicalPresenceDxe/PhysicalPresence.h | 38 + .../PhysicalPresenceDxe.inf | 61 + .../PhysicalPresenceStrings.uni | Bin 0 -> 8304 bytes .../PhysicalPresencePei/PhysicalPresencePei.c | 134 + .../PhysicalPresencePei.inf | 55 + SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr | 114 + .../Tcg/TcgConfigDxe/TcgConfigDriver.c | 147 + SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf | 75 + SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c | 555 +++ SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h | 195 + .../Tcg/TcgConfigDxe/TcgConfigNvData.h | 48 + .../Tcg/TcgConfigDxe/TcgConfigStrings.uni | Bin 0 -> 5016 bytes SecurityPkg/Tcg/TcgDxe/TcgDxe.c | 1212 +++++ SecurityPkg/Tcg/TcgDxe/TcgDxe.inf | 70 + SecurityPkg/Tcg/TcgDxe/TisDxe.c | 432 ++ SecurityPkg/Tcg/TcgDxe/TpmComm.c | 163 + SecurityPkg/Tcg/TcgDxe/TpmComm.h | 99 + SecurityPkg/Tcg/TcgPei/TcgPei.c | 593 +++ SecurityPkg/Tcg/TcgPei/TcgPei.inf | 67 + SecurityPkg/Tcg/TcgPei/TisPei.c | 160 + SecurityPkg/Tcg/TcgPei/TpmComm.c | 272 + SecurityPkg/Tcg/TcgPei/TpmComm.h | 163 + SecurityPkg/Tcg/TcgSmm/TcgSmm.c | 455 ++ SecurityPkg/Tcg/TcgSmm/TcgSmm.inf | 56 + SecurityPkg/Tcg/TcgSmm/Tpm.asl | 354 ++ .../PwdCredentialProvider.c | 1422 ++++++ .../PwdCredentialProvider.h | 354 ++ .../PwdCredentialProviderData.h | 33 + .../PwdCredentialProviderDxe.inf | 53 + .../PwdCredentialProviderStrings.uni | Bin 0 -> 5128 bytes .../PwdCredentialProviderVfr.Vfr | 35 + .../UsbCredentialProvider.c | 1407 ++++++ .../UsbCredentialProvider.h | 354 ++ .../UsbCredentialProviderDxe.inf | 58 + .../UsbCredentialProviderStrings.uni | Bin 0 -> 3556 bytes .../LoadDeferredImage.c | 148 + .../UserIdentifyManager.c | 4381 +++++++++++++++++ .../UserIdentifyManager.h | 413 ++ .../UserIdentifyManagerData.h | 42 + .../UserIdentifyManagerDxe.inf | 62 + .../UserIdentifyManagerStrings.uni | Bin 0 -> 2696 bytes .../UserIdentifyManagerVfr.Vfr | 44 + .../UserProfileManagerDxe/UserProfileAdd.c | 372 ++ .../UserProfileManagerDxe/UserProfileDelete.c | 314 ++ .../UserProfileManager.c | 806 +++ .../UserProfileManager.h | 387 ++ .../UserProfileManagerData.h | 161 + .../UserProfileManagerDxe.inf | 60 + .../UserProfileManagerStrings.uni | Bin 0 -> 21532 bytes .../UserProfileManagerVfr.Vfr | 247 + .../UserProfileManagerDxe/UserProfileModify.c | 2511 ++++++++++ .../EsalVariableDxeSal/AuthService.c | 882 ++++ .../EsalVariableDxeSal/AuthService.h | 151 + .../EsalVariableDxeSal/EsalVariableDxeSal.inf | 85 + .../EsalVariableDxeSal/InitVariable.c | 245 + .../EsalVariableDxeSal/Reclaim.c | 262 + .../EsalVariableDxeSal/Variable.c | 3198 ++++++++++++ .../EsalVariableDxeSal/Variable.h | 496 ++ .../VariableAuthenticated/Pei/Variable.c | 671 +++ .../VariableAuthenticated/Pei/Variable.h | 128 + .../VariableAuthenticated/Pei/VariablePei.inf | 64 + .../RuntimeDxe/AuthService.c | 1205 +++++ .../RuntimeDxe/AuthService.h | 209 + .../RuntimeDxe/Reclaim.c | 172 + .../RuntimeDxe/Variable.c | 2618 ++++++++++ .../RuntimeDxe/Variable.h | 491 ++ .../RuntimeDxe/VariableDxe.c | 433 ++ .../RuntimeDxe/VariableRuntimeDxe.inf | 98 + .../RuntimeDxe/VariableSmm.c | 587 +++ .../RuntimeDxe/VariableSmm.inf | 96 + .../RuntimeDxe/VariableSmmRuntimeDxe.c | 651 +++ .../RuntimeDxe/VariableSmmRuntimeDxe.inf | 68 + 102 files changed, 38487 insertions(+) create mode 100644 SecurityPkg/Application/VariableInfo/VariableInfo.c create mode 100644 SecurityPkg/Application/VariableInfo/VariableInfo.inf create mode 100644 SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h create mode 100644 SecurityPkg/Include/Guid/PhysicalPresenceData.h create mode 100644 SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h create mode 100644 SecurityPkg/Include/Guid/TcgEventHob.h create mode 100644 SecurityPkg/Include/Library/PlatformSecureLib.h create mode 100644 SecurityPkg/Include/Library/TpmCommLib.h create mode 100644 SecurityPkg/Include/Ppi/LockPhysicalPresence.h create mode 100644 SecurityPkg/Include/Ppi/TpmInitialized.h create mode 100644 SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c create mode 100644 SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h create mode 100644 SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf create mode 100644 SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c create mode 100644 SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h create mode 100644 SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c create mode 100644 SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf create mode 100644 SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c create mode 100644 SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf create mode 100644 SecurityPkg/Library/TpmCommLib/CommonHeader.h create mode 100644 SecurityPkg/Library/TpmCommLib/TisPc.c create mode 100644 SecurityPkg/Library/TpmCommLib/TpmComm.c create mode 100644 SecurityPkg/Library/TpmCommLib/TpmCommLib.inf create mode 100644 SecurityPkg/SecurityPkg.dec create mode 100644 SecurityPkg/SecurityPkg.dsc create mode 100644 SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c create mode 100644 SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h create mode 100644 SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf create mode 100644 SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c create mode 100644 SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h create mode 100644 SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf create mode 100644 SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni create mode 100644 SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c create mode 100644 SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf create mode 100644 SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr create mode 100644 SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c create mode 100644 SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf create mode 100644 SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c create mode 100644 SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h create mode 100644 SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h create mode 100644 SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni create mode 100644 SecurityPkg/Tcg/TcgDxe/TcgDxe.c create mode 100644 SecurityPkg/Tcg/TcgDxe/TcgDxe.inf create mode 100644 SecurityPkg/Tcg/TcgDxe/TisDxe.c create mode 100644 SecurityPkg/Tcg/TcgDxe/TpmComm.c create mode 100644 SecurityPkg/Tcg/TcgDxe/TpmComm.h create mode 100644 SecurityPkg/Tcg/TcgPei/TcgPei.c create mode 100644 SecurityPkg/Tcg/TcgPei/TcgPei.inf create mode 100644 SecurityPkg/Tcg/TcgPei/TisPei.c create mode 100644 SecurityPkg/Tcg/TcgPei/TpmComm.c create mode 100644 SecurityPkg/Tcg/TcgPei/TpmComm.h create mode 100644 SecurityPkg/Tcg/TcgSmm/TcgSmm.c create mode 100644 SecurityPkg/Tcg/TcgSmm/TcgSmm.inf create mode 100644 SecurityPkg/Tcg/TcgSmm/Tpm.asl create mode 100644 SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c create mode 100644 SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h create mode 100644 SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h create mode 100644 SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf create mode 100644 SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni create mode 100644 SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr create mode 100644 SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c create mode 100644 SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h create mode 100644 SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf create mode 100644 SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni create mode 100644 SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c create mode 100644 SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c create mode 100644 SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h create mode 100644 SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h create mode 100644 SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf create mode 100644 SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni create mode 100644 SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr create mode 100644 SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c create mode 100644 SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c create mode 100644 SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c create mode 100644 SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h create mode 100644 SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h create mode 100644 SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf create mode 100644 SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni create mode 100644 SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr create mode 100644 SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c create mode 100644 SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c create mode 100644 SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h create mode 100644 SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf create mode 100644 SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c create mode 100644 SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c create mode 100644 SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c create mode 100644 SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h create mode 100644 SecurityPkg/VariableAuthenticated/Pei/Variable.c create mode 100644 SecurityPkg/VariableAuthenticated/Pei/Variable.h create mode 100644 SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.h create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/Reclaim.c create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c create mode 100644 SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf diff --git a/SecurityPkg/Application/VariableInfo/VariableInfo.c b/SecurityPkg/Application/VariableInfo/VariableInfo.c new file mode 100644 index 0000000000..418cec3e5b --- /dev/null +++ b/SecurityPkg/Application/VariableInfo/VariableInfo.c @@ -0,0 +1,268 @@ +/** @file + If the Variable services have PcdVariableCollectStatistics set to TRUE then + this utility will print out the statistics information. You can use console + redirection to capture the data. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define EFI_VARIABLE_GUID \ + { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } } + +EFI_GUID mEfiVariableGuid = EFI_VARIABLE_GUID; +EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL; + +/** + + This function get the variable statistics data from SMM variable driver. + + @param[in, out] SmmCommunicateHeader In input, a pointer to a collection of data that will + be passed into an SMM environment. In output, a pointer + to a collection of data that comes from an SMM environment. + @param[in, out] SmmCommunicateSize The size of the SmmCommunicateHeader. + + @retval EFI_SUCCESS Get the statistics data information. + @retval EFI_NOT_FOUND Not found. + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +GetVariableStatisticsData ( + IN OUT EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader, + IN OUT UINTN *SmmCommunicateSize + ) +{ + EFI_STATUS Status; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + + CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid); + SmmCommunicateHeader->MessageLength = *SmmCommunicateSize - OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data); + + SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) &SmmCommunicateHeader->Data[0]; + SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_STATISTICS; + + Status = mSmmCommunication->Communicate (mSmmCommunication, SmmCommunicateHeader, SmmCommunicateSize); + ASSERT_EFI_ERROR (Status); + + Status = SmmVariableFunctionHeader->ReturnStatus; + return Status; +} + + +/** + + This function get and print the variable statistics data from SMM variable driver. + + @retval EFI_SUCCESS Print the statistics information successfully. + @retval EFI_NOT_FOUND Not found the statistics information. + +**/ +EFI_STATUS +PrintInfoFromSmm ( + VOID + ) +{ + EFI_STATUS Status; + VARIABLE_INFO_ENTRY *VariableInfo; + EFI_SMM_COMMUNICATE_HEADER *CommBuffer; + UINTN RealCommSize; + UINTN CommSize; + SMM_VARIABLE_COMMUNICATE_HEADER *FunctionHeader; + EFI_SMM_VARIABLE_PROTOCOL *Smmvariable; + + + Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &Smmvariable); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication); + if (EFI_ERROR (Status)) { + return Status; + } + + CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; + RealCommSize = CommSize; + CommBuffer = AllocateZeroPool (CommSize); + ASSERT (CommBuffer != NULL); + + Print (L"Non-Volatile SMM Variables:\n"); + do { + Status = GetVariableStatisticsData (CommBuffer, &CommSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + FreePool (CommBuffer); + CommBuffer = AllocateZeroPool (CommSize); + ASSERT (CommBuffer != NULL); + RealCommSize = CommSize; + Status = GetVariableStatisticsData (CommBuffer, &CommSize); + } + + if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) { + break; + } + + if (CommSize < RealCommSize) { + CommSize = RealCommSize; + } + + FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data; + VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data; + + if (!VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + (CHAR16 *)(VariableInfo + 1) + ); + } + } while (TRUE); + + Print (L"Volatile SMM Variables:\n"); + ZeroMem (CommBuffer, CommSize); + do { + Status = GetVariableStatisticsData (CommBuffer, &CommSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + FreePool (CommBuffer); + CommBuffer = AllocateZeroPool (CommSize); + ASSERT (CommBuffer != NULL); + RealCommSize = CommSize; + Status = GetVariableStatisticsData (CommBuffer, &CommSize); + } + + if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) { + break; + } + + if (CommSize < RealCommSize) { + CommSize = RealCommSize; + } + + FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data; + VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data; + + if (VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + (CHAR16 *)(VariableInfo + 1) + ); + } + } while (TRUE); + + FreePool (CommBuffer); + return Status; +} + +/** + The user Entry Point for Application. The user code starts with this function + as the real entry point for the image goes into a library that calls this + function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VARIABLE_INFO_ENTRY *VariableInfo; + VARIABLE_INFO_ENTRY *Entry; + + Status = EfiGetSystemConfigurationTable (&mEfiVariableGuid, (VOID **)&Entry); + if (EFI_ERROR (Status) || (Entry == NULL)) { + Status = EfiGetSystemConfigurationTable (&gEfiAuthenticatedVariableGuid, (VOID **)&Entry); + } + + if (EFI_ERROR (Status) || (Entry == NULL)) { + Status = PrintInfoFromSmm (); + if (!EFI_ERROR (Status)) { + return Status; + } + } + + if (!EFI_ERROR (Status) && (Entry != NULL)) { + Print (L"Non-Volatile EFI Variables:\n"); + VariableInfo = Entry; + do { + if (!VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + VariableInfo->Name + ); + } + + VariableInfo = VariableInfo->Next; + } while (VariableInfo != NULL); + + Print (L"Volatile EFI Variables:\n"); + VariableInfo = Entry; + do { + if (VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + VariableInfo->Name + ); + } + VariableInfo = VariableInfo->Next; + } while (VariableInfo != NULL); + + } else { + Print (L"Warning: Variable Dxe driver doesn't enable the feature of statistical information!\n"); + Print (L"If you want to see this info, please:\n"); + Print (L" 1. Set PcdVariableCollectStatistics as TRUE\n"); + Print (L" 2. Rebuild Variable Dxe driver\n"); + Print (L" 3. Run \"VariableInfo\" cmd again\n"); + } + + return Status; +} diff --git a/SecurityPkg/Application/VariableInfo/VariableInfo.inf b/SecurityPkg/Application/VariableInfo/VariableInfo.inf new file mode 100644 index 0000000000..a247d53ceb --- /dev/null +++ b/SecurityPkg/Application/VariableInfo/VariableInfo.inf @@ -0,0 +1,54 @@ +## @file +# This is a shell application that will display statistical information +# about variable usage. +# Note that if Variable Dxe driver doesn't enable the feature by setting +# PcdVariableCollectStatistics as TRUE, The application will not display +# variable statistical information. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VariableInfo + FILE_GUID = B9EF901F-A2A2-4fc8-8D2B-3A2E07B301CC + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + ENTRY_POINT = UefiMain + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + VariableInfo.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + UefiApplicationEntryPoint + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + MemoryAllocationLib + +[Protocols] + gEfiSmmCommunicationProtocolGuid + gEfiSmmVariableProtocolGuid + +[Guids] + gEfiAuthenticatedVariableGuid ## CONSUMES ## Configuration Table Guid + diff --git a/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h b/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h new file mode 100644 index 0000000000..245339c3df --- /dev/null +++ b/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h @@ -0,0 +1,174 @@ +/** @file + The variable data structures are related to EDKII-specific + implementation of UEFI authenticated variables. + AuthenticatedVariableFormat.h defines variable data headers + and variable storage region headers. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __AUTHENTICATED_VARIABLE_FORMAT_H__ +#define __AUTHENTICATED_VARIABLE_FORMAT_H__ + +#define EFI_AUTHENTICATED_VARIABLE_GUID \ + { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } } + +extern EFI_GUID gEfiAuthenticatedVariableGuid; + +/// +/// Alignment of variable name and data, according to the architecture: +/// * For IA-32 and Intel(R) 64 architectures: 1. +/// * For IA-64 architecture: 8. +/// +#if defined (MDE_CPU_IPF) +#define ALIGNMENT 8 +#else +#define ALIGNMENT 1 +#endif + +// +// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement. +// +#if (ALIGNMENT == 1) +#define GET_PAD_SIZE(a) (0) +#else +#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1)) +#endif + +/// +/// Alignment of Variable Data Header in Variable Store region. +/// +#define HEADER_ALIGNMENT 4 +#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1))) + +/// +/// Status of Variable Store Region. +/// +typedef enum { + EfiRaw, + EfiValid, + EfiInvalid, + EfiUnknown +} VARIABLE_STORE_STATUS; + +#pragma pack(1) + +#define VARIABLE_STORE_SIGNATURE EFI_AUTHENTICATED_VARIABLE_GUID + +/// +/// Variable Store Header Format and State. +/// +#define VARIABLE_STORE_FORMATTED 0x5a +#define VARIABLE_STORE_HEALTHY 0xfe + +/// +/// Variable Store region header. +/// +typedef struct { + /// + /// Variable store region signature. + /// + EFI_GUID Signature; + /// + /// Size of entire variable store, + /// including size of variable store header but not including the size of FvHeader. + /// + UINT32 Size; + /// + /// Variable region format state. + /// + UINT8 Format; + /// + /// Variable region healthy state. + /// + UINT8 State; + UINT16 Reserved; + UINT32 Reserved1; +} VARIABLE_STORE_HEADER; + +/// +/// Variable data start flag. +/// +#define VARIABLE_DATA 0x55AA + +/// +/// Variable State flags. +/// +#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition. +#define VAR_DELETED 0xfd ///< Variable is obsolete. +#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid. +#define VAR_ADDED 0x3f ///< Variable has been completely added. + +/// +/// Single Variable Data Header Structure. +/// +typedef struct { + /// + /// Variable Data Start Flag. + /// + UINT16 StartId; + /// + /// Variable State defined above. + /// + UINT8 State; + UINT8 Reserved; + /// + /// Attributes of variable defined in UEFI specification. + /// + UINT32 Attributes; + /// + /// Associated monotonic count value against replay attack. + /// + UINT64 MonotonicCount; + /// + /// Associated TimeStamp value against replay attack. + /// + EFI_TIME TimeStamp; + /// + /// Index of associated public key in database. + /// + UINT32 PubKeyIndex; + /// + /// Size of variable null-terminated Unicode string name. + /// + UINT32 NameSize; + /// + /// Size of the variable data without this header. + /// + UINT32 DataSize; + /// + /// A unique identifier for the vendor that produces and consumes this varaible. + /// + EFI_GUID VendorGuid; +} VARIABLE_HEADER; + +#pragma pack() + +typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY; + +/// +/// This structure contains the variable list that is put in EFI system table. +/// The variable driver collects all variables that were used at boot service time and produces this list. +/// This is an optional feature to dump all used variables in shell environment. +/// +struct _VARIABLE_INFO_ENTRY { + VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry. + EFI_GUID VendorGuid; ///< Guid of Variable. + CHAR16 *Name; ///< Name of Variable. + UINT32 Attributes; ///< Attributes of variable defined in UEFI spec. + UINT32 ReadCount; ///< Number of times to read this variable. + UINT32 WriteCount; ///< Number of times to write this variable. + UINT32 DeleteCount; ///< Number of times to delete this variable. + UINT32 CacheCount; ///< Number of times that cache hits this variable. + BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile. +}; + +#endif // __AUTHENTICATED_VARIABLE_FORMAT_H__ diff --git a/SecurityPkg/Include/Guid/PhysicalPresenceData.h b/SecurityPkg/Include/Guid/PhysicalPresenceData.h new file mode 100644 index 0000000000..1ae8095e54 --- /dev/null +++ b/SecurityPkg/Include/Guid/PhysicalPresenceData.h @@ -0,0 +1,76 @@ +/** @file + Define the variable data structures used for TCG physical presence. + The TPM request from firmware or OS is saved to variable. And it is + cleared after it is processed in the next boot cycle. The TPM response + is saved to variable. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PHYSICAL_PRESENCE_DATA_GUID_H__ +#define __PHYSICAL_PRESENCE_DATA_GUID_H__ + +#define EFI_PHYSICAL_PRESENCE_DATA_GUID \ + { \ + 0xf6499b1, 0xe9ad, 0x493d, { 0xb9, 0xc2, 0x2f, 0x90, 0x81, 0x5c, 0x6c, 0xbc }\ + } + +#define PHYSICAL_PRESENCE_VARIABLE L"PhysicalPresence" + +typedef struct { + UINT8 PPRequest; ///< Physical Presence request command. + UINT8 LastPPRequest; + UINT32 PPResponse; + UINT8 Flags; +} EFI_PHYSICAL_PRESENCE; + +// +// The definition bit of the flags +// +#define FLAG_NO_PPI_PROVISION BIT0 +#define FLAG_NO_PPI_CLEAR BIT1 +#define FLAG_NO_PPI_MAINTENANCE BIT2 +#define FLAG_RESET_TRACK BIT3 + +#define H2NS(x) ((((x) << 8) | ((x) >> 8)) & 0xffff) +#define H2NL(x) (H2NS ((x) >> 16) | (H2NS ((x) & 0xffff) << 16)) + +// +// The definition of physical presence operation actions +// +#define NO_ACTION 0 +#define ENABLE 1 +#define DISABLE 2 +#define ACTIVATE 3 +#define DEACTIVATE 4 +#define CLEAR 5 +#define ENABLE_ACTIVATE 6 +#define DEACTIVATE_DISABLE 7 +#define SET_OWNER_INSTALL_TRUE 8 +#define SET_OWNER_INSTALL_FALSE 9 +#define ENABLE_ACTIVATE_OWNER_TRUE 10 +#define DEACTIVATE_DISABLE_OWNER_FALSE 11 +#define DEFERRED_PP_UNOWNERED_FIELD_UPGRADE 12 +#define SET_OPERATOR_AUTH 13 +#define CLEAR_ENABLE_ACTIVATE 14 +#define SET_NO_PPI_PROVISION_FALSE 15 +#define SET_NO_PPI_PROVISION_TRUE 16 +#define SET_NO_PPI_CLEAR_FALSE 17 +#define SET_NO_PPI_CLEAR_TRUE 18 +#define SET_NO_PPI_MAINTENANCE_FALSE 19 +#define SET_NO_PPI_MAINTENANCE_TRUE 20 +#define ENABLE_ACTIVATE_CLEAR 21 +#define ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE 22 + +extern EFI_GUID gEfiPhysicalPresenceGuid; + +#endif + diff --git a/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h b/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h new file mode 100644 index 0000000000..b1b7666f18 --- /dev/null +++ b/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h @@ -0,0 +1,25 @@ +/** @file + GUID for SecurityPkg PCD Token Space. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _SECURITYPKG_TOKEN_SPACE_GUID_H_ +#define _SECURITYPKG_TOKEN_SPACE_GUID_H_ + +#define SECURITYPKG_TOKEN_SPACE_GUID \ + { \ + 0xd3fb176, 0x9569, 0x4d51, { 0xa3, 0xef, 0x7d, 0x61, 0xc6, 0x4f, 0xea, 0xba } \ + } + +extern EFI_GUID gEfiSecurityPkgTokenSpaceGuid; + +#endif diff --git a/SecurityPkg/Include/Guid/TcgEventHob.h b/SecurityPkg/Include/Guid/TcgEventHob.h new file mode 100644 index 0000000000..e88bd3a5f4 --- /dev/null +++ b/SecurityPkg/Include/Guid/TcgEventHob.h @@ -0,0 +1,30 @@ +/** @file + Defines the HOB GUID used to pass a TCG_PCR_EVENT from a TPM PEIM to + a TPM DXE Driver. A GUIDed HOB is generated for each measurement + made in the PEI Phase. + +Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _TCG_EVENT_HOB_H_ +#define _TCG_EVENT_HOB_H_ + +/// +/// The Global ID of a GUIDed HOB used to pass a TCG_PCR_EVENT from a TPM PEIM to a TPM DXE Driver. +/// +#define EFI_TCG_EVENT_HOB_GUID \ + { \ + 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 } \ + } + +extern EFI_GUID gTcgEventEntryHobGuid; + +#endif diff --git a/SecurityPkg/Include/Library/PlatformSecureLib.h b/SecurityPkg/Include/Library/PlatformSecureLib.h new file mode 100644 index 0000000000..c544719ba2 --- /dev/null +++ b/SecurityPkg/Include/Library/PlatformSecureLib.h @@ -0,0 +1,42 @@ +/** @file + Provides a secure platform-specific method to clear PK(Platform Key). + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PLATFORM_SECURE_LIB_H__ +#define __PLATFORM_SECURE_LIB_H__ + + +/** + + This function detects whether a secure platform-specific method to clear PK(Platform Key) + is configured by platform owner. This method is provided for users force to clear PK + in case incorrect enrollment mis-haps. + + UEFI231 spec chapter 27.5.2 stipulates: The platform key may also be cleared using + a secure platform-specific method. In this case, the global variable SetupMode + must also be updated to 1. + + NOTE THAT: This function cannot depend on any EFI Variable Service since they are + not available when this function is called in AuthenticateVariable driver. + + @retval TRUE The Platform owner wants to force clear PK. + @retval FALSE The Platform owner doesn't want to force clear PK. + +**/ +BOOLEAN +EFIAPI +ForceClearPK ( + VOID + ); + +#endif \ No newline at end of file diff --git a/SecurityPkg/Include/Library/TpmCommLib.h b/SecurityPkg/Include/Library/TpmCommLib.h new file mode 100644 index 0000000000..175dd8d9b6 --- /dev/null +++ b/SecurityPkg/Include/Library/TpmCommLib.h @@ -0,0 +1,286 @@ +/** @file + Ihis library is only intended to be used by TPM modules. + It provides basic TPM Interface Specification (TIS) and Command functions. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _TPM_COMM_LIB_H_ +#define _TPM_COMM_LIB_H_ + +#include + +typedef EFI_HANDLE TIS_TPM_HANDLE; + +/// +/// TPM register base address. +/// +#define TPM_BASE_ADDRESS 0xfed40000 + +// +// Set structure alignment to 1-byte +// +#pragma pack (1) + +// +// Register set map as specified in TIS specification Chapter 10 +// +typedef struct { + /// + /// Used to gain ownership for this particular port. + /// + UINT8 Access; // 0 + UINT8 Reserved1[7]; // 1 + /// + /// Controls interrupts. + /// + UINT32 IntEnable; // 8 + /// + /// SIRQ vector to be used by the TPM. + /// + UINT8 IntVector; // 0ch + UINT8 Reserved2[3]; // 0dh + /// + /// What caused interrupt. + /// + UINT32 IntSts; // 10h + /// + /// Shows which interrupts are supported by that particular TPM. + /// + UINT32 IntfCapability; // 14h + /// + /// Status Register. Provides status of the TPM. + /// + UINT8 Status; // 18h + /// + /// Number of consecutive writes that can be done to the TPM. + /// + UINT16 BurstCount; // 19h + UINT8 Reserved3[9]; + /// + /// Read or write FIFO, depending on transaction. + /// + UINT32 DataFifo; // 24 + UINT8 Reserved4[0xed8]; // 28h + /// + /// Vendor ID + /// + UINT16 Vid; // 0f00h + /// + /// Device ID + /// + UINT16 Did; // 0f02h + /// + /// Revision ID + /// + UINT8 Rid; // 0f04h + /// + /// TCG defined configuration registers. + /// + UINT8 TcgDefined[0x7b]; // 0f05h + /// + /// Alias to I/O legacy space. + /// + UINT32 LegacyAddress1; // 0f80h + /// + /// Additional 8 bits for I/O legacy space extension. + /// + UINT32 LegacyAddress1Ex; // 0f84h + /// + /// Alias to second I/O legacy space. + /// + UINT32 LegacyAddress2; // 0f88h + /// + /// Additional 8 bits for second I/O legacy space extension. + /// + UINT32 LegacyAddress2Ex; // 0f8ch + /// + /// Vendor-defined configuration registers. + /// + UINT8 VendorDefined[0x70];// 0f90h +} TIS_PC_REGISTERS; + +// +// Restore original structure alignment +// +#pragma pack () + +// +// Define pointer types used to access TIS registers on PC +// +typedef TIS_PC_REGISTERS *TIS_PC_REGISTERS_PTR; + +// +// TCG Platform Type based on TCG ACPI Specification Version 1.00 +// +#define TCG_PLATFORM_TYPE_CLIENT 0 +#define TCG_PLATFORM_TYPE_SERVER 1 + +// +// Define bits of ACCESS and STATUS registers +// + +/// +/// This bit is a 1 to indicate that the other bits in this register are valid. +/// +#define TIS_PC_VALID BIT7 +/// +/// Indicate that this locality is active. +/// +#define TIS_PC_ACC_ACTIVE BIT5 +/// +/// Set to 1 to indicate that this locality had the TPM taken away while +/// this locality had the TIS_PC_ACC_ACTIVE bit set. +/// +#define TIS_PC_ACC_SEIZED BIT4 +/// +/// Set to 1 to indicate that TPM MUST reset the +/// TIS_PC_ACC_ACTIVE bit and remove ownership for localities less than the +/// locality that is writing this bit. +/// +#define TIS_PC_ACC_SEIZE BIT3 +/// +/// When this bit is 1, another locality is requesting usage of the TPM. +/// +#define TIS_PC_ACC_PENDIND BIT2 +/// +/// Set to 1 to indicate that this locality is requesting to use TPM. +/// +#define TIS_PC_ACC_RQUUSE BIT1 +/// +/// A value of 1 indicates that a T/OS has not been established on the platform +/// +#define TIS_PC_ACC_ESTABLISH BIT0 + +/// +/// When this bit is 1, TPM is in the Ready state, +/// indicating it is ready to receive a new command. +/// +#define TIS_PC_STS_READY BIT6 +/// +/// Write a 1 to this bit to cause the TPM to execute that command. +/// +#define TIS_PC_STS_GO BIT5 +/// +/// This bit indicates that the TPM has data available as a response. +/// +#define TIS_PC_STS_DATA BIT4 +/// +/// The TPM sets this bit to a value of 1 when it expects another byte of data for a command. +/// +#define TIS_PC_STS_EXPECT BIT3 +/// +/// Writes a 1 to this bit to force the TPM to re-send the response. +/// +#define TIS_PC_STS_RETRY BIT1 + +// +// Default TimeOut value +// +#define TIS_TIMEOUT_B 2000 * 1000 // 2s +#define TIS_TIMEOUT_C 750 * 1000 // 750ms +#define TIS_TIMEOUT_D 750 * 1000 // 750ms + +// +// Max TPM command/reponse length +// +#define TPMCMDBUFLENGTH 1024 + +/** + Check whether the value of a TPM chip register satisfies the input BIT setting. + + @param[in] Register Address port of register to be checked. + @param[in] BitSet Check these data bits are set. + @param[in] BitClear Check these data bits are clear. + @param[in] TimeOut The max wait time (unit MicroSecond) when checking register. + + @retval EFI_SUCCESS The register satisfies the check bit. + @retval EFI_TIMEOUT The register can't run into the expected status in time. +**/ +EFI_STATUS +EFIAPI +TisPcWaitRegisterBits ( + IN UINT8 *Register, + IN UINT8 BitSet, + IN UINT8 BitClear, + IN UINT32 TimeOut + ); + +/** + Get BurstCount by reading the burstCount field of a TIS regiger + in the time of default TIS_TIMEOUT_D. + + @param[in] TisReg Pointer to TIS register. + @param[out] BurstCount Pointer to a buffer to store the got BurstConut. + + @retval EFI_SUCCESS Get BurstCount. + @retval EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL. + @retval EFI_TIMEOUT BurstCount can't be got in time. +**/ +EFI_STATUS +EFIAPI +TisPcReadBurstCount ( + IN TIS_PC_REGISTERS_PTR TisReg, + OUT UINT16 *BurstCount + ); + +/** + Set TPM chip to ready state by sending ready command TIS_PC_STS_READY + to Status Register in time. + + @param[in] TisReg Pointer to TIS register. + + @retval EFI_SUCCESS TPM chip enters into ready state. + @retval EFI_INVALID_PARAMETER TisReg is NULL. + @retval EFI_TIMEOUT TPM chip can't be set to ready state in time. +**/ +EFI_STATUS +EFIAPI +TisPcPrepareCommand ( + IN TIS_PC_REGISTERS_PTR TisReg + ); + +/** + Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE + to ACCESS Register in the time of default TIS_TIMEOUT_D. + + @param[in] TisReg Pointer to TIS register. + + @retval EFI_SUCCESS Get the control of TPM chip. + @retval EFI_INVALID_PARAMETER TisReg is NULL. + @retval EFI_NOT_FOUND TPM chip doesn't exit. + @retval EFI_TIMEOUT Can't get the TPM control in time. +**/ +EFI_STATUS +EFIAPI +TisPcRequestUseTpm ( + IN TIS_PC_REGISTERS_PTR TisReg + ); + +/** + Single function calculates SHA1 digest value for all raw data. It + combines Sha1Init(), Sha1Update() and Sha1Final(). + + @param[in] Data Raw data to be digested. + @param[in] DataLen Size of the raw data. + @param[out] Digest Pointer to a buffer that stores the final digest. + + @retval EFI_SUCCESS Always successfully calculate the final digest. +**/ +EFI_STATUS +EFIAPI +TpmCommHashAll ( + IN CONST UINT8 *Data, + IN UINTN DataLen, + OUT TPM_DIGEST *Digest + ); + +#endif diff --git a/SecurityPkg/Include/Ppi/LockPhysicalPresence.h b/SecurityPkg/Include/Ppi/LockPhysicalPresence.h new file mode 100644 index 0000000000..0ae3b7b0ab --- /dev/null +++ b/SecurityPkg/Include/Ppi/LockPhysicalPresence.h @@ -0,0 +1,60 @@ +/** @file + This file defines the lock physical Presence PPI. This PPI is + produced by a platform specific PEIM and consumed by the TPM + PEIM. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PEI_LOCK_PHYSICAL_PRESENCE_H__ +#define __PEI_LOCK_PHYSICAL_PRESENCE_H__ + +/// +/// Global ID for the PEI_LOCK_PHYSICAL_PRESENCE_PPI_GUID. +/// +#define PEI_LOCK_PHYSICAL_PRESENCE_PPI_GUID \ + { \ + 0xef9aefe5, 0x2bd3, 0x4031, { 0xaf, 0x7d, 0x5e, 0xfe, 0x5a, 0xbb, 0x9a, 0xd } \ + } + +/// +/// Forward declaration for the PEI_LOCK_PHYSICAL_PRESENCE_PPI +/// +typedef struct _PEI_LOCK_PHYSICAL_PRESENCE_PPI PEI_LOCK_PHYSICAL_PRESENCE_PPI; + +/** + This interface returns whether TPM physical presence needs be locked. + + @param[in] PeiServices The pointer to the PEI Services Table. + + @retval TRUE The TPM physical presence should be locked. + @retval FALSE The TPM physical presence cannot be locked. + +**/ +typedef +BOOLEAN +(EFIAPI *PEI_LOCK_PHYSICAL_PRESENCE)( + IN CONST EFI_PEI_SERVICES **PeiServices +); + +/// +/// This service abstracts TPM physical presence lock interface. It is necessary for +/// safety to convey this information to the TPM driver so that TPM physical presence +/// can be locked as early as possible. This PPI is produced by a platform specific +/// PEIM and consumed by the TPM PEIM. +/// +struct _PEI_LOCK_PHYSICAL_PRESENCE_PPI { + PEI_LOCK_PHYSICAL_PRESENCE LockPhysicalPresence; +}; + +extern EFI_GUID gPeiLockPhysicalPresencePpiGuid; + +#endif // __PEI_LOCK_PHYSICAL_PRESENCE_H__ \ No newline at end of file diff --git a/SecurityPkg/Include/Ppi/TpmInitialized.h b/SecurityPkg/Include/Ppi/TpmInitialized.h new file mode 100644 index 0000000000..dbbd415989 --- /dev/null +++ b/SecurityPkg/Include/Ppi/TpmInitialized.h @@ -0,0 +1,30 @@ +/** @file + Tag GUID that must be installed by the TPM PEIM after the TPM hardware is + initialized. PEIMs that must execute after TPM hardware initialization + may use this GUID in their dependency expressions. + +Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PEI_TPM_INITIALIZED_PPI_H_ +#define _PEI_TPM_INITIALIZED_PPI_H_ + +/// +/// Global ID for the PEI_TPM_INITIALIZED_PPI which always uses a NULL interface. +/// +#define PEI_TPM_INITIALIZED_PPI_GUID \ + { \ + 0xe9db0d58, 0xd48d, 0x47f6, 0x9c, 0x6e, 0x6f, 0x40, 0xe8, 0x6c, 0x7b, 0x41 \ + } + +extern EFI_GUID gPeiTpmInitializedPpiGuid; + +#endif diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c new file mode 100644 index 0000000000..f7fe594060 --- /dev/null +++ b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c @@ -0,0 +1,858 @@ +/** @file + Implement defer image load services for user identification in UEFI2.2. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "DxeDeferImageLoadLib.h" + +// +// Handle for the Deferred Image Load Protocol instance produced by this driver. +// +EFI_HANDLE mDeferredImageHandle = NULL; +BOOLEAN mIsProtocolInstalled = FALSE; +EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL; +DEFERRED_IMAGE_TABLE mDeferredImage = { + 0, // Deferred image count + NULL // The deferred image info +}; + +EFI_DEFERRED_IMAGE_LOAD_PROTOCOL gDeferredImageLoad = { + GetDefferedImageInfo +}; + +/** + Get the image type. + + @param[in] File This is a pointer to the device path of the file + that is being dispatched. + + @return UINT32 Image Type + +**/ +UINT32 +GetFileType ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *File + ) +{ + EFI_STATUS Status; + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + + // + // First check to see if File is from a Firmware Volume + // + DeviceHandle = NULL; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + Status = gBS->LocateDevicePath ( + &gEfiFirmwareVolume2ProtocolGuid, + &TempDevicePath, + &DeviceHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + DeviceHandle, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return IMAGE_FROM_FV; + } + } + + // + // Next check to see if File is from a Block I/O device + // + DeviceHandle = NULL; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + Status = gBS->LocateDevicePath ( + &gEfiBlockIoProtocolGuid, + &TempDevicePath, + &DeviceHandle + ); + if (!EFI_ERROR (Status)) { + BlockIo = NULL; + Status = gBS->OpenProtocol ( + DeviceHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status) && BlockIo != NULL) { + if (BlockIo->Media != NULL) { + if (BlockIo->Media->RemovableMedia) { + // + // Block I/O is present and specifies the media is removable + // + return IMAGE_FROM_REMOVABLE_MEDIA; + } else { + // + // Block I/O is present and specifies the media is not removable + // + return IMAGE_FROM_FIXED_MEDIA; + } + } + } + } + + // + // File is not in a Firmware Volume or on a Block I/O device, so check to see if + // the device path supports the Simple File System Protocol. + // + DeviceHandle = NULL; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + &TempDevicePath, + &DeviceHandle + ); + if (!EFI_ERROR (Status)) { + // + // Simple File System is present without Block I/O, so assume media is fixed. + // + return IMAGE_FROM_FIXED_MEDIA; + } + + // + // File is not from an FV, Block I/O or Simple File System, so the only options + // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC. + // + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + while (!IsDevicePathEndType (TempDevicePath)) { + switch (DevicePathType (TempDevicePath)) { + + case MEDIA_DEVICE_PATH: + if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) { + return IMAGE_FROM_OPTION_ROM; + } + break; + + case MESSAGING_DEVICE_PATH: + if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) { + return IMAGE_FROM_REMOVABLE_MEDIA; + } + break; + + default: + break; + } + TempDevicePath = NextDevicePathNode (TempDevicePath); + } + return IMAGE_UNKNOWN; +} + + +/** + Get current user's access right. + + @param[out] AccessControl Points to the user's access control data, the + caller should free data buffer. + @param[in] AccessType The type of user access control. + + @retval EFI_SUCCESS Get current user access control successfully + @retval others Fail to get current user access control + +**/ +EFI_STATUS +GetAccessControl ( + OUT EFI_USER_INFO_ACCESS_CONTROL **AccessControl, + IN UINT32 AccessType + ) +{ + EFI_STATUS Status; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO *Info; + UINTN InfoSize; + EFI_USER_INFO_ACCESS_CONTROL *Access; + EFI_USER_PROFILE_HANDLE CurrentUser; + UINTN CheckLen; + EFI_USER_MANAGER_PROTOCOL *UserManager; + + CurrentUser = NULL; + Status = gBS->LocateProtocol ( + &gEfiUserManagerProtocolGuid, + NULL, + (VOID **) &UserManager + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Get current user access information. + // + UserManager->Current (UserManager, &CurrentUser); + + UserInfo = NULL; + Info = NULL; + InfoSize = 0; + while (TRUE) { + // + // Get next user information. + // + Status = UserManager->GetNextInfo (UserManager, CurrentUser, &UserInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = UserManager->GetInfo ( + UserManager, + CurrentUser, + UserInfo, + Info, + &InfoSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + if (Info != NULL) { + FreePool (Info); + } + Info = AllocateZeroPool (InfoSize); + ASSERT (Info != NULL); + Status = UserManager->GetInfo ( + UserManager, + CurrentUser, + UserInfo, + Info, + &InfoSize + ); + } + + if (EFI_ERROR (Status)) { + break; + } + + ASSERT (Info != NULL); + if (Info->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) { + continue; + } + + // + // Get specified access information. + // + CheckLen = 0; + while (CheckLen < Info->InfoSize - sizeof (EFI_USER_INFO)) { + Access = (EFI_USER_INFO_ACCESS_CONTROL *) ((UINT8 *) (Info + 1) + CheckLen); + if ((Access->Type == AccessType)) { + *AccessControl = AllocateZeroPool (Access->Size); + ASSERT (*AccessControl != NULL); + CopyMem (*AccessControl, Access, Access->Size); + FreePool (Info); + return EFI_SUCCESS; + } + CheckLen += Access->Size; + } + } + + if (Info != NULL) { + FreePool (Info); + } + return EFI_NOT_FOUND; +} + + +/** + Convert the '/' to '\' in the specified string. + + @param[in, out] Str Points to the string to convert. + +**/ +VOID +ConvertDPStr ( + IN OUT EFI_STRING Str + ) +{ + INTN Count; + INTN Index; + + Count = StrSize(Str) / 2 - 1; + + if (Count < 4) { + return; + } + + // + // Convert device path string. + // + Index = Count - 1; + while (Index > 0) { + // + // Find the last '/'. + // + for (Index = Count - 1; Index > 0; Index--) { + if (Str[Index] == L'/') + break; + } + + // + // Check next char. + // + if (Str[Index + 1] == L'\\') + return; + + Str[Index] = L'\\'; + + // + // Check previous char. + // + if ((Index > 0) && (Str[Index - 1] == L'\\')) { + CopyMem (&Str[Index - 1], &Str[Index], (UINTN) ((Count - Index + 1) * sizeof (CHAR16))); + return; + } + Index--; + } +} + + +/** + Check whether the DevicePath2 is identical with DevicePath1, or identical with + DevicePath1's child device path. + + If DevicePath2 is identical with DevicePath1, or with DevicePath1's child device + path, then TRUE returned. Otherwise, FALSE is returned. + + If DevicePath1 is NULL, then ASSERT(). + If DevicePath2 is NULL, then ASSERT(). + + @param[in] DevicePath1 A pointer to a device path. + @param[in] DevicePath2 A pointer to a device path. + + @retval TRUE Two device paths are identical , or DevicePath2 is + DevicePath1's child device path. + @retval FALSE Two device paths are not identical, and DevicePath2 + is not DevicePath1's child device path. + +**/ +BOOLEAN +CheckDevicePath ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2 + ) +{ + EFI_STATUS Status; + EFI_STRING DevicePathStr1; + EFI_STRING DevicePathStr2; + UINTN StrLen1; + UINTN StrLen2; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathText; + BOOLEAN DevicePathEqual; + + ASSERT (DevicePath1 != NULL); + ASSERT (DevicePath2 != NULL); + + DevicePathEqual = FALSE; + DevicePathText = NULL; + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevicePathText + ); + ASSERT (Status == EFI_SUCCESS); + + // + // Get first device path string. + // + DevicePathStr1 = DevicePathText->ConvertDevicePathToText (DevicePath1, TRUE, TRUE); + ConvertDPStr (DevicePathStr1); + // + // Get second device path string. + // + DevicePathStr2 = DevicePathText->ConvertDevicePathToText (DevicePath2, TRUE, TRUE); + ConvertDPStr (DevicePathStr2); + + // + // Compare device path string. + // + StrLen1 = StrSize (DevicePathStr1); + StrLen2 = StrSize (DevicePathStr2); + if (StrLen1 > StrLen2) { + DevicePathEqual = FALSE; + goto Done; + } + + if (CompareMem (DevicePathStr1, DevicePathStr2, StrLen1) == 0) { + DevicePathEqual = TRUE; + } + +Done: + FreePool (DevicePathStr1); + FreePool (DevicePathStr2); + return DevicePathEqual; +} + + +/** + Check whether the image pointed to by DevicePath is in the device path list + specified by AccessType. + + @param[in] DevicePath Points to device path. + @param[in] AccessType The type of user access control. + + @retval TURE The DevicePath is in the specified List. + @retval FALSE The DevicePath is not in the specified List. + +**/ +BOOLEAN +IsDevicePathInList ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN UINT32 AccessType + ) +{ + EFI_STATUS Status; + EFI_USER_INFO_ACCESS_CONTROL *Access; + EFI_DEVICE_PATH_PROTOCOL *Path; + UINTN OffSet; + + Status = GetAccessControl (&Access, AccessType); + if (EFI_ERROR (Status)) { + return FALSE; + } + + OffSet = 0; + while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) { + Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet); + if (CheckDevicePath (Path, DevicePath)) { + // + // The device path is found in list. + // + FreePool (Access); + return TRUE; + } + OffSet += GetDevicePathSize (Path); + } + + FreePool (Access); + return FALSE; +} + + +/** + Check whether the image pointed to by DevicePath is permitted to load. + + @param[in] DevicePath Points to device path + + @retval TURE The image pointed by DevicePath is permitted to load. + @retval FALSE The image pointed by DevicePath is forbidden to load. + +**/ +BOOLEAN +VerifyDevicePath ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) { + // + // This access control overrides any restrictions put in place by the + // EFI_USER_INFO_ACCESS_FORBID_LOAD record. + // + return TRUE; + } + + if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) { + // + // The device path is found in the forbidden list. + // + return FALSE; + } + + return TRUE; +} + + +/** + Check the image pointed by DevicePath is a boot option or not. + + @param[in] DevicePath Points to device path. + + @retval TURE The image pointed by DevicePath is a boot option. + @retval FALSE The image pointed by DevicePath is not a boot option. + +**/ +BOOLEAN +IsBootOption ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + UINT16 *BootOrderList; + UINTN BootOrderListSize; + UINTN Index; + CHAR16 StrTemp[20]; + UINT8 *OptionBuffer; + UINT8 *OptionPtr; + EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath; + + // + // Get BootOrder + // + BootOrderListSize = 0; + BootOrderList = NULL; + Status = gRT->GetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + NULL, + &BootOrderListSize, + NULL + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + BootOrderList = AllocateZeroPool (BootOrderListSize); + ASSERT (BootOrderList != NULL); + Status = gRT->GetVariable ( + L"BootOrder", + &gEfiGlobalVariableGuid, + NULL, + &BootOrderListSize, + BootOrderList + ); + } + + if (EFI_ERROR (Status)) { + // + // No Boot option + // + return FALSE; + } + + OptionBuffer = NULL; + for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) { + // + // Try to find the DevicePath in BootOption + // + UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index); + OptionBuffer = GetEfiGlobalVariable (StrTemp); + if (OptionBuffer == NULL) { + continue; + } + + // + // Check whether the image is forbidden. + // + + OptionPtr = OptionBuffer; + // + // Skip attribute. + // + OptionPtr += sizeof (UINT32); + + // + // Skip device path length. + // + OptionPtr += sizeof (UINT16); + + // + // Skip descript string + // + OptionPtr += StrSize ((UINT16 *) OptionPtr); + + // + // Now OptionPtr points to Device Path. + // + OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) OptionPtr; + + if (CheckDevicePath (DevicePath, OptionDevicePath)) { + FreePool (OptionBuffer); + OptionBuffer = NULL; + return TRUE; + } + FreePool (OptionBuffer); + OptionBuffer = NULL; + } + + if (BootOrderList != NULL) { + FreePool (BootOrderList); + } + + return FALSE; +} + + +/** + Add the image info to a deferred image list. + + @param[in] ImageDevicePath A pointer to the device path of a image. + @param[in] Image Points to the first byte of the image, or NULL if the + image is not available. + @param[in] ImageSize The size of the image, or 0 if the image is not available. + +**/ +VOID +PutDefferedImageInfo ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath, + IN VOID *Image, + IN UINTN ImageSize + ) +{ + DEFERRED_IMAGE_INFO *CurImageInfo; + UINTN PathSize; + + // + // Expand memory for the new deferred image. + // + if (mDeferredImage.Count == 0) { + mDeferredImage.ImageInfo = AllocatePool (sizeof (DEFERRED_IMAGE_INFO)); + ASSERT (mDeferredImage.ImageInfo != NULL); + } else { + CurImageInfo = AllocatePool ((mDeferredImage.Count + 1) * sizeof (DEFERRED_IMAGE_INFO)); + ASSERT (CurImageInfo != NULL); + + CopyMem ( + CurImageInfo, + mDeferredImage.ImageInfo, + mDeferredImage.Count * sizeof (DEFERRED_IMAGE_INFO) + ); + FreePool (mDeferredImage.ImageInfo); + mDeferredImage.ImageInfo = CurImageInfo; + } + mDeferredImage.Count++; + + // + // Save the deferred image information. + // + CurImageInfo = &mDeferredImage.ImageInfo[mDeferredImage.Count - 1]; + PathSize = GetDevicePathSize (ImageDevicePath); + CurImageInfo->ImageDevicePath = AllocateZeroPool (PathSize); + ASSERT (CurImageInfo->ImageDevicePath != NULL); + CopyMem (CurImageInfo->ImageDevicePath, ImageDevicePath, PathSize); + + CurImageInfo->Image = Image; + CurImageInfo->ImageSize = ImageSize; + CurImageInfo->BootOption = IsBootOption (ImageDevicePath); +} + + +/** + Returns information about a deferred image. + + This function returns information about a single deferred image. The deferred images are + numbered consecutively, starting with 0. If there is no image which corresponds to + ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by + iteratively calling this function until EFI_NOT_FOUND is returned. + Image may be NULL and ImageSize set to 0 if the decision to defer execution was made + because of the location of the executable image, rather than its actual contents. + + @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL. + @param[in] ImageIndex Zero-based index of the deferred index. + @param[out] ImageDevicePath On return, points to a pointer to the device path of the image. + The device path should not be freed by the caller. + @param[out] Image On return, points to the first byte of the image or NULL if the + image is not available. The image should not be freed by the caller + unless LoadImage() has been successfully called. + @param[out] ImageSize On return, the size of the image, or 0 if the image is not available. + @param[out] BootOption On return, points to TRUE if the image was intended as a boot option + or FALSE if it was not intended as a boot option. + + @retval EFI_SUCCESS Image information returned successfully. + @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image. + @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or + BootOption is NULL. + +**/ +EFI_STATUS +EFIAPI +GetDefferedImageInfo ( + IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This, + IN UINTN ImageIndex, + OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath, + OUT VOID **Image, + OUT UINTN *ImageSize, + OUT BOOLEAN *BootOption + ) +{ + DEFERRED_IMAGE_INFO *ReqImageInfo; + + // + // Check the parameter. + // + + if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((ImageDevicePath == NULL) || (BootOption == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (ImageIndex >= mDeferredImage.Count) { + return EFI_NOT_FOUND; + } + + // + // Get the request deferred image. + // + ReqImageInfo = &mDeferredImage.ImageInfo[ImageIndex]; + + *ImageDevicePath = ReqImageInfo->ImageDevicePath; + *Image = ReqImageInfo->Image; + *ImageSize = ReqImageInfo->ImageSize; + *BootOption = ReqImageInfo->BootOption; + + return EFI_SUCCESS; +} + + +/** + Provides the service of deferring image load based on platform policy control, + and installs Deferred Image Load Protocol. + + @param[in] AuthenticationStatus This is the authentication status returned from the + security measurement services for the input file. + @param[in] File This is a pointer to the device path of the file that + is being dispatched. This will optionally be used for + logging. + @param[in] FileBuffer File buffer matches the input file device path. + @param[in] FileSize Size of File buffer matches the input file device path. + + @retval EFI_SUCCESS The file specified by File did authenticate, and the + platform policy dictates that the DXE Core may use File. + @retval EFI_INVALID_PARAMETER File is NULL. + @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and + the platform policy dictates that File should be placed + in the untrusted state. A file may be promoted from + the untrusted to the trusted state at a future time + with a call to the Trust() DXE Service. + @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and + the platform policy dictates that File should not be + used for any purpose. + +**/ +EFI_STATUS +EFIAPI +DxeDeferImageLoadHandler ( + IN UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File, + IN VOID *FileBuffer, + IN UINTN FileSize + ) + +{ + EFI_STATUS Status; + EFI_USER_PROFILE_HANDLE CurrentUser; + UINT32 Policy; + UINT32 FileType; + + if (File == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether user has a logon. + // + CurrentUser = NULL; + if (mUserManager != NULL) { + mUserManager->Current (mUserManager, &CurrentUser); + if (CurrentUser != NULL) { + // + // The user is logon; verify the FilePath by current user access policy. + // + if (!VerifyDevicePath (File)) { + DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n")); + return EFI_ACCESS_DENIED; + } + return EFI_SUCCESS; + } + } + + // + // Still no user logon. + // Check the file type and get policy setting. + // + FileType = GetFileType (File); + Policy = PcdGet32 (PcdDeferImageLoadPolicy); + if ((Policy & FileType) == FileType) { + // + // This file type is secure to load. + // + return EFI_SUCCESS; + } + + DEBUG ((EFI_D_ERROR, "[Security] No user identified, the image is deferred to load!\n")); + PutDefferedImageInfo (File, NULL, 0); + + // + // Install the Deferred Image Load Protocol onto a new handle. + // + if (!mIsProtocolInstalled) { + Status = gBS->InstallMultipleProtocolInterfaces ( + &mDeferredImageHandle, + &gEfiDeferredImageLoadProtocolGuid, + &gDeferredImageLoad, + NULL + ); + ASSERT_EFI_ERROR (Status); + mIsProtocolInstalled = TRUE; + } + + return EFI_ACCESS_DENIED; +} + +/** + Locate user manager protocol when user manager is installed. + + @param[in] Event The Event that is being processed, not used. + @param[in] Context Event Context, not used. + +**/ +VOID +EFIAPI +FindUserManagerProtocol ( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + gBS->LocateProtocol ( + &gEfiUserManagerProtocolGuid, + NULL, + (VOID **) &mUserManager + ); + +} + + +/** + Register security handler for deferred image load. + + @param[in] ImageHandle ImageHandle of the loaded driver. + @param[in] SystemTable Pointer to the EFI System Table. + + @retval EFI_SUCCESS The handlers were registered successfully. +**/ +EFI_STATUS +EFIAPI +DxeDeferImageLoadLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *Registration; + + // + // Register user manager notification function. + // + EfiCreateProtocolNotifyEvent ( + &gEfiUserManagerProtocolGuid, + TPL_CALLBACK, + FindUserManagerProtocol, + NULL, + &Registration + ); + + return RegisterSecurityHandler ( + DxeDeferImageLoadHandler, + EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD + ); +} + + diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h new file mode 100644 index 0000000000..52eb81b796 --- /dev/null +++ b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h @@ -0,0 +1,106 @@ +/** @file + The internal header file includes the common header files, defines + internal structure and functions used by DeferImageLoadLib. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __DEFER_IMAGE_LOAD_LIB_H__ +#define __DEFER_IMAGE_LOAD_LIB_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +// +// Image type definitions. +// +#define IMAGE_UNKNOWN 0x00000001 +#define IMAGE_FROM_FV 0x00000002 +#define IMAGE_FROM_OPTION_ROM 0x00000004 +#define IMAGE_FROM_REMOVABLE_MEDIA 0x00000008 +#define IMAGE_FROM_FIXED_MEDIA 0x00000010 + +// +// The struct to save the deferred image information. +// +typedef struct { + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; + VOID *Image; + UINTN ImageSize; + BOOLEAN BootOption; +} DEFERRED_IMAGE_INFO; + +// +// The table to save the deferred image item. +// +typedef struct { + UINTN Count; ///< deferred image count + DEFERRED_IMAGE_INFO *ImageInfo; ///< deferred image item +} DEFERRED_IMAGE_TABLE; + +/** + Returns information about a deferred image. + + This function returns information about a single deferred image. The deferred images are + numbered consecutively, starting with 0. If there is no image which corresponds to + ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by + iteratively calling this function until EFI_NOT_FOUND is returned. + Image may be NULL and ImageSize set to 0 if the decision to defer execution was made + because of the location of the executable image, rather than its actual contents. + + @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL. + @param[in] ImageIndex Zero-based index of the deferred index. + @param[out] ImageDevicePath On return, points to a pointer to the device path of the image. + The device path should not be freed by the caller. + @param[out] Image On return, points to the first byte of the image or NULL if the + image is not available. The image should not be freed by the caller + unless LoadImage() has been called successfully. + @param[out] ImageSize On return, the size of the image, or 0 if the image is not available. + @param[out] BootOption On return, points to TRUE if the image was intended as a boot option + or FALSE if it was not intended as a boot option. + + @retval EFI_SUCCESS Image information returned successfully. + @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image. + @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or + BootOption is NULL. + +**/ +EFI_STATUS +EFIAPI +GetDefferedImageInfo ( + IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This, + IN UINTN ImageIndex, + OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath, + OUT VOID **Image, + OUT UINTN *ImageSize, + OUT BOOLEAN *BootOption + ); + +#endif diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf new file mode 100644 index 0000000000..e16fe8dc04 --- /dev/null +++ b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf @@ -0,0 +1,62 @@ +## @file +# The library instance provides security service of deferring image load. +# +# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeDeferImageLoadLib + FILE_GUID = 5E2FAE1F-41DA-4fbd-BC81-603CE5CD8497 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION + CONSTRUCTOR = DxeDeferImageLoadLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + DxeDeferImageLoadLib.c + DxeDeferImageLoadLib.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + SecurityManagementLib + MemoryAllocationLib + DevicePathLib + BaseMemoryLib + PrintLib + DebugLib + UefiLib + PcdLib + +[Protocols] + gEfiFirmwareVolume2ProtocolGuid + gEfiBlockIoProtocolGuid + gEfiSimpleFileSystemProtocolGuid + gEfiUserManagerProtocolGuid + gEfiDeferredImageLoadProtocolGuid + gEfiDevicePathToTextProtocolGuid + +[Guids] + gEfiGlobalVariableGuid + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdDeferImageLoadPolicy diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c new file mode 100644 index 0000000000..148dbd5a89 --- /dev/null +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c @@ -0,0 +1,1368 @@ +/** @file + Implement image verification services for secure boot service in UEFI2.3.1. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "DxeImageVerificationLib.h" + +EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader; +UINTN mImageSize; +UINT32 mPeCoffHeaderOffset; +UINT8 mImageDigest[MAX_DIGEST_SIZE]; +UINTN mImageDigestSize; +EFI_IMAGE_DATA_DIRECTORY *mSecDataDir = NULL; +UINT8 *mImageBase = NULL; +EFI_GUID mCertType; + +// +// Notify string for authorization UI. +// +CHAR16 mNotifyString1[MAX_NOTIFY_STRING_LEN] = L"Image verification pass but not found in authorized database!"; +CHAR16 mNotifyString2[MAX_NOTIFY_STRING_LEN] = L"Launch this image anyway? (Yes/Defer/No)"; +// +// Public Exponent of RSA Key. +// +CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 }; + + +// +// OID ASN.1 Value for Hash Algorithms +// +UINT8 mHashOidValue[] = { + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, // OBJ_md5 + 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1 + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224 + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256 + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, // OBJ_sha384 + 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512 + }; + +HASH_TABLE mHash[] = { + { L"SHA1", 20, &mHashOidValue[8], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final }, + { L"SHA224", 28, &mHashOidValue[13], 9, NULL, NULL, NULL, NULL }, + { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize,Sha256Init, Sha256Update, Sha256Final}, + { L"SHA384", 48, &mHashOidValue[31], 9, NULL, NULL, NULL, NULL }, + { L"SHA512", 64, &mHashOidValue[40], 9, NULL, NULL, NULL, NULL } +}; + + +/** + Get the image type. + + @param[in] File This is a pointer to the device path of the file that is + being dispatched. + + @return UINT32 Image Type + +**/ +UINT32 +GetImageType ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *File + ) +{ + EFI_STATUS Status; + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + + // + // First check to see if File is from a Firmware Volume + // + DeviceHandle = NULL; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + Status = gBS->LocateDevicePath ( + &gEfiFirmwareVolume2ProtocolGuid, + &TempDevicePath, + &DeviceHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + DeviceHandle, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return IMAGE_FROM_FV; + } + } + + // + // Next check to see if File is from a Block I/O device + // + DeviceHandle = NULL; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + Status = gBS->LocateDevicePath ( + &gEfiBlockIoProtocolGuid, + &TempDevicePath, + &DeviceHandle + ); + if (!EFI_ERROR (Status)) { + BlockIo = NULL; + Status = gBS->OpenProtocol ( + DeviceHandle, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlockIo, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status) && BlockIo != NULL) { + if (BlockIo->Media != NULL) { + if (BlockIo->Media->RemovableMedia) { + // + // Block I/O is present and specifies the media is removable + // + return IMAGE_FROM_REMOVABLE_MEDIA; + } else { + // + // Block I/O is present and specifies the media is not removable + // + return IMAGE_FROM_FIXED_MEDIA; + } + } + } + } + + // + // File is not in a Firmware Volume or on a Block I/O device, so check to see if + // the device path supports the Simple File System Protocol. + // + DeviceHandle = NULL; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + &TempDevicePath, + &DeviceHandle + ); + if (!EFI_ERROR (Status)) { + // + // Simple File System is present without Block I/O, so assume media is fixed. + // + return IMAGE_FROM_FIXED_MEDIA; + } + + // + // File is not from an FV, Block I/O or Simple File System, so the only options + // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC. + // + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + while (!IsDevicePathEndType (TempDevicePath)) { + switch (DevicePathType (TempDevicePath)) { + + case MEDIA_DEVICE_PATH: + if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) { + return IMAGE_FROM_OPTION_ROM; + } + break; + + case MESSAGING_DEVICE_PATH: + if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) { + return IMAGE_FROM_REMOVABLE_MEDIA; + } + break; + + default: + break; + } + TempDevicePath = NextDevicePathNode (TempDevicePath); + } + return IMAGE_UNKNOWN; +} + +/** + Caculate hash of Pe/Coff image based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A + + @param[in] HashAlg Hash algorithm type. + + @retval TRUE Successfully hash image. + @retval FALSE Fail in hash image. + +**/ +BOOLEAN +HashPeImage ( + IN UINT32 HashAlg + ) +{ + BOOLEAN Status; + UINT16 Magic; + EFI_IMAGE_SECTION_HEADER *Section; + VOID *HashCtx; + UINTN CtxSize; + UINT8 *HashBase; + UINTN HashSize; + UINTN SumOfBytesHashed; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINTN Index; + UINTN Pos; + + HashCtx = NULL; + SectionHeader = NULL; + Status = FALSE; + + if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) { + return FALSE; + } + + // + // Initialize context of hash. + // + ZeroMem (mImageDigest, MAX_DIGEST_SIZE); + + if (HashAlg == HASHALG_SHA1) { + mImageDigestSize = SHA1_DIGEST_SIZE; + mCertType = gEfiCertSha1Guid; + } else if (HashAlg == HASHALG_SHA256) { + mImageDigestSize = SHA256_DIGEST_SIZE; + mCertType = gEfiCertSha256Guid; + } else { + return FALSE; + } + + CtxSize = mHash[HashAlg].GetContextSize(); + + HashCtx = AllocatePool (CtxSize); + ASSERT (HashCtx != NULL); + + // 1. Load the image header into memory. + + // 2. Initialize a SHA hash context. + Status = mHash[HashAlg].HashInit(HashCtx); + + if (!Status) { + goto Done; + } + // + // Measuring PE/COFF Image Header; + // But CheckSum field and SECURITY data directory (certificate) are excluded + // + Magic = mNtHeader.Pe32->OptionalHeader.Magic; + // + // 3. Calculate the distance from the base of the image header to the image checksum address. + // 4. Hash the image header from its base to beginning of the image checksum. + // + HashBase = mImageBase; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase); + } else { + // + // Use PE32+ offset. + // + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase); + } + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + // + // 5. Skip over the image checksum (it occupies a single ULONG). + // 6. Get the address of the beginning of the Cert Directory. + // 7. Hash everything from the end of the checksum to the start of the Cert Directory. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + } + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + // + // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) + // 9. Hash everything from the end of the Cert Directory to the end of image header. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase); + } + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + // + // 10. Set the SUM_OF_BYTES_HASHED to the size of the header. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders; + } else { + // + // Use PE32+ offset + // + SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders; + } + + // + // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER + // structures in the image. The 'NumberOfSections' field of the image + // header indicates how big the table should be. Do not include any + // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections); + ASSERT (SectionHeader != NULL); + // + // 12. Using the 'PointerToRawData' in the referenced section headers as + // a key, arrange the elements in the table in ascending order. In other + // words, sort the section headers according to the disk-file offset of + // the section. + // + Section = (EFI_IMAGE_SECTION_HEADER *) ( + mImageBase + + mPeCoffHeaderOffset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader + ); + for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) { + Pos = Index; + while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { + CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); + Pos--; + } + CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); + Section += 1; + } + + // + // 13. Walk through the sorted table, bring the corresponding section + // into memory, and hash the entire section (using the 'SizeOfRawData' + // field in the section header to determine the amount of data to hash). + // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . + // 15. Repeat steps 13 and 14 for all the sections in the sorted table. + // + for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) { + Section = &SectionHeader[Index]; + if (Section->SizeOfRawData == 0) { + continue; + } + HashBase = mImageBase + Section->PointerToRawData; + HashSize = (UINTN) Section->SizeOfRawData; + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + + SumOfBytesHashed += HashSize; + } + + // + // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra + // data in the file that needs to be added to the hash. This data begins + // at file offset SUM_OF_BYTES_HASHED and its length is: + // FileSize - (CertDirectory->Size) + // + if (mImageSize > SumOfBytesHashed) { + HashBase = mImageBase + SumOfBytesHashed; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashSize = (UINTN)( + mImageSize - + mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - + SumOfBytesHashed); + } else { + // + // Use PE32+ offset. + // + HashSize = (UINTN)( + mImageSize - + mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - + SumOfBytesHashed); + } + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + } + Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest); + +Done: + if (HashCtx != NULL) { + FreePool (HashCtx); + } + if (SectionHeader != NULL) { + FreePool (SectionHeader); + } + return Status; +} + +/** + Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of + Pe/Coff image based on the authenticode image hashing in PE/COFF Specification + 8.0 Appendix A + + @retval EFI_UNSUPPORTED Hash algorithm is not supported. + @retval EFI_SUCCESS Hash successfully. + +**/ +EFI_STATUS +HashPeImageByType ( + VOID + ) +{ + UINT8 Index; + WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; + + PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress); + + for (Index = 0; Index < HASHALG_MAX; Index++) { + // + // Check the Hash algorithm in PE/COFF Authenticode. + // According to PKCS#7 Definition: + // SignedData ::= SEQUENCE { + // version Version, + // digestAlgorithms DigestAlgorithmIdentifiers, + // contentInfo ContentInfo, + // .... } + // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing + // This field has the fixed offset (+32) in final Authenticode ASN.1 data. + // + if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) { + break; + } + } + + if (Index == HASHALG_MAX) { + return EFI_UNSUPPORTED; + } + + // + // HASH PE Image based on Hash algorithm in PE/COFF Authenticode. + // + if (!HashPeImage(Index)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + + +/** + Returns the size of a given image execution info table in bytes. + + This function returns the size, in bytes, of the image execution info table specified by + ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned. + + @param ImageExeInfoTable A pointer to a image execution info table structure. + + @retval 0 If ImageExeInfoTable is NULL. + @retval Others The size of a image execution info table in bytes. + +**/ +UINTN +GetImageExeInfoTableSize ( + EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable + ) +{ + UINTN Index; + EFI_IMAGE_EXECUTION_INFO *ImageExeInfoItem; + UINTN TotalSize; + + if (ImageExeInfoTable == NULL) { + return 0; + } + + ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoTable + sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE)); + TotalSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE); + for (Index = 0; Index < ImageExeInfoTable->NumberOfImages; Index++) { + TotalSize += ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize); + ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoItem + ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize)); + } + + return TotalSize; +} + +/** + Create an Image Execution Information Table entry and add it to system configuration table. + + @param[in] Action Describes the action taken by the firmware regarding this image. + @param[in] Name Input a null-terminated, user-friendly name. + @param[in] DevicePath Input device path pointer. + @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure. + @param[in] SignatureSize Size of signature. + +**/ +VOID +AddImageExeInfo ( + IN EFI_IMAGE_EXECUTION_ACTION Action, + IN CHAR16 *Name OPTIONAL, + IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_SIGNATURE_LIST *Signature OPTIONAL, + IN UINTN SignatureSize + ) +{ + EFI_STATUS Status; + EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable; + EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable; + EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry; + UINTN ImageExeInfoTableSize; + UINTN NewImageExeInfoEntrySize; + UINTN NameStringLen; + UINTN DevicePathSize; + + ASSERT (DevicePath != NULL); + ImageExeInfoTable = NULL; + NewImageExeInfoTable = NULL; + ImageExeInfoEntry = NULL; + NameStringLen = 0; + + if (Name != NULL) { + NameStringLen = StrSize (Name); + } + + ImageExeInfoTable = NULL; + EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID**)&ImageExeInfoTable); + if (ImageExeInfoTable != NULL) { + // + // The table has been found! + // We must enlarge the table to accmodate the new exe info entry. + // + ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable); + } else { + // + // Not Found! + // We should create a new table to append to the configuration table. + // + ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE); + } + + DevicePathSize = GetDevicePathSize (DevicePath); + NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize; + NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize); + ASSERT (NewImageExeInfoTable != NULL); + + if (ImageExeInfoTable != NULL) { + CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize); + } else { + NewImageExeInfoTable->NumberOfImages = 0; + } + NewImageExeInfoTable->NumberOfImages++; + ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize); + // + // Update new item's infomation. + // + WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->Action, Action); + WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->InfoSize, (UINT32) NewImageExeInfoEntrySize); + + if (Name != NULL) { + CopyMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), Name, NameStringLen); + } + CopyMem ( + (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen, + DevicePath, + DevicePathSize + ); + if (Signature != NULL) { + CopyMem ( + (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen + DevicePathSize, + Signature, + SignatureSize + ); + } + // + // Update/replace the image execution table. + // + Status = gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable); + ASSERT_EFI_ERROR (Status); + // + // Free Old table data! + // + if (ImageExeInfoTable != NULL) { + FreePool (ImageExeInfoTable); + } +} + +/** + Discover if the UEFI image is authorized by user's policy setting. + + @param[in] Policy Specify platform's policy setting. + + @retval EFI_ACCESS_DENIED Image is not allowed to run. + @retval EFI_SECURITY_VIOLATION Image is deferred. + @retval EFI_SUCCESS Image is authorized to run. + +**/ +EFI_STATUS +ImageAuthorization ( + IN UINT32 Policy + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + + Status = EFI_ACCESS_DENIED; + + switch (Policy) { + + case QUERY_USER_ON_SECURITY_VIOLATION: + do { + CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, mNotifyString1, mNotifyString2, NULL); + if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') { + Status = EFI_SUCCESS; + break; + } else if (Key.UnicodeChar == L'N' || Key.UnicodeChar == L'n') { + Status = EFI_ACCESS_DENIED; + break; + } else if (Key.UnicodeChar == L'D' || Key.UnicodeChar == L'd') { + Status = EFI_SECURITY_VIOLATION; + break; + } + } while (TRUE); + break; + + case ALLOW_EXECUTE_ON_SECURITY_VIOLATION: + Status = EFI_SUCCESS; + break; + + case DEFER_EXECUTE_ON_SECURITY_VIOLATION: + Status = EFI_SECURITY_VIOLATION; + break; + + case DENY_EXECUTE_ON_SECURITY_VIOLATION: + Status = EFI_ACCESS_DENIED; + break; + } + + return Status; +} + +/** + Check whether signature is in specified database. + + @param[in] VariableName Name of database variable that is searched in. + @param[in] Signature Pointer to signature that is searched for. + @param[in] CertType Pointer to hash algrithom. + @param[in] SignatureSize Size of Signature. + + @return TRUE Found the signature in the variable database. + @return FALSE Not found the signature in the variable database. + +**/ +BOOLEAN +IsSignatureFoundInDatabase ( + IN CHAR16 *VariableName, + IN UINT8 *Signature, + IN EFI_GUID *CertType, + IN UINTN SignatureSize + ) +{ + EFI_STATUS Status; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *Cert; + UINTN DataSize; + UINT8 *Data; + UINTN Index; + UINTN CertCount; + BOOLEAN IsFound; + // + // Read signature database variable. + // + IsFound = FALSE; + Data = NULL; + DataSize = 0; + Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL); + if (Status != EFI_BUFFER_TOO_SMALL) { + return FALSE; + } + + Data = (UINT8 *) AllocateZeroPool (DataSize); + ASSERT (Data != NULL); + + Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Enumerate all signature data in SigDB to check if executable's signature exists. + // + CertList = (EFI_SIGNATURE_LIST *) Data; + while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { + CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize; + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) { + for (Index = 0; Index < CertCount; Index++) { + if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) { + // + // Find the signature in database. + // + IsFound = TRUE; + break; + } + + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); + } + + if (IsFound) { + break; + } + } + + DataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + +Done: + if (Data != NULL) { + FreePool (Data); + } + + return IsFound; +} + +/** + Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format . + + @retval EFI_SUCCESS Image pass verification. + @retval EFI_SECURITY_VIOLATION Image fail verification. + @retval other error value + +**/ +EFI_STATUS +VerifyCertPkcsSignedData ( + VOID + ) +{ + EFI_STATUS Status; + BOOLEAN VerifyStatus; + WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *Cert; + UINTN DataSize; + UINT8 *Data; + UINT8 *RootCert; + UINTN RootCertSize; + UINTN Index; + UINTN CertCount; + + Data = NULL; + CertList = NULL; + Cert = NULL; + RootCert = NULL; + RootCertSize = 0; + VerifyStatus = FALSE; + PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress); + + // + // 1: Find certificate from KEK database and try to verify authenticode struct. + // + DataSize = 0; + Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + Data = (UINT8 *)AllocateZeroPool (DataSize); + ASSERT (Data != NULL); + + Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, (VOID *)Data); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Find Cert Enrolled in KEK database to verify the signature in pkcs7 signed data. + // + CertList = (EFI_SIGNATURE_LIST *) Data; + while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + for (Index = 0; Index < CertCount; Index++) { + // + // Iterate each Signature Data Node within this CertList for a verify + // + RootCert = Cert->SignatureData; + RootCertSize = CertList->SignatureSize; + + // + // Call AuthenticodeVerify library to Verify Authenticode struct. + // + VerifyStatus = AuthenticodeVerify ( + PkcsCertData->CertData, + mSecDataDir->Size - sizeof(PkcsCertData->Hdr), + RootCert, + RootCertSize, + mImageDigest, + mImageDigestSize + ); + + if (VerifyStatus) { + goto Done; + } + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); + } + } + DataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + } + + + + // + // 2: Find certificate from DB database and try to verify authenticode struct. + // + DataSize = 0; + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL); + if (Status == EFI_BUFFER_TOO_SMALL) { + Data = (UINT8 *)AllocateZeroPool (DataSize); + ASSERT (Data != NULL); + + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)Data); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Find Cert Enrolled in DB database to verify the signature in pkcs7 signed data. + // + CertList = (EFI_SIGNATURE_LIST *) Data; + while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + for (Index = 0; Index < CertCount; Index++) { + // + // Iterate each Signature Data Node within this CertList for a verify + // + RootCert = Cert->SignatureData; + RootCertSize = CertList->SignatureSize; + + // + // Call AuthenticodeVerify library to Verify Authenticode struct. + // + VerifyStatus = AuthenticodeVerify ( + PkcsCertData->CertData, + mSecDataDir->Size - sizeof(PkcsCertData->Hdr), + RootCert, + RootCertSize, + mImageDigest, + mImageDigestSize + ); + + if (VerifyStatus) { + goto Done; + } + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); + } + } + DataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + } + +Done: + if (Data != NULL) { + FreePool (Data); + } + + if (VerifyStatus) { + return EFI_SUCCESS; + } else { + return EFI_SECURITY_VIOLATION; + } +} + +/** + Verify certificate in WIN_CERTIFICATE_UEFI_GUID format. + + @retval EFI_SUCCESS Image pass verification. + @retval EFI_SECURITY_VIOLATION Image fail verification. + @retval other error value + +**/ +EFI_STATUS +VerifyCertUefiGuid ( + VOID + ) +{ + BOOLEAN Status; + WIN_CERTIFICATE_UEFI_GUID *EfiCert; + EFI_SIGNATURE_LIST *KekList; + EFI_SIGNATURE_DATA *KekItem; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock; + VOID *Rsa; + UINTN KekCount; + UINTN Index; + UINTN KekDataSize; + BOOLEAN IsFound; + EFI_STATUS Result; + + EfiCert = NULL; + KekList = NULL; + KekItem = NULL; + CertBlock = NULL; + Rsa = NULL; + Status = FALSE; + IsFound = FALSE; + KekDataSize = 0; + + EfiCert = (WIN_CERTIFICATE_UEFI_GUID *) (mImageBase + mSecDataDir->VirtualAddress); + CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) EfiCert->CertData; + if (!CompareGuid (&EfiCert->CertType, &gEfiCertTypeRsa2048Sha256Guid)) { + // + // Invalid Certificate Data Type. + // + return EFI_SECURITY_VIOLATION; + } + + // + // Get KEK database variable data size + // + Result = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &KekDataSize, NULL); + if (Result != EFI_BUFFER_TOO_SMALL) { + return EFI_SECURITY_VIOLATION; + } + + // + // Get KEK database variable. + // + KekList = GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME); + if (KekList == NULL) { + return EFI_SECURITY_VIOLATION; + } + + // + // Enumerate all Kek items in this list to verify the variable certificate data. + // If anyone is authenticated successfully, it means the variable is correct! + // + while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) { + if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) { + KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize); + KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize; + 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); + } + } + KekDataSize -= KekList->SignatureListSize; + KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize); + } + + if (!IsFound) { + // + // Signed key is not a trust one. + // + goto Done; + } + + // + // Now, we found the corresponding security policy. + // Verify the data payload. + // + Rsa = RsaNew (); + ASSERT (Rsa != NULL); + // + // Set RSA Key Components. + // NOTE: Only N and E are needed to be set as RSA public key for signature verification. + // + Status = RsaSetKey (Rsa, RsaKeyN, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE); + if (!Status) { + goto Done; + } + Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE)); + if (!Status) { + goto Done; + } + // + // Verify the signature. + // + Status = RsaPkcs1Verify ( + Rsa, + mImageDigest, + mImageDigestSize, + CertBlock->Signature, + EFI_CERT_TYPE_RSA2048_SHA256_SIZE + ); + +Done: + if (KekList != NULL) { + FreePool (KekList); + } + if (Rsa != NULL ) { + RsaFree (Rsa); + } + if (Status) { + return EFI_SUCCESS; + } else { + return EFI_SECURITY_VIOLATION; + } +} + +/** + Provide verification service for signed images, which include both signature validation + and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and + MSFT Authenticode type signatures are supported. + + In this implementation, only verify external executables when in USER MODE. + Executables from FV is bypass, so pass in AuthenticationStatus is ignored. + + @param[in] AuthenticationStatus + This is the authentication status returned from the security + measurement services for the input file. + @param[in] File This is a pointer to the device path of the file that is + being dispatched. This will optionally be used for logging. + @param[in] FileBuffer File buffer matches the input file device path. + @param[in] FileSize Size of File buffer matches the input file device path. + + @retval EFI_SUCCESS The file specified by File did authenticate, and the + platform policy dictates that the DXE Core may use File. + @retval EFI_INVALID_PARAMETER File is NULL. + @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and + the platform policy dictates that File should be placed + in the untrusted state. A file may be promoted from + the untrusted to the trusted state at a future time + with a call to the Trust() DXE Service. + @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and + the platform policy dictates that File should not be + used for any purpose. + +**/ +EFI_STATUS +EFIAPI +DxeImageVerificationHandler ( + IN UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File, + IN VOID *FileBuffer, + IN UINTN FileSize + ) + +{ + EFI_STATUS Status; + UINT16 Magic; + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_STATUS VerifyStatus; + UINT8 *SetupMode; + EFI_SIGNATURE_LIST *SignatureList; + UINTN SignatureListSize; + EFI_SIGNATURE_DATA *Signature; + EFI_IMAGE_EXECUTION_ACTION Action; + WIN_CERTIFICATE *WinCertificate; + UINT32 Policy; + + if (File == NULL) { + return EFI_INVALID_PARAMETER; + } + + SignatureList = NULL; + SignatureListSize = 0; + WinCertificate = NULL; + Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; + Status = EFI_ACCESS_DENIED; + // + // Check the image type and get policy setting. + // + switch (GetImageType (File)) { + + case IMAGE_FROM_FV: + Policy = ALWAYS_EXECUTE; + break; + + case IMAGE_FROM_OPTION_ROM: + Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy); + break; + + case IMAGE_FROM_REMOVABLE_MEDIA: + Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy); + break; + + case IMAGE_FROM_FIXED_MEDIA: + Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy); + break; + + default: + Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION; + break; + } + // + // If policy is always/never execute, return directly. + // + if (Policy == ALWAYS_EXECUTE) { + return EFI_SUCCESS; + } else if (Policy == NEVER_EXECUTE) { + return EFI_ACCESS_DENIED; + } + SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME); + + // + // SetupMode doesn't exist means no AuthVar driver is dispatched, + // skip verification. + // + if (SetupMode == NULL) { + return EFI_SUCCESS; + } + + // + // If platform is in SETUP MODE, skip verification. + // + if (*SetupMode == SETUP_MODE) { + FreePool (SetupMode); + return EFI_SUCCESS; + } + // + // Read the Dos header. + // + ASSERT (FileBuffer != NULL); + mImageBase = (UINT8 *) FileBuffer; + mImageSize = FileSize; + DosHdr = (EFI_IMAGE_DOS_HEADER *) (mImageBase); + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, + // so read the PE header after the DOS image header. + // + mPeCoffHeaderOffset = DosHdr->e_lfanew; + } else { + mPeCoffHeaderOffset = 0; + } + // + // Check PE/COFF image. + // + mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset); + if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { + // + // It is not a valid Pe/Coff file. + // + return EFI_ACCESS_DENIED; + } + + Magic = mNtHeader.Pe32->OptionalHeader.Magic; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } else { + // + // Use PE32+ offset. + // + mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + + if (mSecDataDir->Size == 0) { + // + // This image is not signed. + // + Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; + Status = EFI_ACCESS_DENIED; + goto Done; + } + // + // Verify signature of executables. + // + WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress); + + switch (WinCertificate->wCertificateType) { + + case WIN_CERT_TYPE_EFI_GUID: + // + // Verify UEFI GUID type. + // + if (!HashPeImage (HASHALG_SHA256)) { + goto Done; + } + + VerifyStatus = VerifyCertUefiGuid (); + break; + + case WIN_CERT_TYPE_PKCS_SIGNED_DATA: + // + // Verify Pkcs signed data type. + // + Status = HashPeImageByType(); + if (EFI_ERROR(Status)) { + goto Done; + } + + VerifyStatus = VerifyCertPkcsSignedData (); + + // + // For image verification against enrolled certificate(root or intermediate), + // no need to check image's hash in the allowed database. + // + if (!EFI_ERROR (VerifyStatus)) { + return EFI_SUCCESS; + } + + default: + return EFI_ACCESS_DENIED; + } + // + // Get image hash value as executable's signature. + // + SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize; + SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize); + ASSERT (SignatureList != NULL); + SignatureList->SignatureHeaderSize = 0; + SignatureList->SignatureListSize = (UINT32) SignatureListSize; + SignatureList->SignatureSize = (UINT32) mImageDigestSize; + CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID)); + Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST)); + CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize); + // + // Signature database check after verification. + // + if (EFI_ERROR (VerifyStatus)) { + // + // Verification failure. + // + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED; + Status = EFI_ACCESS_DENIED; + } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) { + // + // Executable signature verification passes, but is found in forbidden signature database. + // + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND; + Status = EFI_ACCESS_DENIED; + } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, Signature->SignatureData, &mCertType, mImageDigestSize)) { + // + // Executable signature is found in authorized signature database. + // + Status = EFI_SUCCESS; + } else { + // + // Executable signature verification passes, but cannot be found in authorized signature database. + // Get platform policy to determine the action. + // + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED; + Status = ImageAuthorization (Policy); + } + +Done: + if (Status != EFI_SUCCESS) { + // + // Policy decides to defer or reject the image; add its information in image executable information table. + // + AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize); + } + + if (SignatureList != NULL) { + FreePool (SignatureList); + } + + FreePool (SetupMode); + + return Status; +} + +/** + When VariableWriteArchProtocol install, create "SecureBoot" variable. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +VariableWriteCallBack ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINT8 SecureBootMode; + UINT8 *SecureBootModePtr; + EFI_STATUS Status; + VOID *ProtocolPointer; + + Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, &ProtocolPointer); + if (EFI_ERROR (Status)) { + return; + } + + // + // Check whether "SecureBoot" variable exists. + // If this library is built-in, it means firmware has capability to perform + // driver signing verification. + // + SecureBootModePtr = GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME); + if (SecureBootModePtr == NULL) { + SecureBootMode = SECURE_BOOT_MODE_DISABLE; + // + // Authenticated variable driver will update "SecureBoot" depending on SetupMode variable. + // + gRT->SetVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + sizeof (UINT8), + &SecureBootMode + ); + } else { + FreePool (SecureBootModePtr); + } +} + +/** + Register security measurement handler. + + @param ImageHandle ImageHandle of the loaded driver. + @param SystemTable Pointer to the EFI System Table. + + @retval EFI_SUCCESS The handlers were registered successfully. +**/ +EFI_STATUS +EFIAPI +DxeImageVerificationLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *Registration; + + // + // Register callback function upon VariableWriteArchProtocol. + // + EfiCreateProtocolNotifyEvent ( + &gEfiVariableWriteArchProtocolGuid, + TPL_CALLBACK, + VariableWriteCallBack, + NULL, + &Registration + ); + + return RegisterSecurityHandler ( + DxeImageVerificationHandler, + EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED + ); +} diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h new file mode 100644 index 0000000000..34ed0c89a1 --- /dev/null +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h @@ -0,0 +1,201 @@ +/** @file + The internal header file includes the common header files, defines + internal structure and functions used by ImageVerificationLib. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __IMAGEVERIFICATIONLIB_H__ +#define __IMAGEVERIFICATIONLIB_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256 +#define EFI_CERT_TYPE_RSA2048_SIZE 256 +#define MAX_NOTIFY_STRING_LEN 64 + +// +// Image type definitions +// +#define IMAGE_UNKNOWN 0x00000000 +#define IMAGE_FROM_FV 0x00000001 +#define IMAGE_FROM_OPTION_ROM 0x00000002 +#define IMAGE_FROM_REMOVABLE_MEDIA 0x00000003 +#define IMAGE_FROM_FIXED_MEDIA 0x00000004 + +// +// Authorization policy bit definition +// +#define ALWAYS_EXECUTE 0x00000000 +#define NEVER_EXECUTE 0x00000001 +#define ALLOW_EXECUTE_ON_SECURITY_VIOLATION 0x00000002 +#define DEFER_EXECUTE_ON_SECURITY_VIOLATION 0x00000003 +#define DENY_EXECUTE_ON_SECURITY_VIOLATION 0x00000004 +#define QUERY_USER_ON_SECURITY_VIOLATION 0x00000005 + +// +// Support hash types +// +#define HASHALG_SHA1 0x00000000 +#define HASHALG_SHA224 0x00000001 +#define HASHALG_SHA256 0x00000002 +#define HASHALG_SHA384 0x00000003 +#define HASHALG_SHA512 0x00000004 +#define HASHALG_MAX 0x00000005 + +// +// Set max digest size as SHA256 Output (32 bytes) by far +// +#define MAX_DIGEST_SIZE SHA256_DIGEST_SIZE +// +// +// PKCS7 Certificate definition +// +typedef struct { + WIN_CERTIFICATE Hdr; + UINT8 CertData[1]; +} WIN_CERTIFICATE_EFI_PKCS; + + +/** + Retrieves the size, in bytes, of the context buffer required for hash operations. + + @return The size, in bytes, of the context buffer required for hash operations. + +**/ +typedef +UINTN +(EFIAPI *HASH_GET_CONTEXT_SIZE)( + VOID + ); + +/** + Initializes user-supplied memory pointed by HashContext as hash context for + subsequent use. + + If HashContext is NULL, then ASSERT(). + + @param[in, out] HashContext Pointer to Context being initialized. + + @retval TRUE HASH context initialization succeeded. + @retval FALSE HASH context initialization failed. + +**/ +typedef +BOOLEAN +(EFIAPI *HASH_INIT)( + IN OUT VOID *HashContext + ); + + +/** + Performs digest on a data buffer of the specified length. This function can + be called multiple times to compute the digest of long or discontinuous data streams. + + If HashContext is NULL, then ASSERT(). + + @param[in, out] HashContext Pointer to the MD5 context. + @param[in] Data Pointer to the buffer containing the data to be hashed. + @param[in] DataLength Length of Data buffer in bytes. + + @retval TRUE HASH data digest succeeded. + @retval FALSE Invalid HASH context. After HashFinal function has been called, the + HASH context cannot be reused. + +**/ +typedef +BOOLEAN +(EFIAPI *HASH_UPDATE)( + IN OUT VOID *HashContext, + IN CONST VOID *Data, + IN UINTN DataLength + ); + +/** + Completes hash computation and retrieves the digest value into the specified + memory. After this function has been called, the context cannot be used again. + + If HashContext is NULL, then ASSERT(). + If HashValue is NULL, then ASSERT(). + + @param[in, out] HashContext Pointer to the MD5 context + @param[out] HashValue Pointer to a buffer that receives the HASH digest + value. + + @retval TRUE HASH digest computation succeeded. + @retval FALSE HASH digest computation failed. + +**/ +typedef +BOOLEAN +(EFIAPI *HASH_FINAL)( + IN OUT VOID *HashContext, + OUT UINT8 *HashValue + ); + + +// +// Hash Algorithm Table +// +typedef struct { + // + // Name for Hash Algorithm + // + CHAR16 *Name; + // + // Digest Length + // + UINTN DigestLength; + // + // Hash Algorithm OID ASN.1 Value + // + UINT8 *OidValue; + // + // Length of Hash OID Value + // + UINTN OidLength; + // + // Pointer to Hash GetContentSize function + // + HASH_GET_CONTEXT_SIZE GetContextSize; + // + // Pointer to Hash Init function + // + HASH_INIT HashInit; + // + // Pointer to Hash Update function + // + HASH_UPDATE HashUpdate; + // + // Pointer to Hash Final function + // + HASH_FINAL HashFinal; +} HASH_TABLE; + +#endif diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf new file mode 100644 index 0000000000..5874d6b66b --- /dev/null +++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf @@ -0,0 +1,73 @@ +## @file +# The library instance provides security service of image verification. +# Image verification Library module supports UEFI2.3.1 +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeImageVerificationLib + FILE_GUID = 0CA970E1-43FA-4402-BC0A-81AF336BFFD6 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = DxeImageVerificationLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + DxeImageVerificationLib.c + DxeImageVerificationLib.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + DevicePathLib + BaseCryptLib + SecurityManagementLib + +[Protocols] + gEfiFirmwareVolume2ProtocolGuid + gEfiBlockIoProtocolGuid + gEfiSimpleFileSystemProtocolGuid + gEfiVariableWriteArchProtocolGuid + +[Guids] + gEfiCertTypeRsa2048Sha256Guid + gEfiImageSecurityDatabaseGuid + gEfiCertSha1Guid + gEfiCertSha256Guid + gEfiCertX509Guid + gEfiCertRsa2048Guid + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy + gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy + gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy + + + + diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c new file mode 100644 index 0000000000..c012f130d9 --- /dev/null +++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c @@ -0,0 +1,830 @@ +/** @file + The library instance provides security service of TPM measure boot. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Flag to check GPT partition. It only need be measured once. +// +BOOLEAN mMeasureGptTableFlag = FALSE; +EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; +UINTN mMeasureGptCount = 0; + +/** + Reads contents of a PE/COFF image in memory buffer. + + @param FileHandle Pointer to the file handle to read the PE/COFF image. + @param FileOffset Offset into the PE/COFF image to begin the read operation. + @param ReadSize On input, the size in bytes of the requested read operation. + On output, the number of bytes actually read. + @param Buffer Output buffer that contains the data read from the PE/COFF image. + + @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size +**/ +EFI_STATUS +EFIAPI +ImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize); + return EFI_SUCCESS; +} + +/** + Measure GPT table data into TPM log. + + @param TcgProtocol Pointer to the located TCG protocol instance. + @param GptHandle Handle that GPT partition was installed. + + @retval EFI_SUCCESS Successfully measure GPT table. + @retval EFI_UNSUPPORTED Not support GPT table on the given handle. + @retval EFI_DEVICE_ERROR Can't get GPT table because device error. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table. + @retval other error value +**/ +EFI_STATUS +EFIAPI +TcgMeasureGptTable ( + IN EFI_TCG_PROTOCOL *TcgProtocol, + IN EFI_HANDLE GptHandle + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlockIo; + EFI_DISK_IO_PROTOCOL *DiskIo; + EFI_PARTITION_TABLE_HEADER *PrimaryHeader; + EFI_PARTITION_ENTRY *PartitionEntry; + UINT8 *EntryPtr; + UINTN NumberOfPartition; + UINT32 Index; + TCG_PCR_EVENT *TcgEvent; + EFI_GPT_DATA *GptData; + UINT32 EventSize; + UINT32 EventNumber; + EFI_PHYSICAL_ADDRESS EventLogLastEntry; + + if (mMeasureGptCount > 0) { + return EFI_SUCCESS; + } + + Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + // + // Read the EFI Partition Table Header + // + PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *) AllocatePool (BlockIo->Media->BlockSize); + if (PrimaryHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + 1 * BlockIo->Media->BlockSize, + BlockIo->Media->BlockSize, + (UINT8 *)PrimaryHeader + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Failed to Read Partition Table Header!\n")); + FreePool (PrimaryHeader); + return EFI_DEVICE_ERROR; + } + // + // Read the partition entry. + // + EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry); + if (EntryPtr == NULL) { + FreePool (PrimaryHeader); + return EFI_OUT_OF_RESOURCES; + } + Status = DiskIo->ReadDisk ( + DiskIo, + BlockIo->Media->MediaId, + MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize), + PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry, + EntryPtr + ); + if (EFI_ERROR (Status)) { + FreePool (PrimaryHeader); + FreePool (EntryPtr); + return EFI_DEVICE_ERROR; + } + + // + // Count the valid partition + // + PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr; + NumberOfPartition = 0; + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) { + if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) { + NumberOfPartition++; + } + PartitionEntry++; + } + + // + // Parepare Data for Measurement + // + EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); + TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT)); + if (TcgEvent == NULL) { + FreePool (PrimaryHeader); + FreePool (EntryPtr); + return EFI_OUT_OF_RESOURCES; + } + + TcgEvent->PCRIndex = 5; + TcgEvent->EventType = EV_EFI_GPT_EVENT; + TcgEvent->EventSize = EventSize; + GptData = (EFI_GPT_DATA *) TcgEvent->Event; + + // + // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition + // + CopyMem ((UINT8 *)GptData, (UINT8*)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER)); + GptData->NumberOfPartitions = NumberOfPartition; + // + // Copy the valid partition entry + // + PartitionEntry = (EFI_PARTITION_ENTRY*)EntryPtr; + NumberOfPartition = 0; + for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) { + if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) { + CopyMem ( + (UINT8 *)&GptData->Partitions + NumberOfPartition * sizeof (EFI_PARTITION_ENTRY), + (UINT8 *)PartitionEntry, + sizeof (EFI_PARTITION_ENTRY) + ); + NumberOfPartition++; + } + PartitionEntry++; + } + + // + // Measure the GPT data + // + EventNumber = 1; + Status = TcgProtocol->HashLogExtendEvent ( + TcgProtocol, + (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData, + (UINT64) TcgEvent->EventSize, + TPM_ALG_SHA, + TcgEvent, + &EventNumber, + &EventLogLastEntry + ); + if (!EFI_ERROR (Status)) { + mMeasureGptCount++; + } + + FreePool (PrimaryHeader); + FreePool (EntryPtr); + FreePool (TcgEvent); + + return Status; +} + +/** + Measure PE image into TPM log based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A. + + @param[in] TcgProtocol Pointer to the located TCG protocol instance. + @param[in] ImageAddress Start address of image buffer. + @param[in] ImageSize Image size + @param[in] LinkTimeBase Address that the image is loaded into memory. + @param[in] ImageType Image subsystem type. + @param[in] FilePath File path is corresponding to the input image. + + @retval EFI_SUCCESS Successfully measure image. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval other error value +**/ +EFI_STATUS +EFIAPI +TcgMeasurePeImage ( + IN EFI_TCG_PROTOCOL *TcgProtocol, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + IN UINTN LinkTimeBase, + IN UINT16 ImageType, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT *TcgEvent; + EFI_IMAGE_LOAD_EVENT *ImageLoad; + UINT32 FilePathSize; + VOID *Sha1Ctx; + UINTN CtxSize; + EFI_IMAGE_DOS_HEADER *DosHdr; + UINT32 PeCoffHeaderOffset; + EFI_IMAGE_SECTION_HEADER *Section; + UINT8 *HashBase; + UINTN HashSize; + UINTN SumOfBytesHashed; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINTN Index, Pos; + UINT16 Magic; + UINT32 EventSize; + UINT32 EventNumber; + EFI_PHYSICAL_ADDRESS EventLogLastEntry; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + + Status = EFI_SUCCESS; + ImageLoad = NULL; + SectionHeader = NULL; + Sha1Ctx = NULL; + FilePathSize = (UINT32) GetDevicePathSize (FilePath); + + // + // Determine destination PCR by BootPolicy + // + EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize; + TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT)); + if (TcgEvent == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TcgEvent->EventSize = EventSize; + ImageLoad = (EFI_IMAGE_LOAD_EVENT *) TcgEvent->Event; + + switch (ImageType) { + case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: + TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION; + TcgEvent->PCRIndex = 4; + break; + case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + TcgEvent->EventType = EV_EFI_BOOT_SERVICES_DRIVER; + TcgEvent->PCRIndex = 2; + break; + case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + TcgEvent->EventType = EV_EFI_RUNTIME_SERVICES_DRIVER; + TcgEvent->PCRIndex = 2; + break; + default: + DEBUG (( + EFI_D_ERROR, + "TcgMeasurePeImage: Unknown subsystem type %d", + ImageType + )); + ASSERT (FALSE); + TcgEvent->EventType = ImageType; + Status = EFI_UNSUPPORTED; + goto Finish; + } + + ImageLoad->ImageLocationInMemory = ImageAddress; + ImageLoad->ImageLengthInMemory = ImageSize; + ImageLoad->ImageLinkTimeAddress = LinkTimeBase; + ImageLoad->LengthOfDevicePath = FilePathSize; + CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize); + + // + // Check PE/COFF image + // + DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress; + PeCoffHeaderOffset = 0; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + PeCoffHeaderOffset = DosHdr->e_lfanew; + } + if (((EFI_TE_IMAGE_HEADER *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset))->Signature + == EFI_TE_IMAGE_HEADER_SIGNATURE) { + goto Finish; + } + + // + // PE/COFF Image Measurement + // + // NOTE: The following codes/steps are based upon the authenticode image hashing in + // PE/COFF Specification 8.0 Appendix A. + // + // + + // 1. Load the image header into memory. + + // 2. Initialize a SHA hash context. + CtxSize = Sha1GetContextSize (); + Sha1Ctx = AllocatePool (CtxSize); + if (Sha1Ctx == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + + Sha1Init (Sha1Ctx); + + // + // Measuring PE/COFF Image Header; + // But CheckSum field and SECURITY data directory (certificate) are excluded + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset); + Magic = Hdr.Pe32->OptionalHeader.Magic; + + // + // 3. Calculate the distance from the base of the image header to the image checksum address. + // 4. Hash the image header from its base to beginning of the image checksum. + // + HashBase = (UINT8 *) (UINTN) ImageAddress; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase); + } else { + // + // Use PE32+ offset + // + HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase); + } + + Sha1Update (Sha1Ctx, HashBase, HashSize); + + // + // 5. Skip over the image checksum (it occupies a single ULONG). + // 6. Get the address of the beginning of the Cert Directory. + // 7. Hash everything from the end of the checksum to the start of the Cert Directory. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + } else { + // + // Use PE32+ offset + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase); + } + + Sha1Update (Sha1Ctx, HashBase, HashSize); + + // + // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) + // 9. Hash everything from the end of the Cert Directory to the end of image header. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - + (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress); + } else { + // + // Use PE32+ offset + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - + (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress); + } + + Sha1Update (Sha1Ctx, HashBase, HashSize); + + // + // 10. Set the SUM_OF_BYTES_HASHED to the size of the header + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders; + } else { + // + // Use PE32+ offset + // + SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; + } + + // + // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER + // structures in the image. The 'NumberOfSections' field of the image + // header indicates how big the table should be. Do not include any + // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); + if (SectionHeader == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + + // + // 12. Using the 'PointerToRawData' in the referenced section headers as + // a key, arrange the elements in the table in ascending order. In other + // words, sort the section headers according to the disk-file offset of + // the section. + // + Section = (EFI_IMAGE_SECTION_HEADER *) ( + (UINT8 *) (UINTN) ImageAddress + + PeCoffHeaderOffset + + sizeof(UINT32) + + sizeof(EFI_IMAGE_FILE_HEADER) + + Hdr.Pe32->FileHeader.SizeOfOptionalHeader + ); + for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { + Pos = Index; + while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { + CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER)); + Pos--; + } + CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER)); + Section += 1; + } + + // + // 13. Walk through the sorted table, bring the corresponding section + // into memory, and hash the entire section (using the 'SizeOfRawData' + // field in the section header to determine the amount of data to hash). + // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . + // 15. Repeat steps 13 and 14 for all the sections in the sorted table. + // + for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { + Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index]; + if (Section->SizeOfRawData == 0) { + continue; + } + HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData; + HashSize = (UINTN) Section->SizeOfRawData; + + Sha1Update (Sha1Ctx, HashBase, HashSize); + + SumOfBytesHashed += HashSize; + } + + // + // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra + // data in the file that needs to be added to the hash. This data begins + // at file offset SUM_OF_BYTES_HASHED and its length is: + // FileSize - (CertDirectory->Size) + // + if (ImageSize > SumOfBytesHashed) { + HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashSize = (UINTN)(ImageSize - + Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - + SumOfBytesHashed); + } else { + // + // Use PE32+ offset + // + HashSize = (UINTN)(ImageSize - + Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - + SumOfBytesHashed); + } + + Sha1Update (Sha1Ctx, HashBase, HashSize); + } + + // + // 17. Finalize the SHA hash. + // + Sha1Final (Sha1Ctx, (UINT8 *)&TcgEvent->Digest); + + // + // Log the PE data + // + EventNumber = 1; + Status = TcgProtocol->HashLogExtendEvent ( + TcgProtocol, + (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL, + 0, + TPM_ALG_SHA, + TcgEvent, + &EventNumber, + &EventLogLastEntry + ); + +Finish: + FreePool (TcgEvent); + + if (SectionHeader != NULL) { + FreePool (SectionHeader); + } + + if (Sha1Ctx != NULL ) { + FreePool (Sha1Ctx); + } + return Status; +} + +/** + The security handler is used to abstract platform-specific policy + from the DXE core response to an attempt to use a file that returns a + given status for the authentication check from the section extraction protocol. + + The possible responses in a given SAP implementation may include locking + flash upon failure to authenticate, attestation logging for all signed drivers, + and other exception operations. The File parameter allows for possible logging + within the SAP of the driver. + + If File is NULL, then EFI_INVALID_PARAMETER is returned. + + If the file specified by File with an authentication status specified by + AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned. + + If the file specified by File with an authentication status specified by + AuthenticationStatus is not safe for the DXE Core to use under any circumstances, + then EFI_ACCESS_DENIED is returned. + + If the file specified by File with an authentication status specified by + AuthenticationStatus is not safe for the DXE Core to use right now, but it + might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is + returned. + + @param[in, out] AuthenticationStatus This is the authentication status returned + from the securitymeasurement services for the + input file. + @param[in] File This is a pointer to the device path of the file that is + being dispatched. This will optionally be used for logging. + @param[in] FileBuffer File buffer matches the input file device path. + @param[in] FileSize Size of File buffer matches the input file device path. + + @retval EFI_SUCCESS The file specified by File did authenticate, and the + platform policy dictates that the DXE Core may use File. + @retval EFI_INVALID_PARAMETER File is NULL. + @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and + the platform policy dictates that File should be placed + in the untrusted state. A file may be promoted from + the untrusted to the trusted state at a future time + with a call to the Trust() DXE Service. + @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and + the platform policy dictates that File should not be + used for any purpose. + +**/ +EFI_STATUS +EFIAPI +DxeTpmMeasureBootHandler ( + IN OUT UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File, + IN VOID *FileBuffer OPTIONAL, + IN UINTN FileSize OPTIONAL + ) +{ + EFI_TCG_PROTOCOL *TcgProtocol; + EFI_STATUS Status; + TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability; + UINT32 TCGFeatureFlags; + EFI_PHYSICAL_ADDRESS EventLogLocation; + EFI_PHYSICAL_ADDRESS EventLogLastEntry; + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode; + EFI_HANDLE Handle; + BOOLEAN ApplicationRequired; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + if (File == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol); + if (EFI_ERROR (Status)) { + // + // TCG protocol is not installed. So, TPM is not present. + // Don't do any measurement, and directly return EFI_SUCCESS. + // + return EFI_SUCCESS; + } + + ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability); + Status = TcgProtocol->StatusCheck ( + TcgProtocol, + &ProtocolCapability, + &TCGFeatureFlags, + &EventLogLocation, + &EventLogLastEntry + ); + if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag) { + // + // TPM device doesn't work or activate. + // + return EFI_SUCCESS; + } + + // + // Copy File Device Path + // + OrigDevicePathNode = DuplicateDevicePath (File); + ASSERT (OrigDevicePathNode != NULL); + + // + // 1. Check whether this device path support BlockIo protocol. + // Is so, this device path may be a GPT device path. + // + DevicePathNode = OrigDevicePathNode; + Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle); + if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) { + // + // Find the gpt partion on the given devicepath + // + DevicePathNode = OrigDevicePathNode; + while (!IsDevicePathEnd (DevicePathNode)) { + // + // Find the Gpt partition + // + if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH && + DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) { + // + // Check whether it is a gpt partition or not + // + if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER && + ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) { + + // + // Change the partition device path to its parent device path (disk) and get the handle. + // + DevicePathNode->Type = END_DEVICE_PATH_TYPE; + DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; + DevicePathNode = OrigDevicePathNode; + Status = gBS->LocateDevicePath ( + &gEfiDiskIoProtocolGuid, + &DevicePathNode, + &Handle + ); + if (!EFI_ERROR (Status)) { + // + // Measure GPT disk. + // + Status = TcgMeasureGptTable (TcgProtocol, Handle); + if (!EFI_ERROR (Status)) { + // + // GPT disk check done. + // + mMeasureGptTableFlag = TRUE; + } + } + FreePool (OrigDevicePathNode); + OrigDevicePathNode = DuplicateDevicePath (File); + ASSERT (OrigDevicePathNode != NULL); + break; + } + } + DevicePathNode = NextDevicePathNode (DevicePathNode); + } + } + + // + // 2. Measure PE image. + // + ApplicationRequired = FALSE; + + // + // Check whether this device path support FV2 protocol. + // + DevicePathNode = OrigDevicePathNode; + Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle); + if (!EFI_ERROR (Status)) { + // + // Don't check FV image, and directly return EFI_SUCCESS. + // It can be extended to the specific FV authentication according to the different requirement. + // + if (IsDevicePathEnd (DevicePathNode)) { + return EFI_SUCCESS; + } + // + // The image from Firmware image will not be mearsured. + // Current policy doesn't measure PeImage from Firmware if it is driver + // If the got PeImage is application, it will be still be measured. + // + ApplicationRequired = TRUE; + } + + // + // File is not found. + // + if (FileBuffer == NULL) { + Status = EFI_SECURITY_VIOLATION; + goto Finish; + } + + // + // Measure PE Image + // + DevicePathNode = OrigDevicePathNode; + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) ImageRead; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + // + // The information can't be got from the invalid PeImage + // + goto Finish; + } + + // + // Measure only application if Application flag is set + // Measure drivers and applications if Application flag is not set + // + if ((!ApplicationRequired) || + (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { + // + // Print the image path to be measured. + // + DEBUG_CODE_BEGIN (); + CHAR16 *ToText; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevPathToText + ); + if (!EFI_ERROR (Status)) { + ToText = DevPathToText->ConvertDevicePathToText ( + DevicePathNode, + FALSE, + TRUE + ); + if (ToText != NULL) { + DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText)); + } + } + DEBUG_CODE_END (); + + // + // Measure PE image into TPM log. + // + Status = TcgMeasurePeImage ( + TcgProtocol, + (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, + FileSize, + (UINTN) ImageContext.ImageAddress, + ImageContext.ImageType, + DevicePathNode + ); + } + + // + // Done, free the allocated resource. + // +Finish: + FreePool (OrigDevicePathNode); + + return Status; +} + +/** + Register the security handler to provide TPM measure boot service. + + @param ImageHandle ImageHandle of the loaded driver. + @param SystemTable Pointer to the EFI System Table. + + @retval EFI_SUCCESS Register successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler. +**/ +EFI_STATUS +EFIAPI +DxeTpmMeasureBootLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return RegisterSecurityHandler ( + DxeTpmMeasureBootHandler, + EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED + ); +} diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf new file mode 100644 index 0000000000..bf83bf1022 --- /dev/null +++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf @@ -0,0 +1,54 @@ +## @file +# The library instance provides security service of TPM measure boot. +# +# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeTpmMeasureBootLib + FILE_GUID = 6C60C7D0-922A-4b7c-87D7-E503EDD73BBF + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = DxeTpmMeasureBootLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + DxeTpmMeasureBootLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + MemoryAllocationLib + DevicePathLib + UefiBootServicesTableLib + BaseCryptLib + PeCoffLib + BaseLib + SecurityManagementLib + +[Protocols] + gEfiTcgProtocolGuid ## CONSUMES + gEfiFirmwareVolume2ProtocolGuid ## CONSUMES + gEfiBlockIoProtocolGuid ## CONSUMES + gEfiDiskIoProtocolGuid ## CONSUMES + gEfiDevicePathToTextProtocolGuid ## SOMETIMES_CONSUMES (Only used in debug mode) diff --git a/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c new file mode 100644 index 0000000000..f085d62b77 --- /dev/null +++ b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c @@ -0,0 +1,39 @@ +/** @file + Provides a secure platform-specific method to clear PK(Platform Key). + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +/** + + This function detects whether a secure platform-specific method to clear PK(Platform Key) + is configured by platform owner. This method is provided for users force to clear PK + in case incorrect enrollment mis-haps. + + UEFI231 spec chapter 27.5.2 stipulates: The platform key may also be cleared using + a secure platform-specific method. In this case, the global variable SetupMode + must also be updated to 1. + + NOTE THAT: This function cannot depend on any EFI Variable Service since they are + not available when this function is called in AuthenticateVariable driver. + + @retval TRUE The Platform owner wants to force clear PK. + @retval FALSE The Platform owner doesn't want to force clear PK. + +**/ +BOOLEAN +EFIAPI +ForceClearPK ( + VOID + ) +{ + return FALSE; +} diff --git a/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf new file mode 100644 index 0000000000..5750198aa7 --- /dev/null +++ b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf @@ -0,0 +1,33 @@ +## @file +# Provides a secure platform-specific method to clear PK(Platform Key). +# +# Copyright (c) 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformSecureLibNull + FILE_GUID = 7FA68D82-10A4-4e71-9524-D3D9500D3CDF + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformSecureLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + PlatformSecureLibNull.c + +[Packages] + MdePkg/MdePkg.dec diff --git a/SecurityPkg/Library/TpmCommLib/CommonHeader.h b/SecurityPkg/Library/TpmCommLib/CommonHeader.h new file mode 100644 index 0000000000..b8496c7276 --- /dev/null +++ b/SecurityPkg/Library/TpmCommLib/CommonHeader.h @@ -0,0 +1,29 @@ +/** @file + The intenal header file for TpmCommLib. + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _TPMCOMMLIB_COMMON_HEADER_H_ +#define _TPMCOMMLIB_COMMON_HEADER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/SecurityPkg/Library/TpmCommLib/TisPc.c b/SecurityPkg/Library/TpmCommLib/TisPc.c new file mode 100644 index 0000000000..3d74a012df --- /dev/null +++ b/SecurityPkg/Library/TpmCommLib/TisPc.c @@ -0,0 +1,180 @@ +/** @file + Basic TIS (TPM Interface Specification) functions. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CommonHeader.h" + +/** + Check whether TPM chip exist. + + @param[in] TisReg Pointer to TIS register. + + @retval TRUE TPM chip exists. + @retval FALSE TPM chip is not found. +**/ +BOOLEAN +TisPcPresenceCheck ( + IN TIS_PC_REGISTERS_PTR TisReg + ) +{ + UINT8 RegRead; + + RegRead = MmioRead8 ((UINTN)&TisReg->Access); + return (BOOLEAN)(RegRead != (UINT8)-1); +} + +/** + Check whether the value of a TPM chip register satisfies the input BIT setting. + + @param[in] Register Address port of register to be checked. + @param[in] BitSet Check these data bits are set. + @param[in] BitClear Check these data bits are clear. + @param[in] TimeOut The max wait time (unit MicroSecond) when checking register. + + @retval EFI_SUCCESS The register satisfies the check bit. + @retval EFI_TIMEOUT The register can't run into the expected status in time. +**/ +EFI_STATUS +EFIAPI +TisPcWaitRegisterBits ( + IN UINT8 *Register, + IN UINT8 BitSet, + IN UINT8 BitClear, + IN UINT32 TimeOut + ) +{ + UINT8 RegRead; + UINT32 WaitTime; + + for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){ + RegRead = MmioRead8 ((UINTN)Register); + if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0) + return EFI_SUCCESS; + MicroSecondDelay (30); + } + return EFI_TIMEOUT; +} + +/** + Get BurstCount by reading the burstCount field of a TIS regiger + in the time of default TIS_TIMEOUT_D. + + @param[in] TisReg Pointer to TIS register. + @param[out] BurstCount Pointer to a buffer to store the got BurstConut. + + @retval EFI_SUCCESS Get BurstCount. + @retval EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL. + @retval EFI_TIMEOUT BurstCount can't be got in time. +**/ +EFI_STATUS +EFIAPI +TisPcReadBurstCount ( + IN TIS_PC_REGISTERS_PTR TisReg, + OUT UINT16 *BurstCount + ) +{ + UINT32 WaitTime; + UINT8 DataByte0; + UINT8 DataByte1; + + if (BurstCount == NULL || TisReg == NULL) { + return EFI_INVALID_PARAMETER; + } + + WaitTime = 0; + do { + // + // TIS_PC_REGISTERS_PTR->burstCount is UINT16, but it is not 2bytes aligned, + // so it needs to use MmioRead8 to read two times + // + DataByte0 = MmioRead8 ((UINTN)&TisReg->BurstCount); + DataByte1 = MmioRead8 ((UINTN)&TisReg->BurstCount + 1); + *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0); + if (*BurstCount != 0) { + return EFI_SUCCESS; + } + MicroSecondDelay (30); + WaitTime += 30; + } while (WaitTime < TIS_TIMEOUT_D); + + return EFI_TIMEOUT; +} + +/** + Set TPM chip to ready state by sending ready command TIS_PC_STS_READY + to Status Register in time. + + @param[in] TisReg Pointer to TIS register. + + @retval EFI_SUCCESS TPM chip enters into ready state. + @retval EFI_INVALID_PARAMETER TisReg is NULL. + @retval EFI_TIMEOUT TPM chip can't be set to ready state in time. +**/ +EFI_STATUS +EFIAPI +TisPcPrepareCommand ( + IN TIS_PC_REGISTERS_PTR TisReg + ) +{ + EFI_STATUS Status; + + if (TisReg == NULL) { + return EFI_INVALID_PARAMETER; + } + + MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY); + Status = TisPcWaitRegisterBits ( + &TisReg->Status, + TIS_PC_STS_READY, + 0, + TIS_TIMEOUT_B + ); + return Status; +} + +/** + Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE + to ACCESS Register in the time of default TIS_TIMEOUT_D. + + @param[in] TisReg Pointer to TIS register. + + @retval EFI_SUCCESS Get the control of TPM chip. + @retval EFI_INVALID_PARAMETER TisReg is NULL. + @retval EFI_NOT_FOUND TPM chip doesn't exit. + @retval EFI_TIMEOUT Can't get the TPM control in time. +**/ +EFI_STATUS +EFIAPI +TisPcRequestUseTpm ( + IN TIS_PC_REGISTERS_PTR TisReg + ) +{ + EFI_STATUS Status; + + if (TisReg == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!TisPcPresenceCheck (TisReg)) { + return EFI_NOT_FOUND; + } + + MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE); + Status = TisPcWaitRegisterBits ( + &TisReg->Access, + (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID), + 0, + TIS_TIMEOUT_D + ); + return Status; +} diff --git a/SecurityPkg/Library/TpmCommLib/TpmComm.c b/SecurityPkg/Library/TpmCommLib/TpmComm.c new file mode 100644 index 0000000000..3197f96a99 --- /dev/null +++ b/SecurityPkg/Library/TpmCommLib/TpmComm.c @@ -0,0 +1,50 @@ +/** @file + Basic TPM command functions. + +Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "CommonHeader.h" + +/** + Single function calculates SHA1 digest value for all raw data. It + combines Sha1Init(), Sha1Update() and Sha1Final(). + + @param[in] Data Raw data to be digested. + @param[in] DataLen Size of the raw data. + @param[out] Digest Pointer to a buffer that stores the final digest. + + @retval EFI_SUCCESS Always successfully calculate the final digest. +**/ +EFI_STATUS +EFIAPI +TpmCommHashAll ( + IN CONST UINT8 *Data, + IN UINTN DataLen, + OUT TPM_DIGEST *Digest + ) +{ + VOID *Sha1Ctx; + UINTN CtxSize; + + CtxSize = Sha1GetContextSize (); + Sha1Ctx = AllocatePool (CtxSize); + ASSERT (Sha1Ctx != NULL); + + Sha1Init (Sha1Ctx); + Sha1Update (Sha1Ctx, Data, DataLen); + Sha1Final (Sha1Ctx, (UINT8 *)Digest); + + FreePool (Sha1Ctx); + + return EFI_SUCCESS; +} + diff --git a/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf b/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf new file mode 100644 index 0000000000..7188a3b165 --- /dev/null +++ b/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf @@ -0,0 +1,46 @@ +## @file +# TpmCommLib instance implements basis TPM Interface Specification (TIS) and TPM command functions. +# +# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TpmCommLib + FILE_GUID = 7d9fe32e-a6a9-4cdf-abff-10cc7f22e1c9 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = TpmCommLib|DXE_DRIVER UEFI_DRIVER PEIM DXE_SMM_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + TisPc.c + TpmComm.c + CommonHeader.h + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + IoLib + TimerLib + BaseCryptLib + MemoryAllocationLib + DebugLib + diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec new file mode 100644 index 0000000000..8121f390a5 --- /dev/null +++ b/SecurityPkg/SecurityPkg.dec @@ -0,0 +1,122 @@ +## @file SecurityPkg.dec +# This package includes the security drivers, defintions(including PPIs/PROTOCOLs/GUIDs +# and library classes) and libraries instances. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials are licensed and made available under +# the terms and conditions of the BSD License which accompanies this distribution. +# The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + DEC_SPECIFICATION = 0x00010005 + PACKAGE_NAME = SecurityPkg + PACKAGE_GUID = 24369CAC-6AA6-4fb8-88DB-90BF061668AD + PACKAGE_VERSION = 0.91 + +[Includes] + Include + +[LibraryClasses] + ## @libraryclass Definitions for common TPM commands as library API for TPM + # module use. + TpmCommLib|Include/Library/TpmCommLib.h + +[Guids] + ## Security package token space guid + # Include/Guid/SecurityPkgTokenSpace.h + gEfiSecurityPkgTokenSpaceGuid = { 0xd3fb176, 0x9569, 0x4d51, { 0xa3, 0xef, 0x7d, 0x61, 0xc6, 0x4f, 0xea, 0xba }} + ## Guid acted as the authenticated variable store header's signature, and to specify the variable list entries put in the EFI system table. + # Include/Guid/AuthenticatedVariableFormat.h + gEfiAuthenticatedVariableGuid = { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } } + + ## Include/Guid/TcgEventHob.h + gTcgEventEntryHobGuid = { 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 }} + + ## Include/Guid/PhysicalPresenceData.h + gEfiPhysicalPresenceGuid = { 0xf6499b1, 0xe9ad, 0x493d, { 0xb9, 0xc2, 0x2f, 0x90, 0x81, 0x5c, 0x6c, 0xbc }} + +[Ppis] + ## Include/Ppi/LockPhysicalPresence.h + gPeiLockPhysicalPresencePpiGuid = { 0xef9aefe5, 0x2bd3, 0x4031, { 0xaf, 0x7d, 0x5e, 0xfe, 0x5a, 0xbb, 0x9a, 0xd } } + + ## Include/Ppi/TpmInitialized.h + gPeiTpmInitializedPpiGuid = { 0xe9db0d58, 0xd48d, 0x47f6, { 0x9c, 0x6e, 0x6f, 0x40, 0xe8, 0x6c, 0x7b, 0x41 }} + +[PcdsFixedAtBuild] + ## Pcd for OptionRom. + # Image verification policy settings: + # ALWAYS_EXECUTE 0x00000000 + # NEVER_EXECUTE 0x00000001 + # ALLOW_EXECUTE_ON_SECURITY_VIOLATION 0x00000002 + # DEFER_EXECUTE_ON_SECURITY_VIOLATION 0x00000003 + # DENY_EXECUTE_ON_SECURITY_VIOLATION 0x00000004 + # QUERY_USER_ON_SECURITY_VIOLATION 0x00000005 + gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x00|UINT32|0x00000001 + + ## Pcd for removable media. + # Removable media include CD-ROM, Floppy, USB and network. + # Image verification policy settings: + # ALWAYS_EXECUTE 0x00000000 + # NEVER_EXECUTE 0x00000001 + # ALLOW_EXECUTE_ON_SECURITY_VIOLATION 0x00000002 + # DEFER_EXECUTE_ON_SECURITY_VIOLATION 0x00000003 + # DENY_EXECUTE_ON_SECURITY_VIOLATION 0x00000004 + # QUERY_USER_ON_SECURITY_VIOLATION 0x00000005 + gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy|0x05|UINT32|0x00000002 + + ## Pcd for fixed media. + # Fixed media include hard disk. + # Image verification policy settings: + # ALWAYS_EXECUTE 0x00000000 + # NEVER_EXECUTE 0x00000001 + # ALLOW_EXECUTE_ON_SECURITY_VIOLATION 0x00000002 + # DEFER_EXECUTE_ON_SECURITY_VIOLATION 0x00000003 + # DENY_EXECUTE_ON_SECURITY_VIOLATION 0x00000004 + # QUERY_USER_ON_SECURITY_VIOLATION 0x00000005 + gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy|0x05|UINT32|0x00000003 + + ## Defer Image Load policy settings. + # The policy is bitwise. + # If bit is set, the image from corresponding device will be trust when loading. + # + # IMAGE_UNKNOWN 0x00000001 + # IMAGE_FROM_FV 0x00000002 + # IMAGE_FROM_OPTION_ROM 0x00000004 + # IMAGE_FROM_REMOVABLE_MEDIA 0x00000008 + # IMAGE_FROM_FIXED_MEDIA 0x00000010 + gEfiSecurityPkgTokenSpaceGuid.PcdDeferImageLoadPolicy|0x0000001F|UINT32|0x0000004 + + ## The token file name used to save credential in USB credential provider driver. + # The specified file should be saved at the root directory of USB storage disk. + gEfiSecurityPkgTokenSpaceGuid.PcdFixedUsbCredentialProviderTokenFileName|L"Token.bin"|VOID*|0x00000005 + + ## The size of Append variable buffer. This buffer is reserved for runtime use, OS can append data into one existing variable. + gEfiSecurityPkgTokenSpaceGuid.PcdMaxAppendVariableSize|0x2000|UINT32|0x30000005 + + ## This PCD specifies the type of TCG platform that contains TPM chip. + # This PCD is only avaiable when PcdTpmPhysicalPresence is TRUE. + # If 0, TCG platform type is PC client. + # If 1, TCG platform type is server. + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass|0|UINT8|0x00000006 + + ## The PCD is used to control whether to support hiding the TPM. + # If TRUE, PcdHideTpm controls whether to hide the TPM. + gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport|FALSE|BOOLEAN|0x00000007 + +[PcdsDynamic, PcdsDynamicEx] + ## The PCD is used to control whether to hide the TPM. + gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm|FALSE|BOOLEAN|0x00010002 + + ## The PCD is used to specify whether or not MOR (MemoryOverwriteControl) feature is enabled. + gEfiSecurityPkgTokenSpaceGuid.PcdMorEnable|FALSE|BOOLEAN|0x00010000 + +[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx] + ## This PCD indicates the presence or absence of the platform operator. + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPhysicalPresence|TRUE|BOOLEAN|0x00010001 + diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc new file mode 100644 index 0000000000..09aa8fcca0 --- /dev/null +++ b/SecurityPkg/SecurityPkg.dsc @@ -0,0 +1,125 @@ +## @file +# Security Module Package for All Architectures. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + PLATFORM_NAME = SecurityPkg + PLATFORM_GUID = B2C4614D-AE76-47ba-B876-5988BFED064F + PLATFORM_VERSION = 0.91 + DSC_SPECIFICATION = 0x00010005 + OUTPUT_DIRECTORY = Build/SecurityPkg + SUPPORTED_ARCHITECTURES = IA32|IPF|X64|EBC + BUILD_TARGETS = DEBUG|RELEASE + SKUID_IDENTIFIER = DEFAULT + +[LibraryClasses] + DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf + DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf + BaseLib|MdePkg/Library/BaseLib/BaseLib.inf + SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf + TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf + UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf + + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf + UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf + DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf + UefiLib|MdePkg/Library/UefiLib/UefiLib.inf + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf + UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf + HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf + UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf + PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf + IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf + TpmCommLib|SecurityPkg/Library/TpmCommLib/TpmCommLib.inf + PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf + +[LibraryClasses.common.PEIM] + PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf + PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf + PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf + HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf + MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf + +[LibraryClasses.common.DXE_DRIVER] + HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf + ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf + +[LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SAL_DRIVER,] + MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf + DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf + +[LibraryClasses.IPF.DXE_SAL_DRIVER] + ExtendedSalLib|MdePkg/Library/DxeRuntimeExtendedSalLib/DxeRuntimeExtendedSalLib.inf + +[LibraryClasses.common.DXE_SMM_DRIVER] + SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf + MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf + +[Components] + SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf + SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf + SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf + SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf + SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf + SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf + SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf + + # + # Application + # + SecurityPkg/Application/VariableInfo/VariableInfo.inf + + # + # TPM + # + SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf + SecurityPkg/Tcg/TcgPei/TcgPei.inf + SecurityPkg/Tcg/TcgDxe/TcgDxe.inf + SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf + SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf + SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf + SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf { + + PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf + } + SecurityPkg/Tcg/TcgSmm/TcgSmm.inf + +[Components.IA32, Components.X64] + SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf { + + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf + } + + SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf + SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf + +[Components.IPF] + SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf + +[Components.EBC] +# Build only + SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf + +[BuildOptions] + MSFT:*_*_IA32_DLINK_FLAGS = /ALIGN:256 + INTEL:*_*_IA32_DLINK_FLAGS = /ALIGN:256 + diff --git a/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c new file mode 100644 index 0000000000..ce53112dc5 --- /dev/null +++ b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c @@ -0,0 +1,82 @@ +/** @file + TCG MOR (Memory Overwrite Request) Control Driver. + + This driver initilize MemoryOverwriteRequestControl variable. It + will clear MOR_CLEAR_MEMORY_BIT bit if it is set. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TcgMor.h" + +/** + Entry Point for TCG MOR Control driver. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SystemTable A Pointer to the EFI System Table. + + @retval EFI_SUCEESS + @return Others Some error occurs. +**/ +EFI_STATUS +EFIAPI +MorDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINT8 MorControl; + UINTN DataSize; + + /// + /// The firmware is required to create the MemoryOverwriteRequestControl UEFI variable. + /// + + DataSize = sizeof (MorControl); + Status = gRT->GetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + NULL, + &DataSize, + &MorControl + ); + if (EFI_ERROR (Status)) { + // + // Set default value to 0 + // + MorControl = 0; + } else { + if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) { + // + // MorControl is expected, directly return to avoid unnecessary variable operation + // + return EFI_SUCCESS; + } + // + // Clear MOR_CLEAR_MEMORY_BIT + // + DEBUG ((EFI_D_INFO, "TcgMor: Clear MorClearMemory bit\n")); + MorControl &= 0xFE; + } + + Status = gRT->SetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &MorControl + ); + ASSERT_EFI_ERROR (Status); + return Status; +} + + diff --git a/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h new file mode 100644 index 0000000000..bfad2cf2f0 --- /dev/null +++ b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h @@ -0,0 +1,27 @@ +/** @file + The header file for TcgMor. + +Copyright (c) 2009, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __TCG_MOR_H__ +#define __TCG_MOR_H__ + +#include + +#include + +#include +#include +#include + +#endif + diff --git a/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf new file mode 100644 index 0000000000..e62a90447c --- /dev/null +++ b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf @@ -0,0 +1,50 @@ +## @file +# Component description file for Memory Overwrite Control driver. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgMor + FILE_GUID = AD416CE3-A483-45b1-94C2-4B4E4D575562 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = MorDriverEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + TcgMor.c + TcgMor.h + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + ReportStatusCodeLib + DebugLib + +[Guids] + gEfiMemoryOverwriteControlDataGuid # GUID ALWAYS_CONSUMED + +[Depex] + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid AND + gEfiTcgProtocolGuid + diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c new file mode 100644 index 0000000000..187c3ca888 --- /dev/null +++ b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c @@ -0,0 +1,1115 @@ +/** @file + This driver checks whether there is pending TPM request. If yes, + it will display TPM request information and ask for user confirmation. + The TPM request will be cleared after it is processed. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PhysicalPresence.h" + +EFI_HII_HANDLE mPpStringPackHandle; + +/** + Get TPM physical presence permanent flags. + + @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag. + @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag. + + @retval EFI_SUCCESS Flags were returns successfully. + @retval other Failed to locate EFI TCG Protocol. + +**/ +EFI_STATUS +GetTpmCapability ( + OUT BOOLEAN *LifetimeLock, + OUT BOOLEAN *CmdEnable + ) +{ + EFI_STATUS Status; + EFI_TCG_PROTOCOL *TcgProtocol; + TPM_RQU_COMMAND_HDR *TpmRqu; + TPM_RSP_COMMAND_HDR *TpmRsp; + UINT32 *SendBufPtr; + UINT8 SendBuffer[sizeof (*TpmRqu) + sizeof (UINT32) * 3]; + TPM_PERMANENT_FLAGS *TpmPermanentFlags; + UINT8 RecvBuffer[40]; + + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Fill request header + // + TpmRsp = (TPM_RSP_COMMAND_HDR*)RecvBuffer; + TpmRqu = (TPM_RQU_COMMAND_HDR*)SendBuffer; + + TpmRqu->tag = H2NS (TPM_TAG_RQU_COMMAND); + TpmRqu->paramSize = H2NL (sizeof (SendBuffer)); + TpmRqu->ordinal = H2NL (TPM_ORD_GetCapability); + + // + // Set request parameter + // + SendBufPtr = (UINT32*)(TpmRqu + 1); + WriteUnaligned32 (SendBufPtr++, H2NL (TPM_CAP_FLAG)); + WriteUnaligned32 (SendBufPtr++, H2NL (sizeof (TPM_CAP_FLAG_PERMANENT))); + WriteUnaligned32 (SendBufPtr, H2NL (TPM_CAP_FLAG_PERMANENT)); + + Status = TcgProtocol->PassThroughToTpm ( + TcgProtocol, + sizeof (SendBuffer), + (UINT8*)TpmRqu, + sizeof (RecvBuffer), + (UINT8*)&RecvBuffer + ); + ASSERT_EFI_ERROR (Status); + ASSERT (TpmRsp->tag == H2NS (TPM_TAG_RSP_COMMAND)); + ASSERT (TpmRsp->returnCode == 0); + + TpmPermanentFlags = (TPM_PERMANENT_FLAGS *)&RecvBuffer[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)]; + + if (LifetimeLock != NULL) { + *LifetimeLock = TpmPermanentFlags->physicalPresenceLifetimeLock; + } + + if (CmdEnable != NULL) { + *CmdEnable = TpmPermanentFlags->physicalPresenceCMDEnable; + } + + return Status; +} + +/** + Issue TSC_PhysicalPresence command to TPM. + + @param[in] PhysicalPresence The state to set the TPM's Physical Presence flags. + + @retval EFI_SUCCESS TPM executed the command successfully. + @retval EFI_SECURITY_VIOLATION TPM returned error when executing the command. + @retval other Failed to locate EFI TCG Protocol. + +**/ +EFI_STATUS +TpmPhysicalPresence ( + IN TPM_PHYSICAL_PRESENCE PhysicalPresence + ) +{ + EFI_STATUS Status; + EFI_TCG_PROTOCOL *TcgProtocol; + TPM_RQU_COMMAND_HDR *TpmRqu; + TPM_PHYSICAL_PRESENCE *TpmPp; + TPM_RSP_COMMAND_HDR TpmRsp; + UINT8 Buffer[sizeof (*TpmRqu) + sizeof (*TpmPp)]; + + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol); + if (EFI_ERROR (Status)) { + return Status; + } + + TpmRqu = (TPM_RQU_COMMAND_HDR*)Buffer; + TpmPp = (TPM_PHYSICAL_PRESENCE*)(TpmRqu + 1); + + TpmRqu->tag = H2NS (TPM_TAG_RQU_COMMAND); + TpmRqu->paramSize = H2NL (sizeof (Buffer)); + TpmRqu->ordinal = H2NL (TSC_ORD_PhysicalPresence); + WriteUnaligned16 (TpmPp, (TPM_PHYSICAL_PRESENCE) H2NS (PhysicalPresence)); + + Status = TcgProtocol->PassThroughToTpm ( + TcgProtocol, + sizeof (Buffer), + (UINT8*)TpmRqu, + sizeof (TpmRsp), + (UINT8*)&TpmRsp + ); + ASSERT_EFI_ERROR (Status); + ASSERT (TpmRsp.tag == H2NS (TPM_TAG_RSP_COMMAND)); + if (TpmRsp.returnCode != 0) { + // + // If it fails, some requirements may be needed for this command. + // + return EFI_SECURITY_VIOLATION; + } + return Status; +} + +/** + Issue a TPM command for which no additional output data will be returned. + + @param[in] TcgProtocol EFI TCG Protocol instance. + @param[in] Ordinal TPM command code. + @param[in] AdditionalParameterSize Additional parameter size. + @param[in] AdditionalParameters Pointer to the Additional paramaters. + + @retval TPM_PP_BIOS_FAILURE Error occurred during sending command to TPM or + receiving response from TPM. + @retval Others Return code from the TPM device after command execution. + +**/ +TPM_RESULT +TpmCommandNoReturnData ( + IN EFI_TCG_PROTOCOL *TcgProtocol, + IN TPM_COMMAND_CODE Ordinal, + IN UINTN AdditionalParameterSize, + IN VOID *AdditionalParameters + ) +{ + EFI_STATUS Status; + TPM_RQU_COMMAND_HDR *TpmRqu; + TPM_RSP_COMMAND_HDR TpmRsp; + UINT32 Size; + + TpmRqu = (TPM_RQU_COMMAND_HDR*)AllocatePool ( + sizeof (*TpmRqu) + AdditionalParameterSize + ); + if (TpmRqu == NULL) { + return TPM_PP_BIOS_FAILURE; + } + + TpmRqu->tag = H2NS (TPM_TAG_RQU_COMMAND); + Size = (UINT32)(sizeof (*TpmRqu) + AdditionalParameterSize); + TpmRqu->paramSize = H2NL (Size); + TpmRqu->ordinal = H2NL (Ordinal); + gBS->CopyMem (TpmRqu + 1, AdditionalParameters, AdditionalParameterSize); + + Status = TcgProtocol->PassThroughToTpm ( + TcgProtocol, + Size, + (UINT8*)TpmRqu, + (UINT32)sizeof (TpmRsp), + (UINT8*)&TpmRsp + ); + FreePool (TpmRqu); + if (EFI_ERROR (Status) || (TpmRsp.tag != H2NS (TPM_TAG_RSP_COMMAND))) { + return TPM_PP_BIOS_FAILURE; + } + return H2NL (TpmRsp.returnCode); +} + +/** + Execute physical presence operation requested by the OS. + + @param[in] TcgProtocol EFI TCG Protocol instance. + @param[in] CommandCode Physical presence operation value. + @param[in, out] PpiFlags The physical presence interface flags. + + @retval TPM_PP_BIOS_FAILURE Unknown physical presence operation. + @retval TPM_PP_BIOS_FAILURE Error occurred during sending command to TPM or + receiving response from TPM. + @retval Others Return code from the TPM device after command execution. + +**/ +TPM_RESULT +ExecutePhysicalPresence ( + IN EFI_TCG_PROTOCOL *TcgProtocol, + IN UINT8 CommandCode, + IN OUT UINT8 *PpiFlags + ) +{ + BOOLEAN BoolVal; + TPM_RESULT TpmResponse; + UINT32 InData[5]; + + switch (CommandCode) { + case ENABLE: + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_PhysicalEnable, + 0, + NULL + ); + + case DISABLE: + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_PhysicalDisable, + 0, + NULL + ); + + case ACTIVATE: + BoolVal = FALSE; + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_PhysicalSetDeactivated, + sizeof (BoolVal), + &BoolVal + ); + + case DEACTIVATE: + BoolVal = TRUE; + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_PhysicalSetDeactivated, + sizeof (BoolVal), + &BoolVal + ); + + case CLEAR: + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_ForceClear, + 0, + NULL + ); + + case ENABLE_ACTIVATE: + TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE, PpiFlags); + if (TpmResponse == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, ACTIVATE, PpiFlags); + } + return TpmResponse; + + case DEACTIVATE_DISABLE: + TpmResponse = ExecutePhysicalPresence (TcgProtocol, DEACTIVATE, PpiFlags); + if (TpmResponse == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, DISABLE, PpiFlags); + } + return TpmResponse; + + case SET_OWNER_INSTALL_TRUE: + BoolVal = TRUE; + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_SetOwnerInstall, + sizeof (BoolVal), + &BoolVal + ); + + case SET_OWNER_INSTALL_FALSE: + BoolVal = FALSE; + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_SetOwnerInstall, + sizeof (BoolVal), + &BoolVal + ); + + case ENABLE_ACTIVATE_OWNER_TRUE: + // + // ENABLE_ACTIVATE + SET_OWNER_INSTALL_TRUE + // SET_OWNER_INSTALL_TRUE will be executed atfer reboot + // + if ((*PpiFlags & FLAG_RESET_TRACK) == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags); + *PpiFlags |= FLAG_RESET_TRACK; + } else { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, SET_OWNER_INSTALL_TRUE, PpiFlags); + *PpiFlags &= ~FLAG_RESET_TRACK; + } + return TpmResponse; + + case DEACTIVATE_DISABLE_OWNER_FALSE: + TpmResponse = ExecutePhysicalPresence (TcgProtocol, SET_OWNER_INSTALL_FALSE, PpiFlags); + if (TpmResponse == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, DEACTIVATE_DISABLE, PpiFlags); + } + return TpmResponse; + + case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + InData[0] = H2NL (TPM_SET_STCLEAR_DATA); // CapabilityArea + InData[1] = H2NL (sizeof(UINT32)); // SubCapSize + InData[2] = H2NL (TPM_SD_DEFERREDPHYSICALPRESENCE); // SubCap + InData[3] = H2NL (sizeof(UINT32)); // SetValueSize + InData[4] = H2NL (1); // UnownedFieldUpgrade; bit0 + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_SetCapability, + sizeof (UINT32) * 5, + InData + ); + + case SET_OPERATOR_AUTH: + // + // TPM_SetOperatorAuth + // This command requires UI to prompt user for Auth data + // Here it is NOT implemented + // + return TPM_PP_BIOS_FAILURE; + + case CLEAR_ENABLE_ACTIVATE: + TpmResponse = ExecutePhysicalPresence (TcgProtocol, CLEAR, PpiFlags); + if (TpmResponse == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags); + } + return TpmResponse; + + case SET_NO_PPI_PROVISION_FALSE: + *PpiFlags &= ~FLAG_NO_PPI_PROVISION; + return 0; + + case SET_NO_PPI_PROVISION_TRUE: + *PpiFlags |= FLAG_NO_PPI_PROVISION; + return 0; + + case SET_NO_PPI_CLEAR_FALSE: + *PpiFlags &= ~FLAG_NO_PPI_CLEAR; + return 0; + + case SET_NO_PPI_CLEAR_TRUE: + *PpiFlags |= FLAG_NO_PPI_CLEAR; + return 0; + + case SET_NO_PPI_MAINTENANCE_FALSE: + *PpiFlags &= ~FLAG_NO_PPI_MAINTENANCE; + return 0; + + case SET_NO_PPI_MAINTENANCE_TRUE: + *PpiFlags |= FLAG_NO_PPI_MAINTENANCE; + return 0; + + case ENABLE_ACTIVATE_CLEAR: + TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags); + if (TpmResponse == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, CLEAR, PpiFlags); + } + return TpmResponse; + + case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + // + // ENABLE_ACTIVATE + CLEAR_ENABLE_ACTIVATE + // CLEAR_ENABLE_ACTIVATE will be executed atfer reboot. + // + if ((*PpiFlags & FLAG_RESET_TRACK) == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags); + *PpiFlags |= FLAG_RESET_TRACK; + } else { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, CLEAR_ENABLE_ACTIVATE, PpiFlags); + *PpiFlags &= ~FLAG_RESET_TRACK; + } + return TpmResponse; + + default: + ; + } + return TPM_PP_BIOS_FAILURE; +} + + +/** + Read the specified key for user confirmation. + + @param[in] CautionKey If true, F12 is used as confirm key; + If false, F10 is used as confirm key. + + @retval TRUE User confirmed the changes by input. + @retval FALSE User discarded the changes. + +**/ +BOOLEAN +ReadUserKey ( + IN BOOLEAN CautionKey + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + UINT16 InputKey; + EFI_TPL OldTpl; + + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + gBS->RestoreTPL (TPL_APPLICATION); + + InputKey = 0; + do { + Status = gBS->CheckEvent (gST->ConIn->WaitForKey); + if (!EFI_ERROR (Status)) { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (Key.ScanCode == SCAN_ESC) { + InputKey = Key.ScanCode; + } + if ((Key.ScanCode == SCAN_F10) && !CautionKey) { + InputKey = Key.ScanCode; + } + if ((Key.ScanCode == SCAN_F12) && CautionKey) { + InputKey = Key.ScanCode; + } + } + } while (InputKey == 0); + + gBS->RaiseTPL (OldTpl); + + if (InputKey != SCAN_ESC) { + return TRUE; + } + + return FALSE; +} + +/** + Display the confirm text and get user confirmation. + + @param[in] TpmPpCommand The requested TPM physical presence command. + + @retval TRUE The user has confirmed the changes. + @retval FALSE The user doesn't confirm the changes. +**/ +BOOLEAN +UserConfirm ( + IN UINT8 TpmPpCommand + ) +{ + CHAR16 *ConfirmText; + CHAR16 *TmpStr1; + CHAR16 *TmpStr2; + UINTN BufSize; + BOOLEAN CautionKey; + UINT16 Index; + CHAR16 DstStr[81]; + + TmpStr2 = NULL; + CautionKey = FALSE; + BufSize = CONFIRM_BUFFER_SIZE; + ConfirmText = AllocateZeroPool (BufSize); + ASSERT (ConfirmText != NULL); + + mPpStringPackHandle = HiiAddPackages ( + &gEfiPhysicalPresenceGuid, + NULL, + PhysicalPresenceDxeStrings, + NULL + ); + ASSERT (mPpStringPackHandle != NULL); + + switch (TpmPpCommand) { + case ENABLE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case DISABLE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DISABLE), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case ACTIVATE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACTIVATE), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case DEACTIVATE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DEACTIVATE), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case CLEAR: + CautionKey = TRUE; + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CLEAR), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + StrnCat (ConfirmText, L" \n\n", (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case ENABLE_ACTIVATE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE_ACTIVATE), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case DEACTIVATE_DISABLE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DEACTIVATE_DISABLE), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_OFF), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case SET_OWNER_INSTALL_TRUE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ALLOW_TAKE_OWNERSHIP), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case SET_OWNER_INSTALL_FALSE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DISALLOW_TAKE_OWNERSHIP), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case ENABLE_ACTIVATE_OWNER_TRUE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_TURN_ON), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case DEACTIVATE_DISABLE_OWNER_FALSE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_TURN_OFF), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_OFF), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + CautionKey = TRUE; + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_UNOWNED_FIELD_UPGRADE), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_UPGRADE_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_MAINTAIN), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case SET_OPERATOR_AUTH: + // + // TPM_SetOperatorAuth + // This command requires UI to prompt user for Auth data + // Here it is NOT implemented + // + break; + + case CLEAR_ENABLE_ACTIVATE: + CautionKey = TRUE; + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CLEAR_TURN_ON), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR_CONT), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case SET_NO_PPI_PROVISION_TRUE: + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_PROVISION), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_PPI_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_INFO), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case SET_NO_PPI_CLEAR_TRUE: + CautionKey = TRUE; + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CLEAR), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_PPI_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_CLEAR), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + StrnCat (ConfirmText, L" \n\n", (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_INFO), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case SET_NO_PPI_MAINTENANCE_TRUE: + CautionKey = TRUE; + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_MAINTAIN), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_PPI_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_MAINTAIN), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_INFO), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case ENABLE_ACTIVATE_CLEAR: + CautionKey = TRUE; + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + StrnCat (ConfirmText, L" \n\n", (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + CautionKey = TRUE; + TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE), NULL); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR_CONT), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL); + StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + default: + ; + } + + if (TmpStr2 == NULL) { + FreePool (ConfirmText); + return FALSE; + } + + TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_REJECT_KEY), NULL); + BufSize -= StrSize (ConfirmText); + UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2); + + DstStr[80] = L'\0'; + for (Index = 0; Index < StrLen (ConfirmText); Index += 80) { + StrnCpy(DstStr, ConfirmText + Index, 80); + Print (DstStr); + } + + FreePool (TmpStr1); + FreePool (TmpStr2); + FreePool (ConfirmText); + + if (ReadUserKey (CautionKey)) { + return TRUE; + } + + return FALSE; +} + +/** + Check and execute the requested physical presence command. + + @param[in, out] TcgPpData Point to the physical presence NV variable. + +**/ +VOID +ExecutePendingTpmRequest ( + IN OUT EFI_PHYSICAL_PRESENCE *TcgPpData + ) +{ + EFI_STATUS Status; + EFI_TCG_PROTOCOL *TcgProtocol; + UINTN DataSize; + UINT8 Flags; + BOOLEAN RequestConfirmed; + + Flags = TcgPpData->Flags; + RequestConfirmed = FALSE; + switch (TcgPpData->PPRequest) { + case NO_ACTION: + return; + case ENABLE: + case DISABLE: + case ACTIVATE: + case DEACTIVATE: + case ENABLE_ACTIVATE: + case DEACTIVATE_DISABLE: + case SET_OWNER_INSTALL_TRUE: + case SET_OWNER_INSTALL_FALSE: + case ENABLE_ACTIVATE_OWNER_TRUE: + case DEACTIVATE_DISABLE_OWNER_FALSE: + case SET_OPERATOR_AUTH: + if ((Flags & FLAG_NO_PPI_PROVISION) != 0) { + RequestConfirmed = TRUE; + } + break; + + case CLEAR: + case ENABLE_ACTIVATE_CLEAR: + if ((Flags & FLAG_NO_PPI_CLEAR) != 0) { + RequestConfirmed = TRUE; + } + break; + + case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) { + RequestConfirmed = TRUE; + } + break; + + case CLEAR_ENABLE_ACTIVATE: + case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) { + RequestConfirmed = TRUE; + } + break; + + case SET_NO_PPI_PROVISION_FALSE: + case SET_NO_PPI_CLEAR_FALSE: + case SET_NO_PPI_MAINTENANCE_FALSE: + RequestConfirmed = TRUE; + break; + } + + if ((Flags & FLAG_RESET_TRACK) != 0) { + // + // It had been confirmed in last boot, it doesn't need confirm again. + // + RequestConfirmed = TRUE; + } + + if (!RequestConfirmed) { + // + // Print confirm text and wait for approval. + // + RequestConfirmed = UserConfirm (TcgPpData->PPRequest); + } + + // + // Execute requested physical presence command. + // + TcgPpData->PPResponse = TPM_PP_USER_ABORT; + if (RequestConfirmed) { + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID**) &TcgProtocol); + ASSERT_EFI_ERROR (Status); + TcgPpData->PPResponse = ExecutePhysicalPresence (TcgProtocol, TcgPpData->PPRequest, &TcgPpData->Flags); + } + + // + // Clear request + // + if ((TcgPpData->Flags & FLAG_RESET_TRACK) == 0) { + TcgPpData->LastPPRequest = TcgPpData->PPRequest; + TcgPpData->PPRequest = 0; + } + + // + // Save changes + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = gRT->SetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + TcgPpData + ); + if (EFI_ERROR (Status)) { + return; + } + + if (TcgPpData->PPResponse == TPM_PP_USER_ABORT) { + return; + } + + // + // Reset system to make new TPM settings in effect + // + switch (TcgPpData->LastPPRequest) { + case ACTIVATE: + case DEACTIVATE: + case CLEAR: + case ENABLE_ACTIVATE: + case DEACTIVATE_DISABLE: + case ENABLE_ACTIVATE_OWNER_TRUE: + case DEACTIVATE_DISABLE_OWNER_FALSE: + case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + case CLEAR_ENABLE_ACTIVATE: + case ENABLE_ACTIVATE_CLEAR: + case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + break; + default: + if (TcgPpData->PPRequest != 0) { + break; + } + return; + } + + Print (L"Rebooting system to make TPM settings in effect\n"); + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + ASSERT (FALSE); +} + +/** + Check and execute the physical presence command requested and + Lock physical presence. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + BOOLEAN LifetimeLock; + BOOLEAN CmdEnable; + UINTN DataSize; + EFI_PHYSICAL_PRESENCE TcgPpData; + + // + // Check pending request, if not exist, just return. + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &TcgPpData + ); + ASSERT_EFI_ERROR (Status); + DEBUG ((EFI_D_INFO, "[TPM] Flags=%x, PPRequest=%x\n", TcgPpData.Flags, TcgPpData.PPRequest)); + + Status = GetTpmCapability (&LifetimeLock, &CmdEnable); + if (EFI_ERROR (Status)) { + return ; + } + + if (!CmdEnable) { + if (LifetimeLock) { + // + // physicalPresenceCMDEnable is locked, can't execute physical presence command. + // + return ; + } + Status = TpmPhysicalPresence (TPM_PHYSICAL_PRESENCE_CMD_ENABLE); + if (EFI_ERROR (Status)) { + return ; + } + } + + // + // Set operator physical presence flags + // + TpmPhysicalPresence (TPM_PHYSICAL_PRESENCE_PRESENT); + + // + // Execute pending TPM request. + // + ExecutePendingTpmRequest (&TcgPpData); + DEBUG ((EFI_D_INFO, "[TPM] PPResponse = %x\n", TcgPpData.PPResponse)); + + // + // Lock physical presence. + // + TpmPhysicalPresence (TPM_PHYSICAL_PRESENCE_NOTPRESENT | TPM_PHYSICAL_PRESENCE_LOCK); +} + +/** + The driver's entry point. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +DriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_EVENT Event; + EFI_STATUS Status; + UINTN DataSize; + EFI_PHYSICAL_PRESENCE TcgPpData; + + // + // Initialize physical presence variable exists. + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &TcgPpData + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_NOT_FOUND) { + ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData)); + TcgPpData.Flags |= FLAG_NO_PPI_PROVISION; + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = gRT->SetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &TcgPpData + ); + } + ASSERT_EFI_ERROR (Status); + } + + // + // TPL Level of physical presence should be larger + // than one of TcgDxe driver (TPL_CALLBACK) + // + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + OnReadyToBoot, + NULL, + &Event + ); + return Status; +} + diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h new file mode 100644 index 0000000000..63d6f21cae --- /dev/null +++ b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h @@ -0,0 +1,38 @@ +/** @file + The header file for TPM physical presence driver. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __PHYSICAL_PRESENCE_H__ +#define __PHYSICAL_PRESENCE_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TPM_PP_USER_ABORT ((TPM_RESULT)(-0x10)) +#define TPM_PP_BIOS_FAILURE ((TPM_RESULT)(-0x0f)) + +#define CONFIRM_BUFFER_SIZE 4096 + +#endif diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf new file mode 100644 index 0000000000..9b4aded16f --- /dev/null +++ b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf @@ -0,0 +1,61 @@ +## @file +# Component file for PhysicalPresenceDxe driver. +# +# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PhysicalPresenceDxe + FILE_GUID = D85A4A0C-2E73-4491-92E1-DCEFC3882A68 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = DriverEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + PhysicalPresence.c + PhysicalPresence.h + PhysicalPresenceStrings.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + PrintLib + HiiLib + +[Protocols] + gEfiTcgProtocolGuid + +[Guids] + gEfiPhysicalPresenceGuid + +[Depex] + gEfiTcgProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid AND + gEfiResetArchProtocolGuid + diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..2034af7a95b0c75f4f0d2e8fc9b0162453c4136d GIT binary patch literal 8304 zcmc(kTW=dT5QX_%pg*8*3kOA;qOp@a^dTsU%CelO^+mAdv;hhTvgBLiTO`@8|9so? zaZHmdOKYxS!w^=xOYRP5&YT&Nv;Y0OD{r8Q?>1>W#HdN+Q^;g zexlZY^uOrGX8fj}IF}s8Kaj+Up88(zz0~=wd#&G3x_WhU_r|?(KkB-z5s<~GNEk^5 z|9!QZ#*6A{sGldIZ0ra+j@+dr45iD@ZrN?QU%XCT>2T!j#hNqegj96zYs{g}6Fq@# zeQAk(CmNf+YrSU(p6DL!7#Cz16_RPI21;Os%pjXL!Jn2(9r&s5cJ)u&h1USN zQ41UA#E%iA80tg49ne67GkGw+w=A!(=zguFi|KjgF&OCou9Zj91ZkjPI5Eyx_gK3t z9mAM-0Ja!f`|2@o1P)AVR7Rx`u6U4UN3?;?=tD+d{AqhMc=1bU(gx3NL|o*+23;q@6qQE^&xT7k5=fu zp;6FkL+x!zNPl>M5RKM0;vg&+_IcoqtykS~F7XW)!oa<^H^t6Q#F> zLq`l^%#|dj$ump0_`MLmF!R7O8xG>5SJECy3woD6d@vU73(0$dRTfoUjkWH29?OQt z>*;-Phh_Kuq7E0*<-jv4)xzEf`!r`AcoxN+Lf_$yEpYNm*JGW@C|~p}kpa6cOPs0a zTi+jJCFBdDggE}r_nT$py{_6W5-A;z-Q*_sl7-gA=b@e$9kRRGw(aL0Pz05U-bm5LJCBVu{wAXyYApOm9vZvP zw`hm?5&v0^wmckWzm!LKDB4GEoalf@it$Ik}vRiBVg% zSuCAxji zKS<+F$u%}tWcHve>`simqTk%KD;#IDWR;9d@c2r`i)mAg5tjoF>OwEV6j&mG8y~@>v ziXH1~W-`uoG-32r;gpVh_c~V-n^F7nQ^1FLHQi@ZA){JYRaGeOCD_s3?`x~ZZFn@_ z%j-D^=UP>k{Z9Hc#7L`_fH&3qv_gf(VQpbmSlelRQ_wTLgN_x~zWVlsP26eOswBk= zrcGCH!#*zTxk3fkP^KzUcwShggx*jqF2r6m1#u$Gq?c<2RvG!Ez6(7OWMjQawrB+b zq}VP3S*)q}P7$*zb3gTW+oc;qL;nV=8nQDouEmc~&D-^rXw%0=3sQ6IHD%x3W%jI= zhx1}Zs02ogbq!we`wB6!=f8dst6-0>sXtNQqULUqV|DT9CF2vjZQer0v447&x8N7w zPpHljcVHU49W=A*DPM$O7X5fXucleXbM|~Zjp@VjY|2tN6>F=J)1ZPyu)02{3)P;C z(Nq_SX1)(SH>X3Un^!@bk3ODY_1={ozc5$B|a=;lm7=kF34chnx!lYc97foqD76JSv%G$qF#K_k8{KH GJorD<`TC6j literal 0 HcmV?d00001 diff --git a/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c new file mode 100644 index 0000000000..e694db8cf1 --- /dev/null +++ b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c @@ -0,0 +1,134 @@ +/** @file + This driver produces PEI_LOCK_PHYSICAL_PRESENCE_PPI to indicate + whether TPM need be locked or not. It can be replaced by a platform + specific driver. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +/** + This interface returns whether TPM physical presence needs be locked or not. + + @param[in] PeiServices The pointer to the PEI Services Table. + + @retval TRUE The TPM physical presence should be locked. + @retval FALSE The TPM physical presence cannot be locked. + +**/ +BOOLEAN +EFIAPI +LockTpmPhysicalPresence ( + IN CONST EFI_PEI_SERVICES **PeiServices + ); + +// +// Gobal defintions for lock physical presence PPI and its descriptor. +// +PEI_LOCK_PHYSICAL_PRESENCE_PPI mLockPhysicalPresencePpi = { + LockTpmPhysicalPresence +}; + +EFI_PEI_PPI_DESCRIPTOR mLockPhysicalPresencePpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiLockPhysicalPresencePpiGuid, + &mLockPhysicalPresencePpi +}; + +/** + This interface returns whether TPM physical presence needs be locked or not. + + @param[in] PeiServices The pointer to the PEI Services Table. + + @retval TRUE The TPM physical presence should be locked. + @retval FALSE The TPM physical presence cannot be locked. + +**/ +BOOLEAN +EFIAPI +LockTpmPhysicalPresence ( + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable; + UINTN DataSize; + EFI_PHYSICAL_PRESENCE TcgPpData; + + // + // The CRTM has sensed the physical presence assertion of the user. For example, + // the user has pressed the startup button or inserted a USB dongle. The details + // of the implementation are vendor-specific. Here we read a PCD value to indicate + // whether operator physical presence. + // + if (!PcdGetBool (PcdTpmPhysicalPresence)) { + return TRUE; + } + + // + // Check the pending TPM requests. Lock TPM physical presence if there is no TPM + // request. + // + Status = PeiServicesLocatePpi ( + &gEfiPeiReadOnlyVariable2PpiGuid, + 0, + NULL, + (VOID **)&Variable + ); + if (!EFI_ERROR (Status)) { + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = Variable->GetVariable ( + Variable, + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &TcgPpData + ); + if (!EFI_ERROR (Status)) { + if (TcgPpData.PPRequest != 0) { + return FALSE; + } + } + } + + // + // Lock TPM physical presence by default. + // + return TRUE; +} + +/** + Entry point of this module. + + It installs lock physical presence PPI. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Describes the list of possible PEI Services. + + @return Status of install lock physical presence PPI. + +**/ +EFI_STATUS +EFIAPI +PeimEntry ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + return PeiServicesInstallPpi (&mLockPhysicalPresencePpiList); +} diff --git a/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf new file mode 100644 index 0000000000..da4e032299 --- /dev/null +++ b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf @@ -0,0 +1,55 @@ +## @file +# Component description file for physical presence PEI module. +# +# Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PhysicalPresencePei + FILE_GUID = 4FE772E8-FE3E-4086-B638-8C493C490488 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = PeimEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + PhysicalPresencePei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + PeimEntryPoint + PeiServicesLib + +[Ppis] + gPeiLockPhysicalPresencePpiGuid + gEfiPeiReadOnlyVariable2PpiGuid + +[Guids] + gEfiPhysicalPresenceGuid + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPhysicalPresence + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid AND + gPeiTpmInitializedPpiGuid diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr new file mode 100644 index 0000000000..360e5569f2 --- /dev/null +++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr @@ -0,0 +1,114 @@ +/** @file + VFR file used by the TCG configuration component. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TcgConfigNvData.h" + +formset + guid = TCG_CONFIG_PRIVATE_GUID, + title = STRING_TOKEN(STR_TPM_TITLE), + help = STRING_TOKEN(STR_TPM_HELP), + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + varstore TCG_CONFIGURATION, + varid = TCG_CONFIGURATION_VARSTORE_ID, + name = TCG_CONFIGURATION, + guid = TCG_CONFIG_PRIVATE_GUID; + + form formid = TCG_CONFIGURATION_FORM_ID, + title = STRING_TOKEN(STR_TPM_TITLE); + + subtitle text = STRING_TOKEN(STR_NULL); + + suppressif TRUE; + checkbox varid = TCG_CONFIGURATION.TpmEnable, + prompt = STRING_TOKEN(STR_NULL), + help = STRING_TOKEN(STR_NULL), + endcheckbox; + endif; + + suppressif TRUE; + checkbox varid = TCG_CONFIGURATION.TpmActivate, + prompt = STRING_TOKEN(STR_NULL), + help = STRING_TOKEN(STR_NULL), + endcheckbox; + endif; + + suppressif TRUE; + checkbox varid = TCG_CONFIGURATION.OriginalHideTpm, + prompt = STRING_TOKEN(STR_NULL), + help = STRING_TOKEN(STR_NULL), + endcheckbox; + endif; + + text + help = STRING_TOKEN(STR_TPM_STATE_HELP), + text = STRING_TOKEN(STR_TPM_STATE_PROMPT), + text = STRING_TOKEN(STR_TPM_STATE_CONTENT); + + subtitle text = STRING_TOKEN(STR_NULL); + + label LABEL_TCG_CONFIGURATION_HIDETPM; + + checkbox varid = TCG_CONFIGURATION.HideTpm, + questionid = KEY_HIDE_TPM, + prompt = STRING_TOKEN(STR_HIDE_TPM_PROMPT), + help = STRING_TOKEN(STR_HIDE_TPM_HELP), + flags = RESET_REQUIRED, + endcheckbox; + + label LABEL_END; + + grayoutif ideqval TCG_CONFIGURATION.OriginalHideTpm == 1; + oneof varid = TCG_CONFIGURATION.TpmOperation, + questionid = KEY_TPM_ACTION, + prompt = STRING_TOKEN(STR_TPM_OPERATION), + help = STRING_TOKEN(STR_TPM_OPERATION_HELP), + flags = INTERACTIVE, + // + // Disable (TPM_ORD_PhysicalDisable) command is not available when disabled. + // Activate/deactivate (TPM_ORD_physicalSetDeactivated) command is not available when disabled. + // + suppressif ideqval TCG_CONFIGURATION.TpmEnable == 0; + option text = STRING_TOKEN(STR_DISABLE), value = DISABLE, flags = 0; + option text = STRING_TOKEN(STR_TPM_ACTIVATE), value = ACTIVATE, flags = 0; + option text = STRING_TOKEN(STR_TPM_DEACTIVATE), value = DEACTIVATE, flags = 0; + option text = STRING_TOKEN(STR_TPM_DEACTIVATE_DISABLE), value = DEACTIVATE_DISABLE, flags = 0; + endif + // + // Clear (TPM_ORD_ForceClear) command is not available when disabled or deactivated. + // + suppressif ideqval TCG_CONFIGURATION.TpmEnable == 0 OR + ideqval TCG_CONFIGURATION.TpmActivate == 0; + option text = STRING_TOKEN(STR_TPM_CLEAR), value = CLEAR, flags = 0; + option text = STRING_TOKEN(STR_TPM_CLEAR_ENABLE_ACTIVATE), value = CLEAR_ENABLE_ACTIVATE, flags = 0; + endif + + option text = STRING_TOKEN(STR_ENABLE), value = ENABLE, flags = 0; + option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE), value = ENABLE_ACTIVATE, flags = 0; + option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR), value = ENABLE_ACTIVATE_CLEAR, flags = 0; + option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR_E_A), value = ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE, flags = 0; + endoneof; + + subtitle text = STRING_TOKEN(STR_NULL); + + checkbox varid = TCG_CONFIGURATION.MorState, + questionid = KEY_TPM_MOR_ENABLE, + prompt = STRING_TOKEN(STR_MOR_PROMPT), + help = STRING_TOKEN(STR_MOR_HELP), + endcheckbox; + endif; + + endform; + +endformset; diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c new file mode 100644 index 0000000000..4b2008f577 --- /dev/null +++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c @@ -0,0 +1,147 @@ +/** @file + The module entry point for Tcg configuration module. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TcgConfigImpl.h" + +EFI_GUID gTcgConfigPrivateGuid = TCG_CONFIG_PRIVATE_GUID; + +/** + The entry point for Tcg configuration driver. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable The system table. + + @retval EFI_ALREADY_STARTED The driver already exists in system. + @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of resources. + @retval EFI_SUCCES All the related protocols are installed on the driver. + @retval Others Fail to install protocols as indicated. + +**/ +EFI_STATUS +EFIAPI +TcgConfigDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + TCG_CONFIG_PRIVATE_DATA *PrivateData; + EFI_TCG_PROTOCOL *TcgProtocol; + + Status = TisPcRequestUseTpm ((TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM not detected!\n")); + return Status; + } + + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol); + if (EFI_ERROR (Status)) { + TcgProtocol = NULL; + } + + Status = gBS->OpenProtocol ( + ImageHandle, + &gTcgConfigPrivateGuid, + NULL, + ImageHandle, + ImageHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return EFI_ALREADY_STARTED; + } + + // + // Create a private data structure. + // + PrivateData = AllocateCopyPool (sizeof (TCG_CONFIG_PRIVATE_DATA), &mTcgConfigPrivateDateTemplate); + if (PrivateData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + PrivateData->TcgProtocol = TcgProtocol; + PrivateData->HideTpm = PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm); + + // + // Install TCG configuration form + // + Status = InstallTcgConfigForm (PrivateData); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Install private GUID. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gTcgConfigPrivateGuid, + PrivateData, + NULL + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + if (PrivateData != NULL) { + UninstallTcgConfigForm (PrivateData); + } + + return Status; +} + +/** + Unload the Tcg configuration form. + + @param[in] ImageHandle The driver's image handle. + + @retval EFI_SUCCESS The Tcg configuration form is unloaded. + @retval Others Failed to unload the form. + +**/ +EFI_STATUS +EFIAPI +TcgConfigDriverUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + TCG_CONFIG_PRIVATE_DATA *PrivateData; + + Status = gBS->HandleProtocol ( + ImageHandle, + &gTcgConfigPrivateGuid, + (VOID **) &PrivateData + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (PrivateData->Signature == TCG_CONFIG_PRIVATE_DATA_SIGNATURE); + + gBS->UninstallMultipleProtocolInterfaces ( + &ImageHandle, + &gTcgConfigPrivateGuid, + PrivateData, + NULL + ); + + UninstallTcgConfigForm (PrivateData); + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf new file mode 100644 index 0000000000..d9d3102668 --- /dev/null +++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf @@ -0,0 +1,75 @@ +## @file +# Component name for Tcg configuration module. +# +# Copyright (c) 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgConfigDxe + FILE_GUID = 1FA4DAFE-FA5D-4d75-BEA6-5863862C520A + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = TcgConfigDriverEntryPoint + UNLOAD_IMAGE = TcgConfigDriverUnload + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + TcgConfigDriver.c + TcgConfigImpl.c + TcgConfigImpl.h + TcgConfig.vfr + TcgConfigStrings.uni + TcgConfigNvData.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + DebugLib + HiiLib + PcdLib + PrintLib + TpmCommLib + +[Guids] + gEfiPhysicalPresenceGuid + gEfiIfrTianoGuid + +[Protocols] + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiHiiConfigRoutingProtocolGuid ## CONSUMES + gEfiTcgProtocolGuid ## CONSUMES + +[FixedPcd] + gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdMorEnable + gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm + +[Depex] + gEfiHiiConfigRoutingProtocolGuid AND + gEfiHiiDatabaseProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid \ No newline at end of file diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c new file mode 100644 index 0000000000..535f5e852a --- /dev/null +++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c @@ -0,0 +1,555 @@ +/** @file + HII Config Access protocol implementation of TCG configuration module. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TcgConfigImpl.h" + +EFI_GUID mTcgFormSetGuid = TCG_CONFIG_PRIVATE_GUID; +CHAR16 mTcgStorageName[] = L"TCG_CONFIGURATION"; + +TCG_CONFIG_PRIVATE_DATA mTcgConfigPrivateDateTemplate = { + TCG_CONFIG_PRIVATE_DATA_SIGNATURE, + { + TcgExtractConfig, + TcgRouteConfig, + TcgCallback + } +}; + +HII_VENDOR_DEVICE_PATH mTcgHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + TCG_CONFIG_PRIVATE_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +/** + Get current state of TPM device. + + @param[in] TcgProtocol Point to EFI_TCG_PROTOCOL instance. + @param[out] TpmEnable Flag to indicate TPM is enabled or not. + @param[out] TpmActivate Flag to indicate TPM is activated or not. + + @retval EFI_SUCCESS State is successfully returned. + @retval EFI_DEVICE_ERROR Failed to get TPM response. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +GetTpmState ( + IN EFI_TCG_PROTOCOL *TcgProtocol, + OUT BOOLEAN *TpmEnable, OPTIONAL + OUT BOOLEAN *TpmActivate OPTIONAL + ) +{ + EFI_STATUS Status; + TPM_RSP_COMMAND_HDR *TpmRsp; + UINT32 TpmSendSize; + TPM_PERMANENT_FLAGS *TpmPermanentFlags; + UINT8 CmdBuf[64]; + + ASSERT (TcgProtocol != NULL); + + // + // Get TPM Permanent flags (TpmEnable, TpmActivate) + // + if ((TpmEnable != NULL) || (TpmActivate != NULL)) { + TpmSendSize = sizeof (TPM_RQU_COMMAND_HDR) + sizeof (UINT32) * 3; + *(UINT16*)&CmdBuf[0] = H2NS (TPM_TAG_RQU_COMMAND); + *(UINT32*)&CmdBuf[2] = H2NL (TpmSendSize); + *(UINT32*)&CmdBuf[6] = H2NL (TPM_ORD_GetCapability); + + *(UINT32*)&CmdBuf[10] = H2NL (TPM_CAP_FLAG); + *(UINT32*)&CmdBuf[14] = H2NL (sizeof (TPM_CAP_FLAG_PERMANENT)); + *(UINT32*)&CmdBuf[18] = H2NL (TPM_CAP_FLAG_PERMANENT); + + Status = TcgProtocol->PassThroughToTpm ( + TcgProtocol, + TpmSendSize, + CmdBuf, + sizeof (CmdBuf), + CmdBuf + ); + TpmRsp = (TPM_RSP_COMMAND_HDR *) &CmdBuf[0]; + if (EFI_ERROR (Status) || (TpmRsp->tag != H2NS (TPM_TAG_RSP_COMMAND)) || (TpmRsp->returnCode != 0)) { + return EFI_DEVICE_ERROR; + } + + TpmPermanentFlags = (TPM_PERMANENT_FLAGS *) &CmdBuf[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)]; + + if (TpmEnable != NULL) { + *TpmEnable = (BOOLEAN) !TpmPermanentFlags->disable; + } + + if (TpmActivate != NULL) { + *TpmActivate = (BOOLEAN) !TpmPermanentFlags->deactivated; + } + } + + return EFI_SUCCESS; +} + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Request A null-terminated Unicode string in + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +TcgExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + TCG_CONFIGURATION Configuration; + TCG_CONFIG_PRIVATE_DATA *PrivateData; + EFI_STRING ConfigRequestHdr; + EFI_STRING ConfigRequest; + BOOLEAN AllocatedRequest; + UINTN Size; + BOOLEAN TpmEnable; + BOOLEAN TpmActivate; + CHAR16 State[32]; + + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Request; + if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mTcgFormSetGuid, mTcgStorageName)) { + return EFI_NOT_FOUND; + } + + ConfigRequestHdr = NULL; + ConfigRequest = NULL; + AllocatedRequest = FALSE; + Size = 0; + + PrivateData = TCG_CONFIG_PRIVATE_DATA_FROM_THIS (This); + + // + // Convert buffer data to by helper function BlockToConfig() + // + ZeroMem (&Configuration, sizeof (TCG_CONFIGURATION)); + + Configuration.MorState = PcdGetBool (PcdMorEnable); + Configuration.TpmOperation = ENABLE; + Configuration.HideTpm = PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm); + // + // Read the original value of HideTpm from PrivateData which won't be changed by Setup in this boot. + // + Configuration.OriginalHideTpm = PrivateData->HideTpm; + + // + // Display current TPM state. + // + if (PrivateData->TcgProtocol != NULL) { + Status = GetTpmState (PrivateData->TcgProtocol, &TpmEnable, &TpmActivate); + if (EFI_ERROR (Status)) { + return Status; + } + + UnicodeSPrint ( + State, + sizeof (State), + L"%s, and %s", + TpmEnable ? L"Enabled" : L"Disabled", + TpmActivate ? L"Activated" : L"Deactivated" + ); + Configuration.TpmEnable = TpmEnable; + Configuration.TpmActivate = TpmActivate; + + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM_STATE_CONTENT), State, NULL); + } + + BufferSize = sizeof (Configuration); + ConfigRequest = Request; + if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { + // + // Request has no request element, construct full request string. + // Allocate and fill a buffer large enough to hold the template + // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator + // + ConfigRequestHdr = HiiConstructConfigHdr (&mTcgFormSetGuid, mTcgStorageName, PrivateData->DriverHandle); + Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); + ConfigRequest = AllocateZeroPool (Size); + ASSERT (ConfigRequest != NULL); + AllocatedRequest = TRUE; + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64) BufferSize); + FreePool (ConfigRequestHdr); + } + + Status = gHiiConfigRouting->BlockToConfig ( + gHiiConfigRouting, + ConfigRequest, + (UINT8 *) &Configuration, + BufferSize, + Results, + Progress + ); + // + // Free the allocated config request string. + // + if (AllocatedRequest) { + FreePool (ConfigRequest); + } + // + // Set Progress string to the original request string. + // + if (Request == NULL) { + *Progress = NULL; + } else if (StrStr (Request, L"OFFSET") == NULL) { + *Progress = Request + StrLen (Request); + } + + return Status; +} + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Configuration A null-terminated Unicode string in + format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +TcgRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + TCG_CONFIGURATION TcgConfiguration; + + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Configuration; + if (!HiiIsConfigHdrMatch (Configuration, &mTcgFormSetGuid, mTcgStorageName)) { + return EFI_NOT_FOUND; + } + + // + // Convert to buffer data by helper function ConfigToBlock() + // + BufferSize = sizeof (TCG_CONFIGURATION); + Status = gHiiConfigRouting->ConfigToBlock ( + gHiiConfigRouting, + Configuration, + (UINT8 *) &TcgConfiguration, + &BufferSize, + Progress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PcdSetBool (PcdMorEnable, TcgConfiguration.MorState); + PcdSetBool (PcdHideTpm, TcgConfiguration.HideTpm); + + return EFI_SUCCESS; +} + +/** + Save TPM request to variable space. + + @param[in] PpRequest Physical Presence request command. + + @retval EFI_SUCCESS The operation is finished successfully. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +SavePpRequest ( + IN UINT8 PpRequest + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_PHYSICAL_PRESENCE PpData; + + // + // Save TPM command to variable. + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PpData.PPRequest = PpRequest; + Status = gRT->SetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &PpData + ); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Reset system. + // + gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL); + + return EFI_SUCCESS; +} + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +TcgCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Action != EFI_BROWSER_ACTION_CHANGING) || (QuestionId != KEY_TPM_ACTION)) { + return EFI_UNSUPPORTED; + } + + SavePpRequest (Value->u8); + ASSERT (FALSE); + + return EFI_SUCCESS; +} + +/** + This function publish the TCG configuration Form for TPM device. + + @param[in, out] PrivateData Points to TCG configuration private data. + + @retval EFI_SUCCESS HII Form is installed for this network device. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallTcgConfigForm ( + IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + DriverHandle = NULL; + ConfigAccess = &PrivateData->ConfigAccess; + Status = gBS->InstallMultipleProtocolInterfaces ( + &DriverHandle, + &gEfiDevicePathProtocolGuid, + &mTcgHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PrivateData->DriverHandle = DriverHandle; + + // + // Publish the HII package list + // + HiiHandle = HiiAddPackages ( + &mTcgFormSetGuid, + DriverHandle, + TcgConfigDxeStrings, + TcgConfigBin, + NULL + ); + if (HiiHandle == NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + DriverHandle, + &gEfiDevicePathProtocolGuid, + &mTcgHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + + return EFI_OUT_OF_RESOURCES; + } + + PrivateData->HiiHandle = HiiHandle; + + // + // Remove the Hide TPM question from the IFR + // + if (!PcdGetBool (PcdHideTpmSupport)) { + // + // Allocate space for creation of UpdateData Buffer + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode as the start opcode + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_TCG_CONFIGURATION_HIDETPM; + + // + // Create Hii Extend Label OpCode as the end opcode + // + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + HiiUpdateForm (HiiHandle, NULL, TCG_CONFIGURATION_FORM_ID, StartOpCodeHandle, EndOpCodeHandle); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + } + + return EFI_SUCCESS; +} + +/** + This function removes TCG configuration Form. + + @param[in, out] PrivateData Points to TCG configuration private data. + +**/ +VOID +UninstallTcgConfigForm ( + IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + // + // Uninstall HII package list + // + if (PrivateData->HiiHandle != NULL) { + HiiRemovePackages (PrivateData->HiiHandle); + PrivateData->HiiHandle = NULL; + } + + // + // Uninstall HII Config Access Protocol + // + if (PrivateData->DriverHandle != NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + PrivateData->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mTcgHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &PrivateData->ConfigAccess, + NULL + ); + PrivateData->DriverHandle = NULL; + } + + FreePool (PrivateData); +} diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h new file mode 100644 index 0000000000..cbfca74392 --- /dev/null +++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h @@ -0,0 +1,195 @@ +/** @file + The header file of HII Config Access protocol implementation of TCG + configuration module. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __TCG_CONFIG_IMPL_H__ +#define __TCG_CONFIG_IMPL_H__ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "TcgConfigNvData.h" + +// +// Tool generated IFR binary data and String package data +// +extern UINT8 TcgConfigBin[]; +extern UINT8 TcgConfigDxeStrings[]; + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +typedef struct { + UINTN Signature; + + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + + EFI_TCG_PROTOCOL *TcgProtocol; + + BOOLEAN HideTpm; +} TCG_CONFIG_PRIVATE_DATA; + +extern TCG_CONFIG_PRIVATE_DATA mTcgConfigPrivateDateTemplate; + +#define TCG_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('T', 'C', 'G', 'D') +#define TCG_CONFIG_PRIVATE_DATA_FROM_THIS(a) CR (a, TCG_CONFIG_PRIVATE_DATA, ConfigAccess, TCG_CONFIG_PRIVATE_DATA_SIGNATURE) + + +/** + This function publish the TCG configuration Form for TPM device. + + @param[in, out] PrivateData Points to TCG configuration private data. + + @retval EFI_SUCCESS HII Form is installed for this network device. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallTcgConfigForm ( + IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData + ); + +/** + This function removes TCG configuration Form. + + @param[in, out] PrivateData Points to TCG configuration private data. + +**/ +VOID +UninstallTcgConfigForm ( + IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData + ); + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Request A null-terminated Unicode string in + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +TcgExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ); + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Configuration A null-terminated Unicode string in + format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +TcgRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ); + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +TcgCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ); + +#endif diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h new file mode 100644 index 0000000000..982764c65c --- /dev/null +++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h @@ -0,0 +1,48 @@ +/** @file + Header file for NV data structure definition. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __TCG_CONFIG_NV_DATA_H__ +#define __TCG_CONFIG_NV_DATA_H__ + +#include +#include + +#define TCG_CONFIG_PRIVATE_GUID \ + { \ + 0xb0f901e4, 0xc424, 0x45de, {0x90, 0x81, 0x95, 0xe2, 0xb, 0xde, 0x6f, 0xb5 } \ + } + +#define TCG_CONFIGURATION_VARSTORE_ID 0x0001 +#define TCG_CONFIGURATION_FORM_ID 0x0001 + +#define KEY_HIDE_TPM 0x2000 +#define KEY_TPM_ACTION 0x3000 +#define KEY_TPM_MOR_ENABLE 0x4000 + +#define LABEL_TCG_CONFIGURATION_HIDETPM 0x0001 +#define LABEL_END 0xffff + +// +// Nv Data structure referenced by IFR +// +typedef struct { + BOOLEAN HideTpm; + BOOLEAN OriginalHideTpm; + BOOLEAN MorState; + UINT8 TpmOperation; + BOOLEAN TpmEnable; + BOOLEAN TpmActivate; +} TCG_CONFIGURATION; + +#endif diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..df39f620930795ef99aa0876d964949efe716f0f GIT binary patch literal 5016 zcmb`LTTdHD6vxkVrGAGMc}c1Uw|z{bsKz+OD!~YxUY;z2jf2Xq>xDF5zU}XSCc~@^ z*;%`2wLAB7{^vR~`|m#;`-Z2mpX|)e?ZRgEwS7gquw$#Nr0>e+w5E(`#uabHdrfUY z{~5KCa%4UGnex;}G;?mZj7;ul$GMlb?L5S%$Lt&Xb4pn;W9IEsm+lhY8vDe$pqop_Ar9x%E}WXAo6w_`7xbS}lg5M~(bh_7Ry}vT zvcSYn_^R*L5r}R=AuW{PlVlNL(D{_rb<131o3w5Rd+yTSU&2zj4nDdLPWg)FvXtlW z6EA5Y=t+DQv?c8c7$Z+vKzY1Fz`o9oe4s;dh9S4DsnB z{OTR;0U9jOp~?}x1H9-xwZ7~1y&X{Y>6Z=yg{1QVUfXBJu~QyWleg--MJc+Xx<$F; zZMEe0!t)zrqBwMJ1??_egzA9)0Ti`<=$wye3Ag&hZ^SIk5yvp=EpxT<56WK{5o&Sj zf94V-=-co2bQ1LedN{;`#B;Y6#mXR^d;L8_zw*qvd$uet8@&X*C~dJ;W3v7Ny>Hdl zMXw4`6|_7C{~>%;N)P+2m!GwL5}I33&E2<_@x;ufymE!#Jq*?$DRrYA2^&!bgRDXR;yEF5+m#rkXmeC@TrIX-3TJN!erTw1R@GtJ0G!N+6f zR)!C|V#t-L|3^lYVPy;Dd&yd#J$qzy6KnN6;$=DIfd6N$_7OV7j>;b?=QMGSV|jZ- z{}|%M+Wpe5-_DO8;u?E~ZjRPGE=5?1J7o{~#qut<@CXd2m1ONzIbtMh4-UCgl%m|p z)1ohEU-(i!lFhs9BkN|$V2`}i%HPqWoAn>|%1yE4k?i^&(hf`9MY`<7+DU%>oY|rm zHkWxU-Ib_r)=WgB6T|w5@@RJP#MM004pGnjMkkDBjVzDm5xw<{7&2${>z+rCPRZ@C z)jfOMT5ox5b&pP`>Zh~lnA4I@bYG5yJjTZ?ny_vX3C-FZ6DP_btDcZYTGysdmaBSH zU%a_Ig;yk;W8d$hmYY2!FGn-BaAr=KurAfA#82Vfb$duoNv9ah%hARjPc3WH{&c`i zV4r6>gS2hs*(?b0{!;q*@&n88FoE9br0x}i*)mfyJq@B5K%wp zEI#8lt`n^8<3s;%Qrbt_`oo};$r0bbIN9i4Qu*JSGwM2*=^h@>?@cz?BO_|}OZU6> xH;gu3zX#UvXC>@5%`x~8%{sQodqj_Oo$hCUqPuWs)8CXjzJm6ZYg_*T{sU~T+!_D? literal 0 HcmV?d00001 diff --git a/SecurityPkg/Tcg/TcgDxe/TcgDxe.c b/SecurityPkg/Tcg/TcgDxe/TcgDxe.c new file mode 100644 index 0000000000..4cb5d3084b --- /dev/null +++ b/SecurityPkg/Tcg/TcgDxe/TcgDxe.c @@ -0,0 +1,1212 @@ +/** @file + This module implements TCG EFI Protocol. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TpmComm.h" + +#define EFI_TCG_LOG_AREA_SIZE 0x10000 + +#pragma pack (1) + +typedef struct _EFI_TCG_CLIENT_ACPI_TABLE { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT16 PlatformClass; + UINT32 Laml; + EFI_PHYSICAL_ADDRESS Lasa; +} EFI_TCG_CLIENT_ACPI_TABLE; + +typedef struct _EFI_TCG_SERVER_ACPI_TABLE { + EFI_ACPI_DESCRIPTION_HEADER Header; + UINT16 PlatformClass; + UINT16 Reserved0; + UINT64 Laml; + EFI_PHYSICAL_ADDRESS Lasa; + UINT16 SpecRev; + UINT8 DeviceFlags; + UINT8 InterruptFlags; + UINT8 Gpe; + UINT8 Reserved1[3]; + UINT32 GlobalSysInt; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE BaseAddress; + UINT32 Reserved2; + EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE ConfigAddress; + UINT8 PciSegNum; + UINT8 PciBusNum; + UINT8 PciDevNum; + UINT8 PciFuncNum; +} EFI_TCG_SERVER_ACPI_TABLE; + +#pragma pack () + +#define TCG_DXE_DATA_FROM_THIS(this) \ + BASE_CR (this, TCG_DXE_DATA, TcgProtocol) + +typedef struct _TCG_DXE_DATA { + EFI_TCG_PROTOCOL TcgProtocol; + TCG_EFI_BOOT_SERVICE_CAPABILITY BsCap; + EFI_TCG_CLIENT_ACPI_TABLE *TcgClientAcpiTable; + EFI_TCG_SERVER_ACPI_TABLE *TcgServerAcpiTable; + UINTN EventLogSize; + UINT8 *LastEvent; + TIS_TPM_HANDLE TpmHandle; +} TCG_DXE_DATA; + + + +EFI_TCG_CLIENT_ACPI_TABLE mTcgClientAcpiTemplate = { + { + EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE, + sizeof (mTcgClientAcpiTemplate), + 0x02 //Revision + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 0, // 0 for PC Client Platform Class + 0, // Log Area Max Length + (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1) // Log Area Start Address +}; + +// +// The following EFI_TCG_SERVER_ACPI_TABLE default setting is just one example, +// the TPM device connectes to LPC, and also defined the ACPI _UID as 0xFF, +// this _UID can be changed and should match with the _UID setting of the TPM +// ACPI device object +// +EFI_TCG_SERVER_ACPI_TABLE mTcgServerAcpiTemplate = { + { + EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE, + sizeof (mTcgServerAcpiTemplate), + 0x02 //Revision + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 1, // 1 for Server Platform Class + 0, // Reserved + 0, // Log Area Max Length + (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1), // Log Area Start Address + 0x0100, // TCG Specification revision 1.0 + 2, // Device Flags + 0, // Interrupt Flags + 0, // GPE + {0}, // Reserved 3 bytes + 0, // Global System Interrupt + { + EFI_ACPI_3_0_SYSTEM_MEMORY, + 0, + 0, + EFI_ACPI_3_0_BYTE, + TPM_BASE_ADDRESS // Base Address + }, + 0, // Reserved + {0}, // Configuration Address + 0xFF, // ACPI _UID value of the device, can be changed for different platforms + 0, // ACPI _UID value of the device, can be changed for different platforms + 0, // ACPI _UID value of the device, can be changed for different platforms + 0 // ACPI _UID value of the device, can be changed for different platforms +}; + +UINTN mBootAttempts = 0; +CHAR16 mBootVarName[] = L"BootOrder"; + +/** + This service provides EFI protocol capability information, state information + about the TPM, and Event Log state information. + + @param[in] This Indicates the calling context + @param[out] ProtocolCapability The callee allocates memory for a TCG_BOOT_SERVICE_CAPABILITY + structure and fills in the fields with the EFI protocol + capability information and the current TPM state information. + @param[out] TCGFeatureFlags This is a pointer to the feature flags. No feature + flags are currently defined so this parameter + MUST be set to 0. However, in the future, + feature flags may be defined that, for example, + enable hash algorithm agility. + @param[out] EventLogLocation This is a pointer to the address of the event log in memory. + @param[out] EventLogLastEntry If the Event Log contains more than one entry, + this is a pointer to the address of the start of + the last entry in the event log in memory. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER ProtocolCapability does not match TCG capability. + +**/ +EFI_STATUS +EFIAPI +TcgDxeStatusCheck ( + IN EFI_TCG_PROTOCOL *This, + OUT TCG_EFI_BOOT_SERVICE_CAPABILITY *ProtocolCapability, + OUT UINT32 *TCGFeatureFlags, + OUT EFI_PHYSICAL_ADDRESS *EventLogLocation, + OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry + ) +{ + TCG_DXE_DATA *TcgData; + + TcgData = TCG_DXE_DATA_FROM_THIS (This); + + if (ProtocolCapability != NULL) { + *ProtocolCapability = TcgData->BsCap; + } + + if (TCGFeatureFlags != NULL) { + *TCGFeatureFlags = 0; + } + + if (EventLogLocation != NULL) { + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + *EventLogLocation = TcgData->TcgClientAcpiTable->Lasa; + } else { + *EventLogLocation = TcgData->TcgServerAcpiTable->Lasa; + } + } + + if (EventLogLastEntry != NULL) { + if (TcgData->BsCap.TPMDeactivatedFlag) { + *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0; + } else { + *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)TcgData->LastEvent; + } + } + + return EFI_SUCCESS; +} + +/** + This service abstracts the capability to do a hash operation on a data buffer. + + @param[in] This Indicates the calling context + @param[in] HashData Pointer to the data buffer to be hashed + @param[in] HashDataLen Length of the data buffer to be hashed + @param[in] AlgorithmId Identification of the Algorithm to use for the hashing operation + @param[in, out] HashedDataLen Resultant length of the hashed data + @param[in, out] HashedDataResult Resultant buffer of the hashed data + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER HashDataLen is NULL. + @retval EFI_INVALID_PARAMETER HashDataLenResult is NULL. + @retval EFI_OUT_OF_RESOURCES Cannot allocate buffer of size *HashedDataLen. + @retval EFI_UNSUPPORTED AlgorithmId not supported. + @retval EFI_BUFFER_TOO_SMALL *HashedDataLen < sizeof (TCG_DIGEST). + +**/ +EFI_STATUS +EFIAPI +TcgDxeHashAll ( + IN EFI_TCG_PROTOCOL *This, + IN UINT8 *HashData, + IN UINT64 HashDataLen, + IN TCG_ALGORITHM_ID AlgorithmId, + IN OUT UINT64 *HashedDataLen, + IN OUT UINT8 **HashedDataResult + ) +{ + if (HashedDataLen == NULL || HashedDataResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + switch (AlgorithmId) { + case TPM_ALG_SHA: + if (*HashedDataLen == 0) { + *HashedDataLen = sizeof (TPM_DIGEST); + *HashedDataResult = AllocatePool ((UINTN) *HashedDataLen); + if (*HashedDataResult == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + if (*HashedDataLen < sizeof (TPM_DIGEST)) { + *HashedDataLen = sizeof (TPM_DIGEST); + return EFI_BUFFER_TOO_SMALL; + } + *HashedDataLen = sizeof (TPM_DIGEST); + + return TpmCommHashAll ( + HashData, + (UINTN) HashDataLen, + (TPM_DIGEST*)*HashedDataResult + ); + default: + return EFI_UNSUPPORTED; + } +} + +/** + Add a new entry to the Event Log. + + @param[in] TcgData TCG_DXE_DATA structure. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + +**/ +EFI_STATUS +EFIAPI +TcgDxeLogEventI ( + IN TCG_DXE_DATA *TcgData, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + TcgData->LastEvent = (UINT8*)(UINTN)TcgData->TcgClientAcpiTable->Lasa; + return TpmCommLogEvent ( + &TcgData->LastEvent, + &TcgData->EventLogSize, + (UINTN)TcgData->TcgClientAcpiTable->Laml, + NewEventHdr, + NewEventData + ); + } else { + TcgData->LastEvent = (UINT8*)(UINTN)TcgData->TcgServerAcpiTable->Lasa; + return TpmCommLogEvent ( + &TcgData->LastEvent, + &TcgData->EventLogSize, + (UINTN)TcgData->TcgServerAcpiTable->Laml, + NewEventHdr, + NewEventData + ); + } +} + +/** + This service abstracts the capability to add an entry to the Event Log. + + @param[in] This Indicates the calling context + @param[in] TCGLogData Pointer to the start of the data buffer containing + the TCG_PCR_EVENT data structure. All fields in + this structure are properly filled by the caller. + @param[in, out] EventNumber The event number of the event just logged + @param[in] Flags Indicate additional flags. Only one flag has been + defined at this time, which is 0x01 and means the + extend operation should not be performed. All + other bits are reserved. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Insufficient memory in the event log to complete this action. + +**/ +EFI_STATUS +EFIAPI +TcgDxeLogEvent ( + IN EFI_TCG_PROTOCOL *This, + IN TCG_PCR_EVENT *TCGLogData, + IN OUT UINT32 *EventNumber, + IN UINT32 Flags + ) +{ + TCG_DXE_DATA *TcgData; + + TcgData = TCG_DXE_DATA_FROM_THIS (This); + + if (TcgData->BsCap.TPMDeactivatedFlag) { + return EFI_DEVICE_ERROR; + } + return TcgDxeLogEventI ( + TcgData, + (TCG_PCR_EVENT_HDR*)TCGLogData, + TCGLogData->Event + ); +} + +/** + This service is a proxy for commands to the TPM. + + @param[in] This Indicates the calling context + @param[in] TpmInputParameterBlockSize Size of the TPM input parameter block + @param[in] TpmInputParameterBlock Pointer to the TPM input parameter block + @param[in] TpmOutputParameterBlockSize Size of the TPM output parameter block + @param[in] TpmOutputParameterBlock Pointer to the TPM output parameter block + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER Invalid ordinal. + @retval EFI_UNSUPPORTED Current Task Priority Level >= EFI_TPL_CALLBACK. + @retval EFI_TIMEOUT The TIS timed-out. + +**/ +EFI_STATUS +EFIAPI +TcgDxePassThroughToTpm ( + IN EFI_TCG_PROTOCOL *This, + IN UINT32 TpmInputParameterBlockSize, + IN UINT8 *TpmInputParameterBlock, + IN UINT32 TpmOutputParameterBlockSize, + IN UINT8 *TpmOutputParameterBlock + ) +{ + TCG_DXE_DATA *TcgData; + + TcgData = TCG_DXE_DATA_FROM_THIS (This); + + return TisPcExecute ( + TcgData->TpmHandle, + "%r%/%r", + TpmInputParameterBlock, + (UINTN) TpmInputParameterBlockSize, + TpmOutputParameterBlock, + (UINTN) TpmOutputParameterBlockSize + ); +} + +/** + Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, + and add an entry to the Event Log. + + @param[in] TcgData TCG_DXE_DATA structure. + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + @param[in, out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +TcgDxeHashLogExtendEventI ( + IN TCG_DXE_DATA *TcgData, + IN UINT8 *HashData, + IN UINT64 HashDataLen, + IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + + if (HashDataLen > 0) { + Status = TpmCommHashAll ( + HashData, + (UINTN) HashDataLen, + &NewEventHdr->Digest + ); + ASSERT_EFI_ERROR (Status); + } + + Status = TpmCommExtend ( + TcgData->TpmHandle, + &NewEventHdr->Digest, + NewEventHdr->PCRIndex, + NULL + ); + if (!EFI_ERROR (Status)) { + Status = TcgDxeLogEventI (TcgData, NewEventHdr, NewEventData); + } + + return Status; +} + +/** + This service abstracts the capability to do a hash operation on a data buffer, + extend a specific TPM PCR with the hash result, and add an entry to the Event Log + + @param[in] This Indicates the calling context + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + @param[in] AlgorithmId Identification of the Algorithm to use for the hashing operation + @param[in, out] TCGLogData The physical address of the start of the data + buffer containing the TCG_PCR_EVENT data structure. + @param[in, out] EventNumber The event number of the event just logged. + @param[out] EventLogLastEntry Physical address of the first byte of the entry + just placed in the Event Log. If the Event Log was + empty when this function was called then this physical + address will be the same as the physical address of + the start of the Event Log. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED AlgorithmId != TPM_ALG_SHA. + @retval EFI_UNSUPPORTED Current TPL >= EFI_TPL_CALLBACK. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +TcgDxeHashLogExtendEvent ( + IN EFI_TCG_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS HashData, + IN UINT64 HashDataLen, + IN TPM_ALGORITHM_ID AlgorithmId, + IN OUT TCG_PCR_EVENT *TCGLogData, + IN OUT UINT32 *EventNumber, + OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry + ) +{ + TCG_DXE_DATA *TcgData; + + TcgData = TCG_DXE_DATA_FROM_THIS (This); + + if (TcgData->BsCap.TPMDeactivatedFlag) { + return EFI_DEVICE_ERROR; + } + + if (AlgorithmId != TPM_ALG_SHA) { + return EFI_UNSUPPORTED; + } + + return TcgDxeHashLogExtendEventI ( + TcgData, + (UINT8 *) (UINTN) HashData, + HashDataLen, + (TCG_PCR_EVENT_HDR*)TCGLogData, + TCGLogData->Event + ); +} + +TCG_DXE_DATA mTcgDxeData = { + { + TcgDxeStatusCheck, + TcgDxeHashAll, + TcgDxeLogEvent, + TcgDxePassThroughToTpm, + TcgDxeHashLogExtendEvent + }, + { + sizeof (mTcgDxeData.BsCap), + { 1, 2, 0, 0 }, + { 1, 2, 0, 0 }, + 1, + TRUE, + FALSE + }, + &mTcgClientAcpiTemplate, + &mTcgServerAcpiTemplate, + 0, + NULL, + NULL +}; + +/** + Initialize the Event Log and log events passed from the PEI phase. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + +**/ +EFI_STATUS +EFIAPI +SetupEventLog ( + VOID + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT *TcgEvent; + EFI_PEI_HOB_POINTERS GuidHob; + EFI_PHYSICAL_ADDRESS Lasa; + + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + Lasa = mTcgClientAcpiTemplate.Lasa; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (EFI_TCG_LOG_AREA_SIZE), + &Lasa + ); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgClientAcpiTemplate.Lasa = Lasa; + // + // To initialize them as 0xFF is recommended + // because the OS can know the last entry for that. + // + SetMem ((VOID *)(UINTN)mTcgClientAcpiTemplate.Lasa, EFI_TCG_LOG_AREA_SIZE, 0xFF); + mTcgClientAcpiTemplate.Laml = EFI_TCG_LOG_AREA_SIZE; + + } else { + Lasa = mTcgServerAcpiTemplate.Lasa; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (EFI_TCG_LOG_AREA_SIZE), + &Lasa + ); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgServerAcpiTemplate.Lasa = Lasa; + // + // To initialize them as 0xFF is recommended + // because the OS can know the last entry for that. + // + SetMem ((VOID *)(UINTN)mTcgServerAcpiTemplate.Lasa, EFI_TCG_LOG_AREA_SIZE, 0xFF); + mTcgServerAcpiTemplate.Laml = EFI_TCG_LOG_AREA_SIZE; + } + + GuidHob.Raw = GetHobList (); + while (!EFI_ERROR (Status) && + (GuidHob.Raw = GetNextGuidHob (&gTcgEventEntryHobGuid, GuidHob.Raw)) != NULL) { + TcgEvent = GET_GUID_HOB_DATA (GuidHob.Guid); + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + Status = TcgDxeLogEventI ( + &mTcgDxeData, + (TCG_PCR_EVENT_HDR*)TcgEvent, + TcgEvent->Event + ); + } + + return Status; +} + +/** + Measure and log an action string, and extend the measurement result into PCR[5]. + + @param[in] String A specific string that indicates an Action event. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +TcgMeasureAction ( + IN CHAR8 *String + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + + TcgEvent.PCRIndex = 5; + TcgEvent.EventType = EV_EFI_ACTION; + TcgEvent.EventSize = (UINT32)AsciiStrLen (String); + return TcgDxeHashLogExtendEventI ( + &mTcgDxeData, + (UINT8*)String, + TcgEvent.EventSize, + &TcgEvent, + (UINT8 *) String + ); +} + +/** + Measure and log EFI handoff tables, and extend the measurement result into PCR[1]. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureHandoffTables ( + VOID + ) +{ + EFI_STATUS Status; + SMBIOS_TABLE_ENTRY_POINT *SmbiosTable; + TCG_PCR_EVENT_HDR TcgEvent; + EFI_HANDOFF_TABLE_POINTERS HandoffTables; + + Status = EfiGetSystemConfigurationTable ( + &gEfiSmbiosTableGuid, + (VOID **) &SmbiosTable + ); + + if (!EFI_ERROR (Status)) { + ASSERT (SmbiosTable != NULL); + + TcgEvent.PCRIndex = 1; + TcgEvent.EventType = EV_EFI_HANDOFF_TABLES; + TcgEvent.EventSize = sizeof (HandoffTables); + + HandoffTables.NumberOfTables = 1; + HandoffTables.TableEntry[0].VendorGuid = gEfiSmbiosTableGuid; + HandoffTables.TableEntry[0].VendorTable = SmbiosTable; + + DEBUG ((DEBUG_INFO, "The Smbios Table starts at: 0x%x\n", SmbiosTable->TableAddress)); + DEBUG ((DEBUG_INFO, "The Smbios Table size: 0x%x\n", SmbiosTable->TableLength)); + + Status = TcgDxeHashLogExtendEventI ( + &mTcgDxeData, + (UINT8*)(UINTN)SmbiosTable->TableAddress, + SmbiosTable->TableLength, + &TcgEvent, + (UINT8*)&HandoffTables + ); + } + + return Status; +} + +/** + Measure and log Separator event, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR index. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureSeparatorEvent ( + IN TPM_PCRINDEX PCRIndex + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + UINT32 EventData; + + EventData = 0; + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EV_SEPARATOR; + TcgEvent.EventSize = (UINT32)sizeof (EventData); + return TcgDxeHashLogExtendEventI ( + &mTcgDxeData, + (UINT8 *)&EventData, + sizeof (EventData), + &TcgEvent, + (UINT8 *)&EventData + ); +} + +/** + Read an EFI Variable. + + This function allocates a buffer to return the contents of the variable. The caller is + responsible for freeing the buffer. + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + + @return A pointer to the buffer to return the contents of the variable.Otherwise NULL. + +**/ +VOID * +EFIAPI +ReadVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize + ) +{ + EFI_STATUS Status; + VOID *VarData; + + *VarSize = 0; + Status = gRT->GetVariable ( + VarName, + VendorGuid, + NULL, + VarSize, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + return NULL; + } + + VarData = AllocatePool (*VarSize); + if (VarData != NULL) { + Status = gRT->GetVariable ( + VarName, + VendorGuid, + NULL, + VarSize, + VarData + ); + if (EFI_ERROR (Status)) { + FreePool (VarData); + VarData = NULL; + *VarSize = 0; + } + } + return VarData; +} + +/** + Measure and log an EFI variable, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR Index. + @param[in] EventType Event type. + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] VarData The content of the variable data. + @param[in] VarSize The size of the variable data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureVariable ( + IN TPM_PCRINDEX PCRIndex, + IN TCG_EVENTTYPE EventType, + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + IN VOID *VarData, + IN UINTN VarSize + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT_HDR TcgEvent; + UINTN VarNameLength; + EFI_VARIABLE_DATA *VarLog; + + VarNameLength = StrLen (VarName); + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EventType; + TcgEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize + - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); + + VarLog = (EFI_VARIABLE_DATA*)AllocatePool (TcgEvent.EventSize); + if (VarLog == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + VarLog->VariableName = *VendorGuid; + VarLog->UnicodeNameLength = VarNameLength; + VarLog->VariableDataLength = VarSize; + CopyMem ( + VarLog->UnicodeName, + VarName, + VarNameLength * sizeof (*VarName) + ); + CopyMem ( + (CHAR16 *)VarLog->UnicodeName + VarNameLength, + VarData, + VarSize + ); + + Status = TcgDxeHashLogExtendEventI ( + &mTcgDxeData, + (UINT8*)VarData, + VarSize, + &TcgEvent, + (UINT8*)VarLog + ); + FreePool (VarLog); + return Status; +} + +/** + Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[5]. + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + @param[out] VarData Pointer to the content of the variable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +ReadAndMeasureBootVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize, + OUT VOID **VarData + ) +{ + EFI_STATUS Status; + + *VarData = ReadVariable (VarName, VendorGuid, VarSize); + if (*VarData == NULL) { + return EFI_NOT_FOUND; + } + + Status = MeasureVariable ( + 5, + EV_EFI_VARIABLE_BOOT, + VarName, + VendorGuid, + *VarData, + *VarSize + ); + return Status; +} + +/** + Measure and log all EFI boot variables, and extend the measurement result into a specific PCR. + + The EFI boot variables are BootOrder and Boot#### variables. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureAllBootVariables ( + VOID + ) +{ + EFI_STATUS Status; + UINT16 *BootOrder; + UINTN BootCount; + UINTN Index; + VOID *BootVarData; + UINTN Size; + + Status = ReadAndMeasureBootVariable ( + mBootVarName, + &gEfiGlobalVariableGuid, + &BootCount, + (VOID **) &BootOrder + ); + if (Status == EFI_NOT_FOUND) { + return EFI_SUCCESS; + } + ASSERT (BootOrder != NULL); + + if (EFI_ERROR (Status)) { + FreePool (BootOrder); + return Status; + } + + BootCount /= sizeof (*BootOrder); + for (Index = 0; Index < BootCount; Index++) { + UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]); + Status = ReadAndMeasureBootVariable ( + mBootVarName, + &gEfiGlobalVariableGuid, + &Size, + &BootVarData + ); + if (!EFI_ERROR (Status)) { + FreePool (BootVarData); + } + } + + FreePool (BootOrder); + return EFI_SUCCESS; +} + +/** + Ready to Boot Event notification handler. + + Sequence of OS boot events is measured in this event notification handler. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + TPM_PCRINDEX PcrIndex; + + if (mBootAttempts == 0) { + + // + // Measure handoff tables. + // + Status = MeasureHandoffTables (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HOBs not Measured. Error!\n")); + } + + // + // Measure BootOrder & Boot#### variables. + // + Status = MeasureAllBootVariables (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Boot Variables not Measured. Error!\n")); + } + + // + // 1. This is the first boot attempt. + // + Status = TcgMeasureAction ( + EFI_CALLING_EFI_APPLICATION + ); + ASSERT_EFI_ERROR (Status); + + // + // 2. Draw a line between pre-boot env and entering post-boot env. + // + for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) { + Status = MeasureSeparatorEvent (PcrIndex); + ASSERT_EFI_ERROR (Status); + } + + // + // 3. Measure GPT. It would be done in SAP driver. + // + + // + // 4. Measure PE/COFF OS loader. It would be done in SAP driver. + // + + // + // 5. Read & Measure variable. BootOrder already measured. + // + } else { + // + // 6. Not first attempt, meaning a return from last attempt + // + Status = TcgMeasureAction ( + EFI_RETURNING_FROM_EFI_APPLICATOIN + ); + ASSERT_EFI_ERROR (Status); + } + + DEBUG ((EFI_D_INFO, "TPM TcgDxe Measure Data when ReadyToBoot\n")); + // + // Increase boot attempt counter. + // + mBootAttempts++; +} + +/** + Install TCG ACPI Table when ACPI Table Protocol is available. + + A system¡¯s firmware uses an ACPI table to identify the system's TCG capabilities + to the Post-Boot environment. The information in this ACPI table is not guaranteed + to be valid until the Host Platform transitions from pre-boot state to post-boot state. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context +**/ +VOID +EFIAPI +InstallAcpiTable ( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + UINTN TableKey; + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINT8 Checksum; + + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable); + if (EFI_ERROR (Status)) { + return; + } + + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + + // + // The ACPI table must be checksumed before calling the InstallAcpiTable() + // service of the ACPI table protocol to install it. + // + Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgClientAcpiTemplate, sizeof (mTcgClientAcpiTemplate)); + mTcgClientAcpiTemplate.Header.Checksum = Checksum; + + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTcgClientAcpiTemplate, + sizeof (mTcgClientAcpiTemplate), + &TableKey + ); + } else { + + // + // The ACPI table must be checksumed before calling the InstallAcpiTable() + // service of the ACPI table protocol to install it. + // + Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgServerAcpiTemplate, sizeof (mTcgServerAcpiTemplate)); + mTcgServerAcpiTemplate.Header.Checksum = Checksum; + + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTcgServerAcpiTemplate, + sizeof (mTcgServerAcpiTemplate), + &TableKey + ); + } + ASSERT_EFI_ERROR (Status); +} + +/** + Exit Boot Services Event notification handler. + + Measure invocation and success of ExitBootServices. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Measure invocation of ExitBootServices, + // + Status = TcgMeasureAction ( + EFI_EXIT_BOOT_SERVICES_INVOCATION + ); + ASSERT_EFI_ERROR (Status); + + // + // Measure success of ExitBootServices + // + Status = TcgMeasureAction ( + EFI_EXIT_BOOT_SERVICES_SUCCEEDED + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Get TPM Deactivated state. + + @param[out] TPMDeactivatedFlag Returns TPM Deactivated state. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +GetTpmStatus ( + OUT BOOLEAN *TPMDeactivatedFlag + ) +{ + EFI_STATUS Status; + TPM_STCLEAR_FLAGS VFlags; + + Status = TpmCommGetFlags ( + mTcgDxeData.TpmHandle, + TPM_CAP_FLAG_VOLATILE, + &VFlags, + sizeof (VFlags) + ); + if (!EFI_ERROR (Status)) { + *TPMDeactivatedFlag = VFlags.deactivated; + } + + return Status; +} + +/** + The driver's entry point. + + It publishes EFI TCG Protocol. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +DriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + VOID *Registration; + + mTcgDxeData.TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS; + Status = TisPcRequestUseTpm (mTcgDxeData.TpmHandle); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM not detected!\n")); + return Status; + } + + Status = GetTpmStatus (&mTcgDxeData.BsCap.TPMDeactivatedFlag); + if (EFI_ERROR (Status)) { + DEBUG (( + EFI_D_ERROR, + "Line %d in file " __FILE__ ":\n " + "DriverEntry: TPM not working properly\n", + __LINE__ + )); + return Status; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiTcgProtocolGuid, + EFI_NATIVE_INTERFACE, + &mTcgDxeData.TcgProtocol + ); + // + // Install ACPI Table + // + EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration); + + if (!EFI_ERROR (Status) && !mTcgDxeData.BsCap.TPMDeactivatedFlag) { + // + // Setup the log area and copy event log from hob list to it + // + Status = SetupEventLog (); + ASSERT_EFI_ERROR (Status); + + // + // Measure handoff tables, Boot#### variables etc. + // + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + OnReadyToBoot, + NULL, + &Event + ); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServices, + NULL, + &gEfiEventExitBootServicesGuid, + &Event + ); + } + + return Status; +} diff --git a/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf b/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf new file mode 100644 index 0000000000..95f37737c4 --- /dev/null +++ b/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf @@ -0,0 +1,70 @@ +## @file +# Component file for module TcgDxe. +# This module will produce TCG protocol and measure boot environment. +# +# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgDxe + FILE_GUID = A5683620-7998-4bb2-A377-1C1E31E1E215 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DriverEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + TcgDxe.c + TisDxe.c + TpmComm.c + TpmComm.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiBootServicesTableLib + HobLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + TpmCommLib + PrintLib + UefiLib + +[Guids] + gEfiSmbiosTableGuid # ALWAYS_CONSUMED + gEfiGlobalVariableGuid # ALWAYS_CONSUMED + gTcgEventEntryHobGuid + gEfiEventReadyToBootGuid + gEfiEventExitBootServicesGuid + +[Protocols] + gEfiTcgProtocolGuid ## PRODUCES + gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass + +[Depex] + TRUE + diff --git a/SecurityPkg/Tcg/TcgDxe/TisDxe.c b/SecurityPkg/Tcg/TcgDxe/TisDxe.c new file mode 100644 index 0000000000..635ff77e13 --- /dev/null +++ b/SecurityPkg/Tcg/TcgDxe/TisDxe.c @@ -0,0 +1,432 @@ +/** @file + TIS (TPM Interface Specification) functions used by TPM Dxe driver. + +Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include + +STATIC UINT8 TpmCommandBuf[TPMCMDBUFLENGTH]; + +/** + Send command to TPM for execution. + + @param[in] TisReg TPM register space base address. + @param[in] TpmBuffer Buffer for TPM command data. + @param[in] DataLength TPM command data length. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + +**/ +EFI_STATUS +TisPcSend ( + IN TIS_PC_REGISTERS_PTR TisReg, + IN UINT8 *TpmBuffer, + IN UINT32 DataLength + ) +{ + UINT16 BurstCount; + UINT32 Index; + EFI_STATUS Status; + + Status = TisPcPrepareCommand (TisReg); + if (EFI_ERROR (Status)){ + DEBUG ((DEBUG_ERROR, "The Tpm not ready!\n")); + return Status; + } + Index = 0; + while (Index < DataLength) { + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + return EFI_TIMEOUT; + } + for (; BurstCount > 0 && Index < DataLength; BurstCount--) { + MmioWrite8 ((UINTN) &TisReg->DataFifo, *(TpmBuffer + Index)); + Index++; + } + } + // + // Ensure the Tpm status STS_EXPECT change from 1 to 0 + // + Status = TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) TIS_PC_VALID, + TIS_PC_STS_EXPECT, + TIS_TIMEOUT_C + ); + return Status; +} + +/** + Receive response data of last command from TPM. + + @param[in] TisReg TPM register space base address. + @param[out] TpmBuffer Buffer for response data. + @param[out] RespSize Response data length. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_DEVICE_ERROR Unexpected device status. + @retval EFI_BUFFER_TOO_SMALL Response data is too long. + +**/ +EFI_STATUS +TisPcReceive ( + IN TIS_PC_REGISTERS_PTR TisReg, + OUT UINT8 *TpmBuffer, + OUT UINT32 *RespSize + ) +{ + EFI_STATUS Status; + UINT16 BurstCount; + UINT32 Index; + UINT32 ResponseSize; + UINT32 Data32; + + // + // Wait for the command completion + // + Status = TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA), + 0, + TIS_TIMEOUT_B + ); + if (EFI_ERROR (Status)) { + return EFI_TIMEOUT; + } + // + // Read the response data header and check it + // + Index = 0; + BurstCount = 0; + while (Index < sizeof (TPM_RSP_COMMAND_HDR)) { + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + return EFI_TIMEOUT; + } + for (; BurstCount > 0 ; BurstCount--) { + *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo); + Index++; + if (Index == sizeof (TPM_RSP_COMMAND_HDR)) + break; + } + } + // + // Check the reponse data header (tag,parasize and returncode ) + // + CopyMem (&Data32, (TpmBuffer + 2), sizeof (UINT32)); + ResponseSize = SwapBytes32 (Data32); + *RespSize = ResponseSize; + if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) { + return EFI_SUCCESS; + } + if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) { + return EFI_DEVICE_ERROR; + } + if (ResponseSize > TPMCMDBUFLENGTH) { + return EFI_BUFFER_TOO_SMALL; + } + // + // Continue reading the remaining data + // + while (Index < ResponseSize) { + for (; BurstCount > 0 ; BurstCount--) { + *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo); + Index++; + if (Index == ResponseSize) { + return EFI_SUCCESS; + } + } + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status) && (Index < ResponseSize)) { + return EFI_DEVICE_ERROR; + } + } + return EFI_SUCCESS; +} + +/** + Format TPM command data according to the format control character. + + @param[in] FmtChar Format control character. + @param[in, out] ap List of arguments. + @param[in] TpmBuffer Buffer for TPM command data. + @param[out] DataLength TPM command data length. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER Invalid format control character. + @retval EFI_BUFFER_TOO_SMALL Buffer too small for command data. + +**/ +EFI_STATUS +TisPcSendV ( + IN UINT8 FmtChar, + IN OUT VA_LIST *ap, + UINT8 *TpmBuffer, + UINT32 *DataLength + ) +{ + UINT8 DataByte; + UINT16 DataWord; + UINT32 DataDword; + TPM_RQU_COMMAND_HDR TpmCmdHdr; + TPM_RQU_COMMAND_HDR *TpmCmdPtr; + UINTN Size; + UINT8 *Raw; + + switch (FmtChar) { + + case 'b': + DataByte = VA_ARG (*ap, UINT8); + Raw = &DataByte; + Size = sizeof (DataByte); + break; + + case 'w': + DataWord = VA_ARG (*ap, UINT16); + DataWord = SwapBytes16 (DataWord); + Raw = (UINT8*)&DataWord; + Size = sizeof (DataWord); + break; + + case 'd': + DataDword = VA_ARG (*ap, UINT32); + DataDword = SwapBytes32 (DataDword); + Raw = (UINT8*)&DataDword; + Size = sizeof (DataDword); + break; + + case 'h': + TpmCmdPtr = VA_ARG (*ap, TPM_RQU_COMMAND_HDR*); + TpmCmdHdr.tag = SwapBytes16 (TpmCmdPtr->tag); + TpmCmdHdr.paramSize = SwapBytes32 (TpmCmdPtr->paramSize); + TpmCmdHdr.ordinal = SwapBytes32 (TpmCmdPtr->ordinal); + Raw = (UINT8*) &TpmCmdHdr; + Size = sizeof (TpmCmdHdr); + break; + + case 'r': + Raw = VA_ARG (*ap, UINT8*); + Size = VA_ARG (*ap, UINTN); + break; + + case '\0': + return EFI_INVALID_PARAMETER; + + default: + return EFI_INVALID_PARAMETER; + } + + if(*DataLength + (UINT32) Size > TPMCMDBUFLENGTH) { + return EFI_BUFFER_TOO_SMALL; + } + CopyMem (TpmBuffer + *DataLength, Raw, Size); + *DataLength += (UINT32) Size; + return EFI_SUCCESS; +} + +/** + Format reponse data according to the format control character. + + @param[in] FmtChar Format control character. + @param[in, out] ap List of arguments. + @param[out] TpmBuffer Buffer for reponse data. + @param[in, out] DataIndex Data offset in reponse data buffer. + @param[in] RespSize Response data length. + @param[out] DataFinished Reach the end of Response data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER Invalid format control character. + @retval EFI_BUFFER_TOO_SMALL Buffer too small for command data. + +**/ +EFI_STATUS +TisPcReceiveV ( + IN UINT8 FmtChar, + IN OUT VA_LIST *ap, + OUT UINT8 *TpmBuffer, + IN OUT UINT32 *DataIndex, + IN UINT32 RespSize, + OUT BOOLEAN *DataFinished + ) +{ + UINT8 *Raw; + TPM_RSP_COMMAND_HDR *TpmRspPtr; + UINTN Size; + + Raw = VA_ARG (*ap, UINT8*); + switch (FmtChar) { + + case 'b': + Size = sizeof (UINT8); + break; + + case 'w': + Size = sizeof (UINT16); + break; + + case 'd': + Size = sizeof (UINT32); + break; + + case 'h': + Size = sizeof (*TpmRspPtr); + break; + + case 'r': + Size = VA_ARG (*ap, UINTN); + if(*DataIndex + (UINT32) Size <= RespSize) { + break; + } + *DataFinished = TRUE; + if (*DataIndex >= RespSize) { + return EFI_SUCCESS; + } + CopyMem (Raw, TpmBuffer + *DataIndex, RespSize - *DataIndex); + *DataIndex += RespSize - *DataIndex; + return EFI_SUCCESS; + + case '\0': + return EFI_INVALID_PARAMETER; + + default: + return EFI_WARN_UNKNOWN_GLYPH; + } + + if(*DataIndex + (UINT32) Size > RespSize) { + *DataFinished = TRUE; + return EFI_SUCCESS; + } + + if( *DataIndex + (UINT32) Size > TPMCMDBUFLENGTH ) + return EFI_BUFFER_TOO_SMALL; + + CopyMem (Raw, TpmBuffer + *DataIndex, Size); + *DataIndex += (UINT32) Size; + + switch (FmtChar) { + + case 'w': + *(UINT16*)Raw = SwapBytes16 (*(UINT16*) Raw); + break; + + case 'd': + *(UINT32*)Raw = SwapBytes32 (*(UINT32*) Raw); + break; + + case 'h': + TpmRspPtr = (TPM_RSP_COMMAND_HDR*) Raw; + TpmRspPtr->tag = SwapBytes16 (TpmRspPtr->tag); + TpmRspPtr->paramSize = SwapBytes32 (TpmRspPtr->paramSize); + TpmRspPtr->returnCode = SwapBytes32 (TpmRspPtr->returnCode); + break; + } + return EFI_SUCCESS; +} + +/** + Send formatted command to TPM for execution and return formatted data from response. + + @param[in] TisReg TPM Handle. + @param[in] Fmt Format control string. + @param[in] ... The variable argument list. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + +**/ +EFI_STATUS +EFIAPI +TisPcExecute ( + IN TIS_TPM_HANDLE TisReg, + IN CONST CHAR8 *Fmt, + ... + ) +{ + EFI_STATUS Status; + VA_LIST Ap; + UINT32 BufSize; + UINT32 ResponseSize; + BOOLEAN DataFinished; + + VA_START (Ap, Fmt); + + // + // Put the formatted command to the TpmCommandBuf + // + BufSize = 0; + while (*Fmt != '\0') { + if (*Fmt == '%') Fmt++; + if (*Fmt == '/') break; + Status = TisPcSendV (*Fmt, &Ap, TpmCommandBuf, &BufSize); + if (EFI_ERROR( Status )) { + return Status; + } + Fmt++; + } + // + // Send the command to TPM + // + Status = TisPcSend (TisReg, TpmCommandBuf, BufSize); + if (EFI_ERROR (Status)) { + // + // Ensure the TPM state change from "Reception" to "Idle/Ready" + // + MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY); + return Status; + } + + MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_GO); + Fmt++; + // + // Receive the response data from TPM + // + ZeroMem (TpmCommandBuf, TPMCMDBUFLENGTH); + Status = TisPcReceive (TisReg, TpmCommandBuf, &ResponseSize); + // + // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready" + // + MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the formatted data from the TpmCommandBuf. + // + BufSize =0; + DataFinished = FALSE; + while (*Fmt != '\0') { + if (*Fmt == '%') { + Fmt++; + } + Status = TisPcReceiveV (*Fmt, &Ap, TpmCommandBuf, &BufSize, ResponseSize, &DataFinished); + if (EFI_ERROR (Status)) { + return Status; + } + if (DataFinished) { + return EFI_SUCCESS; + } + Fmt++; + } + + VA_END (Ap); + return Status; +} + diff --git a/SecurityPkg/Tcg/TcgDxe/TpmComm.c b/SecurityPkg/Tcg/TcgDxe/TpmComm.c new file mode 100644 index 0000000000..c47794b4f6 --- /dev/null +++ b/SecurityPkg/Tcg/TcgDxe/TpmComm.c @@ -0,0 +1,163 @@ +/** @file + Utility functions used by TPM Dxe driver. + +Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +#include "TpmComm.h" + +/** + Extend a TPM PCR. + + @param[in] TpmHandle TPM handle. + @param[in] DigestToExtend The 160 bit value representing the event to be recorded. + @param[in] PcrIndex The PCR to be updated. + @param[out] NewPcrValue New PCR value after extend. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +TpmCommExtend ( + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_DIGEST *DigestToExtend, + IN TPM_PCRINDEX PcrIndex, + OUT TPM_DIGEST *NewPcrValue + ) +{ + EFI_STATUS Status; + TPM_DIGEST NewValue; + TPM_RQU_COMMAND_HDR CmdHdr; + TPM_RSP_COMMAND_HDR RspHdr; + + if (NewPcrValue == NULL) { + NewPcrValue = &NewValue; + } + + CmdHdr.tag = TPM_TAG_RQU_COMMAND; + CmdHdr.paramSize = + sizeof (CmdHdr) + sizeof (PcrIndex) + sizeof (*DigestToExtend); + CmdHdr.ordinal = TPM_ORD_Extend; + Status = TisPcExecute ( + TpmHandle, + "%h%d%r%/%h%r", + &CmdHdr, + PcrIndex, + DigestToExtend, + (UINTN)sizeof (*DigestToExtend), + &RspHdr, + NewPcrValue, + (UINTN)sizeof (*NewPcrValue) + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (RspHdr.returnCode != 0) { + return EFI_DEVICE_ERROR; + } + return EFI_SUCCESS; +} + +/** + Get TPM capability flags. + + @param[in] TpmHandle TPM handle. + @param[in] FlagSubcap Flag subcap. + @param[out] FlagBuffer Pointer to the buffer for returned flag structure. + @param[in] FlagSize Size of the buffer. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +TpmCommGetFlags ( + IN TIS_TPM_HANDLE TpmHandle, + IN UINT32 FlagSubcap, + OUT VOID *FlagBuffer, + IN UINTN FlagSize + ) +{ + EFI_STATUS Status; + TPM_RQU_COMMAND_HDR CmdHdr; + TPM_RSP_COMMAND_HDR RspHdr; + UINT32 Size; + + CmdHdr.tag = TPM_TAG_RQU_COMMAND; + CmdHdr.paramSize = sizeof (CmdHdr) + sizeof (UINT32) * 3; + CmdHdr.ordinal = TPM_ORD_GetCapability; + + Status = TisPcExecute ( + TpmHandle, + "%h%d%d%d%/%h%d%r", + &CmdHdr, + TPM_CAP_FLAG, + sizeof (FlagSubcap), + FlagSubcap, + &RspHdr, + &Size, + FlagBuffer, + FlagSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (RspHdr.returnCode != 0) { + return EFI_DEVICE_ERROR; + } + return EFI_SUCCESS; +} + +/** + Add a new entry to the Event Log. + + @param[in, out] EventLogPtr Pointer to the Event Log data. + @param[in, out] LogSize Size of the Event Log. + @param[in] MaxSize Maximum size of the Event Log. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + +**/ +EFI_STATUS +TpmCommLogEvent ( + IN OUT UINT8 **EventLogPtr, + IN OUT UINTN *LogSize, + IN UINTN MaxSize, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + UINT32 NewLogSize; + + NewLogSize = sizeof (*NewEventHdr) + NewEventHdr->EventSize; + if (NewLogSize + *LogSize > MaxSize) { + return EFI_OUT_OF_RESOURCES; + } + + *EventLogPtr += *LogSize; + *LogSize += NewLogSize; + CopyMem (*EventLogPtr, NewEventHdr, sizeof (*NewEventHdr)); + CopyMem ( + *EventLogPtr + sizeof (*NewEventHdr), + NewEventData, + NewEventHdr->EventSize + ); + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Tcg/TcgDxe/TpmComm.h b/SecurityPkg/Tcg/TcgDxe/TpmComm.h new file mode 100644 index 0000000000..763ad76d62 --- /dev/null +++ b/SecurityPkg/Tcg/TcgDxe/TpmComm.h @@ -0,0 +1,99 @@ +/** @file + Definitions and function prototypes used by TPM DXE driver. + +Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _TPM_COMM_H_ +#define _TPM_COMM_H_ + +/** + Add a new entry to the Event Log. + + @param[in, out] EventLogPtr Pointer to the Event Log data. + @param[in, out] LogSize Size of the Event Log. + @param[in] MaxSize Maximum size of the Event Log. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + +**/ +EFI_STATUS +TpmCommLogEvent ( + IN OUT UINT8 **EventLogPtr, + IN OUT UINTN *LogSize, + IN UINTN MaxSize, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ); + +/** + Extend a TPM PCR. + + @param[in] TpmHandle TPM handle. + @param[in] DigestToExtend The 160 bit value representing the event to be recorded. + @param[in] PcrIndex The PCR to be updated. + @param[out] NewPcrValue New PCR value after extend. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +TpmCommExtend ( + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_DIGEST *DigestToExtend, + IN TPM_PCRINDEX PcrIndex, + OUT TPM_DIGEST *NewPcrValue + ); + +/** + Get TPM capability flags. + + @param[in] TpmHandle TPM handle. + @param[in] FlagSubcap Flag subcap. + @param[out] FlagBuffer Pointer to the buffer for returned flag structure. + @param[in] FlagSize Size of the buffer. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +TpmCommGetFlags ( + IN TIS_TPM_HANDLE TpmHandle, + IN UINT32 FlagSubcap, + OUT VOID *Buffer, + IN UINTN Size + ); + +/** + Send formatted command to TPM for execution and return formatted data from response. + + @param[in] TisReg TPM Handle. + @param[in] Fmt Format control string. + @param[in] ... The variable argument list. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + +**/ +EFI_STATUS +EFIAPI +TisPcExecute ( + IN TIS_TPM_HANDLE TisReg, + IN CONST CHAR8 *Fmt, + ... + ); + +#endif // _TPM_COMM_H_ diff --git a/SecurityPkg/Tcg/TcgPei/TcgPei.c b/SecurityPkg/Tcg/TcgPei/TcgPei.c new file mode 100644 index 0000000000..63caddec8c --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TcgPei.c @@ -0,0 +1,593 @@ +/** @file + Initialize TPM device and measure FVs before handing off control to DXE. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TpmComm.h" + +BOOLEAN mImageInMemory = FALSE; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializedPpiGuid, + NULL +}; + +/** + Lock physical presence if needed. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS Operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +PhysicalPresencePpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = { + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gPeiLockPhysicalPresencePpiGuid, + PhysicalPresencePpiNotifyCallback + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiFirmwareVolumeInfoPpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + } +}; + +CHAR8 mSCrtmVersion[] = "{D20BC7C6-A1A5-415c-AE85-38290AB6BE04}"; + +EFI_PLATFORM_FIRMWARE_BLOB mMeasuredFvInfo[FixedPcdGet32 (PcdPeiCoreMaxFvSupported)]; +UINT32 mMeasuredFvIndex = 0; + +/** + Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, + and build a GUIDed HOB recording the event which will be passed to the DXE phase and + added into the Event Log. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData. + @param[in] TpmHandle TPM handle. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +HashLogExtendEvent ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 *HashData, + IN UINTN HashDataLen, + IN TIS_TPM_HANDLE TpmHandle, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + VOID *HobData; + + HobData = NULL; + if (HashDataLen != 0) { + Status = TpmCommHashAll ( + HashData, + HashDataLen, + &NewEventHdr->Digest + ); + ASSERT_EFI_ERROR (Status); + } + + Status = TpmCommExtend ( + PeiServices, + TpmHandle, + &NewEventHdr->Digest, + NewEventHdr->PCRIndex, + NULL + ); + ASSERT_EFI_ERROR (Status); + + HobData = BuildGuidHob ( + &gTcgEventEntryHobGuid, + sizeof (*NewEventHdr) + NewEventHdr->EventSize + ); + if (HobData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr)); + HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr)); + CopyMem (HobData, NewEventData, NewEventHdr->EventSize); + return EFI_SUCCESS; +} + +/** + Measure CRTM version. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureCRTMVersion ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle + ) +{ + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Here, only a static GUID is measured instead of real CRTM version. + // OEMs should get real CRTM version string and measure it. + // + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_S_CRTM_VERSION; + TcgEventHdr.EventSize = sizeof (mSCrtmVersion); + return HashLogExtendEvent ( + PeiServices, + (UINT8*)&mSCrtmVersion, + TcgEventHdr.EventSize, + TpmHandle, + &TcgEventHdr, + (UINT8*)&mSCrtmVersion + ); +} + +/** + Measure FV image. + Add it into the measured FV list after the FV is measured successfully. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + + @retval EFI_SUCCESS Fv image is measured successfully + or it has been already measured. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureFvImage ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength + ) +{ + UINT32 Index; + EFI_STATUS Status; + EFI_PLATFORM_FIRMWARE_BLOB FvBlob; + TCG_PCR_EVENT_HDR TcgEventHdr; + TIS_TPM_HANDLE TpmHandle; + + TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS; + + // + // Check whether FV is in the measured FV list. + // + for (Index = 0; Index < mMeasuredFvIndex; Index ++) { + if (mMeasuredFvInfo[Index].BlobBase == FvBase) { + return EFI_SUCCESS; + } + } + + // + // Measure and record the FV to the TPM + // + FvBlob.BlobBase = FvBase; + FvBlob.BlobLength = FvLength; + + DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei starts at: 0x%x\n", FvBlob.BlobBase)); + DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei has the size: 0x%x\n", FvBlob.BlobLength)); + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; + TcgEventHdr.EventSize = sizeof (FvBlob); + + Status = HashLogExtendEvent ( + (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(), + (UINT8*) (UINTN) FvBlob.BlobBase, + (UINTN) FvBlob.BlobLength, + TpmHandle, + &TcgEventHdr, + (UINT8*) &FvBlob + ); + ASSERT_EFI_ERROR (Status); + + // + // Add new FV into the measured FV list. + // + ASSERT (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) { + mMeasuredFvInfo[mMeasuredFvIndex].BlobBase = FvBase; + mMeasuredFvInfo[mMeasuredFvIndex++].BlobLength = FvLength; + } + + return Status; +} + +/** + Measure main BIOS. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureMainBios ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle + ) +{ + EFI_STATUS Status; + UINT32 FvInstances; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_FV_INFO VolumeInfo; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + + FvInstances = 0; + while (TRUE) { + // + // Traverse all firmware volume instances of Static Core Root of Trust for Measurement + // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special + // platform for special CRTM TPM measuring. + // + Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle); + if (EFI_ERROR (Status)) { + break; + } + + // + // Measure and record the firmware volume that is dispatched by PeiCore + // + Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo); + ASSERT_EFI_ERROR (Status); + // + // Locate the corresponding FV_PPI according to founded FV's format guid + // + Status = PeiServicesLocatePpi ( + &VolumeInfo.FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (!EFI_ERROR (Status)) { + MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize); + } + + FvInstances++; + } + + return EFI_SUCCESS; +} + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv; + EFI_STATUS Status; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + + Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi; + + // + // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi. + // + Status = PeiServicesLocatePpi ( + &Fv->FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + // + // This is an FV from an FFS file, and the parent FV must have already been measured, + // No need to measure twice, so just returns + // + if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) { + return EFI_SUCCESS; + } + + return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize); +} + +/** + Lock physical presence if needed. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_ABORTED physicalPresenceCMDEnable is locked. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +PhysicalPresencePpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_STATUS Status; + PEI_LOCK_PHYSICAL_PRESENCE_PPI *LockPhysicalPresencePpi; + BOOLEAN LifetimeLock; + BOOLEAN CmdEnable; + TIS_TPM_HANDLE TpmHandle; + + TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS; + LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi; + + if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) { + return EFI_SUCCESS; + } + + // + // Lock TPM physical presence. + // + + Status = TpmCommGetCapability (PeiServices, TpmHandle, NULL, &LifetimeLock, &CmdEnable); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!CmdEnable) { + if (LifetimeLock) { + // + // physicalPresenceCMDEnable is locked, can't change. + // + return EFI_ABORTED; + } + + // + // Enable physical presence command + // It is necessary in order to lock physical presence + // + Status = TpmCommPhysicalPresence ( + PeiServices, + TpmHandle, + TPM_PHYSICAL_PRESENCE_CMD_ENABLE + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Lock physical presence + // + Status = TpmCommPhysicalPresence ( + PeiServices, + TpmHandle, + TPM_PHYSICAL_PRESENCE_LOCK + ); + return Status; +} + +/** + Check if TPM chip is activeated or not. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @retval TRUE TPM is activated. + @retval FALSE TPM is deactivated. + +**/ +BOOLEAN +EFIAPI +IsTpmUsable ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle + ) +{ + EFI_STATUS Status; + BOOLEAN Deactivated; + + Status = TpmCommGetCapability (PeiServices, TpmHandle, &Deactivated, NULL, NULL); + if (EFI_ERROR (Status)) { + return FALSE; + } + return (BOOLEAN)(!Deactivated); +} + +/** + Do measurement after memory is ready. + + @param[in] PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +PeimEntryMP ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + TIS_TPM_HANDLE TpmHandle; + + TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS; + Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsTpmUsable (PeiServices, TpmHandle)) { + Status = MeasureCRTMVersion (PeiServices, TpmHandle); + ASSERT_EFI_ERROR (Status); + + Status = MeasureMainBios (PeiServices, TpmHandle); + } + + // + // Post callbacks: + // 1). for the FvInfoPpi services to measure and record + // the additional Fvs to TPM + // 2). for the OperatorPresencePpi service to determine whether to + // lock the TPM + // + Status = PeiServicesNotifyPpi (&mNotifyList[0]); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Entry point of this module. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Describes the list of possible PEI Services. + + @return Status. + +**/ +EFI_STATUS +EFIAPI +PeimEntryMA ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + TIS_TPM_HANDLE TpmHandle; + + if (PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm)) { + return EFI_UNSUPPORTED; + } + + Status = (**PeiServices).RegisterForShadow(FileHandle); + if (Status == EFI_ALREADY_STARTED) { + mImageInMemory = TRUE; + } else if (Status == EFI_NOT_FOUND) { + ASSERT_EFI_ERROR (Status); + } + + if (!mImageInMemory) { + // + // Initialize TPM device + // + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS; + Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "TPM not detected!\n")); + return Status; + } + + Status = TpmCommStartup ((EFI_PEI_SERVICES**)PeiServices, TpmHandle, BootMode); + if (EFI_ERROR (Status) ) { + return Status; + } + Status = TpmCommContinueSelfTest ((EFI_PEI_SERVICES**)PeiServices, TpmHandle); + if (EFI_ERROR (Status)) { + return Status; + } + Status = PeiServicesInstallPpi (&mTpmInitializedPpiList); + ASSERT_EFI_ERROR (Status); + } + + if (mImageInMemory) { + Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices); + if (EFI_ERROR (Status)) { + return Status; + } + } + + return Status; +} diff --git a/SecurityPkg/Tcg/TcgPei/TcgPei.inf b/SecurityPkg/Tcg/TcgPei/TcgPei.inf new file mode 100644 index 0000000000..60a3bfa5f1 --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TcgPei.inf @@ -0,0 +1,67 @@ +## @file +# This module will initialize TPM device and measure FVs in PEI phase. +# +# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgPei + FILE_GUID = 2BE1E4A6-6505-43b3-9FFC-A3C8330E0432 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimEntryMA + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + TcgPei.c + TisPei.c + TpmComm.c + TpmComm.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + HobLib + PeimEntryPoint + PeiServicesLib + BaseMemoryLib + DebugLib + TpmCommLib + TimerLib + IoLib + PeiServicesTablePointerLib + +[Guids] + gTcgEventEntryHobGuid + +[Ppis] + gPeiLockPhysicalPresencePpiGuid + gEfiPeiFirmwareVolumeInfoPpiGuid + gPeiTpmInitializedPpiGuid + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm + +[FixedPcd] + gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport + gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid diff --git a/SecurityPkg/Tcg/TcgPei/TisPei.c b/SecurityPkg/Tcg/TcgPei/TisPei.c new file mode 100644 index 0000000000..97d9628bda --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TisPei.c @@ -0,0 +1,160 @@ +/** @file + TIS (TPM Interface Specification) functions used by TPM PEI driver. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include + +/** + Send a command to TPM for execution and return response data. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TisReg TPM register space base address. + @param[in] BufferIn Buffer for command data. + @param[in] SizeIn Size of command data. + @param[in, out] BufferOut Buffer for response data. + @param[in, out] SizeOut Size of response data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TisTpmCommand ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_PC_REGISTERS_PTR TisReg, + IN UINT8 *BufferIn, + IN UINT32 SizeIn, + IN OUT UINT8 *BufferOut, + IN OUT UINT32 *SizeOut + ) +{ + EFI_STATUS Status; + UINT16 BurstCount; + UINT32 Index; + UINT32 TpmOutSize; + UINT16 Data16; + UINT32 Data32; + + Status = TisPcPrepareCommand (TisReg); + if (EFI_ERROR (Status)){ + DEBUG ((DEBUG_ERROR, "Tpm is not ready for command!\n")); + return Status; + } + // + // Send the command data to Tpm + // + Index = 0; + while (Index < SizeIn) { + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_TIMEOUT; + goto Exit; + } + for (; BurstCount > 0 && Index < SizeIn; BurstCount--) { + MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index)); + Index++; + } + } + // + // Check the Tpm status STS_EXPECT change from 1 to 0 + // + Status = TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) TIS_PC_VALID, + TIS_PC_STS_EXPECT, + TIS_TIMEOUT_C + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "The send buffer too small!\n")); + Status = EFI_BUFFER_TOO_SMALL; + goto Exit; + } + // + // Executed the TPM command and waiting for the response data ready + // + MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO); + Status = TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA), + 0, + TIS_TIMEOUT_B + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Wait for Tpm response data time out!!\n")); + Status = EFI_TIMEOUT; + goto Exit; + } + // + // Get response data header + // + Index = 0; + BurstCount = 0; + while (Index < sizeof (TPM_RSP_COMMAND_HDR)) { + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_TIMEOUT; + goto Exit; + } + for (; BurstCount > 0; BurstCount--) { + *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo); + Index++; + if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break; + } + } + // + // Check the reponse data header (tag,parasize and returncode ) + // + CopyMem (&Data16, BufferOut, sizeof (UINT16)); + if (SwapBytes16 (Data16) != TPM_TAG_RSP_COMMAND ) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + + CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32)); + TpmOutSize = SwapBytes32 (Data32); + if (*SizeOut < TpmOutSize) { + Status = EFI_BUFFER_TOO_SMALL; + goto Exit; + } + *SizeOut = TpmOutSize; + // + // Continue reading the remaining data + // + while ( Index < TpmOutSize ) { + for (; BurstCount > 0; BurstCount--) { + *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo); + Index++; + if (Index == TpmOutSize) { + Status = EFI_SUCCESS; + goto Exit; + } + } + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_TIMEOUT; + goto Exit; + } + } +Exit: + MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY); + return Status; +} + diff --git a/SecurityPkg/Tcg/TcgPei/TpmComm.c b/SecurityPkg/Tcg/TcgPei/TpmComm.c new file mode 100644 index 0000000000..fb5011ee9d --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TpmComm.c @@ -0,0 +1,272 @@ +/** @file + Utility functions used by TPM PEI driver. + +Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TpmComm.h" + +/** + Send a command to TPM for execution and return response data. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TisReg TPM register space base address. + @param[in] BufferIn Buffer for command data. + @param[in] SizeIn Size of command data. + @param[in, out] BufferOut Buffer for response data. + @param[in, out] SizeOut size of response data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TisTpmCommand ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_PC_REGISTERS_PTR TisReg, + IN UINT8 *BufferIn, + IN UINT32 SizeIn, + IN OUT UINT8 *BufferOut, + IN OUT UINT32 *SizeOut + ); + +/** + Send TPM_Startup command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] BootMode Boot mode. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommStartup ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN EFI_BOOT_MODE BootMode + ) +{ + EFI_STATUS Status; + TPM_STARTUP_TYPE TpmSt; + UINT32 TpmRecvSize; + UINT32 TpmSendSize; + TPM_CMD_START_UP SendBuffer; + UINT8 RecvBuffer[20]; + + TpmSt = TPM_ST_CLEAR; + if (BootMode == BOOT_ON_S3_RESUME) { + TpmSt = TPM_ST_STATE; + } + // + // send Tpm command TPM_ORD_Startup + // + TpmRecvSize = 20; + TpmSendSize = sizeof (TPM_CMD_START_UP); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_Startup); + SendBuffer.TpmSt = SwapBytes16 (TpmSt); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + return Status; +} + +/** + Send TPM_ContinueSelfTest command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommContinueSelfTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle + ) +{ + EFI_STATUS Status; + UINT32 TpmRecvSize; + UINT32 TpmSendSize; + TPM_CMD_SELF_TEST SendBuffer; + UINT8 RecvBuffer[20]; + + // + // send Tpm command TPM_ORD_ContinueSelfTest + // + TpmRecvSize = 20; + TpmSendSize = sizeof (TPM_CMD_SELF_TEST); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_ContinueSelfTest); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + return Status; +} + +/** + Get TPM capability flags. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[out] Deactivated Returns deactivated flag. + @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag. + @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommGetCapability ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + OUT BOOLEAN *Deactivated, OPTIONAL + OUT BOOLEAN *LifetimeLock, OPTIONAL + OUT BOOLEAN *CmdEnable OPTIONAL + ) +{ + EFI_STATUS Status; + UINT32 TpmRecvSize; + UINT32 TpmSendSize; + TPM_CMD_GET_CAPABILITY SendBuffer; + UINT8 RecvBuffer[40]; + TPM_PERMANENT_FLAGS *TpmPermanentFlags; + + // + // send Tpm command TPM_ORD_GetCapability + // + TpmRecvSize = 40; + TpmSendSize = sizeof (TPM_CMD_GET_CAPABILITY); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_GetCapability); + SendBuffer.Capability = SwapBytes32 (TPM_CAP_FLAG); + SendBuffer.CapabilityFlagSize = SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT)); + SendBuffer.CapabilityFlag = SwapBytes32 (TPM_CAP_FLAG_PERMANENT); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + if (EFI_ERROR (Status)) { + return Status; + } + TpmPermanentFlags = (TPM_PERMANENT_FLAGS *)&RecvBuffer[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)]; + if (Deactivated != NULL) { + *Deactivated = TpmPermanentFlags->deactivated; + } + + if (LifetimeLock != NULL) { + *LifetimeLock = TpmPermanentFlags->physicalPresenceLifetimeLock; + } + + if (CmdEnable != NULL) { + *CmdEnable = TpmPermanentFlags->physicalPresenceCMDEnable; + } + return Status; +} + +/** + Extend a TPM PCR. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] DigestToExtend The 160 bit value representing the event to be recorded. + @param[in] PcrIndex The PCR to be updated. + @param[out] NewPcrValue New PCR value after extend. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommExtend ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_DIGEST *DigestToExtend, + IN TPM_PCRINDEX PcrIndex, + OUT TPM_DIGEST *NewPcrValue + ) +{ + EFI_STATUS Status; + UINT32 TpmSendSize; + UINT32 TpmRecvSize; + TPM_CMD_EXTEND SendBuffer; + UINT8 RecvBuffer[10 + sizeof(TPM_DIGEST)]; + + // + // send Tpm command TPM_ORD_Extend + // + TpmRecvSize = sizeof (TPM_RSP_COMMAND_HDR) + sizeof (TPM_DIGEST); + TpmSendSize = sizeof (TPM_CMD_EXTEND); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_Extend); + SendBuffer.PcrIndex = SwapBytes32 (PcrIndex); + CopyMem (&SendBuffer.TpmDigest, (UINT8 *)DigestToExtend, sizeof (TPM_DIGEST)); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + ASSERT_EFI_ERROR (Status); + + if(NewPcrValue != NULL) { + CopyMem ((UINT8*)NewPcrValue, &RecvBuffer[10], sizeof (TPM_DIGEST)); + } + + return Status; +} + + +/** + Send TSC_PhysicalPresence command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] PhysicalPresence The state to set the TPMs Physical Presence flags. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommPhysicalPresence ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_PHYSICAL_PRESENCE PhysicalPresence + ) +{ + EFI_STATUS Status; + UINT32 TpmSendSize; + UINT32 TpmRecvSize; + TPM_CMD_PHYSICAL_PRESENCE SendBuffer; + UINT8 RecvBuffer[10]; + + // + // send Tpm command TSC_ORD_PhysicalPresence + // + TpmRecvSize = 10; + TpmSendSize = sizeof (TPM_CMD_PHYSICAL_PRESENCE); + SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize); + SendBuffer.Hdr.ordinal = SwapBytes32 (TSC_ORD_PhysicalPresence); + SendBuffer.PhysicalPresence = SwapBytes16 (PhysicalPresence); + Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize); + return Status; +} diff --git a/SecurityPkg/Tcg/TcgPei/TpmComm.h b/SecurityPkg/Tcg/TcgPei/TpmComm.h new file mode 100644 index 0000000000..52d7f2e20d --- /dev/null +++ b/SecurityPkg/Tcg/TcgPei/TpmComm.h @@ -0,0 +1,163 @@ +/** @file + The header file for TPM PEI driver. + +Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _TPM_COMM_H_ +#define _TPM_COMM_H_ + +#include +#include +#include +#include +#include +#include + +#pragma pack(1) + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_STARTUP_TYPE TpmSt; +} TPM_CMD_START_UP; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; +} TPM_CMD_SELF_TEST; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + UINT32 Capability; + UINT32 CapabilityFlagSize; + UINT32 CapabilityFlag; +} TPM_CMD_GET_CAPABILITY; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_PCRINDEX PcrIndex; + TPM_DIGEST TpmDigest; +} TPM_CMD_EXTEND; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_PHYSICAL_PRESENCE PhysicalPresence; +} TPM_CMD_PHYSICAL_PRESENCE; + +#pragma pack() + +/** + Send TPM_Startup command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] BootMode Boot mode. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommStartup ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN EFI_BOOT_MODE BootMode + ); + +/** + Send TPM_ContinueSelfTest command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommContinueSelfTest ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle + ); + +/** + Get TPM capability flags. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[out] Deactivated Returns deactivated flag. + @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag. + @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommGetCapability ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + OUT BOOLEAN *Deactivated, OPTIONAL + OUT BOOLEAN *LifetimeLock, OPTIONAL + OUT BOOLEAN *CmdEnable OPTIONAL + ); + +/** + Extend a TPM PCR. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] DigestToExtend The 160 bit value representing the event to be recorded. + @param[in] PcrIndex The PCR to be updated. + @param[out] NewPcrValue New PCR value after extend. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommExtend ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_DIGEST *DigestToExtend, + IN TPM_PCRINDEX PcrIndex, + OUT TPM_DIGEST *NewPcrValue + ); + + +/** + Send TSC_PhysicalPresence command to TPM. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] TpmHandle TPM handle. + @param[in] PhysicalPresence The state to set the TPMs Physical Presence flags. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_TIMEOUT The register can't run into the expected status in time. + @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + +**/ +EFI_STATUS +TpmCommPhysicalPresence ( + IN EFI_PEI_SERVICES **PeiServices, + IN TIS_TPM_HANDLE TpmHandle, + IN TPM_PHYSICAL_PRESENCE PhysicalPresence + ); + +#endif // _TPM_COMM_H_ diff --git a/SecurityPkg/Tcg/TcgSmm/TcgSmm.c b/SecurityPkg/Tcg/TcgSmm/TcgSmm.c new file mode 100644 index 0000000000..9116944081 --- /dev/null +++ b/SecurityPkg/Tcg/TcgSmm/TcgSmm.c @@ -0,0 +1,455 @@ +/** @file + It updates TPM items in ACPI table and registers SMI callback + functions for physical presence and ClearMemory. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +// +// AML parsing definitions +// +#define AML_OPREGION_OP 0x80 +#define AML_BYTE_PREFIX 0x0A +#define AML_DWORD_PREFIX 0x0C + +#pragma pack(1) +typedef struct { + UINT8 SoftwareSmi; + UINT32 Parameter; + UINT32 Response; + UINT32 Request; + UINT32 LastRequest; + UINT32 ReturnCode; +} PHYSICAL_PRESENCE_NVS; + +typedef struct { + UINT8 SoftwareSmi; + UINT32 Parameter; + UINT32 Request; +} MEMORY_CLEAR_NVS; + +typedef struct { + PHYSICAL_PRESENCE_NVS PhysicalPresence; + MEMORY_CLEAR_NVS MemoryClear; +} TCG_NVS; + +typedef struct { + UINT8 OpRegionOp; + UINT32 NameString; + UINT8 RegionSpace; + UINT8 DWordPrefix; + UINT32 RegionOffset; + UINT8 BytePrefix; + UINT8 RegionLen; +} AML_OP_REGION_32_8; +#pragma pack() + +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable; +TCG_NVS *mTcgNvs; + +/** + Software SMI callback for TPM physical presence which is called from ACPI method. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + +**/ +EFI_STATUS +EFIAPI +PhysicalPresenceCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_PHYSICAL_PRESENCE PpData; + UINT8 Flags; + BOOLEAN RequestConfirmed; + + // + // Get the Physical Presence variable + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = mSmmVariable->SmmGetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter)); + if (mTcgNvs->PhysicalPresence.Parameter == 5) { + // + // Return TPM Operation Response to OS Environment + // + mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest; + mTcgNvs->PhysicalPresence.Response = PpData.PPResponse; + + } else if ((mTcgNvs->PhysicalPresence.Parameter == 2) || (mTcgNvs->PhysicalPresence.Parameter == 7)) { + // + // Submit TPM Operation Request to Pre-OS Environment + // + + if (mTcgNvs->PhysicalPresence.Request == SET_OPERATOR_AUTH) { + // + // This command requires UI to prompt user for Auth data, NOT implemented. + // + mTcgNvs->PhysicalPresence.ReturnCode = 1; + return EFI_SUCCESS; + } + + if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) { + PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request; + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = mSmmVariable->SmmSetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &PpData + ); + } + + if (EFI_ERROR (Status)) { + // + // General failure. + // + mTcgNvs->PhysicalPresence.ReturnCode = 2; + return EFI_SUCCESS; + } + mTcgNvs->PhysicalPresence.ReturnCode = 0; + } else if (mTcgNvs->PhysicalPresence.Parameter == 8) { + // + // Get User Confirmation Status for Operation + // + Flags = PpData.Flags; + RequestConfirmed = FALSE; + + switch (mTcgNvs->PhysicalPresence.Request) { + case ENABLE: + case DISABLE: + case ACTIVATE: + case DEACTIVATE: + case ENABLE_ACTIVATE: + case DEACTIVATE_DISABLE: + case SET_OWNER_INSTALL_TRUE: + case SET_OWNER_INSTALL_FALSE: + case ENABLE_ACTIVATE_OWNER_TRUE: + case DEACTIVATE_DISABLE_OWNER_FALSE: + if ((Flags & FLAG_NO_PPI_PROVISION) != 0) { + RequestConfirmed = TRUE; + } + break; + + case CLEAR: + case ENABLE_ACTIVATE_CLEAR: + if ((Flags & FLAG_NO_PPI_CLEAR) != 0) { + RequestConfirmed = TRUE; + } + break; + + case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) { + RequestConfirmed = TRUE; + } + break; + + case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + case CLEAR_ENABLE_ACTIVATE: + if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) { + RequestConfirmed = TRUE; + } + break; + + case SET_NO_PPI_PROVISION_FALSE: + case SET_NO_PPI_CLEAR_FALSE: + case SET_NO_PPI_MAINTENANCE_FALSE: + case NO_ACTION: + RequestConfirmed = TRUE; + break; + + case SET_OPERATOR_AUTH: + // + // This command requires UI to prompt user for Auth data + // Here it is NOT implemented + // + mTcgNvs->PhysicalPresence.ReturnCode = 0; + return EFI_SUCCESS; + } + + if (RequestConfirmed) { + // + // Allowed and physically present user not required + // + mTcgNvs->PhysicalPresence.ReturnCode = 4; + } else { + // + // Allowed and physically present user required + // + mTcgNvs->PhysicalPresence.ReturnCode = 3; + } + } + + return EFI_SUCCESS; +} + + +/** + Software SMI callback for MemoryClear which is called from ACPI method. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + +**/ +EFI_STATUS +EFIAPI +MemoryClearCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + UINTN DataSize; + UINT8 MorControl; + + if (mTcgNvs->MemoryClear.Parameter == 1) { + // + // Called from ACPI _DSM method, save the MOR data to variable. + // + MorControl = (UINT8) mTcgNvs->MemoryClear.Request; + } else if (mTcgNvs->MemoryClear.Parameter == 2) { + // + // Called from ACPI _PTS method, setup ClearMemory flags if needed. + // + DataSize = sizeof (UINT8); + Status = mSmmVariable->SmmGetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + NULL, + &DataSize, + &MorControl + ); + if (EFI_ERROR (Status)) { + ASSERT (Status == EFI_NOT_FOUND); + return EFI_SUCCESS; + } + + if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) { + return EFI_SUCCESS; + } + MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK; + } + + DataSize = sizeof (UINT8); + Status = mSmmVariable->SmmSetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &MorControl + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + Find the operation region in TCG ACPI table by given Name and Size, + and initialize it if the region is found. + + @param[in, out] Table The TPM item in ACPI table. + @param[in] Name The name string to find in TPM table. + @param[in] Size The size of the region to find. + + @return The allocated address for the found region. + +**/ +VOID * +AssignOpRegion ( + EFI_ACPI_DESCRIPTION_HEADER *Table, + UINT32 Name, + UINT16 Size + ) +{ + EFI_STATUS Status; + AML_OP_REGION_32_8 *OpRegion; + EFI_PHYSICAL_ADDRESS MemoryAddress; + + MemoryAddress = SIZE_4GB - 1; + + // + // Patch some pointers for the ASL code before loading the SSDT. + // + for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1); + OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length); + OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) { + if ((OpRegion->OpRegionOp == AML_OPREGION_OP) && + (OpRegion->NameString == Name) && + (OpRegion->RegionLen == Size) && + (OpRegion->DWordPrefix == AML_DWORD_PREFIX) && + (OpRegion->BytePrefix == AML_BYTE_PREFIX)) { + + Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress); + ASSERT_EFI_ERROR (Status); + ZeroMem ((VOID *)(UINTN)MemoryAddress, Size); + OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress; + break; + } + } + + return (VOID *) (UINTN) MemoryAddress; +} + +/** + Initialize and publish TPM items in ACPI table. + + @retval EFI_SUCCESS The TCG ACPI table is published successfully. + @retval Others The TCG ACPI table is not published. + +**/ +EFI_STATUS +PublishAcpiTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINTN TableKey; + EFI_ACPI_DESCRIPTION_HEADER *Table; + UINTN TableSize; + + Status = GetSectionFromFv ( + &gEfiCallerIdGuid, + EFI_SECTION_RAW, + 0, + (VOID **) &Table, + &TableSize + ); + ASSERT_EFI_ERROR (Status); + + ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e')); + mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), sizeof (TCG_NVS)); + ASSERT (mTcgNvs != NULL); + + // + // Publish the TPM ACPI table + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); + ASSERT_EFI_ERROR (Status); + + TableKey = 0; + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + Table, + TableSize, + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + The driver's entry point. + + It install callbacks for TPM physical presence and MemoryClear, and locate + SMM variable to be used in the callback function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeTcgSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; + EFI_SMM_SW_REGISTER_CONTEXT SwContext; + EFI_HANDLE SwHandle; + + Status = PublishAcpiTable (); + ASSERT_EFI_ERROR (Status); + + // + // Get the Sw dispatch protocol and register SMI callback functions. + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch); + ASSERT_EFI_ERROR (Status); + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; + + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; + + // + // Locate SmmVariableProtocol. + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf b/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf new file mode 100644 index 0000000000..c8e7092e73 --- /dev/null +++ b/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf @@ -0,0 +1,56 @@ +## @file +# This driver implements TPM definition block in ACPI table and +# registers SMI callback functions for physical presence and +# MemoryClear to handle the requests from ACPI method. +# +# Copyright (c) 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgSmm + FILE_GUID = 42293093-76B9-4482-8C02-3BEFDEA9B35D + MODULE_TYPE = DXE_SMM_DRIVER + PI_SPECIFICATION_VERSION = 0x0001000A + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeTcgSmm + +[Sources] + TcgSmm.c + Tpm.asl + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiDriverEntryPoint + SmmServicesTableLib + UefiBootServicesTableLib + DebugLib + DxeServicesLib + +[Guids] + gEfiPhysicalPresenceGuid + gEfiMemoryOverwriteControlDataGuid + +[Protocols] + gEfiSmmSwDispatch2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiSmmVariableProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED + +[Depex] + gEfiAcpiTableProtocolGuid AND + gEfiSmmSwDispatch2ProtocolGuid AND + gEfiSmmVariableProtocolGuid AND + gEfiTcgProtocolGuid \ No newline at end of file diff --git a/SecurityPkg/Tcg/TcgSmm/Tpm.asl b/SecurityPkg/Tcg/TcgSmm/Tpm.asl new file mode 100644 index 0000000000..000fc661a9 --- /dev/null +++ b/SecurityPkg/Tcg/TcgSmm/Tpm.asl @@ -0,0 +1,354 @@ +/** @file + The TPM definition block in ACPI table for physical presence + and MemoryClear. + +Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +DefinitionBlock ( + "Tpm.aml", + "SSDT", + 1, + "Intel_", + "TcgTable", + 0x1000 + ) +{ + Scope (\_SB) + { + Device (TPM) + { + // + // Define _HID, "PNP0C31" is defined in + // "Secure Startup-FVE and TPM Admin BIOS and Platform Requirements" + // + Name (_HID, EISAID ("PNP0C31")) + + // + // Readable name of this device, don't know if this way is correct yet + // + Name (_STR, Unicode ("TPM 1.2 Device")) + + // + // Return the resource consumed by TPM device + // + Name (_CRS, ResourceTemplate () { + Memory32Fixed (ReadOnly, 0xfed40000, 0x5000) + }) + + // + // Operational region for Smi port access + // + OperationRegion (SMIP, SystemIO, 0xB2, 1) + Field (SMIP, ByteAcc, NoLock, Preserve) + { + IOB2, 8 + } + + // + // Operational region for TPM access + // + OperationRegion (TPMR, SystemMemory, 0xfed40000, 0x5000) + Field (TPMR, AnyAcc, NoLock, Preserve) + { + ACC0, 8, + } + + // + // Operational region for TPM support, TPM Physical Presence and TPM Memory Clear + // Region Offset to be fixed at runtime + // + OperationRegion (TNVS, SystemMemory, 0xFFFF0000, 0x1E) + Field (TNVS, AnyAcc, NoLock, Preserve) + { + PPIN, 8, // Software SMI for Physical Presence Interface + PPIP, 32, // Used for save physical presence paramter + PPRP, 32, // Physical Presence request operation response + PPRQ, 32, // Physical Presence request operation + LPPR, 32, // Last Physical Presence request operation + FRET, 32, // Physical Presence function return code + MCIN, 8, // Software SMI for Memory Clear Interface + MCIP, 32, // Used for save the Mor paramter + MORD, 32 // Memory Overwrite Request Data + } + + Method (PTS, 1, Serialized) + { + // + // Detect Sx state for MOR, only S4, S5 need to handle + // + If (LAnd (LLess (Arg0, 6), LGreater (Arg0, 3))) + { + // + // Bit4 -- DisableAutoDetect. 0 -- Firmware MAY autodetect. + // + If (LNot (And (MORD, 0x10))) + { + // + // Triggle the SMI through ACPI _PTS method. + // + Store (0x02, MCIP) + + // + // Triggle the SMI interrupt + // + Store (MCIN, IOB2) + } + } + Return (0) + } + + Method (_STA, 0) + { + if (LEqual (ACC0, 0xff)) + { + Return (0) + } + Return (0x0f) + } + + // + // TCG Hardware Information + // + Method (HINF, 3, Serialized, 0, {BuffObj, PkgObj}, {IntObj, IntObj, PkgObj}) + { + // + // Switch by function index + // + Switch (ToInteger(Arg1)) + { + Case (0) + { + // + // Standard query + // + Return (Buffer () {0x03}) + } + Case (1) + { + // + // Return failure if no TPM present + // + Name(TPMV, Package () {0x01, Package () {ToBCD (1), ToBCD (20)}}) + if (LEqual (_STA (), 0x00)) + { + Return (Package () {0x00}) + } + + // + // Return TPM version + // + Return (TPMV) + } + Default {BreakPoint} + } + Return (Buffer () {0}) + } + + Name(TPM2, Package (0x02){ + Zero, + Zero + }) + + Name(TPM3, Package (0x03){ + Zero, + Zero, + Zero + }) + + // + // TCG Physical Presence Interface + // + Method (TPPI, 3, Serialized, 0, {BuffObj, PkgObj, IntObj, StrObj}, {IntObj, IntObj, PkgObj}) + { + // + // Switch by function index + // + Switch (ToInteger(Arg1)) + { + Case (0) + { + // + // Standard query, supports function 1-8 + // + Return (Buffer () {0xFF, 0x01}) + } + Case (1) + { + // + // a) Get Physical Presence Interface Version + // + Return ("1.2") + } + Case (2) + { + // + // b) Submit TPM Operation Request to Pre-OS Environment + // + + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + Store (0x02, PPIP) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + Return (FRET) + + + } + Case (3) + { + // + // c) Get Pending TPM Operation Requested By the OS + // + + Store (PPRQ, Index (TPM2, 0x01)) + Return (TPM2) + } + Case (4) + { + // + // d) Get Platform-Specific Action to Transition to Pre-OS Environment + // + Return (2) + } + Case (5) + { + // + // e) Return TPM Operation Response to OS Environment + // + Store (0x05, PPIP) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + + Store (LPPR, Index (TPM3, 0x01)) + Store (PPRP, Index (TPM3, 0x02)) + + Return (TPM3) + } + Case (6) + { + + // + // f) Submit preferred user language (Not implemented) + // + + Return (3) + + } + Case (7) + { + // + // g) Submit TPM Operation Request to Pre-OS Environment 2 + // + Store (7, PPIP) + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + Return (FRET) + } + Case (8) + { + // + // e) Get User Confirmation Status for Operation + // + Store (8, PPIP) + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + + Return (FRET) + } + + Default {BreakPoint} + } + Return (1) + } + + Method (TMCI, 3, Serialized, 0, IntObj, {IntObj, IntObj, PkgObj}) + { + // + // Switch by function index + // + Switch (ToInteger (Arg1)) + { + Case (0) + { + // + // Standard query, supports function 1-1 + // + Return (Buffer () {0x03}) + } + Case (1) + { + // + // Save the Operation Value of the Request to MORD (reserved memory) + // + Store (DerefOf (Index (Arg2, 0x00)), MORD) + + // + // Triggle the SMI through ACPI _DSM method. + // + Store (0x01, MCIP) + + // + // Triggle the SMI interrupt + // + Store (MCIN, IOB2) + Return (0) + } + Default {BreakPoint} + } + Return (1) + } + + Method (_DSM, 4, Serialized, 0, UnknownObj, {BuffObj, IntObj, IntObj, PkgObj}) + { + + // + // TCG Hardware Information + // + If(LEqual(Arg0, ToUUID ("cf8e16a5-c1e8-4e25-b712-4f54a96702c8"))) + { + Return (HINF (Arg1, Arg2, Arg3)) + } + + // + // TCG Physical Presence Interface + // + If(LEqual(Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653"))) + { + Return (TPPI (Arg1, Arg2, Arg3)) + } + + // + // TCG Memory Clear Interface + // + If(LEqual(Arg0, ToUUID ("376054ed-cc13-4675-901c-4756d7f2d45d"))) + { + Return (TMCI (Arg1, Arg2, Arg3)) + } + + Return (Buffer () {0}) + } + } + } +} diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c new file mode 100644 index 0000000000..ad1521040c --- /dev/null +++ b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c @@ -0,0 +1,1422 @@ +/** @file + Password Credential Provider driver implementation. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PwdCredentialProvider.h" + +CREDENTIAL_TABLE *mPwdTable = NULL; +PWD_PROVIDER_CALLBACK_INFO *mCallbackInfo = NULL; +PASSWORD_CREDENTIAL_INFO *mPwdInfoHandle = NULL; + +// +// Used for save password credential and form browser. +// Also used as provider identifier. +// +EFI_GUID mPwdCredentialGuid = PWD_CREDENTIAL_PROVIDER_GUID; + +HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + { 0xeba7fc2b, 0xa465, 0x4d96, { 0x85, 0xa9, 0xd2, 0xf6, 0x64, 0xdf, 0x9b, 0x45 } } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +EFI_USER_CREDENTIAL_PROTOCOL gPwdCredentialProviderDriver = { + PWD_CREDENTIAL_PROVIDER_GUID, + EFI_USER_CREDENTIAL_CLASS_PASSWORD, + CredentialEnroll, + CredentialForm, + CredentialTile, + CredentialTitle, + CredentialUser, + CredentialSelect, + CredentialDeselect, + CredentialDefault, + CredentialGetInfo, + CredentialGetNextInfo +}; + + +/** + Get string by string id from HII Interface. + + + @param[in] Id String ID to get the string from. + + @retval CHAR16 * String from ID. + @retval NULL If error occurs. + +**/ +CHAR16 * +GetStringById ( + IN EFI_STRING_ID Id + ) +{ + // + // Get the current string for the current Language. + // + return HiiGetString (mCallbackInfo->HiiHandle, Id, NULL); +} + + +/** + Expand password table size. + +**/ +VOID +ExpandTableSize ( + VOID + ) +{ + CREDENTIAL_TABLE *NewTable; + UINTN Count; + + Count = mPwdTable->MaxCount + PASSWORD_TABLE_INC; + // + // Create new credential table. + // + NewTable = (CREDENTIAL_TABLE *) AllocateZeroPool ( + sizeof (CREDENTIAL_TABLE) + + (Count - 1) * sizeof (PASSWORD_INFO) + ); + ASSERT (NewTable != NULL); + + NewTable->MaxCount = Count; + NewTable->Count = mPwdTable->Count; + NewTable->ValidIndex = mPwdTable->ValidIndex; + // + // Copy old entries + // + CopyMem ( + &NewTable->UserInfo, + &mPwdTable->UserInfo, + mPwdTable->Count * sizeof (PASSWORD_INFO) + ); + FreePool (mPwdTable); + mPwdTable = NewTable; +} + + +/** + Add or delete info in table, and sync with NV variable. + + @param[in] Index The index of the password in table. The index begin from 1. + If index is found in table, delete the info, else add the + into to table. + @param[in] Info The new password info to add into table. + + @retval EFI_INVALID_PARAMETER Info is NULL when save the info. + @retval EFI_SUCCESS Modify the table successfully. + @retval Others Failed to modify the table. + +**/ +EFI_STATUS +ModifyTable ( + IN UINTN Index, + IN PASSWORD_INFO * Info OPTIONAL + ) +{ + EFI_STATUS Status; + + if (Index < mPwdTable->Count) { + // + // Delete the specified entry. + // + mPwdTable->Count--; + if (Index != mPwdTable->Count) { + CopyMem ( + &mPwdTable->UserInfo[Index], + &mPwdTable->UserInfo[mPwdTable->Count], + sizeof (PASSWORD_INFO) + ); + } + } else { + // + // Add a new entry. + // + if (Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mPwdTable->Count >= mPwdTable->MaxCount) { + ExpandTableSize (); + } + + CopyMem ( + &mPwdTable->UserInfo[mPwdTable->Count], + Info, + sizeof (PASSWORD_INFO) + ); + mPwdTable->Count++; + } + + // + // Save the credential table. + // + Status = gRT->SetVariable ( + L"PwdCredential", + &mPwdCredentialGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + mPwdTable->Count * sizeof (PASSWORD_INFO), + &mPwdTable->UserInfo + ); + return Status; +} + + +/** + Create a password table. + + @retval EFI_SUCCESS Create a password table successfully. + @retval Others Failed to create a password. + +**/ +EFI_STATUS +InitCredentialTable ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 *Var; + UINTN VarSize; + + // + // Get Password credential data from NV variable. + // + VarSize = 0; + Var = NULL; + Status = gRT->GetVariable ( + L"PwdCredential", + &mPwdCredentialGuid, + NULL, + &VarSize, + Var + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Var = AllocateZeroPool (VarSize); + if (Var == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = gRT->GetVariable ( + L"PwdCredential", + &mPwdCredentialGuid, + NULL, + &VarSize, + Var + ); + } + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + return Status; + } + + // + // Create the password credential table. + // + mPwdTable = AllocateZeroPool ( + sizeof (CREDENTIAL_TABLE) - sizeof (PASSWORD_INFO) + + PASSWORD_TABLE_INC * sizeof (PASSWORD_INFO) + + VarSize + ); + if (mPwdTable == NULL) { + FreePool (Var); + return EFI_OUT_OF_RESOURCES; + } + + mPwdTable->Count = VarSize / sizeof (PASSWORD_INFO); + mPwdTable->MaxCount = mPwdTable->Count + PASSWORD_TABLE_INC; + mPwdTable->ValidIndex = 0; + if (Var != NULL) { + CopyMem (mPwdTable->UserInfo, Var, VarSize); + FreePool (Var); + } + return EFI_SUCCESS; +} + + +/** + Hash the password to get credential. + + @param[in] Password Points to the input password. + @param[in] PasswordSize The size of password, in bytes. + @param[out] Credential Points to the hashed result. + + @retval TRUE Hash the password successfully. + @retval FALSE Failed to hash the password. + +**/ +BOOLEAN +GenerateCredential ( + IN CHAR16 *Password, + IN UINTN PasswordSize, + OUT UINT8 *Credential + ) +{ + BOOLEAN Status; + UINTN HashSize; + VOID *Hash; + + HashSize = Sha1GetContextSize (); + Hash = AllocatePool (HashSize); + ASSERT (Hash != NULL); + + Status = Sha1Init (Hash); + if (!Status) { + goto Done; + } + + Status = Sha1Update (Hash, Password, PasswordSize); + if (!Status) { + goto Done; + } + + Status = Sha1Final (Hash, Credential); + +Done: + FreePool (Hash); + return Status; +} + + +/** + Get password from user input. + + @param[in] FirstPwd If True, prompt to input the first password. + If False, prompt to input password again. + @param[out] Credential Points to the input password. + +**/ +VOID +GetPassword ( + IN BOOLEAN FirstPwd, + OUT CHAR8 *Credential + ) +{ + EFI_INPUT_KEY Key; + CHAR16 PasswordMask[CREDENTIAL_LEN + 1]; + CHAR16 Password[CREDENTIAL_LEN]; + UINTN PasswordLen; + CHAR16 *QuestionStr; + CHAR16 *LineStr; + + PasswordLen = 0; + while (TRUE) { + PasswordMask[PasswordLen] = L'_'; + PasswordMask[PasswordLen + 1] = L'\0'; + LineStr = GetStringById (STRING_TOKEN (STR_DRAW_A_LINE)); + if (FirstPwd) { + QuestionStr = GetStringById (STRING_TOKEN (STR_INPUT_PASSWORD)); + } else { + QuestionStr = GetStringById (STRING_TOKEN (STR_INPUT_PASSWORD_AGAIN)); + } + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + QuestionStr, + LineStr, + PasswordMask, + NULL + ); + FreePool (QuestionStr); + FreePool (LineStr); + + // + // Check key stroke + // + if (Key.ScanCode == SCAN_NULL) { + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + break; + } else if (Key.UnicodeChar == CHAR_BACKSPACE) { + if (PasswordLen > 0) { + PasswordLen--; + } + } else if ((Key.UnicodeChar == CHAR_NULL) || + (Key.UnicodeChar == CHAR_TAB) || + (Key.UnicodeChar == CHAR_LINEFEED)) { + continue; + } else { + Password[PasswordLen] = Key.UnicodeChar; + PasswordMask[PasswordLen] = L'*'; + PasswordLen++; + if (PasswordLen == CREDENTIAL_LEN) { + break; + } + } + } + } + + PasswordLen = PasswordLen * sizeof (CHAR16); + GenerateCredential (Password, PasswordLen, (UINT8 *)Credential); +} + +/** + Check whether the password can be found on this provider. + + @param[in] Password The password to be found. + + @retval EFI_SUCCESS Found password sucessfully. + @retval EFI_NOT_FOUND Fail to find the password. + +**/ +EFI_STATUS +CheckPassword ( + IN CHAR8 *Password + ) +{ + UINTN Index; + CHAR8 *Pwd; + + // + // Check password credential. + // + mPwdTable->ValidIndex = 0; + for (Index = 0; Index < mPwdTable->Count; Index++) { + Pwd = mPwdTable->UserInfo[Index].Password; + if (CompareMem (Pwd, Password, CREDENTIAL_LEN) == 0) { + mPwdTable->ValidIndex = Index + 1; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +/** + Find a user infomation record by the information record type. + + This function searches all user information records of User from beginning + until either the information is found, or there are no more user infomation + records. A match occurs when a Info.InfoType field matches the user information + record type. + + @param[in] User Points to the user profile record to search. + @param[in] InfoType The infomation type to be searched. + @param[out] Info Points to the user info found, the caller is responsible + to free. + + @retval EFI_SUCCESS Find the user information successfully. + @retval Others Fail to find the user information. + +**/ +EFI_STATUS +FindUserInfoByType ( + IN EFI_USER_PROFILE_HANDLE User, + IN UINT8 InfoType, + OUT EFI_USER_INFO **Info + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *UserInfo; + UINTN UserInfoSize; + EFI_USER_INFO_HANDLE UserInfoHandle; + EFI_USER_MANAGER_PROTOCOL *UserManager; + + // + // Find user information by information type. + // + if (Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->LocateProtocol ( + &gEfiUserManagerProtocolGuid, + NULL, + (VOID **) &UserManager + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Get each user information. + // + + UserInfoHandle = NULL; + UserInfo = NULL; + UserInfoSize = 0; + while (TRUE) { + Status = UserManager->GetNextInfo (UserManager, User, &UserInfoHandle); + if (EFI_ERROR (Status)) { + break; + } + // + // Get information. + // + Status = UserManager->GetInfo ( + UserManager, + User, + UserInfoHandle, + UserInfo, + &UserInfoSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + if (UserInfo != NULL) { + FreePool (UserInfo); + } + UserInfo = AllocateZeroPool (UserInfoSize); + if (UserInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = UserManager->GetInfo ( + UserManager, + User, + UserInfoHandle, + UserInfo, + &UserInfoSize + ); + } + if (EFI_ERROR (Status)) { + break; + } + + ASSERT (UserInfo != NULL); + if (UserInfo->InfoType == InfoType) { + *Info = UserInfo; + return EFI_SUCCESS; + } + } + + if (UserInfo != NULL) { + FreePool (UserInfo); + } + return Status; +} + + +/** + This function processes the results of changes in configuration. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original + exporting driver. + @param ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +CredentialDriverCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + CHAR8 Password[CREDENTIAL_LEN]; + CHAR16 *PromptStr; + + if (Action == EFI_BROWSER_ACTION_CHANGING) { + if (QuestionId == KEY_GET_PASSWORD) { + // + // Get and check password. + // + GetPassword (TRUE, Password); + Status = CheckPassword (Password); + if (EFI_ERROR (Status)) { + PromptStr = GetStringById (STRING_TOKEN (STR_PASSWORD_INCORRECT)); + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"", + PromptStr, + L"", + NULL + ); + FreePool (PromptStr); + return Status; + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + } + return EFI_SUCCESS; + } + + // + // All other action return unsupported. + // + return EFI_UNSUPPORTED; +} + + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in format. + @param Progress On return, points to a character in the Request string. + Points to the string's null terminator if request was successful. + Points to the most recent '&' before the first failing name/value + pair (or the beginning of the string if the failure is in the + first name/value pair) if the request was not successful. + @param Results A null-terminated Unicode string in format which + has all values filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +FakeExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + *Progress = Request; + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration A null-terminated Unicode string in format. + @param Progress A pointer to a string filled in with the offset of the most + recent '&' before the first failing name/value pair (or the + beginning of the string if the failure is in the first + name/value pair) or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +FakeRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_NOT_FOUND; +} + +/** + This function initialize the data mainly used in form browser. + + @retval EFI_SUCCESS Initialize form data successfully. + @retval Others Fail to Initialize form data. + +**/ +EFI_STATUS +InitFormBrowser ( + VOID + ) +{ + EFI_STATUS Status; + PWD_PROVIDER_CALLBACK_INFO *CallbackInfo; + + // + // Initialize driver private data. + // + CallbackInfo = AllocateZeroPool (sizeof (PWD_PROVIDER_CALLBACK_INFO)); + if (CallbackInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CallbackInfo->Signature = PWD_PROVIDER_SIGNATURE; + CallbackInfo->ConfigAccess.ExtractConfig = FakeExtractConfig; + CallbackInfo->ConfigAccess.RouteConfig = FakeRouteConfig; + CallbackInfo->ConfigAccess.Callback = CredentialDriverCallback; + CallbackInfo->DriverHandle = NULL; + + // + // Install Device Path Protocol and Config Access protocol to driver handle. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &CallbackInfo->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &CallbackInfo->ConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish HII data. + // + CallbackInfo->HiiHandle = HiiAddPackages ( + &mPwdCredentialGuid, + CallbackInfo->DriverHandle, + PwdCredentialProviderStrings, + PwdCredentialProviderVfrBin, + NULL + ); + if (CallbackInfo->HiiHandle == NULL) { + return EFI_OUT_OF_RESOURCES; + } + mCallbackInfo = CallbackInfo; + + return Status; +} + + +/** + Enroll a user on a credential provider. + + This function enrolls and deletes a user profile using this credential provider. + If a user profile is successfully enrolled, it calls the User Manager Protocol + function Notify() to notify the user manager driver that credential information + has changed. If an enrolled user does exist, delete the user on the credential + provider. + + @param[in] This Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] User The user profile to enroll. + + @retval EFI_SUCCESS User profile was successfully enrolled. + @retval EFI_ACCESS_DENIED Current user profile does not permit enrollment on the + user profile handle. Either the user profile cannot enroll + on any user profile or cannot enroll on a user profile + other than the current user profile. + @retval EFI_UNSUPPORTED This credential provider does not support enrollment in + the pre-OS. + @retval EFI_DEVICE_ERROR The new credential could not be created because of a device + error. + @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle. + +**/ +EFI_STATUS +EFIAPI +CredentialEnroll ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User + ) +{ + EFI_STATUS Status; + UINTN Index; + PASSWORD_INFO PwdInfo; + EFI_USER_INFO *UserInfo; + CHAR8 Password[CREDENTIAL_LEN]; + EFI_INPUT_KEY Key; + EFI_USER_MANAGER_PROTOCOL *UserManager; + UINT8 *UserId; + UINT8 *NewUserId; + CHAR16 *QuestionStr; + CHAR16 *PromptStr; + + if ((This == NULL) || (User == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->LocateProtocol ( + &gEfiUserManagerProtocolGuid, + NULL, + (VOID **) &UserManager + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Get User Identifier. + // + UserInfo = NULL; + Status = FindUserInfoByType ( + User, + EFI_USER_INFO_IDENTIFIER_RECORD, + &UserInfo + ); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + // + // If User exists in mPwdTable, delete User. + // + for (Index = 0; Index < mPwdTable->Count; Index++) { + UserId = (UINT8 *) &mPwdTable->UserInfo[Index].UserId; + NewUserId = (UINT8 *) (UserInfo + 1); + if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) { + // + // Delete the existing password. + // + FreePool (UserInfo); + return ModifyTable (Index, NULL); + } + } + + // + // The User doesn't exist in mPwdTable; Enroll the new User. + // + while (TRUE) { + // + // Input password. + // + GetPassword (TRUE, PwdInfo.Password); + + // + // Input password again. + // + GetPassword (FALSE, Password); + + // + // Compare the two password consistency. + // + if (CompareMem (PwdInfo.Password, Password, CREDENTIAL_LEN) == 0) { + break; + } + + QuestionStr = GetStringById (STRING_TOKEN (STR_PASSWORD_MISMATCH)); + PromptStr = GetStringById (STRING_TOKEN (STR_INPUT_PASSWORD_AGAIN)); + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + QuestionStr, + L"", + PromptStr, + NULL + ); + FreePool (QuestionStr); + FreePool (PromptStr); + } + + CopyMem ( + PwdInfo.UserId, + (UINT8 *) (UserInfo + 1), + sizeof (EFI_USER_INFO_IDENTIFIER) + ); + FreePool (UserInfo); + + // + // Save the new added entry. + // + Status = ModifyTable (mPwdTable->Count, &PwdInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Notify the user manager driver that credential information has changed. + // + UserManager->Notify (UserManager, mCallbackInfo->DriverHandle); + + return EFI_SUCCESS; +} + + +/** + Returns the user interface information used during user identification. + + This function returns information about the form used when interacting with the + user during user identification. The form is the first enabled form in the form-set + class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If + the user credential provider does not require a form to identify the user, then this + function should return EFI_NOT_FOUND. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] Hii On return, holds the HII database handle. + @param[out] FormSetId On return, holds the identifier of the form set which contains + the form used during user identification. + @param[out] FormId On return, holds the identifier of the form used during user + identification. + + @retval EFI_SUCCESS Form returned successfully. + @retval EFI_NOT_FOUND Form not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or FormSetId is NULL or FormId is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialForm ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_GUID *FormSetId, + OUT EFI_FORM_ID *FormId + ) +{ + if ((This == NULL) || (Hii == NULL) || + (FormSetId == NULL) || (FormId == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *Hii = mCallbackInfo->HiiHandle; + *FormId = FORMID_GET_PASSWORD_FORM; + CopyGuid (FormSetId, &mPwdCredentialGuid); + + return EFI_SUCCESS; +} + + +/** + Returns bitmap used to describe the credential provider type. + + This optional function returns a bitmap that is less than or equal to the number + of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND + is returned. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in, out] Width On entry, points to the desired bitmap width. If NULL then no + bitmap information will be returned. On exit, points to the + width of the bitmap returned. + @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no + bitmap information will be returned. On exit, points to the + height of the bitmap returned + @param[out] Hii On return, holds the HII database handle. + @param[out] Image On return, holds the HII image identifier. + + @retval EFI_SUCCESS Image identifier returned successfully. + @retval EFI_NOT_FOUND Image identifier not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or Image is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialTile ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN OUT UINTN *Width, + IN OUT UINTN *Height, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_IMAGE_ID *Image + ) +{ + if ((This == NULL) || (Hii == NULL) || (Image == NULL)) { + return EFI_INVALID_PARAMETER; + } + return EFI_NOT_FOUND; +} + + +/** + Returns string used to describe the credential provider type. + + This function returns a string which describes the credential provider. If no + such string exists, then EFI_NOT_FOUND is returned. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] Hii On return, holds the HII database handle. + @param[out] String On return, holds the HII string identifier. + + @retval EFI_SUCCESS String identifier returned successfully. + @retval EFI_NOT_FOUND String identifier not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or String is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialTitle ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_STRING_ID *String + ) +{ + if ((This == NULL) || (Hii == NULL) || (String == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Set Hii handle and String ID. + // + *Hii = mCallbackInfo->HiiHandle; + *String = STRING_TOKEN (STR_CREDENTIAL_TITLE); + + return EFI_SUCCESS; +} + + +/** + Return the user identifier associated with the currently authenticated user. + + This function returns the user identifier of the user authenticated by this credential + provider. This function is called after the credential-related information has been + submitted on a form, OR after a call to Default() has returned that this credential is + ready to log on. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] User The user profile handle of the user profile currently being + considered by the user identity manager. If NULL, then no user + profile is currently under consideration. + @param[out] Identifier On return, points to the user identifier. + + @retval EFI_SUCCESS User identifier returned successfully. + @retval EFI_NOT_READY No user identifier can be returned. + @retval EFI_ACCESS_DENIED The user has been locked out of this user credential. + @retval EFI_INVALID_PARAMETER This is NULL, or Identifier is NULL. + @retval EFI_NOT_FOUND User is not NULL, and the specified user handle can't be + found in user profile database + +**/ +EFI_STATUS +EFIAPI +CredentialUser ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + OUT EFI_USER_INFO_IDENTIFIER *Identifier + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_USER_INFO *UserInfo; + UINT8 *UserId; + UINT8 *NewUserId; + CHAR8 *Pwd; + CHAR8 *NewPwd; + + if ((This == NULL) || (Identifier == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (mPwdTable->ValidIndex == 0) { + // + // No password input, or the input password doesn't match + // anyone in PwdTable. + // + return EFI_NOT_READY; + } + + if (User == NULL) { + // + // Return the user ID whose password matches the input password. + // + CopyMem ( + Identifier, + &mPwdTable->UserInfo[mPwdTable->ValidIndex - 1].UserId, + sizeof (EFI_USER_INFO_IDENTIFIER) + ); + return EFI_SUCCESS; + } + + // + // Get the User's ID. + // + Status = FindUserInfoByType ( + User, + EFI_USER_INFO_IDENTIFIER_RECORD, + &UserInfo + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Check whether the input password matches one in PwdTable. + // + for (Index = 0; Index < mPwdTable->Count; Index++) { + UserId = (UINT8 *) &mPwdTable->UserInfo[Index].UserId; + NewUserId = (UINT8 *) (UserInfo + 1); + if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) { + Pwd = mPwdTable->UserInfo[Index].Password; + NewPwd = mPwdTable->UserInfo[mPwdTable->ValidIndex - 1].Password; + if (CompareMem (Pwd, NewPwd, CREDENTIAL_LEN) == 0) { + CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER)); + FreePool (UserInfo); + return EFI_SUCCESS; + } + } + } + + // + // The User's password doesn't match the input password. + // Return the user ID whose password matches the input password. + // + CopyMem ( + Identifier, + &mPwdTable->UserInfo[mPwdTable->ValidIndex - 1].UserId, + sizeof (EFI_USER_INFO_IDENTIFIER) + ); + FreePool (UserInfo); + return EFI_SUCCESS; +} + + +/** + Indicate that user interface interaction has begun for the specified credential. + + This function is called when a credential provider is selected by the user. If + AutoLogon returns FALSE, then the user interface will be constructed by the User + Identity Manager. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] AutoLogon On return, points to the credential provider's capabilities + after the credential provider has been selected by the user. + + @retval EFI_SUCCESS Credential provider successfully selected. + @retval EFI_INVALID_PARAMETER AutoLogon is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialSelect ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon + ) +{ + if ((This == NULL) || (AutoLogon == NULL)) { + return EFI_INVALID_PARAMETER; + } + *AutoLogon = 0; + + return EFI_SUCCESS; +} + + +/** + Indicate that user interface interaction has ended for the specified credential. + + This function is called when a credential provider is deselected by the user. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + + @retval EFI_SUCCESS Credential provider successfully deselected. + +**/ +EFI_STATUS +EFIAPI +CredentialDeselect ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This + ) +{ + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + + +/** + Return the default logon behavior for this user credential. + + This function reports the default login behavior regarding this credential provider. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] AutoLogon On return, holds whether the credential provider should be used + by default to automatically log on the user. + + @retval EFI_SUCCESS Default information successfully returned. + @retval EFI_INVALID_PARAMETER AutoLogon is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialDefault ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon + ) +{ + if ((This == NULL) || (AutoLogon == NULL)) { + return EFI_INVALID_PARAMETER; + } + *AutoLogon = 0; + + return EFI_SUCCESS; +} + + +/** + Return information attached to the credential provider. + + This function returns user information. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] UserInfo Handle of the user information data record. + @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On + exit, holds the user information. If the buffer is too small + to hold the information, then EFI_BUFFER_TOO_SMALL is returned + and InfoSize is updated to contain the number of bytes actually + required. + @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the + size of the user information. + + @retval EFI_SUCCESS Information returned successfully. + @retval EFI_BUFFER_TOO_SMALL The size specified by InfoSize is too small to hold all of the + user information. The size required is returned in *InfoSize. + @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL. + @retval EFI_NOT_FOUND The specified UserInfo does not refer to a valid user info handle. + +**/ +EFI_STATUS +EFIAPI +CredentialGetInfo ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_INFO_HANDLE UserInfo, + OUT EFI_USER_INFO *Info, + IN OUT UINTN *InfoSize + ) +{ + EFI_USER_INFO *CredentialInfo; + UINTN Index; + + if ((This == NULL) || (InfoSize == NULL) || (Info == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((UserInfo == NULL) || (mPwdInfoHandle == NULL)) { + return EFI_NOT_FOUND; + } + + // + // Find information handle in credential info table. + // + for (Index = 0; Index < mPwdInfoHandle->Count; Index++) { + CredentialInfo = mPwdInfoHandle->Info[Index]; + if (UserInfo == (EFI_USER_INFO_HANDLE)CredentialInfo) { + // + // The handle is found, copy the user info. + // + if (CredentialInfo->InfoSize > *InfoSize) { + *InfoSize = CredentialInfo->InfoSize; + return EFI_BUFFER_TOO_SMALL; + } + CopyMem (Info, CredentialInfo, CredentialInfo->InfoSize); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +/** + Enumerate all of the user informations on the credential provider. + + This function returns the next user information record. To retrieve the first user + information record handle, point UserInfo at a NULL. Each subsequent call will retrieve + another user information record handle until there are no more, at which point UserInfo + will point to NULL. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in, out] UserInfo On entry, points to the previous user information handle or NULL + to start enumeration. On exit, points to the next user information + handle or NULL if there is no more user information. + + @retval EFI_SUCCESS User information returned. + @retval EFI_NOT_FOUND No more user information found. + @retval EFI_INVALID_PARAMETER UserInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialGetNextInfo ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN OUT EFI_USER_INFO_HANDLE *UserInfo + ) +{ + EFI_USER_INFO *Info; + CHAR16 *ProvNameStr; + UINTN InfoLen; + UINTN Index; + UINTN ProvStrLen; + + if ((This == NULL) || (UserInfo == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (mPwdInfoHandle == NULL) { + // + // Initilized user info table. There are 4 user info records in the table. + // + InfoLen = sizeof (PASSWORD_CREDENTIAL_INFO) + (4 - 1) * sizeof (EFI_USER_INFO *); + mPwdInfoHandle = AllocateZeroPool (InfoLen); + if (mPwdInfoHandle == NULL) { + *UserInfo = NULL; + return EFI_NOT_FOUND; + } + + // + // The first information, Credential Provider info. + // + InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID); + Info = AllocateZeroPool (InfoLen); + ASSERT (Info != NULL); + + Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD; + Info->InfoSize = (UINT32) InfoLen; + Info->InfoAttribs = EFI_USER_INFO_PROTECTED; + CopyGuid (&Info->Credential, &mPwdCredentialGuid); + CopyGuid ((EFI_GUID *)(Info + 1), &mPwdCredentialGuid); + + mPwdInfoHandle->Info[0] = Info; + mPwdInfoHandle->Count++; + + // + // The second information, Credential Provider name info. + // + ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_NAME)); + ProvStrLen = StrSize (ProvNameStr); + InfoLen = sizeof (EFI_USER_INFO) + ProvStrLen; + Info = AllocateZeroPool (InfoLen); + ASSERT (Info != NULL); + + Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD; + Info->InfoSize = (UINT32) InfoLen; + Info->InfoAttribs = EFI_USER_INFO_PROTECTED; + CopyGuid (&Info->Credential, &mPwdCredentialGuid); + CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen); + FreePool (ProvNameStr); + + mPwdInfoHandle->Info[1] = Info; + mPwdInfoHandle->Count++; + + // + // The third information, Credential Provider type info. + // + InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID); + Info = AllocateZeroPool (InfoLen); + ASSERT (Info != NULL); + + Info->InfoType = EFI_USER_INFO_CREDENTIAL_TYPE_RECORD; + Info->InfoSize = (UINT32) InfoLen; + Info->InfoAttribs = EFI_USER_INFO_PROTECTED; + CopyGuid (&Info->Credential, &mPwdCredentialGuid); + CopyGuid ((EFI_GUID *)(Info + 1), &gEfiUserCredentialClassPasswordGuid); + + mPwdInfoHandle->Info[2] = Info; + mPwdInfoHandle->Count++; + + // + // The fourth information, Credential Provider type name info. + // + ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_TYPE_NAME)); + ProvStrLen = StrSize (ProvNameStr); + InfoLen = sizeof (EFI_USER_INFO) + ProvStrLen; + Info = AllocateZeroPool (InfoLen); + ASSERT (Info != NULL); + + Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD; + Info->InfoSize = (UINT32) InfoLen; + Info->InfoAttribs = EFI_USER_INFO_PROTECTED; + CopyGuid (&Info->Credential, &mPwdCredentialGuid); + CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen); + FreePool (ProvNameStr); + + mPwdInfoHandle->Info[3] = Info; + mPwdInfoHandle->Count++; + } + + if (*UserInfo == NULL) { + // + // Return the first info handle. + // + *UserInfo = (EFI_USER_INFO_HANDLE) mPwdInfoHandle->Info[0]; + return EFI_SUCCESS; + } + + // + // Find information handle in credential info table. + // + for (Index = 0; Index < mPwdInfoHandle->Count; Index++) { + Info = mPwdInfoHandle->Info[Index]; + if (*UserInfo == (EFI_USER_INFO_HANDLE)Info) { + // + // The handle is found, get the next one. + // + if (Index == mPwdInfoHandle->Count - 1) { + // + // Already last one. + // + *UserInfo = NULL; + return EFI_NOT_FOUND; + } + + Index++; + *UserInfo = (EFI_USER_INFO_HANDLE)mPwdInfoHandle->Info[Index]; + return EFI_SUCCESS; + } + } + + *UserInfo = NULL; + return EFI_NOT_FOUND; +} + + +/** + Main entry for this driver. + + @param ImageHandle Image handle this driver. + @param SystemTable Pointer to SystemTable. + + @retval EFI_SUCESS This function always complete successfully. + +**/ +EFI_STATUS +EFIAPI +PasswordProviderInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Init credential table. + // + Status = InitCredentialTable (); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Init Form Browser. + // + Status = InitFormBrowser (); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Install protocol interfaces for the password credential provider. + // + Status = gBS->InstallProtocolInterface ( + &mCallbackInfo->DriverHandle, + &gEfiUserCredentialProtocolGuid, + EFI_NATIVE_INTERFACE, + &gPwdCredentialProviderDriver + ); + return Status; +} diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h new file mode 100644 index 0000000000..9b5e7768ba --- /dev/null +++ b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h @@ -0,0 +1,354 @@ +/** @file + Password Credential Provider driver header file. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PASSWORD_CREDENTIAL_PROVIDER_H_ +#define _PASSWORD_CREDENTIAL_PROVIDER_H_ + +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PwdCredentialProviderData.h" + +extern UINT8 PwdCredentialProviderStrings[]; +extern UINT8 PwdCredentialProviderVfrBin[]; + +#define PASSWORD_TABLE_INC 16 +#define CREDENTIAL_LEN 20 + +// +// Password credential information. +// +typedef struct { + EFI_USER_INFO_IDENTIFIER UserId; + CHAR8 Password[CREDENTIAL_LEN]; +} PASSWORD_INFO; + +// +// Password credential table. +// +typedef struct { + UINTN Count; + UINTN MaxCount; + UINTN ValidIndex; + PASSWORD_INFO UserInfo[1]; +} CREDENTIAL_TABLE; + +// +// The user information on the password provider. +// +typedef struct { + UINTN Count; + EFI_USER_INFO *Info[1]; +} PASSWORD_CREDENTIAL_INFO; + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +#define PWD_PROVIDER_SIGNATURE SIGNATURE_32 ('P', 'W', 'D', 'P') + +typedef struct { + UINTN Signature; + EFI_HANDLE DriverHandle; + EFI_HII_HANDLE HiiHandle; + // + // Produced protocol. + // + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; +} PWD_PROVIDER_CALLBACK_INFO; + + +/** + Enroll a user on a credential provider. + + This function enrolls and deletes a user profile using this credential provider. + If a user profile is successfully enrolled, it calls the User Manager Protocol + function Notify() to notify the user manager driver that credential information + has changed. If an enrolled user does exist, delete the user on the credential + provider. + + @param[in] This Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] User The user profile to enroll. + + @retval EFI_SUCCESS User profile was successfully enrolled. + @retval EFI_ACCESS_DENIED Current user profile does not permit enrollment on the + user profile handle. Either the user profile cannot enroll + on any user profile or cannot enroll on a user profile + other than the current user profile. + @retval EFI_UNSUPPORTED This credential provider does not support enrollment in + the pre-OS. + @retval EFI_DEVICE_ERROR The new credential could not be created because of a device + error. + @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle. + +**/ +EFI_STATUS +EFIAPI +CredentialEnroll ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User + ); + +/** + Returns the user interface information used during user identification. + + This function returns information about the form used when interacting with the + user during user identification. The form is the first enabled form in the form-set + class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If + the user credential provider does not require a form to identify the user, then this + function should return EFI_NOT_FOUND. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] Hii On return, holds the HII database handle. + @param[out] FormSetId On return, holds the identifier of the form set which contains + the form used during user identification. + @param[out] FormId On return, holds the identifier of the form used during user + identification. + + @retval EFI_SUCCESS Form returned successfully. + @retval EFI_NOT_FOUND Form not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or FormSetId is NULL or FormId is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialForm ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_GUID *FormSetId, + OUT EFI_FORM_ID *FormId + ); + +/** + Returns bitmap used to describe the credential provider type. + + This optional function returns a bitmap which is less than or equal to the number + of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND + is returned. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in, out] Width On entry, points to the desired bitmap width. If NULL then no + bitmap information will be returned. On exit, points to the + width of the bitmap returned. + @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no + bitmap information will be returned. On exit, points to the + height of the bitmap returned + @param[out] Hii On return, holds the HII database handle. + @param[out] Image On return, holds the HII image identifier. + + @retval EFI_SUCCESS Image identifier returned successfully. + @retval EFI_NOT_FOUND Image identifier not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or Image is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialTile ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN OUT UINTN *Width, + IN OUT UINTN *Height, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_IMAGE_ID *Image + ); + +/** + Returns string used to describe the credential provider type. + + This function returns a string which describes the credential provider. If no + such string exists, then EFI_NOT_FOUND is returned. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] Hii On return, holds the HII database handle. + @param[out] String On return, holds the HII string identifier. + + @retval EFI_SUCCESS String identifier returned successfully. + @retval EFI_NOT_FOUND String identifier not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or String is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialTitle ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_STRING_ID *String + ); + +/** + Return the user identifier associated with the currently authenticated user. + + This function returns the user identifier of the user authenticated by this credential + provider. This function is called after the credential-related information has been + submitted on a form OR after a call to Default() has returned that this credential is + ready to log on. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] User The user profile handle of the user profile currently being + considered by the user identity manager. If NULL, then no user + profile is currently under consideration. + @param[out] Identifier On return, points to the user identifier. + + @retval EFI_SUCCESS User identifier returned successfully. + @retval EFI_NOT_READY No user identifier can be returned. + @retval EFI_ACCESS_DENIED The user has been locked out of this user credential. + @retval EFI_INVALID_PARAMETER This is NULL, or Identifier is NULL. + @retval EFI_NOT_FOUND User is not NULL, and the specified user handle can't be + found in user profile database + +**/ +EFI_STATUS +EFIAPI +CredentialUser ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + OUT EFI_USER_INFO_IDENTIFIER *Identifier + ); + +/** + Indicate that user interface interaction has begun for the specified credential. + + This function is called when a credential provider is selected by the user. If + AutoLogon returns FALSE, then the user interface will be constructed by the User + Identity Manager. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] AutoLogon On return, points to the credential provider's capabilities + after the credential provider has been selected by the user. + + @retval EFI_SUCCESS Credential provider successfully selected. + @retval EFI_INVALID_PARAMETER AutoLogon is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialSelect ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon + ); + +/** + Indicate that user interface interaction has ended for the specified credential. + + This function is called when a credential provider is deselected by the user. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + + @retval EFI_SUCCESS Credential provider successfully deselected. + +**/ +EFI_STATUS +EFIAPI +CredentialDeselect ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This + ); + +/** + Return the default logon behavior for this user credential. + + This function reports the default login behavior regarding this credential provider. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] AutoLogon On return, holds whether the credential provider should be used + by default to automatically log on the user. + + @retval EFI_SUCCESS Default information successfully returned. + @retval EFI_INVALID_PARAMETER AutoLogon is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialDefault ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon + ); + +/** + Return information attached to the credential provider. + + This function returns user information. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] UserInfo Handle of the user information data record. + @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On + exit, holds the user information. If the buffer is too small + to hold the information, then EFI_BUFFER_TOO_SMALL is returned + and InfoSize is updated to contain the number of bytes actually + required. + @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the + size of the user information. + + @retval EFI_SUCCESS Information returned successfully. + @retval EFI_BUFFER_TOO_SMALL The size specified by InfoSize is too small to hold all of the + user information. The size required is returned in *InfoSize. + @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL. + @retval EFI_NOT_FOUND The specified UserInfo does not refer to a valid user info handle. + +**/ +EFI_STATUS +EFIAPI +CredentialGetInfo ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_INFO_HANDLE UserInfo, + OUT EFI_USER_INFO *Info, + IN OUT UINTN *InfoSize + ); + + +/** + Enumerate all of the user informations on the credential provider. + + This function returns the next user information record. To retrieve the first user + information record handle, point UserInfo at a NULL. Each subsequent call will retrieve + another user information record handle until there are no more, at which point UserInfo + will point to NULL. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in, out] UserInfo On entry, points to the previous user information handle or NULL + to start enumeration. On exit, points to the next user information + handle or NULL if there is no more user information. + + @retval EFI_SUCCESS User information returned. + @retval EFI_NOT_FOUND No more user information found. + @retval EFI_INVALID_PARAMETER UserInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialGetNextInfo ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN OUT EFI_USER_INFO_HANDLE *UserInfo + ); + +#endif diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h new file mode 100644 index 0000000000..ffe0adea20 --- /dev/null +++ b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h @@ -0,0 +1,33 @@ +/** @file + Data structure used by the Password Credential Provider driver. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PWD_CREDENTIAL_PROVIDER_DATA_H_ +#define _PWD_CREDENTIAL_PROVIDER_DATA_H_ + +#define PWD_CREDENTIAL_PROVIDER_GUID \ + { \ + 0x78b9ec8b, 0xc000, 0x46c5, { 0xac, 0x93, 0x24, 0xa0, 0xc1, 0xbb, 0x0, 0xce } \ + } + +// +// Forms definition +// +#define FORMID_GET_PASSWORD_FORM 1 + +// +// Key defination +// +#define KEY_GET_PASSWORD 0x1000 + +#endif diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf new file mode 100644 index 0000000000..0ffc24e076 --- /dev/null +++ b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf @@ -0,0 +1,53 @@ +## @file +# Component description file for Password Credential Provider. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PwdCredentialProvider + FILE_GUID = D6C589EA-DD29-49ef-97F6-1A9FE19A04E0 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = PasswordProviderInit + +[Sources] + PwdCredentialProvider.c + PwdCredentialProvider.h + PwdCredentialProviderData.h + PwdCredentialProviderVfr.Vfr + PwdCredentialProviderStrings.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + MemoryAllocationLib + BaseMemoryLib + DebugLib + HiiLib + UefiLib + BaseCryptLib + +[Guids] + gEfiIfrTianoGuid ## CONSUMES ## Guid + gEfiUserCredentialClassPasswordGuid ## CONSUMES ## Guid + +[Protocols] + gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiHiiConfigAccessProtocolGuid + gEfiUserCredentialProtocolGuid + gEfiUserManagerProtocolGuid \ No newline at end of file diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..48573b6e8ee68adc8ecfd9da4b5710884e0190fb GIT binary patch literal 5128 zcmd6r+fNfw5XR>f6aR-5Uc_)w-!#SurC=k428!rYQ_8K0T(T`7|GfJ9=CEwLY?p0C z(`>ruKJ(2tbLO1w?_bOIiYKy9c5GeyVMq4dp3#nM*ZLOIcWx)N4jIvmbAEk(7u0(6 zA5)7d`*zBV$QstBzh^hze@IV-@grYDAC_BtJL$}6mSr^zla~!g>OYH~JWNF(q zN3^@FJ7TU-NMa&c>%@=v*upN_q)7|}j-;hWTb3SxFo_khADOrm@?%DVCxrJWvm!7K;u+>7 z!lE{OM#v27FYc@troOYONa@4;dt2sF3E+OTV zUmBfF`)pNkG>DIF+u*%ob=o!fi(pV?linH;v`4M#tnS$sWtDz$5G16G*NE6EGj?6_ zHZ?`6-m{dFE2*=TtKL>?!EN4WMDn&>S7iH)?>MF{`fJG3>TTD%LrbXDCv8pUYL4`U zS?kP|-tUxO7!hXet?HeYfWKzV6|gW4yR%>u!}+t<#p&4sWdt>w>-{7Q;RazG=a?c#uZ|Pb(mA zIU7xC@^A4oR>YWDeRRY?J20U_&vAry0$&BFpfkRw#4JJ7Pr{Wd7c#`F>gV zSgq&!V#e~HJp5TNY=A&HCTmAvIbUv3Z=TL9XQOnE$H*3YW7DHE$tzoAoyk0(hdRsD zbj4jjGk1TY4DVuPsD@|07Ns)fE*VhSZf!)Yh_^B}j3H;cjv1XW9RapzYvSeI-|iGpPlSI>jE(dxLRTJ_pKAIte#(c3|22;dI62Q&{x3K5KGLH(+&q@0HsD zlilN|%TL*SUpCqv`ercl|5d%{#!{5)TI}8pewtGTTN(fBdumk9(=GAD?^@?~=Xudt znU0OZmWL;MnwG_rcjHJA6xBwdEAq-3XUz&{jy%vJzsUpRWzke?9t+vid69eXWY2W% z%gJnbxT^Smki8SM+&>k+A?W^J;Z#cbFRqpGPAWmss;} +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "PwdCredentialProviderData.h" + +formset + guid = PWD_CREDENTIAL_PROVIDER_GUID, + title = STRING_TOKEN(STR_CREDENTIAL_TITLE), + help = STRING_TOKEN(STR_NULL_STRING), + classguid = PWD_CREDENTIAL_PROVIDER_GUID, + + form formid = FORMID_GET_PASSWORD_FORM, + title = STRING_TOKEN(STR_FORM_TITLE); + + text + help = STRING_TOKEN(STR_NULL_STRING), + text = STRING_TOKEN(STR_INPUT_PASSWORD), + text = STRING_TOKEN(STR_NULL_STRING), + flags = INTERACTIVE, + key = KEY_GET_PASSWORD; + + endform; + +endformset; \ No newline at end of file diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c new file mode 100644 index 0000000000..6c22bfb2bb --- /dev/null +++ b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c @@ -0,0 +1,1407 @@ +/** @file + Usb Credential Provider driver implemenetation. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UsbCredentialProvider.h" + +CREDENTIAL_TABLE *mUsbTable = NULL; +USB_PROVIDER_CALLBACK_INFO *mCallbackInfo = NULL; +USB_CREDENTIAL_INFO *mUsbInfoHandle = NULL; + +// +// Used for save password credential and form browser +// And used as provider identifier +// +EFI_GUID mUsbCredentialGuid = USB_CREDENTIAL_PROVIDER_GUID; + +HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + { 0x9463f883, 0x48f6, 0x4a7a, { 0x97, 0x2d, 0x9f, 0x8f, 0x38, 0xf2, 0xdd, 0x91 } } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +EFI_USER_CREDENTIAL_PROTOCOL gUsbCredentialProviderDriver = { + USB_CREDENTIAL_PROVIDER_GUID, + EFI_USER_CREDENTIAL_CLASS_SECURE_CARD, + CredentialEnroll, + CredentialForm, + CredentialTile, + CredentialTitle, + CredentialUser, + CredentialSelect, + CredentialDeselect, + CredentialDefault, + CredentialGetInfo, + CredentialGetNextInfo +}; + + +/** + Get string by string id from HII Interface. + + + @param[in] Id String ID to get the string from. + + @retval CHAR16 * String from ID. + @retval NULL If error occurs. + +**/ +CHAR16 * +GetStringById ( + IN EFI_STRING_ID Id + ) +{ + // + // Get the current string for the current Language + // + return HiiGetString (mCallbackInfo->HiiHandle, Id, NULL); +} + + +/** + Expand password table size. + +**/ +VOID +ExpandTableSize ( + VOID + ) +{ + CREDENTIAL_TABLE *NewTable; + UINTN Count; + + Count = mUsbTable->MaxCount + USB_TABLE_INC; + // + // Create new credential table. + // + NewTable = AllocateZeroPool ( + sizeof (CREDENTIAL_TABLE) - sizeof (USB_INFO) + + Count * sizeof (USB_INFO) + ); + ASSERT (NewTable != NULL); + + NewTable->MaxCount = Count; + NewTable->Count = mUsbTable->Count; + + // + // Copy old entries. + // + CopyMem ( + &NewTable->UserInfo, + &mUsbTable->UserInfo, + mUsbTable->Count * sizeof (USB_INFO) + ); + FreePool (mUsbTable); + mUsbTable = NewTable; +} + + +/** + Add or delete info in table, and sync with NV variable. + + @param[in] Index The index of the password in table. The index begin from 1. + If index is found in table, delete the info, else add the + into to table. + @param[in] Info The new password info to add into table. + + @retval EFI_INVALID_PARAMETER Info is NULL when save the info. + @retval EFI_SUCCESS Modify the table successfully. + @retval Others Failed to modify the table. + +**/ +EFI_STATUS +ModifyTable ( + IN UINTN Index, + IN USB_INFO * Info OPTIONAL + ) +{ + EFI_STATUS Status; + + if (Index < mUsbTable->Count) { + // + // Delete the specified entry + // + mUsbTable->Count--; + if (Index != mUsbTable->Count) { + CopyMem ( + &mUsbTable->UserInfo[Index], + &mUsbTable->UserInfo[mUsbTable->Count], + sizeof (USB_INFO) + ); + } + } else { + // + // Add a new entry + // + if (Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mUsbTable->Count >= mUsbTable->MaxCount) { + ExpandTableSize (); + } + + CopyMem ( + &mUsbTable->UserInfo[mUsbTable->Count], + Info, + sizeof (USB_INFO) + ); + mUsbTable->Count++; + } + + // + // Save the credential table. + // + Status = gRT->SetVariable ( + L"UsbCredential", + &mUsbCredentialGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + mUsbTable->Count * sizeof (USB_INFO), + &mUsbTable->UserInfo + ); + return Status; +} + + +/** + Create a credential table + + @retval EFI_SUCCESS Create a credential table successfully. + @retval Others Failed to create a password. + +**/ +EFI_STATUS +InitCredentialTable ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 *Var; + UINTN VarSize; + + // + // Get Usb credential data from NV variable. + // + VarSize = 0; + Var = NULL; + Status = gRT->GetVariable ( + L"UsbCredential", + &mUsbCredentialGuid, + NULL, + &VarSize, + Var + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Var = AllocateZeroPool (VarSize); + if (Var == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = gRT->GetVariable ( + L"UsbCredential", + &mUsbCredentialGuid, + NULL, + &VarSize, + Var + ); + } + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + return Status; + } + + // + // Init Usb credential table. + // + mUsbTable = AllocateZeroPool ( + sizeof (CREDENTIAL_TABLE) - sizeof (USB_INFO) + + USB_TABLE_INC * sizeof (USB_INFO) + + VarSize + ); + if (mUsbTable == NULL) { + FreePool (Var); + return EFI_OUT_OF_RESOURCES; + } + + mUsbTable->Count = VarSize / sizeof (USB_INFO); + mUsbTable->MaxCount = mUsbTable->Count + USB_TABLE_INC; + if (Var != NULL) { + CopyMem (mUsbTable->UserInfo, Var, VarSize); + FreePool (Var); + } + return EFI_SUCCESS; +} + + +/** + Read the specified file by FileName in the Usb key and return the file size in BufferSize + and file content in Buffer. + Note: the caller is responsible to free the buffer memory. + + @param FileName File to read. + @param Buffer Returned with data read from the file. + @param BufferSize Size of the data buffer. + + @retval EFI_SUCCESS The command completed successfully. + @retval EFI_OUT_OF_RESOURCES Resource allocation failed. + @retval EFI_NOT_FOUND File not found. + @retval EFI_DEVICE_ERROR Device I/O error. + +**/ +EFI_STATUS +GetFileData ( + IN CHAR16 *FileName, + OUT VOID **Buffer, + OUT UINTN *BufferSize + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN HandleCount; + UINTN ScratchBufferSize; + EFI_HANDLE *HandleBuffer; + EFI_FILE *RootFs; + EFI_FILE *FileHandle; + EFI_FILE_INFO *FileInfo; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + + FileInfo = NULL; + FileHandle = NULL; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Can not Locate SimpleFileSystemProtocol\n")); + goto Done; + } + + // + // Find and open the file in removable media disk. + // + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo + ); + if (EFI_ERROR (Status)) { + continue; + } + + if (BlkIo->Media->RemovableMedia) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiSimpleFileSystemProtocolGuid, + (VOID **) &SimpleFileSystem + ); + if (EFI_ERROR (Status)) { + continue; + } + + Status = SimpleFileSystem->OpenVolume ( + SimpleFileSystem, + &RootFs + ); + if (EFI_ERROR (Status)) { + continue; + } + + Status = RootFs->Open ( + RootFs, + &FileHandle, + FileName, + EFI_FILE_MODE_READ, + 0 + ); + if (!EFI_ERROR (Status)) { + break; + } + } + } + + FreePool (HandleBuffer); + + if (Index >= HandleCount) { + DEBUG ((DEBUG_ERROR, "Can not found the token file!\n")); + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Figure out how big the file is. + // + ScratchBufferSize = 0; + Status = FileHandle->GetInfo ( + FileHandle, + &gEfiFileInfoGuid, + &ScratchBufferSize, + NULL + ); + if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) { + DEBUG ((DEBUG_ERROR, "Can not obtain file size info!\n")); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + FileInfo = AllocateZeroPool (ScratchBufferSize); + if (FileInfo == NULL) { + DEBUG ((DEBUG_ERROR, "Can not allocate enough memory for the token file!\n")); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = FileHandle->GetInfo ( + FileHandle, + &gEfiFileInfoGuid, + &ScratchBufferSize, + FileInfo + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Can not obtain file info from the token file!\n")); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + // + // Allocate a buffer for the file. + // + *BufferSize = (UINT32) FileInfo->FileSize; + *Buffer = AllocateZeroPool (*BufferSize); + if (*Buffer == NULL) { + DEBUG ((DEBUG_ERROR, "Can not allocate a buffer for the file!\n")); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Load file into the allocated memory. + // + Status = FileHandle->Read (FileHandle, BufferSize, *Buffer); + if (EFI_ERROR (Status)) { + FreePool (*Buffer); + DEBUG ((DEBUG_ERROR, "Can not read the token file!\n")); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + // + // Close file. + // + Status = FileHandle->Close (FileHandle); + if (EFI_ERROR (Status)) { + FreePool (*Buffer); + DEBUG ((DEBUG_ERROR, "Can not close the token file !\n")); + Status = EFI_DEVICE_ERROR; + } + +Done: + + if (FileInfo != NULL) { + FreePool (FileInfo); + } + + return Status; +} + + +/** + Hash the data to get credential. + + @param[in] Buffer Points to the data buffer + @param[in] BufferSize The size of data in buffer, in bytes. + @param[out] Credential Points to the hashed result + + @retval TRUE Hash the data successfully. + @retval FALSE Failed to hash the data. + +**/ +BOOLEAN +GenerateCredential ( + IN UINT8 *Buffer, + IN UINTN BufferSize, + OUT UINT8 *Credential + ) +{ + BOOLEAN Status; + UINTN HashSize; + VOID *Hash; + + HashSize = Sha1GetContextSize (); + Hash = AllocatePool (HashSize); + ASSERT (Hash != NULL); + + Status = Sha1Init (Hash); + if (!Status) { + goto Done; + } + + Status = Sha1Update (Hash, Buffer, BufferSize); + if (!Status) { + goto Done; + } + + Status = Sha1Final (Hash, Credential); + +Done: + FreePool (Hash); + return Status; +} + + +/** + Read the token file, and default the Token is saved at the begining of the file. + + @param[out] Token Token read from a Token file. + + @retval EFI_SUCCESS Read a Token successfully. + @retval Others Fails to read a Token. + +**/ +EFI_STATUS +GetToken ( + OUT UINT8 *Token + ) +{ + EFI_STATUS Status; + UINT8 *Buffer; + UINTN BufSize; + CHAR16 *TokenFile; + + BufSize = 0; + Buffer = NULL; + TokenFile = FixedPcdGetPtr (PcdFixedUsbCredentialProviderTokenFileName); + Status = GetFileData (TokenFile, (VOID *)&Buffer, &BufSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Read file %s from USB error! Status=(%r)\n", TokenFile, Status)); + return Status; + } + + if (!GenerateCredential (Buffer, BufSize, Token)) { + DEBUG ((DEBUG_ERROR, "Generate credential from read data failed!\n")); + FreePool (Buffer); + return EFI_SECURITY_VIOLATION; + } + + FreePool (Buffer); + return EFI_SUCCESS; +} + + +/** + Find a user infomation record by the information record type. + + This function searches all user information records of User from beginning + until either the information is found or there are no more user infomation + record. A match occurs when a Info.InfoType field matches the user information + record type. + + @param[in] User Points to the user profile record to search. + @param[in] InfoType The infomation type to be searched. + @param[out] Info Points to the user info found, the caller is responsible + to free. + + @retval EFI_SUCCESS Find the user information successfully. + @retval Others Fail to find the user information. + +**/ +EFI_STATUS +FindUserInfoByType ( + IN EFI_USER_PROFILE_HANDLE User, + IN UINT8 InfoType, + OUT EFI_USER_INFO **Info + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *UserInfo; + UINTN UserInfoSize; + EFI_USER_INFO_HANDLE UserInfoHandle; + EFI_USER_MANAGER_PROTOCOL *UserManager; + + // + // Find user information by information type. + // + if (Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->LocateProtocol ( + &gEfiUserManagerProtocolGuid, + NULL, + (VOID **) &UserManager + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Get each user information. + // + + UserInfoHandle = NULL; + UserInfo = NULL; + UserInfoSize = 0; + while (TRUE) { + Status = UserManager->GetNextInfo (UserManager, User, &UserInfoHandle); + if (EFI_ERROR (Status)) { + break; + } + // + // Get information. + // + Status = UserManager->GetInfo ( + UserManager, + User, + UserInfoHandle, + UserInfo, + &UserInfoSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + if (UserInfo != NULL) { + FreePool (UserInfo); + } + UserInfo = AllocateZeroPool (UserInfoSize); + if (UserInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = UserManager->GetInfo ( + UserManager, + User, + UserInfoHandle, + UserInfo, + &UserInfoSize + ); + } + if (EFI_ERROR (Status)) { + break; + } + + ASSERT (UserInfo != NULL); + if (UserInfo->InfoType == InfoType) { + *Info = UserInfo; + return EFI_SUCCESS; + } + } + + if (UserInfo != NULL) { + FreePool (UserInfo); + } + return Status; +} + + +/** + This function initialize the data mainly used in form browser. + + @retval EFI_SUCCESS Initialize form data successfully. + @retval Others Fail to Initialize form data. + +**/ +EFI_STATUS +InitFormBrowser ( + VOID + ) +{ + USB_PROVIDER_CALLBACK_INFO *CallbackInfo; + + // + // Initialize driver private data. + // + CallbackInfo = AllocateZeroPool (sizeof (USB_PROVIDER_CALLBACK_INFO)); + if (CallbackInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CallbackInfo->DriverHandle = NULL; + + // + // Publish HII data. + // + CallbackInfo->HiiHandle = HiiAddPackages ( + &mUsbCredentialGuid, + CallbackInfo->DriverHandle, + UsbCredentialProviderStrings, + NULL + ); + if (CallbackInfo->HiiHandle == NULL) { + return EFI_OUT_OF_RESOURCES; + } + mCallbackInfo = CallbackInfo; + + return EFI_SUCCESS; +} + + +/** + Enroll a user on a credential provider. + + This function enrolls and deletes a user profile using this credential provider. + If a user profile is successfully enrolled, it calls the User Manager Protocol + function Notify() to notify the user manager driver that credential information + has changed. If an enrolled user does exist, delete the user on the credential + provider. + + @param[in] This Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] User The user profile to enroll. + + @retval EFI_SUCCESS User profile was successfully enrolled. + @retval EFI_ACCESS_DENIED Current user profile does not permit enrollment on the + user profile handle. Either the user profile cannot enroll + on any user profile or cannot enroll on a user profile + other than the current user profile. + @retval EFI_UNSUPPORTED This credential provider does not support enrollment in + the pre-OS. + @retval EFI_DEVICE_ERROR The new credential could not be created because of a device + error. + @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle. + +**/ +EFI_STATUS +EFIAPI +CredentialEnroll ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User + ) +{ + EFI_STATUS Status; + UINTN Index; + USB_INFO UsbInfo; + EFI_USER_INFO *UserInfo; + EFI_INPUT_KEY Key; + EFI_USER_MANAGER_PROTOCOL *UserManager; + UINT8 *UserId; + UINT8 *NewUserId; + EFI_TPL OldTpl; + CHAR16 *QuestionStr; + CHAR16 *PromptStr; + + if ((This == NULL) || (User == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->LocateProtocol ( + &gEfiUserManagerProtocolGuid, + NULL, + (VOID **) &UserManager + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Get User Identifier + // + UserInfo = NULL; + Status = FindUserInfoByType ( + User, + EFI_USER_INFO_IDENTIFIER_RECORD, + &UserInfo + ); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + // + // If User exists in mUsbTable, delete User. + // + for (Index = 0; Index < mUsbTable->Count; Index++) { + UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId; + NewUserId = (UINT8 *) (UserInfo + 1); + if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) { + // + // Delete the exist Token. + // + FreePool (UserInfo); + return ModifyTable (Index, NULL); + } + } + + // + // Get Token and User ID to UsbInfo. + // + Status = GetToken (UsbInfo.Token); + if (EFI_ERROR (Status)) { + QuestionStr = GetStringById (STRING_TOKEN (STR_READ_USB_TOKEN_ERROR)); + PromptStr = GetStringById (STRING_TOKEN (STR_INSERT_USB_TOKEN)); + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + gBS->RestoreTPL (TPL_APPLICATION); + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + QuestionStr, + L"", + PromptStr, + NULL + ); + gBS->RaiseTPL (OldTpl); + FreePool (QuestionStr); + FreePool (PromptStr); + FreePool (UserInfo); + return Status; + } + CopyMem ( + UsbInfo.UserId, + (UINT8 *) (UserInfo + 1), + sizeof (EFI_USER_INFO_IDENTIFIER) + ); + FreePool (UserInfo); + + // + // Save the new added entry. + // + Status = ModifyTable (mUsbTable->Count, &UsbInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Notify the user manager driver that credential information has changed. + // + UserManager->Notify (UserManager, mCallbackInfo->DriverHandle); + + return EFI_SUCCESS; +} + + +/** + Returns the user interface information used during user identification. + + This function returns information about the form used when interacting with the + user during user identification. The form is the first enabled form in the form-set + class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If + the user credential provider does not require a form to identify the user, then this + function should return EFI_NOT_FOUND. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] Hii On return, holds the HII database handle. + @param[out] FormSetId On return, holds the identifier of the form set which contains + the form used during user identification. + @param[out] FormId On return, holds the identifier of the form used during user + identification. + + @retval EFI_SUCCESS Form returned successfully. + @retval EFI_NOT_FOUND Form not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or FormSetId is NULL or FormId is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialForm ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_GUID *FormSetId, + OUT EFI_FORM_ID *FormId + ) +{ + if ((This == NULL) || (Hii == NULL) || + (FormSetId == NULL) || (FormId == NULL)) { + return EFI_INVALID_PARAMETER; + } + return EFI_NOT_FOUND; +} + + +/** + Returns bitmap used to describe the credential provider type. + + This optional function returns a bitmap which is less than or equal to the number + of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND + is returned. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in, out] Width On entry, points to the desired bitmap width. If NULL then no + bitmap information will be returned. On exit, points to the + width of the bitmap returned. + @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no + bitmap information will be returned. On exit, points to the + height of the bitmap returned. + @param[out] Hii On return, holds the HII database handle. + @param[out] Image On return, holds the HII image identifier. + + @retval EFI_SUCCESS Image identifier returned successfully. + @retval EFI_NOT_FOUND Image identifier not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or Image is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialTile ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN OUT UINTN *Width, + IN OUT UINTN *Height, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_IMAGE_ID *Image + ) +{ + if ((This == NULL) || (Hii == NULL) || (Image == NULL)) { + return EFI_INVALID_PARAMETER; + } + return EFI_NOT_FOUND; +} + + +/** + Returns string used to describe the credential provider type. + + This function returns a string which describes the credential provider. If no + such string exists, then EFI_NOT_FOUND is returned. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] Hii On return, holds the HII database handle. + @param[out] String On return, holds the HII string identifier. + + @retval EFI_SUCCESS String identifier returned successfully. + @retval EFI_NOT_FOUND String identifier not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or String is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialTitle ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_STRING_ID *String + ) +{ + if ((This == NULL) || (Hii == NULL) || (String == NULL)) { + return EFI_INVALID_PARAMETER; + } + // + // Set Hii handle and String ID. + // + *Hii = mCallbackInfo->HiiHandle; + *String = STRING_TOKEN (STR_CREDENTIAL_TITLE); + + return EFI_SUCCESS; +} + + +/** + Return the user identifier associated with the currently authenticated user. + + This function returns the user identifier of the user authenticated by this credential + provider. This function is called after the credential-related information has been + submitted on a form OR after a call to Default() has returned that this credential is + ready to log on. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] User The user profile handle of the user profile currently being + considered by the user identity manager. If NULL, then no user + profile is currently under consideration. + @param[out] Identifier On return, points to the user identifier. + + @retval EFI_SUCCESS User identifier returned successfully. + @retval EFI_NOT_READY No user identifier can be returned. + @retval EFI_ACCESS_DENIED The user has been locked out of this user credential. + @retval EFI_INVALID_PARAMETER This is NULL, or Identifier is NULL. + @retval EFI_NOT_FOUND User is not NULL, and the specified user handle can't be + found in user profile database. + +**/ +EFI_STATUS +EFIAPI +CredentialUser ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + OUT EFI_USER_INFO_IDENTIFIER *Identifier + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_USER_INFO *UserInfo; + UINT8 *UserId; + UINT8 *NewUserId; + UINT8 *UserToken; + UINT8 ReadToken[HASHED_CREDENTIAL_LEN]; + EFI_INPUT_KEY Key; + EFI_TPL OldTpl; + CHAR16 *QuestionStr; + CHAR16 *PromptStr; + + if ((This == NULL) || (Identifier == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (User == NULL) { + // + // Verify the auto logon user, get user id by matched token. + // + if (mUsbTable->Count == 0) { + return EFI_NOT_READY; + } + + // + // No user selected, get token first and verify the user existed in user database. + // + Status = GetToken (ReadToken); + if (EFI_ERROR (Status)) { + return EFI_NOT_READY; + } + + for (Index = 0; Index < mUsbTable->Count; Index++) { + // + // find the specified credential in the Usb credential database. + // + UserToken = mUsbTable->UserInfo[Index].Token; + if (CompareMem (UserToken, ReadToken, HASHED_CREDENTIAL_LEN) == 0) { + UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId; + CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER)); + return EFI_SUCCESS; + } + } + + return EFI_NOT_READY; + } + + // + // User is not NULL here. Read a token, and check whether the token matches with + // the selected user's Token. If not, try to find a token in token DB to matches + // with read token. + // + + Status = GetToken (ReadToken); + if (EFI_ERROR (Status)) { + QuestionStr = GetStringById (STRING_TOKEN (STR_READ_USB_TOKEN_ERROR)); + PromptStr = GetStringById (STRING_TOKEN (STR_INSERT_USB_TOKEN)); + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + gBS->RestoreTPL (TPL_APPLICATION); + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + QuestionStr, + L"", + PromptStr, + NULL + ); + gBS->RaiseTPL (OldTpl); + FreePool (QuestionStr); + FreePool (PromptStr); + return EFI_NOT_FOUND; + } + + // + // Get the selected user's identifier. + // + Status = FindUserInfoByType (User, EFI_USER_INFO_IDENTIFIER_RECORD, &UserInfo); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Check the selected user's Token with the read token. + // + for (Index = 0; Index < mUsbTable->Count; Index++) { + UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId; + NewUserId = (UINT8 *) (UserInfo + 1); + if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) { + // + // The user's ID is found in the UsbTable. + // + UserToken = mUsbTable->UserInfo[Index].Token; + if (CompareMem (UserToken, ReadToken, HASHED_CREDENTIAL_LEN) == 0) { + // + // The read token matches with the one in UsbTable. + // + CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER)); + FreePool (UserInfo); + return EFI_SUCCESS; + } + } + } + FreePool (UserInfo); + + // + // The read token mismatch with the User's Token. + // Only check token. + // + for (Index = 0; Index < mUsbTable->Count; Index++) { + UserToken = mUsbTable->UserInfo[Index].Token; + if (CompareMem (UserToken, ReadToken, HASHED_CREDENTIAL_LEN) == 0) { + // + // The read token matches with the one in UsbTable. + // + UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId; + CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER)); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +/** + Indicate that user interface interaction has begun for the specified credential. + + This function is called when a credential provider is selected by the user. If + AutoLogon returns FALSE, then the user interface will be constructed by the User + Identity Manager. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] AutoLogon On return, points to the credential provider's capabilities + after the credential provider has been selected by the user. + + @retval EFI_SUCCESS Credential provider successfully selected. + @retval EFI_INVALID_PARAMETER AutoLogon is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialSelect ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon + ) +{ + if ((This == NULL) || (AutoLogon == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *AutoLogon = EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO; + + return EFI_SUCCESS; +} + + +/** + Indicate that user interface interaction has ended for the specified credential. + + This function is called when a credential provider is deselected by the user. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + + @retval EFI_SUCCESS Credential provider successfully deselected. + +**/ +EFI_STATUS +EFIAPI +CredentialDeselect ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This + ) +{ + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + return EFI_SUCCESS; +} + + +/** + Return the default logon behavior for this user credential. + + This function reports the default login behavior regarding this credential provider. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] AutoLogon On return, holds whether the credential provider should be used + by default to automatically log on the user. + + @retval EFI_SUCCESS Default information successfully returned. + @retval EFI_INVALID_PARAMETER AutoLogon is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialDefault ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon + ) +{ + if ((This == NULL) || (AutoLogon == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *AutoLogon = EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO; + return EFI_SUCCESS; +} + + +/** + Return information attached to the credential provider. + + This function returns user information. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] UserInfo Handle of the user information data record. + @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On + exit, holds the user information. If the buffer is too small + to hold the information, then EFI_BUFFER_TOO_SMALL is returned + and InfoSize is updated to contain the number of bytes actually + required. + @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the + size of the user information. + + @retval EFI_SUCCESS Information returned successfully. + @retval EFI_BUFFER_TOO_SMALL The size specified by InfoSize is too small to hold all of the + user information. The size required is returned in *InfoSize. + @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL. + @retval EFI_NOT_FOUND The specified UserInfo does not refer to a valid user info handle. + +**/ +EFI_STATUS +EFIAPI +CredentialGetInfo ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_INFO_HANDLE UserInfo, + OUT EFI_USER_INFO *Info, + IN OUT UINTN *InfoSize + ) +{ + EFI_USER_INFO *CredentialInfo; + UINTN Index; + + if ((This == NULL) || (InfoSize == NULL) || (Info == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((UserInfo == NULL) || (mUsbInfoHandle == NULL)) { + return EFI_NOT_FOUND; + } + + // + // Find information handle in credential info table. + // + for (Index = 0; Index < mUsbInfoHandle->Count; Index++) { + CredentialInfo = mUsbInfoHandle->Info[Index]; + if (UserInfo == (EFI_USER_INFO_HANDLE)CredentialInfo) { + // + // The handle is found, copy the user info. + // + if (CredentialInfo->InfoSize > *InfoSize) { + *InfoSize = CredentialInfo->InfoSize; + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem (Info, CredentialInfo, CredentialInfo->InfoSize); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +/** + Enumerate all of the user informations on the credential provider. + + This function returns the next user information record. To retrieve the first user + information record handle, point UserInfo at a NULL. Each subsequent call will retrieve + another user information record handle until there are no more, at which point UserInfo + will point to NULL. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in, out] UserInfo On entry, points to the previous user information handle or NULL + to start enumeration. On exit, points to the next user information + handle or NULL if there is no more user information. + + @retval EFI_SUCCESS User information returned. + @retval EFI_NOT_FOUND No more user information found. + @retval EFI_INVALID_PARAMETER UserInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialGetNextInfo ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN OUT EFI_USER_INFO_HANDLE *UserInfo + ) +{ + EFI_USER_INFO *Info; + CHAR16 *ProvNameStr; + UINTN InfoLen; + UINTN Index; + UINTN ProvStrLen; + + if ((This == NULL) || (UserInfo == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (mUsbInfoHandle == NULL) { + // + // Initilized user info table. There are 4 user info records in the table. + // + InfoLen = sizeof (USB_CREDENTIAL_INFO) + (4 - 1) * sizeof (EFI_USER_INFO *); + mUsbInfoHandle = AllocateZeroPool (InfoLen); + if (mUsbInfoHandle == NULL) { + *UserInfo = NULL; + return EFI_NOT_FOUND; + } + + // + // The first information, Credential Provider info. + // + InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID); + Info = AllocateZeroPool (InfoLen); + ASSERT (Info != NULL); + + Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD; + Info->InfoSize = (UINT32) InfoLen; + Info->InfoAttribs = EFI_USER_INFO_PROTECTED; + CopyGuid (&Info->Credential, &mUsbCredentialGuid); + CopyGuid ((EFI_GUID *)(Info + 1), &mUsbCredentialGuid); + + mUsbInfoHandle->Info[0] = Info; + mUsbInfoHandle->Count++; + + // + // The second information, Credential Provider name info. + // + ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_NAME)); + ProvStrLen = StrSize (ProvNameStr); + InfoLen = sizeof (EFI_USER_INFO) + ProvStrLen; + Info = AllocateZeroPool (InfoLen); + ASSERT (Info != NULL); + + Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD; + Info->InfoSize = (UINT32) InfoLen; + Info->InfoAttribs = EFI_USER_INFO_PROTECTED; + CopyGuid (&Info->Credential, &mUsbCredentialGuid); + CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen); + FreePool (ProvNameStr); + + mUsbInfoHandle->Info[1] = Info; + mUsbInfoHandle->Count++; + + // + // The third information, Credential Provider type info. + // + InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID); + Info = AllocateZeroPool (InfoLen); + ASSERT (Info != NULL); + + Info->InfoType = EFI_USER_INFO_CREDENTIAL_TYPE_RECORD; + Info->InfoSize = (UINT32) InfoLen; + Info->InfoAttribs = EFI_USER_INFO_PROTECTED; + CopyGuid (&Info->Credential, &mUsbCredentialGuid); + CopyGuid ((EFI_GUID *)(Info + 1), &gEfiUserCredentialClassSecureCardGuid); + + mUsbInfoHandle->Info[2] = Info; + mUsbInfoHandle->Count++; + + // + // The fourth information, Credential Provider type name info. + // + ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_TYPE_NAME)); + ProvStrLen = StrSize (ProvNameStr); + InfoLen = sizeof (EFI_USER_INFO) + ProvStrLen; + Info = AllocateZeroPool (InfoLen); + ASSERT (Info != NULL); + + Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD; + Info->InfoSize = (UINT32) InfoLen; + Info->InfoAttribs = EFI_USER_INFO_PROTECTED; + CopyGuid (&Info->Credential, &mUsbCredentialGuid); + CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen); + FreePool (ProvNameStr); + + mUsbInfoHandle->Info[3] = Info; + mUsbInfoHandle->Count++; + } + + if (*UserInfo == NULL) { + // + // Return the first info handle. + // + *UserInfo = (EFI_USER_INFO_HANDLE) mUsbInfoHandle->Info[0]; + return EFI_SUCCESS; + } + + // + // Find information handle in credential info table. + // + for (Index = 0; Index < mUsbInfoHandle->Count; Index++) { + Info = mUsbInfoHandle->Info[Index]; + if (*UserInfo == (EFI_USER_INFO_HANDLE)Info) { + // + // The handle is found, get the next one. + // + if (Index == mUsbInfoHandle->Count - 1) { + // + // Already last one. + // + *UserInfo = NULL; + return EFI_NOT_FOUND; + } + Index++; + *UserInfo = (EFI_USER_INFO_HANDLE)mUsbInfoHandle->Info[Index]; + return EFI_SUCCESS; + } + } + + *UserInfo = NULL; + return EFI_NOT_FOUND; +} + + +/** + Main entry for this driver. + + @param ImageHandle Image handle this driver. + @param SystemTable Pointer to SystemTable. + + @retval EFI_SUCESS This function always complete successfully. + +**/ +EFI_STATUS +EFIAPI +UsbProviderInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Init credential table. + // + Status = InitCredentialTable (); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Init Form Browser + // + Status = InitFormBrowser (); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Install protocol interfaces for the Usb Credential Provider. + // + Status = gBS->InstallProtocolInterface ( + &mCallbackInfo->DriverHandle, + &gEfiUserCredentialProtocolGuid, + EFI_NATIVE_INTERFACE, + &gUsbCredentialProviderDriver + ); + return Status; +} diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h new file mode 100644 index 0000000000..1d43e9ac99 --- /dev/null +++ b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h @@ -0,0 +1,354 @@ +/** @file + Usb Credential Provider driver header file. + +Copyright (c) 2009, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _USB_CREDENTIAL_PROVIDER_H_ +#define _USB_CREDENTIAL_PROVIDER_H_ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern UINT8 UsbCredentialProviderStrings[]; +extern UINT8 UsbCredentialProviderVfrBin[]; + +#define USB_TABLE_INC 16 +#define HASHED_CREDENTIAL_LEN 20 + +#define USB_CREDENTIAL_PROVIDER_GUID \ + { \ + 0xd0849ed1, 0xa88c, 0x4ba6, { 0xb1, 0xd6, 0xab, 0x50, 0xe2, 0x80, 0xb7, 0xa9 }\ + } + +// +// Save the enroll user credential Information. +// +typedef struct { + EFI_USER_INFO_IDENTIFIER UserId; + UINT8 Token[HASHED_CREDENTIAL_LEN]; +} USB_INFO; + +// +// USB Credential Table. +// +typedef struct { + UINTN Count; + UINTN MaxCount; + USB_INFO UserInfo[1]; +} CREDENTIAL_TABLE; + +// +// The user information on the USB provider. +// +typedef struct { + UINTN Count; + EFI_USER_INFO *Info[1]; +} USB_CREDENTIAL_INFO; + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +#define USB_PROVIDER_SIGNATURE SIGNATURE_32 ('U', 'S', 'B', 'P') + +typedef struct { + UINTN Signature; + EFI_HANDLE DriverHandle; + EFI_HII_HANDLE HiiHandle; +} USB_PROVIDER_CALLBACK_INFO; + +/** + Enroll a user on a credential provider. + + This function enrolls and deletes a user profile using this credential provider. + If a user profile is successfully enrolled, it calls the User Manager Protocol + function Notify() to notify the user manager driver that credential information + has changed. If an enrolled user does exist, delete the user on the credential + provider. + + @param[in] This Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] User The user profile to enroll. + + @retval EFI_SUCCESS User profile was successfully enrolled. + @retval EFI_ACCESS_DENIED Current user profile does not permit enrollment on the + user profile handle. Either the user profile cannot enroll + on any user profile or cannot enroll on a user profile + other than the current user profile. + @retval EFI_UNSUPPORTED This credential provider does not support enrollment in + the pre-OS. + @retval EFI_DEVICE_ERROR The new credential could not be created because of a device + error. + @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle. + +**/ +EFI_STATUS +EFIAPI +CredentialEnroll ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User + ); + +/** + Returns the user interface information used during user identification. + + This function returns information about the form used when interacting with the + user during user identification. The form is the first enabled form in the form-set + class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If + the user credential provider does not require a form to identify the user, then this + function should return EFI_NOT_FOUND. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] Hii On return, holds the HII database handle. + @param[out] FormSetId On return, holds the identifier of the form set which contains + the form used during user identification. + @param[out] FormId On return, holds the identifier of the form used during user + identification. + + @retval EFI_SUCCESS Form returned successfully. + @retval EFI_NOT_FOUND Form not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or FormSetId is NULL or FormId is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialForm ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_GUID *FormSetId, + OUT EFI_FORM_ID *FormId + ); + +/** + Returns bitmap used to describe the credential provider type. + + This optional function returns a bitmap which is less than or equal to the number + of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND + is returned. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in, out] Width On entry, points to the desired bitmap width. If NULL then no + bitmap information will be returned. On exit, points to the + width of the bitmap returned. + @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no + bitmap information will be returned. On exit, points to the + height of the bitmap returned. + @param[out] Hii On return, holds the HII database handle. + @param[out] Image On return, holds the HII image identifier. + + @retval EFI_SUCCESS Image identifier returned successfully. + @retval EFI_NOT_FOUND Image identifier not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or Image is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialTile ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN OUT UINTN *Width, + IN OUT UINTN *Height, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_IMAGE_ID *Image + ); + +/** + Returns string used to describe the credential provider type. + + This function returns a string which describes the credential provider. If no + such string exists, then EFI_NOT_FOUND is returned. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] Hii On return, holds the HII database handle. + @param[out] String On return, holds the HII string identifier. + + @retval EFI_SUCCESS String identifier returned successfully. + @retval EFI_NOT_FOUND String identifier not returned. + @retval EFI_INVALID_PARAMETER Hii is NULL or String is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialTitle ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_HII_HANDLE *Hii, + OUT EFI_STRING_ID *String + ); + +/** + Return the user identifier associated with the currently authenticated user. + + This function returns the user identifier of the user authenticated by this credential + provider. This function is called after the credential-related information has been + submitted on a form OR after a call to Default() has returned that this credential is + ready to log on. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] User The user profile handle of the user profile currently being + considered by the user identity manager. If NULL, then no user + profile is currently under consideration. + @param[out] Identifier On return, points to the user identifier. + + @retval EFI_SUCCESS User identifier returned successfully. + @retval EFI_NOT_READY No user identifier can be returned. + @retval EFI_ACCESS_DENIED The user has been locked out of this user credential. + @retval EFI_INVALID_PARAMETER This is NULL, or Identifier is NULL. + @retval EFI_NOT_FOUND User is not NULL, and the specified user handle can't be + found in user profile database. + +**/ +EFI_STATUS +EFIAPI +CredentialUser ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + OUT EFI_USER_INFO_IDENTIFIER *Identifier + ); + +/** + Indicate that user interface interaction has begun for the specified credential. + + This function is called when a credential provider is selected by the user. If + AutoLogon returns FALSE, then the user interface will be constructed by the User + Identity Manager. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] AutoLogon On return, points to the credential provider's capabilities + after the credential provider has been selected by the user. + + @retval EFI_SUCCESS Credential provider successfully selected. + @retval EFI_INVALID_PARAMETER AutoLogon is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialSelect ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon + ); + +/** + Indicate that user interface interaction has ended for the specified credential. + + This function is called when a credential provider is deselected by the user. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + + @retval EFI_SUCCESS Credential provider successfully deselected. + +**/ +EFI_STATUS +EFIAPI +CredentialDeselect ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This + ); + +/** + Return the default logon behavior for this user credential. + + This function reports the default login behavior regarding this credential provider. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[out] AutoLogon On return, holds whether the credential provider should be used + by default to automatically log on the user. + + @retval EFI_SUCCESS Default information successfully returned. + @retval EFI_INVALID_PARAMETER AutoLogon is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialDefault ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon + ); + +/** + Return information attached to the credential provider. + + This function returns user information. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in] UserInfo Handle of the user information data record. + @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On + exit, holds the user information. If the buffer is too small + to hold the information, then EFI_BUFFER_TOO_SMALL is returned + and InfoSize is updated to contain the number of bytes actually + required. + @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the + size of the user information. + + @retval EFI_SUCCESS Information returned successfully. + @retval EFI_BUFFER_TOO_SMALL The size specified by InfoSize is too small to hold all of the + user information. The size required is returned in *InfoSize. + @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL. + @retval EFI_NOT_FOUND The specified UserInfo does not refer to a valid user info handle. + +**/ +EFI_STATUS +EFIAPI +CredentialGetInfo ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN EFI_USER_INFO_HANDLE UserInfo, + OUT EFI_USER_INFO *Info, + IN OUT UINTN *InfoSize + ); + +/** + Enumerate all of the user informations on the credential provider. + + This function returns the next user information record. To retrieve the first user + information record handle, point UserInfo at a NULL. Each subsequent call will retrieve + another user information record handle until there are no more, at which point UserInfo + will point to NULL. + + @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL. + @param[in, out] UserInfo On entry, points to the previous user information handle or NULL + to start enumeration. On exit, points to the next user information + handle or NULL if there is no more user information. + + @retval EFI_SUCCESS User information returned. + @retval EFI_NOT_FOUND No more user information found. + @retval EFI_INVALID_PARAMETER UserInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +CredentialGetNextInfo ( + IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This, + IN OUT EFI_USER_INFO_HANDLE *UserInfo + ); + +#endif diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf new file mode 100644 index 0000000000..2a45763566 --- /dev/null +++ b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf @@ -0,0 +1,58 @@ +## @file +# Component description file for USB Credential Provider. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UsbCredentialProvider + FILE_GUID = 672A0C68-2BF0-46f9-93C3-C4E7DC0FA555 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = UsbProviderInit + +[Sources] + UsbCredentialProvider.c + UsbCredentialProvider.h + UsbCredentialProviderStrings.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + MemoryAllocationLib + BaseMemoryLib + DebugLib + HiiLib + UefiLib + BaseCryptLib + +[Guids] + gEfiIfrTianoGuid ## CONSUMES ## Guid + gEfiFileInfoGuid ## CONSUMES ## Guid + gEfiUserCredentialClassSecureCardGuid ## CONSUMES ## Guid + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdFixedUsbCredentialProviderTokenFileName + +[Protocols] + gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiUserCredentialProtocolGuid + gEfiUserManagerProtocolGuid + gEfiBlockIoProtocolGuid + gEfiSimpleFileSystemProtocolGuid + \ No newline at end of file diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..7c531f423038ceca320f2404bed66c3cc822e586 GIT binary patch literal 3556 zcmdUx-%k@k5Xa|L6aR;^zKDTVebX3YfkPXxZAuY+YD!C?5n6IBApgAj`Ofy}4~}>( zFPO{S-tNxMeCIo}v-{_F$zJh9_Q`tIw=+AoXZDnSWcxO@gt390(CacIi2?7JcgWv} z@g9E(?buF{i0puMo3vYu9{Z|+%eT=TS)I|LU9n#J5-YkjS=?g$!fqJrWABtTk-fBz ztkTXQ$83!I%h4*A*V?+k77wC$E7`hC_N zBP$frm}=HK@uQI|Ud5$tM|?GQ>Gq{{ia{JCAdp|F7GV<7`FIV9*mT_{(b}fJH-|+i zuigI+Uum58u#Yua5(9xFSsBrnr$-=6Geqo1CN71%$4rQX@cu$70^=;6c}^lcYQtxQ z&ai$s@m`q5&ZaVD4D;`;#G@Pvj7le--_)<+NIacM;3;0!5o_JO(-ipzN*9v(X`2ySt`G6gO$+nHFq|1;rz z=q|B;;@LUtle}845(cmHBUoKB3;Qg$%VSriRy@RjD#qGv46`Fqg_}KRKixG|_S9+~ zWqGq0iO0oln%~*ngbMSG9Th4^i)>Y`SuQ^VmwC9+epkKPga7|IV^{ZM+3dX=p(eGn z4u{LfDo=#=*;gGu&2$ECQEw9JXxaXJB7e064q zQ}W-nCr_jrL`pX|?W7TR3!VBy`{{KtqC$rIwNBQAN4JvalS=u-@;vvU%)+)<(O1E? zEZ^FLx@9!*JB#!C@Mn!@`LtNq>)b2ExbDvp?1r0k;`hol0%Bh`$ZO_xU!9G~ +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UserIdentifyManager.h" + +EFI_HANDLE mDeferredImageHandle; + +/** + The function will load all the deferred images again. If the deferred image is loaded + successfully, try to start it. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +LoadDeferredImage ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *DeferredImage; + UINTN HandleCount; + EFI_HANDLE *HandleBuf; + UINTN Index; + UINTN DriverIndex; + EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath; + VOID *DriverImage; + UINTN ImageSize; + BOOLEAN BootOption; + EFI_HANDLE ImageHandle; + UINTN ExitDataSize; + CHAR16 *ExitData; + + // + // Find all the deferred image load protocols. + // + HandleCount = 0; + HandleBuf = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiDeferredImageLoadProtocolGuid, + NULL, + &HandleCount, + &HandleBuf + ); + if (EFI_ERROR (Status)) { + return ; + } + + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuf[Index], + &gEfiDeferredImageLoadProtocolGuid, + (VOID **) &DeferredImage + ); + if (EFI_ERROR (Status)) { + continue ; + } + + DriverIndex = 0; + do { + // + // Load all the deferred images in this protocol instance. + // + Status = DeferredImage->GetImageInfo( + DeferredImage, + DriverIndex, + &ImageDevicePath, + (VOID **) &DriverImage, + &ImageSize, + &BootOption + ); + if (EFI_ERROR (Status)) { + break; + } + + // + // Load and start the image. + // + Status = gBS->LoadImage ( + BootOption, + mDeferredImageHandle, + ImageDevicePath, + NULL, + 0, + &ImageHandle + ); + if (!EFI_ERROR (Status)) { + // + // Before calling the image, enable the Watchdog Timer for + // a 5 Minute period + // + gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL); + Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData); + + // + // Clear the Watchdog Timer after the image returns. + // + gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL); + } + DriverIndex++; + } while (TRUE); + } + FreePool (HandleBuf); +} + + +/** + Register an event notification function for user profile changed. + + @param[in] ImageHandle Image handle this driver. + +**/ +VOID +LoadDeferredImageInit ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + mDeferredImageHandle = ImageHandle; + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + LoadDeferredImage, + NULL, + &gEfiEventUserProfileChangedGuid, + &Event + ); + + ASSERT (Status == EFI_SUCCESS); +} diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c new file mode 100644 index 0000000000..e105579115 --- /dev/null +++ b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c @@ -0,0 +1,4381 @@ +/** @file + This driver manages user information and produces user manager protocol. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UserIdentifyManager.h" + +// +// Guid used in user profile saving and in form browser. +// +EFI_GUID mUserManagerGuid = USER_IDENTIFY_MANAGER_GUID; + +// +// Default user name. +// +CHAR16 mUserName[] = L"Administrator"; + +// +// Points to the user profile database. +// +USER_PROFILE_DB *mUserProfileDb = NULL; + +// +// Points to the credential providers found in system. +// +CREDENTIAL_PROVIDER_INFO *mProviderDb = NULL; + +// +// Current user shared in multi function. +// +EFI_USER_PROFILE_HANDLE mCurrentUser = NULL; + +// +// Flag indicates a user is identified. +// +BOOLEAN mIdentified = FALSE; +USER_MANAGER_CALLBACK_INFO *mCallbackInfo = NULL; +HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + // + // {ACA7C06F-743C-454f-9C6D-692138482498} + // + { 0xaca7c06f, 0x743c, 0x454f, { 0x9c, 0x6d, 0x69, 0x21, 0x38, 0x48, 0x24, 0x98 } } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + + +EFI_USER_MANAGER_PROTOCOL gUserIdentifyManager = { + UserProfileCreate, + UserProfileDelete, + UserProfileGetNext, + UserProfileCurrent, + UserProfileIdentify, + UserProfileFind, + UserProfileNotify, + UserProfileGetInfo, + UserProfileSetInfo, + UserProfileDeleteInfo, + UserProfileGetNextInfo, +}; + + +/** + Find the specified user in the user database. + + This function searches the specified user from the beginning of the user database. + And if NextUser is TRUE, return the next User in the user database. + + @param[in, out] User On entry, points to the user profile entry to search. + On return, points to the user profile entry or NULL if not found. + @param[in] NextUser If FALSE, find the user in user profile database specifyed by User + If TRUE, find the next user in user profile database specifyed + by User. + @param[out] ProfileIndex A pointer to the index of user profile database that matches the + user specifyed by User. + + @retval EFI_NOT_FOUND User was NULL, or User was not found, or the next user was not found. + @retval EFI_SUCCESS User or the next user are found in user profile database + +**/ +EFI_STATUS +FindUserProfile ( + IN OUT USER_PROFILE_ENTRY **User, + IN BOOLEAN NextUser, + OUT UINTN *ProfileIndex OPTIONAL + ) +{ + UINTN Index; + + // + // Check parameters + // + if ((mUserProfileDb == NULL) || (User == NULL)) { + return EFI_NOT_FOUND; + } + + // + // Check whether the user profile is in the user profile database. + // + for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) { + if (mUserProfileDb->UserProfile[Index] == *User) { + if (ProfileIndex != NULL) { + *ProfileIndex = Index; + } + break; + } + } + + if (NextUser) { + // + // Find the next user profile. + // + Index++; + if (Index < mUserProfileDb->UserProfileNum) { + *User = mUserProfileDb->UserProfile[Index]; + } else if (Index == mUserProfileDb->UserProfileNum) { + *User = NULL; + return EFI_NOT_FOUND; + } else { + if ((mUserProfileDb->UserProfileNum > 0) && (*User == NULL)) { + *User = mUserProfileDb->UserProfile[0]; + } else { + *User = NULL; + return EFI_NOT_FOUND; + } + } + } else if (Index == mUserProfileDb->UserProfileNum) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + Find the specified user information record in the specified User profile. + + This function searches the specified user information record from the beginning of the user + profile. And if NextInfo is TRUE, return the next info in the user profile. + + @param[in] User Points to the user profile entry. + @param[in, out] Info On entry, points to the user information record or NULL to start + searching with the first user information record. + On return, points to the user information record or NULL if not found. + @param[in] NextInfo If FALSE, find the user information record in profile specifyed by User. + If TRUE, find the next user information record in profile specifyed + by User. + @param[out] Offset A pointer to the offset of the information record in the user profile. + + @retval EFI_INVALID_PARAMETER Info is NULL + @retval EFI_NOT_FOUND Info was not found, or the next Info was not found. + @retval EFI_SUCCESS Info or the next info are found in user profile. + +**/ +EFI_STATUS +FindUserInfo ( + IN USER_PROFILE_ENTRY * User, + IN OUT EFI_USER_INFO **Info, + IN BOOLEAN NextInfo, + OUT UINTN *Offset OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *UserInfo; + UINTN InfoLen; + + if (Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check user profile entry + // + Status = FindUserProfile (&User, FALSE, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Find user information in the specified user record. + // + InfoLen = 0; + while (InfoLen < User->UserProfileSize) { + UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen); + if (UserInfo == *Info) { + if (Offset != NULL) { + *Offset = InfoLen; + } + break; + } + InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize); + } + + // + // Check whether to find the next user information. + // + if (NextInfo) { + if (InfoLen < User->UserProfileSize) { + UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen); + InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize); + if (InfoLen < User->UserProfileSize) { + *Info = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen); + if (Offset != NULL) { + *Offset = InfoLen; + } + } else if (InfoLen == User->UserProfileSize) { + *Info = NULL; + return EFI_NOT_FOUND; + } + } else { + if (*Info == NULL) { + *Info = (EFI_USER_INFO *) User->ProfileInfo; + if (Offset != NULL) { + *Offset = 0; + } + } else { + *Info = NULL; + return EFI_NOT_FOUND; + } + } + } else if (InfoLen == User->UserProfileSize) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + Find a user infomation record by the information record type. + + This function searches all user information records of User. The search starts with the + user information record following Info and continues until either the information is found + or there are no more user infomation record. + A match occurs when a Info.InfoType field matches the user information record type. + + @param[in] User Points to the user profile record to search. + @param[in, out] Info On entry, points to the user information record or NULL to start + searching with the first user information record. + On return, points to the user information record or NULL if not found. + @param[in] InfoType The infomation type to be searched. + + @retval EFI_SUCCESS User information was found. Info points to the user information record. + @retval EFI_NOT_FOUND User information was not found. + @retval EFI_INVALID_PARAMETER User is NULL or Info is NULL. + +**/ +EFI_STATUS +FindUserInfoByType ( + IN USER_PROFILE_ENTRY *User, + IN OUT EFI_USER_INFO **Info, + IN UINT8 InfoType + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *UserInfo; + UINTN InfoLen; + + if (Info == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether the user has the specified user information. + // + InfoLen = 0; + if (*Info == NULL) { + Status = FindUserProfile (&User, FALSE, NULL); + } else { + Status = FindUserInfo (User, Info, TRUE, &InfoLen); + } + + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + while (InfoLen < User->UserProfileSize) { + UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen); + if (UserInfo->InfoType == InfoType) { + if (UserInfo != *Info) { + *Info = UserInfo; + return EFI_SUCCESS; + } + } + + InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize); + } + + *Info = NULL; + return EFI_NOT_FOUND; +} + +/** + Find a user using a user information record. + + This function searches all user profiles for the specified user information record. The + search starts with the user information record handle following UserInfo and continues + until either the information is found or there are no more user profiles. + A match occurs when the Info.InfoType field matches the user information record type and the + user information record data matches the portion of Info passed the EFI_USER_INFO header. + + @param[in, out] User On entry, points to the previously returned user profile record, + or NULL to start searching with the first user profile. + On return, points to the user profile entry, or NULL if not found. + @param[in, out] UserInfo On entry, points to the previously returned user information record, + or NULL to start searching with the first. + On return, points to the user information record, or NULL if not found. + @param[in] Info Points to the buffer containing the user information to be compared + to the user information record. + @param[in] InfoSize The size of Info, in bytes. Same as Info->InfoSize. + + @retval EFI_SUCCESS User information was found. User points to the user profile record, + and UserInfo points to the user information record. + @retval EFI_NOT_FOUND User information was not found. + @retval EFI_INVALID_PARAMETER User is NULL; Info is NULL; or, InfoSize is too small. + +**/ +EFI_STATUS +FindUserProfileByInfo ( + IN OUT USER_PROFILE_ENTRY **User, + IN OUT EFI_USER_INFO **UserInfo, OPTIONAL + IN EFI_USER_INFO *Info, + IN UINTN InfoSize + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *InfoEntry; + + + if ((User == NULL) || (Info == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (InfoSize < sizeof (EFI_USER_INFO)) { + return EFI_INVALID_PARAMETER; + } + + if (UserInfo != NULL) { + InfoEntry = *UserInfo; + } else { + InfoEntry = NULL; + } + // + // Find user profile according to information. + // + if (*User == NULL) { + *User = mUserProfileDb->UserProfile[0]; + } + + // + // Check user profile handle. + // + Status = FindUserProfile (User, FALSE, NULL); + + while (!EFI_ERROR (Status)) { + // + // Find the user information in a user profile. + // + while (TRUE) { + Status = FindUserInfoByType (*User, &InfoEntry, Info->InfoType); + if (EFI_ERROR (Status)) { + break; + } + + if (InfoSize == Info->InfoSize) { + if (CompareMem ((UINT8 *) (InfoEntry + 1), (UINT8 *) (Info + 1), InfoSize - sizeof (EFI_USER_INFO)) == 0) { + // + // Found the infomation record. + // + if (UserInfo != NULL) { + *UserInfo = InfoEntry; + } + return EFI_SUCCESS; + } + } + } + + // + // Get next user profile. + // + InfoEntry = NULL; + Status = FindUserProfile (User, TRUE, NULL); + } + + return EFI_NOT_FOUND; +} + +/** + Find the credential provider in the specified identity policy. + + @param[in] FindIdentity Point to the user identity policy. + @param[in] IdentifyInfo Point to the user information to be searched. + + @retval TRUE The credential provider was found in the identity policy. + @retval FALSE The credential provider was not found. +**/ +BOOLEAN +FindProvider ( + IN EFI_USER_INFO_IDENTITY_POLICY *FindIdentity, + IN CONST EFI_USER_INFO *IdentifyInfo + ) +{ + UINTN TotalLen; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + + // + // Found the credential provider. + // + TotalLen = 0; + while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen); + if ((Identity->Type == FindIdentity->Type) && + (Identity->Length == FindIdentity->Length) && + CompareGuid ((EFI_GUID *) (Identity + 1), (EFI_GUID *) (FindIdentity + 1)) + ) { + return TRUE; + } + + TotalLen += Identity->Length; + } + + return FALSE; +} + + +/** + Check whether the access policy is valid. + + @param[in] PolicyInfo Point to the access policy. + @param[in] InfoLen The policy length. + + @retval TRUE The policy is a valid access policy. + @retval FALSE The access policy is not a valid access policy. + +**/ +BOOLEAN +CheckAccessPolicy ( + IN UINT8 *PolicyInfo, + IN UINTN InfoLen + ) +{ + UINTN TotalLen; + UINTN ValueLen; + UINTN OffSet; + EFI_USER_INFO_ACCESS_CONTROL Access; + EFI_DEVICE_PATH_PROTOCOL *Path; + UINTN PathSize; + + TotalLen = 0; + while (TotalLen < InfoLen) { + // + // Check access policy according to type. + // + CopyMem (&Access, PolicyInfo + TotalLen, sizeof (Access)); + ValueLen = Access.Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL); + switch (Access.Type) { + case EFI_USER_INFO_ACCESS_FORBID_LOAD: + case EFI_USER_INFO_ACCESS_PERMIT_LOAD: + case EFI_USER_INFO_ACCESS_FORBID_CONNECT: + case EFI_USER_INFO_ACCESS_PERMIT_CONNECT: + OffSet = 0; + while (OffSet < ValueLen) { + Path = (EFI_DEVICE_PATH_PROTOCOL *) (PolicyInfo + TotalLen + sizeof (Access) + OffSet); + PathSize = GetDevicePathSize (Path); + OffSet += PathSize; + } + if (OffSet != ValueLen) { + return FALSE; + } + break; + + case EFI_USER_INFO_ACCESS_SETUP: + if (ValueLen % sizeof (EFI_GUID) != 0) { + return FALSE; + } + break; + + case EFI_USER_INFO_ACCESS_BOOT_ORDER: + if (ValueLen % sizeof (EFI_USER_INFO_ACCESS_BOOT_ORDER_HDR) != 0) { + return FALSE; + } + break; + + case EFI_USER_INFO_ACCESS_ENROLL_SELF: + case EFI_USER_INFO_ACCESS_ENROLL_OTHERS: + case EFI_USER_INFO_ACCESS_MANAGE: + if (ValueLen != 0) { + return FALSE; + } + break; + + default: + return FALSE; + break; + } + + TotalLen += Access.Size; + } + + if (TotalLen != InfoLen) { + return FALSE; + } + + return TRUE; +} + + +/** + Check whether the identity policy is valid. + + @param[in] PolicyInfo Point to the identity policy. + @param[in] InfoLen The policy length. + + @retval TRUE The policy is a valid identity policy. + @retval FALSE The access policy is not a valid identity policy. + +**/ +BOOLEAN +CheckIdentityPolicy ( + IN UINT8 *PolicyInfo, + IN UINTN InfoLen + ) +{ + UINTN TotalLen; + UINTN ValueLen; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + + TotalLen = 0; + + // + // Check each part of policy expression. + // + while (TotalLen < InfoLen) { + // + // Check access polisy according to type. + // + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + TotalLen); + ValueLen = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY); + switch (Identity->Type) { + // + // Check False option. + // + case EFI_USER_INFO_IDENTITY_FALSE: + if (ValueLen != 0) { + return FALSE; + } + break; + + // + // Check True option. + // + case EFI_USER_INFO_IDENTITY_TRUE: + if (ValueLen != 0) { + return FALSE; + } + break; + + // + // Check negative operation. + // + case EFI_USER_INFO_IDENTITY_NOT: + if (ValueLen != 0) { + return FALSE; + } + break; + + // + // Check and operation. + // + case EFI_USER_INFO_IDENTITY_AND: + if (ValueLen != 0) { + return FALSE; + } + break; + + // + // Check or operation. + // + case EFI_USER_INFO_IDENTITY_OR: + if (ValueLen != 0) { + return FALSE; + } + break; + + // + // Check credential provider by type. + // + case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE: + if (ValueLen != sizeof (EFI_GUID)) { + return FALSE; + } + break; + + // + // Check credential provider by ID. + // + case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER: + if (ValueLen != sizeof (EFI_GUID)) { + return FALSE; + } + break; + + default: + return FALSE; + break; + } + + TotalLen += Identity->Length; + } + + if (TotalLen != InfoLen) { + return FALSE; + } + + return TRUE; +} + + +/** + Check whether the user information is a valid user information record. + + @param[in] Info points to the user information. + + @retval TRUE The info is a valid user information record. + @retval FALSE The info is not a valid user information record. + +**/ +BOOLEAN +CheckUserInfo ( + IN CONST EFI_USER_INFO *Info + ) +{ + UINTN InfoLen; + + if (Info == NULL) { + return FALSE; + } + // + // Check user information according to information type. + // + InfoLen = Info->InfoSize - sizeof (EFI_USER_INFO); + switch (Info->InfoType) { + case EFI_USER_INFO_EMPTY_RECORD: + if (InfoLen != 0) { + return FALSE; + } + break; + + case EFI_USER_INFO_NAME_RECORD: + case EFI_USER_INFO_CREDENTIAL_TYPE_NAME_RECORD: + case EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD: + break; + + case EFI_USER_INFO_CREATE_DATE_RECORD: + case EFI_USER_INFO_USAGE_DATE_RECORD: + if (InfoLen != sizeof (EFI_TIME)) { + return FALSE; + } + break; + + case EFI_USER_INFO_USAGE_COUNT_RECORD: + if (InfoLen != sizeof (UINT64)) { + return FALSE; + } + break; + + case EFI_USER_INFO_IDENTIFIER_RECORD: + if (InfoLen != 16) { + return FALSE; + } + break; + + case EFI_USER_INFO_CREDENTIAL_TYPE_RECORD: + case EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD: + case EFI_USER_INFO_GUID_RECORD: + if (InfoLen != sizeof (EFI_GUID)) { + return FALSE; + } + break; + + case EFI_USER_INFO_PKCS11_RECORD: + case EFI_USER_INFO_CBEFF_RECORD: + break; + + case EFI_USER_INFO_FAR_RECORD: + case EFI_USER_INFO_RETRY_RECORD: + if (InfoLen != 1) { + return FALSE; + } + break; + + case EFI_USER_INFO_ACCESS_POLICY_RECORD: + if(!CheckAccessPolicy ((UINT8 *) (Info + 1), InfoLen)) { + return FALSE; + } + break; + + case EFI_USER_INFO_IDENTITY_POLICY_RECORD: + if (!CheckIdentityPolicy ((UINT8 *) (Info + 1), InfoLen)) { + return FALSE; + } + break; + + default: + return FALSE; + break; + } + + return TRUE; +} + + +/** + Check the user profile data format to be added. + + @param[in] UserProfileInfo Points to the user profile data. + @param[in] UserProfileSize The length of user profile data. + + @retval TRUE It is a valid user profile. + @retval FALSE It is not a valid user profile. + +**/ +BOOLEAN +CheckProfileInfo ( + IN UINT8 *UserProfileInfo, + IN UINTN UserProfileSize + ) +{ + UINTN ChkLen; + EFI_USER_INFO *Info; + + if (UserProfileInfo == NULL) { + return FALSE; + } + + // + // Check user profile information length. + // + ChkLen = 0; + while (ChkLen < UserProfileSize) { + Info = (EFI_USER_INFO *) (UserProfileInfo + ChkLen); + // + // Check user information format. + // + if (!CheckUserInfo (Info)) { + return FALSE; + } + + ChkLen += ALIGN_VARIABLE (Info->InfoSize); + } + + if (ChkLen != UserProfileSize) { + return FALSE; + } + + return TRUE; +} + + +/** + Find the specified RightType in current user profile. + + @param[in] RightType Could be EFI_USER_INFO_ACCESS_MANAGE, + EFI_USER_INFO_ACCESS_ENROLL_OTHERS or + EFI_USER_INFO_ACCESS_ENROLL_SELF. + + @retval TRUE Find the specified RightType in current user profile. + @retval FALSE Can't find the right in the profile. + +**/ +BOOLEAN +CheckCurrentUserAccessRight ( + IN UINT32 RightType + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *Info; + UINTN TotalLen; + UINTN CheckLen; + EFI_USER_INFO_ACCESS_CONTROL Access; + + // + // Get user access right information. + // + Info = NULL; + Status = FindUserInfoByType ( + (USER_PROFILE_ENTRY *) mCurrentUser, + &Info, + EFI_USER_INFO_ACCESS_POLICY_RECORD + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + ASSERT (Info != NULL); + TotalLen = Info->InfoSize - sizeof (EFI_USER_INFO); + CheckLen = 0; + while (CheckLen < TotalLen) { + // + // Check right according to access type. + // + CopyMem (&Access, (UINT8 *) (Info + 1) + CheckLen, sizeof (Access)); + if (Access.Type == RightType) { + return TRUE;; + } + + CheckLen += Access.Size; + } + + return FALSE; +} + + +/** + Create a unique user identifier. + + @param[out] Identifier This points to the identifier. + +**/ +VOID +GenerateIdentifier ( + OUT UINT8 *Identifier + ) +{ + EFI_TIME Time; + UINT64 MonotonicCount; + UINT32 *MonotonicPointer; + UINTN Index; + + // + // Create a unique user identifier. + // + gRT->GetTime (&Time, NULL); + CopyMem (Identifier, &Time, sizeof (EFI_TIME)); + // + // Remove zeros. + // + for (Index = 0; Index < sizeof (EFI_TIME); Index++) { + if (Identifier[Index] == 0) { + Identifier[Index] = 0x5a; + } + } + + MonotonicPointer = (UINT32 *) Identifier; + gBS->GetNextMonotonicCount (&MonotonicCount); + MonotonicPointer[0] += (UINT32) MonotonicCount; + MonotonicPointer[1] += (UINT32) MonotonicCount; + MonotonicPointer[2] += (UINT32) MonotonicCount; + MonotonicPointer[3] += (UINT32) MonotonicCount; +} + + +/** + Generate unique user ID. + + @param[out] UserId Points to the user identifer. + +**/ +VOID +GenerateUserId ( + OUT UINT8 *UserId + ) +{ + EFI_STATUS Status; + USER_PROFILE_ENTRY *UserProfile; + EFI_USER_INFO *UserInfo; + UINTN Index; + + // + // Generate unique user ID + // + while (TRUE) { + GenerateIdentifier (UserId); + // + // Check whether it's unique in user profile database. + // + if (mUserProfileDb == NULL) { + return ; + } + + for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) { + UserProfile = (USER_PROFILE_ENTRY *) (mUserProfileDb->UserProfile[Index]); + UserInfo = NULL; + Status = FindUserInfoByType (UserProfile, &UserInfo, EFI_USER_INFO_IDENTIFIER_RECORD); + if (EFI_ERROR (Status)) { + continue; + } + + if (CompareMem ((UINT8 *) (UserInfo + 1), UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) { + break; + } + } + + if (Index == mUserProfileDb->UserProfileNum) { + return ; + } + } +} + + +/** + Expand user profile database. + + @retval TRUE Success to expand user profile database. + @retval FALSE Fail to expand user profile database. + +**/ +BOOLEAN +ExpandUsermUserProfileDb ( + VOID + ) +{ + UINTN MaxNum; + USER_PROFILE_DB *NewDataBase; + + // + // Create new user profile database. + // + if (mUserProfileDb == NULL) { + MaxNum = USER_NUMBER_INC; + } else { + MaxNum = mUserProfileDb->MaxProfileNum + USER_NUMBER_INC; + } + + NewDataBase = AllocateZeroPool ( + sizeof (USER_PROFILE_DB) - sizeof (EFI_USER_PROFILE_HANDLE) + + MaxNum * sizeof (EFI_USER_PROFILE_HANDLE) + ); + if (NewDataBase == NULL) { + return FALSE; + } + + NewDataBase->MaxProfileNum = MaxNum; + + // + // Copy old user profile database value + // + if (mUserProfileDb == NULL) { + NewDataBase->UserProfileNum = 0; + } else { + NewDataBase->UserProfileNum = mUserProfileDb->UserProfileNum; + CopyMem ( + NewDataBase->UserProfile, + mUserProfileDb->UserProfile, + NewDataBase->UserProfileNum * sizeof (EFI_USER_PROFILE_HANDLE) + ); + FreePool (mUserProfileDb); + } + + mUserProfileDb = NewDataBase; + return TRUE; +} + + +/** + Expand user profile + + @param[in] User Points to user profile. + @param[in] ExpandSize The size of user profile. + + @retval TRUE Success to expand user profile size. + @retval FALSE Fail to expand user profile size. + +**/ +BOOLEAN +ExpandUserProfile ( + IN USER_PROFILE_ENTRY *User, + IN UINTN ExpandSize + ) +{ + UINT8 *Info; + UINTN InfoSizeInc; + + // + // Allocate new memory. + // + InfoSizeInc = 128; + User->MaxProfileSize += ((ExpandSize + InfoSizeInc - 1) / InfoSizeInc) * InfoSizeInc; + Info = AllocateZeroPool (User->MaxProfileSize); + if (Info == NULL) { + return FALSE; + } + + // + // Copy exist information. + // + if (User->UserProfileSize > 0) { + CopyMem (Info, User->ProfileInfo, User->UserProfileSize); + FreePool (User->ProfileInfo); + } + + User->ProfileInfo = Info; + return TRUE; +} + + +/** + Add or delete the user's credential record in the provider. + + @param[in] ProviderGuid Point to credential provider guid or class guid. + @param[in] ByType If TRUE, Provider is credential class guid. + If FALSE, Provider is provider guid. + @param[in] User Points to user profile. + + @retval EFI_SUCCESS Add or delete record successfully. + @retval Others Fail to add or delete record. + +**/ +EFI_STATUS +ModifyProviderCredential ( + IN EFI_GUID *Provider, + IN BOOLEAN ByType, + IN USER_PROFILE_ENTRY *User + ) +{ + UINTN Index; + EFI_USER_CREDENTIAL_PROTOCOL *UserCredential; + + if (Provider == NULL) { + return EFI_INVALID_PARAMETER; + } + + + // + // Find the specified credential provider. + // + for (Index = 0; Index < mProviderDb->Count; Index++) { + // + // Check credential provider ID. + // + UserCredential = mProviderDb->Provider[Index]; + if (CompareGuid (&UserCredential->Identifier, Provider)) { + return UserCredential->Enroll (UserCredential, User); + } + } + + return EFI_NOT_FOUND; +} + + +/** + Modify user's credential record in the providers. + + Found the providers information in PolicyInfo, and then add or delete the user's credential + record in the providers. + + @param User Points to user profile. + @param PolicyInfo Point to identification policy to be modified. + @param InfoLen The length of PolicyInfo. + + @retval EFI_SUCCESS Modify PolicyInfo successfully. + @retval Others Fail to modify PolicyInfo. + +**/ +EFI_STATUS +ModifyCredentialInfo ( + IN USER_PROFILE_ENTRY *User, + IN UINT8 *PolicyInfo, + IN UINTN InfoLen + ) +{ + EFI_STATUS Status; + UINTN TotalLen; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + + // + // Modify user's credential. + // + TotalLen = 0; + while (TotalLen < InfoLen) { + // + // Check identification policy according to type. + // + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + TotalLen); + switch (Identity->Type) { + case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE: + Status = ModifyProviderCredential ((EFI_GUID *) (Identity + 1), TRUE, User); + if (EFI_ERROR (Status)) { + return Status; + } + break; + + case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER: + Status = ModifyProviderCredential ((EFI_GUID *) (Identity + 1), FALSE, User); + if (EFI_ERROR (Status)) { + return Status; + } + break; + + default: + break; + } + + TotalLen += Identity->Length; + } + + return EFI_SUCCESS; +} + + +/** + Save the user profile to non-volatile memory, or delete it from non-volatile memory. + + @param[in] User Point to the user profile + @param[in] Delete If TRUE, delete the found user profile. + If FALSE, save the user profile. + @retval EFI_SUCCESS Save or delete user profile successfully. + @retval Others Fail to change the profile. + +**/ +EFI_STATUS +SaveNvUserProfile ( + IN USER_PROFILE_ENTRY *User, + IN BOOLEAN Delete + ) +{ + EFI_STATUS Status; + + // + // Check user profile entry. + // + Status = FindUserProfile (&User, FALSE, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Save the user profile to non-volatile memory. + // + Status = gRT->SetVariable ( + User->UserVarName, + &mUserManagerGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + Delete ? 0 : User->UserProfileSize, + User->ProfileInfo + ); + return Status; +} + + +/** + Replace the old identity info with NewInfo in NV Flash. + + This function only replace the identity record in the user profile. Don't update + the the information on the credential provider. + + @param[in] User Point to the user profile. + @param[in] NewInfo Point to the new identity policy info. + @param[out] UserInfo Point to the new added identity info. + + @retval EFI_SUCCESS Replace user identity successfully. + @retval Others Fail to Replace user identity. + +**/ +EFI_STATUS +SaveUserIpInfo ( + IN USER_PROFILE_ENTRY * User, + IN CONST EFI_USER_INFO * NewInfo, + OUT EFI_USER_INFO **UserInfo OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *OldIpInfo; + UINTN Offset; + UINTN NextOffset; + + if ((NewInfo == NULL) || (User == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Get user old identify policy information. + // + OldIpInfo = NULL; + Status = FindUserInfoByType (User, &OldIpInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the old identity policy offset. + // + Status = FindUserInfo (User, &OldIpInfo, FALSE, &Offset); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Delete the old identity policy information. + // + NextOffset = ALIGN_VARIABLE (OldIpInfo->InfoSize) + Offset; + User->UserProfileSize -= ALIGN_VARIABLE (OldIpInfo->InfoSize); + if (Offset < User->UserProfileSize) { + CopyMem (User->ProfileInfo + Offset, User->ProfileInfo + NextOffset, User->UserProfileSize - Offset); + } + + // + // Add new user information. + // + if (User->MaxProfileSize - User->UserProfileSize < ALIGN_VARIABLE (NewInfo->InfoSize)) { + if (!ExpandUserProfile (User, ALIGN_VARIABLE (NewInfo->InfoSize))) { + return EFI_OUT_OF_RESOURCES; + } + } + + CopyMem (User->ProfileInfo + User->UserProfileSize, (VOID *) NewInfo, NewInfo->InfoSize); + if (UserInfo != NULL) { + *UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + User->UserProfileSize); + } + + User->UserProfileSize += ALIGN_VARIABLE (NewInfo->InfoSize); + + // + // Save user profile information. + // + Status = SaveNvUserProfile (User, FALSE); + return Status; +} + + +/** + Remove the provider in FindIdentity from the user identification information record. + + @param[in, out] NewInfo On entry, points to the user information to remove provider. + On return, points to the user information the provider is removed. + @param[in] FindIdentity Point to the user identity policy. + + @retval TRUE The provider is removed successfully. + @retval FALSE Fail to remove the provider. + +**/ +BOOLEAN +RemoveProvider ( + IN OUT EFI_USER_INFO **NewInfo, + IN EFI_USER_INFO_IDENTITY_POLICY *FindIdentity + ) +{ + UINTN TotalLen; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + EFI_USER_INFO *IdentifyInfo; + UINT8 *Buffer; + + IdentifyInfo = *NewInfo; + TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO); + if (TotalLen == FindIdentity->Length) { + // + // Only one credential provider in the identification policy. + // Set the new policy to be TRUE after removed the provider. + // + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (IdentifyInfo + 1); + Identity->Type = EFI_USER_INFO_IDENTITY_TRUE; + Identity->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY); + IdentifyInfo->InfoSize = sizeof (EFI_USER_INFO) + Identity->Length; + return TRUE; + } + + // + // Found the credential provider. + // + TotalLen = 0; + while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen); + if ((Identity->Type == FindIdentity->Type) && + (Identity->Length == FindIdentity->Length) && + CompareGuid ((EFI_GUID *) (Identity + 1), (EFI_GUID *) (FindIdentity + 1)) + ) { + // + // Found the credential provider to delete + // + if (Identity == (EFI_USER_INFO_IDENTITY_POLICY *)(IdentifyInfo + 1)) { + // + // It is the first item in the identification policy, delete it and the connector after it. + // + Buffer = (UINT8 *) Identity + Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY); + IdentifyInfo->InfoSize -= Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY); + TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO); + CopyMem (Identity, Buffer, TotalLen); + } else { + // + // It is not the first item in the identification policy, delete it and the connector before it. + // + Buffer = (UINT8 *) Identity + Identity->Length; + TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO); + TotalLen -= (Buffer - (UINT8 *)(IdentifyInfo + 1)); + IdentifyInfo->InfoSize -= Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY); + CopyMem ((UINT8 *) (Identity - 1), Buffer, TotalLen); + } + return TRUE; + } + + TotalLen += Identity->Length; + } + return FALSE; +} + + +/** + This function replaces the old identity policy with a new identity policy. + + This function changes user identity policy information. + If enroll new credential failed, recover the old identity policy. + + For new policy: + a. For each credential, if it is newly added, try to enroll it. + If enroll failed, try to delete the newly added ones. + + b. For each credential, if it exists in the old policy, delete old one, + and enroll new one. If failed to enroll the new one, removed it from new + identification policy. + + For old policy: + a. For each credential, if it does not exist in new one, delete it. + + @param[in] User Point to the user profile. + @param[in] Info Points to the user identity information. + @param[in] InfoSize The size of Info (Not used in this function). + @param[out] IpInfo The new identification info after modify. + + @retval EFI_SUCCESS Modify user identity policy successfully. + @retval Others Fail to modify user identity policy. + +**/ +EFI_STATUS +ModifyUserIpInfo ( + IN USER_PROFILE_ENTRY *User, + IN CONST EFI_USER_INFO *Info, + IN UINTN InfoSize, + OUT EFI_USER_INFO **IpInfo + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *OldIpInfo; + UINTN TotalLen; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + UINT32 CredentialCount; + EFI_USER_INFO *NewIpInfo; + + // + // Get user old identify policy information. + // + OldIpInfo = NULL; + Status = FindUserInfoByType (User, &OldIpInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (OldIpInfo != NULL); + + // + // Enroll new added credential provider. + // + CredentialCount = 0; + TotalLen = 0; + while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen); + if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) { + if (!FindProvider (Identity, OldIpInfo)) { + // + // The credential is NOT found in the old identity policy; add it. + // + Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length); + if (EFI_ERROR (Status)) { + break; + } + CredentialCount++; + } + } + + TotalLen += Identity->Length; + } + + if (EFI_ERROR (Status)) { + // + // Enroll new credential failed. Delete the newly enrolled credential, and return. + // + TotalLen = 0; + while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen); + if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) { + if (!FindProvider (Identity, OldIpInfo)) { + // + // The credential is NOT found in the old identity policy. Delete it. + // + if (CredentialCount == 0) { + break; + } + + ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length); + CredentialCount--; + } + } + TotalLen += Identity->Length; + } + + return EFI_DEVICE_ERROR; + } + + // + // Backup new identification policy + // + NewIpInfo = AllocateCopyPool (Info->InfoSize, Info); + ASSERT (NewIpInfo != NULL); + + // + // Enroll the credential that existed in the old identity policy. + // + TotalLen = 0; + while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen); + if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) { + if (FindProvider (Identity, OldIpInfo)) { + // + // The credential is found in the old identity policy, so delete the old credential first. + // + Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length); + if (EFI_ERROR (Status)) { + // + // Failed to delete old credential. + // + FreePool (NewIpInfo); + return EFI_DEVICE_ERROR; + } + + // + // Add the new credential. + // + Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length); + if (EFI_ERROR (Status)) { + // + // Failed to enroll the user by new identification policy. + // So removed the credential provider from the identification policy + // + RemoveProvider (&NewIpInfo, Identity); + } + } + } + TotalLen += Identity->Length; + } + + // + // Delete old credential that didn't exist in the new identity policy. + // + TotalLen = 0; + while (TotalLen < OldIpInfo->InfoSize - sizeof (EFI_USER_INFO)) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (OldIpInfo + 1) + TotalLen); + if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) { + if (!FindProvider (Identity, Info)) { + // + // The credential is NOT found in the new identity policy. Delete the old credential. + // + ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length); + } + } + TotalLen += Identity->Length; + } + + *IpInfo = NewIpInfo; + return EFI_SUCCESS; +} + + +/** + Add one new user info into the user's profile. + + @param[in] User point to the user profile + @param[in] Info Points to the user information payload. + @param[in] InfoSize The size of the user information payload, in bytes. + @param[out] UserInfo Point to the new info in user profile + @param[in] Save If TRUE, save the profile to NV flash. + If FALSE, don't need to save the profile to NV flash. + + @retval EFI_SUCCESS Add user info to user profile successfully. + @retval Others Fail to add user info to user profile. + +**/ +EFI_STATUS +AddUserInfo ( + IN USER_PROFILE_ENTRY *User, + IN UINT8 *Info, + IN UINTN InfoSize, + OUT EFI_USER_INFO **UserInfo, OPTIONAL + IN BOOLEAN Save + ) +{ + EFI_STATUS Status; + + if ((Info == NULL) || (User == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check user profile handle. + // + Status = FindUserProfile (&User, FALSE, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check user information memory size. + // + if (User->MaxProfileSize - User->UserProfileSize < ALIGN_VARIABLE (InfoSize)) { + if (!ExpandUserProfile (User, ALIGN_VARIABLE (InfoSize))) { + return EFI_OUT_OF_RESOURCES; + } + } + + // + // Add credential. + // + if (((EFI_USER_INFO *) Info)->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) { + Status = ModifyCredentialInfo ( + User, + (UINT8 *) ((EFI_USER_INFO *) Info + 1), + InfoSize - sizeof (EFI_USER_INFO) + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Add new user information. + // + CopyMem (User->ProfileInfo + User->UserProfileSize, Info, InfoSize); + if (UserInfo != NULL) { + *UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + User->UserProfileSize); + } + User->UserProfileSize += ALIGN_VARIABLE (InfoSize); + + // + // Save user profile information. + // + if (Save) { + Status = SaveNvUserProfile (User, FALSE); + } + + return Status; +} + + +/** + Get the user info from the specified user info handle. + + @param[in] User Point to the user profile. + @param[in] UserInfo Point to the user information record to get. + @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. + On exit, holds the user information. + @param[in, out] InfoSize On entry, points to the size of Info. + On return, points to the size of the user information. + @param[in] ChkRight If TRUE, check the user info attribute. + If FALSE, don't check the user info attribute. + + + @retval EFI_ACCESS_DENIED The information cannot be accessed by the current user. + @retval EFI_INVALID_PARAMETER InfoSize is NULL or UserInfo is NULL. + @retval EFI_BUFFER_TOO_SMALL The number of bytes specified by *InfoSize is too small to hold the + returned data. The actual size required is returned in *InfoSize. + @retval EFI_SUCCESS Information returned successfully. + +**/ +EFI_STATUS +GetUserInfo ( + IN USER_PROFILE_ENTRY *User, + IN EFI_USER_INFO *UserInfo, + OUT EFI_USER_INFO *Info, + IN OUT UINTN *InfoSize, + IN BOOLEAN ChkRight + ) +{ + EFI_STATUS Status; + + if ((InfoSize == NULL) || (UserInfo == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((*InfoSize != 0) && (Info == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Find the user information to get. + // + Status = FindUserInfo (User, &UserInfo, FALSE, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check information attributes. + // + if (ChkRight) { + switch (UserInfo->InfoAttribs & EFI_USER_INFO_ACCESS) { + case EFI_USER_INFO_PRIVATE: + case EFI_USER_INFO_PROTECTED: + if (User != mCurrentUser) { + return EFI_ACCESS_DENIED; + } + break; + + case EFI_USER_INFO_PUBLIC: + break; + + default: + return EFI_INVALID_PARAMETER; + break; + } + } + + // + // Get user information. + // + if (UserInfo->InfoSize > *InfoSize) { + *InfoSize = UserInfo->InfoSize; + return EFI_BUFFER_TOO_SMALL; + } + + *InfoSize = UserInfo->InfoSize; + if (Info != NULL) { + CopyMem (Info, UserInfo, *InfoSize); + } + + return EFI_SUCCESS; +} + + +/** + Delete the specified user information from user profile. + + @param[in] User Point to the user profile. + @param[in] Info Point to the user information record to delete. + @param[in] Save If TRUE, save the profile to NV flash. + If FALSE, don't need to save the profile to NV flash. + + @retval EFI_SUCCESS Delete user info from user profile successfully. + @retval Others Fail to delete user info from user profile. + +**/ +EFI_STATUS +DelUserInfo ( + IN USER_PROFILE_ENTRY *User, + IN EFI_USER_INFO *Info, + IN BOOLEAN Save + ) +{ + EFI_STATUS Status; + UINTN Offset; + UINTN NextOffset; + + // + // Check user information handle. + // + Status = FindUserInfo (User, &Info, FALSE, &Offset); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) { + return EFI_ACCESS_DENIED; + } else if (Info->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) { + Status = ModifyCredentialInfo (User, (UINT8 *) (Info + 1), Info->InfoSize - sizeof (EFI_USER_INFO)); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Delete the specified user information. + // + NextOffset = Offset + ALIGN_VARIABLE (Info->InfoSize); + User->UserProfileSize -= ALIGN_VARIABLE (Info->InfoSize); + if (Offset < User->UserProfileSize) { + CopyMem (User->ProfileInfo + Offset, User->ProfileInfo + NextOffset, User->UserProfileSize - Offset); + } + + if (Save) { + Status = SaveNvUserProfile (User, FALSE); + } + + return Status; +} + + +/** + Add or update user information. + + @param[in] User Point to the user profile. + @param[in, out] UserInfo On entry, points to the user information to modify, + or NULL to add a new UserInfo. + On return, points to the modified user information. + @param[in] Info Points to the new user information. + @param[in] InfoSize The size of Info,in bytes. + + @retval EFI_INVALID_PARAMETER UserInfo is NULL or Info is NULL. + @retval EFI_ACCESS_DENIED The record is exclusive. + @retval EFI_SUCCESS User information was successfully changed/added. + +**/ +EFI_STATUS +ModifyUserInfo ( + IN USER_PROFILE_ENTRY *User, + IN OUT EFI_USER_INFO **UserInfo, + IN CONST EFI_USER_INFO *Info, + IN UINTN InfoSize + ) +{ + EFI_STATUS Status; + UINTN PayloadLen; + EFI_USER_INFO *OldInfo; + EFI_USER_INFO *IpInfo; + + if ((UserInfo == NULL) || (Info == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (InfoSize < sizeof (EFI_USER_INFO) || InfoSize != Info->InfoSize) { + return EFI_INVALID_PARAMETER; + } + + // + // Check user information. + // + if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) { + return EFI_ACCESS_DENIED; + } + + if (!CheckUserInfo (Info)) { + return EFI_INVALID_PARAMETER; + } + + + if (*UserInfo == NULL) { + // + // Add new user information. + // + OldInfo = NULL; + do { + Status = FindUserInfoByType (User, &OldInfo, Info->InfoType); + if (EFI_ERROR (Status)) { + break; + } + ASSERT (OldInfo != NULL); + + if (((OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) || + ((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0)) { + // + // Same type can not co-exist for exclusive information. + // + return EFI_ACCESS_DENIED; + } + + // + // Check whether it exists in DB. + // + if (Info->InfoSize != OldInfo->InfoSize) { + continue; + } + + if (!CompareGuid (&OldInfo->Credential, &Info->Credential)) { + continue; + } + + PayloadLen = Info->InfoSize - sizeof (EFI_USER_INFO); + if (PayloadLen == 0) { + continue; + } + + if (CompareMem ((UINT8 *)(OldInfo + 1), (UINT8 *)(Info + 1), PayloadLen) != 0) { + continue; + } + + // + // Yes. The new info is as same as the one in profile. + // + return EFI_SUCCESS; + } while (!EFI_ERROR (Status)); + + Status = AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE); + return Status; + } + + // + // Modify existing user information. + // + OldInfo = *UserInfo; + if (OldInfo->InfoType != Info->InfoType) { + return EFI_INVALID_PARAMETER; + } + + if (((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) && + (OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) == 0) { + // + // Try to add exclusive attrib in new info. + // Check whether there is another information with the same type in profile. + // + OldInfo = NULL; + do { + Status = FindUserInfoByType (User, &OldInfo, Info->InfoType); + if (EFI_ERROR (Status)) { + break; + } + if (OldInfo != *UserInfo) { + // + // There is another information with the same type in profile. + // Therefore, can't modify existing user information to add exclusive attribute. + // + return EFI_ACCESS_DENIED; + } + } while (TRUE); + } + + if (Info->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) { + // + // For user identification policy, need to update the info in credential provider. + // + IpInfo = NULL; + Status = ModifyUserIpInfo (User, Info, InfoSize, &IpInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (IpInfo != NULL); + Status = SaveUserIpInfo (User, IpInfo, UserInfo); + if (IpInfo->InfoSize != Info->InfoSize) { + Status = EFI_DEVICE_ERROR; + } + FreePool (IpInfo); + return Status; + } + + Status = DelUserInfo (User, *UserInfo, FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + + return AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE); +} + + +/** + Delete the user profile from non-volatile memory and database. + + @param[in] User Points to the user profile. + + @retval EFI_SUCCESS Delete user from the user profile successfully. + @retval Others Fail to delete user from user profile + +**/ +EFI_STATUS +DelUserProfile ( + IN USER_PROFILE_ENTRY *User + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_USER_INFO *UserInfo; + + // + // Check whether it is in the user profile database. + // + Status = FindUserProfile (&User, FALSE, &Index); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether it is the current user. + // + if (User == mCurrentUser) { + return EFI_ACCESS_DENIED; + } + + // + // Delete user credential information. + // + UserInfo = NULL; + Status = FindUserInfoByType (User, &UserInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD); + if (Status == EFI_SUCCESS) { + Status = DelUserInfo (User, UserInfo, FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Delete user profile from the non-volatile memory. + // + Status = SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + mUserProfileDb->UserProfileNum--; + + // + // Modify user profile database. + // + if (Index != mUserProfileDb->UserProfileNum) { + mUserProfileDb->UserProfile[Index] = mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum]; + CopyMem ( + ((USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index])->UserVarName, + User->UserVarName, + sizeof (User->UserVarName) + ); + Status = SaveNvUserProfile (mUserProfileDb->UserProfile[Index], FALSE); + if (EFI_ERROR (Status)) { + return Status; + } + } + // + // Delete user profile information. + // + if (User->ProfileInfo != NULL) { + FreePool (User->ProfileInfo); + } + + FreePool (User); + return EFI_SUCCESS; +} + + +/** + Add user profile to user profile database. + + @param[out] UserProfile Point to the newly added user profile. + @param[in] ProfileSize The size of the user profile. + @param[in] ProfileInfo Point to the user profie data. + @param[in] Save If TRUE, save the new added profile to NV flash. + If FALSE, don't save the profile to NV flash. + + @retval EFI_SUCCESS Add user profile to user profile database successfully. + @retval Others Fail to add user profile to user profile database. + +**/ +EFI_STATUS +AddUserProfile ( + OUT USER_PROFILE_ENTRY **UserProfile, OPTIONAL + IN UINTN ProfileSize, + IN UINT8 *ProfileInfo, + IN BOOLEAN Save + ) +{ + EFI_STATUS Status; + USER_PROFILE_ENTRY *User; + + // + // Check the data format to be added. + // + if (!CheckProfileInfo (ProfileInfo, ProfileSize)) { + return EFI_SECURITY_VIOLATION; + } + + // + // Create user profile entry. + // + User = AllocateZeroPool (sizeof (USER_PROFILE_ENTRY)); + if (User == NULL) { + return EFI_OUT_OF_RESOURCES; + } + // + // Add the entry to the user profile database. + // + if (mUserProfileDb->UserProfileNum == mUserProfileDb->MaxProfileNum) { + if (!ExpandUsermUserProfileDb ()) { + FreePool (User); + return EFI_OUT_OF_RESOURCES; + } + } + + UnicodeSPrint ( + User->UserVarName, + sizeof (User->UserVarName), + L"User%04x", + mUserProfileDb->UserProfileNum + ); + User->UserProfileSize = 0; + User->MaxProfileSize = 0; + User->ProfileInfo = NULL; + mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum] = (EFI_USER_PROFILE_HANDLE) User; + mUserProfileDb->UserProfileNum++; + + // + // Add user profile information. + // + Status = AddUserInfo (User, ProfileInfo, ProfileSize, NULL, Save); + if (EFI_ERROR (Status)) { + DelUserProfile (User); + return Status; + } + // + // Set new user profile handle. + // + if (UserProfile != NULL) { + *UserProfile = User; + } + + return EFI_SUCCESS; +} + + +/** + This function creates a new user profile with only a new user identifier + attached and returns its handle. The user profile is non-volatile, but the + handle User can change across reboots. + + @param[out] User Handle of a new user profile. + + @retval EFI_SUCCESS User profile was successfully created. + @retval Others Fail to create user profile + +**/ +EFI_STATUS +CreateUserProfile ( + OUT USER_PROFILE_ENTRY **User + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *UserInfo; + + if (User == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Generate user id information. + // + UserInfo = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER)); + if (UserInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UserInfo->InfoType = EFI_USER_INFO_IDENTIFIER_RECORD; + UserInfo->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER); + UserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE; + GenerateUserId ((UINT8 *) (UserInfo + 1)); + + // + // Add user profile to the user profile database. + // + Status = AddUserProfile (User, UserInfo->InfoSize, (UINT8 *) UserInfo, TRUE); + FreePool (UserInfo); + return Status; +} + + +/** + Add a default user profile to user profile database. + + @retval EFI_SUCCESS A default user profile is added successfully. + @retval Others Fail to add a default user profile + +**/ +EFI_STATUS +AddDefaultUserProfile ( + VOID + ) +{ + EFI_STATUS Status; + USER_PROFILE_ENTRY *User; + EFI_USER_INFO *Info; + EFI_USER_INFO *NewInfo; + EFI_USER_INFO_CREATE_DATE CreateDate; + EFI_USER_INFO_USAGE_COUNT UsageCount; + EFI_USER_INFO_ACCESS_CONTROL *Access; + EFI_USER_INFO_IDENTITY_POLICY *Policy; + + // + // Create a user profile. + // + Status = CreateUserProfile (&User); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Allocate a buffer to add all default user information. + // + Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + INFO_PAYLOAD_SIZE); + if (Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Add user name. + // + Info->InfoType = EFI_USER_INFO_NAME_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE; + Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (mUserName); + CopyMem ((UINT8 *) (Info + 1), mUserName, sizeof (mUserName)); + NewInfo = NULL; + Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Add user profile create date record. + // + Info->InfoType = EFI_USER_INFO_CREATE_DATE_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE; + Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE); + Status = gRT->GetTime (&CreateDate, NULL); + if (EFI_ERROR (Status)) { + goto Done; + } + + CopyMem ((UINT8 *) (Info + 1), &CreateDate, sizeof (EFI_USER_INFO_CREATE_DATE)); + NewInfo = NULL; + Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Add user profile usage count record. + // + Info->InfoType = EFI_USER_INFO_USAGE_COUNT_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE; + Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT); + UsageCount = 0; + CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT)); + NewInfo = NULL; + Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Add user access right. + // + Info->InfoType = EFI_USER_INFO_ACCESS_POLICY_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE; + Access = (EFI_USER_INFO_ACCESS_CONTROL *) (Info + 1); + Access->Type = EFI_USER_INFO_ACCESS_MANAGE; + Access->Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL); + Info->InfoSize = sizeof (EFI_USER_INFO) + Access->Size; + NewInfo = NULL; + Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Add user identity policy. + // + Info->InfoType = EFI_USER_INFO_IDENTITY_POLICY_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PRIVATE | EFI_USER_INFO_EXCLUSIVE; + Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (Info + 1); + Policy->Type = EFI_USER_INFO_IDENTITY_TRUE; + Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY); + Info->InfoSize = sizeof (EFI_USER_INFO) + Policy->Length; + NewInfo = NULL; + Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize); + +Done: + FreePool (Info); + return Status; +} + + +/** + Publish current user information into EFI System Configuration Table. + + By UEFI spec, the User Identity Manager will publish the current user profile + into the EFI System Configuration Table. Currently, only the user identifier and user + name are published. + + @retval EFI_SUCCESS Current user information is published successfully. + @retval Others Fail to publish current user information + +**/ +EFI_STATUS +PublishUserTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_CONFIGURATION_TABLE *EfiConfigurationTable; + EFI_USER_INFO_TABLE *UserInfoTable; + EFI_USER_INFO *IdInfo; + EFI_USER_INFO *NameInfo; + + Status = EfiGetSystemConfigurationTable ( + &gEfiUserManagerProtocolGuid, + (VOID **) &EfiConfigurationTable + ); + if (!EFI_ERROR (Status)) { + // + // The table existed! + // + return EFI_SUCCESS; + } + + // + // Get user ID information. + // + IdInfo = NULL; + Status = FindUserInfoByType (mCurrentUser, &IdInfo, EFI_USER_INFO_IDENTIFIER_RECORD); + if (EFI_ERROR (Status)) { + return Status; + + } + // + // Get user name information. + // + NameInfo = NULL; + Status = FindUserInfoByType (mCurrentUser, &NameInfo, EFI_USER_INFO_NAME_RECORD); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Allocate a buffer for user information table. + // + UserInfoTable = (EFI_USER_INFO_TABLE *) AllocateRuntimePool ( + sizeof (EFI_USER_INFO_TABLE) + + IdInfo->InfoSize + + NameInfo->InfoSize + ); + if (UserInfoTable == NULL) { + Status = EFI_OUT_OF_RESOURCES; + return Status; + } + + UserInfoTable->Size = sizeof (EFI_USER_INFO_TABLE); + + // + // Append the user information to the user info table + // + CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) IdInfo, IdInfo->InfoSize); + UserInfoTable->Size += IdInfo->InfoSize; + + CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) NameInfo, NameInfo->InfoSize); + UserInfoTable->Size += NameInfo->InfoSize; + + Status = gBS->InstallConfigurationTable (&gEfiUserManagerProtocolGuid, (VOID *) UserInfoTable); + return Status; +} + + +/** + Get the user's identity type. + + The identify manager only supports the identity policy in which the credential + provider handles are connected by the operator 'AND' or 'OR'. + + + @param[in] User Handle of a user profile. + @param[out] PolicyType Point to the identity type. + + @retval EFI_SUCCESS Get user's identity type successfully. + @retval Others Fail to get user's identity type. + +**/ +EFI_STATUS +GetIdentifyType ( + IN EFI_USER_PROFILE_HANDLE User, + OUT UINT8 *PolicyType + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *IdentifyInfo; + UINTN TotalLen; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + + // + // Get user identify policy information. + // + IdentifyInfo = NULL; + Status = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (IdentifyInfo != NULL); + + // + // Search the user identify policy according to type. + // + TotalLen = 0; + *PolicyType = EFI_USER_INFO_IDENTITY_FALSE; + while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen); + if (Identity->Type == EFI_USER_INFO_IDENTITY_AND) { + *PolicyType = EFI_USER_INFO_IDENTITY_AND; + break; + } + + if (Identity->Type == EFI_USER_INFO_IDENTITY_OR) { + *PolicyType = EFI_USER_INFO_IDENTITY_OR; + break; + } + TotalLen += Identity->Length; + } + return EFI_SUCCESS; +} + + +/** + Identify the User by the specfied provider. + + @param[in] User Handle of a user profile. + @param[in] Provider Points to the identifir of credential provider. + + @retval EFI_INVALID_PARAMETER Provider is NULL. + @retval EFI_NOT_FOUND Fail to identify the specified user. + @retval EFI_SUCCESS User is identified successfully. + +**/ +EFI_STATUS +IdentifyByProviderId ( + IN EFI_USER_PROFILE_HANDLE User, + IN EFI_GUID *Provider + ) +{ + EFI_STATUS Status; + EFI_USER_INFO_IDENTIFIER UserId; + UINTN Index; + EFI_CREDENTIAL_LOGON_FLAGS AutoLogon; + EFI_HII_HANDLE HiiHandle; + EFI_GUID FormSetId; + EFI_FORM_ID FormId; + EFI_USER_CREDENTIAL_PROTOCOL *UserCredential; + EFI_USER_INFO *IdInfo; + + if (Provider == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check the user ID identified by the specified credential provider. + // + for (Index = 0; Index < mProviderDb->Count; Index++) { + // + // Check credential provider class. + // + UserCredential = mProviderDb->Provider[Index]; + if (CompareGuid (&UserCredential->Identifier, Provider)) { + Status = UserCredential->Select (UserCredential, &AutoLogon); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((AutoLogon & EFI_CREDENTIAL_LOGON_FLAG_AUTO) == 0) { + // + // Get credential provider form. + // + Status = UserCredential->Form ( + UserCredential, + &HiiHandle, + &FormSetId, + &FormId + ); + if (!EFI_ERROR (Status)) { + // + // Send form to get user input. + // + Status = mCallbackInfo->FormBrowser2->SendForm ( + mCallbackInfo->FormBrowser2, + &HiiHandle, + 1, + &FormSetId, + FormId, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + Status = UserCredential->User (UserCredential, User, &UserId); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = UserCredential->Deselect (UserCredential); + if (EFI_ERROR (Status)) { + return Status; + } + + if (User == NULL) { + return EFI_SUCCESS; + } + + // + // Get user ID information. + // + IdInfo = NULL; + Status = FindUserInfoByType (User, &IdInfo, EFI_USER_INFO_IDENTIFIER_RECORD); + ASSERT (IdInfo != NULL); + + if (CompareMem ((UINT8 *) (IdInfo + 1), UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) != 0) { + // + // One user name is selected, but the other's credential is given. Here no user passed. + // + break; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + + +/** + Update user information when user is logon on successfully. + + @param[in] User Points to user profile. + + @retval EFI_SUCCESS Update user information successfully. + @retval Others Fail to update user information. + +**/ +EFI_STATUS +UpdateUserInfo ( + IN USER_PROFILE_ENTRY *User + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *Info; + EFI_USER_INFO *NewInfo; + EFI_USER_INFO_CREATE_DATE Date; + EFI_USER_INFO_USAGE_COUNT UsageCount; + UINTN InfoLen; + + // + // Allocate a buffer to update user's date record and usage record. + // + InfoLen = MAX (sizeof (EFI_USER_INFO_CREATE_DATE), sizeof (EFI_USER_INFO_USAGE_COUNT)); + Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + InfoLen); + if (Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Check create date record. + // + NewInfo = NULL; + Status = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_CREATE_DATE_RECORD); + if (Status == EFI_NOT_FOUND) { + Info->InfoType = EFI_USER_INFO_CREATE_DATE_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE; + Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE); + Status = gRT->GetTime (&Date, NULL); + if (EFI_ERROR (Status)) { + FreePool (Info); + return Status; + } + + CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_CREATE_DATE)); + NewInfo = NULL; + Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize); + if (EFI_ERROR (Status)) { + FreePool (Info); + return Status; + } + } + + // + // Update usage date record. + // + NewInfo = NULL; + Status = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_DATE_RECORD); + if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) { + Info->InfoType = EFI_USER_INFO_USAGE_DATE_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE; + Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_DATE); + Status = gRT->GetTime (&Date, NULL); + if (EFI_ERROR (Status)) { + FreePool (Info); + return Status; + } + + CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_USAGE_DATE)); + Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize); + if (EFI_ERROR (Status)) { + FreePool (Info); + return Status; + } + } + + // + // Update usage count record. + // + UsageCount = 0; + NewInfo = NULL; + Status = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_COUNT_RECORD); + // + // Get usage count. + // + if (Status == EFI_SUCCESS) { + CopyMem (&UsageCount, (UINT8 *) (NewInfo + 1), sizeof (EFI_USER_INFO_USAGE_COUNT)); + } + + UsageCount++; + if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) { + Info->InfoType = EFI_USER_INFO_USAGE_COUNT_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE; + Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT); + CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT)); + Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize); + if (EFI_ERROR (Status)) { + FreePool (Info); + return Status; + } + } + + FreePool (Info); + return EFI_SUCCESS; +} + + +/** + Add a credenetial provider item in form. + + @param[in] ProviderGuid Points to the identifir of credential provider. + @param[in] OpCodeHandle Points to container for dynamic created opcodes. + +**/ +VOID +AddProviderSelection ( + IN EFI_GUID *ProviderGuid, + IN VOID *OpCodeHandle + ) +{ + EFI_HII_HANDLE HiiHandle; + EFI_STRING_ID ProvID; + CHAR16 *ProvStr; + UINTN Index; + EFI_USER_CREDENTIAL_PROTOCOL *UserCredential; + + for (Index = 0; Index < mProviderDb->Count; Index++) { + UserCredential = mProviderDb->Provider[Index]; + if (CompareGuid (&UserCredential->Identifier, ProviderGuid)) { + // + // Add credential provider selection. + // + UserCredential->Title (UserCredential, &HiiHandle, &ProvID); + ProvStr = HiiGetString (HiiHandle, ProvID, NULL); + if (ProvStr == NULL) { + continue ; + } + ProvID = HiiSetString (mCallbackInfo->HiiHandle, 0, ProvStr, NULL); + FreePool (ProvStr); + HiiCreateActionOpCode ( + OpCodeHandle, // Container for dynamic created opcodes + (EFI_QUESTION_ID)(LABEL_PROVIDER_NAME + Index), // Question ID + ProvID, // Prompt text + STRING_TOKEN (STR_NULL_STRING), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + 0 // Action String ID + ); + break; + } + } +} + + +/** + Add a username item in form. + + @param[in] Index The index of the user in the user name list. + @param[in] User Points to the user profile whose username is added. + @param[in] OpCodeHandle Points to container for dynamic created opcodes. + + @retval EFI_SUCCESS Add a username successfully. + @retval Others Fail to add a username. + +**/ +EFI_STATUS +AddUserSelection ( + IN UINT16 Index, + IN USER_PROFILE_ENTRY *User, + IN VOID *OpCodeHandle + ) +{ + EFI_STRING_ID UserName; + EFI_STATUS Status; + EFI_USER_INFO *UserInfo; + + UserInfo = NULL; + Status = FindUserInfoByType (User, &UserInfo, EFI_USER_INFO_NAME_RECORD); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Add user name selection. + // + UserName = HiiSetString (mCallbackInfo->HiiHandle, 0, (EFI_STRING) (UserInfo + 1), NULL); + if (UserName == 0) { + return EFI_OUT_OF_RESOURCES; + } + + HiiCreateGotoOpCode ( + OpCodeHandle, // Container for dynamic created opcodes + FORMID_PROVIDER_FORM, // Target Form ID + UserName, // Prompt text + STRING_TOKEN (STR_NULL_STRING), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + (UINT16) Index // Question ID + ); + + return EFI_SUCCESS; +} + + +/** + Identify the user whose identity policy does not contain the operator 'OR'. + + @param[in] User Points to the user profile. + + @retval EFI_SUCCESS The specified user is identified successfully. + @retval Others Fail to identify the user. + +**/ +EFI_STATUS +IdentifyAndTypeUser ( + IN USER_PROFILE_ENTRY *User + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *IdentifyInfo; + BOOLEAN Success; + UINTN TotalLen; + UINTN ValueLen; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + + // + // Get user identify policy information. + // + IdentifyInfo = NULL; + Status = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (IdentifyInfo != NULL); + + // + // Check each part of identification policy expression. + // + Success = FALSE; + TotalLen = 0; + while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen); + ValueLen = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY); + switch (Identity->Type) { + + case EFI_USER_INFO_IDENTITY_FALSE: + // + // Check False option. + // + Success = FALSE; + break; + + case EFI_USER_INFO_IDENTITY_TRUE: + // + // Check True option. + // + Success = TRUE; + break; + + case EFI_USER_INFO_IDENTITY_NOT: + // + // Check negative operation. + // + break; + + case EFI_USER_INFO_IDENTITY_AND: + // + // Check and operation. + // + if (!Success) { + return EFI_NOT_READY; + } + + Success = FALSE; + break; + + case EFI_USER_INFO_IDENTITY_OR: + // + // Check or operation. + // + if (Success) { + return EFI_SUCCESS; + } + break; + + case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE: + // + // Check credential provider by type. + // + break; + + case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER: + // + // Check credential provider by ID. + // + if (ValueLen != sizeof (EFI_GUID)) { + return EFI_INVALID_PARAMETER; + } + + Status = IdentifyByProviderId (User, (EFI_GUID *) (Identity + 1)); + if (EFI_ERROR (Status)) { + return Status; + } + + Success = TRUE; + break; + + default: + return EFI_INVALID_PARAMETER; + break; + } + + TotalLen += Identity->Length; + } + + if (TotalLen != IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) { + return EFI_INVALID_PARAMETER; + } + + if (!Success) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + + +/** + Identify the user whose identity policy does not contain the operator 'AND'. + + @param[in] User Points to the user profile. + + @retval EFI_SUCCESS The specified user is identified successfully. + @retval Others Fail to identify the user. + +**/ +EFI_STATUS +IdentifyOrTypeUser ( + IN USER_PROFILE_ENTRY *User + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *IdentifyInfo; + UINTN TotalLen; + UINTN ValueLen; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + + // + // Get user identify policy information. + // + IdentifyInfo = NULL; + Status = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (IdentifyInfo != NULL); + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_PROVIDER_NAME; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Add the providers that exists in the user's policy. + // + TotalLen = 0; + while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen); + ValueLen = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY); + if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) { + AddProviderSelection ((EFI_GUID *) (Identity + 1), StartOpCodeHandle); + } + + TotalLen += Identity->Length; + } + + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserManagerGuid, // Formset GUID + FORMID_PROVIDER_FORM, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + + return EFI_SUCCESS; +} + + +/** + This function processes the results of changes in configuration. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original + exporting driver. + @param ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval Others Fail to handle the action. + +**/ +EFI_STATUS +EFIAPI +UserIdentifyManagerCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + EFI_STATUS Status; + USER_PROFILE_ENTRY *User; + UINT8 PolicyType; + UINT16 Index; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + + Status = EFI_SUCCESS; + + switch (Action) { + case EFI_BROWSER_ACTION_FORM_OPEN: + { + // + // Update user Form when user Form is opened. + // This will be done only in FORM_OPEN CallBack of question with FORM_OPEN_QUESTION_ID from user Form. + // + if (QuestionId != FORM_OPEN_QUESTION_ID) { + return EFI_SUCCESS; + } + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_USER_NAME; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Add all the user profile in the user profile database. + // + for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) { + User = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index]; + AddUserSelection ((UINT16)(LABEL_USER_NAME + Index), User, StartOpCodeHandle); + } + + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserManagerGuid, // Formset GUID + FORMID_USER_FORM, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + + return EFI_SUCCESS; + } + break; + + case EFI_BROWSER_ACTION_FORM_CLOSE: + Status = EFI_SUCCESS; + break; + + case EFI_BROWSER_ACTION_CHANGING: + { + if (QuestionId >= LABEL_PROVIDER_NAME) { + // + // QuestionId comes from the second Form (Select a Credential Provider if identity + // policy is OR type). Identify the user by the selected provider. + // + Status = IdentifyByProviderId (mCurrentUser, &mProviderDb->Provider[QuestionId & 0xFFF]->Identifier); + if (Status == EFI_SUCCESS) { + mIdentified = TRUE; + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + } + return EFI_SUCCESS; + } + + // + // QuestionId comes from the first Form (Select a user to identify). + // + User = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[QuestionId & 0xFFF]; + Status = GetIdentifyType (User, &PolicyType); + if (EFI_ERROR (Status)) { + return Status; + } + + if (PolicyType == EFI_USER_INFO_IDENTITY_OR) { + // + // Identify the user by "OR" logical. + // + Status = IdentifyOrTypeUser (User); + if (EFI_ERROR (Status)) { + return Status; + } + + mCurrentUser = (EFI_USER_PROFILE_HANDLE) User; + } else { + // + // Identify the user by "AND" logical. + // + Status = IdentifyAndTypeUser (User); + if (EFI_ERROR (Status)) { + return Status; + } + + mCurrentUser = (EFI_USER_PROFILE_HANDLE) User; + mIdentified = TRUE; + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + } + } + break; + + default: + // + // All other action return unsupported. + // + Status = EFI_UNSUPPORTED; + break; + } + + + return Status; +} + + +/** + This function construct user profile database from user data saved in the Flash. + If no user is found in Flash, add one default user "administrator" in the user + profile database. + + @retval EFI_SUCCESS Init user profile database successfully. + @retval Others Fail to init user profile database. + +**/ +EFI_STATUS +InitUserProfileDb ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 *VarData; + UINTN VarSize; + UINTN CurVarSize; + CHAR16 VarName[10]; + UINTN Index; + UINT32 VarAttr; + + if (mUserProfileDb != NULL) { + // + // The user profiles had been already initialized. + // + return EFI_SUCCESS; + } + + // + // Init user profile database structure. + // + if (!ExpandUsermUserProfileDb ()) { + return EFI_OUT_OF_RESOURCES; + } + + CurVarSize = DEFAULT_PROFILE_SIZE; + VarData = AllocateZeroPool (CurVarSize); + if (VarData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all user proifle entries. + // + Index = 0; + while (TRUE) { + // + // Get variable name. + // + UnicodeSPrint ( + VarName, + sizeof (VarName), + L"User%04x", + Index + ); + Index++; + + // + // Get variable value. + // + VarSize = CurVarSize; + Status = gRT->GetVariable (VarName, &mUserManagerGuid, &VarAttr, &VarSize, VarData); + if (Status == EFI_BUFFER_TOO_SMALL) { + FreePool (VarData); + VarData = AllocatePool (VarSize); + if (VarData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + break; + } + + CurVarSize = VarSize; + Status = gRT->GetVariable (VarName, &mUserManagerGuid, &VarAttr, &VarSize, VarData); + } + + if (EFI_ERROR (Status)) { + if (Status == EFI_NOT_FOUND) { + Status = EFI_SUCCESS; + } + break; + } + + // + // Check variable attributes. + // + if (VarAttr != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)) { + Status = gRT->SetVariable (VarName, &mUserManagerGuid, VarAttr, 0, NULL); + continue; + } + + // + // Add user profile to the user profile database. + // + Status = AddUserProfile (NULL, VarSize, VarData, FALSE); + if (EFI_ERROR (Status)) { + if (Status == EFI_SECURITY_VIOLATION) { + // + // Delete invalid user profile + // + gRT->SetVariable (VarName, &mUserManagerGuid, VarAttr, 0, NULL); + } else if (Status == EFI_OUT_OF_RESOURCES) { + break; + } + } else { + // + // Delete and save the profile again if some invalid profiles are deleted. + // + if (mUserProfileDb->UserProfileNum < Index) { + gRT->SetVariable (VarName, &mUserManagerGuid, VarAttr, 0, NULL); + SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], FALSE); + } + } + } + + if (VarData != NULL) { + FreePool (VarData); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check whether the user profile database is empty. + // + if (mUserProfileDb->UserProfileNum == 0) { + Status = AddDefaultUserProfile (); + } + + return Status; +} + + +/** + This function collects all the credential providers and saves to mProviderDb. + + @retval EFI_SUCCESS Collect credential providers successfully. + @retval Others Fail to collect credential providers. + +**/ +EFI_STATUS +InitProviderInfo ( + VOID + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuf; + UINTN Index; + + if (mProviderDb != NULL) { + // + // The credential providers had been collected before. + // + return EFI_SUCCESS; + } + + // + // Try to find all the user credential provider driver. + // + HandleCount = 0; + HandleBuf = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiUserCredentialProtocolGuid, + NULL, + &HandleCount, + &HandleBuf + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get provider infomation. + // + mProviderDb = AllocateZeroPool ( + sizeof (CREDENTIAL_PROVIDER_INFO) - + sizeof (EFI_USER_CREDENTIAL_PROTOCOL *) + + HandleCount * sizeof (EFI_USER_CREDENTIAL_PROTOCOL *) + ); + if (mProviderDb == NULL) { + FreePool (HandleBuf); + return EFI_OUT_OF_RESOURCES; + } + + mProviderDb->Count = HandleCount; + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuf[Index], + &gEfiUserCredentialProtocolGuid, + (VOID **) &mProviderDb->Provider[Index] + ); + if (EFI_ERROR (Status)) { + FreePool (HandleBuf); + FreePool (mProviderDb); + mProviderDb = NULL; + return Status; + } + } + + FreePool (HandleBuf); + return EFI_SUCCESS; +} + + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in format. + @param Progress On return, points to a character in the Request string. + Points to the string's null terminator if request was successful. + Points to the most recent '&' before the first failing name/value + pair (or the beginning of the string if the failure is in the + first name/value pair) if the request was not successful. + @param Results A null-terminated Unicode string in format which + has all values filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +FakeExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + *Progress = Request; + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration A null-terminated Unicode string in format. + @param Progress A pointer to a string filled in with the offset of the most + recent '&' before the first failing name/value pair (or the + beginning of the string if the failure is in the first + name/value pair) or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +FakeRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_NOT_FOUND; +} + + +/** + This function initialize the data mainly used in form browser. + + @retval EFI_SUCCESS Initialize form data successfully. + @retval Others Fail to Initialize form data. + +**/ +EFI_STATUS +InitFormBrowser ( + VOID + ) +{ + EFI_STATUS Status; + USER_MANAGER_CALLBACK_INFO *CallbackInfo; + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HII_STRING_PROTOCOL *HiiString; + EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2; + + // + // Initialize driver private data. + // + CallbackInfo = AllocateZeroPool (sizeof (USER_MANAGER_CALLBACK_INFO)); + if (CallbackInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CallbackInfo->Signature = USER_MANAGER_SIGNATURE; + CallbackInfo->ConfigAccess.ExtractConfig = FakeExtractConfig; + CallbackInfo->ConfigAccess.RouteConfig = FakeRouteConfig; + CallbackInfo->ConfigAccess.Callback = UserIdentifyManagerCallback; + + // + // Locate Hii Database protocol. + // + Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase); + if (EFI_ERROR (Status)) { + return Status; + } + CallbackInfo->HiiDatabase = HiiDatabase; + + // + // Locate HiiString protocol. + // + Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString); + if (EFI_ERROR (Status)) { + return Status; + } + CallbackInfo->HiiString = HiiString; + + // + // Locate Formbrowser2 protocol. + // + Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2); + if (EFI_ERROR (Status)) { + return Status; + } + + CallbackInfo->FormBrowser2 = FormBrowser2; + CallbackInfo->DriverHandle = NULL; + + // + // Install Device Path Protocol and Config Access protocol to driver handle. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &CallbackInfo->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &CallbackInfo->ConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish HII data. + // + CallbackInfo->HiiHandle = HiiAddPackages ( + &mUserManagerGuid, + CallbackInfo->DriverHandle, + UserIdentifyManagerStrings, + UserIdentifyManagerVfrBin, + NULL + ); + if (CallbackInfo->HiiHandle == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mCallbackInfo = CallbackInfo; + + return EFI_SUCCESS; +} + + +/** + Identify the user whose identification policy supports auto logon. + + @param[in] ProviderIndex The provider index in the provider list. + @param[out] User Points to user user profile if a user is identified successfully. + + @retval EFI_SUCCESS Identify a user with the specified provider successfully. + @retval Others Fail to identify a user. + +**/ +EFI_STATUS +IdentifyAutoLogonUser ( + IN UINTN ProviderIndex, + OUT USER_PROFILE_ENTRY **User + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *Info; + UINT8 PolicyType; + + Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER)); + if (Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Info->InfoType = EFI_USER_INFO_IDENTIFIER_RECORD; + Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER); + + // + // Identify the specified credential provider's auto logon user. + // + Status = mProviderDb->Provider[ProviderIndex]->User ( + mProviderDb->Provider[ProviderIndex], + NULL, + (EFI_USER_INFO_IDENTIFIER *) (Info + 1) + ); + if (EFI_ERROR (Status)) { + FreePool (Info); + return Status; + } + + // + // Find user with the specified user ID. + // + *User = NULL; + Status = FindUserProfileByInfo (User, NULL, Info, Info->InfoSize); + FreePool (Info); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = GetIdentifyType ((EFI_USER_PROFILE_HANDLE) * User, &PolicyType); + if (PolicyType == EFI_USER_INFO_IDENTITY_AND) { + // + // The identified user need also identified by other credential provider. + // This can handle through select user. + // + return EFI_NOT_READY; + } + + return Status; +} + + +/** + Check whether the given console is ready. + + @param[in] ProtocolGuid Points to the protocol guid of sonsole . + + @retval TRUE The given console is ready. + @retval FALSE The given console is not ready. + +**/ +BOOLEAN +CheckConsole ( + EFI_GUID *ProtocolGuid + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuf; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + // + // Try to find all the handle driver. + // + HandleCount = 0; + HandleBuf = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + ProtocolGuid, + NULL, + &HandleCount, + &HandleBuf + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + for (Index = 0; Index < HandleCount; Index++) { + DevicePath = DevicePathFromHandle (HandleBuf[Index]); + if (DevicePath != NULL) { + FreePool (HandleBuf); + return TRUE; + } + } + FreePool (HandleBuf); + return FALSE; +} + + +/** + Check whether the console is ready. + + @retval TRUE The console is ready. + @retval FALSE The console is not ready. + +**/ +BOOLEAN +IsConsoleReady ( + VOID + ) +{ + if (!CheckConsole (&gEfiSimpleTextOutProtocolGuid)) { + return FALSE; + } + + if (!CheckConsole (&gEfiSimpleTextInProtocolGuid)) { + if (!CheckConsole (&gEfiSimpleTextInputExProtocolGuid)) { + return FALSE; + } + } + + return TRUE; +} + + +/** + Identify a user to logon. + + @param[out] User Points to user user profile if a user is identified successfully. + + @retval EFI_SUCCESS Identify a user successfully. + +**/ +EFI_STATUS +IdentifyUser ( + OUT USER_PROFILE_ENTRY **User + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_CREDENTIAL_LOGON_FLAGS AutoLogon; + EFI_USER_INFO *IdentifyInfo; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + EFI_USER_CREDENTIAL_PROTOCOL *UserCredential; + USER_PROFILE_ENTRY *UserEntry; + + // + // Initialize credential providers. + // + InitProviderInfo (); + + // + // Initialize user profile database. + // + InitUserProfileDb (); + + // + // If only one user in system, and its identify policy is TRUE, then auto logon. + // + if (mUserProfileDb->UserProfileNum == 1) { + UserEntry = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[0]; + IdentifyInfo = NULL; + Status = FindUserInfoByType (UserEntry, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (IdentifyInfo != NULL); + + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1)); + if (Identity->Type == EFI_USER_INFO_IDENTITY_TRUE) { + mCurrentUser = (EFI_USER_PROFILE_HANDLE) UserEntry; + UpdateUserInfo (UserEntry); + *User = UserEntry; + return EFI_SUCCESS; + } + } + + // + // Find and login the default & AutoLogon user. + // + for (Index = 0; Index < mProviderDb->Count; Index++) { + UserCredential = mProviderDb->Provider[Index]; + Status = UserCredential->Default (UserCredential, &AutoLogon); + if (EFI_ERROR (Status)) { + continue; + } + + if ((AutoLogon & (EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO)) != 0) { + Status = IdentifyAutoLogonUser (Index, &UserEntry); + if (Status == EFI_SUCCESS) { + mCurrentUser = (EFI_USER_PROFILE_HANDLE) UserEntry; + UpdateUserInfo (UserEntry); + *User = UserEntry; + return EFI_SUCCESS; + } + } + } + + if (!IsConsoleReady ()) { + // + // The console is still not ready for user selection. + // + return EFI_ACCESS_DENIED; + } + + // + // Select a user and identify it. + // + mCallbackInfo->FormBrowser2->SendForm ( + mCallbackInfo->FormBrowser2, + &mCallbackInfo->HiiHandle, + 1, + &mUserManagerGuid, + 0, + NULL, + NULL + ); + + if (mIdentified) { + *User = (USER_PROFILE_ENTRY *) mCurrentUser; + UpdateUserInfo (*User); + return EFI_SUCCESS; + } + + return EFI_ACCESS_DENIED; +} + + +/** + An empty function to pass error checking of CreateEventEx (). + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +InternalEmptyFuntion ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ +} + + +/** + Create, Signal, and Close the User Profile Changed event. + +**/ +VOID +SignalEventUserProfileChanged ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + InternalEmptyFuntion, + NULL, + &gEfiEventUserProfileChangedGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + gBS->SignalEvent (Event); + gBS->CloseEvent (Event); +} + + +/** + Create a new user profile. + + This function creates a new user profile with only a new user identifier attached and returns + its handle. The user profile is non-volatile, but the handle User can change across reboots. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[out] User On return, points to the new user profile handle. + The user profile handle is unique only during this boot. + + @retval EFI_SUCCESS User profile was successfully created. + @retval EFI_ACCESS_DENIED Current user does not have sufficient permissions to create a + user profile. + @retval EFI_UNSUPPORTED Creation of new user profiles is not supported. + @retval EFI_INVALID_PARAMETER The User parameter is NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileCreate ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + OUT EFI_USER_PROFILE_HANDLE *User + ) +{ + EFI_STATUS Status; + + if ((This == NULL) || (User == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check the right of the current user. + // + if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) { + if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_OTHERS)) { + return EFI_ACCESS_DENIED; + } + } + + // + // Create new user profile + // + Status = CreateUserProfile ((USER_PROFILE_ENTRY **) User); + if (EFI_ERROR (Status)) { + return EFI_ACCESS_DENIED; + } + return EFI_SUCCESS; +} + + +/** + Delete an existing user profile. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[in] User User profile handle. + + @retval EFI_SUCCESS User profile was successfully deleted. + @retval EFI_ACCESS_DENIED Current user does not have sufficient permissions to delete a user + profile or there is only one user profile. + @retval EFI_UNSUPPORTED Deletion of new user profiles is not supported. + @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile. + +**/ +EFI_STATUS +EFIAPI +UserProfileDelete ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User + ) +{ + EFI_STATUS Status; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check the right of the current user. + // + if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) { + return EFI_ACCESS_DENIED; + } + + // + // Delete user profile. + // + Status = DelUserProfile (User); + if (EFI_ERROR (Status)) { + if (Status != EFI_INVALID_PARAMETER) { + return EFI_ACCESS_DENIED; + } + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + + +/** + Enumerate all of the enrolled users on the platform. + + This function returns the next enrolled user profile. To retrieve the first user profile handle, + point User at a NULL. Each subsequent call will retrieve another user profile handle until there + are no more, at which point User will point to NULL. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[in, out] User On entry, points to the previous user profile handle or NULL to + start enumeration. On exit, points to the next user profile handle + or NULL if there are no more user profiles. + + @retval EFI_SUCCESS Next enrolled user profile successfully returned. + @retval EFI_ACCESS_DENIED Next enrolled user profile was not successfully returned. + @retval EFI_INVALID_PARAMETER The User parameter is NULL. +**/ +EFI_STATUS +EFIAPI +UserProfileGetNext ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN OUT EFI_USER_PROFILE_HANDLE *User + ) +{ + EFI_STATUS Status; + + if ((This == NULL) || (User == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Status = FindUserProfile ((USER_PROFILE_ENTRY **) User, TRUE, NULL); + if (EFI_ERROR (Status)) { + return EFI_ACCESS_DENIED; + } + return EFI_SUCCESS; +} + + +/** + Return the current user profile handle. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[out] CurrentUser On return, points to the current user profile handle. + + @retval EFI_SUCCESS Current user profile handle returned successfully. + @retval EFI_INVALID_PARAMETER The CurrentUser parameter is NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileCurrent ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + OUT EFI_USER_PROFILE_HANDLE *CurrentUser + ) +{ + // + // Get current user profile. + // + if ((This == NULL) || (CurrentUser == NULL)) { + return EFI_INVALID_PARAMETER; + } + + *CurrentUser = mCurrentUser; + return EFI_SUCCESS; +} + + +/** + Identify a user. + + Identify the user and, if authenticated, returns the user handle and changes the current + user profile. All user information marked as private in a previously selected profile + is no longer available for inspection. + Whenever the current user profile is changed then the an event with the GUID + EFI_EVENT_GROUP_USER_PROFILE_CHANGED is signaled. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[out] User On return, points to the user profile handle for the current + user profile. + + @retval EFI_SUCCESS User was successfully identified. + @retval EFI_ACCESS_DENIED User was not successfully identified. + @retval EFI_INVALID_PARAMETER The User parameter is NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileIdentify ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + OUT EFI_USER_PROFILE_HANDLE *User + ) +{ + EFI_STATUS Status; + + if ((This == NULL) || (User == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (mCurrentUser != NULL) { + *User = mCurrentUser; + return EFI_SUCCESS; + } + + // + // Identify user + // + Status = IdentifyUser ((USER_PROFILE_ENTRY **) User); + if (EFI_ERROR (Status)) { + return EFI_ACCESS_DENIED; + } + + // + // Publish the user info into the EFI system configuration table. + // + PublishUserTable (); + + // + // Signal User Profile Changed event. + // + SignalEventUserProfileChanged (); + return EFI_SUCCESS; +} + +/** + Find a user using a user information record. + + This function searches all user profiles for the specified user information record. + The search starts with the user information record handle following UserInfo and + continues until either the information is found or there are no more user profiles. + A match occurs when the Info.InfoType field matches the user information record + type and the user information record data matches the portion of Info. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[in, out] User On entry, points to the previously returned user profile + handle, or NULL to start searching with the first user profile. + On return, points to the user profile handle, or NULL if not + found. + @param[in, out] UserInfo On entry, points to the previously returned user information + handle, or NULL to start searching with the first. On return, + points to the user information handle of the user information + record, or NULL if not found. Can be NULL, in which case only + one user information record per user can be returned. + @param[in] Info Points to the buffer containing the user information to be + compared to the user information record. If the user information + record data is empty, then only the user information record type + is compared. If InfoSize is 0, then the user information record + must be empty. + + @param[in] InfoSize The size of Info, in bytes. + + @retval EFI_SUCCESS User information was found. User points to the user profile + handle, and UserInfo points to the user information handle. + @retval EFI_NOT_FOUND User information was not found. User points to NULL, and + UserInfo points to NULL. + @retval EFI_INVALID_PARAMETER User is NULL. Or Info is NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileFind ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN OUT EFI_USER_PROFILE_HANDLE *User, + IN OUT EFI_USER_INFO_HANDLE *UserInfo OPTIONAL, + IN CONST EFI_USER_INFO *Info, + IN UINTN InfoSize + ) +{ + EFI_STATUS Status; + UINTN Size; + + if ((This == NULL) || (User == NULL) || (Info == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (InfoSize == 0) { + // + // If InfoSize is 0, then the user information record must be empty. + // + if (Info->InfoSize != sizeof (EFI_USER_INFO)) { + return EFI_INVALID_PARAMETER; + } + } else { + if (InfoSize != Info->InfoSize) { + return EFI_INVALID_PARAMETER; + } + } + Size = Info->InfoSize; + + // + // Find user profile accdoring to user information. + // + Status = FindUserProfileByInfo ( + (USER_PROFILE_ENTRY **) User, + (EFI_USER_INFO **) UserInfo, + (EFI_USER_INFO *) Info, + Size + ); + if (EFI_ERROR (Status)) { + *User = NULL; + if (UserInfo != NULL) { + *UserInfo = NULL; + } + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + + +/** + Return information attached to the user. + + This function returns user information. The format of the information is described in User + Information. The function may return EFI_ACCESS_DENIED if the information is marked private + and the handle specified by User is not the current user profile. The function may return + EFI_ACCESS_DENIED if the information is marked protected and the information is associated + with a credential provider for which the user has not been authenticated. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[in] User Handle of the user whose profile will be retrieved. + @param[in] UserInfo Handle of the user information data record. + @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On exit, + holds the user information. If the buffer is too small to hold the + information, then EFI_BUFFER_TOO_SMALL is returned and InfoSize is + updated to contain the number of bytes actually required. + @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the size + of the user information. + + @retval EFI_SUCCESS Information returned successfully. + @retval EFI_ACCESS_DENIED The information about the specified user cannot be accessed by the + current user. + @retval EFI_BUFFER_TOO_SMALL The number of bytes specified by *InfoSize is too small to hold the + returned data. The actual size required is returned in *InfoSize. + @retval EFI_NOT_FOUND User does not refer to a valid user profile or UserInfo does not refer + to a valid user info handle. + @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileGetInfo ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + IN EFI_USER_INFO_HANDLE UserInfo, + OUT EFI_USER_INFO *Info, + IN OUT UINTN *InfoSize + ) +{ + EFI_STATUS Status; + + if ((This == NULL) || (InfoSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((*InfoSize != 0) && (Info == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((User == NULL) || (UserInfo == NULL)) { + return EFI_NOT_FOUND; + } + + Status = GetUserInfo (User, UserInfo, Info, InfoSize, TRUE); + if (EFI_ERROR (Status)) { + if (Status == EFI_BUFFER_TOO_SMALL) { + return EFI_BUFFER_TOO_SMALL; + } + return EFI_ACCESS_DENIED; + } + return EFI_SUCCESS; +} + + +/** + Add or update user information. + + This function changes user information. If NULL is pointed to by UserInfo, then a new user + information record is created and its handle is returned in UserInfo. Otherwise, the existing + one is replaced. + If EFI_USER_INFO_EXCLUSIVE is specified in Info and a user information record of the same + type already exists in the user profile, then EFI_ACCESS_DENIED will be returned and UserInfo + will point to the handle of the existing record. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[in] User Handle of the user whose profile will be retrieved. + @param[in, out] UserInfo Handle of the user information data record. + @param[in] Info On entry, points to a buffer of at least *InfoSize bytes. On exit, + holds the user information. If the buffer is too small to hold the + information, then EFI_BUFFER_TOO_SMALL is returned and InfoSize is + updated to contain the number of bytes actually required. + @param[in] InfoSize On entry, points to the size of Info. On return, points to the size + of the user information. + + @retval EFI_SUCCESS Information returned successfully. + @retval EFI_ACCESS_DENIED The record is exclusive. + @retval EFI_SECURITY_VIOLATION The current user does not have permission to change the specified + user profile or user information record. + @retval EFI_NOT_FOUND User does not refer to a valid user profile or UserInfo does not + refer to a valid user info handle. + @retval EFI_INVALID_PARAMETER UserInfo is NULL or Info is NULL. +**/ +EFI_STATUS +EFIAPI +UserProfileSetInfo ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + IN OUT EFI_USER_INFO_HANDLE *UserInfo, + IN CONST EFI_USER_INFO *Info, + IN UINTN InfoSize + ) +{ + EFI_STATUS Status; + + if ((This == NULL) || (User == NULL) || (UserInfo == NULL) || (Info == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check the right of the current user. + // + if (User != mCurrentUser) { + if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) { + if (*UserInfo != NULL) { + // + // Can't update info in other profiles without MANAGE right. + // + return EFI_SECURITY_VIOLATION; + } + + if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_OTHERS)) { + // + // Can't add info into other profiles. + // + return EFI_SECURITY_VIOLATION; + } + } + } + + if (User == mCurrentUser) { + if (CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_SELF)) { + // + // Only identify policy can be added/updated. + // + if (Info->InfoType != EFI_USER_INFO_IDENTITY_POLICY_RECORD) { + return EFI_SECURITY_VIOLATION; + } + } + } + + // + // Modify user information. + // + Status = ModifyUserInfo (User, (EFI_USER_INFO **) UserInfo, Info, InfoSize); + if (EFI_ERROR (Status)) { + if (Status == EFI_ACCESS_DENIED) { + return EFI_ACCESS_DENIED; + } + return EFI_SECURITY_VIOLATION; + } + return EFI_SUCCESS; +} + + +/** + Called by credential provider to notify of information change. + + This function allows the credential provider to notify the User Identity Manager when user status + has changed while deselected. + If the User Identity Manager doesn't support asynchronous changes in credentials, then this function + should return EFI_UNSUPPORTED. + If the User Identity Manager supports this, it will call User() to get the user identifier and then + GetNextInfo() and GetInfo() in the User Credential Protocol to get all of the information from the + credential and add it. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[in] Changed Handle on which is installed an instance of the EFI_USER_CREDENTIAL_PROTOCOL + where the user has changed. + + @retval EFI_SUCCESS The User Identity Manager has handled the notification. + @retval EFI_NOT_READY The function was called while the specified credential provider was not selected. + @retval EFI_UNSUPPORTED The User Identity Manager doesn't support asynchronous notifications. + +**/ +EFI_STATUS +EFIAPI +UserProfileNotify ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_HANDLE Changed + ) +{ + EFI_STATUS Status; + EFI_USER_CREDENTIAL_PROTOCOL *Provider; + EFI_USER_INFO_IDENTIFIER UserId; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO_HANDLE UserInfo2; + UINTN InfoSize; + EFI_USER_INFO *Info; + USER_PROFILE_ENTRY *User; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = gBS->HandleProtocol ( + Changed, + &gEfiUserCredentialProtocolGuid, + (VOID **) &Provider + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = Provider->User (Provider, NULL, &UserId); + if (EFI_ERROR (Status)) { + return EFI_NOT_READY; + } + + // + // Find user with the UserId. + // + User = NULL; + while (TRUE) { + // + // Find next user profile. + // + Status = FindUserProfile (&User, TRUE, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Find the user information. + // + Info = NULL; + FindUserInfoByType (User, &Info, EFI_USER_INFO_IDENTIFIER_RECORD); + if (CompareMem ((UINT8 *) (Info + 1), UserId, sizeof (UserId)) == 0) { + // + // Found the infomation record. + // + break; + } + } + + UserInfo = NULL; + do { + // + // Get user info handle. + // + Status = Provider->GetNextInfo(Provider, &UserInfo); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + // + // Get the user information from the user info handle. + // + InfoSize = 0; + Status = Provider->GetInfo(Provider, UserInfo, NULL, &InfoSize); + if (EFI_ERROR (Status)) { + if (Status == EFI_BUFFER_TOO_SMALL) { + Info = AllocateZeroPool (InfoSize); + if (Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = Provider->GetInfo(Provider, UserInfo, Info, &InfoSize); + if (EFI_ERROR (Status)) { + FreePool (Info); + break; + } + } + break; + } + + // + // Save the user information. + // + UserInfo2 = NULL; + Status = UserProfileSetInfo (&gUserIdentifyManager, (EFI_USER_PROFILE_HANDLE)User, &UserInfo2, Info, InfoSize); + FreePool (Info); + if (EFI_ERROR (Status)) { + break; + } + } while (TRUE); + + return Status; +} + + +/** + Delete user information. + + Delete the user information attached to the user profile specified by the UserInfo. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[in] User Handle of the user whose information will be deleted. + @param[in] UserInfo Handle of the user information to remove. + + @retval EFI_SUCCESS User information deleted successfully. + @retval EFI_NOT_FOUND User information record UserInfo does not exist in the user profile. + @retval EFI_ACCESS_DENIED The current user does not have permission to delete this user information. + +**/ +EFI_STATUS +EFIAPI +UserProfileDeleteInfo ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + IN EFI_USER_INFO_HANDLE UserInfo + ) +{ + EFI_STATUS Status; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Check the right of the current user. + // + if (User != mCurrentUser) { + if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) { + return EFI_ACCESS_DENIED; + } + } + + // + // Delete user information. + // + Status = DelUserInfo (User, UserInfo, TRUE); + if (EFI_ERROR (Status)) { + if (Status == EFI_NOT_FOUND) { + return EFI_NOT_FOUND; + } + return EFI_ACCESS_DENIED; + } + return EFI_SUCCESS; +} + + +/** + Enumerate user information of all the enrolled users on the platform. + + This function returns the next user information record. To retrieve the first user + information record handle, point UserInfo at a NULL. Each subsequent call will retrieve + another user information record handle until there are no more, at which point UserInfo + will point to NULL. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[in] User Handle of the user whose information will be deleted. + @param[in, out] UserInfo Handle of the user information to remove. + + @retval EFI_SUCCESS User information returned. + @retval EFI_NOT_FOUND No more user information found. + @retval EFI_INVALID_PARAMETER UserInfo is NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileGetNextInfo ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + IN OUT EFI_USER_INFO_HANDLE *UserInfo + ) +{ + if ((This == NULL) || (UserInfo == NULL)) { + return EFI_INVALID_PARAMETER; + } + // + // Get next user information entry. + // + return FindUserInfo (User, (EFI_USER_INFO **) UserInfo, TRUE, NULL); +} + + +/** + Main entry for this driver. + + @param[in] ImageHandle Image handle this driver. + @param[in] SystemTable Pointer to SystemTable. + + @retval EFI_SUCESS This function always complete successfully. + +**/ +EFI_STATUS +EFIAPI +UserIdentifyManagerInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + + EFI_STATUS Status; + + // + // Initiate form browser. + // + InitFormBrowser (); + + // + // Install protocol interfaces for the User Identity Manager. + // + Status = gBS->InstallProtocolInterface ( + &mCallbackInfo->DriverHandle, + &gEfiUserManagerProtocolGuid, + EFI_NATIVE_INTERFACE, + &gUserIdentifyManager + ); + ASSERT_EFI_ERROR (Status); + + LoadDeferredImageInit (ImageHandle); + return EFI_SUCCESS; +} + + diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h new file mode 100644 index 0000000000..b1e078a03e --- /dev/null +++ b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h @@ -0,0 +1,413 @@ +/** @file + The header file for User identify Manager driver. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _USER_IDENTIFY_MANAGER_H_ +#define _USER_IDENTIFY_MANAGER_H_ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "UserIdentifyManagerData.h" + +// +// This is the generated IFR binary data for each formset defined in VFR. +// This data array is ready to be used as input of HiiAddPackages() to +// create a packagelist. +// +extern UINT8 UserIdentifyManagerVfrBin[]; + +// +// This is the generated String package data for all .UNI files. +// This data array is ready to be used as input of HiiAddPackages() to +// create a packagelist. +// +extern UINT8 UserIdentifyManagerStrings[]; + +#define USER_NUMBER_INC 32 +#define DEFAULT_PROFILE_SIZE 512 +#define INFO_PAYLOAD_SIZE 64 + +// +// Credential Provider Information. +// +typedef struct { + UINTN Count; + EFI_USER_CREDENTIAL_PROTOCOL *Provider[1]; +} CREDENTIAL_PROVIDER_INFO; + +// +// Internal user profile entry. +// +typedef struct { + UINTN MaxProfileSize; + UINTN UserProfileSize; + CHAR16 UserVarName[9]; + UINT8 *ProfileInfo; +} USER_PROFILE_ENTRY; + +// +// Internal user profile database. +// +typedef struct { + UINTN UserProfileNum; + UINTN MaxProfileNum; + EFI_USER_PROFILE_HANDLE UserProfile[1]; +} USER_PROFILE_DB; + +#define USER_MANAGER_SIGNATURE SIGNATURE_32 ('U', 'I', 'M', 'S') + +typedef struct { + UINTN Signature; + EFI_HANDLE DriverHandle; + EFI_HII_HANDLE HiiHandle; + + // + // Consumed protocol. + // + EFI_HII_DATABASE_PROTOCOL *HiiDatabase; + EFI_HII_STRING_PROTOCOL *HiiString; + EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting; + EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2; + + // + // Produced protocol. + // + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; +} USER_MANAGER_CALLBACK_INFO; + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +/** + Register an event notification function for the user profile changed. + + @param[in] ImageHandle Image handle this driver. + +**/ +VOID +LoadDeferredImageInit ( + IN EFI_HANDLE ImageHandle + ); + + +/** + This function creates a new user profile with only + a new user identifier attached and returns its handle. + The user profile is non-volatile, but the handle User + can change across reboots. + + @param[in] This Protocol EFI_USER_MANAGER_PROTOCOL instance + pointer. + @param[out] User Handle of a new user profile. + + @retval EFI_SUCCESS User profile was successfully created. + @retval EFI_ACCESS_DENIED Current user does not have sufficient permissions + to create a user profile. + @retval EFI_UNSUPPORTED Creation of new user profiles is not supported. + @retval EFI_INVALID_PARAMETER User is NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileCreate ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + OUT EFI_USER_PROFILE_HANDLE *User + ); + + +/** + Delete an existing user profile. + + @param This Protocol EFI_USER_MANAGER_PROTOCOL instance + pointer. + @param User User profile handle. + + @retval EFI_SUCCESS User profile was successfully deleted. + @retval EFI_ACCESS_DENIED Current user does not have sufficient permissions + to delete a user profile or there is only one + user profile. + @retval EFI_UNSUPPORTED Deletion of new user profiles is not supported. + @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile. + +**/ +EFI_STATUS +EFIAPI +UserProfileDelete ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User + ); + + +/** + Get next user profile from the user profile database. + + @param[in] This Protocol EFI_USER_MANAGER_PROTOCOL instance + pointer. + @param[in, out] User User profile handle. + + @retval EFI_SUCCESS Next enrolled user profile successfully returned. + @retval EFI_INVALID_PARAMETER User is NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileGetNext ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN OUT EFI_USER_PROFILE_HANDLE *User + ); + + +/** + This function returns the current user profile handle. + + @param[in] This Protocol EFI_USER_MANAGER_PROTOCOL instance pointer. + @param[out] CurrentUser User profile handle. + + @retval EFI_SUCCESS Current user profile handle returned successfully. + @retval EFI_INVALID_PARAMETER CurrentUser is NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileCurrent ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + OUT EFI_USER_PROFILE_HANDLE *CurrentUser + ); + + +/** + Identify the user and, if authenticated, returns the user handle and changes + the current user profile. + + @param This Protocol EFI_USER_MANAGER_PROTOCOL instance pointer. + @param CurrentUser User profile handle. + + @retval EFI_SUCCESS User was successfully identified. + @retval EFI_INVALID_PARAMETER User is NULL. + @retval EFI_ACCESS_DENIED User was not successfully identified. + +**/ +EFI_STATUS +EFIAPI +UserProfileIdentify ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + OUT EFI_USER_PROFILE_HANDLE *User + ); + + +/** + Find a user using a user information record. + + This function searches all user profiles for the specified user information record. + The search starts with the user information record handle following UserInfo and + continues until either the information is found or there are no more user profiles. + A match occurs when the Info.InfoType field matches the user information record + type and the user information record data matches the portion of Info passed the + EFI_USER_INFO header. + + @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL. + @param[in, out] User On entry, points to the previously returned user profile + handle, or NULL to start searching with the first user profile. + On return, points to the user profile handle, or NULL if not + found. + @param[in, out] UserInfo On entry, points to the previously returned user information + handle, or NULL to start searching with the first. On return, + points to the user information handle of the user information + record, or NULL if not found. Can be NULL, in which case only + one user information record per user can be returned. + @param[in] Info Points to the buffer containing the user information to be + compared to the user information record. If NULL, then only + the user information record type is compared. If InfoSize is 0, + then the user information record must be empty. + + @param[in] InfoSize The size of Info, in bytes. + + @retval EFI_SUCCESS User information was found. User points to the user profile handle, + and UserInfo points to the user information handle. + @retval EFI_NOT_FOUND User information was not found. User points to NULL and UserInfo + points to NULL. + +**/ +EFI_STATUS +EFIAPI +UserProfileFind ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN OUT EFI_USER_PROFILE_HANDLE *User, + IN OUT EFI_USER_INFO_HANDLE *UserInfo OPTIONAL, + IN CONST EFI_USER_INFO *Info, + IN UINTN InfoSize + ); + + +/** + This function returns user information. + + @param This Protocol EFI_USER_MANAGER_PROTOCOL instance + pointer. + @param User Handle of the user whose profile will be + retrieved. + @param UserInfo Handle of the user information data record. + @param Info On entry, points to a buffer of at least + *InfoSize bytes. On exit, holds the user + information. + @param InfoSize On entry, points to the size of Info. On return, + points to the size of the user information. + + @retval EFI_SUCCESS Information returned successfully. + @retval EFI_ACCESS_DENIED The information about the specified user cannot + be accessed by the current user. + EFI_BUFFER_TOO_SMALL- The number of bytes + specified by *InfoSize is too small to hold the + returned data. + +**/ +EFI_STATUS +EFIAPI +UserProfileGetInfo ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + IN EFI_USER_INFO_HANDLE UserInfo, + OUT EFI_USER_INFO *Info, + IN OUT UINTN *InfoSize + ); + + +/** + This function changes user information. + + @param This Protocol EFI_USER_MANAGER_PROTOCOL instance + pointer. + @param User Handle of the user whose profile will be + retrieved. + @param UserInfo Handle of the user information data record. + @param Info Points to the user information. + @param InfoSize The size of Info, in bytes. + + @retval EFI_SUCCESS User profile information was successfully + changed/added. + @retval EFI_ACCESS_DENIED The record is exclusive. + @retval EFI_SECURITY_VIOLATION The current user does not have permission to + change the specified user profile or user + information record. + +**/ +EFI_STATUS +EFIAPI +UserProfileSetInfo ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + IN OUT EFI_USER_INFO_HANDLE *UserInfo, + IN CONST EFI_USER_INFO *Info, + IN UINTN InfoSize + ); + + +/** + This function allows the credential provider to notify the User Identity Manager + when user status has changed while deselected. + + @param This Protocol EFI_USER_MANAGER_PROTOCOL instance + pointer. + @param Changed Points to the instance of the + EFI_USER_CREDENTIAL_PROTOCOL where the user has + changed. + + @retval EFI_SUCCESS The User Identity Manager has handled the + notification. + @retval EFI_NOT_READY The function was called while the specified + credential provider was not selected. + @retval EFI_UNSUPPORTED The User Identity Manager doesn't support + asynchronous notifications. + +**/ +EFI_STATUS +EFIAPI +UserProfileNotify ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_HANDLE Changed + ); + + +/** + Delete the user information attached to the user profile specified by the UserInfo. + + @param This Protocol EFI_USER_MANAGER_PROTOCOL instance pointer. + @param User Handle of the user whose profile will be retrieved. + @param UserInfo Handle of the user information data record. + + @retval EFI_SUCCESS User information deleted successfully. + @retval EFI_ACCESS_DENIED The current user does not have permission to + delete this user in-formation. + @retval EFI_NOT_FOUND User information record UserInfo does not exist + in the user pro-file. + +**/ +EFI_STATUS +EFIAPI +UserProfileDeleteInfo ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + IN EFI_USER_INFO_HANDLE UserInfo + ); + + +/** + This function returns the next user information record. + + @param This Protocol EFI_USER_MANAGER_PROTOCOL instance pointer. + @param User Handle of the user whose profile will be retrieved. + @param UserInfo Handle of the user information data record. + + @retval EFI_SUCCESS User information returned. + @retval EFI_NOT_FOUND No more user information found. + +**/ +EFI_STATUS +EFIAPI +UserProfileGetNextInfo ( + IN CONST EFI_USER_MANAGER_PROTOCOL *This, + IN EFI_USER_PROFILE_HANDLE User, + IN OUT EFI_USER_INFO_HANDLE *UserInfo + ); + +#endif diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h new file mode 100644 index 0000000000..d91de101f7 --- /dev/null +++ b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h @@ -0,0 +1,42 @@ +/** @file + Data structure used by the user identify manager driver. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _USER_IDENTIFY_MANAGER_DATA_H_ +#define _USER_IDENTIFY_MANAGER_DATA_H_ + +#include "UserIdentifyManagerStrDefs.h" + +// +// Guid used in user profile saving and in form browser. +// +#define USER_IDENTIFY_MANAGER_GUID \ + { \ + 0x3ccd3dd8, 0x8d45, 0x4fed, { 0x96, 0x2d, 0x2b, 0x38, 0xcd, 0x82, 0xb3, 0xc4 } \ + } + +// +// Forms definition. +// +#define FORMID_USER_FORM 1 +#define FORMID_PROVIDER_FORM 2 + +// +// Labels definition. +// +#define LABEL_USER_NAME 0x1000 +#define LABEL_PROVIDER_NAME 0x3000 +#define LABEL_END 0xffff +#define FORM_OPEN_QUESTION_ID 0xfffe + +#endif diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf new file mode 100644 index 0000000000..d5fccea342 --- /dev/null +++ b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf @@ -0,0 +1,62 @@ +## @file +# Component description file for user identify manager driver. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[defines] + INF_VERSION = 0x00010005 + BASE_NAME = UserIdentifyManager + FILE_GUID = C5D3191B-27D5-4873-8DF2-628136991A21 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = UserIdentifyManagerInit + +[sources] + UserIdentifyManager.c + LoadDeferredImage.c + UserIdentifyManager.h + UserIdentifyManagerData.h + UserIdentifyManagerStrings.uni + UserIdentifyManagerVfr.Vfr + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + MemoryAllocationLib + BaseMemoryLib + DebugLib + HiiLib + UefiLib + +[Guids] + gEfiIfrTianoGuid ## CONSUMES ## Guid + gEfiEventUserProfileChangedGuid ## CONSUMES ## Guid + +[Protocols] + gEfiFormBrowser2ProtocolGuid ## CONSUMES + gEfiHiiDatabaseProtocolGuid ## CONSUMES + gEfiUserCredentialProtocolGuid ## CONSUMES + gEfiDeferredImageLoadProtocolGuid ## CONSUMES + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiUserManagerProtocolGuid ## PRODUCES + gEfiSimpleTextOutProtocolGuid + gEfiSimpleTextInProtocolGuid + gEfiSimpleTextInputExProtocolGuid + +[Depex] + gEfiHiiDatabaseProtocolGuid AND + gEfiHiiStringProtocolGuid AND + gEfiFormBrowser2ProtocolGuid diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..8ae44897154ffd7888700af1a524876b7d2910c0 GIT binary patch literal 2696 zcmdUxU2hUm5QgVg6aT{oZ(378z0(+DDO8CS2p?9jn&q=36q;pQ?VnelcMb?Eq@m%a zX0vcwEIk!Q(ahiao+>isgaz?2z%b zz2terEWcR2VtvHCisuwh6Xx=e;6vZo;|pzpon!W;vGT1P66^wMVdF|-u$QQJne|x)i%|aX{Cj-m zF`MC-Xo{rhfg?qkvsR{E5H5Q~>_;Xpg?z|PsD$wTL@NU0I-V>i5gEnaL*0e_Y>~Y% zrOu{0C58F7R^(9+1xBTrIKKs?3H2-f!}uIY7u0>aDjTumpvm<|Xj}_TD`%TAGLte$7tm_`P$x5gtQ?xd^(owvib&9UyerNp5jxg(NRTfbK z{)&D3>u2S?3JVRoM={H5eCc*6I#%`4bNE$Pj=ZZ?Z`CLddU?uWt3B0V4(~a)+q4-{ z#k`$*RyjtU$0-%o`Is-PLbPQkhEv!g-=3xhvXbBYPY=ts<*o7!ber&gsSXV` literal 0 HcmV?d00001 diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr new file mode 100644 index 0000000000..ebe8195c73 --- /dev/null +++ b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr @@ -0,0 +1,44 @@ +/** @file + User identify manager formset. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UserIdentifyManagerData.h" + +formset + guid = USER_IDENTIFY_MANAGER_GUID, + title = STRING_TOKEN(STR_TITLE), + help = STRING_TOKEN(STR_NULL_STRING), + classguid = USER_IDENTIFY_MANAGER_GUID, + + form formid = FORMID_USER_FORM, + title = STRING_TOKEN(STR_USER_SELECT); + + suppressif TRUE; + text + help = STRING_TOKEN(STR_NULL_STRING), + text = STRING_TOKEN(STR_NULL_STRING), + text = STRING_TOKEN(STR_NULL_STRING), + flags = INTERACTIVE, + key = FORM_OPEN_QUESTION_ID; + endif; + + label LABEL_USER_NAME; + label LABEL_END; + endform; + + form formid = FORMID_PROVIDER_FORM, + title = STRING_TOKEN(STR_PROVIDER_SELECT); + label LABEL_PROVIDER_NAME; + label LABEL_END; + endform; +endformset; \ No newline at end of file diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c new file mode 100644 index 0000000000..eb96c8edf6 --- /dev/null +++ b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c @@ -0,0 +1,372 @@ +/** @file + The functions to add a user profile. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UserProfileManager.h" + + +/** + Get user name from the popup windows. + + @param[in, out] UserNameLen On entry, point to UserName buffer lengh, in bytes. + On exit, point to input user name length, in bytes. + @param[out] UserName The buffer to hold the input user name. + + @retval EFI_ABORTED It is given up by pressing 'ESC' key. + @retval EFI_NOT_READY Not a valid input at all. + @retval EFI_SUCCESS Get a user name successfully. + +**/ +EFI_STATUS +GetUserNameInput ( + IN OUT UINTN *UserNameLen, + OUT CHAR16 *UserName + ) +{ + EFI_INPUT_KEY Key; + UINTN NameLen; + CHAR16 Name[USER_NAME_LENGTH]; + + NameLen = 0; + while (TRUE) { + Name[NameLen] = L'_'; + Name[NameLen + 1] = L'\0'; + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Input User Name", + L"---------------------", + Name, + NULL + ); + // + // Check key. + // + if (Key.ScanCode == SCAN_NULL) { + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + // + // Add the null terminator. + // + Name[NameLen] = 0; + NameLen++; + break; + } else if ((Key.UnicodeChar == CHAR_NULL) || + (Key.UnicodeChar == CHAR_TAB) || + (Key.UnicodeChar == CHAR_LINEFEED) + ) { + continue; + } else { + if (Key.UnicodeChar == CHAR_BACKSPACE) { + if (NameLen > 0) { + NameLen--; + } + } else { + Name[NameLen] = Key.UnicodeChar; + NameLen++; + if (NameLen + 1 == USER_NAME_LENGTH) { + // + // Add the null terminator. + // + Name[NameLen] = 0; + NameLen++; + break; + } + } + } + } + + if (Key.ScanCode == SCAN_ESC) { + return EFI_ABORTED; + } + } + + if (NameLen <= 1) { + return EFI_NOT_READY; + } + + if (*UserNameLen < NameLen * sizeof (CHAR16)) { + return EFI_NOT_READY; + } + + *UserNameLen = NameLen * sizeof (CHAR16); + CopyMem (UserName, Name, *UserNameLen); + + return EFI_SUCCESS; +} + +/** + Set a user's username. + + @param[in] User Handle of a user profile . + @param[in] UserNameLen The lengh of UserName. + @param[in] UserName Point to the buffer of user name. + + @retval EFI_NOT_READY The usernme in mAddUserName had been used. + @retval EFI_SUCCESS Change the user's username successfully with + username in mAddUserName. + +**/ +EFI_STATUS +SetUserName ( + IN EFI_USER_PROFILE_HANDLE User, + IN UINTN UserNameLen, + IN CHAR16 *UserName + ) +{ + EFI_STATUS Status; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_PROFILE_HANDLE TempUser; + EFI_USER_INFO *NewUserInfo; + + NewUserInfo = AllocateZeroPool (sizeof (EFI_USER_INFO) + UserNameLen); + ASSERT (NewUserInfo != NULL); + + NewUserInfo->InfoType = EFI_USER_INFO_NAME_RECORD; + NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | + EFI_USER_INFO_PUBLIC | + EFI_USER_INFO_EXCLUSIVE; + NewUserInfo->InfoSize = (UINT32) (sizeof (EFI_USER_INFO) + UserNameLen); + CopyMem ((UINT8 *) (NewUserInfo + 1), UserName, UserNameLen); + TempUser = NULL; + Status = mUserManager->Find ( + mUserManager, + &TempUser, + NULL, + NewUserInfo, + NewUserInfo->InfoSize + ); + if (!EFI_ERROR (Status)) { + // + // The user name had been used, return error. + // + FreePool (NewUserInfo); + return EFI_NOT_READY; + } + + UserInfo = NULL; + mUserManager->SetInfo ( + mUserManager, + User, + &UserInfo, + NewUserInfo, + NewUserInfo->InfoSize + ); + FreePool (NewUserInfo); + return EFI_SUCCESS; +} + + +/** + Set create date of the specified user. + + @param[in] User Handle of a user profile. + +**/ +VOID +SetCreateDate ( + IN EFI_USER_PROFILE_HANDLE User + ) +{ + EFI_STATUS Status; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO_CREATE_DATE Date; + EFI_USER_INFO *NewUserInfo; + + NewUserInfo = AllocateZeroPool ( + sizeof (EFI_USER_INFO) + + sizeof (EFI_USER_INFO_CREATE_DATE) + ); + ASSERT (NewUserInfo != NULL); + + NewUserInfo->InfoType = EFI_USER_INFO_CREATE_DATE_RECORD; + NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | + EFI_USER_INFO_PUBLIC | + EFI_USER_INFO_EXCLUSIVE; + NewUserInfo->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE); + Status = gRT->GetTime (&Date, NULL); + if (EFI_ERROR (Status)) { + FreePool (NewUserInfo); + return ; + } + + CopyMem ((UINT8 *) (NewUserInfo + 1), &Date, sizeof (EFI_USER_INFO_CREATE_DATE)); + UserInfo = NULL; + mUserManager->SetInfo ( + mUserManager, + User, + &UserInfo, + NewUserInfo, + NewUserInfo->InfoSize + ); + FreePool (NewUserInfo); +} + + +/** + Set the default identity policy of the specified user. + + @param[in] User Handle of a user profile. + +**/ +VOID +SetIdentityPolicy ( + IN EFI_USER_PROFILE_HANDLE User + ) +{ + EFI_USER_INFO_IDENTITY_POLICY *Policy; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO *NewUserInfo; + + NewUserInfo = AllocateZeroPool ( + sizeof (EFI_USER_INFO) + + sizeof (EFI_USER_INFO_IDENTITY_POLICY) + ); + ASSERT (NewUserInfo != NULL); + + Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (NewUserInfo + 1); + Policy->Type = EFI_USER_INFO_IDENTITY_TRUE; + Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY); + + NewUserInfo->InfoType = EFI_USER_INFO_IDENTITY_POLICY_RECORD; + NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | + EFI_USER_INFO_PRIVATE | + EFI_USER_INFO_EXCLUSIVE; + NewUserInfo->InfoSize = sizeof (EFI_USER_INFO) + Policy->Length; + UserInfo = NULL; + mUserManager->SetInfo ( + mUserManager, + User, + &UserInfo, + NewUserInfo, + NewUserInfo->InfoSize + ); + FreePool (NewUserInfo); +} + + +/** + Set the default access policy of the specified user. + + @param[in] User Handle of a user profile. + +**/ +VOID +SetAccessPolicy ( + IN EFI_USER_PROFILE_HANDLE User + ) +{ + EFI_USER_INFO_ACCESS_CONTROL *Control; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO *NewUserInfo; + + NewUserInfo = AllocateZeroPool ( + sizeof (EFI_USER_INFO) + + sizeof (EFI_USER_INFO_ACCESS_CONTROL) + ); + ASSERT (NewUserInfo != NULL); + + Control = (EFI_USER_INFO_ACCESS_CONTROL *) (NewUserInfo + 1); + Control->Type = EFI_USER_INFO_ACCESS_ENROLL_SELF; + Control->Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL); + + NewUserInfo->InfoType = EFI_USER_INFO_ACCESS_POLICY_RECORD; + NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | + EFI_USER_INFO_PUBLIC | + EFI_USER_INFO_EXCLUSIVE; + NewUserInfo->InfoSize = sizeof (EFI_USER_INFO) + Control->Size; + UserInfo = NULL; + mUserManager->SetInfo ( + mUserManager, + User, + &UserInfo, + NewUserInfo, + NewUserInfo->InfoSize + ); + FreePool (NewUserInfo); +} + + +/** + Add a new user profile into the user profile database. + +**/ +VOID +CallAddUser ( + VOID + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + EFI_USER_PROFILE_HANDLE User; + UINTN UserNameLen; + CHAR16 UserName[USER_NAME_LENGTH]; + CHAR16 *QuestionStr; + CHAR16 *PromptStr; + + QuestionStr = NULL; + PromptStr = NULL; + + // + // Get user name to add. + // + UserNameLen = sizeof (UserName); + Status = GetUserNameInput (&UserNameLen, UserName); + if (EFI_ERROR (Status)) { + if (Status != EFI_ABORTED) { + QuestionStr = GetStringById (STRING_TOKEN (STR_GET_USERNAME_FAILED)); + PromptStr = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); + goto Done; + } + return ; + } + + // + // Create a new user profile. + // + User = NULL; + Status = mUserManager->Create (mUserManager, &User); + if (EFI_ERROR (Status)) { + QuestionStr = GetStringById (STRING_TOKEN (STR_CREATE_PROFILE_FAILED)); + PromptStr = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); + } else { + // + // Add default user information. + // + Status = SetUserName (User, UserNameLen, UserName); + if (EFI_ERROR (Status)) { + QuestionStr = GetStringById (STRING_TOKEN (STR_USER_ALREADY_EXISTED)); + PromptStr = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); + goto Done; + } + + SetCreateDate (User); + SetIdentityPolicy (User); + SetAccessPolicy (User); + + QuestionStr = GetStringById (STRING_TOKEN (STR_CREATE_PROFILE_SUCCESS)); + PromptStr = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); + } + +Done: + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + QuestionStr, + L"", + PromptStr, + NULL + ); + FreePool (QuestionStr); + FreePool (PromptStr); +} + diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c new file mode 100644 index 0000000000..d0295b731b --- /dev/null +++ b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c @@ -0,0 +1,314 @@ +/** @file + The functions to delete a user profile. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UserProfileManager.h" + +/** + Get the username from the specified user. + + @param[in] User Handle of a user profile. + + @retval EFI_STRING_ID The String Id of the user's username. + +**/ +EFI_STRING_ID +GetUserName ( + IN EFI_USER_PROFILE_HANDLE User + ) +{ + EFI_STATUS Status; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO *Info; + UINTN InfoSize; + UINTN MemSize; + UINTN NameLen; + CHAR16 UserName[USER_NAME_LENGTH]; + EFI_STRING_ID UserId; + + // + // Allocate user information memory. + // + MemSize = sizeof (EFI_USER_INFO) + 63; + Info = AllocateZeroPool (MemSize); + ASSERT (Info != NULL); + + // + // Get user name information. + // + UserInfo = NULL; + while (TRUE) { + InfoSize = MemSize; + // + // Get next user information. + // + Status = mUserManager->GetNextInfo ( + mUserManager, + User, + &UserInfo + ); + if (EFI_ERROR (Status)) { + break; + } + + Status = mUserManager->GetInfo ( + mUserManager, + User, + UserInfo, + Info, + &InfoSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + MemSize = InfoSize; + FreePool (Info); + Info = AllocateZeroPool (MemSize); + ASSERT (Info != NULL); + + Status = mUserManager->GetInfo ( + mUserManager, + User, + UserInfo, + Info, + &InfoSize + ); + } + // + // Check user information. + // + if (Status == EFI_SUCCESS) { + if (Info->InfoType == EFI_USER_INFO_NAME_RECORD) { + NameLen = Info->InfoSize - sizeof (EFI_USER_INFO); + if (NameLen > USER_NAME_LENGTH * sizeof (CHAR16)) { + NameLen = USER_NAME_LENGTH * sizeof (CHAR16); + } + ASSERT (NameLen >= sizeof (CHAR16)); + CopyMem (UserName, (UINT8 *) (Info + 1), NameLen); + UserName[NameLen / sizeof (CHAR16) - 1] = 0; + UserId = HiiSetString ( + mCallbackInfo->HiiHandle, + 0, + UserName, + NULL + ); + if (UserId != 0) { + FreePool (Info); + return UserId; + } + } + } + } + + FreePool (Info); + return 0; +} + + +/** + Add a username item in form. + + @param[in] User Points to the user profile whose username is added. + @param[in] Index The index of the user in the user name list + @param[in] OpCodeHandle Points to container for dynamic created opcodes. + +**/ +VOID +AddUserToForm ( + IN EFI_USER_PROFILE_HANDLE User, + IN UINT16 Index, + IN VOID *OpCodeHandle + ) +{ + EFI_STRING_ID NameId; + + // + // Get user name + // + NameId = GetUserName (User); + if (NameId == 0) { + return ; + } + + // + // Create user name option. + // + switch (Index & KEY_FIRST_FORM_MASK) { + case KEY_MODIFY_USER: + HiiCreateGotoOpCode ( + OpCodeHandle, // Container for dynamic created opcodes + FORMID_USER_INFO, // Target Form ID + NameId, // Prompt text + STRING_TOKEN (STR_NULL_STRING), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + Index // Question ID + ); + break; + + case KEY_DEL_USER: + HiiCreateActionOpCode ( + OpCodeHandle, // Container for dynamic created opcodes + Index, // Question ID + NameId, // Prompt text + STRING_TOKEN (STR_NULL_STRING), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + 0 // Action String ID + ); + break; + + default: + break; + } +} + + +/** + Delete the user specified by UserIndex in user profile database. + + @param[in] UserIndex The index of user in the user name list + to be deleted. + +**/ +VOID +DeleteUser ( + IN UINT8 UserIndex + ) +{ + EFI_STATUS Status; + EFI_USER_PROFILE_HANDLE User; + EFI_INPUT_KEY Key; + + // + // Find specified user profile and delete it. + // + User = NULL; + Status = mUserManager->GetNext (mUserManager, &User); + if (EFI_ERROR (Status)) { + goto Done; + } + + while (UserIndex > 1) { + Status = mUserManager->GetNext (mUserManager, &User); + if (EFI_ERROR (Status)) { + goto Done; + } + UserIndex--; + } + + if (UserIndex == 1) { + Status = mUserManager->Delete (mUserManager, User); + if (EFI_ERROR (Status)) { + goto Done; + } + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Delete User Succeed!", + L"", + L"Please Press Any Key to Continue ...", + NULL + ); + return ; + } + +Done: + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Delete User Failed!", + L"", + L"Please Press Any Key to Continue ...", + NULL + ); +} + + +/** + Display user select form, cab select a user to delete. + +**/ +VOID +SelectUserToDelete ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 Index; + EFI_USER_PROFILE_HANDLE User; + EFI_USER_PROFILE_HANDLE CurrentUser; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_USER_DEL_FUNC; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Add each user can be deleted. + // + User = NULL; + Index = 1; + mUserManager->Current (mUserManager, &CurrentUser); + while (TRUE) { + Status = mUserManager->GetNext (mUserManager, &User); + if (EFI_ERROR (Status)) { + break; + } + + if (User != CurrentUser) { + AddUserToForm ( + User, + (UINT16)(KEY_DEL_USER | KEY_SELECT_USER | Index), + StartOpCodeHandle + ); + } + Index++; + } + + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserProfileManagerGuid, // Formset GUID + FORMID_DEL_USER, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c new file mode 100644 index 0000000000..74c979d58e --- /dev/null +++ b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c @@ -0,0 +1,806 @@ +/** @file + This driver is a configuration tool for adding, deleting or modifying user + profiles, including gathering the necessary information to ascertain their + identity in the future, updating user access policy and identification + policy, etc. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UserProfileManager.h" + +EFI_GUID mUserProfileManagerGuid = USER_PROFILE_MANAGER_GUID; +EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL; +CREDENTIAL_PROVIDER_INFO *mProviderInfo = NULL; +UINT8 mProviderChoice; +UINT8 mConncetLogical; +USER_INFO_ACCESS mAccessInfo; +USER_INFO mUserInfo; +USER_PROFILE_MANAGER_CALLBACK_INFO *mCallbackInfo; +HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + {0xad2e3474, 0x93e6, 0x488b, {0x93, 0x19, 0x64, 0x88, 0xfc, 0x68, 0x1f, 0x16}} + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + + +/** + Get string by string id from HII Interface. + + + @param[in] Id String ID to get the string from. + + @retval CHAR16 * String from ID. + @retval NULL If error occurs. + +**/ +CHAR16 * +GetStringById ( + IN EFI_STRING_ID Id + ) +{ + // + // Get the current string for the current Language. + // + return HiiGetString (mCallbackInfo->HiiHandle, Id, NULL); +} + + +/** + This function gets all the credential providers in the system and saved them + to mProviderInfo. + + @retval EFI_SUCESS Init credential provider database successfully. + @retval Others Fail to init credential provider database. + +**/ +EFI_STATUS +InitProviderInfo ( + VOID + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuf; + UINTN Index; + + // + // Try to find all the user credential provider driver. + // + HandleCount = 0; + HandleBuf = NULL; + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiUserCredentialProtocolGuid, + NULL, + &HandleCount, + &HandleBuf + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get provider infomation. + // + if (mProviderInfo != NULL) { + FreePool (mProviderInfo); + } + mProviderInfo = AllocateZeroPool ( + sizeof (CREDENTIAL_PROVIDER_INFO) - + sizeof (EFI_USER_CREDENTIAL_PROTOCOL *) + + HandleCount * sizeof (EFI_USER_CREDENTIAL_PROTOCOL *) + ); + if (mProviderInfo == NULL) { + FreePool (HandleBuf); + return EFI_OUT_OF_RESOURCES; + } + + mProviderInfo->Count = HandleCount; + for (Index = 0; Index < HandleCount; Index++) { + Status = gBS->HandleProtocol ( + HandleBuf[Index], + &gEfiUserCredentialProtocolGuid, + (VOID **) &mProviderInfo->Provider[Index] + ); + if (EFI_ERROR (Status)) { + FreePool (HandleBuf); + FreePool (mProviderInfo); + mProviderInfo = NULL; + return Status; + } + } + + FreePool (HandleBuf); + return EFI_SUCCESS; +} + + +/** + This function processes changes in user profile configuration. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original + exporting driver. + @param ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval Others Fail to handle the action. + +**/ +EFI_STATUS +EFIAPI +UserProfileManagerCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + UINT32 CurrentAccessRight; + CHAR16 *QuestionStr; + CHAR16 *PromptStr; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + EFI_USER_PROFILE_HANDLE CurrentUser; + + Status = EFI_SUCCESS; + + switch (Action) { + case EFI_BROWSER_ACTION_FORM_OPEN: + { + // + // Update user manage Form when user manage Form is opened. + // This will be done only in FORM_OPEN CallBack of question with QUESTIONID_USER_MANAGE from user manage Form. + // + if (QuestionId != QUESTIONID_USER_MANAGE) { + return EFI_SUCCESS; + } + + // + // Get current user + // + CurrentUser = NULL; + mUserManager->Current (mUserManager, &CurrentUser); + if (CurrentUser == NULL) { + DEBUG ((DEBUG_ERROR, "Error: current user does not exist!\n")); + return EFI_NOT_READY; + } + + // + // Get current user's right information. + // + Status = GetAccessRight (&CurrentAccessRight); + if (EFI_ERROR (Status)) { + CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF; + } + + // + // Init credential provider information. + // + Status = InitProviderInfo (); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_USER_MANAGE_FUNC; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Add user profile option. + // + if ((CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) || + (CurrentAccessRight == EFI_USER_INFO_ACCESS_ENROLL_OTHERS) + ) { + HiiCreateActionOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + KEY_ADD_USER, // Question ID + STRING_TOKEN (STR_ADD_USER_TITLE), // Prompt text + STRING_TOKEN (STR_ADD_USER_HELP), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + 0 // Action String ID + ); + } + + // + // Add modify user profile option. + // + HiiCreateGotoOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + FORMID_MODIFY_USER, // Target Form ID + STRING_TOKEN (STR_MODIFY_USER_TITLE), // Prompt text + STRING_TOKEN (STR_MODIFY_USER_HELP), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + KEY_MODIFY_USER // Question ID + ); + + // + // Add delete user profile option + // + if (CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) { + HiiCreateGotoOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + FORMID_DEL_USER, // Target Form ID + STRING_TOKEN (STR_DELETE_USER_TITLE), // Prompt text + STRING_TOKEN (STR_DELETE_USER_HELP), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + KEY_DEL_USER // Question ID + ); + } + + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserProfileManagerGuid, // Formset GUID + FORMID_USER_MANAGE, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + + return EFI_SUCCESS; + } + break; + + case EFI_BROWSER_ACTION_FORM_CLOSE: + Status = EFI_SUCCESS; + break; + + case EFI_BROWSER_ACTION_CHANGING: + { + // + // Handle the request from form. + // + if ((Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Judge first 2 bits. + // + switch (QuestionId & KEY_FIRST_FORM_MASK) { + // + // Add user profile operation. + // + case KEY_ADD_USER: + CallAddUser (); + break; + + // + // Delete user profile operation. + // + case KEY_DEL_USER: + // + // Judge next 2 bits. + // + switch (QuestionId & KEY_SECOND_FORM_MASK) { + // + // Enter delete user profile form. + // + case KEY_ENTER_NEXT_FORM: + SelectUserToDelete (); + break; + + // + // Delete specified user profile. + // + case KEY_SELECT_USER: + DeleteUser ((UINT8) QuestionId); + // + // Update select user form after delete a user. + // + SelectUserToDelete (); + break; + + default: + break; + } + break; + + // + // Modify user profile operation. + // + case KEY_MODIFY_USER: + // + // Judge next 2 bits. + // + switch (QuestionId & KEY_SECOND_FORM_MASK) { + // + // Enter modify user profile form. + // + case KEY_ENTER_NEXT_FORM: + SelectUserToModify (); + break; + + // + // Enter user profile information form. + // + case KEY_SELECT_USER: + // + // Judge next 3 bits. + // + switch (QuestionId & KEY_MODIFY_INFO_MASK) { + // + // Display user information form. + // + case KEY_ENTER_NEXT_FORM: + ModifyUserInfo ((UINT8) QuestionId); + break; + + // + // Modify user name. + // + case KEY_MODIFY_NAME: + ModifyUserName (); + // + // Update username in parent form. + // + SelectUserToModify (); + break; + + // + // Modify identity policy. + // + case KEY_MODIFY_IP: + // + // Judge next 3 bits + // + switch (QuestionId & KEY_MODIFY_IP_MASK) { + // + // Display identity policy modify form. + // + case KEY_ENTER_NEXT_FORM: + ModifyIdentityPolicy (); + break; + + // + // Change credential provider option. + // + case KEY_MODIFY_PROV: + mProviderChoice = Value->u8; + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + break; + + // + // Change logical connector. + // + case KEY_MODIFY_CONN: + mConncetLogical = Value->u8; + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + break; + + // + // Save option. + // + case KEY_ADD_IP_OP: + AddIdentityPolicyItem (); + break; + + // + // Return to user profile information form. + // + case KEY_IP_RETURN_UIF: + SaveIdentityPolicy (); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + break; + + default: + break; + } + break; + + // + // Modify access policy. + // + case KEY_MODIFY_AP: + // + // Judge next 3 bits. + // + switch (QuestionId & KEY_MODIFY_AP_MASK) { + // + // Display access policy modify form. + // + case KEY_ENTER_NEXT_FORM: + ModidyAccessPolicy (); + break; + + // + // Change access right choice. + // + case KEY_MODIFY_RIGHT: + mAccessInfo.AccessRight = Value->u8; + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + break; + + // + // Change setup choice. + // + case KEY_MODIFY_SETUP: + mAccessInfo.AccessSetup= Value->u8; + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + break; + + // + // Change boot order choice. + // + case KEY_MODIFY_BOOT: + mAccessInfo.AccessBootOrder = Value->u32; + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + break; + + // + // Load device path form. + // + case KEY_MODIFY_LOAD: + // + // Judge next 2 bits. + // + switch (QuestionId & KEY_DISPLAY_DP_MASK) { + // + // Permit load device path. + // + case KEY_PERMIT_MODIFY: + DisplayLoadPermit (); + break; + + // + // Forbid load device path. + // + case KEY_FORBID_MODIFY: + DisplayLoadForbid (); + break; + + default: + break; + } + break; + + // + // Connect device path form. + // + case KEY_MODIFY_CONNECT: + // + // Judge next 2 bits. + // + switch (QuestionId & KEY_DISPLAY_DP_MASK) { + // + // Permit connect device path. + // + case KEY_PERMIT_MODIFY: + DisplayConnectPermit (); + break; + + // + // Forbid connect device path. + // + case KEY_FORBID_MODIFY: + DisplayConnectForbid (); + break; + + default: + break; + } + break; + + // + // Return to user profile information form. + // + case KEY_AP_RETURN_UIF: + SaveAccessPolicy (); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + break; + + default: + break; + } + break; + + default: + break; + } + break; + + // + // Access policy device path modified. + // + case KEY_MODIFY_AP_DP: + // + // Judge next 2 bits. + // + switch (QuestionId & KEY_MODIFY_DP_MASK) { + // + // Load permit device path modified. + // + case KEY_LOAD_PERMIT_MODIFY: + QuestionStr = GetStringById (STRING_TOKEN (STR_MOVE_TO_FORBID_LIST)); + PromptStr = GetStringById (STRING_TOKEN (STR_PRESS_KEY_CONTINUE)); + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + QuestionStr, + L"", + PromptStr, + NULL + ); + FreePool (QuestionStr); + FreePool (PromptStr); + if (Key.UnicodeChar != CHAR_CARRIAGE_RETURN) { + break; + } + + AddToForbidLoad ((UINT16)(QuestionId & (KEY_MODIFY_DP_MASK - 1))); + DisplayLoadPermit (); + break; + + // + // Load forbid device path modified. + // + case KEY_LOAD_FORBID_MODIFY: + QuestionStr = GetStringById (STRING_TOKEN (STR_MOVE_TO_PERMIT_LIST)); + PromptStr = GetStringById (STRING_TOKEN (STR_PRESS_KEY_CONTINUE)); + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + QuestionStr, + L"", + PromptStr, + NULL + ); + FreePool (QuestionStr); + FreePool (PromptStr); + if (Key.UnicodeChar != CHAR_CARRIAGE_RETURN) { + break; + } + + DeleteFromForbidLoad ((UINT16)(QuestionId & (KEY_MODIFY_DP_MASK - 1))); + DisplayLoadForbid (); + break; + + // + // Connect permit device path modified. + // + case KEY_CONNECT_PERMIT_MODIFY: + break; + + // + // Connect forbid device path modified. + // + case KEY_CONNECT_FORBID_MODIFY: + break; + + default: + break; + } + break; + + default: + break; + } + break; + + default: + break; + } + } + break; + + default: + // + // All other action return unsupported. + // + Status = EFI_UNSUPPORTED; + break; + } + + + return Status; +} + + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in format. + @param Progress On return, points to a character in the Request string. + Points to the string's null terminator if request was successful. + Points to the most recent '&' before the first failing name/value + pair (or the beginning of the string if the failure is in the + first name/value pair) if the request was not successful. + @param Results A null-terminated Unicode string in format which + has all values filled in for the names in the Request string. + String to be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +FakeExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + *Progress = Request; + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration A null-terminated Unicode string in format. + @param Progress A pointer to a string filled in with the offset of the most + recent '&' before the first failing name/value pair (or the + beginning of the string if the failure is in the first + name/value pair) or the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +FakeRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_NOT_FOUND; +} + + +/** + Main entry for this driver. + + @param ImageHandle Image handle this driver. + @param SystemTable Pointer to SystemTable. + + @retval EFI_SUCESS This function always complete successfully. + +**/ +EFI_STATUS +EFIAPI +UserProfileManagerInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + USER_PROFILE_MANAGER_CALLBACK_INFO *CallbackInfo; + + Status = gBS->LocateProtocol ( + &gEfiUserManagerProtocolGuid, + NULL, + (VOID **) &mUserManager + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + // + // Initialize driver private data. + // + ZeroMem (&mUserInfo, sizeof (mUserInfo)); + ZeroMem (&mAccessInfo, sizeof (mAccessInfo)); + + CallbackInfo = AllocateZeroPool (sizeof (USER_PROFILE_MANAGER_CALLBACK_INFO)); + ASSERT (CallbackInfo != NULL); + + CallbackInfo->Signature = USER_PROFILE_MANAGER_SIGNATURE; + CallbackInfo->ConfigAccess.ExtractConfig = FakeExtractConfig; + CallbackInfo->ConfigAccess.RouteConfig = FakeRouteConfig; + CallbackInfo->ConfigAccess.Callback = UserProfileManagerCallback; + CallbackInfo->DriverHandle = NULL; + + // + // Install Device Path Protocol and Config Access protocol to driver handle. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &CallbackInfo->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &CallbackInfo->ConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Publish HII data. + // + CallbackInfo->HiiHandle = HiiAddPackages ( + &mUserProfileManagerGuid, + CallbackInfo->DriverHandle, + UserProfileManagerStrings, + UserProfileManagerVfrBin, + NULL + ); + ASSERT (CallbackInfo->HiiHandle != NULL); + mCallbackInfo = CallbackInfo; + + return Status; +} + + diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h new file mode 100644 index 0000000000..b7098dc7b6 --- /dev/null +++ b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h @@ -0,0 +1,387 @@ +/** @file + The header file for user profile manager driver. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __EFI_USER_PROFILE_MANAGER_H__ +#define __EFI_USER_PROFILE_MANAGER_H__ + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "UserProfileManagerData.h" + +#define USER_NAME_LENGTH 17 + +// +// Credential Provider Information. +// +typedef struct { + UINTN Count; + EFI_USER_CREDENTIAL_PROTOCOL *Provider[1]; +} CREDENTIAL_PROVIDER_INFO; + +// +// User profile information structure. +// +typedef struct { + UINT64 UsageCount; + EFI_TIME CreateDate; + EFI_TIME UsageDate; + UINTN AccessPolicyLen; + UINTN IdentityPolicyLen; + UINTN NewIdentityPolicyLen; + UINT8 *AccessPolicy; + UINT8 *IdentityPolicy; + UINT8 *NewIdentityPolicy; + CHAR16 UserName[USER_NAME_LENGTH]; + BOOLEAN CreateDateExist; + BOOLEAN UsageDateExist; + BOOLEAN AccessPolicyModified; + BOOLEAN IdentityPolicyModified; + BOOLEAN NewIdentityPolicyModified; +} USER_INFO; + +// +// User access information structure. +// +typedef struct { + UINTN LoadPermitLen; + UINTN LoadForbidLen; + UINTN ConnectPermitLen; + UINTN ConnectForbidLen; + UINT8 *LoadPermit; + UINT8 *LoadForbid; + UINT8 *ConnectPermit; + UINT8 *ConnectForbid; + UINT32 AccessBootOrder; + UINT8 AccessRight; + UINT8 AccessSetup; +} USER_INFO_ACCESS; + +#define USER_PROFILE_MANAGER_SIGNATURE SIGNATURE_32 ('U', 'P', 'M', 'S') + +typedef struct { + UINTN Signature; + EFI_HANDLE DriverHandle; + EFI_HII_HANDLE HiiHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; +} USER_PROFILE_MANAGER_CALLBACK_INFO; + +// +// HII specific Vendor Device Path definition. +// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +// +// This is the generated IFR binary data for each formset defined in VFR. +// +extern UINT8 UserProfileManagerVfrBin[]; + +// +// This is the generated String package data for .UNI file. +// +extern UINT8 UserProfileManagerStrings[]; + +// +// Guid used in the form browse. +// +extern EFI_GUID mUserProfileManagerGuid; + +// +// The user manager protocol, used in several function. +// +extern EFI_USER_MANAGER_PROTOCOL *mUserManager; + +// +// The credential providers database in system. +// +extern CREDENTIAL_PROVIDER_INFO *mProviderInfo; + +// +// The variables used to update identity policy. +// +extern UINT8 mProviderChoice; +extern UINT8 mConncetLogical; + +// +// The variables used to update access policy. +// +extern USER_INFO_ACCESS mAccessInfo; + +// +// The user information used to record all data in UI. +// +extern USER_INFO mUserInfo; + +extern USER_PROFILE_MANAGER_CALLBACK_INFO *mCallbackInfo; + + +/** + Get string by string id from HII Interface. + + + @param[in] Id String ID to get the string from. + + @retval CHAR16 * String from ID. + @retval NULL If error occurs. + +**/ +CHAR16 * +GetStringById ( + IN EFI_STRING_ID Id + ); + +/** + Add a new user profile into the user profile database. + +**/ +VOID +CallAddUser ( + VOID + ); + +/** + Display user select form; can select a user to modify. + +**/ +VOID +SelectUserToModify ( + VOID + ); + +/** + Display user select form, cab select a user to delete. + +**/ +VOID +SelectUserToDelete ( + VOID + ); + +/** + Delete the user specified by UserIndex in user profile database. + + @param[in] UserIndex The index of user in the user name list to be deleted. + +**/ +VOID +DeleteUser ( + IN UINT8 UserIndex + ); + +/** + Add a username item in form. + + @param[in] User Points to the user profile whose username is added. + @param[in] Index The index of the user in the user name list. + @param[in] OpCodeHandle Points to container for dynamic created opcodes. + +**/ +VOID +AddUserToForm ( + IN EFI_USER_PROFILE_HANDLE User, + IN UINT16 Index, + IN VOID *OpCodeHandle + ); + +/** + Display modify user information form + + In this form, username, create Date, usage date, usage count, identity policy, + and access policy are displayed. + + @param[in] UserIndex The index of the user in display list to modify. + +**/ +VOID +ModifyUserInfo ( + IN UINT8 UserIndex + ); + +/** + Get the username from user input and update username string in Hii + database with it. + +**/ +VOID +ModifyUserName ( + VOID + ); + +/** + Display the form of modifying user identity policy. + +**/ +VOID +ModifyIdentityPolicy ( + VOID + ); + +/** + Update the mUserInfo.NewIdentityPolicy and UI when 'add option' is pressed. + +**/ +VOID +AddIdentityPolicyItem ( + VOID + ); + +/** + Save the identity policy and update UI with it. + + This funciton will verify the new identity policy, in current implementation, + the identity policy can be: T, P & P & P & ..., P | P | P | ... + Here, "T" means "True", "P" means "Credential Provider", "&" means "and", "|" means "or". + Other identity policies are not supported. + +**/ +VOID +SaveIdentityPolicy ( + VOID + ); + +/** + Display modify user access policy form + + In this form, access right, access setu,p and access boot order are dynamically + added. Load devicepath and connect devicepath are displayed too. + +**/ +VOID +ModidyAccessPolicy ( + VOID + ); + +/** + Collect all the access policy data to mUserInfo.AccessPolicy, + and save it to user profile. + +**/ +VOID +SaveAccessPolicy ( + VOID + ); + +/** + Get current user's access rights. + + @param[out] AccessRight Points to the buffer used for user's access rights. + + @retval EFI_SUCCESS Get current user access rights successfully. + @retval others Fail to get current user access rights. + +**/ +EFI_STATUS +GetAccessRight ( + OUT UINT32 *AccessRight + ); + +/** + Display the permit load device path in the loadable device path list. + +**/ +VOID +DisplayLoadPermit( + VOID + ); + +/** + Display the forbid load device path list (mAccessInfo.LoadForbid). + +**/ +VOID +DisplayLoadForbid ( + VOID + ); + +/** + Display the permit connect device path. + +**/ +VOID +DisplayConnectPermit ( + VOID + ); + +/** + Display the forbid connect device path list. + +**/ +VOID +DisplayConnectForbid ( + VOID + ); + +/** + Delete the specified device path by DriverIndex from the forbid device path + list (mAccessInfo.LoadForbid). + + @param[in] DriverIndex The index of driver in a forbidden device path list. + +**/ +VOID +DeleteFromForbidLoad ( + IN UINT16 DriverIndex + ); + +/** + Add the specified device path by DriverIndex to the forbid device path + list (mAccessInfo.LoadForbid). + + @param[in] DriverIndex The index of driver saved in driver options. + +**/ +VOID +AddToForbidLoad ( + IN UINT16 DriverIndex + ); + +/** + Get user name from the popup windows. + + @param[in, out] UserNameLen On entry, point to the buffer lengh of UserName. + On exit, point to the input user name length. + @param[out] UserName The buffer to hold the input user name. + + @retval EFI_ABORTED It is given up by pressing 'ESC' key. + @retval EFI_NOT_READY Not a valid input at all. + @retval EFI_SUCCESS Get a user name successfully. + +**/ +EFI_STATUS +GetUserNameInput ( + IN OUT UINTN *UserNameLen, + OUT CHAR16 *UserName + ); + +#endif diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h new file mode 100644 index 0000000000..58b6cb8c1e --- /dev/null +++ b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h @@ -0,0 +1,161 @@ +/** @file + The form data for user profile manager driver. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __USER_PROFILE_MANAGER_DATA_H__ +#define __USER_PROFILE_MANAGER_DATA_H__ + +#define USER_PROFILE_MANAGER_GUID \ + { \ + 0xc35f272c, 0x97c2, 0x465a, { 0xa2, 0x16, 0x69, 0x6b, 0x66, 0x8a, 0x8c, 0xfe } \ + } + +// +// Form ID +// +#define FORMID_USER_MANAGE 0x0001 +#define FORMID_MODIFY_USER 0x0002 +#define FORMID_DEL_USER 0x0003 +#define FORMID_USER_INFO 0x0004 +#define FORMID_MODIFY_IP 0x0005 +#define FORMID_MODIFY_AP 0x0006 +#define FORMID_LOAD_DP 0x0007 +#define FORMID_CONNECT_DP 0x0008 +#define FORMID_PERMIT_LOAD_DP 0x0009 +#define FORMID_FORBID_LOAD_DP 0x000A +#define FORMID_PERMIT_CONNECT_DP 0x000B +#define FORMID_FORBID_CONNECT_DP 0x000C + +// +// Label ID +// +#define LABEL_USER_MANAGE_FUNC 0x0010 +#define LABEL_USER_DEL_FUNC 0x0020 +#define LABEL_USER_MOD_FUNC 0x0030 +#define LABEL_USER_INFO_FUNC 0x0040 +#define LABEL_IP_MOD_FUNC 0x0050 +#define LABEL_AP_MOD_FUNC 0x0060 +#define LABEL_PERMIT_LOAD_FUNC 0x0070 +#define LABLE_FORBID_LOAD_FUNC 0x0080 +#define LABEL_END 0x00F0 + +// +// First form key (Add/modify/del user profile). +// First 2 bits (bit 16~15). +// +#define KEY_MODIFY_USER 0x4000 +#define KEY_DEL_USER 0x8000 +#define KEY_ADD_USER 0xC000 +#define KEY_FIRST_FORM_MASK 0xC000 + +// +// Second form key (Display new form /Select user / modify device path in access policy). +// Next 2 bits (bit 14~13). +// +#define KEY_ENTER_NEXT_FORM 0x0000 +#define KEY_SELECT_USER 0x1000 +#define KEY_MODIFY_AP_DP 0x2000 +#define KEY_OPEN_CLOSE_FORM_ACTION 0x3000 +#define KEY_SECOND_FORM_MASK 0x3000 + +// +// User profile information form key. +// Next 3 bits (bit 12~10). +// +#define KEY_MODIFY_NAME 0x0200 +#define KEY_MODIFY_IP 0x0400 +#define KEY_MODIFY_AP 0x0600 +#define KEY_MODIFY_INFO_MASK 0x0E00 + +// +// Specified key, used in VFR (KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_NAME). +// +#define KEY_MODIFY_USER_NAME 0x5200 + +// +// Modify identity policy form key. +// Next 3 bits (bit 9~7). +// +#define KEY_MODIFY_PROV 0x0040 +#define KEY_MODIFY_MTYPE 0x0080 +#define KEY_MODIFY_CONN 0x00C0 +#define KEY_ADD_IP_OP 0x0100 +#define KEY_IP_RETURN_UIF 0x0140 +#define KEY_MODIFY_IP_MASK 0x01C0 + +// +// Specified key. +// +#define KEY_ADD_LOGICAL_OP 0x5500 +#define KEY_IP_RETURN 0x5540 + +// +// Modify access policy form key. +// Next 3 bits (bit 9~7). +// +#define KEY_MODIFY_RIGHT 0x0040 +#define KEY_MODIFY_SETUP 0x0080 +#define KEY_MODIFY_BOOT 0x00C0 +#define KEY_MODIFY_LOAD 0x0100 +#define KEY_MODIFY_CONNECT 0x0140 +#define KEY_AP_RETURN_UIF 0x0180 +#define KEY_MODIFY_AP_MASK 0x01C0 + +// +// Specified key. +// +#define KEY_LOAD_DP 0x5700 +#define KEY_CONN_DP 0x5740 +#define KEY_AP_RETURN 0x5780 + +// +// Device path form key. +// Next 2 bits (bit 6~5). +// +#define KEY_PERMIT_MODIFY 0x0010 +#define KEY_FORBID_MODIFY 0x0020 +#define KEY_DISPLAY_DP_MASK 0x0030 + +// +// Specified key. +// +#define KEY_LOAD_PERMIT 0x5710 +#define KEY_LOAD_FORBID 0x5720 +#define KEY_CONNECT_PERMIT 0x5750 +#define KEY_CONNECT_FORBID 0x5760 + +// +// Device path modify key. +// 2 bits (bit 12~11). +// +#define KEY_LOAD_PERMIT_MODIFY 0x0000 +#define KEY_LOAD_FORBID_MODIFY 0x0400 +#define KEY_CONNECT_PERMIT_MODIFY 0x0800 +#define KEY_CONNECT_FORBID_MODIFY 0x0C00 +#define KEY_MODIFY_DP_MASK 0x0C00 + + +// +// The permissions usable when configuring the platform. +// +#define ACCESS_SETUP_RESTRICTED 1 +#define ACCESS_SETUP_NORMAL 2 +#define ACCESS_SETUP_ADMIN 3 + +// +// Question ID for the question used in each form (KEY_OPEN_CLOSE_FORM_ACTION | FORMID_FORM_USER_MANAGE) +// This ID is used in FORM OPEN/CLOSE CallBack action. +// +#define QUESTIONID_USER_MANAGE 0x3001 + +#endif diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf new file mode 100644 index 0000000000..27b3464dcf --- /dev/null +++ b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf @@ -0,0 +1,60 @@ +## @file +# Component description file for user profile manager driver. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = UserProfileManager + FILE_GUID = E38CB52D-A74D-45db-A8D0-290C9B21BBF2 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = UserProfileManagerInit + +[Sources] + UserProfileManager.c + UserProfileManager.h + UserProfileAdd.c + UserProfileDelete.c + UserProfileModify.c + UserProfileManagerData.h + UserProfileManagerStrings.uni + UserProfileManagerVfr.Vfr + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiRuntimeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + MemoryAllocationLib + BaseMemoryLib + DebugLib + HiiLib + UefiLib + + [Guids] + gEfiIfrTianoGuid ## CONSUMES ## Guid + gEfiUserInfoAccessSetupAdminGuid ## CONSUMES ## Guid + gEfiUserInfoAccessSetupNormalGuid ## CONSUMES ## Guid + gEfiUserInfoAccessSetupRestrictedGuid ## CONSUMES ## Guid + +[Protocols] + gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED + gEfiHiiConfigAccessProtocolGuid + gEfiUserCredentialProtocolGuid + gEfiUserManagerProtocolGuid + gEfiDevicePathToTextProtocolGuid + +[Depex] + gEfiUserManagerProtocolGuid \ No newline at end of file diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni new file mode 100644 index 0000000000000000000000000000000000000000..64631bb921c7a05741df6ae018eba47654c6831a GIT binary patch literal 21532 zcmeHPU2h{b6!q&O@gIh+gmw|z0&gG$q-j#3O_Qog7kH}DCM^}+wo0?R^cV9lfOCB7 z+B4&s*oh}yBorm{ks056&%Hjr?-0K?kELbmKuvJ%1f|ITQ(fwNeYCBmQDPhS z+^T#1--Y@eGBWi-ovD}Dexts^=UeQ(dN}$T$6sQR;;IZ>OU)DWHCbGpEpdirC6a-bN|E1-xgw< zF*w5Sp5BgewudM>#?>8->#-VO+rfEaASGDLdx+W&t{CZ(huCAZ@^=ecmdnz&u-(NS+Ir?eyuL=Ac>5Yw}3W?Y~S6hpYzFe5wLQr?Ct7EIMDtd!)khe4Eq_;)gPZ+*JG4x znLp3;PlZF3J}-2XP`JYLInibM1OEfBM$E^>@zQ5J^k0r-$v=ef=gEp|;uTA184 z=#--_B{uQ|CC_m3v?A?L`e+NotV*9aESYaJvtbUNCerpET53MCY?9N$cEncBLCfjtZ4-91>s zy`l%htZ9QIW;zEV;|e>(WI@7SKGrJcjebdSp7dMp^JbX!P583Tb7ZI%`afL1Wh;7) zwZim`#QUv^35#CyNs05B&*uN8$J%I7*v~jl;4${1vwwNfz!Qh-Gb?9xuUWf4F25PZ zt7pp|SWWt3%`?#<{K#I^HlC178Qg|(Mo;&v(sSmC=n%e?KJEJkyjd?V&a3rU6uldU z$EG>71;4R3e}vBo`U(8L4E1J9kGF7)#|L?@hlPpT(vw#@1(phV4PNCHXRwVy}_au)eO@5x-5K6|0L6(Yjnj z#@F6}2W8yMU}m>raU^-&6p{43Cbx`A3?}7>5_H0l8NqTh z?!a+#X4=be;z;7HZd*8}+(d0$SEn+f^<2e~(GytDF;E*@b}tOeVIwibQp@(#MF_`k z*?YgPJuP^5+JJwh+_FveJ`!sNXa(BHZs{@WAF~(cr#@=^1#0~nS{L#F^UrI1Wb}=5 z1JcLza+zg3>U>;A!_Na@h~!ydxvraKfLMLXNY+PISjKt$n9GD=nm&f4#HumQWmfq6 zbVG8Fww^h|mVvD&`xk8sA>%F0=A?1*W4&)i_lC#^%sd#wCuSSwaWk^lZ0qQgQntB{ zJA4+e!yZN>JL>NuV8#wN9W^PmipAA^>Z{B6*&`WJ^K8~%{am)$j6X(?b!t_z%mR`26j;q-#$T_B*pJ-YmcN=D12Q4?Bbvc_Xy>)Ksan{LvEE#QZ ztup&z*12;H(_813Ube12HuL>}oP#z-@BFIshB)im^a8SeFOZkrHsH^EJ++d`*4IUD zmF>-Nn$>buP75C;G~9ZnXKQkJt0*@o4QBONm`7oW3B z*}s#%miVN^SDHW&bk)b%0qA;`!fyex!W-7T4*I@6;KTGg|`Q8`EmBi zTAV&w5RMkQmYMx93(3B>$n7RNLrCwzeED%UGCwEdbzvpf+4$l#%t~g_!D29)mxG3msy-g zvrJ|gi8_`yIQW@eH1_MoenztnjH`;2lI2pW9AxM68xskiKT5(=86& zeE+}C|6$nX$3E7LHtOM*Ta2|Zx$9t36?cC9R*$(bOP(_F!ZeJ-+SYEi&sHH0<} zrS+_iha%o?t$vDn949{oR=)TQi_JFpUslgbi(vV1IdY~q-sR2ov6))KRq>XUuDgg$ zw>^%HO&6=>2&YFgPJRlkQpIMR<|a1Xx|kl#d~B|-VI1E1cAIkptJyPTgviCJIFn&> zt@$ciq{FQot?Tn>Set1g){Ua3BX$+6eR{5kzn@vFvcF<$@8b1zQM-y3=}=1(wX4`* zqQQ-%rlU5Mo^kk__ndGR_G>ULR~rihbEXI1`(b-s!Z?F-M$H(E%-EN=p~(9fgf%$p z{u(_LGyT?-p?+Rxj>fmC%=G$Xb2YO#KG$;=+P40r_e0YfmpxM7Kf<-&oEOe_3Jme< zGRX;^;Q3w~`y>(Om6rBO2LH<2F-CgE60>7Lnk$ZF9(fOE%-MWQ_Te?Yv*^bLdO*|a zw=Uvt&aqjPOKhE5icS6W)cEe1Z zVaxYq75RqqTrE2_$vJ5><9pw_x^9QPsVBeoQdSRi!6}+ z_%N-{GPr)3Bg_U}^A3S(79hGIOyJgRzQ>R6;o1jk%qz+^Hi2ZU20rxIV%Zj~dQaB5 F{R<>sG4%id literal 0 HcmV?d00001 diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr new file mode 100644 index 0000000000..d094d78a76 --- /dev/null +++ b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr @@ -0,0 +1,247 @@ +/** @file + User Profile Manager formset. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UserProfileManagerData.h" + +#define USER_MANAGER_CLASS 0x00 +#define USER_MANAGER_SUBCLASS 0x04 + +formset + guid = USER_PROFILE_MANAGER_GUID, + title = STRING_TOKEN(STR_FORMSET_TITLE), + help = STRING_TOKEN(STR_TITLE_HELP), + class = USER_MANAGER_CLASS, + subclass = USER_MANAGER_SUBCLASS, + + // User manager form + form formid = FORMID_USER_MANAGE, + title = STRING_TOKEN(STR_USERMAN_TITLE); + + label LABEL_USER_MANAGE_FUNC; + label LABEL_END; + + suppressif TRUE; + text + help = STRING_TOKEN(STR_NULL_STRING), + text = STRING_TOKEN(STR_NULL_STRING), + text = STRING_TOKEN(STR_NULL_STRING), + flags = INTERACTIVE, + key = QUESTIONID_USER_MANAGE; + endif; + + endform; + + // Modify user profile form + form formid = FORMID_MODIFY_USER, + title = STRING_TOKEN(STR_MODIFY_USER_TITLE); + + label LABEL_USER_MOD_FUNC; + label LABEL_END; + + endform; + + // Delete user profile form + form formid = FORMID_DEL_USER, + title = STRING_TOKEN(STR_DELETE_USER_TITLE); + + label LABEL_USER_DEL_FUNC; + label LABEL_END; + + subtitle + text = STRING_TOKEN(STR_NULL_STRING); + endform; + + // + // User profile information form + // + form formid = FORMID_USER_INFO, + title = STRING_TOKEN(STR_USER_INFO); + + text + help = STRING_TOKEN(STR_USER_NAME_VAL), + text = STRING_TOKEN(STR_USER_NAME), + flags = INTERACTIVE, + key = KEY_MODIFY_USER_NAME; + + text + help = STRING_TOKEN(STR_CREATE_DATE_VAL), + text = STRING_TOKEN(STR_CREATE_DATE); + + text + help = STRING_TOKEN(STR_USAGE_DATE_VAL), + text = STRING_TOKEN(STR_USAGE_DATE); + + text + help = STRING_TOKEN(STR_USAGE_COUNT_VAL), + text = STRING_TOKEN(STR_USAGE_COUNT); + + label LABEL_USER_INFO_FUNC; + label LABEL_END; + + endform; + + // + // Identify policy modify form + // + form formid = FORMID_MODIFY_IP, + title = STRING_TOKEN(STR_IDENTIFY_POLICY); + + text + help = STRING_TOKEN(STR_IDENTIFY_POLICY_HELP), + text = STRING_TOKEN(STR_IDENTIFY_POLICY), + text = STRING_TOKEN(STR_IDENTIFY_POLICY_VALUE); + + label LABEL_IP_MOD_FUNC; + label LABEL_END; + + text + help = STRING_TOKEN(STR_ADD_OPTION_HELP), + text = STRING_TOKEN(STR_ADD_OPTION), + flags = INTERACTIVE, + key = KEY_ADD_LOGICAL_OP; + + subtitle + text = STRING_TOKEN(STR_NULL_STRING); + + goto FORMID_USER_INFO, + prompt = STRING_TOKEN(STR_SAVE), + help = STRING_TOKEN(STR_IDENTIFY_SAVE_HELP), + flags = INTERACTIVE, + key = KEY_IP_RETURN; + + endform; + + // + // Access policy modify form + // + form formid = FORMID_MODIFY_AP, + title = STRING_TOKEN(STR_ACCESS_POLICY); + + label LABEL_AP_MOD_FUNC; + label LABEL_END; + + goto FORMID_LOAD_DP, + prompt = STRING_TOKEN(STR_LOAD), + help = STRING_TOKEN(STR_LOAD_HELP), + flags = INTERACTIVE, + key = KEY_LOAD_DP; + + goto FORMID_CONNECT_DP, + prompt = STRING_TOKEN(STR_CONNECT), + help = STRING_TOKEN(STR_CONNECT_HELP), + flags = INTERACTIVE, + key = KEY_CONN_DP; + + subtitle + text = STRING_TOKEN(STR_NULL_STRING); + + goto FORMID_USER_INFO, + prompt = STRING_TOKEN(STR_SAVE), + help = STRING_TOKEN(STR_ACCESS_SAVE_HELP), + flags = INTERACTIVE, + key = KEY_AP_RETURN; + + endform; + + // + // Load device path form + // + form formid = FORMID_LOAD_DP, + title = STRING_TOKEN(STR_LOAD); + + goto FORMID_PERMIT_LOAD_DP, + prompt = STRING_TOKEN(STR_LOAD_PERMIT), + help = STRING_TOKEN(STR_LOAD_PERMIT_HELP), + flags = INTERACTIVE, + key = KEY_LOAD_PERMIT; + + goto FORMID_FORBID_LOAD_DP, + prompt = STRING_TOKEN(STR_LOAD_FORBID), + help = STRING_TOKEN(STR_LOAD_FORBID_HELP), + flags = INTERACTIVE, + key = KEY_LOAD_FORBID; + + endform; + + // + // Permit load device path form + // + form formid = FORMID_PERMIT_LOAD_DP, + title = STRING_TOKEN(STR_LOAD_PERMIT); + + label LABEL_PERMIT_LOAD_FUNC; + label LABEL_END; + + subtitle + text = STRING_TOKEN(STR_NULL_STRING); + + endform; + + // + // Forbid load device path form + // + form formid = FORMID_FORBID_LOAD_DP, + title = STRING_TOKEN(STR_LOAD_FORBID); + + label LABLE_FORBID_LOAD_FUNC; + label LABEL_END; + + subtitle + text = STRING_TOKEN(STR_NULL_STRING); + + endform; + + // + // Connect device path form + // + form formid = FORMID_CONNECT_DP, + title = STRING_TOKEN(STR_CONNECT); + + goto FORMID_PERMIT_CONNECT_DP, + prompt = STRING_TOKEN(STR_CONNECT_PERMIT), + help = STRING_TOKEN(STR_CONNECT_PERMIT_HELP), + flags = INTERACTIVE, + key = KEY_CONNECT_PERMIT; + + goto FORMID_FORBID_CONNECT_DP, + prompt = STRING_TOKEN(STR_CONNECT_FORBID), + help = STRING_TOKEN(STR_CONNECT_FORBID_HELP), + flags = INTERACTIVE, + key = KEY_CONNECT_FORBID; + + endform; + + // + // Permit connect device path form + // + form formid = FORMID_PERMIT_CONNECT_DP, + title = STRING_TOKEN(STR_CONNECT_PERMIT); + + subtitle + text = STRING_TOKEN(STR_NULL_STRING); + + endform; + + // + // Forbid connect device path form + // + form formid = FORMID_FORBID_CONNECT_DP, + title = STRING_TOKEN(STR_CONNECT_FORBID); + + subtitle + text = STRING_TOKEN(STR_NULL_STRING); + + endform; + +endformset; diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c new file mode 100644 index 0000000000..156c155c2c --- /dev/null +++ b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c @@ -0,0 +1,2511 @@ +/** @file + The functions to modify a user profile. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "UserProfileManager.h" + +EFI_USER_PROFILE_HANDLE mModifyUser = NULL; + +/** + Display user select form, cab select a user to modify. + +**/ +VOID +SelectUserToModify ( + VOID + ) +{ + EFI_STATUS Status; + UINT8 Index; + EFI_USER_PROFILE_HANDLE User; + EFI_USER_PROFILE_HANDLE CurrentUser; + UINT32 CurrentAccessRight; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_USER_MOD_FUNC; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Add each user can be modified. + // + User = NULL; + Index = 1; + mUserManager->Current (mUserManager, &CurrentUser); + while (TRUE) { + Status = mUserManager->GetNext (mUserManager, &User); + if (EFI_ERROR (Status)) { + break; + } + + Status = GetAccessRight (&CurrentAccessRight); + if (EFI_ERROR (Status)) { + CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF; + } + + if ((CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) || (User == CurrentUser)) { + AddUserToForm (User, (UINT16)(KEY_MODIFY_USER | KEY_SELECT_USER | Index), StartOpCodeHandle); + } + Index++; + } + + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserProfileManagerGuid, // Formset GUID + FORMID_MODIFY_USER, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} + + +/** + Get all the user info from mModifyUser in the user manager, and save on the + global variable. + +**/ +VOID +GetAllUserInfo ( + VOID + ) +{ + EFI_STATUS Status; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO *Info; + UINTN InfoSize; + UINTN MemSize; + UINTN DataLen; + + // + // Init variable to default value. + // + mProviderChoice = 0; + mConncetLogical = 0; + + mUserInfo.CreateDateExist = FALSE; + mUserInfo.UsageDateExist = FALSE; + mUserInfo.UsageCount = 0; + + mUserInfo.AccessPolicyLen = 0; + mUserInfo.AccessPolicyModified = FALSE; + if (mUserInfo.AccessPolicy != NULL) { + FreePool (mUserInfo.AccessPolicy); + mUserInfo.AccessPolicy = NULL; + } + mUserInfo.IdentityPolicyLen = 0; + mUserInfo.IdentityPolicyModified = FALSE; + if (mUserInfo.IdentityPolicy != NULL) { + FreePool (mUserInfo.IdentityPolicy); + mUserInfo.IdentityPolicy = NULL; + } + + // + // Allocate user information memory. + // + MemSize = sizeof (EFI_USER_INFO) + 63; + Info = AllocateZeroPool (MemSize); + if (Info == NULL) { + return ; + } + + // + // Get each user information. + // + UserInfo = NULL; + while (TRUE) { + Status = mUserManager->GetNextInfo (mUserManager, mModifyUser, &UserInfo); + if (EFI_ERROR (Status)) { + break; + } + // + // Get information. + // + InfoSize = MemSize; + Status = mUserManager->GetInfo ( + mUserManager, + mModifyUser, + UserInfo, + Info, + &InfoSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + MemSize = InfoSize; + FreePool (Info); + Info = AllocateZeroPool (MemSize); + if (Info == NULL) { + return ; + } + + Status = mUserManager->GetInfo ( + mUserManager, + mModifyUser, + UserInfo, + Info, + &InfoSize + ); + } + + if (Status == EFI_SUCCESS) { + // + // Deal with each information according to informaiton type. + // + DataLen = Info->InfoSize - sizeof (EFI_USER_INFO); + switch (Info->InfoType) { + case EFI_USER_INFO_NAME_RECORD: + CopyMem (&mUserInfo.UserName, (UINT8 *) (Info + 1), DataLen); + break; + + case EFI_USER_INFO_CREATE_DATE_RECORD: + CopyMem (&mUserInfo.CreateDate, (UINT8 *) (Info + 1), DataLen); + mUserInfo.CreateDateExist = TRUE; + break; + + case EFI_USER_INFO_USAGE_DATE_RECORD: + CopyMem (&mUserInfo.UsageDate, (UINT8 *) (Info + 1), DataLen); + mUserInfo.UsageDateExist = TRUE; + break; + + case EFI_USER_INFO_USAGE_COUNT_RECORD: + CopyMem (&mUserInfo.UsageCount, (UINT8 *) (Info + 1), DataLen); + break; + + case EFI_USER_INFO_ACCESS_POLICY_RECORD: + mUserInfo.AccessPolicy = AllocateZeroPool (DataLen); + if (mUserInfo.AccessPolicy == NULL) { + break; + } + + CopyMem (mUserInfo.AccessPolicy, (UINT8 *) (Info + 1), DataLen); + mUserInfo.AccessPolicyLen = DataLen; + break; + + case EFI_USER_INFO_IDENTITY_POLICY_RECORD: + mUserInfo.IdentityPolicy = AllocateZeroPool (DataLen); + if (mUserInfo.IdentityPolicy == NULL) { + break; + } + + CopyMem (mUserInfo.IdentityPolicy, (UINT8 *) (Info + 1), DataLen); + mUserInfo.IdentityPolicyLen = DataLen; + break; + + default: + break; + } + } + } + FreePool (Info); +} + + +/** + Convert the Date to a string, and update the Hii database DateID string with it. + + @param[in] Date Points to the date to be converted. + @param[in] DateId String ID in the HII database to be replaced. + +**/ +VOID +ResolveDate ( + IN EFI_TIME *Date, + IN EFI_STRING_ID DateId + ) +{ + CHAR16 *Str; + UINTN DateBufLen; + + // + // Convert date to string. + // + DateBufLen = 64; + Str = AllocateZeroPool (DateBufLen); + if (Str == NULL) { + return ; + } + + UnicodeSPrint ( + Str, + DateBufLen, + L"%4d-%2d-%2d ", + Date->Year, + Date->Month, + Date->Day + ); + + // + // Convert time to string. + // + DateBufLen -= StrLen (Str); + UnicodeSPrint ( + Str + StrLen (Str), + DateBufLen, + L"%2d:%2d:%2d", + Date->Hour, + Date->Minute, + Date->Second + ); + + HiiSetString (mCallbackInfo->HiiHandle, DateId, Str, NULL); + FreePool (Str); +} + + +/** + Convert the CountVal to a string, and update the Hii database CountId string + with it. + + @param[in] CountVal The hex value to convert. + @param[in] CountId String ID in the HII database to be replaced. + +**/ +VOID +ResolveCount ( + IN UINT32 CountVal, + IN EFI_STRING_ID CountId + ) +{ + CHAR16 Count[10]; + + UnicodeSPrint (Count, 20, L"%d", CountVal); + HiiSetString (mCallbackInfo->HiiHandle, CountId, Count, NULL); +} + + +/** + Concatenates one Null-terminated Unicode string to another Null-terminated + Unicode string. + + @param[in, out] Source1 On entry, point to a Null-terminated Unicode string. + On exit, point to a new concatenated Unicode string + @param[in] Source2 Pointer to a Null-terminated Unicode string. + +**/ +VOID +AddStr ( + IN OUT CHAR16 **Source1, + IN CONST CHAR16 *Source2 + ) +{ + CHAR16 *TmpStr; + UINTN StrLength; + + ASSERT (Source1 != NULL); + ASSERT (Source2 != NULL); + + if (*Source1 == NULL) { + StrLength = StrSize (Source2); + } else { + StrLength = StrSize (*Source1); + StrLength += StrSize (Source2) -1; + } + + TmpStr = AllocateZeroPool (StrLength); + ASSERT (TmpStr != NULL); + + if (*Source1 == NULL) { + StrCpy (TmpStr, Source2);; + } else { + StrCpy (TmpStr, *Source1); + FreePool (*Source1); + StrCat (TmpStr, Source2); + } + + *Source1 = TmpStr; +} + + +/** + Convert the identity policy to a unicode string and update the Hii database + IpStringId string with it. + + @param[in] Ip Points to identity policy. + @param[in] IpLen The identity policy length. + @param[in] IpStringId String ID in the HII database to be replaced. + +**/ +VOID +ResolveIdentityPolicy ( + IN UINT8 *Ip, + IN UINTN IpLen, + IN EFI_STRING_ID IpStringId + ) +{ + CHAR16 *TmpStr; + UINTN ChkLen; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + UINT16 Index; + CHAR16 *ProvStr; + EFI_STRING_ID ProvId; + EFI_HII_HANDLE HiiHandle; + EFI_USER_CREDENTIAL_PROTOCOL *UserCredential; + + TmpStr = NULL; + + // + // Resolve each policy. + // + ChkLen = 0; + while (ChkLen < IpLen) { + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (Ip + ChkLen); + switch (Identity->Type) { + case EFI_USER_INFO_IDENTITY_FALSE: + AddStr (&TmpStr, L"False"); + break; + + case EFI_USER_INFO_IDENTITY_TRUE: + AddStr (&TmpStr, L"None"); + break; + + case EFI_USER_INFO_IDENTITY_NOT: + AddStr (&TmpStr, L"! "); + break; + + case EFI_USER_INFO_IDENTITY_AND: + AddStr (&TmpStr, L" && "); + break; + + case EFI_USER_INFO_IDENTITY_OR: + AddStr (&TmpStr, L" || "); + break; + + case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE: + for (Index = 0; Index < mProviderInfo->Count; Index++) { + UserCredential = mProviderInfo->Provider[Index]; + if (CompareGuid ((EFI_GUID *) (Identity + 1), &UserCredential->Type)) { + UserCredential->Title ( + UserCredential, + &HiiHandle, + &ProvId + ); + ProvStr = HiiGetString (HiiHandle, ProvId, NULL); + if (ProvStr != NULL) { + AddStr (&TmpStr, ProvStr); + FreePool (ProvStr); + } + break; + } + } + break; + + case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER: + for (Index = 0; Index < mProviderInfo->Count; Index++) { + UserCredential = mProviderInfo->Provider[Index]; + if (CompareGuid ((EFI_GUID *) (Identity + 1), &UserCredential->Identifier)) { + UserCredential->Title ( + UserCredential, + &HiiHandle, + &ProvId + ); + ProvStr = HiiGetString (HiiHandle, ProvId, NULL); + if (ProvStr != NULL) { + AddStr (&TmpStr, ProvStr); + FreePool (ProvStr); + } + break; + } + } + break; + } + + ChkLen += Identity->Length; + } + + if (TmpStr != NULL) { + HiiSetString (mCallbackInfo->HiiHandle, IpStringId, TmpStr, NULL); + FreePool (TmpStr); + } +} + + +/** + Display modify user information form. + + This form displays, username, create Date, usage date, usage count, identity policy, + and access policy. + + @param[in] UserIndex The index of the user in display list to modify. + +**/ +VOID +ModifyUserInfo ( + IN UINT8 UserIndex + ) +{ + EFI_STATUS Status; + EFI_USER_PROFILE_HANDLE CurrentUser; + UINT32 CurrentAccessRight; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_USER_INFO_FUNC; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Find the user profile to be modified. + // + mModifyUser = NULL; + Status = mUserManager->GetNext (mUserManager, &mModifyUser); + if (EFI_ERROR (Status)) { + return ; + } + + while (UserIndex > 1) { + Status = mUserManager->GetNext (mUserManager, &mModifyUser); + if (EFI_ERROR (Status)) { + return ; + } + UserIndex--; + } + + // + // Get user profile information. + // + GetAllUserInfo (); + + // + // Update user name. + HiiSetString ( + mCallbackInfo->HiiHandle, + STRING_TOKEN (STR_USER_NAME_VAL), + mUserInfo.UserName, + NULL + ); + + // + // Update create date. + // + if (mUserInfo.CreateDateExist) { + ResolveDate (&mUserInfo.CreateDate, STRING_TOKEN (STR_CREATE_DATE_VAL)); + } else { + HiiSetString ( + mCallbackInfo->HiiHandle, + STRING_TOKEN (STR_CREATE_DATE_VAL), + L"", + NULL + ); + } + + // + // Add usage date. + // + if (mUserInfo.UsageDateExist) { + ResolveDate (&mUserInfo.UsageDate, STRING_TOKEN (STR_USAGE_DATE_VAL)); + } else { + HiiSetString ( + mCallbackInfo->HiiHandle, + STRING_TOKEN (STR_USAGE_DATE_VAL), + L"", + NULL + ); + } + + // + // Add usage count. + // + ResolveCount ((UINT32) mUserInfo.UsageCount, STRING_TOKEN (STR_USAGE_COUNT_VAL)); + + // + // Add identity policy. + // + mUserManager->Current (mUserManager, &CurrentUser); + if (mModifyUser == CurrentUser) { + ResolveIdentityPolicy ( + mUserInfo.IdentityPolicy, + mUserInfo.IdentityPolicyLen, + STRING_TOKEN (STR_IDENTIFY_POLICY_VAL) + ); + HiiCreateGotoOpCode ( + StartOpCodeHandle, // Container for opcodes + FORMID_MODIFY_IP, // Target Form ID + STRING_TOKEN (STR_IDENTIFY_POLICY), // Prompt text + STRING_TOKEN (STR_IDENTIFY_POLICY_VAL), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_IP // Question ID + ); + } + + // + // Add access policy. + // + Status = GetAccessRight (&CurrentAccessRight); + if (EFI_ERROR (Status)) { + CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF; + } + + if (CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) { + HiiCreateGotoOpCode ( + StartOpCodeHandle, // Container for opcodes + FORMID_MODIFY_AP, // Target Form ID + STRING_TOKEN (STR_ACCESS_POLICY), // Prompt text + STRING_TOKEN (STR_NULL_STRING), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP // Question ID + ); + } + + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserProfileManagerGuid, // Formset GUID + FORMID_USER_INFO, // Form ID + StartOpCodeHandle, // Label + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} + + +/** + Get all the access policy info from current user info, and save in the global + variable. + +**/ +VOID +ResolveAccessPolicy ( + VOID + ) +{ + UINTN OffSet; + EFI_USER_INFO_ACCESS_CONTROL Control; + UINTN ValLen; + UINT8 *AccessData; + + // + // Set default value + // + mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF; + mAccessInfo.AccessSetup = ACCESS_SETUP_RESTRICTED; + mAccessInfo.AccessBootOrder = EFI_USER_INFO_ACCESS_BOOT_ORDER_INSERT; + + mAccessInfo.LoadPermitLen = 0; + mAccessInfo.LoadForbidLen = 0; + mAccessInfo.ConnectPermitLen = 0; + mAccessInfo.ConnectForbidLen = 0; + + // + // Get each user access policy. + // + OffSet = 0; + while (OffSet < mUserInfo.AccessPolicyLen) { + CopyMem (&Control, mUserInfo.AccessPolicy + OffSet, sizeof (Control)); + ValLen = Control.Size - sizeof (Control); + switch (Control.Type) { + case EFI_USER_INFO_ACCESS_ENROLL_SELF: + mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF; + break; + + case EFI_USER_INFO_ACCESS_ENROLL_OTHERS: + mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_ENROLL_OTHERS; + break; + + case EFI_USER_INFO_ACCESS_MANAGE: + mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_MANAGE; + break; + + case EFI_USER_INFO_ACCESS_SETUP: + AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control); + if (CompareGuid ((EFI_GUID *) AccessData, &gEfiUserInfoAccessSetupNormalGuid)) { + mAccessInfo.AccessSetup = ACCESS_SETUP_NORMAL; + } else if (CompareGuid ((EFI_GUID *) AccessData, &gEfiUserInfoAccessSetupRestrictedGuid)) { + mAccessInfo.AccessSetup = ACCESS_SETUP_RESTRICTED; + } else if (CompareGuid ((EFI_GUID *) AccessData, &gEfiUserInfoAccessSetupAdminGuid)) { + mAccessInfo.AccessSetup = ACCESS_SETUP_ADMIN; + } + break; + + case EFI_USER_INFO_ACCESS_BOOT_ORDER: + AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control); + CopyMem (&mAccessInfo.AccessBootOrder, AccessData, sizeof (UINT32)); + break; + + case EFI_USER_INFO_ACCESS_FORBID_LOAD: + if (mAccessInfo.LoadForbid != NULL) { + FreePool (mAccessInfo.LoadForbid); + } + + mAccessInfo.LoadForbid = AllocateZeroPool (ValLen); + if (mAccessInfo.LoadForbid != NULL) { + AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control); + CopyMem (mAccessInfo.LoadForbid, AccessData, ValLen); + mAccessInfo.LoadForbidLen = ValLen; + } + break; + + case EFI_USER_INFO_ACCESS_PERMIT_LOAD: + if (mAccessInfo.LoadPermit != NULL) { + FreePool (mAccessInfo.LoadPermit); + } + + mAccessInfo.LoadPermit = AllocateZeroPool (ValLen); + if (mAccessInfo.LoadPermit != NULL) { + AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control); + CopyMem (mAccessInfo.LoadPermit, AccessData, ValLen); + mAccessInfo.LoadPermitLen = ValLen; + } + break; + + case EFI_USER_INFO_ACCESS_FORBID_CONNECT: + if (mAccessInfo.ConnectForbid != NULL) { + FreePool (mAccessInfo.ConnectForbid); + } + + mAccessInfo.ConnectForbid = AllocateZeroPool (ValLen); + if (mAccessInfo.ConnectForbid != NULL) { + AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control); + CopyMem (mAccessInfo.ConnectForbid, AccessData, ValLen); + mAccessInfo.ConnectForbidLen = ValLen; + } + break; + + case EFI_USER_INFO_ACCESS_PERMIT_CONNECT: + if (mAccessInfo.ConnectPermit != NULL) { + FreePool (mAccessInfo.ConnectPermit); + } + + mAccessInfo.ConnectPermit = AllocateZeroPool (ValLen); + if (mAccessInfo.ConnectPermit != NULL) { + AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control); + CopyMem (mAccessInfo.ConnectPermit, AccessData, ValLen); + mAccessInfo.ConnectPermitLen = ValLen; + } + break; + } + + OffSet += Control.Size; + } +} + + +/** + Find the specified info in profile mModifyUser by the InfoType. + + @param[in] InfoType The user information type to find. + @param[out] UserInfo Points to user information handle found. + + @retval EFI_SUCCESS Find the user information successfully. + @retval Others Fail to find the user information. + +**/ +EFI_STATUS +FindInfoByType ( + IN UINT8 InfoType, + OUT EFI_USER_INFO_HANDLE *UserInfo + ) +{ + EFI_STATUS Status; + EFI_USER_INFO *Info; + UINTN InfoSize; + UINTN MemSize; + + if (UserInfo == NULL) { + return EFI_INVALID_PARAMETER; + } + + *UserInfo = NULL; + // + // Allocate user information memory. + // + MemSize = sizeof (EFI_USER_INFO) + 63; + Info = AllocateZeroPool (MemSize); + if (Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get each user information. + // + while (TRUE) { + Status = mUserManager->GetNextInfo (mUserManager, mModifyUser, UserInfo); + if (EFI_ERROR (Status)) { + break; + } + // + // Get information. + // + InfoSize = MemSize; + Status = mUserManager->GetInfo ( + mUserManager, + mModifyUser, + *UserInfo, + Info, + &InfoSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + MemSize = InfoSize; + FreePool (Info); + Info = AllocateZeroPool (MemSize); + if (Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = mUserManager->GetInfo ( + mUserManager, + mModifyUser, + *UserInfo, + Info, + &InfoSize + ); + } + if (Status == EFI_SUCCESS) { + if (Info->InfoType == InfoType) { + break; + } + } + } + + FreePool (Info); + return Status; +} + + +/** + Display modify user access policy form. + + In this form, access right, access setup and access boot order are dynamically + added. Load devicepath and connect devicepath are displayed too. + +**/ +VOID +ModidyAccessPolicy ( + VOID + ) +{ + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + VOID *OptionsOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + VOID *DefaultOpCodeHandle; + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_AP_MOD_FUNC; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + + // + // Resolve access policy information. + // + ResolveAccessPolicy (); + + // + // Add access right one-of-code. + // + OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (OptionsOpCodeHandle != NULL); + DefaultOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (DefaultOpCodeHandle != NULL); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_NORMAL), + 0, + EFI_IFR_NUMERIC_SIZE_1, + EFI_USER_INFO_ACCESS_ENROLL_SELF + ); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_ENROLL), + 0, + EFI_IFR_NUMERIC_SIZE_1, + EFI_USER_INFO_ACCESS_ENROLL_OTHERS + ); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_MANAGE), + 0, + EFI_IFR_NUMERIC_SIZE_1, + EFI_USER_INFO_ACCESS_MANAGE + ); + + HiiCreateDefaultOpCode ( + DefaultOpCodeHandle, + EFI_HII_DEFAULT_CLASS_STANDARD, + EFI_IFR_NUMERIC_SIZE_1, + mAccessInfo.AccessRight + ); + + HiiCreateOneOfOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP | KEY_MODIFY_RIGHT, // Question ID + 0, // VarStore ID + 0, // Offset in Buffer Storage + STRING_TOKEN (STR_ACCESS_RIGHT), // Question prompt text + STRING_TOKEN (STR_ACCESS_RIGHT_HELP), // Question help text + EFI_IFR_FLAG_CALLBACK, // Question flag + EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value + OptionsOpCodeHandle, // Option Opcode list + DefaultOpCodeHandle // Default Opcode + ); + HiiFreeOpCodeHandle (DefaultOpCodeHandle); + HiiFreeOpCodeHandle (OptionsOpCodeHandle); + + + // + // Add setup type one-of-code. + // + OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (OptionsOpCodeHandle != NULL); + DefaultOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (DefaultOpCodeHandle != NULL); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_RESTRICTED), + 0, + EFI_IFR_NUMERIC_SIZE_1, + ACCESS_SETUP_RESTRICTED + ); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_NORMAL), + 0, + EFI_IFR_NUMERIC_SIZE_1, + ACCESS_SETUP_NORMAL + ); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_ADMIN), + 0, + EFI_IFR_NUMERIC_SIZE_1, + ACCESS_SETUP_ADMIN + ); + + HiiCreateDefaultOpCode ( + DefaultOpCodeHandle, + EFI_HII_DEFAULT_CLASS_STANDARD, + EFI_IFR_NUMERIC_SIZE_1, + mAccessInfo.AccessSetup + ); + + HiiCreateOneOfOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP | KEY_MODIFY_SETUP, // Question ID + 0, // VarStore ID + 0, // Offset in Buffer Storage + STRING_TOKEN (STR_ACCESS_SETUP), // Question prompt text + STRING_TOKEN (STR_ACCESS_SETUP_HELP), // Question help text + EFI_IFR_FLAG_CALLBACK, // Question flag + EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value + OptionsOpCodeHandle, // Option Opcode list + DefaultOpCodeHandle // Default Opcode + ); + HiiFreeOpCodeHandle (DefaultOpCodeHandle); + HiiFreeOpCodeHandle (OptionsOpCodeHandle); + + // + // Add boot order one-of-code. + // + OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (OptionsOpCodeHandle != NULL); + DefaultOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (DefaultOpCodeHandle != NULL); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_INSERT), + 0, + EFI_IFR_NUMERIC_SIZE_4, + EFI_USER_INFO_ACCESS_BOOT_ORDER_INSERT + ); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_APPEND), + 0, + EFI_IFR_NUMERIC_SIZE_4, + EFI_USER_INFO_ACCESS_BOOT_ORDER_APPEND + ); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_REPLACE), + 0, + EFI_IFR_NUMERIC_SIZE_4, + EFI_USER_INFO_ACCESS_BOOT_ORDER_REPLACE + ); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_NODEFAULT), + 0, + EFI_IFR_NUMERIC_SIZE_4, + EFI_USER_INFO_ACCESS_BOOT_ORDER_NODEFAULT + ); + + HiiCreateDefaultOpCode ( + DefaultOpCodeHandle, + EFI_HII_DEFAULT_CLASS_STANDARD, + EFI_IFR_NUMERIC_SIZE_4, + mAccessInfo.AccessBootOrder + ); + + HiiCreateOneOfOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP | KEY_MODIFY_BOOT, // Question ID + 0, // VarStore ID + 0, // Offset in Buffer Storage + STRING_TOKEN (STR_BOOR_ORDER), // Question prompt text + STRING_TOKEN (STR_BOOT_ORDER_HELP), // Question help text + EFI_IFR_FLAG_CALLBACK, // Question flag + EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value + OptionsOpCodeHandle, // Option Opcode list + DefaultOpCodeHandle // Default Opcode + ); + HiiFreeOpCodeHandle (DefaultOpCodeHandle); + HiiFreeOpCodeHandle (OptionsOpCodeHandle); + + // + // Update Form. + // + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserProfileManagerGuid, // Formset GUID + FORMID_MODIFY_AP, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} + + +/** + Expand access policy memory size. + + @param[in] ValidLen The valid access policy length. + @param[in] ExpandLen The length that is needed to expand. + +**/ +VOID +ExpandMemory ( + IN UINTN ValidLen, + IN UINTN ExpandLen + ) +{ + UINT8 *Mem; + UINTN Len; + + // + // Expand memory. + // + Len = mUserInfo.AccessPolicyLen + (ExpandLen / 64 + 1) * 64; + Mem = AllocateZeroPool (Len); + ASSERT (Mem != NULL); + + if (mUserInfo.AccessPolicy != NULL) { + CopyMem (Mem, mUserInfo.AccessPolicy, ValidLen); + FreePool (mUserInfo.AccessPolicy); + } + + mUserInfo.AccessPolicy = Mem; + mUserInfo.AccessPolicyLen = Len; +} + + +/** + Collect all the access policy data to mUserInfo.AccessPolicy, + and save it to user profile. + +**/ +VOID +SaveAccessPolicy ( + VOID + ) +{ + EFI_STATUS Status; + UINTN OffSet; + UINTN Size; + EFI_USER_INFO_ACCESS_CONTROL Control; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO *Info; + + if (mUserInfo.AccessPolicy != NULL) { + FreePool (mUserInfo.AccessPolicy); + } + mUserInfo.AccessPolicy = NULL; + mUserInfo.AccessPolicyLen = 0; + mUserInfo.AccessPolicyModified = TRUE; + OffSet = 0; + + // + // Save access right. + // + Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL); + if (mUserInfo.AccessPolicyLen - OffSet < Size) { + ExpandMemory (OffSet, Size); + } + + Control.Type = mAccessInfo.AccessRight; + Control.Size = (UINT32) Size; + CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control)); + OffSet += sizeof (Control); + + // + // Save access setup. + // + Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + sizeof (EFI_GUID); + if (mUserInfo.AccessPolicyLen - OffSet < Size) { + ExpandMemory (OffSet, Size); + } + + Control.Type = EFI_USER_INFO_ACCESS_SETUP; + Control.Size = (UINT32) Size; + CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control)); + OffSet += sizeof (Control); + + if (mAccessInfo.AccessSetup == ACCESS_SETUP_NORMAL) { + CopyGuid ((EFI_GUID *) (mUserInfo.AccessPolicy + OffSet), &gEfiUserInfoAccessSetupNormalGuid); + } else if (mAccessInfo.AccessSetup == ACCESS_SETUP_RESTRICTED) { + CopyGuid ((EFI_GUID *) (mUserInfo.AccessPolicy + OffSet), &gEfiUserInfoAccessSetupRestrictedGuid); + } else if (mAccessInfo.AccessSetup == ACCESS_SETUP_ADMIN) { + CopyGuid ((EFI_GUID *) (mUserInfo.AccessPolicy + OffSet), &gEfiUserInfoAccessSetupAdminGuid); + } + OffSet += sizeof (EFI_GUID); + + // + // Save access of boot order. + // + Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + sizeof (UINT32); + if (mUserInfo.AccessPolicyLen - OffSet < Size) { + ExpandMemory (OffSet, Size); + } + + Control.Type = EFI_USER_INFO_ACCESS_BOOT_ORDER; + Control.Size = (UINT32) Size; + CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control)); + OffSet += sizeof (Control); + + CopyMem ((UINT8 *) (mUserInfo.AccessPolicy + OffSet), &mAccessInfo.AccessBootOrder, sizeof (UINT32)); + OffSet += sizeof (UINT32); + + // + // Save permit load. + // + if (mAccessInfo.LoadPermitLen > 0) { + Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.LoadPermitLen; + if (mUserInfo.AccessPolicyLen - OffSet < Size) { + ExpandMemory (OffSet, Size); + } + + Control.Type = EFI_USER_INFO_ACCESS_PERMIT_LOAD; + Control.Size = (UINT32) Size; + CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control)); + OffSet += sizeof (Control); + + CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.LoadPermit, mAccessInfo.LoadPermitLen); + OffSet += mAccessInfo.LoadPermitLen; + } + + // + // Save forbid load. + // + if (mAccessInfo.LoadForbidLen > 0) { + Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.LoadForbidLen; + if (mUserInfo.AccessPolicyLen - OffSet < Size) { + ExpandMemory (OffSet, Size); + } + + Control.Type = EFI_USER_INFO_ACCESS_FORBID_LOAD; + Control.Size = (UINT32) Size; + CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control)); + OffSet += sizeof (Control); + + CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.LoadForbid, mAccessInfo.LoadForbidLen); + OffSet += mAccessInfo.LoadForbidLen; + } + + // + // Save permit connect. + // + if (mAccessInfo.ConnectPermitLen > 0) { + Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.ConnectPermitLen; + if (mUserInfo.AccessPolicyLen - OffSet < Size) { + ExpandMemory (OffSet, Size); + } + + Control.Type = EFI_USER_INFO_ACCESS_PERMIT_CONNECT; + Control.Size = (UINT32) Size; + CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control)); + OffSet += sizeof (Control); + + CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.ConnectPermit, mAccessInfo.ConnectPermitLen); + OffSet += mAccessInfo.ConnectPermitLen; + } + + // + // Save forbid connect. + // + if (mAccessInfo.ConnectForbidLen > 0) { + Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.ConnectForbidLen; + if (mUserInfo.AccessPolicyLen - OffSet < Size) { + ExpandMemory (OffSet, Size); + } + + Control.Type = EFI_USER_INFO_ACCESS_FORBID_CONNECT; + Control.Size = (UINT32) Size; + CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control)); + OffSet += sizeof (Control); + + CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.ConnectForbid, mAccessInfo.ConnectForbidLen); + OffSet += mAccessInfo.ConnectForbidLen; + } + + mUserInfo.AccessPolicyLen = OffSet; + + // + // Save access policy. + // + if (mUserInfo.AccessPolicyModified && (mUserInfo.AccessPolicyLen > 0)) { + Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + mUserInfo.AccessPolicyLen); + if (Info == NULL) { + return ; + } + + Status = FindInfoByType (EFI_USER_INFO_ACCESS_POLICY_RECORD, &UserInfo); + if (!EFI_ERROR (Status)) { + Info->InfoType = EFI_USER_INFO_ACCESS_POLICY_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | + EFI_USER_INFO_PUBLIC | + EFI_USER_INFO_EXCLUSIVE; + Info->InfoSize = (UINT32) (sizeof (EFI_USER_INFO) + mUserInfo.AccessPolicyLen); + CopyMem ((UINT8 *) (Info + 1), mUserInfo.AccessPolicy, mUserInfo.AccessPolicyLen); + Status = mUserManager->SetInfo ( + mUserManager, + mModifyUser, + &UserInfo, + Info, + Info->InfoSize + ); + mUserInfo.AccessPolicyModified = FALSE; + } + FreePool (Info); + } + + if (mAccessInfo.ConnectForbid != NULL) { + FreePool (mAccessInfo.ConnectForbid); + mAccessInfo.ConnectForbid = NULL; + } + + if (mAccessInfo.ConnectPermit != NULL) { + FreePool (mAccessInfo.ConnectPermit); + mAccessInfo.ConnectPermit = NULL; + } + + if (mAccessInfo.LoadForbid != NULL) { + FreePool (mAccessInfo.LoadForbid); + mAccessInfo.LoadForbid = NULL; + } + + if (mAccessInfo.LoadPermit != NULL) { + FreePool (mAccessInfo.LoadPermit); + mAccessInfo.LoadPermit = NULL; + } +} + + +/** + Get the username from user input, and update username string in the Hii + database with it. + +**/ +VOID +ModifyUserName ( + VOID + ) +{ + EFI_STATUS Status; + CHAR16 UserName[USER_NAME_LENGTH]; + UINTN Len; + EFI_INPUT_KEY Key; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO *Info; + EFI_USER_PROFILE_HANDLE TempUser; + + // + // Get the new user name. + // + Len = sizeof (UserName); + Status = GetUserNameInput (&Len, UserName); + if (EFI_ERROR (Status)) { + if (Status != EFI_ABORTED) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Failed To Get User Name.", + L"", + L"Please Press Any Key to Continue ...", + NULL + ); + } + return ; + } + + // + // Check whether the username had been used or not. + // + Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + Len); + if (Info == NULL) { + return ; + } + + Info->InfoType = EFI_USER_INFO_NAME_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | + EFI_USER_INFO_PUBLIC | + EFI_USER_INFO_EXCLUSIVE; + Info->InfoSize = (UINT32) (sizeof (EFI_USER_INFO) + Len); + CopyMem ((UINT8 *) (Info + 1), UserName, Len); + + TempUser = NULL; + Status = mUserManager->Find ( + mUserManager, + &TempUser, + NULL, + Info, + Info->InfoSize + ); + if (!EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"The User Name Had Been Used.", + L"", + L"Please Use Other User Name", + NULL + ); + FreePool (Info); + return ; + } + + // + // Update username display in the form. + // + CopyMem (mUserInfo.UserName, UserName, Len); + HiiSetString ( + mCallbackInfo->HiiHandle, + STRING_TOKEN (STR_USER_NAME_VAL), + mUserInfo.UserName, + NULL + ); + + // + // Save the user name. + // + Status = FindInfoByType (EFI_USER_INFO_NAME_RECORD, &UserInfo); + if (!EFI_ERROR (Status)) { + mUserManager->SetInfo ( + mUserManager, + mModifyUser, + &UserInfo, + Info, + Info->InfoSize + ); + } + FreePool (Info); +} + + +/** + Display the form of the modifying user identity policy. + +**/ +VOID +ModifyIdentityPolicy ( + VOID + ) +{ + UINTN Index; + CHAR16 *ProvStr; + EFI_STRING_ID ProvID; + EFI_HII_HANDLE HiiHandle; + VOID *OptionsOpCodeHandle; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_IP_MOD_FUNC; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Add credential providers + //. + if (mProviderInfo->Count > 0) { + OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (OptionsOpCodeHandle != NULL); + + // + // Add credential provider Option OpCode. + // + for (Index = 0; Index < mProviderInfo->Count; Index++) { + mProviderInfo->Provider[Index]->Title ( + mProviderInfo->Provider[Index], + &HiiHandle, + &ProvID + ); + ProvStr = HiiGetString (HiiHandle, ProvID, NULL); + ProvID = HiiSetString (mCallbackInfo->HiiHandle, 0, ProvStr, NULL); + FreePool (ProvStr); + if (ProvID == 0) { + return ; + } + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + ProvID, + 0, + EFI_IFR_NUMERIC_SIZE_1, + (UINT8) Index + ); + } + + HiiCreateOneOfOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_IP | KEY_MODIFY_PROV, // Question ID + 0, // VarStore ID + 0, // Offset in Buffer Storage + STRING_TOKEN (STR_PROVIDER), // Question prompt text + STRING_TOKEN (STR_PROVIDER_HELP), // Question help text + EFI_IFR_FLAG_CALLBACK, // Question flag + EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value + OptionsOpCodeHandle, // Option Opcode list + NULL // Default Opcode is NULl + ); + + HiiFreeOpCodeHandle (OptionsOpCodeHandle); + } + + // + // Add logical connector Option OpCode. + // + OptionsOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (OptionsOpCodeHandle != NULL); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_AND_CON), + 0, + EFI_IFR_NUMERIC_SIZE_1, + 0 + ); + + HiiCreateOneOfOptionOpCode ( + OptionsOpCodeHandle, + STRING_TOKEN (STR_OR_CON), + 0, + EFI_IFR_NUMERIC_SIZE_1, + 1 + ); + + HiiCreateOneOfOpCode ( + StartOpCodeHandle, // Container for dynamic created opcodes + KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_IP | KEY_MODIFY_CONN, // Question ID + 0, // VarStore ID + 0, // Offset in Buffer Storage + STRING_TOKEN (STR_CONNECTOR), // Question prompt text + STRING_TOKEN (STR_CONNECTOR_HELP), // Question help text + EFI_IFR_FLAG_CALLBACK, // Question flag + EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value + OptionsOpCodeHandle, // Option Opcode list + NULL // Default Opcode is NULl + ); + + HiiFreeOpCodeHandle (OptionsOpCodeHandle); + + // + // Update identity policy in the form. + // + ResolveIdentityPolicy ( + mUserInfo.IdentityPolicy, + mUserInfo.IdentityPolicyLen, + STRING_TOKEN (STR_IDENTIFY_POLICY_VALUE) + ); + + if (mUserInfo.NewIdentityPolicy != NULL) { + FreePool (mUserInfo.NewIdentityPolicy); + mUserInfo.NewIdentityPolicy = NULL; + mUserInfo.NewIdentityPolicyLen = 0; + mUserInfo.NewIdentityPolicyModified = FALSE; + } + mProviderChoice = 0; + mConncetLogical = 0; + + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserProfileManagerGuid, // Formset GUID + FORMID_MODIFY_IP, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} + + +/** + Save the identity policy and update UI with it. + + This funciton will verify the new identity policy, in current implementation, + the identity policy can be: T, P & P & P & ..., P | P | P | ... + Here, "T" means "True", "P" means "Credential Provider", "&" means "and", "|" means "or". + Other identity policies are not supported. + +**/ +VOID +SaveIdentityPolicy ( + VOID + ) +{ + EFI_STATUS Status; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO *Info; + EFI_INPUT_KEY Key; + UINTN Offset; + UINT32 OpCode; + UINTN InfoSize; + + if (!mUserInfo.NewIdentityPolicyModified || (mUserInfo.NewIdentityPolicyLen == 0)) { + return; + } + + // + // Check policy expression. + // + OpCode = EFI_USER_INFO_IDENTITY_FALSE; + Offset = 0; + while (Offset < mUserInfo.NewIdentityPolicyLen) { + // + // Check access policy according to type + // + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy + Offset); + switch (Identity->Type) { + + case EFI_USER_INFO_IDENTITY_TRUE: + break; + + case EFI_USER_INFO_IDENTITY_OR: + if (OpCode == EFI_USER_INFO_IDENTITY_AND) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Identity Policy, Mixed Connector Unsupport!", + L"", + L"Press Any Key to Continue ...", + NULL + ); + return ; + } + + OpCode = EFI_USER_INFO_IDENTITY_OR; + break; + + case EFI_USER_INFO_IDENTITY_AND: + if (OpCode == EFI_USER_INFO_IDENTITY_OR) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Identity Policy, Mixed Connector Unsupport!", + L"", + L"Press Any Key to Continue ...", + NULL + ); + return ; + } + + OpCode = EFI_USER_INFO_IDENTITY_AND; + break; + + case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER: + break; + + default: + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Unsupport parameter", + L"", + L"Press Any Key to Continue ...", + NULL + ); + return ; + } + Offset += Identity->Length; + } + + // + // Save identity policy. + // + Info = AllocateZeroPool ( + sizeof (EFI_USER_INFO) + + mUserInfo.NewIdentityPolicyLen + ); + if (Info == NULL) { + return ; + } + + Status = FindInfoByType (EFI_USER_INFO_IDENTITY_POLICY_RECORD, &UserInfo); + if (EFI_ERROR (Status)) { + FreePool (Info); + return ; + } + + Info->InfoType = EFI_USER_INFO_IDENTITY_POLICY_RECORD; + Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | + EFI_USER_INFO_PRIVATE | + EFI_USER_INFO_EXCLUSIVE; + Info->InfoSize = (UINT32) (sizeof (EFI_USER_INFO) + mUserInfo.NewIdentityPolicyLen); + CopyMem ((UINT8 *) (Info + 1), mUserInfo.NewIdentityPolicy, mUserInfo.NewIdentityPolicyLen); + Status = mUserManager->SetInfo ( + mUserManager, + mModifyUser, + &UserInfo, + Info, + Info->InfoSize + ); + FreePool (Info); + if (EFI_ERROR (Status)) { + // + // Get the user information again, it may be changed during saving it. + // + InfoSize = 0; + Status = mUserManager->GetInfo ( + mUserManager, + mModifyUser, + UserInfo, + Info, + &InfoSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Info = AllocateZeroPool (InfoSize); + ASSERT (Info != NULL); + Status = mUserManager->GetInfo ( + mUserManager, + mModifyUser, + UserInfo, + Info, + &InfoSize + ); + } + ASSERT_EFI_ERROR (Status); + + // + // Save current identification policy to mUserInfo.IdentityPolicy. + // + ASSERT (Info != NULL); + if (mUserInfo.IdentityPolicy != NULL) { + FreePool (mUserInfo.IdentityPolicy); + } + + mUserInfo.IdentityPolicyLen = Info->InfoSize - sizeof (EFI_USER_INFO); + mUserInfo.IdentityPolicy = AllocateCopyPool (mUserInfo.IdentityPolicyLen, Info + 1); + ASSERT (mUserInfo.IdentityPolicy != NULL); + + // + // Free the memory + // + FreePool (Info); + FreePool (mUserInfo.NewIdentityPolicy); + } else { + // + // Update the mUserInfo.IdentityPolicy by mUserInfo.NewIdentityPolicy + // + if (mUserInfo.IdentityPolicy != NULL) { + FreePool (mUserInfo.IdentityPolicy); + } + mUserInfo.IdentityPolicy = mUserInfo.NewIdentityPolicy; + mUserInfo.IdentityPolicyLen = mUserInfo.NewIdentityPolicyLen; + } + + mUserInfo.NewIdentityPolicy = NULL; + mUserInfo.NewIdentityPolicyLen = 0; + mUserInfo.NewIdentityPolicyModified = FALSE; + + // + // Update identity policy choice. + // + ResolveIdentityPolicy ( + mUserInfo.IdentityPolicy, + mUserInfo.IdentityPolicyLen, + STRING_TOKEN (STR_IDENTIFY_POLICY_VAL) + ); +} + + +/** + Verify the new identity policy in the current implementation. The same credential + provider can't appear twice in one identity policy. + + @param[in] NewGuid Points to the credential provider guid. + + @retval TRUE The NewGuid was found in the identity policy. + @retval FALSE The NewGuid was not found. + +**/ +BOOLEAN +CheckIdentityPolicy ( + IN EFI_GUID *NewGuid + ) +{ + UINTN Offset; + EFI_USER_INFO_IDENTITY_POLICY *Identity; + EFI_INPUT_KEY Key; + + Offset = 0; + while (Offset < mUserInfo.NewIdentityPolicyLen) { + // + // Check access policy according to type. + // + Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy + Offset); + switch (Identity->Type) { + + case EFI_USER_INFO_IDENTITY_TRUE: + case EFI_USER_INFO_IDENTITY_OR: + case EFI_USER_INFO_IDENTITY_AND: + break; + + case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER: + if (CompareGuid (NewGuid, (EFI_GUID *) (Identity + 1))) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"This Credential Provider Are Already Used!", + L"", + L"Press Any Key to Continue ...", + NULL + ); + return FALSE; + } + break; + + default: + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Unsupport parameter", + L"", + L"Press Any Key to Continue ...", + NULL + ); + return FALSE; + } + + Offset += Identity->Length; + } + return TRUE; +} + + +/** + Update the mUserInfo.NewIdentityPolicy, and UI when 'add option' is pressed. + +**/ +VOID +AddIdentityPolicyItem ( + VOID + ) +{ + UINT8 *NewInfo; + EFI_USER_INFO_IDENTITY_POLICY *Policy; + + if (mProviderInfo->Count == 0) { + return ; + } + + if (!mUserInfo.NewIdentityPolicyModified && (mUserInfo.NewIdentityPolicyLen > 0)) { + FreePool (mUserInfo.NewIdentityPolicy); + mUserInfo.NewIdentityPolicy = NULL; + mUserInfo.NewIdentityPolicyLen = 0; + } + // + // Expand the identity policy memory for the newly added policy info. + // + if (mUserInfo.NewIdentityPolicyLen > 0) { + // + // The new policy is not empty, expand space for connetor and provider. + // + if (!CheckIdentityPolicy (&mProviderInfo->Provider[mProviderChoice]->Identifier)) { + return ; + } + NewInfo = AllocateZeroPool ( + mUserInfo.NewIdentityPolicyLen + + sizeof (EFI_USER_INFO_IDENTITY_POLICY) * 2 + + sizeof (EFI_GUID) + ); + } else { + // + // The new policy is empty, only expand space for provider. + // + NewInfo = AllocateZeroPool ( + mUserInfo.NewIdentityPolicyLen + + sizeof (EFI_USER_INFO_IDENTITY_POLICY) + + sizeof (EFI_GUID) + ); + } + + if (NewInfo == NULL) { + return ; + } + + if (mUserInfo.NewIdentityPolicyLen > 0) { + CopyMem (NewInfo, mUserInfo.NewIdentityPolicy, mUserInfo.NewIdentityPolicyLen); + FreePool (mUserInfo.NewIdentityPolicy); + } + mUserInfo.NewIdentityPolicy = NewInfo; + + // + // Save logical connector. + // + if (mUserInfo.NewIdentityPolicyLen > 0) { + Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy + + mUserInfo.NewIdentityPolicyLen); + if (mConncetLogical == 0) { + Policy->Type = EFI_USER_INFO_IDENTITY_AND; + } else { + Policy->Type = EFI_USER_INFO_IDENTITY_OR; + } + + Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY); + mUserInfo.NewIdentityPolicyLen += Policy->Length; + } + + // + // Save credential provider. + // + Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy + + mUserInfo.NewIdentityPolicyLen); + Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY) + sizeof (EFI_GUID); + Policy->Type = EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER; + CopyGuid ((EFI_GUID *) (Policy + 1), &mProviderInfo->Provider[mProviderChoice]->Identifier); + mUserInfo.NewIdentityPolicyLen += Policy->Length; + + // + // Update identity policy choice. + // + mUserInfo.NewIdentityPolicyModified = TRUE; + ResolveIdentityPolicy ( + mUserInfo.NewIdentityPolicy, + mUserInfo.NewIdentityPolicyLen, + STRING_TOKEN (STR_IDENTIFY_POLICY_VALUE) + ); +} + + +/** + Create an action OpCode with QuestionID and DevicePath on a given OpCodeHandle. + + @param[in] QuestionID The question ID. + @param[in] DevicePath Points to device path. + @param[in] OpCodeHandle Points to container for dynamic created opcodes. + +**/ +VOID +AddDevicePath ( + IN UINTN QuestionID, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN VOID *OpCodeHandle + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *Next; + EFI_STRING_ID NameID; + EFI_STRING DriverName; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathText; + + // + // Locate device path to text protocol. + // + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevicePathText + ); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Get driver file name node. + // + Next = DevicePath; + while (!IsDevicePathEnd (Next)) { + DevicePath = Next; + Next = NextDevicePathNode (Next); + } + + // + // Display the device path in form. + // + DriverName = DevicePathText->ConvertDevicePathToText (DevicePath, FALSE, FALSE); + NameID = HiiSetString (mCallbackInfo->HiiHandle, 0, DriverName, NULL); + FreePool (DriverName); + if (NameID == 0) { + return ; + } + + HiiCreateActionOpCode ( + OpCodeHandle, // Container for dynamic created opcodes + (UINT16) QuestionID, // Question ID + NameID, // Prompt text + STRING_TOKEN (STR_NULL_STRING), // Help text + EFI_IFR_FLAG_CALLBACK, // Question flag + 0 // Action String ID + ); +} + + +/** + Check whether the DevicePath is in the device path forbid list + (mAccessInfo.LoadForbid). + + @param[in] DevicePath Points to device path. + + @retval TRUE The DevicePath is in the device path forbid list. + @retval FALSE The DevicePath is not in the device path forbid list. + +**/ +BOOLEAN +IsLoadForbidden ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + UINTN OffSet; + UINTN DPSize; + UINTN Size; + EFI_DEVICE_PATH_PROTOCOL *Dp; + + OffSet = 0; + Size = GetDevicePathSize (DevicePath); + // + // Check each device path. + // + while (OffSet < mAccessInfo.LoadForbidLen) { + Dp = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + OffSet); + DPSize = GetDevicePathSize (Dp); + // + // Compare device path. + // + if ((DPSize == Size) && (CompareMem (DevicePath, Dp, Size) == 0)) { + return TRUE; + } + OffSet += DPSize; + } + return FALSE; +} + + +/** + Display the permit load device path in the loadable device path list. + +**/ +VOID +DisplayLoadPermit( + VOID + ) +{ + EFI_STATUS Status; + CHAR16 *Order; + UINTN OrderSize; + UINTN ListCount; + UINTN Index; + UINT8 *Var; + UINT8 *VarPtr; + CHAR16 VarName[12]; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + + // + // Get DriverOrder. + // + OrderSize = 0; + Status = gRT->GetVariable ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + NULL, + &OrderSize, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + return ; + } + + Order = AllocateZeroPool (OrderSize); + if (Order == NULL) { + return ; + } + + Status = gRT->GetVariable ( + L"DriverOrder", + &gEfiGlobalVariableGuid, + NULL, + &OrderSize, + Order + ); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABEL_PERMIT_LOAD_FUNC; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Add each driver option. + // + Var = NULL; + ListCount = OrderSize / sizeof (UINT16); + for (Index = 0; Index < ListCount; Index++) { + // + // Get driver device path. + // + UnicodeSPrint (VarName, sizeof (VarName), L"Driver%04x", Order[Index]); + Var = GetEfiGlobalVariable (VarName); + if (Var == NULL) { + continue; + } + + // + // Check whether the driver is already forbidden. + // + + VarPtr = Var; + // + // Skip attribute. + // + VarPtr += sizeof (UINT32); + + // + // Skip device path lenth. + // + VarPtr += sizeof (UINT16); + + // + // Skip descript string. + // + VarPtr += StrSize ((UINT16 *) VarPtr); + + if (IsLoadForbidden ((EFI_DEVICE_PATH_PROTOCOL *) VarPtr)) { + FreePool (Var); + Var = NULL; + continue; + } + + AddDevicePath ( + KEY_MODIFY_USER | KEY_MODIFY_AP_DP | KEY_LOAD_PERMIT_MODIFY | Order[Index], + (EFI_DEVICE_PATH_PROTOCOL *) VarPtr, + StartOpCodeHandle + ); + FreePool (Var); + Var = NULL; + } + + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserProfileManagerGuid, // Formset GUID + FORMID_PERMIT_LOAD_DP, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); + + // + // Clear Environment. + // + if (Var != NULL) { + FreePool (Var); + } + FreePool (Order); +} + + +/** + Display the forbid load device path list (mAccessInfo.LoadForbid). + +**/ +VOID +DisplayLoadForbid ( + VOID + ) +{ + UINTN Offset; + UINTN DPSize; + UINTN Index; + EFI_DEVICE_PATH_PROTOCOL *Dp; + VOID *StartOpCodeHandle; + VOID *EndOpCodeHandle; + EFI_IFR_GUID_LABEL *StartLabel; + EFI_IFR_GUID_LABEL *EndLabel; + + // + // Initialize the container for dynamic opcodes. + // + StartOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (StartOpCodeHandle != NULL); + + EndOpCodeHandle = HiiAllocateOpCodeHandle (); + ASSERT (EndOpCodeHandle != NULL); + + // + // Create Hii Extend Label OpCode. + // + StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + StartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + StartLabel->Number = LABLE_FORBID_LOAD_FUNC; + + EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + EndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + EndLabel->Number = LABEL_END; + + // + // Add each forbid load drivers. + // + Offset = 0; + Index = 0; + while (Offset < mAccessInfo.LoadForbidLen) { + Dp = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + Offset); + DPSize = GetDevicePathSize (Dp); + AddDevicePath ( + KEY_MODIFY_USER | KEY_MODIFY_AP_DP | KEY_LOAD_FORBID_MODIFY | Index, + Dp, + StartOpCodeHandle + ); + Index++; + Offset += DPSize; + } + + HiiUpdateForm ( + mCallbackInfo->HiiHandle, // HII handle + &mUserProfileManagerGuid, // Formset GUID + FORMID_FORBID_LOAD_DP, // Form ID + StartOpCodeHandle, // Label for where to insert opcodes + EndOpCodeHandle // Replace data + ); + + HiiFreeOpCodeHandle (StartOpCodeHandle); + HiiFreeOpCodeHandle (EndOpCodeHandle); +} + + +/** + Display the permit connect device path. + +**/ +VOID +DisplayConnectPermit ( + VOID + ) +{ + // + // Note: + // As no architect protocol/interface to be called in ConnectController() + // to verify the device path, just add a place holder for permitted connect + // device path. + // +} + + +/** + Display the forbid connect device path list. + +**/ +VOID +DisplayConnectForbid ( + VOID + ) +{ + // + // Note: + // As no architect protocol/interface to be called in ConnectController() + // to verify the device path, just add a place holder for forbidden connect + // device path. + // +} + + +/** + Delete the specified device path by DriverIndex from the forbid device path + list (mAccessInfo.LoadForbid). + + @param[in] DriverIndex The index of driver in forbidden device path list. + +**/ +VOID +DeleteFromForbidLoad ( + IN UINT16 DriverIndex + ) +{ + UINTN OffSet; + UINTN DPSize; + UINTN OffLen; + EFI_DEVICE_PATH_PROTOCOL *Dp; + + OffSet = 0; + // + // Find the specified device path. + // + while ((OffSet < mAccessInfo.LoadForbidLen) && (DriverIndex > 0)) { + Dp = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + OffSet); + DPSize = GetDevicePathSize (Dp); + OffSet += DPSize; + DriverIndex--; + } + + // + // Specified device path found. + // + if (DriverIndex == 0) { + Dp = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + OffSet); + DPSize = GetDevicePathSize (Dp); + OffLen = mAccessInfo.LoadForbidLen - OffSet - DPSize; + if (OffLen > 0) { + CopyMem ( + mAccessInfo.LoadForbid + OffSet, + mAccessInfo.LoadForbid + OffSet + DPSize, + OffLen + ); + } + mAccessInfo.LoadForbidLen -= DPSize; + } +} + + +/** + Add the specified device path by DriverIndex to the forbid device path + list (mAccessInfo.LoadForbid). + + @param[in] DriverIndex The index of driver saved in driver options. + +**/ +VOID +AddToForbidLoad ( + IN UINT16 DriverIndex + ) +{ + UINTN DevicePathLen; + UINT8 *Var; + UINT8 *VarPtr; + UINTN NewLen; + UINT8 *NewFL; + CHAR16 VarName[13]; + + // + // Get loadable driver device path. + // + UnicodeSPrint (VarName, sizeof (VarName), L"Driver%04x", DriverIndex); + Var = GetEfiGlobalVariable (VarName); + if (Var == NULL) { + return; + } + + // + // Save forbid load driver. + // + + VarPtr = Var; + // + // Skip attribute. + // + VarPtr += sizeof (UINT32); + + DevicePathLen = *(UINT16 *) VarPtr; + // + // Skip device path length. + // + VarPtr += sizeof (UINT16); + + // + // Skip description string. + // + VarPtr += StrSize ((UINT16 *) VarPtr); + + NewLen = mAccessInfo.LoadForbidLen + DevicePathLen; + NewFL = AllocateZeroPool (NewLen); + if (NewFL == NULL) { + FreePool (Var); + return ; + } + + if (mAccessInfo.LoadForbidLen > 0) { + CopyMem (NewFL, mAccessInfo.LoadForbid, mAccessInfo.LoadForbidLen); + FreePool (mAccessInfo.LoadForbid); + } + + CopyMem (NewFL + mAccessInfo.LoadForbidLen, VarPtr, DevicePathLen); + mAccessInfo.LoadForbidLen = NewLen; + mAccessInfo.LoadForbid = NewFL; + FreePool (Var); +} + + +/** + Get current user's access right. + + @param[out] AccessRight Points to the buffer used for user's access right. + + @retval EFI_SUCCESS Get current user access right successfully. + @retval others Fail to get current user access right. + +**/ +EFI_STATUS +GetAccessRight ( + OUT UINT32 *AccessRight + ) +{ + EFI_STATUS Status; + EFI_USER_INFO_HANDLE UserInfo; + EFI_USER_INFO *Info; + UINTN InfoSize; + UINTN MemSize; + EFI_USER_INFO_ACCESS_CONTROL Access; + EFI_USER_PROFILE_HANDLE CurrentUser; + UINTN TotalLen; + UINTN CheckLen; + + // + // Allocate user information memory. + // + MemSize = sizeof (EFI_USER_INFO) + 63; + Info = AllocateZeroPool (MemSize); + if (Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get user access information. + // + UserInfo = NULL; + mUserManager->Current (mUserManager, &CurrentUser); + while (TRUE) { + InfoSize = MemSize; + // + // Get next user information. + // + Status = mUserManager->GetNextInfo (mUserManager, CurrentUser, &UserInfo); + if (EFI_ERROR (Status)) { + break; + } + + Status = mUserManager->GetInfo ( + mUserManager, + CurrentUser, + UserInfo, + Info, + &InfoSize + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + MemSize = InfoSize; + FreePool (Info); + Info = AllocateZeroPool (MemSize); + if (Info == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = mUserManager->GetInfo ( + mUserManager, + CurrentUser, + UserInfo, + Info, + &InfoSize + ); + } + if (EFI_ERROR (Status)) { + break; + } + + // + // Check user information. + // + if (Info->InfoType == EFI_USER_INFO_ACCESS_POLICY_RECORD) { + TotalLen = Info->InfoSize - sizeof (EFI_USER_INFO); + CheckLen = 0; + // + // Get specified access information. + // + while (CheckLen < TotalLen) { + CopyMem (&Access, (UINT8 *) (Info + 1) + CheckLen, sizeof (Access)); + if ((Access.Type == EFI_USER_INFO_ACCESS_ENROLL_SELF) || + (Access.Type == EFI_USER_INFO_ACCESS_ENROLL_OTHERS) || + (Access.Type == EFI_USER_INFO_ACCESS_MANAGE) + ) { + *AccessRight = Access.Type; + FreePool (Info); + return EFI_SUCCESS; + } + CheckLen += Access.Size; + } + } + } + FreePool (Info); + return EFI_NOT_FOUND; +} + + + diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c new file mode 100644 index 0000000000..38f462628a --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c @@ -0,0 +1,882 @@ +/** @file + Implement authentication services for the authenticated variable + service in UEFI2.2. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Variable.h" +#include "AuthService.h" + +/// +/// Global database array for scratch +/// +UINT32 mPubKeyNumber; +UINT32 mPlatformMode; +EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID}; +// +// Public Exponent of RSA Key. +// +CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 }; + +/** + 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; + + 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; +} + +/** + Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type. + Follow the steps in UEFI2.2. + + @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] Data The pointer to data with AuthInfo. + @param[in] DataSize The size of Data. + @param[in] PubKey The public key used for verification. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_SECURITY_VIOLATION Authentication failed. + @retval EFI_SUCCESS Authentication successful. + +**/ +EFI_STATUS +VerifyDataPayload ( + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global, + IN UINT8 *Data, + IN UINTN DataSize, + IN UINT8 *PubKey + ) +{ + BOOLEAN Status; + EFI_VARIABLE_AUTHENTICATION *CertData; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock; + UINT8 Digest[SHA256_DIGEST_SIZE]; + VOID *Rsa; + VOID *HashContext; + + Rsa = NULL; + CertData = NULL; + CertBlock = NULL; + + if (Data == NULL || PubKey == NULL) { + return EFI_INVALID_PARAMETER; + } + + CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; + CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData); + + // + // wCertificateType should be WIN_CERT_TYPE_EFI_GUID. + // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256. + // + if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) || + !CompareGuid (&CertData->AuthInfo.CertType, Global->CertRsa2048Sha256Guid[VirtualMode]) + ) { + // + // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + } + + // + // Hash data payload with SHA256. + // + ZeroMem (Digest, SHA256_DIGEST_SIZE); + HashContext = Global->HashContext[VirtualMode]; + Status = Sha256Init (HashContext); + if (!Status) { + goto Done; + } + Status = Sha256Update (HashContext, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE)); + if (!Status) { + goto Done; + } + // + // Hash Monotonic Count. + // + Status = Sha256Update (HashContext, &CertData->MonotonicCount, sizeof (UINT64)); + if (!Status) { + goto Done; + } + Status = Sha256Final (HashContext, Digest); + if (!Status) { + goto Done; + } + // + // Generate & Initialize RSA Context. + // + Rsa = RsaNew (); + ASSERT (Rsa != NULL); + // + // Set RSA Key Components. + // NOTE: Only N and E are needed to be set as RSA public key for signature verification. + // + Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE); + if (!Status) { + goto Done; + } + Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE)); + if (!Status) { + goto Done; + } + // + // Verify the signature. + // + Status = RsaPkcs1Verify ( + Rsa, + Digest, + SHA256_DIGEST_SIZE, + CertBlock->Signature, + EFI_CERT_TYPE_RSA2048_SHA256_SIZE + ); + +Done: + if (Rsa != NULL) { + RsaFree (Rsa); + } + if (Status) { + return EFI_SUCCESS; + } else { + return EFI_SECURITY_VIOLATION; + } +} + + +/** + 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 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; + + 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; +} + +/** + 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; + + 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 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key. + + @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[out] KeyIndex The output index of corresponding public key in database. + @param[out] MonotonicCount The output value of corresponding Monotonic Count. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_WRITE_PROTECTED The variable is write-protected and needs authentication with + EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. + @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + set, but the AuthInfo does NOT pass the validation + check carried out by the firmware. + @retval EFI_SUCCESS The variable is not write-protected, or passed validation successfully. + +**/ +EFI_STATUS +VerifyVariable ( + IN VOID *Data, + IN UINTN DataSize, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global, + IN VARIABLE_POINTER_TRACK *Variable, + IN UINT32 Attributes OPTIONAL, + OUT UINT32 *KeyIndex OPTIONAL, + OUT UINT64 *MonotonicCount OPTIONAL + ) +{ + EFI_STATUS Status; + BOOLEAN IsDeletion; + BOOLEAN IsFirstTime; + UINT8 *PubKey; + EFI_VARIABLE_AUTHENTICATION *CertData; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock; + VARIABLE_HEADER VariableHeader; + BOOLEAN Valid; + + CertData = NULL; + CertBlock = NULL; + PubKey = NULL; + IsDeletion = FALSE; + Valid = FALSE; + + if (KeyIndex != NULL) { + *KeyIndex = 0; + } + // + // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS. + // + ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER)); + if (Variable->CurrPtr != 0x0) { + Valid = IsValidVariableHeader ( + Variable->CurrPtr, + Variable->Volatile, + &Global->VariableGlobal[VirtualMode], + Global->FvbInstance, + &VariableHeader + ); + ASSERT (Valid); + } + + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + if (KeyIndex == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Determine current operation type. + // + if (DataSize == AUTHINFO_SIZE) { + IsDeletion = TRUE; + } + // + // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. + // + if (Variable->CurrPtr == 0x0) { + IsFirstTime = TRUE; + } else if (Valid &&(VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) { + IsFirstTime = TRUE; + } else { + *KeyIndex = VariableHeader.PubKeyIndex; + IsFirstTime = FALSE; + } + } else if (Valid && (VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // If the variable is already write-protected, it always needs authentication before update. + // + return EFI_WRITE_PROTECTED; + } else { + // + // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision. + // That means it is not authenticated variable, just return EFI_SUCCESS. + // + return EFI_SUCCESS; + } + + // + // Get PubKey and check Monotonic Count value corresponding to the variable. + // + CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; + CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData); + PubKey = CertBlock->PublicKey; + + if (MonotonicCount != NULL) { + // + // Update Monotonic Count value. + // + *MonotonicCount = CertData->MonotonicCount; + } + + if (!IsFirstTime) { + // + // Check input PubKey. + // + if (CompareMem (PubKey, Global->PubKeyStore + (*KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) { + return EFI_SECURITY_VIOLATION; + } + // + // Compare the current monotonic count and ensure that it is greater than the last SetVariable + // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set. + // + if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) { + // + // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + } + } + // + // Verify the certificate in Data payload. + // + Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, PubKey); + if (!EFI_ERROR (Status)) { + // + // Now, the signature has been verified! + // + if (IsFirstTime && !IsDeletion) { + // + // Update public key database variable if need and return the index. + // + *KeyIndex = AddPubKeyInStore (VirtualMode, Global, PubKey); + } + } + + return Status; +} + diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h new file mode 100644 index 0000000000..f3e15f61e2 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h @@ -0,0 +1,151 @@ +/** @file + The internal header file includes the common header files, defines + internal structure and functions used by AuthService module. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _AUTHSERVICE_H_ +#define _AUTHSERVICE_H_ + +#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256 +#define EFI_CERT_TYPE_RSA2048_SIZE 256 + +/// +/// Size of AuthInfo prior to the data payload +/// +#define AUTHINFO_SIZE (((UINTN)(((EFI_VARIABLE_AUTHENTICATION *) 0)->AuthInfo.CertData)) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256)) + +/// +/// Item number of support signature types. +/// +#define SIGSUPPORT_NUM 2 + +/** + Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key. + + @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[out] KeyIndex The output index of corresponding public key in database. + @param[out] MonotonicCount The output value of corresponding Monotonic Count. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_WRITE_PROTECTED The variable is write-protected and needs authentication with + EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. + @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + set, but the AuthInfo does NOT pass the validation + check carried out by the firmware. + @retval EFI_SUCCESS The variable is not write-protected, or passed validation successfully. + +**/ +EFI_STATUS +VerifyVariable ( + IN VOID *Data, + IN UINTN DataSize, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global, + IN VARIABLE_POINTER_TRACK *Variable, + IN UINT32 Attributes OPTIONAL, + OUT UINT32 *KeyIndex OPTIONAL, + OUT UINT64 *MonotonicCount OPTIONAL + ); + +/** + 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 + ); + +/** + Initializes for cryptlib service before use, include register algrithm and allocate scratch. + +**/ +VOID +CryptLibraryInitialize ( + VOID + ); + +/** + Process variable with platform key for verification. + + @param[in] VariableName The name of Variable to be found. + @param[in] VendorGuid 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 + ); + +/** + 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 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 does 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 + ); + +#endif diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf new file mode 100644 index 0000000000..dc161c9a9a --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf @@ -0,0 +1,85 @@ +## @file +# Component description file for Extended SAL authentication variable +# service module. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = EsalVariableDxeSal + FILE_GUID = 14610837-4E97-4427-96E0-21D9B2956996 + MODULE_TYPE = DXE_SAL_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = VariableServiceInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IPF +# +# VIRTUAL_ADDRESS_MAP_CALLBACK = VariableClassAddressChangeEvent +# + +[Sources.common] + InitVariable.c + Reclaim.c + Variable.c + Variable.h + AuthService.c + AuthService.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + SynchronizationLib + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + UefiRuntimeLib + DxeServicesTableLib + UefiDriverEntryPoint + PcdLib + ExtendedSalLib + BaseCryptLib + +[Protocols] + gEfiFirmwareVolumeBlockProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + gEfiFaultTolerantWriteProtocolGuid # PROTOCOL SOMETIMES_CONSUMED + +[Guids] + gEfiGlobalVariableGuid + gEfiAuthenticatedVariableGuid + gEfiEventVirtualAddressChangeGuid + gEfiCertRsa2048Sha256Guid + gEfiImageSecurityDatabaseGuid + +[Pcd.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize + gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize + +[FeaturePcd.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics + +[Depex] + gEfiExtendedSalFvBlockServicesProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid + diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c new file mode 100644 index 0000000000..0cf8141ce6 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c @@ -0,0 +1,245 @@ +/** @file + Entrypoint of Extended SAL variable service module. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Variable.h" +#include "AuthService.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +EFI_EVENT mEfiVirtualNotifyEvent; + +/** + Common entry for Extended SAL Variable Services Class. + + This is the common entry of all functions of Extended SAL Variable Services Class. + + @param[in] FunctionId The Function ID of member function in Extended SAL Variable Services Class. + @param[in] Arg2 The 2nd parameter for SAL procedure call. + @param[in] Arg3 The 3rd parameter for SAL procedure call. + @param[in] Arg4 The 4th parameter for SAL procedure call. + @param[in] Arg5 The 5th parameter for SAL procedure call. + @param[in] Arg6 The 6th parameter for SAL procedure call. + @param[in] Arg7 The 7th parameter for SAL procedure call. + @param[in] Arg8 The 8th parameter for SAL procedure call. + @param[in] VirtualMode The current calling mode for this function. + @param[in] Global The context of this Extended SAL Variable Services Class call. + + @return The register of SAL. + +**/ +SAL_RETURN_REGS +EFIAPI +EsalVariableCommonEntry ( + IN UINT64 FunctionId, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN UINT64 Arg5, + IN UINT64 Arg6, + IN UINT64 Arg7, + IN UINT64 Arg8, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ) +{ + SAL_RETURN_REGS ReturnVal; + + ReturnVal.r9 = 0; + ReturnVal.r10 = 0; + ReturnVal.r11 = 0; + + switch (FunctionId) { + case EsalGetVariableFunctionId: + ReturnVal.Status = EsalGetVariable ( + (CHAR16 *) Arg2, + (EFI_GUID *) Arg3, + (UINT32 *) Arg4, + (UINTN *) Arg5, + (VOID *) Arg6, + VirtualMode, + Global + ); + return ReturnVal; + + case EsalGetNextVariableNameFunctionId: + ReturnVal.Status = EsalGetNextVariableName ( + (UINTN *) Arg2, + (CHAR16 *) Arg3, + (EFI_GUID *) Arg4, + VirtualMode, + Global + ); + return ReturnVal; + + case EsalSetVariableFunctionId: + ReturnVal.Status = EsalSetVariable ( + (CHAR16 *) Arg2, + (EFI_GUID *) Arg3, + (UINT32) Arg4, + (UINTN) Arg5, + (VOID *) Arg6, + VirtualMode, + Global + ); + return ReturnVal; + + case EsalQueryVariableInfoFunctionId: + ReturnVal.Status = EsalQueryVariableInfo ( + (UINT32) Arg2, + (UINT64 *) Arg3, + (UINT64 *) Arg4, + (UINT64 *) Arg5, + VirtualMode, + Global + ); + return ReturnVal; + + default: + ReturnVal.Status = EFI_SAL_INVALID_ARGUMENT; + return ReturnVal; + } +} + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + It convers pointer to new virtual address. + + @param[in] Event The event whose notification function is being invoked. + @param[in] Context The pointer to the notification function's context. + +**/ +VOID +EFIAPI +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Index; + + CopyMem ( + &mVariableModuleGlobal->VariableGlobal[Virtual], + &mVariableModuleGlobal->VariableGlobal[Physical], + sizeof (VARIABLE_GLOBAL) + ); + + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableGlobal[Virtual].NonVolatileVariableBase + ); + EfiConvertPointer ( + 0x0, + (VOID **) &mVariableModuleGlobal->VariableGlobal[Virtual].VolatileVariableBase + ); + + mVariableModuleGlobal->PlatformLangCodes[Virtual] = mVariableModuleGlobal->PlatformLangCodes[Physical]; + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes[Virtual]); + + mVariableModuleGlobal->LangCodes[Virtual] = mVariableModuleGlobal->LangCodes[Physical]; + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes[Virtual]); + + mVariableModuleGlobal->PlatformLang[Virtual] = mVariableModuleGlobal->PlatformLang[Physical]; + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang[Virtual]); + + CopyMem ( + mVariableModuleGlobal->VariableName[Virtual], + mVariableModuleGlobal->VariableName[Physical], + sizeof (mVariableModuleGlobal->VariableName[Physical]) + ); + for (Index = 0; Index < NUM_VAR_NAME; Index++) { + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableName[Virtual][Index]); + } + + mVariableModuleGlobal->GlobalVariableGuid[Virtual] = &gEfiGlobalVariableGuid; + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->GlobalVariableGuid[Virtual]); + + mVariableModuleGlobal->AuthenticatedVariableGuid[Virtual] = &gEfiAuthenticatedVariableGuid; + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->AuthenticatedVariableGuid[Virtual]); + + mVariableModuleGlobal->CertRsa2048Sha256Guid[Virtual] = &gEfiCertRsa2048Sha256Guid; + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->CertRsa2048Sha256Guid[Virtual]); + + mVariableModuleGlobal->ImageSecurityDatabaseGuid[Virtual] = &gEfiImageSecurityDatabaseGuid; + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->ImageSecurityDatabaseGuid[Virtual]); + + mVariableModuleGlobal->HashContext[Virtual] = mVariableModuleGlobal->HashContext[Physical]; + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->HashContext[Virtual]); +} + +/** + Entry point of Extended SAL Variable service module. + + This function is the entry point of Extended SAL Variable service module. + It registers all functions of Extended SAL Variable class, initializes + variable store for non-volatile and volatile variables, and registers + notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + + @param[in] ImageHandle The Image handle of this driver. + @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE. + + @retval EFI_SUCCESS Extended SAL Variable Services Class successfully registered. + +**/ +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + VariableClassAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mEfiVirtualNotifyEvent + ); + + ASSERT_EFI_ERROR (Status); + + Status = VariableCommonInitialize (ImageHandle, SystemTable); + ASSERT_EFI_ERROR (Status); + + // + // Authenticated variable initialize + // + Status = AutenticatedVariableServiceInitialize (); + ASSERT_EFI_ERROR (Status); + + // + // Register All the Functions with Extended SAL Variable Services Class + // + RegisterEsalClass ( + EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID_LO, + EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID_HI, + mVariableModuleGlobal, + EsalVariableCommonEntry, + EsalGetVariableFunctionId, + EsalVariableCommonEntry, + EsalGetNextVariableNameFunctionId, + EsalVariableCommonEntry, + EsalSetVariableFunctionId, + EsalVariableCommonEntry, + EsalQueryVariableInfoFunctionId, + NULL + ); + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c new file mode 100644 index 0000000000..1cbf9ac877 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c @@ -0,0 +1,262 @@ +/** @file + Handles non-volatile variable store garbage collection, using FTW + (Fault Tolerant Write) protocol. + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Variable.h" + +/** + Gets firmware volume block handle by given address. + + This function gets firmware volume block handle whose + address range contains the parameter Address. + + @param[in] Address Address which should be contained + by returned FVB handle. + @param[out] FvbHandle Pointer to FVB handle for output. + + @retval EFI_SUCCESS FVB handle successfully returned. + @retval EFI_NOT_FOUND Failed to find FVB handle by address. + +**/ +EFI_STATUS +GetFvbHandleByAddress ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT EFI_HANDLE *FvbHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + EFI_PHYSICAL_ADDRESS FvbBaseAddress; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + + *FvbHandle = NULL; + // + // Locate all handles with Firmware Volume Block protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Traverse all the handles, searching for the one containing parameter Address + // + for (Index = 0; Index < HandleCount; Index += 1) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &Fvb + ); + if (EFI_ERROR (Status)) { + Status = EFI_NOT_FOUND; + break; + } + // + // Checks if the address range of this handle contains parameter Address + // + Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); + if (EFI_ERROR (Status)) { + continue; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); + if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) { + *FvbHandle = HandleBuffer[Index]; + Status = EFI_SUCCESS; + break; + } + } + + FreePool (HandleBuffer); + return Status; +} + +/** + Gets LBA of block and offset by given address. + + This function gets the Logical Block Address (LBA) of firmware + volume block containing the given address, and the offset of + address on the block. + + @param[in] Address Address which should be contained + by returned FVB handle. + @param[out] Lba The pointer to LBA for output. + @param[out] Offset The pointer to offset for output. + + @retval EFI_SUCCESS LBA and offset successfully returned. + @retval EFI_NOT_FOUND Failed to find FVB handle by address. + @retval EFI_ABORTED Failed to find valid LBA and offset. + +**/ +EFI_STATUS +GetLbaAndOffsetByAddress ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT EFI_LBA *Lba, + OUT UINTN *Offset + ) +{ + EFI_STATUS Status; + EFI_HANDLE FvbHandle; + EFI_PHYSICAL_ADDRESS FvbBaseAddress; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; + UINT32 LbaIndex; + + *Lba = (EFI_LBA) (-1); + *Offset = 0; + + // + // Gets firmware volume block handle by given address. + // + Status = GetFvbHandleByAddress (Address, &FvbHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol ( + FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &Fvb + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the Base Address of FV + // + Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); + if (EFI_ERROR (Status)) { + return Status; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); + + // + // Get the (LBA, Offset) of Address + // + if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) { + if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { + // + // BUGBUG: Assume one FV has one type of BlockLength + // + FvbMapEntry = &FwVolHeader->BlockMap[0]; + for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { + if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) { + // + // Found the (Lba, Offset) + // + *Lba = LbaIndex - 1; + *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))); + return EFI_SUCCESS; + } + } + } + } + + return EFI_ABORTED; +} + +/** + Writes a buffer to variable storage space. + + This function writes a buffer to variable storage space into firmware + volume block device. The destination is specified by parameter + VariableBase. Fault Tolerant Write protocol is used for writing. + + @param[in] VariableBase The base address of the variable to write. + @param[in] Buffer Points to the data buffer. + @param[in] BufferSize The number of bytes of the data Buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol. + @retval Other The function could not complete successfully. + +**/ +EFI_STATUS +FtwVariableSpace ( + IN EFI_PHYSICAL_ADDRESS VariableBase, + IN UINT8 *Buffer, + IN UINTN BufferSize + ) +{ + EFI_STATUS Status; + EFI_HANDLE FvbHandle; + EFI_LBA VarLba; + UINTN VarOffset; + UINT8 *FtwBuffer; + UINTN FtwBufferSize; + EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; + + // + // Locate Fault Tolerant Write protocol + // + Status = gBS->LocateProtocol ( + &gEfiFaultTolerantWriteProtocolGuid, + NULL, + (VOID **) &FtwProtocol + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Gets firmware volume block handle by VariableBase. + // + Status = GetFvbHandleByAddress (VariableBase, &FvbHandle); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Gets LBA of block and offset by VariableBase. + // + Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Prepare for the variable data + // + FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size; + FtwBuffer = AllocatePool (FtwBufferSize); + if (FtwBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff); + CopyMem (FtwBuffer, Buffer, BufferSize); + + // + // FTW write record + // + Status = FtwProtocol->Write ( + FtwProtocol, + VarLba, // LBA + VarOffset, // Offset + FtwBufferSize, // NumBytes, + NULL, + FvbHandle, + FtwBuffer + ); + + FreePool (FtwBuffer); + return Status; +} diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c new file mode 100644 index 0000000000..d6c6686351 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c @@ -0,0 +1,3198 @@ +/** @file + The implementation of Extended SAL variable services. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Variable.h" +#include "AuthService.h" + +// +// Don't use module globals after the SetVirtualAddress map is signaled +// +ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; +CHAR16 *mVariableName[NUM_VAR_NAME] = { + L"PlatformLangCodes", + L"LangCodes", + L"PlatformLang", + L"Lang", + L"HwErrRec", + AUTHVAR_KEYDB_NAME, + EFI_SETUP_MODE_NAME, + EFI_PLATFORM_KEY_NAME, + EFI_KEY_EXCHANGE_KEY_NAME +}; + +GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL; + +// +// The current Hii implementation accesses this variable a larg # of times on every boot. +// Other common variables are only accessed a single time. This is why this cache algorithm +// only targets a single variable. Probably to get an performance improvement out of +// a Cache you would need a cache that improves the search performance for a variable. +// +VARIABLE_CACHE_ENTRY mVariableCache[] = { + { + &gEfiGlobalVariableGuid, + L"Lang", + 0x00000000, + 0x00, + NULL + }, + { + &gEfiGlobalVariableGuid, + L"PlatformLang", + 0x00000000, + 0x00, + NULL + } +}; + +/** + Acquires lock only at boot time. Simply returns at runtime. + + This is a temperary function which will be removed when + EfiAcquireLock() in UefiLib can handle the call in UEFI + Runtimer driver in RT phase. + It calls EfiAcquireLock() at boot time, and simply returns + at runtime. + + @param[in] Lock A pointer to the lock to acquire. + +**/ +VOID +AcquireLockOnlyAtBootTime ( + IN EFI_LOCK *Lock + ) +{ + if (!EfiAtRuntime ()) { + EfiAcquireLock (Lock); + } +} + +/** + Releases lock only at boot time. Simply returns at runtime. + + This is a temperary function which will be removed when + EfiReleaseLock() in UefiLib can handle the call in UEFI + Runtimer driver in RT phase. + It calls EfiReleaseLock() at boot time, and simply returns + at runtime + + @param[in] Lock A pointer to the lock to release. + +**/ +VOID +ReleaseLockOnlyAtBootTime ( + IN EFI_LOCK *Lock + ) +{ + if (!EfiAtRuntime ()) { + EfiReleaseLock (Lock); + } +} + +/** + Reads/Writes variable storage, volatile or non-volatile. + + This function reads or writes volatile or non-volatile variable stroage. + For volatile storage, it performs memory copy. + For non-volatile storage, it accesses data on firmware storage. Data + area to access can span multiple firmware blocks. + + @param[in] Write TRUE - Write variable store. + FALSE - Read variable store. + @param[in] Global Pointer to VARAIBLE_GLOBAL structure. + @param[in] Volatile TRUE - Variable is volatile. + FALSE - Variable is non-volatile. + @param[in] Instance Instance of FV Block services. + @param[in] StartAddress Start address of data to access. + @param[in] DataSize Size of data to access. + @param[in, out] Buffer For write, pointer to the buffer from which data is written. + For read, pointer to the buffer to hold the data read. + + @retval EFI_SUCCESS Variable store successfully accessed. + @retval EFI_INVALID_PARAMETER Data area to access exceeds valid variable storage. + +**/ +EFI_STATUS +AccessVariableStore ( + IN BOOLEAN Write, + IN VARIABLE_GLOBAL *Global, + IN BOOLEAN Volatile, + IN UINTN Instance, + IN EFI_PHYSICAL_ADDRESS StartAddress, + IN UINT32 DataSize, + IN OUT VOID *Buffer + ) +{ + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + UINTN BlockIndex; + UINTN LinearOffset; + UINTN CurrWriteSize; + UINTN CurrWritePtr; + UINT8 *CurrBuffer; + EFI_LBA LbaNumber; + UINTN Size; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + VARIABLE_STORE_HEADER *VolatileBase; + EFI_PHYSICAL_ADDRESS FvVolHdr; + EFI_STATUS Status; + VARIABLE_STORE_HEADER *VariableStoreHeader; + + FvVolHdr = 0; + FwVolHeader = NULL; + + if (Volatile) { + // + // If data is volatile, simply calculate the data pointer and copy memory. + // Data pointer should point to the actual address where data is to be + // accessed. + // + VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase); + + if ((StartAddress + DataSize) > ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) { + return EFI_INVALID_PARAMETER; + } + + // + // For volatile variable, a simple memory copy is enough. + // + if (Write) { + CopyMem ((VOID *) StartAddress, Buffer, DataSize); + } else { + CopyMem (Buffer, (VOID *) StartAddress, DataSize); + } + + return EFI_SUCCESS; + } + + // + // If data is non-volatile, calculate firmware volume header and data pointer. + // + Status = (EFI_STATUS) EsalCall ( + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO, + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI, + GetPhysicalAddressFunctionId, + Instance, + (UINT64) &FvVolHdr, + 0, + 0, + 0, + 0, + 0 + ).Status; + ASSERT_EFI_ERROR (Status); + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr); + ASSERT (FwVolHeader != NULL); + VariableStoreHeader = (VARIABLE_STORE_HEADER *)(FwVolHeader + 1); + + if ((StartAddress + DataSize) > ((EFI_PHYSICAL_ADDRESS) (UINTN) ((CHAR8 *)VariableStoreHeader + VariableStoreHeader->Size))) { + return EFI_INVALID_PARAMETER; + } + + LinearOffset = (UINTN) FwVolHeader; + CurrWritePtr = StartAddress; + CurrWriteSize = DataSize; + CurrBuffer = Buffer; + LbaNumber = 0; + + if (CurrWritePtr < LinearOffset) { + return EFI_INVALID_PARAMETER; + } + + // + // Traverse data blocks of this firmware storage to find the one where CurrWritePtr locates + // + for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { + for (BlockIndex = 0; BlockIndex < PtrBlockMapEntry->NumBlocks; BlockIndex++) { + if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) { + // + // Check to see if the data area to access spans multiple blocks. + // + if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) { + // + // If data area to access is contained in one block, just access and return. + // + if (Write) { + Status = (EFI_STATUS) EsalCall ( + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO, + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI, + WriteFunctionId, + Instance, + LbaNumber, + (CurrWritePtr - LinearOffset), + (UINT64) &CurrWriteSize, + (UINT64) CurrBuffer, + 0, + 0 + ).Status; + } else { + Status = (EFI_STATUS) EsalCall ( + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO, + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI, + ReadFunctionId, + Instance, + LbaNumber, + (CurrWritePtr - LinearOffset), + (UINT64) &CurrWriteSize, + (UINT64) CurrBuffer, + 0, + 0 + ).Status; + } + return Status; + } else { + // + // If data area to access spans multiple blocks, access this one and adjust for the next one. + // + Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr); + if (Write) { + Status = (EFI_STATUS) EsalCall ( + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO, + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI, + WriteFunctionId, + Instance, + LbaNumber, + (CurrWritePtr - LinearOffset), + (UINT64) &Size, + (UINT64) CurrBuffer, + 0, + 0 + ).Status; + } else { + Status = (EFI_STATUS) EsalCall ( + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO, + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI, + ReadFunctionId, + Instance, + LbaNumber, + (CurrWritePtr - LinearOffset), + (UINT64) &Size, + (UINT64) CurrBuffer, + 0, + 0 + ).Status; + } + if (EFI_ERROR (Status)) { + return Status; + } + // + // Adjust for the remaining data. + // + CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length; + CurrBuffer = CurrBuffer + Size; + CurrWriteSize = CurrWriteSize - Size; + } + } + + LinearOffset += PtrBlockMapEntry->Length; + LbaNumber++; + } + } + + return EFI_SUCCESS; +} + +/** + Retrieves header of volatile or non-volatile variable stroage. + + @param[in] VarStoreAddress Start address of variable storage. + @param[in] Volatile TRUE - Variable storage is volatile. + FALSE - Variable storage is non-volatile. + @param[in] Global Pointer to VARAIBLE_GLOBAL structure. + @param[in] Instance Instance of FV Block services. + @param[out] VarStoreHeader Pointer to VARIABLE_STORE_HEADER for output. + +**/ +VOID +GetVarStoreHeader ( + IN EFI_PHYSICAL_ADDRESS VarStoreAddress, + IN BOOLEAN Volatile, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance, + OUT VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + EFI_STATUS Status; + + Status = AccessVariableStore ( + FALSE, + Global, + Volatile, + Instance, + VarStoreAddress, + sizeof (VARIABLE_STORE_HEADER), + VarStoreHeader + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Checks variable header. + + This function checks if variable header is valid or not. + + @param[in] VariableAddress Start address of variable header. + @param[in] Volatile TRUE - Variable is volatile. + FALSE - Variable is non-volatile. + @param[in] Global Pointer to VARAIBLE_GLOBAL structure. + @param[in] Instance Instance of FV Block services. + @param[out] VariableHeader Pointer to VARIABLE_HEADER for output. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +IsValidVariableHeader ( + IN EFI_PHYSICAL_ADDRESS VariableAddress, + IN BOOLEAN Volatile, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance, + OUT VARIABLE_HEADER *VariableHeader OPTIONAL + ) +{ + EFI_STATUS Status; + VARIABLE_HEADER LocalVariableHeader; + + Status = AccessVariableStore ( + FALSE, + Global, + Volatile, + Instance, + VariableAddress, + sizeof (VARIABLE_HEADER), + &LocalVariableHeader + ); + + if (EFI_ERROR (Status) || LocalVariableHeader.StartId != VARIABLE_DATA) { + return FALSE; + } + + if (VariableHeader != NULL) { + CopyMem (VariableHeader, &LocalVariableHeader, sizeof (VARIABLE_HEADER)); + } + + return TRUE; +} + +/** + Gets status of variable store. + + This function gets the current status of variable store. + + @param[in] VarStoreHeader Pointer to header of variable store. + + @retval EfiRaw Variable store status is raw. + @retval EfiValid Variable store status is valid. + @retval EfiInvalid Variable store status is invalid. + +**/ +VARIABLE_STORE_STATUS +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + + if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) && + VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && + VarStoreHeader->State == VARIABLE_STORE_HEALTHY + ) { + + return EfiValid; + } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff && + VarStoreHeader->Size == 0xffffffff && + VarStoreHeader->Format == 0xff && + VarStoreHeader->State == 0xff + ) { + + return EfiRaw; + } else { + return EfiInvalid; + } +} + +/** + Gets the size of variable name. + + This function gets the size of variable name. + The variable is specified by its variable header. + If variable header contains raw data, just return 0. + + @param[in] Variable Pointer to the variable header. + + @return Size of variable name in bytes. + +**/ +UINTN +NameSizeOfVariable ( + IN VARIABLE_HEADER *Variable + ) +{ + if (Variable->State == (UINT8) (-1) || + Variable->DataSize == (UINT32) -1 || + Variable->NameSize == (UINT32) -1 || + Variable->Attributes == (UINT32) -1) { + return 0; + } + return (UINTN) Variable->NameSize; +} + +/** + Gets the size of variable data area. + + This function gets the size of variable data area. + The variable is specified by its variable header. + If variable header contains raw data, just return 0. + + @param[in] Variable Pointer to the variable header. + + @return Size of variable data area in bytes. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable + ) +{ + if (Variable->State == (UINT8) -1 || + Variable->DataSize == (UINT32) -1 || + Variable->NameSize == (UINT32) -1 || + Variable->Attributes == (UINT32) -1) { + return 0; + } + return (UINTN) Variable->DataSize; +} + +/** + Gets the pointer to variable name. + + This function gets the pointer to variable name. + The variable is specified by its variable header. + + @param[in] VariableAddress Start address of variable header. + @param[in] Volatile TRUE - Variable is volatile. + FALSE - Variable is non-volatile. + @param[in] Global Pointer to VARAIBLE_GLOBAL structure. + @param[in] Instance Instance of FV Block services. + @param[out] VariableName Buffer to hold variable name for output. + +**/ +VOID +GetVariableNamePtr ( + IN EFI_PHYSICAL_ADDRESS VariableAddress, + IN BOOLEAN Volatile, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance, + OUT CHAR16 *VariableName + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + VARIABLE_HEADER VariableHeader; + BOOLEAN IsValid; + + IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader); + ASSERT (IsValid); + + // + // Name area follows variable header. + // + Address = VariableAddress + sizeof (VARIABLE_HEADER); + + Status = AccessVariableStore ( + FALSE, + Global, + Volatile, + Instance, + Address, + VariableHeader.NameSize, + VariableName + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Gets the pointer to variable data area. + + This function gets the pointer to variable data area. + The variable is specified by its variable header. + + @param[in] VariableAddress Start address of variable header. + @param[in] Volatile TRUE - Variable is volatile. + FALSE - Variable is non-volatile. + @param[in] Global Pointer to VARAIBLE_GLOBAL structure. + @param[in] Instance Instance of FV Block services. + @param[out] VariableData Buffer to hold variable data for output. + +**/ +VOID +GetVariableDataPtr ( + IN EFI_PHYSICAL_ADDRESS VariableAddress, + IN BOOLEAN Volatile, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance, + OUT CHAR16 *VariableData + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Address; + VARIABLE_HEADER VariableHeader; + BOOLEAN IsValid; + + IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader); + ASSERT (IsValid); + + // + // Data area follows variable name. + // Be careful about pad size for alignment + // + Address = VariableAddress + sizeof (VARIABLE_HEADER); + Address += NameSizeOfVariable (&VariableHeader); + Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader)); + + Status = AccessVariableStore ( + FALSE, + Global, + Volatile, + Instance, + Address, + VariableHeader.DataSize, + VariableData + ); + ASSERT_EFI_ERROR (Status); +} + + +/** + Gets the pointer to the next variable header. + + This function gets the pointer to the next variable header. + The variable is specified by its variable header. + + @param[in] VariableAddress Start address of variable header. + @param[in] Volatile TRUE - Variable is volatile. + FALSE - Variable is non-volatile. + @param[in] Global Pointer to VARAIBLE_GLOBAL structure. + @param[in] Instance Instance of FV Block services. + + @return Pointer to the next variable header. + NULL if variable header is invalid. + +**/ +EFI_PHYSICAL_ADDRESS +GetNextVariablePtr ( + IN EFI_PHYSICAL_ADDRESS VariableAddress, + IN BOOLEAN Volatile, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance + ) +{ + EFI_PHYSICAL_ADDRESS Address; + VARIABLE_HEADER VariableHeader; + + if (!IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader)) { + return 0x0; + } + + // + // Header of next variable follows data area of this variable + // + Address = VariableAddress + sizeof (VARIABLE_HEADER); + Address += NameSizeOfVariable (&VariableHeader); + Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader)); + Address += DataSizeOfVariable (&VariableHeader); + Address += GET_PAD_SIZE (DataSizeOfVariable (&VariableHeader)); + + // + // Be careful about pad size for alignment + // + return HEADER_ALIGN (Address); +} + +/** + Gets the pointer to the first variable header in given variable store area. + + This function gets the pointer to the first variable header in given variable + store area. The variable store area is given by its start address. + + @param[in] VarStoreHeaderAddress Pointer to the header of variable store area. + + @return Pointer to the first variable header. + +**/ +EFI_PHYSICAL_ADDRESS +GetStartPointer ( + IN EFI_PHYSICAL_ADDRESS VarStoreHeaderAddress + ) +{ + return HEADER_ALIGN (VarStoreHeaderAddress + sizeof (VARIABLE_STORE_HEADER)); +} + +/** + Gets the pointer to the end of given variable store area. + + This function gets the pointer to the end of given variable store area. + The variable store area is given by its start address. + + @param[in] VarStoreHeaderAddress Pointer to the header of variable store area. + @param[in] Volatile TRUE - Variable is volatile. + FALSE - Variable is non-volatile. + @param[in] Global Pointer to VARAIBLE_GLOBAL structure. + @param[in] Instance Instance of FV Block services. + + @return Pointer to the end of given variable store area. + +**/ +EFI_PHYSICAL_ADDRESS +GetEndPointer ( + IN EFI_PHYSICAL_ADDRESS VarStoreHeaderAddress, + IN BOOLEAN Volatile, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance + ) +{ + EFI_STATUS Status; + VARIABLE_STORE_HEADER VariableStoreHeader; + + Status = AccessVariableStore ( + FALSE, + Global, + Volatile, + Instance, + VarStoreHeaderAddress, + sizeof (VARIABLE_STORE_HEADER), + &VariableStoreHeader + ); + + ASSERT_EFI_ERROR (Status); + return HEADER_ALIGN (VarStoreHeaderAddress + VariableStoreHeader.Size); +} + +/** + Updates variable info entry in EFI system table for statistical information. + + Routine used to track statistical information about variable usage. + The data is stored in the EFI system table so it can be accessed later. + VariableInfo.efi can dump out the table. Only Boot Services variable + accesses are tracked by this code. The PcdVariableCollectStatistics + build flag controls if this feature is enabled. + A read that hits in the cache will have Read and Cache true for + the transaction. Data is allocated by this routine, but never + freed. + + @param[in] VariableName Name of the Variable to track. + @param[in] VendorGuid Guid of the Variable to track. + @param[in] Volatile TRUE if volatile FALSE if non-volatile. + @param[in] Read TRUE if GetVariable() was called. + @param[in] Write TRUE if SetVariable() was called. + @param[in] Delete TRUE if deleted via SetVariable(). + @param[in] Cache TRUE for a cache hit. + +**/ +VOID +UpdateVariableInfo ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN BOOLEAN Volatile, + IN BOOLEAN Read, + IN BOOLEAN Write, + IN BOOLEAN Delete, + IN BOOLEAN Cache + ) +{ + VARIABLE_INFO_ENTRY *Entry; + + if (FeaturePcdGet (PcdVariableCollectStatistics)) { + + if (EfiAtRuntime ()) { + // + // Don't collect statistics at runtime + // + return; + } + + if (gVariableInfo == NULL) { + // + // on the first call allocate a entry and place a pointer to it in + // the EFI System Table + // + gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); + ASSERT (gVariableInfo != NULL); + + CopyGuid (&gVariableInfo->VendorGuid, VendorGuid); + gVariableInfo->Name = AllocatePool (StrSize (VariableName)); + ASSERT (gVariableInfo->Name != NULL); + StrCpy (gVariableInfo->Name, VariableName); + gVariableInfo->Volatile = Volatile; + + gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo); + } + + + for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) { + if (CompareGuid (VendorGuid, &Entry->VendorGuid)) { + if (StrCmp (VariableName, Entry->Name) == 0) { + // + // Find the entry matching both variable name and vender GUID, + // and update counters for all types. + // + if (Read) { + Entry->ReadCount++; + } + if (Write) { + Entry->WriteCount++; + } + if (Delete) { + Entry->DeleteCount++; + } + if (Cache) { + Entry->CacheCount++; + } + + return; + } + } + + if (Entry->Next == NULL) { + // + // If the entry is not in the table add it. + // Next iteration of the loop will fill in the data + // + Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); + ASSERT (Entry->Next != NULL); + + CopyGuid (&Entry->Next->VendorGuid, VendorGuid); + Entry->Next->Name = AllocatePool (StrSize (VariableName)); + ASSERT (Entry->Next->Name != NULL); + StrCpy (Entry->Next->Name, VariableName); + Entry->Next->Volatile = Volatile; + } + + } + } +} + +/** + Updates variable in cache. + + This function searches the variable cache. If the variable to set exists in the cache, + it updates the variable in cache. It has the same parameters with UEFI SetVariable() + service. + + @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's + variable. Each VariableName is unique for each VendorGuid. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] Attributes Attributes bitmask to set for the variable. + @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the + variable to be deleted. + @param[in] Data The contents for the variable. + +**/ +VOID +UpdateVariableCache ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + VARIABLE_CACHE_ENTRY *Entry; + UINTN Index; + + if (EfiAtRuntime ()) { + // + // Don't use the cache at runtime + // + return; + } + + // + // Searches cache for the variable to update. If it exists, update it. + // + for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) { + if (CompareGuid (VendorGuid, Entry->Guid)) { + if (StrCmp (VariableName, Entry->Name) == 0) { + Entry->Attributes = Attributes; + if (DataSize == 0) { + // + // If DataSize is 0, delete the variable. + // + if (Entry->DataSize != 0) { + FreePool (Entry->Data); + } + Entry->DataSize = DataSize; + } else if (DataSize == Entry->DataSize) { + // + // If size of data does not change, simply copy data + // + CopyMem (Entry->Data, Data, DataSize); + } else { + // + // If size of data changes, allocate pool and copy data. + // + Entry->Data = AllocatePool (DataSize); + Entry->DataSize = DataSize; + CopyMem (Entry->Data, Data, DataSize); + } + } + } + } +} + + +/** + Search the cache to check if the variable is in it. + + This function searches the variable cache. If the variable to find exists, return its data + and attributes. + + @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's + variable. Each VariableName is unique for each VendorGuid. + @param[in] VendorGuid A unique identifier for the vendor + @param[out] Attributes Pointer to the attributes bitmask of the variable for output. + @param[in, out] DataSize On input, size of the buffer of Data. + On output, size of the variable's data. + @param[out] Data Pointer to the data buffer for output. + + @retval EFI_SUCCESS VariableGuid & VariableName data was returned. + @retval EFI_NOT_FOUND No matching variable found in cache. + @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return. + +**/ +EFI_STATUS +FindVariableInCache ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + VARIABLE_CACHE_ENTRY *Entry; + UINTN Index; + + if (EfiAtRuntime ()) { + // + // Don't use the cache at runtime + // + return EFI_NOT_FOUND; + } + + // + // Searches cache for the variable + // + for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) { + if (CompareGuid (VendorGuid, Entry->Guid)) { + if (StrCmp (VariableName, Entry->Name) == 0) { + if (Entry->DataSize == 0) { + // + // Variable has been deleted so return EFI_NOT_FOUND + // + return EFI_NOT_FOUND; + } else if (Entry->DataSize > *DataSize) { + // + // If buffer is too small, return the size needed and EFI_BUFFER_TOO_SMALL + // + *DataSize = Entry->DataSize; + return EFI_BUFFER_TOO_SMALL; + } else { + // + // If buffer is large enough, return the data + // + *DataSize = Entry->DataSize; + CopyMem (Data, Entry->Data, Entry->DataSize); + // + // If Attributes is not NULL, return the variable's attribute. + // + if (Attributes != NULL) { + *Attributes = Entry->Attributes; + } + return EFI_SUCCESS; + } + } + } + } + + return EFI_NOT_FOUND; +} + +/** + Finds variable in volatile and non-volatile storage areas. + + This code finds variable in volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + Otherwise, VariableName and VendorGuid are compared. + + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Vendor GUID to be found. + @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output, + including the range searched and the target position. + @param[in] Global Pointer to VARIABLE_GLOBAL structure, including + base of volatile variable storage area, base of + NV variable storage area, and a lock. + @param[in] Instance Instance of FV Block services. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while + VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_INVALID_PARAMETER Variable not found. + +**/ +EFI_STATUS +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance + ) +{ + EFI_PHYSICAL_ADDRESS Variable[2]; + EFI_PHYSICAL_ADDRESS InDeletedVariable; + EFI_PHYSICAL_ADDRESS VariableStoreHeader[2]; + UINTN InDeletedStorageIndex; + UINTN Index; + CHAR16 LocalVariableName[MAX_NAME_SIZE]; + BOOLEAN Volatile; + VARIABLE_HEADER VariableHeader; + + // + // 0: Volatile, 1: Non-Volatile + // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName + // make use of this mapping to implement search algorithme. + // + VariableStoreHeader[0] = Global->VolatileVariableBase; + VariableStoreHeader[1] = Global->NonVolatileVariableBase; + + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable[0] = GetStartPointer (VariableStoreHeader[0]); + Variable[1] = GetStartPointer (VariableStoreHeader[1]); + + if (VariableName[0] != 0 && VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Find the variable by walk through volatile and then non-volatile variable store + // + InDeletedVariable = 0x0; + InDeletedStorageIndex = 0; + Volatile = TRUE; + for (Index = 0; Index < 2; Index++) { + if (Index == 1) { + Volatile = FALSE; + } + while (IsValidVariableHeader (Variable[Index], Volatile, Global, Instance, &VariableHeader)) { + if (VariableHeader.State == VAR_ADDED || + VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) + ) { + if (!EfiAtRuntime () || ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { + if (VariableName[0] == 0) { + // + // If VariableName is an empty string, then we just find the first qualified variable + // without comparing VariableName and VendorGuid + // + if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + // + // If variable is in delete transition, record it. + // + InDeletedVariable = Variable[Index]; + InDeletedStorageIndex = Index; + } else { + // + // If variable is not in delete transition, return it. + // + PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance); + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = Volatile; + + return EFI_SUCCESS; + } + } else { + // + // If VariableName is not an empty string, then VariableName and VendorGuid are compared. + // + if (CompareGuid (VendorGuid, &VariableHeader.VendorGuid)) { + GetVariableNamePtr ( + Variable[Index], + Volatile, + Global, + Instance, + LocalVariableName + ); + + ASSERT (NameSizeOfVariable (&VariableHeader) != 0); + if (CompareMem (VariableName, LocalVariableName, NameSizeOfVariable (&VariableHeader)) == 0) { + if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + // + // If variable is in delete transition, record it. + // We will use if only no VAR_ADDED variable is found. + // + InDeletedVariable = Variable[Index]; + InDeletedStorageIndex = Index; + } else { + // + // If variable is not in delete transition, return it. + // + PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance); + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = Volatile; + + return EFI_SUCCESS; + } + } + } + } + } + } + + Variable[Index] = GetNextVariablePtr ( + Variable[Index], + Volatile, + Global, + Instance + ); + } + if (InDeletedVariable != 0x0) { + // + // If no VAR_ADDED variable is found, and only variable in delete transition, then use this one. + // + PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]); + PtrTrack->EndPtr = GetEndPointer ( + VariableStoreHeader[InDeletedStorageIndex], + (BOOLEAN)(InDeletedStorageIndex == 0), + Global, + Instance + ); + PtrTrack->CurrPtr = InDeletedVariable; + PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0); + return EFI_SUCCESS; + } + } + PtrTrack->CurrPtr = 0x0; + return EFI_NOT_FOUND; +} + +/** + Variable store garbage collection and reclaim operation. + + @param[in] VariableBase Base address of variable store area. + @param[out] LastVariableOffset Offset of last variable. + @param[in] IsVolatile The variable store is volatile or not, + if it is non-volatile, need FTW. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + @param[in] UpdatingVariable Pointer to header of the variable that is being updated. + + @retval EFI_SUCCESS Variable store successfully reclaimed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate memory buffer to hold all valid variables. + +**/ +EFI_STATUS +Reclaim ( + IN EFI_PHYSICAL_ADDRESS VariableBase, + OUT UINTN *LastVariableOffset, + IN BOOLEAN IsVolatile, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global, + IN EFI_PHYSICAL_ADDRESS UpdatingVariable + ) +{ + EFI_PHYSICAL_ADDRESS Variable; + EFI_PHYSICAL_ADDRESS AddedVariable; + EFI_PHYSICAL_ADDRESS NextVariable; + EFI_PHYSICAL_ADDRESS NextAddedVariable; + VARIABLE_STORE_HEADER VariableStoreHeader; + VARIABLE_HEADER VariableHeader; + VARIABLE_HEADER AddedVariableHeader; + CHAR16 VariableName[MAX_NAME_SIZE]; + CHAR16 AddedVariableName[MAX_NAME_SIZE]; + UINT8 *ValidBuffer; + UINTN MaximumBufferSize; + UINTN VariableSize; + UINTN NameSize; + UINT8 *CurrPtr; + BOOLEAN FoundAdded; + EFI_STATUS Status; + VARIABLE_GLOBAL *VariableGlobal; + UINT32 Instance; + + VariableGlobal = &Global->VariableGlobal[VirtualMode]; + Instance = Global->FvbInstance; + + GetVarStoreHeader (VariableBase, IsVolatile, VariableGlobal, Instance, &VariableStoreHeader); + // + // recaluate the total size of Common/HwErr type variables in non-volatile area. + // + if (!IsVolatile) { + Global->CommonVariableTotalSize = 0; + Global->HwErrVariableTotalSize = 0; + } + + // + // Calculate the size of buffer needed to gather all valid variables + // + Variable = GetStartPointer (VariableBase); + MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER); + + while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) { + NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance); + // + // Collect VAR_ADDED variables, and variables in delete transition status. + // + if (VariableHeader.State == VAR_ADDED || + VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) + ) { + VariableSize = NextVariable - Variable; + MaximumBufferSize += VariableSize; + } + + Variable = NextVariable; + } + + // + // Reserve the 1 Bytes with Oxff to identify the + // end of the variable buffer. + // + MaximumBufferSize += 1; + ValidBuffer = AllocatePool (MaximumBufferSize); + if (ValidBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SetMem (ValidBuffer, MaximumBufferSize, 0xff); + + // + // Copy variable store header + // + CopyMem (ValidBuffer, &VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER)); + CurrPtr = (UINT8 *) GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer); + + // + // Reinstall all ADDED variables + // + Variable = GetStartPointer (VariableBase); + while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) { + NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance); + if (VariableHeader.State == VAR_ADDED) { + VariableSize = NextVariable - Variable; + CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); + CurrPtr += VariableSize; + if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + Global->HwErrVariableTotalSize += VariableSize; + } else if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + Global->CommonVariableTotalSize += VariableSize; + } + } + Variable = NextVariable; + } + // + // Reinstall in delete transition variables + // + Variable = GetStartPointer (VariableBase); + while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) { + NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance); + if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + + // + // Buffer has cached all ADDED variable. + // Per IN_DELETED variable, we have to guarantee that + // no ADDED one in previous buffer. + // + FoundAdded = FALSE; + AddedVariable = GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer); + while (IsValidVariableHeader (AddedVariable, IsVolatile, VariableGlobal, Instance, &AddedVariableHeader)) { + NextAddedVariable = GetNextVariablePtr (AddedVariable, IsVolatile, VariableGlobal, Instance); + NameSize = NameSizeOfVariable (&AddedVariableHeader); + if (CompareGuid (&AddedVariableHeader.VendorGuid, &VariableHeader.VendorGuid) && + NameSize == NameSizeOfVariable (&VariableHeader) + ) { + GetVariableNamePtr (Variable, IsVolatile, VariableGlobal, Instance, VariableName); + GetVariableNamePtr (AddedVariable, IsVolatile, VariableGlobal, Instance, AddedVariableName); + if (CompareMem (VariableName, AddedVariableName, NameSize) == 0) { + // + // If ADDED variable with the same name and vender GUID has been reinstalled, + // then discard this IN_DELETED copy. + // + FoundAdded = TRUE; + break; + } + } + AddedVariable = NextAddedVariable; + } + // + // Add IN_DELETE variables that have not been added to buffer + // + if (!FoundAdded) { + VariableSize = NextVariable - Variable; + CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); + if (Variable != UpdatingVariable) { + // + // Make this IN_DELETE instance valid if: + // 1. No valid instance of this variable exists. + // 2. It is not the variable that is going to be updated. + // + ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED; + } + CurrPtr += VariableSize; + if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + Global->HwErrVariableTotalSize += VariableSize; + } else if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + Global->CommonVariableTotalSize += VariableSize; + } + } + } + Variable = NextVariable; + } + + if (IsVolatile) { + // + // If volatile variable store, just copy valid buffer + // + SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader.Size, 0xff); + CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)); + Status = EFI_SUCCESS; + } else { + // + // If non-volatile variable store, perform FTW here. + // Write ValidBuffer to destination specified by VariableBase. + // + Status = FtwVariableSpace ( + VariableBase, + ValidBuffer, + (UINTN) (CurrPtr - (UINT8 *) ValidBuffer) + ); + } + if (!EFI_ERROR (Status)) { + *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer); + } else { + *LastVariableOffset = 0; + } + + FreePool (ValidBuffer); + + return Status; +} + +/** + Get index from supported language codes according to language string. + + This code is used to get corresponding index in supported language codes. It can handle + RFC4646 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index. + In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index. + + For example: + SupportedLang = "engfraengfra" + Lang = "eng" + Iso639Language = TRUE + The return value is "0". + Another example: + SupportedLang = "en;fr;en-US;fr-FR" + Lang = "fr-FR" + Iso639Language = FALSE + The return value is "3". + + @param[in] SupportedLang Platform supported language codes. + @param[in] Lang Configured language. + @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646. + + @return The index of language in the language codes. + +**/ +UINTN +GetIndexFromSupportedLangCodes( + IN CHAR8 *SupportedLang, + IN CHAR8 *Lang, + IN BOOLEAN Iso639Language + ) +{ + UINTN Index; + UINTN CompareLength; + UINTN LanguageLength; + + if (Iso639Language) { + CompareLength = ISO_639_2_ENTRY_SIZE; + for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) { + if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) { + // + // Successfully find the index of Lang string in SupportedLang string. + // + Index = Index / CompareLength; + return Index; + } + } + ASSERT (FALSE); + return 0; + } else { + // + // Compare RFC4646 language code + // + Index = 0; + for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++); + + for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) { + // + // Skip ';' characters in SupportedLang + // + for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++); + // + // Determine the length of the next language code in SupportedLang + // + for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++); + + if ((CompareLength == LanguageLength) && + (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) { + // + // Successfully find the index of Lang string in SupportedLang string. + // + return Index; + } + } + ASSERT (FALSE); + return 0; + } +} + +/** + Get language string from supported language codes according to index. + + This code is used to get corresponding language string in supported language codes. It can handle + RFC4646 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index. + In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index. + + For example: + SupportedLang = "engfraengfra" + Index = "1" + Iso639Language = TRUE + The return value is "fra". + Another example: + SupportedLang = "en;fr;en-US;fr-FR" + Index = "1" + Iso639Language = FALSE + The return value is "fr". + + @param[in] SupportedLang Platform supported language codes. + @param[in] Index the index in supported language codes. + @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + + @return The language string in the language codes. + +**/ +CHAR8 * +GetLangFromSupportedLangCodes ( + IN CHAR8 *SupportedLang, + IN UINTN Index, + IN BOOLEAN Iso639Language, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ) +{ + UINTN SubIndex; + UINTN CompareLength; + CHAR8 *Supported; + + SubIndex = 0; + Supported = SupportedLang; + if (Iso639Language) { + // + // according to the index of Lang string in SupportedLang string to get the language. + // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation. + // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string. + // + CompareLength = ISO_639_2_ENTRY_SIZE; + Global->Lang[CompareLength] = '\0'; + return CopyMem (Global->Lang, SupportedLang + Index * CompareLength, CompareLength); + + } else { + while (TRUE) { + // + // take semicolon as delimitation, sequentially traverse supported language codes. + // + for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) { + Supported++; + } + if ((*Supported == '\0') && (SubIndex != Index)) { + // + // Have completed the traverse, but not find corrsponding string. + // This case is not allowed to happen. + // + ASSERT(FALSE); + return NULL; + } + if (SubIndex == Index) { + // + // according to the index of Lang string in SupportedLang string to get the language. + // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation. + // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string. + // + Global->PlatformLang[VirtualMode][CompareLength] = '\0'; + return CopyMem (Global->PlatformLang[VirtualMode], Supported - CompareLength, CompareLength); + } + SubIndex++; + + // + // Skip ';' characters in Supported + // + for (; *Supported != '\0' && *Supported == ';'; Supported++); + } + } +} + +/** + Returns a pointer to an allocated buffer that contains the best matching language + from a set of supported languages. + + This function supports both ISO 639-2 and RFC 4646 language codes, but language + code types may not be mixed in a single call to this function. This function + supports a variable argument list that allows the caller to pass in a prioritized + list of language codes to test against all the language codes in SupportedLanguages. + + If SupportedLanguages is NULL, then ASSERT(). + + @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that + contains a set of language codes in the format + specified by Iso639Language. + @param[in] Iso639Language If TRUE, then all language codes are assumed to be + in ISO 639-2 format. If FALSE, then all language + codes are assumed to be in RFC 4646 language format. + @param[in] VirtualMode Current calling mode for this function. + @param[in] ... A variable argument list that contains pointers to + Null-terminated ASCII strings that contain one or more + language codes in the format specified by Iso639Language. + The first language code from each of these language + code lists is used to determine if it is an exact or + close match to any of the language codes in + SupportedLanguages. Close matches only apply to RFC 4646 + language codes, and the matching algorithm from RFC 4647 + is used to determine if a close match is present. If + an exact or close match is found, then the matching + language code from SupportedLanguages is returned. If + no matches are found, then the next variable argument + parameter is evaluated. The variable argument list + is terminated by a NULL. + + @retval NULL The best matching language could not be found in SupportedLanguages. + @retval NULL There are not enough resources available to return the best matching + language. + @retval Other A pointer to a Null-terminated ASCII string that is the best matching + language in SupportedLanguages. + +**/ +CHAR8 * +VariableGetBestLanguage ( + IN CONST CHAR8 *SupportedLanguages, + IN BOOLEAN Iso639Language, + IN BOOLEAN VirtualMode, + ... + ) +{ + VA_LIST Args; + CHAR8 *Language; + UINTN CompareLength; + UINTN LanguageLength; + CONST CHAR8 *Supported; + CHAR8 *Buffer; + + ASSERT (SupportedLanguages != NULL); + + VA_START (Args, VirtualMode); + while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) { + // + // Default to ISO 639-2 mode + // + CompareLength = 3; + LanguageLength = MIN (3, AsciiStrLen (Language)); + + // + // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language + // + if (!Iso639Language) { + for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++); + } + + // + // Trim back the length of Language used until it is empty + // + while (LanguageLength > 0) { + // + // Loop through all language codes in SupportedLanguages + // + for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) { + // + // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages + // + if (!Iso639Language) { + // + // Skip ';' characters in Supported + // + for (; *Supported != '\0' && *Supported == ';'; Supported++); + // + // Determine the length of the next language code in Supported + // + for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++); + // + // If Language is longer than the Supported, then skip to the next language + // + if (LanguageLength > CompareLength) { + continue; + } + } + // + // See if the first LanguageLength characters in Supported match Language + // + if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) { + VA_END (Args); + + Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang[VirtualMode]; + Buffer[CompareLength] = '\0'; + return CopyMem (Buffer, Supported, CompareLength); + } + } + + if (Iso639Language) { + // + // If ISO 639 mode, then each language can only be tested once + // + LanguageLength = 0; + } else { + // + // If RFC 4646 mode, then trim Language from the right to the next '-' character + // + for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--); + } + } + } + VA_END (Args); + + // + // No matches were found + // + return NULL; +} + +/** + Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang. + + When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes. + According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization, + and are read-only. Therefore, in variable driver, only store the original value for other use. + + @param[in] VariableName Name of variable. + @param[in] Data Variable data. + @param[in] DataSize Size of data. 0 means delete. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + +**/ +VOID +AutoUpdateLangVariable( + IN CHAR16 *VariableName, + IN VOID *Data, + IN UINTN DataSize, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ) +{ + EFI_STATUS Status; + CHAR8 *BestPlatformLang; + CHAR8 *BestLang; + UINTN Index; + UINT32 Attributes; + VARIABLE_POINTER_TRACK Variable; + BOOLEAN SetLanguageCodes; + CHAR16 **PredefinedVariableName; + VARIABLE_GLOBAL *VariableGlobal; + UINT32 Instance; + + // + // Don't do updates for delete operation + // + if (DataSize == 0) { + return; + } + + SetLanguageCodes = FALSE; + VariableGlobal = &Global->VariableGlobal[VirtualMode]; + Instance = Global->FvbInstance; + + + PredefinedVariableName = &Global->VariableName[VirtualMode][0]; + if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG_CODES]) == 0) { + // + // PlatformLangCodes is a volatile variable, so it can not be updated at runtime. + // + if (EfiAtRuntime ()) { + return; + } + + SetLanguageCodes = TRUE; + + // + // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only + // Therefore, in variable driver, only store the original value for other use. + // + if (Global->PlatformLangCodes[VirtualMode] != NULL) { + FreePool (Global->PlatformLangCodes[VirtualMode]); + } + Global->PlatformLangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data); + ASSERT (mVariableModuleGlobal->PlatformLangCodes[VirtualMode] != NULL); + + // + // PlatformLang holds a single language from PlatformLangCodes, + // so the size of PlatformLangCodes is enough for the PlatformLang. + // + if (Global->PlatformLang[VirtualMode] != NULL) { + FreePool (Global->PlatformLang[VirtualMode]); + } + Global->PlatformLang[VirtualMode] = AllocateRuntimePool (DataSize); + ASSERT (Global->PlatformLang[VirtualMode] != NULL); + + } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG_CODES]) == 0) { + // + // LangCodes is a volatile variable, so it can not be updated at runtime. + // + if (EfiAtRuntime ()) { + return; + } + + SetLanguageCodes = TRUE; + + // + // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only + // Therefore, in variable driver, only store the original value for other use. + // + if (Global->LangCodes[VirtualMode] != NULL) { + FreePool (Global->LangCodes[VirtualMode]); + } + Global->LangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data); + ASSERT (Global->LangCodes[VirtualMode] != NULL); + } + + if (SetLanguageCodes + && (Global->PlatformLangCodes[VirtualMode] != NULL) + && (Global->LangCodes[VirtualMode] != NULL)) { + // + // Update Lang if PlatformLang is already set + // Update PlatformLang if Lang is already set + // + Status = FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance); + if (!EFI_ERROR (Status)) { + // + // Update Lang + // + VariableName = PredefinedVariableName[VAR_PLATFORM_LANG]; + } else { + Status = FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance); + if (!EFI_ERROR (Status)) { + // + // Update PlatformLang + // + VariableName = PredefinedVariableName[VAR_LANG]; + } else { + // + // Neither PlatformLang nor Lang is set, directly return + // + return; + } + } + Data = (VOID *) GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance); + GetVariableDataPtr ((EFI_PHYSICAL_ADDRESS) Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, (CHAR16 *) Data); + + Status = AccessVariableStore ( + FALSE, + VariableGlobal, + Variable.Volatile, + Instance, + (UINTN) &(((VARIABLE_HEADER *)Variable.CurrPtr)->DataSize), + sizeof (DataSize), + &DataSize + ); + ASSERT_EFI_ERROR (Status); + } + + // + // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions. + // + Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; + + if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG]) == 0) { + // + // Update Lang when PlatformLangCodes/LangCodes were set. + // + if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) { + // + // When setting PlatformLang, firstly get most matched language string from supported language codes. + // + BestPlatformLang = VariableGetBestLanguage (Global->PlatformLangCodes[VirtualMode], FALSE, VirtualMode, Data, NULL); + if (BestPlatformLang != NULL) { + // + // Get the corresponding index in language codes. + // + Index = GetIndexFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], BestPlatformLang, FALSE); + + // + // Get the corresponding ISO639 language tag according to RFC4646 language tag. + // + BestLang = GetLangFromSupportedLangCodes (Global->LangCodes[VirtualMode], Index, TRUE, VirtualMode, Global); + + // + // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously. + // + FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance); + + Status = UpdateVariable ( + PredefinedVariableName[VAR_LANG], + Global->GlobalVariableGuid[VirtualMode], + BestLang, + ISO_639_2_ENTRY_SIZE + 1, + Attributes, + 0, + 0, + VirtualMode, + Global, + &Variable + ); + + DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang)); + + ASSERT_EFI_ERROR (Status); + } + } + + } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG]) == 0) { + // + // Update PlatformLang when PlatformLangCodes/LangCodes were set. + // + if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) { + // + // When setting Lang, firstly get most matched language string from supported language codes. + // + BestLang = VariableGetBestLanguage (Global->LangCodes[VirtualMode], TRUE, VirtualMode, Data, NULL); + if (BestLang != NULL) { + // + // Get the corresponding index in language codes. + // + Index = GetIndexFromSupportedLangCodes (Global->LangCodes[VirtualMode], BestLang, TRUE); + + // + // Get the corresponding RFC4646 language tag according to ISO639 language tag. + // + BestPlatformLang = GetLangFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], Index, FALSE, VirtualMode, Global); + + // + // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously. + // + FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance); + + Status = UpdateVariable ( + PredefinedVariableName[VAR_PLATFORM_LANG], + Global->GlobalVariableGuid[VirtualMode], + BestPlatformLang, + AsciiStrSize (BestPlatformLang), + Attributes, + 0, + 0, + VirtualMode, + Global, + &Variable + ); + + DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang)); + ASSERT_EFI_ERROR (Status); + } + } + } +} + +/** + Update the variable region with Variable information. These are the same + arguments as the EFI Variable services. + + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] Data Variable data. + @param[in] DataSize Size of data. 0 means delete. + @param[in] Attributes Attributes of the variable. + @param[in] KeyIndex Index of associated public key. + @param[in] MonotonicCount Value of associated monotonic count. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + @param[in] Variable The variable information which is used to keep track of variable usage. + + @retval EFI_SUCCESS The update operation is success. + @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region. + +**/ +EFI_STATUS +EFIAPI +UpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL, + IN UINT32 KeyIndex OPTIONAL, + IN UINT64 MonotonicCount OPTIONAL, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global, + IN VARIABLE_POINTER_TRACK *Variable + ) +{ + EFI_STATUS Status; + VARIABLE_HEADER *NextVariable; + UINTN VarNameOffset; + UINTN VarDataOffset; + UINTN VarNameSize; + UINTN VarSize; + BOOLEAN Volatile; + UINT8 State; + VARIABLE_HEADER VariableHeader; + VARIABLE_HEADER *NextVariableHeader; + BOOLEAN Valid; + BOOLEAN Reclaimed; + VARIABLE_STORE_HEADER VariableStoreHeader; + UINTN ScratchSize; + VARIABLE_GLOBAL *VariableGlobal; + UINT32 Instance; + + VariableGlobal = &Global->VariableGlobal[VirtualMode]; + Instance = Global->FvbInstance; + + Reclaimed = FALSE; + + if (Variable->CurrPtr != 0) { + + Valid = IsValidVariableHeader (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, &VariableHeader); + if (!Valid) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Update/Delete existing variable + // + Volatile = Variable->Volatile; + + if (EfiAtRuntime ()) { + // + // If EfiAtRuntime and the variable is Volatile and Runtime Access, + // the volatile is ReadOnly, and SetVariable should be aborted and + // return EFI_WRITE_PROTECTED. + // + if (Variable->Volatile) { + Status = EFI_WRITE_PROTECTED; + goto Done; + } + // + // Only variable have NV attribute can be updated/deleted in Runtime + // + if ((VariableHeader.Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } + // + // Setting a data variable with no access, or zero DataSize attributes + // specified causes it to be deleted. + // + if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { + State = VariableHeader.State; + State &= VAR_DELETED; + + Status = AccessVariableStore ( + TRUE, + VariableGlobal, + Variable->Volatile, + Instance, + (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State), + sizeof (UINT8), + &State + ); + if (!EFI_ERROR (Status)) { + UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE); + UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data); + } + goto Done; + } + // + // Logic comes here to update variable. + // If the variable is marked valid and the same data has been passed in + // then return to the caller immediately. + // + if (DataSizeOfVariable (&VariableHeader) == DataSize) { + NextVariable = (VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance); + GetVariableDataPtr (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, (CHAR16 *) NextVariable); + if (CompareMem (Data, (VOID *) NextVariable, DataSize) == 0) { + UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE); + Status = EFI_SUCCESS; + goto Done; + } + } + if ((VariableHeader.State == VAR_ADDED) || + (VariableHeader.State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) { + // + // If new data is different from the old one, mark the old one as VAR_IN_DELETED_TRANSITION. + // It will be deleted if new variable is successfully written. + // + State = VariableHeader.State; + State &= VAR_IN_DELETED_TRANSITION; + + Status = AccessVariableStore ( + TRUE, + VariableGlobal, + Variable->Volatile, + Instance, + (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State), + sizeof (UINT8), + &State + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + } else { + // + // Create a new variable + // + + // + // Make sure we are trying to create a new variable. + // Setting a data variable with no access, or zero DataSize attributes means to delete it. + // + if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Only variable have NV|RT attribute can be created in Runtime + // + if (EfiAtRuntime () && + (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } + + // + // Function part - create a new variable and copy the data. + // Both update a variable and create a variable will come here. + // + // Tricky part: Use scratch data area at the end of volatile variable store + // as a temporary storage. + // + NextVariable = (VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance); + ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); + NextVariableHeader = (VARIABLE_HEADER *) NextVariable; + + SetMem (NextVariableHeader, ScratchSize, 0xff); + + NextVariableHeader->StartId = VARIABLE_DATA; + NextVariableHeader->Attributes = Attributes; + NextVariableHeader->PubKeyIndex = KeyIndex; + NextVariableHeader->MonotonicCount = MonotonicCount; + NextVariableHeader->Reserved = 0; + VarNameOffset = sizeof (VARIABLE_HEADER); + VarNameSize = StrSize (VariableName); + CopyMem ( + (UINT8 *) ((UINTN)NextVariable + VarNameOffset), + VariableName, + VarNameSize + ); + VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize); + CopyMem ( + (UINT8 *) ((UINTN)NextVariable + VarDataOffset), + Data, + DataSize + ); + CopyMem (&NextVariableHeader->VendorGuid, VendorGuid, sizeof (EFI_GUID)); + // + // There will be pad bytes after Data, the NextVariable->NameSize and + // NextVariable->DataSize should not include pad size so that variable + // service can get actual size in GetVariable. + // + NextVariableHeader->NameSize = (UINT32)VarNameSize; + NextVariableHeader->DataSize = (UINT32)DataSize; + + // + // The actual size of the variable that stores in storage should + // include pad size. + // + VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize); + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + // + // Create a nonvolatile variable + // + Volatile = FALSE; + + GetVarStoreHeader (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance, &VariableStoreHeader); + if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) + && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize))) + || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) + && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) { + if (EfiAtRuntime ()) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + // + // Perform garbage collection & reclaim operation + // + Status = Reclaim (VariableGlobal->NonVolatileVariableBase, &(Global->NonVolatileLastVariableOffset), FALSE, VirtualMode, Global, Variable->CurrPtr); + if (EFI_ERROR (Status)) { + goto Done; + } + + Reclaimed = TRUE; + // + // If still no enough space, return out of resources + // + if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) + && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize))) + || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) + && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + } + // + // Four steps + // 1. Write variable header + // 2. Set variable state to header valid + // 3. Write variable data + // 4. Set variable state to valid + // + // + // Step 1: + // + Status = AccessVariableStore ( + TRUE, + VariableGlobal, + FALSE, + Instance, + VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset, + sizeof (VARIABLE_HEADER), + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Step 2: + // + NextVariableHeader->State = VAR_HEADER_VALID_ONLY; + Status = AccessVariableStore ( + TRUE, + VariableGlobal, + FALSE, + Instance, + VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset, + sizeof (VARIABLE_HEADER), + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Step 3: + // + Status = AccessVariableStore ( + TRUE, + VariableGlobal, + FALSE, + Instance, + VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER), + (UINT32) VarSize - sizeof (VARIABLE_HEADER), + (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER) + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Step 4: + // + NextVariableHeader->State = VAR_ADDED; + Status = AccessVariableStore ( + TRUE, + VariableGlobal, + FALSE, + Instance, + VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset, + sizeof (VARIABLE_HEADER), + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + Global->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize); + + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) { + Global->HwErrVariableTotalSize += HEADER_ALIGN (VarSize); + } else { + Global->CommonVariableTotalSize += HEADER_ALIGN (VarSize); + } + } else { + // + // Create a volatile variable + // + Volatile = TRUE; + + if ((UINT32) (HEADER_ALIGN(VarSize) + Global->VolatileLastVariableOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size) { + // + // Perform garbage collection & reclaim operation + // + Status = Reclaim (VariableGlobal->VolatileVariableBase, &Global->VolatileLastVariableOffset, TRUE, VirtualMode, Global, Variable->CurrPtr); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // If still no enough space, return out of resources + // + if ((UINT32) (HEADER_ALIGN (VarSize) + Global->VolatileLastVariableOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size + ) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + Reclaimed = TRUE; + } + + NextVariableHeader->State = VAR_ADDED; + Status = AccessVariableStore ( + TRUE, + VariableGlobal, + TRUE, + Instance, + VariableGlobal->VolatileVariableBase + Global->VolatileLastVariableOffset, + (UINT32) VarSize, + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + Global->VolatileLastVariableOffset += HEADER_ALIGN (VarSize); + } + // + // Mark the old variable as deleted + // If storage has just been reclaimed, the old variable marked as VAR_IN_DELETED_TRANSITION + // has already been eliminated, so no need to delete it. + // + if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != 0) { + State = ((VARIABLE_HEADER *)Variable->CurrPtr)->State; + State &= VAR_DELETED; + + Status = AccessVariableStore ( + TRUE, + VariableGlobal, + Variable->Volatile, + Instance, + (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State), + sizeof (UINT8), + &State + ); + } + + if (!EFI_ERROR (Status)) { + UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE); + UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data); + } + +Done: + return Status; +} + +/** + Implements EsalGetVariable function of Extended SAL Variable Services Class. + + This function implements EsalGetVariable function of Extended SAL Variable Services Class. + It is equivalent in functionality to the EFI Runtime Service GetVariable(). + + @param[in] VariableName A Null-terminated Unicode string that is the name of + the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] Attributes If not NULL, a pointer to the memory location to return the + attributes bitmask for the variable. + @param[in, out] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[out] Data On input, the size in bytes of the return Data buffer. + On output, the size of data returned in Data. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The variable was not found. + @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has + been updated with the size needed to complete the request. + @retval EFI_INVALID_PARAMETER VariableName is NULL. + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. + @retval EFI_INVALID_PARAMETER DataSize is NULL. + @retval EFI_INVALID_PARAMETER DataSize is not too small and Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +EsalGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ) +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + EFI_STATUS Status; + VARIABLE_HEADER VariableHeader; + BOOLEAN Valid; + VARIABLE_GLOBAL *VariableGlobal; + UINT32 Instance; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + VariableGlobal = &Global->VariableGlobal[VirtualMode]; + Instance = Global->FvbInstance; + + AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock); + + // + // Check if this variable exists in cache. + // + Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data); + if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){ + // + // If variable exists in cache, just update statistical information for it and finish. + // Here UpdateVariableInfo() has already retrieved data & attributes for output. + // + UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE); + goto Done; + } + // + // If variable does not exist in cache, search for it in variable storage area. + // + Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance); + if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) { + // + // If it cannot be found in variable storage area, goto Done. + // + goto Done; + } + + Valid = IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader); + if (!Valid) { + Status = EFI_NOT_FOUND; + goto Done; + } + // + // If variable exists, but not in cache, get its data and attributes, update + // statistical information, and update cache. + // + VarDataSize = DataSizeOfVariable (&VariableHeader); + ASSERT (VarDataSize != 0); + + if (*DataSize >= VarDataSize) { + if (Data == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + GetVariableDataPtr ( + Variable.CurrPtr, + Variable.Volatile, + VariableGlobal, + Instance, + Data + ); + if (Attributes != NULL) { + *Attributes = VariableHeader.Attributes; + } + + *DataSize = VarDataSize; + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE); + UpdateVariableCache (VariableName, VendorGuid, VariableHeader.Attributes, VarDataSize, Data); + + Status = EFI_SUCCESS; + goto Done; + } else { + // + // If DataSize is too small for the result, return EFI_BUFFER_TOO_SMALL. + // + *DataSize = VarDataSize; + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + +Done: + ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock); + return Status; +} + +/** + Implements EsalGetNextVariableName function of Extended SAL Variable Services Class. + + This function implements EsalGetNextVariableName function of Extended SAL Variable Services Class. + It is equivalent in functionality to the EFI Runtime Service GetNextVariableName(). + + @param[in, out] VariableNameSize Size of the variable + @param[in, out] VariableName On input, supplies the last VariableName that was returned by GetNextVariableName(). + On output, returns the Null-terminated Unicode string of the current variable. + @param[in, out] VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName(). + On output, returns the VendorGuid of the current variable. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The next variable was not found. + @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result. + VariableNameSize has been updated with the size needed to complete the request. + @retval EFI_INVALID_PARAMETER VariableNameSize is NULL. + @retval EFI_INVALID_PARAMETER VariableName is NULL. + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. + @retval EFI_DEVICE_ERROR The variable name could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +EsalGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ) +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + VARIABLE_HEADER VariableHeader; + VARIABLE_GLOBAL *VariableGlobal; + UINT32 Instance; + + if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + VariableGlobal = &Global->VariableGlobal[VirtualMode]; + Instance = Global->FvbInstance; + + AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock); + + Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance); + // + // If the variable does not exist, goto Done and return. + // + if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) { + goto Done; + } + + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + Variable.CurrPtr = GetNextVariablePtr ( + Variable.CurrPtr, + Variable.Volatile, + VariableGlobal, + Instance + ); + } + + while (TRUE) { + if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == 0x0) { + // + // If fail to find a variable in current area, reverse the volatile attribute of area to search. + // + Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1)); + // + // Here we depend on the searching sequence of FindVariable(). + // It first searches volatile area, then NV area. + // So if the volatile attribute after switching is non-volatile, it means that we have finished searching volatile area, + // and EFI_NOT_FOUND is returnd. + // Otherwise, it means that we have finished searchig non-volatile area, and we will continue to search volatile area. + // + if (!Variable.Volatile) { + Variable.StartPtr = GetStartPointer (VariableGlobal->NonVolatileVariableBase); + Variable.EndPtr = GetEndPointer (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance); + } else { + Status = EFI_NOT_FOUND; + goto Done; + } + + Variable.CurrPtr = Variable.StartPtr; + if (!IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, NULL)) { + continue; + } + } + // + // Variable is found + // + if (IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader)) { + if ((VariableHeader.State == VAR_ADDED) && + (!(EfiAtRuntime () && ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)))) { + VarNameSize = NameSizeOfVariable (&VariableHeader); + ASSERT (VarNameSize != 0); + + if (VarNameSize <= *VariableNameSize) { + GetVariableNamePtr ( + Variable.CurrPtr, + Variable.Volatile, + VariableGlobal, + Instance, + VariableName + ); + CopyMem ( + VendorGuid, + &VariableHeader.VendorGuid, + sizeof (EFI_GUID) + ); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + goto Done; + } + } + + Variable.CurrPtr = GetNextVariablePtr ( + Variable.CurrPtr, + Variable.Volatile, + VariableGlobal, + Instance + ); + } + +Done: + ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock); + return Status; +} + +/** + Implements EsalSetVariable function of Extended SAL Variable Services Class. + + This function implements EsalSetVariable function of Extended SAL Variable Services Class. + It is equivalent in functionality to the EFI Runtime Service SetVariable(). + + @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's + variable. Each VariableName is unique for each + VendorGuid. VariableName must contain 1 or more + Unicode characters. If VariableName is an empty Unicode + string, then EFI_INVALID_PARAMETER is returned. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] Attributes Attributes bitmask to set for the variable. + @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the + variable to be deleted. + @param[in] Data The contents for the variable. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the + DataSize exceeds the maximum allowed. + @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. + @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure. + @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. + +**/ +EFI_STATUS +EFIAPI +EsalSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ) +{ + VARIABLE_POINTER_TRACK Variable; + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS NextVariable; + EFI_PHYSICAL_ADDRESS Point; + VARIABLE_GLOBAL *VariableGlobal; + UINT32 Instance; + UINT32 KeyIndex; + UINT64 MonotonicCount; + UINTN PayloadSize; + + // + // Check input parameters + // + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (DataSize != 0 && Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // EFI_VARIABLE_RUNTIME_ACCESS bit cannot be set without EFI_VARIABLE_BOOTSERVICE_ACCESS bit. + // + if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { + return EFI_INVALID_PARAMETER; + } + + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { + if (DataSize < AUTHINFO_SIZE) { + // + // Try to write Authencated Variable without AuthInfo + // + return EFI_SECURITY_VIOLATION; + } + PayloadSize = DataSize - AUTHINFO_SIZE; + } else { + PayloadSize = DataSize; + } + + VariableGlobal = &Global->VariableGlobal[VirtualMode]; + Instance = Global->FvbInstance; + + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + // + // For variable for hardware error record, the size of the VariableName, including the Unicode Null + // in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxHardwareErrorVariableSize) bytes. + // + if ((PayloadSize > PcdGet32(PcdMaxHardwareErrorVariableSize)) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxHardwareErrorVariableSize))) { + return EFI_INVALID_PARAMETER; + } + // + // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX" + // + if (StrnCmp (VariableName, \ + Global->VariableName[VirtualMode][VAR_HW_ERR_REC], \ + StrLen(Global->VariableName[VirtualMode][VAR_HW_ERR_REC])) != 0) { + return EFI_INVALID_PARAMETER; + } + } else { + // + // For variable not for hardware error record, the size of the VariableName, including the + // Unicode Null in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxVariableSize) bytes. + // + if ((PayloadSize > PcdGet32(PcdMaxVariableSize)) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxVariableSize))) { + return EFI_INVALID_PARAMETER; + } + } + + AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock); + + // + // Consider reentrant in MCA/INIT/NMI. It needs be reupdated; + // + if (InterlockedIncrement (&Global->ReentrantState) > 1) { + Point = VariableGlobal->NonVolatileVariableBase;; + // + // Parse non-volatile variable data and get last variable offset + // + NextVariable = GetStartPointer (Point); + while (IsValidVariableHeader (NextVariable, FALSE, VariableGlobal, Instance, NULL)) { + NextVariable = GetNextVariablePtr (NextVariable, FALSE, VariableGlobal, Instance); + } + Global->NonVolatileLastVariableOffset = NextVariable - Point; + } + + // + // Check whether the input variable exists + // + + Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance); + + // + // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang + // + AutoUpdateLangVariable (VariableName, Data, PayloadSize, VirtualMode, Global); + + // + // Process PK, KEK, Sigdb seperately + // + if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_PLATFORM_KEY]) == 0)) { + Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, TRUE); + } else if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY]) == 0)) { + Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, FALSE); + } else if (CompareGuid (VendorGuid, Global->ImageSecurityDatabaseGuid[VirtualMode])) { + Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes); + } else { + Status = VerifyVariable (Data, DataSize, VirtualMode, Global, &Variable, Attributes, &KeyIndex, &MonotonicCount); + if (!EFI_ERROR(Status)) { + // + // Verification pass + // + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // Cut the certificate size before set + // + Status = UpdateVariable ( + VariableName, + VendorGuid, + (UINT8*)Data + AUTHINFO_SIZE, + DataSize - AUTHINFO_SIZE, + Attributes, + KeyIndex, + MonotonicCount, + VirtualMode, + Global, + &Variable + ); + } else { + // + // Update variable as usual + // + Status = UpdateVariable ( + VariableName, + VendorGuid, + Data, + DataSize, + Attributes, + 0, + 0, + VirtualMode, + Global, + &Variable + ); + } + } + } + + InterlockedDecrement (&Global->ReentrantState); + ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock); + return Status; +} + +/** + Implements EsalQueryVariableInfo function of Extended SAL Variable Services Class. + + This function implements EsalQueryVariableInfo function of Extended SAL Variable Services Class. + It is equivalent in functionality to the EFI Runtime Service QueryVariableInfo(). + + @param[in] Attributes Attributes bitmask to specify the type of variables + on which to return information. + @param[out] MaximumVariableStorageSize On output the maximum size of the storage space available for + the EFI variables associated with the attributes specified. + @param[out] RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI + variables associated with the attributes specified. + @param[out] MaximumVariableSize Returns the maximum size of an individual EFI variable + associated with the attributes specified. + @param[in] VirtualMode Current calling mode for this function + @param[in] Global Context of this Extended SAL Variable Services Class call + + @retval EFI_SUCCESS Valid answer returned. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied. + @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the + MaximumVariableStorageSize, RemainingVariableStorageSize, + MaximumVariableSize are undefined. +**/ +EFI_STATUS +EFIAPI +EsalQueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ) +{ + EFI_PHYSICAL_ADDRESS Variable; + EFI_PHYSICAL_ADDRESS NextVariable; + UINT64 VariableSize; + EFI_PHYSICAL_ADDRESS VariableStoreHeaderAddress; + BOOLEAN Volatile; + VARIABLE_STORE_HEADER VarStoreHeader; + VARIABLE_HEADER VariableHeader; + UINT64 CommonVariableTotalSize; + UINT64 HwErrVariableTotalSize; + VARIABLE_GLOBAL *VariableGlobal; + UINT32 Instance; + + CommonVariableTotalSize = 0; + HwErrVariableTotalSize = 0; + + if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) { + return EFI_INVALID_PARAMETER; + } + + if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) { + // + // Make sure the Attributes combination is supported by the platform. + // + return EFI_UNSUPPORTED; + } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { + // + // Make sure if runtime bit is set, boot service bit is set also. + // + return EFI_INVALID_PARAMETER; + } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) { + // + // Make sure RT Attribute is set if we are in Runtime phase. + // + return EFI_INVALID_PARAMETER; + } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + // + // Make sure Hw Attribute is set with NV. + // + return EFI_INVALID_PARAMETER; + } + + VariableGlobal = &Global->VariableGlobal[VirtualMode]; + Instance = Global->FvbInstance; + + AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock); + + if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { + // + // Query is Volatile related. + // + Volatile = TRUE; + VariableStoreHeaderAddress = VariableGlobal->VolatileVariableBase; + } else { + // + // Query is Non-Volatile related. + // + Volatile = FALSE; + VariableStoreHeaderAddress = VariableGlobal->NonVolatileVariableBase; + } + + // + // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize + // with the storage size (excluding the storage header size). + // + GetVarStoreHeader (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance, &VarStoreHeader); + + *MaximumVariableStorageSize = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER); + + // Harware error record variable needs larger size. + // + if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + *MaximumVariableStorageSize = PcdGet32(PcdHwErrStorageSize); + *MaximumVariableSize = PcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER); + } else { + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + ASSERT (PcdGet32(PcdHwErrStorageSize) < VarStoreHeader.Size); + *MaximumVariableStorageSize = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); + } + + // + // Let *MaximumVariableSize be PcdGet32(PcdMaxVariableSize) with the exception of the variable header size. + // + *MaximumVariableSize = PcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER); + } + + // + // Point to the starting address of the variables. + // + Variable = GetStartPointer (VariableStoreHeaderAddress); + + // + // Now walk through the related variable store. + // + while (IsValidVariableHeader (Variable, Volatile, VariableGlobal, Instance, &VariableHeader) && + (Variable < GetEndPointer (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance))) { + NextVariable = GetNextVariablePtr (Variable, Volatile, VariableGlobal, Instance); + VariableSize = NextVariable - Variable; + + if (EfiAtRuntime ()) { + // + // we don't take the state of the variables in mind + // when calculating RemainingVariableStorageSize, + // since the space occupied by variables not marked with + // VAR_ADDED is not allowed to be reclaimed in Runtime. + // + if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + HwErrVariableTotalSize += VariableSize; + } else { + CommonVariableTotalSize += VariableSize; + } + } else { + // + // Only care about Variables with State VAR_ADDED,because + // the space not marked as VAR_ADDED is reclaimable now. + // + if (VariableHeader.State == VAR_ADDED) { + if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + HwErrVariableTotalSize += VariableSize; + } else { + CommonVariableTotalSize += VariableSize; + } + } + } + + // + // Go to the next one + // + Variable = NextVariable; + } + + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){ + *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize; + }else { + *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize; + } + + if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) { + *MaximumVariableSize = 0; + } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) { + *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER); + } + + ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock); + return EFI_SUCCESS; +} + +/** + Notification function of EVT_GROUP_READY_TO_BOOT event group. + + This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group. + When the Boot Manager is about to load and execute a boot option, it reclaims variable + storage if free size is below the threshold. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +ReclaimForOS( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINT32 VarSize; + EFI_STATUS Status; + UINTN CommonVariableSpace; + UINTN RemainingCommonVariableSpace; + UINTN RemainingHwErrVariableSpace; + + VarSize = ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase))->Size; + Status = EFI_SUCCESS; + // + //Allowable max size of common variable storage space + // + CommonVariableSpace = VarSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); + + RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize; + + RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize; + // + // If the free area is below a threshold, then performs reclaim operation. + // + if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize)) + || ((PcdGet32 (PcdHwErrStorageSize) != 0) && + (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){ + Status = Reclaim ( + mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase, + &mVariableModuleGlobal->NonVolatileLastVariableOffset, + FALSE, + Physical, + mVariableModuleGlobal, + 0x0 + ); + ASSERT_EFI_ERROR (Status); + } +} + +/** + Initializes variable store area for non-volatile and volatile variable. + + This function allocates and initializes memory space for global context of ESAL + variable service and variable store area for non-volatile and volatile variable. + + @param[in] ImageHandle The Image handle of this driver. + @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + +**/ +EFI_STATUS +VariableCommonInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_PHYSICAL_ADDRESS CurrPtr; + VARIABLE_STORE_HEADER *VolatileVariableStore; + VARIABLE_STORE_HEADER *VariableStoreHeader; + EFI_PHYSICAL_ADDRESS Variable; + EFI_PHYSICAL_ADDRESS NextVariable; + UINTN VariableSize; + UINT32 Instance; + EFI_PHYSICAL_ADDRESS FvVolHdr; + EFI_PHYSICAL_ADDRESS TempVariableStoreHeader; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + UINT64 BaseAddress; + UINT64 Length; + UINTN Index; + UINT8 Data; + EFI_PHYSICAL_ADDRESS VariableStoreBase; + UINT64 VariableStoreLength; + EFI_EVENT ReadyToBootEvent; + UINTN ScratchSize; + + // + // Allocate memory for mVariableModuleGlobal + // + mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (ESAL_VARIABLE_GLOBAL)); + if (mVariableModuleGlobal == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mVariableModuleGlobal->GlobalVariableGuid[Physical] = &gEfiGlobalVariableGuid; + CopyMem ( + mVariableModuleGlobal->VariableName[Physical], + mVariableName, + sizeof (mVariableName) + ); + + EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY); + + // + // Note that in EdkII variable driver implementation, Hardware Error Record type variable + // is stored with common variable in the same NV region. So the platform integrator should + // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of + // PcdFlashNvStorageVariableSize. + // + ASSERT (PcdGet32(PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize)); + + // + // Allocate memory for volatile variable store + // + ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); + VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize); + if (VolatileVariableStore == NULL) { + FreePool (mVariableModuleGlobal); + return EFI_OUT_OF_RESOURCES; + } + + SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff); + + // + // Variable Specific Data + // + mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore; + mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer ((EFI_PHYSICAL_ADDRESS) VolatileVariableStore) - (UINTN) VolatileVariableStore; + + CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid); + VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize); + VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED; + VolatileVariableStore->State = VARIABLE_STORE_HEALTHY; + VolatileVariableStore->Reserved = 0; + VolatileVariableStore->Reserved1 = 0; + + // + // Get non volatile varaible store + // + TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase); + VariableStoreBase = TempVariableStoreHeader + \ + (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength); + VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \ + (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength); + // + // Mark the variable storage region of the FLASH as RUNTIME + // + BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK); + Length = VariableStoreLength + (VariableStoreBase - BaseAddress); + Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK); + + Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = gDS->SetMemorySpaceAttributes ( + BaseAddress, + Length, + GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Get address of non volatile variable store base. + // + mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreBase; + + // + // Check Integrity + // + // + // Find the Correct Instance of the FV Block Service. + // + Instance = 0; + CurrPtr = mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase; + + do { + FvVolHdr = 0; + Status = (EFI_STATUS) EsalCall ( + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO, + EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI, + GetPhysicalAddressFunctionId, + Instance, + (UINT64) &FvVolHdr, + 0, + 0, + 0, + 0, + 0 + ).Status; + if (EFI_ERROR (Status)) { + break; + } + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr); + ASSERT (FwVolHeader != NULL); + if (CurrPtr >= (EFI_PHYSICAL_ADDRESS) FwVolHeader && + CurrPtr < ((EFI_PHYSICAL_ADDRESS) FwVolHeader + FwVolHeader->FvLength)) { + mVariableModuleGlobal->FvbInstance = Instance; + break; + } + + Instance++; + } while (Status == EFI_SUCCESS); + + VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr; + if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) { + if (~VariableStoreHeader->Size == 0) { + Status = AccessVariableStore ( + TRUE, + &mVariableModuleGlobal->VariableGlobal[Physical], + FALSE, + mVariableModuleGlobal->FvbInstance, + (UINTN) &VariableStoreHeader->Size, + sizeof (UINT32), + (UINT8 *) &VariableStoreLength + ); + // + // As Variables are stored in NV storage, which are slow devices,such as flash. + // Variable operation may skip checking variable program result to improve performance, + // We can assume Variable program is OK through some check point. + // Variable Store Size Setting should be the first Variable write operation, + // We can assume all Read/Write is OK if we can set Variable store size successfully. + // If write fail, we will assert here. + // + ASSERT(VariableStoreHeader->Size == VariableStoreLength); + + if (EFI_ERROR (Status)) { + goto Done; + } + } + + mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr); + // + // Parse non-volatile variable data and get last variable offset. + // + Variable = GetStartPointer (CurrPtr); + Status = EFI_SUCCESS; + + while (IsValidVariableHeader (Variable, FALSE, &(mVariableModuleGlobal->VariableGlobal[Physical]), Instance, NULL)) { + NextVariable = GetNextVariablePtr ( + Variable, + FALSE, + &(mVariableModuleGlobal->VariableGlobal[Physical]), + Instance + ); + VariableSize = NextVariable - Variable; + if ((((VARIABLE_HEADER *)Variable)->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; + } else { + mVariableModuleGlobal->CommonVariableTotalSize += VariableSize; + } + + Variable = NextVariable; + } + + mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) CurrPtr; + + // + // Check if the free area is really free. + // + for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) { + Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index]; + if (Data != 0xff) { + // + // There must be something wrong in variable store, do reclaim operation. + // + Status = Reclaim ( + mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase, + &mVariableModuleGlobal->NonVolatileLastVariableOffset, + FALSE, + Physical, + mVariableModuleGlobal, + 0x0 + ); + if (EFI_ERROR (Status)) { + goto Done; + } + break; + } + } + + // + // Register the event handling function to reclaim variable for OS usage. + // + Status = EfiCreateEventReadyToBootEx ( + TPL_NOTIFY, + ReclaimForOS, + NULL, + &ReadyToBootEvent + ); + } else { + Status = EFI_VOLUME_CORRUPTED; + DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n")); + } + +Done: + if (EFI_ERROR (Status)) { + FreePool (mVariableModuleGlobal); + FreePool (VolatileVariableStore); + } + + return Status; +} diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h new file mode 100644 index 0000000000..ecff20fb80 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h @@ -0,0 +1,496 @@ +/** @file + Internal header file for Extended SAL variable service module. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _VARIABLE_H_ +#define _VARIABLE_H_ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NAME_SIZE 0x100 +#define NUM_VAR_NAME 9 // Number of pre-defined variable name to be referenced +#define VAR_PLATFORM_LANG_CODES 0 // Index of "PlatformLangCodes" variable +#define VAR_LANG_CODES 1 // Index of "LangCodes" variable +#define VAR_PLATFORM_LANG 2 // Index of "PlatformLang" variable +#define VAR_LANG 3 // Index of "Lang" variable +#define VAR_HW_ERR_REC 4 // Index of "HwErrRecXXXX" variable +#define VAR_AUTH_KEY_DB 5 // Index of "AuthVarKeyDatabase" variable +#define VAR_SETUP_MODE 6 // Index of "SetupMode" variable +#define VAR_PLATFORM_KEY 7 // Index of "PK" variable +#define VAR_KEY_EXCHANGE_KEY 8 // Index of "KEK" variable + +/// +/// "AuthVarKeyDatabase" variable for the Public Key store. +/// +#define AUTHVAR_KEYDB_NAME L"AuthVarKeyDatabase" +#define AUTHVAR_KEYDB_NAME_SIZE 38 + +/// +/// The maximum size of the public key database, restricted by maximum individal EFI +/// varible size, and excluding the variable header and name size. +/// +#define MAX_KEYDB_SIZE (FixedPcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER) - AUTHVAR_KEYDB_NAME_SIZE) +#define MAX_KEY_NUM (MAX_KEYDB_SIZE / EFI_CERT_TYPE_RSA2048_SIZE) + +/// +/// The size of a 3 character ISO639 language code. +/// +#define ISO_639_2_ENTRY_SIZE 3 + +typedef enum { + Physical, + Virtual +} VARIABLE_POINTER_TYPE; + +typedef struct { + EFI_PHYSICAL_ADDRESS CurrPtr; + EFI_PHYSICAL_ADDRESS EndPtr; + EFI_PHYSICAL_ADDRESS StartPtr; + BOOLEAN Volatile; +} VARIABLE_POINTER_TRACK; + +typedef struct { + EFI_PHYSICAL_ADDRESS VolatileVariableBase; + EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; + EFI_LOCK VariableServicesLock; +} VARIABLE_GLOBAL; + +typedef struct { + VARIABLE_GLOBAL VariableGlobal[2]; + CHAR16 *VariableName[2][NUM_VAR_NAME]; + EFI_GUID *GlobalVariableGuid[2]; + UINTN VolatileLastVariableOffset; + UINTN NonVolatileLastVariableOffset; + UINTN CommonVariableTotalSize; + UINTN HwErrVariableTotalSize; + CHAR8 *PlatformLangCodes[2]; + CHAR8 *LangCodes[2]; + CHAR8 *PlatformLang[2]; + CHAR8 Lang[ISO_639_2_ENTRY_SIZE + 1]; + UINT32 FvbInstance; + UINT32 ReentrantState; + EFI_GUID *AuthenticatedVariableGuid[2]; + EFI_GUID *CertRsa2048Sha256Guid[2]; + EFI_GUID *ImageSecurityDatabaseGuid[2]; + VOID *HashContext[2]; // Hash context pointer + UINT8 KeyList[MAX_KEYDB_SIZE]; // Cached Platform Key list + UINT8 PubKeyStore[MAX_KEYDB_SIZE]; // Cached Public Key list +} ESAL_VARIABLE_GLOBAL; + +typedef struct { + EFI_GUID *Guid; + CHAR16 *Name; + UINT32 Attributes; + UINTN DataSize; + VOID *Data; +} VARIABLE_CACHE_ENTRY; + + +extern ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; + +// +// Functions +// + +/** + Initializes variable store area for non-volatile and volatile variable. + + This function allocates and initializes memory space for global context of ESAL + variable service and variable store area for non-volatile and volatile variable. + + @param[in] ImageHandle The Image handle of this driver. + @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resource. + +**/ +EFI_STATUS +VariableCommonInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Entry point of Extended SAL Variable service module. + + This function is the entry point of Extended SAL Variable service module. + It registers all functions of Extended SAL Variable class, initializes + variable store for non-volatile and volatile variables, and registers + notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + + @param[in] ImageHandle The Image handle of this driver. + @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE. + + @retval EFI_SUCCESS Extended SAL Variable Services Class successfully registered. + +**/ +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + It convers pointer to new virtual address. + + @param[in] Event The event whose notification function is being invoked. + @param[in] Context The pointer to the notification function's context. + +**/ +VOID +EFIAPI +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Implements EsalGetVariable function of Extended SAL Variable Services Class. + + This function implements EsalGetVariable function of Extended SAL Variable Services Class. + It is equivalent in functionality to the EFI Runtime Service GetVariable(). + + @param[in] VariableName A Null-terminated Unicode string that is the name of + the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] Attributes If not NULL, a pointer to the memory location to return the + attributes bitmask for the variable. + @param[in, out] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[out] Data On input, the size in bytes of the return Data buffer. + On output, the size of data returned in Data. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The variable was not found. + @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has + been updated with the size needed to complete the request. + @retval EFI_INVALID_PARAMETER VariableName is NULL. + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. + @retval EFI_INVALID_PARAMETER DataSize is NULL. + @retval EFI_INVALID_PARAMETER DataSize is not too small and Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure. + +**/ +EFI_STATUS +EFIAPI +EsalGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ); + +/** + Implements EsalGetNextVariableName function of Extended SAL Variable Services Class. + + This function implements EsalGetNextVariableName function of Extended SAL Variable Services Class. + It is equivalent in functionality to the EFI Runtime Service GetNextVariableName(). + + @param[in, out] VariableNameSize Size of the variable + @param[in, out] VariableName On input, supplies the last VariableName that was returned by GetNextVariableName(). + On output, returns the Null-terminated Unicode string of the current variable. + @param[in, out] VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName(). + On output, returns the VendorGuid of the current variable. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The next variable was not found. + @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result. + VariableNameSize has been updated with the size needed to complete the request. + @retval EFI_INVALID_PARAMETER VariableNameSize is NULL. + @retval EFI_INVALID_PARAMETER VariableName is NULL. + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. + @retval EFI_DEVICE_ERROR The variable name could not be retrieved due to a hardware error. + +**/ +EFI_STATUS +EFIAPI +EsalGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ); + +/** + Implements EsalSetVariable function of Extended SAL Variable Services Class. + + This function implements EsalSetVariable function of Extended SAL Variable Services Class. + It is equivalent in functionality to the EFI Runtime Service SetVariable(). + + @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's + variable. Each VariableName is unique for each + VendorGuid. VariableName must contain 1 or more + Unicode characters. If VariableName is an empty Unicode + string, then EFI_INVALID_PARAMETER is returned. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] Attributes Attributes bitmask to set for the variable. + @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the + variable to be deleted. + @param[in] Data The contents for the variable. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the + DataSize exceeds the maximum allowed. + @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. + @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure. + @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. + +**/ +EFI_STATUS +EFIAPI +EsalSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ); + +/** + Implements EsalQueryVariableInfo function of Extended SAL Variable Services Class. + + This function implements EsalQueryVariableInfo function of Extended SAL Variable Services Class. + It is equivalent in functionality to the EFI Runtime Service QueryVariableInfo(). + + @param[in] Attributes Attributes bitmask to specify the type of variables + on which to return information. + @param[out] MaximumVariableStorageSize On output the maximum size of the storage space available for + the EFI variables associated with the attributes specified. + @param[out] RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI + variables associated with the attributes specified. + @param[out] MaximumVariableSize Returns the maximum size of an individual EFI variable + associated with the attributes specified. + @param[in] VirtualMode Current calling mode for this function + @param[in] Global Context of this Extended SAL Variable Services Class call + + @retval EFI_SUCCESS Valid answer returned. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied. + @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the + MaximumVariableStorageSize, RemainingVariableStorageSize, + MaximumVariableSize are undefined. +**/ +EFI_STATUS +EFIAPI +EsalQueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global + ); + +/** + Writes a buffer to variable storage space. + + This function writes a buffer to variable storage space into firmware + volume block device. The destination is specified by parameter + VariableBase. Fault Tolerant Write protocol is used for writing. + + @param[in] VariableBase The base address of the variable to write. + @param[in] Buffer Points to the data buffer. + @param[in] BufferSize The number of bytes of the data Buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol. + @retval Other The function could not complete successfully. + +**/ +EFI_STATUS +FtwVariableSpace ( + IN EFI_PHYSICAL_ADDRESS VariableBase, + IN UINT8 *Buffer, + IN UINTN BufferSize + ); + +/** + Finds variable in volatile and non-volatile storage areas. + + This code finds variable in volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + Otherwise, VariableName and VendorGuid are compared. + + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Vendor GUID to be found. + @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output, + including the range searched and the target position. + @param[in] Global Pointer to VARIABLE_GLOBAL structure, including + base of volatile variable storage area, base of + NV variable storage area, and a lock. + @param[in] Instance Instance of FV Block services. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while + VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_INVALID_PARAMETER Variable not found. + +**/ +EFI_STATUS +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance + ); + +/** + Gets the pointer to variable data area. + + This function gets the pointer to variable data area. + The variable is specified by its variable header. + + @param[in] VariableAddress Start address of variable header. + @param[in] Volatile TRUE - Variable is volatile. + FALSE - Variable is non-volatile. + @param[in] Global Pointer to VARAIBLE_GLOBAL structure. + @param[in] Instance Instance of FV Block services. + @param[out] VariableData Buffer to hold variable data for output. + +**/ +VOID +GetVariableDataPtr ( + IN EFI_PHYSICAL_ADDRESS VariableAddress, + IN BOOLEAN Volatile, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance, + OUT CHAR16 *VariableData + ); + +/** + Gets the size of variable data area. + + This function gets the size of variable data area. + The variable is specified by its variable header. + If variable header contains raw data, just return 0. + + @param[in] Variable Pointer to the variable header. + + @return Size of variable data area in bytes. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable + ); + +/** + Update the variable region with Variable information. These are the same + arguments as the EFI Variable services. + + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] Data Variable data. + @param[in] DataSize Size of data. 0 means delete. + @param[in] Attributes Attributes of the variable. + @param[in] KeyIndex Index of associated public key. + @param[in] MonotonicCount Value of associated monotonic count. + @param[in] VirtualMode Current calling mode for this function. + @param[in] Global Context of this Extended SAL Variable Services Class call. + @param[in] Variable The variable information which is used to keep track of variable usage. + + @retval EFI_SUCCESS The update operation is success. + @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region. + +**/ +EFI_STATUS +EFIAPI +UpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL, + IN UINT32 KeyIndex OPTIONAL, + IN UINT64 MonotonicCount OPTIONAL, + IN BOOLEAN VirtualMode, + IN ESAL_VARIABLE_GLOBAL *Global, + IN VARIABLE_POINTER_TRACK *Variable + ); + +/** + Checks variable header. + + This function checks if variable header is valid or not. + + @param[in] VariableAddress Start address of variable header. + @param[in] Volatile TRUE - Variable is volatile. + FALSE - Variable is non-volatile. + @param[in] Global Pointer to VARAIBLE_GLOBAL structure. + @param[in] Instance Instance of FV Block services. + @param[out] VariableHeader Pointer to VARIABLE_HEADER for output. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +IsValidVariableHeader ( + IN EFI_PHYSICAL_ADDRESS VariableAddress, + IN BOOLEAN Volatile, + IN VARIABLE_GLOBAL *Global, + IN UINTN Instance, + OUT VARIABLE_HEADER *VariableHeader OPTIONAL + ); + +#endif diff --git a/SecurityPkg/VariableAuthenticated/Pei/Variable.c b/SecurityPkg/VariableAuthenticated/Pei/Variable.c new file mode 100644 index 0000000000..1fd051b354 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/Pei/Variable.c @@ -0,0 +1,671 @@ +/** @file + Implement ReadOnly Variable Services required by PEIM and install PEI + ReadOnly Varaiable2 PPI. These services operates the non-volatile + storage space. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include "Variable.h" + +// +// Module globals +// +EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = { + PeiGetVariable, + PeiGetNextVariableName +}; + +EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiReadOnlyVariable2PpiGuid, + &mVariablePpi +}; + + +/** + Provide the functionality of the variable services. + + @param FileHandle Handle of the file being invoked. + Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile(). + @param PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS If the interface could be successfully installed + @retval Others Returned from PeiServicesInstallPpi() + +**/ +EFI_STATUS +EFIAPI +PeimInitializeVariableServices ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_BOOT_MODE BootMode; + EFI_STATUS Status; + + // + // Check if this is recovery boot path. If no, publish the variable access capability + // to other modules. If yes, the content of variable area is not reliable. Therefore, + // in this case we should not provide variable service to other pei modules. + // + Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode); + ASSERT_EFI_ERROR (Status); + + if (BootMode == BOOT_IN_RECOVERY_MODE) { + return EFI_UNSUPPORTED; + } + + return PeiServicesInstallPpi (&mPpiListVariable); + +} + +/** + + Gets the pointer to the first variable header in given variable store area. + + @param VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the first variable header + +**/ +VARIABLE_HEADER * +GetStartPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1); +} + + +/** + This code gets the pointer to the last variable memory pointer byte. + + @param VarStoreHeader Pointer to the Variable Store Header. + + @return VARIABLE_HEADER* pointer to last unavailable Variable Header. + +**/ +VARIABLE_HEADER * +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size); +} + + +/** + This code checks if variable header is valid or not. + + @param Variable Pointer to the Variable Header. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable + ) +{ + if (Variable == NULL || Variable->StartId != VARIABLE_DATA ) { + return FALSE; + } + + return TRUE; +} + + +/** + This code gets the size of name of variable. + + @param Variable Pointer to the Variable Header. + + @return Size of variable in bytes in type UINTN. + +**/ +UINTN +NameSizeOfVariable ( + IN VARIABLE_HEADER *Variable + ) +{ + if (Variable->State == (UINT8) (-1) || + Variable->DataSize == (UINT32) (-1) || + Variable->NameSize == (UINT32) (-1) || + Variable->Attributes == (UINT32) (-1)) { + return 0; + } + return (UINTN) Variable->NameSize; +} + + +/** + This code gets the size of data of variable. + + @param Variable Pointer to the Variable Header. + + @return Size of variable in bytes in type UINTN. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable + ) +{ + if (Variable->State == (UINT8) (-1) || + Variable->DataSize == (UINT32) (-1) || + Variable->NameSize == (UINT32) (-1) || + Variable->Attributes == (UINT32) (-1)) { + return 0; + } + return (UINTN) Variable->DataSize; +} + +/** + This code gets the pointer to the variable name. + + @param Variable Pointer to the Variable Header. + + @return A CHAR16* pointer to Variable Name. + +**/ +CHAR16 * +GetVariableNamePtr ( + IN VARIABLE_HEADER *Variable + ) +{ + + return (CHAR16 *) (Variable + 1); +} + + +/** + This code gets the pointer to the variable data. + + @param Variable Pointer to the Variable Header. + + @return A UINT8* pointer to Variable Data. + +**/ +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable + ) +{ + UINTN Value; + + // + // Be careful about pad size for alignment + // + Value = (UINTN) GetVariableNamePtr (Variable); + Value += NameSizeOfVariable (Variable); + Value += GET_PAD_SIZE (NameSizeOfVariable (Variable)); + + return (UINT8 *) Value; +} + + +/** + This code gets the pointer to the next variable header. + + @param Variable Pointer to the Variable Header. + + @return A VARIABLE_HEADER* pointer to next variable header. + +**/ +VARIABLE_HEADER * +GetNextVariablePtr ( + IN VARIABLE_HEADER *Variable + ) +{ + UINTN Value; + + if (!IsValidVariableHeader (Variable)) { + return NULL; + } + + Value = (UINTN) GetVariableDataPtr (Variable); + Value += DataSizeOfVariable (Variable); + Value += GET_PAD_SIZE (DataSizeOfVariable (Variable)); + + // + // Be careful about pad size for alignment + // + return (VARIABLE_HEADER *) HEADER_ALIGN (Value); +} + +/** + This code gets the pointer to the variable name. + + @param VarStoreHeader Pointer to the Variable Store Header. + + @retval EfiRaw Variable store is raw + @retval EfiValid Variable store is valid + @retval EfiInvalid Variable store is invalid + +**/ +VARIABLE_STORE_STATUS +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + + if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) && + VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && + VarStoreHeader->State == VARIABLE_STORE_HEALTHY + ) { + + return EfiValid; + } + + if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff && + VarStoreHeader->Size == 0xffffffff && + VarStoreHeader->Format == 0xff && + VarStoreHeader->State == 0xff + ) { + + return EfiRaw; + } else { + return EfiInvalid; + } +} + + +/** + This function compares a variable with variable entries in database. + + @param Variable Pointer to the variable in our database + @param VariableName Name of the variable to compare to 'Variable' + @param VendorGuid GUID of the variable to compare to 'Variable' + @param PtrTrack Variable Track Pointer structure that contains Variable Information. + + @retval EFI_SUCCESS Found match variable + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +CompareWithValidVariable ( + IN VARIABLE_HEADER *Variable, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +{ + VOID *Point; + + if (VariableName[0] == 0) { + PtrTrack->CurrPtr = Variable; + return EFI_SUCCESS; + } else { + // + // Don't use CompareGuid function here for performance reasons. + // Instead we compare the GUID a UINT32 at a time and branch + // on the first failed comparison. + // + if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &Variable->VendorGuid)[0]) && + (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) && + (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) && + (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3]) + ) { + ASSERT (NameSizeOfVariable (Variable) != 0); + Point = (VOID *) GetVariableNamePtr (Variable); + if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable)) == 0) { + PtrTrack->CurrPtr = Variable; + return EFI_SUCCESS; + } + } + } + + return EFI_NOT_FOUND; +} + + +/** + This code finds variable in storage blocks (Non-Volatile). + + @param PeiServices General purpose services available to every PEIM. + @param VariableName Name of the variable to be found + @param VendorGuid Vendor GUID to be found. + @param PtrTrack Variable Track Pointer structure that contains Variable Information. + + @retval EFI_SUCCESS Variable found successfully + @retval EFI_NOT_FOUND Variable not found + @retval EFI_INVALID_PARAMETER Invalid variable name + +**/ +EFI_STATUS +FindVariable ( + IN CONST EFI_PEI_SERVICES **PeiServices, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_HEADER *Variable; + VARIABLE_HEADER *LastVariable; + VARIABLE_HEADER *MaxIndex; + VARIABLE_INDEX_TABLE *IndexTable; + UINT32 Count; + UINT32 Offset; + UINT8 *VariableBase; + BOOLEAN StopRecord; + + if (VariableName[0] != 0 && VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // No Variable Address equals zero, so 0 as initial value is safe. + // + MaxIndex = 0; + StopRecord = FALSE; + + GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid); + if (GuidHob == NULL) { + // + // If it's the first time to access variable region in flash, create a guid hob to record + // VAR_ADDED type variable info. + // Note that as the resource of PEI phase is limited, only store the number of + // VARIABLE_INDEX_TABLE_VOLUME of VAR_ADDED type variables to reduce access time. + // + IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE)); + IndexTable->Length = 0; + IndexTable->StartPtr = NULL; + IndexTable->EndPtr = NULL; + IndexTable->GoneThrough = 0; + } else { + IndexTable = GET_GUID_HOB_DATA (GuidHob); + for (Offset = 0, Count = 0; Count < IndexTable->Length; Count++) { + // + // traverse the variable info list to look for varible. + // The IndexTable->Index[Count] records the distance of two neighbouring VAR_ADDED type variables. + // + ASSERT (Count < VARIABLE_INDEX_TABLE_VOLUME); + Offset += IndexTable->Index[Count]; + MaxIndex = (VARIABLE_HEADER *)((CHAR8 *)(IndexTable->StartPtr) + Offset); + if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { + PtrTrack->StartPtr = IndexTable->StartPtr; + PtrTrack->EndPtr = IndexTable->EndPtr; + + return EFI_SUCCESS; + } + } + + if (IndexTable->GoneThrough != 0) { + return EFI_NOT_FOUND; + } + } + // + // If not found in HOB, then let's start from the MaxIndex we've found. + // + if (MaxIndex != NULL) { + Variable = GetNextVariablePtr (MaxIndex); + LastVariable = MaxIndex; + } else { + if ((IndexTable->StartPtr != NULL) || (IndexTable->EndPtr != NULL)) { + Variable = IndexTable->StartPtr; + } else { + VariableBase = (UINT8 *) (UINTN) PcdGet64 (PcdFlashNvStorageVariableBase64); + if (VariableBase == NULL) { + VariableBase = (UINT8 *) (UINTN) PcdGet32 (PcdFlashNvStorageVariableBase); + } + + VariableStoreHeader = (VARIABLE_STORE_HEADER *) (VariableBase + \ + ((EFI_FIRMWARE_VOLUME_HEADER *) (VariableBase)) -> HeaderLength); + + if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) { + return EFI_UNSUPPORTED; + } + + if (~VariableStoreHeader->Size == 0) { + return EFI_NOT_FOUND; + } + // + // Find the variable by walk through non-volatile variable store + // + IndexTable->StartPtr = GetStartPointer (VariableStoreHeader); + IndexTable->EndPtr = GetEndPointer (VariableStoreHeader); + + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable = IndexTable->StartPtr; + } + + LastVariable = IndexTable->StartPtr; + } + // + // Find the variable by walk through non-volatile variable store + // + PtrTrack->StartPtr = IndexTable->StartPtr; + PtrTrack->EndPtr = IndexTable->EndPtr; + + while ((Variable < IndexTable->EndPtr) && IsValidVariableHeader (Variable)) { + if (Variable->State == VAR_ADDED) { + // + // Record Variable in VariableIndex HOB + // + if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME && !StopRecord) { + Offset = (UINT32)((UINTN)Variable - (UINTN)LastVariable); + // + // The distance of two neighbouring VAR_ADDED variable is larger than 2^16, + // which is beyond the allowable scope(UINT16) of record. In such case, need not to + // record the subsequent VAR_ADDED type variables again. + // + if ((Offset & 0xFFFF0000UL) != 0) { + StopRecord = TRUE; + } + + if (!StopRecord) { + IndexTable->Index[IndexTable->Length++] = (UINT16) Offset; + } + LastVariable = Variable; + } + + if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) { + return EFI_SUCCESS; + } + } + + Variable = GetNextVariablePtr (Variable); + } + // + // If gone through the VariableStore, that means we never find in Firmware any more. + // + if ((IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) && (!StopRecord)) { + IndexTable->GoneThrough = 1; + } + + PtrTrack->CurrPtr = NULL; + + return EFI_NOT_FOUND; +} + +/** + This service retrieves a variable's value using its name and GUID. + + Read the specified variable from the UEFI variable store. If the Data + buffer is too small to hold the contents of the variable, the error + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer + size to obtain the data. + + @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. + @param VariableName A pointer to a null-terminated string that is the variable's name. + @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of + VariableGuid and VariableName must be unique. + @param Attributes If non-NULL, on return, points to the variable's attributes. + @param DataSize On entry, points to the size in bytes of the Data buffer. + On return, points to the size of the data returned in Data. + @param Data Points to the buffer which will hold the returned variable value. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable could not be found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data. + DataSize is updated with the size required for + the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +PeiGetVariable ( + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VariableGuid, + OUT UINT32 *Attributes, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + EFI_STATUS Status; + CONST EFI_PEI_SERVICES **PeiServices; + + PeiServices = GetPeiServicesTablePointer (); + if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Find existing variable + // + Status = FindVariable (PeiServices, VariableName, VariableGuid, &Variable); + if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) { + return Status; + } + // + // Get data size + // + VarDataSize = DataSizeOfVariable (Variable.CurrPtr); + if (*DataSize >= VarDataSize) { + if (Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + + if (Attributes != NULL) { + *Attributes = Variable.CurrPtr->Attributes; + } + + *DataSize = VarDataSize; + return EFI_SUCCESS; + } else { + *DataSize = VarDataSize; + return EFI_BUFFER_TOO_SMALL; + } +} + +/** + Return the next variable name and GUID. + + This function is called multiple times to retrieve the VariableName + and VariableGuid of all variables currently available in the system. + On each call, the previous results are passed into the interface, + and, on return, the interface returns the data for the next + interface. When the entire variable list has been returned, + EFI_NOT_FOUND is returned. + + @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. + + @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName. + On return, the size of the variable name buffer. + @param VariableName On entry, a pointer to a null-terminated string that is the variable's name. + On return, points to the next variable's null-terminated name string. + @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID. + On return, a pointer to the next variable's GUID. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable could not be found. + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting + data. VariableNameSize is updated with the size + required for the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or + VariableNameSize is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +PeiGetNextVariableName ( + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VariableGuid + ) +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + CONST EFI_PEI_SERVICES **PeiServices; + + PeiServices = GetPeiServicesTablePointer (); + if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FindVariable (PeiServices, VariableName, VariableGuid, &Variable); + if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) { + return Status; + } + + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + + while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) { + if (IsValidVariableHeader (Variable.CurrPtr)) { + if (Variable.CurrPtr->State == VAR_ADDED) { + ASSERT (NameSizeOfVariable (Variable.CurrPtr) != 0); + + VarNameSize = (UINTN) NameSizeOfVariable (Variable.CurrPtr); + if (VarNameSize <= *VariableNameSize) { + CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize); + + CopyMem (VariableGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID)); + + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + return Status; + // + // Variable is found + // + } else { + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + } else { + break; + } + } + + return EFI_NOT_FOUND; +} diff --git a/SecurityPkg/VariableAuthenticated/Pei/Variable.h b/SecurityPkg/VariableAuthenticated/Pei/Variable.h new file mode 100644 index 0000000000..af22687fe8 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/Pei/Variable.h @@ -0,0 +1,128 @@ +/** @file + The internal header file includes the common header files, defines + internal structure and functions used by PeiVariable module. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PEI_VARIABLE_H_ +#define _PEI_VARIABLE_H_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +// +// Functions +// +/** + Provide the functionality of the variable services. + + @param FileHandle Handle of the file being invoked. + Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile(). + @param PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS If the interface could be successfully installed + @retval Others Returned from PeiServicesInstallPpi() + +**/ +EFI_STATUS +EFIAPI +PeimInitializeVariableServices ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ); + +/** + This service retrieves a variable's value using its name and GUID. + + Read the specified variable from the UEFI variable store. If the Data + buffer is too small to hold the contents of the variable, the error + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer + size to obtain the data. + + @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. + @param VariableName A pointer to a null-terminated string that is the variable's name. + @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of + VariableGuid and VariableName must be unique. + @param Attributes If non-NULL, on return, points to the variable's attributes. + @param DataSize On entry, points to the size in bytes of the Data buffer. + On return, points to the size of the data returned in Data. + @param Data Points to the buffer which will hold the returned variable value. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable could not be found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data. + DataSize is updated with the size required for + the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +PeiGetVariable ( + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, + IN CONST CHAR16 *VariableName, + IN CONST EFI_GUID *VariableGuid, + OUT UINT32 *Attributes, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + Return the next variable name and GUID. + + This function is called multiple times to retrieve the VariableName + and VariableGuid of all variables currently available in the system. + On each call, the previous results are passed into the interface, + and, on return, the interface returns the data for the next + interface. When the entire variable list has been returned, + EFI_NOT_FOUND is returned. + + @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI. + + @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName. + @param VariableName On entry, a pointer to a null-terminated string that is the variable's name. + On return, points to the next variable's null-terminated name string. + + @param VariableGuid On entry, a pointer to an UEFI _GUID that is the variable's GUID. + On return, a pointer to the next variable's GUID. + + @retval EFI_SUCCESS The variable was read successfully. + @retval EFI_NOT_FOUND The variable could not be found. + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting + data. VariableNameSize is updated with the size + required for the specified variable. + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or + VariableNameSize is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error. + +**/ +EFI_STATUS +EFIAPI +PeiGetNextVariableName ( + IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This, + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VariableGuid + ); + +#endif diff --git a/SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf b/SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf new file mode 100644 index 0000000000..7863293ff8 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf @@ -0,0 +1,64 @@ +## @file +# The component description for PEI variable driver. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiVariable + FILE_GUID = B1F7AF2F-2807-478c-A893-2BF4DDD1F62B + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimInitializeVariableServices + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + Variable.c + Variable.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseMemoryLib + PcdLib + HobLib + PeimEntryPoint + DebugLib + PeiServicesTablePointerLib + PeiServicesLib + +[Guids] + gEfiAuthenticatedVariableGuid + gEfiVariableIndexTableGuid + +[Ppis] + gEfiPeiReadOnlyVariable2PpiGuid ## SOMETIMES_PRODUCES (Not for boot mode RECOVERY) + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 ## CONSUMES + +[Depex] + TRUE + +# +# [BootMode] +# RECOVERY ## CONSUMES +# + diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c new file mode 100644 index 0000000000..cf94182612 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c @@ -0,0 +1,1205 @@ +/** @file + Implement authentication services for the authenticated variable + service in UEFI2.2. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Variable.h" +#include "AuthService.h" + +/// +/// Global database array for scratch +/// +UINT8 mPubKeyStore[MAX_KEYDB_SIZE]; +UINT32 mPubKeyNumber; +UINT32 mPlatformMode; +EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID}; +// +// Public Exponent of RSA Key. +// +CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 }; +// +// Hash context pointer +// +VOID *mHashCtx = NULL; + + +// +// Pointer to runtime buffer. +// For "Append" operation to an existing variable, a read/modify/write operation +// is supported by firmware internally. Reserve runtime buffer to cache previous +// variable data in runtime phase because memory allocation is forbidden in virtual mode. +// +VOID *mStorageArea = NULL; + +/** + Update platform mode. + + @param[in] Mode SETUP_MODE or USER_MODE. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Update platform mode successfully. + +**/ +EFI_STATUS +UpdatePlatformMode ( + IN UINT32 Mode + ); + +/** + Initializes for authenticated varibale service. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resources. + +**/ +EFI_STATUS +AutenticatedVariableServiceInitialize ( + VOID + ) +{ + EFI_STATUS Status; + VARIABLE_POINTER_TRACK Variable; + UINT8 VarValue; + UINT32 VarAttr; + UINT8 *Data; + UINTN DataSize; + UINTN CtxSize; + // + // Initialize hash context. + // + CtxSize = Sha256GetContextSize (); + mHashCtx = AllocateRuntimePool (CtxSize); + if (mHashCtx == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Reserved runtime buffer for "Append" operation in virtual mode. + // + mStorageArea = AllocateRuntimePool (PcdGet32 (PcdMaxAppendVariableSize)); + if (mStorageArea == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // 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 ( + AUTHVAR_KEYDB_NAME, + &gEfiAuthenticatedVariableGuid, + &Variable, + &mVariableModuleGlobal->VariableGlobal + ); + + if (Variable.CurrPtr == NULL) { + VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; + VarValue = 0; + mPubKeyNumber = 0; + Status = UpdateVariable ( + AUTHVAR_KEYDB_NAME, + &gEfiAuthenticatedVariableGuid, + &VarValue, + sizeof(UINT8), + VarAttr, + 0, + 0, + &Variable, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + // + // Load database in global variable for cache. + // + DataSize = DataSizeOfVariable (Variable.CurrPtr); + Data = GetVariableDataPtr (Variable.CurrPtr); + ASSERT ((DataSize != 0) && (Data != NULL)); + CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize); + 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 ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &Variable, + &mVariableModuleGlobal->VariableGlobal + ); + + if (Variable.CurrPtr == NULL) { + Status = FindVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + &Variable, + &mVariableModuleGlobal->VariableGlobal + ); + if (Variable.CurrPtr == NULL) { + mPlatformMode = SETUP_MODE; + } else { + mPlatformMode = USER_MODE; + } + + VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; + Status = UpdateVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &mPlatformMode, + sizeof(UINT8), + VarAttr, + 0, + 0, + &Variable, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr)); + } + // + // 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 + ); + + if (Variable.CurrPtr == NULL) { + 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, + &Variable, + NULL + ); + } + + // + // Detect whether a secure platform-specific method to clear PK(Platform Key) + // is configured by platform owner. This method is provided for users force to clear PK + // in case incorrect enrollment mis-haps. + // + if (ForceClearPK ()) { + // + // 1. Check whether PK is existing, and clear PK if existing + // + FindVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + &Variable, + &mVariableModuleGlobal->VariableGlobal + ); + if (Variable.CurrPtr != NULL) { + VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; + Status = UpdateVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + NULL, + 0, + VarAttr, + 0, + 0, + &Variable, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // 2. Update "SetupMode" variable to SETUP_MODE + // + UpdatePlatformMode (SETUP_MODE); + } + return Status; +} + +/** + Add public key in store and return its index. + + @param[in] PubKey Input pointer to Public Key data + + @return Index of new added item + +**/ +UINT32 +AddPubKeyInStore ( + IN UINT8 *PubKey + ) +{ + EFI_STATUS Status; + BOOLEAN IsFound; + UINT32 Index; + VARIABLE_POINTER_TRACK Variable; + UINT8 *Ptr; + + if (PubKey == NULL) { + return 0; + } + + Status = FindVariable ( + AUTHVAR_KEYDB_NAME, + &gEfiAuthenticatedVariableGuid, + &Variable, + &mVariableModuleGlobal->VariableGlobal + ); + ASSERT_EFI_ERROR (Status); + // + // Check whether the public key entry does exist. + // + IsFound = FALSE; + for (Ptr = mPubKeyStore, 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 (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE); + Index = ++mPubKeyNumber; + // + // Update public key database variable. + // + Status = UpdateVariable ( + AUTHVAR_KEYDB_NAME, + &gEfiAuthenticatedVariableGuid, + mPubKeyStore, + 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, + &Variable, + NULL + ); + ASSERT_EFI_ERROR (Status); + } + + return Index; +} + +/** + Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type. + Follow the steps in UEFI2.2. + + @param[in] Data Pointer to data with AuthInfo. + @param[in] DataSize Size of Data. + @param[in] PubKey Public key used for verification. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_SECURITY_VIOLATION If authentication failed. + @return EFI_SUCCESS Authentication successful. + +**/ +EFI_STATUS +VerifyCounterBasedPayload ( + IN UINT8 *Data, + IN UINTN DataSize, + IN UINT8 *PubKey + ) +{ + BOOLEAN Status; + EFI_VARIABLE_AUTHENTICATION *CertData; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock; + UINT8 Digest[SHA256_DIGEST_SIZE]; + VOID *Rsa; + + Rsa = NULL; + CertData = NULL; + CertBlock = NULL; + + if (Data == NULL || PubKey == NULL) { + return EFI_INVALID_PARAMETER; + } + + CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; + CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData); + + // + // wCertificateType should be WIN_CERT_TYPE_EFI_GUID. + // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256. + // + if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) || + !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid) + ) { + // + // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + } + // + // Hash data payload with SHA256. + // + ZeroMem (Digest, SHA256_DIGEST_SIZE); + Status = Sha256Init (mHashCtx); + if (!Status) { + goto Done; + } + Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE)); + if (!Status) { + goto Done; + } + // + // Hash Monotonic Count. + // + Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64)); + if (!Status) { + goto Done; + } + Status = Sha256Final (mHashCtx, Digest); + if (!Status) { + goto Done; + } + // + // Generate & Initialize RSA Context. + // + Rsa = RsaNew (); + ASSERT (Rsa != NULL); + // + // Set RSA Key Components. + // NOTE: Only N and E are needed to be set as RSA public key for signature verification. + // + Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE); + if (!Status) { + goto Done; + } + Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE)); + if (!Status) { + goto Done; + } + // + // Verify the signature. + // + Status = RsaPkcs1Verify ( + Rsa, + Digest, + SHA256_DIGEST_SIZE, + CertBlock->Signature, + EFI_CERT_TYPE_RSA2048_SHA256_SIZE + ); + +Done: + if (Rsa != NULL) { + RsaFree (Rsa); + } + if (Status) { + return EFI_SUCCESS; + } else { + return EFI_SECURITY_VIOLATION; + } +} + + +/** + Update platform mode. + + @param[in] Mode SETUP_MODE or USER_MODE. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Update platform mode successfully. + +**/ +EFI_STATUS +UpdatePlatformMode ( + IN UINT32 Mode + ) +{ + EFI_STATUS Status; + VARIABLE_POINTER_TRACK Variable; + UINT32 VarAttr; + UINT8 SecureBootMode; + + Status = FindVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &Variable, + &mVariableModuleGlobal->VariableGlobal + ); + if (EFI_ERROR (Status)) { + return Status; + } + + mPlatformMode = Mode; + VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; + Status = UpdateVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &mPlatformMode, + sizeof(UINT8), + VarAttr, + 0, + 0, + &Variable, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check "SecureBoot" variable's existence. + // If it doesn't exist, firmware has no capability to perform driver signing verification, + // then set "SecureBoot" to 0. + // + Status = FindVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &Variable, + &mVariableModuleGlobal->VariableGlobal + ); + // + // If "SecureBoot" variable exists, then check "SetupMode" variable update. + // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1. + // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0. + // + if (Variable.CurrPtr == NULL) { + SecureBootMode = SECURE_BOOT_MODE_DISABLE; + } else { + if (mPlatformMode == USER_MODE) { + SecureBootMode = SECURE_BOOT_MODE_ENABLE; + } else if (mPlatformMode == SETUP_MODE) { + SecureBootMode = SECURE_BOOT_MODE_DISABLE; + } else { + return EFI_NOT_FOUND; + } + } + + VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS; + return UpdateVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &SecureBootMode, + sizeof(UINT8), + VarAttr, + 0, + 0, + &Variable, + NULL + ); +} + +/** + Process variable with platform key for verification. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Variable The variable information which is used to keep track of variable usage. + @param[in] Attributes Attribute value of the variable + @param[in] IsPk Indicate whether it is to process pk. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation. + check carried out by the firmware. + @return EFI_SUCCESS Variable passed validation successfully. + +**/ +EFI_STATUS +ProcessVarWithPk ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + 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; + BOOLEAN TimeBase; + BOOLEAN Del; + + 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_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK. + // + TimeBase = TRUE; + } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK. + // + TimeBase = FALSE; + } else { + return EFI_INVALID_PARAMETER; + } + + if (TimeBase) { + // + // Verify against X509 Cert PK. + // + Del = FALSE; + Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del); + if (!EFI_ERROR (Status)) { + // + // If delete PK in user mode, need change to setup mode. + // + if (Del && IsPk) { + Status = UpdatePlatformMode (SETUP_MODE); + } + } + return Status; + } else { + // + // Verify against RSA2048 Cert PK. + // + CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; + if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) { + // + // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + } + // + // Get platform key from variable. + // + Status = FindVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + &PkVariable, + &mVariableModuleGlobal->VariableGlobal + ); + ASSERT_EFI_ERROR (Status); + + OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr); + OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize); + Status = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData); + if (!EFI_ERROR (Status)) { + Status = UpdateVariable ( + VariableName, + VendorGuid, + (UINT8*)Data + AUTHINFO_SIZE, + DataSize - AUTHINFO_SIZE, + Attributes, + 0, + CertData->MonotonicCount, + Variable, + NULL + ); + + if (!EFI_ERROR (Status)) { + // + // If delete PK in user mode, need change to setup mode. + // + if ((DataSize == AUTHINFO_SIZE) && IsPk) { + Status = UpdatePlatformMode (SETUP_MODE); + } + } + } + } + } else { + Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL); + // + // If enroll PK in setup mode, need change to user mode. + // + if ((DataSize != 0) && IsPk) { + Status = UpdatePlatformMode (USER_MODE); + } + } + + return Status; +} + +/** + Process variable with key exchange key for verification. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Variable The variable information which is used to keep track of variable usage. + @param[in] Attributes Attribute value of the variable. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation + check carried out by the firmware. + @return EFI_SUCCESS Variable pass validation successfully. + +**/ +EFI_STATUS +ProcessVarWithKek ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + 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; + UINT32 KekDataSize; + + 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 != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) { + // + // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + } + // + // Get KEK database from variable. + // + Status = FindVariable ( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + &KekVariable, + &mVariableModuleGlobal->VariableGlobal + ); + ASSERT_EFI_ERROR (Status); + + KekDataSize = KekVariable.CurrPtr->DataSize; + KekList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr); + + // + // Enumerate all Kek items in this list to verify the variable certificate data. + // If anyone is authenticated successfully, it means the variable is correct! + // + IsFound = FALSE; + while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) { + if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) { + KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize); + KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize; + 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); + } + } + KekDataSize -= KekList->SignatureListSize; + KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize); + } + + if (!IsFound) { + return EFI_SECURITY_VIOLATION; + } + + Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey); + if (!EFI_ERROR (Status)) { + Status = UpdateVariable ( + VariableName, + VendorGuid, + (UINT8*)Data + AUTHINFO_SIZE, + DataSize - AUTHINFO_SIZE, + Attributes, + 0, + CertData->MonotonicCount, + Variable, + NULL + ); + } + } else { + // + // If in setup mode, no authentication needed. + // + Status = UpdateVariable ( + VariableName, + VendorGuid, + Data, + DataSize, + Attributes, + 0, + 0, + Variable, + NULL + ); + } + + return Status; +} + +/** + Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Variable The variable information which is used to keep track of variable usage. + @param[in] Attributes Attribute value of the variable. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with + EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. + @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + set, but the AuthInfo does NOT pass the validation + check carried out by the firmware. + @return EFI_SUCCESS Variable is not write-protected or pass validation successfully. + +**/ +EFI_STATUS +ProcessVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN VARIABLE_POINTER_TRACK *Variable, + IN UINT32 Attributes + ) +{ + EFI_STATUS Status; + BOOLEAN IsDeletion; + BOOLEAN IsFirstTime; + UINT8 *PubKey; + EFI_VARIABLE_AUTHENTICATION *CertData; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock; + UINT32 KeyIndex; + UINT64 MonotonicCount; + + KeyIndex = 0; + CertData = NULL; + CertBlock = NULL; + PubKey = NULL; + IsDeletion = FALSE; + + // + // Process Time-based Authenticated variable. + // + if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL); + } + + // + // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS. + // + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // Determine current operation type. + // + if (DataSize == AUTHINFO_SIZE) { + IsDeletion = TRUE; + } + // + // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. + // + if (Variable->CurrPtr == NULL) { + IsFirstTime = TRUE; + } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) { + IsFirstTime = TRUE; + } else { + KeyIndex = Variable->CurrPtr->PubKeyIndex; + IsFirstTime = FALSE; + } + } else if ((Variable->CurrPtr != NULL) && + (Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0 + ) { + // + // If the variable is already write-protected, it always needs authentication before update. + // + return EFI_WRITE_PROTECTED; + } else { + // + // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision. + // That means it is not authenticated variable, just update variable as usual. + // + Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL); + return Status; + } + + // + // Get PubKey and check Monotonic Count value corresponding to the variable. + // + CertData = (EFI_VARIABLE_AUTHENTICATION *) Data; + CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData); + PubKey = CertBlock->PublicKey; + + // + // Update Monotonic Count value. + // + MonotonicCount = CertData->MonotonicCount; + + if (!IsFirstTime) { + // + // Check input PubKey. + // + if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) { + return EFI_SECURITY_VIOLATION; + } + // + // Compare the current monotonic count and ensure that it is greater than the last SetVariable + // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set. + // + if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) { + // + // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + } + } + // + // Verify the certificate in Data payload. + // + Status = VerifyCounterBasedPayload (Data, DataSize, PubKey); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Now, the signature has been verified! + // + if (IsFirstTime && !IsDeletion) { + // + // Update public key database variable if need. + // + KeyIndex = AddPubKeyInStore (PubKey); + } + + // + // Verification pass. + // + return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL); +} + +/** + Compare two EFI_TIME data. + + + @param FirstTime A pointer to the first EFI_TIME data. + @param SecondTime A pointer to the second EFI_TIME data. + + @retval TRUE The FirstTime is not later than the SecondTime. + @retval FALSE The FirstTime is later than the SecondTime. + +**/ +BOOLEAN +CompareTimeStamp ( + IN EFI_TIME *FirstTime, + IN EFI_TIME *SecondTime + ) +{ + if (FirstTime->Year != SecondTime->Year) { + return (BOOLEAN) (FirstTime->Year < SecondTime->Year); + } else if (FirstTime->Month != SecondTime->Month) { + return (BOOLEAN) (FirstTime->Month < SecondTime->Month); + } else if (FirstTime->Day != SecondTime->Day) { + return (BOOLEAN) (FirstTime->Day < SecondTime->Day); + } else if (FirstTime->Hour != SecondTime->Hour) { + return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour); + } else if (FirstTime->Minute != SecondTime->Minute) { + return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute); + } + + return (BOOLEAN) (FirstTime->Second <= SecondTime->Second); +} + +/** + Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Variable The variable information which is used to keep track of variable usage. + @param[in] Attributes Attribute value of the variable. + @param[in] Pk Verify against PK or KEK database. + @param[out] VarDel Delete the variable or not. + + @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_OUT_OF_RESOURCES Failed to process variable due to lack + of resources. + @retval EFI_SUCCESS Variable pass validation successfully. + +**/ +EFI_STATUS +VerifyTimeBasedPayload ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN VARIABLE_POINTER_TRACK *Variable, + IN UINT32 Attributes, + IN BOOLEAN Pk, + OUT BOOLEAN *VarDel + ) +{ + UINT8 *RootCert; + UINT8 *SigData; + UINT8 *PayLoadPtr; + UINTN RootCertSize; + UINTN Index; + UINTN CertCount; + UINTN PayLoadSize; + UINT32 Attr; + UINT32 SigDataSize; + UINT32 KekDataSize; + BOOLEAN Result; + BOOLEAN VerifyStatus; + EFI_STATUS Status; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *Cert; + VARIABLE_POINTER_TRACK KekVariable; + EFI_VARIABLE_AUTHENTICATION_2 *CertData; + UINT8 *NewData; + UINTN NewDataSize; + VARIABLE_POINTER_TRACK PkVariable; + + + Result = FALSE; + VerifyStatus = FALSE; + CertData = NULL; + NewData = NULL; + Attr = Attributes; + + // + // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is + // set, then the Data buffer shall begin with an instance of a complete (and serialized) + // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new + // variable value and DataSize shall reflect the combined size of the descriptor and the new + // variable value. The authentication descriptor is not part of the variable data and is not + // returned by subsequent calls to GetVariable(). + // + CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data; + + if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) { + if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) { + // + // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + } + } + + // + // wCertificateType should be WIN_CERT_TYPE_EFI_GUID. + // Cert type should be EFI_CERT_TYPE_PKCS7_GUID. + // + if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) || + !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid) + ) { + // + // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION. + // + return EFI_SECURITY_VIOLATION; + } + + // + // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor. + // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header. + // + SigData = (UINT8*) ((UINTN)Data + (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData)); + SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(UINTN)(((WIN_CERTIFICATE_UEFI_GUID *) 0)->CertData); + + // + // Find out the new data payload which follows Pkcs7 SignedData directly. + // + PayLoadPtr = (UINT8*) ((UINTN) SigData + (UINTN) SigDataSize); + PayLoadSize = DataSize - (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData) - (UINTN) SigDataSize; + + + // + // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data). + // + NewDataSize = PayLoadSize + sizeof (EFI_TIME) + sizeof (UINT32) + + sizeof (EFI_GUID) + StrSize (VariableName); + NewData = (UINT8 *) AllocateZeroPool (NewDataSize); + + if (NewData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (NewData, VariableName, StrSize (VariableName)); + + CopyMem (NewData + StrSize (VariableName), VendorGuid, sizeof (EFI_GUID)); + + CopyMem ( + NewData + StrSize (VariableName) + sizeof (EFI_GUID), + &Attr, + sizeof (UINT32) + ); + + CopyMem ( + NewData + StrSize (VariableName) + sizeof (EFI_GUID) + sizeof (UINT32), + &CertData->TimeStamp, + sizeof (EFI_TIME) + ); + + CopyMem (NewData + (NewDataSize - PayLoadSize), PayLoadPtr, PayLoadSize); + + + if (Pk) { + // + // Get platform key from variable. + // + Status = FindVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + &PkVariable, + &mVariableModuleGlobal->VariableGlobal + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr); + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + RootCert = Cert->SignatureData; + RootCertSize = CertList->SignatureSize; + + + // + // Verify Pkcs7 SignedData via Pkcs7Verify library. + // + VerifyStatus = Pkcs7Verify ( + SigData, + SigDataSize, + RootCert, + RootCertSize, + NewData, + NewDataSize + ); + + } else { + + // + // Get KEK database from variable. + // + Status = FindVariable ( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + &KekVariable, + &mVariableModuleGlobal->VariableGlobal + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList. + // + KekDataSize = KekVariable.CurrPtr->DataSize; + CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr); + while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + for (Index = 0; Index < CertCount; Index++) { + // + // Iterate each Signature Data Node within this CertList for a verify + // + RootCert = Cert->SignatureData; + RootCertSize = CertList->SignatureSize; + + // + // Verify Pkcs7 SignedData via Pkcs7Verify library. + // + VerifyStatus = Pkcs7Verify ( + SigData, + SigDataSize, + RootCert, + RootCertSize, + NewData, + NewDataSize + ); + if (VerifyStatus) { + goto Exit; + } + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); + } + } + KekDataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + } + +Exit: + + FreePool (NewData); + + if (!VerifyStatus) { + return EFI_SECURITY_VIOLATION; + } + + if ((PayLoadSize == 0) && (VarDel != NULL)) { + *VarDel = TRUE; + } + + // + // Final step: Update/Append Variable if it pass Pkcs7Verify + // + return UpdateVariable ( + VariableName, + VendorGuid, + PayLoadPtr, + PayLoadSize, + Attributes, + 0, + 0, + Variable, + &CertData->TimeStamp + ); +} diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.h b/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.h new file mode 100644 index 0000000000..6b0db74c81 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.h @@ -0,0 +1,209 @@ +/** @file + The internal header file includes the common header files, defines + internal structure and functions used by AuthService module. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _AUTHSERVICE_H_ +#define _AUTHSERVICE_H_ + +#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256 +#define EFI_CERT_TYPE_RSA2048_SIZE 256 + +/// +/// Size of AuthInfo prior to the data payload +/// +#define AUTHINFO_SIZE (((UINTN)(((EFI_VARIABLE_AUTHENTICATION *) 0)->AuthInfo.CertData)) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256)) + +/// +/// "AuthVarKeyDatabase" variable for the Public Key store. +/// +#define AUTHVAR_KEYDB_NAME L"AuthVarKeyDatabase" +#define AUTHVAR_KEYDB_NAME_SIZE 38 + +/// +/// Max size of public key database, restricted by max individal EFI varible size, exclude variable header and name size. +/// +#define MAX_KEYDB_SIZE (FixedPcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER) - AUTHVAR_KEYDB_NAME_SIZE) +#define MAX_KEY_NUM (MAX_KEYDB_SIZE / EFI_CERT_TYPE_RSA2048_SIZE) + +/// +/// Item number of support signature types. +/// +#define SIGSUPPORT_NUM 2 + + +/** + Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Variable The variable information which is used to keep track of variable usage. + @param[in] Attributes Attribute value of the variable. + + @return EFI_INVALID_PARAMETER Invalid parameter + @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with + EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. + @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + set, but the AuthInfo does NOT pass the validation + check carried out by the firmware. + @return EFI_SUCCESS Variable is not write-protected, or passed validation successfully. + +**/ +EFI_STATUS +ProcessVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN VARIABLE_POINTER_TRACK *Variable, + IN UINT32 Attributes + ); + +/** + Initializes for authenticated varibale service. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + +**/ +EFI_STATUS +AutenticatedVariableServiceInitialize ( + VOID + ); + +/** + Initializes for cryptlib service before use, include register algrithm and allocate scratch. + +**/ +VOID +CryptLibraryInitialize ( + VOID + ); + +/** + Process variable with platform key for verification. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Variable The variable information which is used to keep track of variable usage. + @param[in] Attributes Attribute value of the variable. + @param[in] IsPk Indicate whether it is to process pk. + + @return EFI_INVALID_PARAMETER Invalid parameter + @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation + check carried out by the firmware. + @return EFI_SUCCESS Variable passed validation successfully. + +**/ +EFI_STATUS +ProcessVarWithPk ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN VARIABLE_POINTER_TRACK *Variable, + IN UINT32 Attributes OPTIONAL, + IN BOOLEAN IsPk + ); + +/** + Process variable with key exchange key for verification. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Variable The variable information that is used to keep track of variable usage. + @param[in] Attributes Attribute value of the variable. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation + check carried out by the firmware. + @return EFI_SUCCESS Variable passed validation successfully. + +**/ +EFI_STATUS +ProcessVarWithKek ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN VARIABLE_POINTER_TRACK *Variable, + IN UINT32 Attributes OPTIONAL + ); + +/** + Compare two EFI_TIME data. + + + @param FirstTime A pointer to the first EFI_TIME data. + @param SecondTime A pointer to the second EFI_TIME data. + + @retval TRUE The FirstTime is not later than the SecondTime. + @retval FALSE The FirstTime is later than the SecondTime. + +**/ +BOOLEAN +CompareTimeStamp ( + IN EFI_TIME *FirstTime, + IN EFI_TIME *SecondTime + ); + + +/** + Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Variable The variable information which is used to keep track of variable usage. + @param[in] Attributes Attribute value of the variable. + @param[in] Pk Verify against PK or KEK database. + @param[out] VarDel Delete the variable or not. + + @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_OUT_OF_RESOURCES Failed to process variable due to lack + of resources. + @retval EFI_SUCCESS Variable pass validation successfully. + +**/ +EFI_STATUS +VerifyTimeBasedPayload ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN VARIABLE_POINTER_TRACK *Variable, + IN UINT32 Attributes, + IN BOOLEAN Pk, + OUT BOOLEAN *VarDel + ); + +extern UINT8 mPubKeyStore[MAX_KEYDB_SIZE]; +extern UINT32 mPubKeyNumber; +extern VOID *mHashCtx; +extern VOID *mStorageArea; + +#endif diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Reclaim.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Reclaim.c new file mode 100644 index 0000000000..4f7a41cd09 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Reclaim.c @@ -0,0 +1,172 @@ +/** @file + Handles non-volatile variable store garbage collection, using FTW + (Fault Tolerant Write) protocol. + +Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Variable.h" + +/** + Gets LBA of block and offset by given address. + + This function gets the Logical Block Address (LBA) of a firmware + volume block containing the given address, and the offset of the + address on the block. + + @param Address Address which should be contained + by returned FVB handle. + @param Lba Pointer to LBA for output. + @param Offset Pointer to offset for output. + + @retval EFI_SUCCESS LBA and offset successfully returned. + @retval EFI_NOT_FOUND Fail to find FVB handle by address. + @retval EFI_ABORTED Fail to find valid LBA and offset. + +**/ +EFI_STATUS +GetLbaAndOffsetByAddress ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT EFI_LBA *Lba, + OUT UINTN *Offset + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS FvbBaseAddress; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry; + UINT32 LbaIndex; + + *Lba = (EFI_LBA) (-1); + *Offset = 0; + + // + // Get the proper FVB protocol. + // + Status = GetFvbInfoByAddress (Address, NULL, &Fvb); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the Base Address of FV. + // + Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); + if (EFI_ERROR (Status)) { + return Status; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); + + // + // Get the (LBA, Offset) of Address. + // + if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) { + // + // BUGBUG: Assume one FV has one type of BlockLength. + // + FvbMapEntry = &FwVolHeader->BlockMap[0]; + for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) { + if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) { + // + // Found the (Lba, Offset). + // + *Lba = LbaIndex - 1; + *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1))); + return EFI_SUCCESS; + } + } + } + + return EFI_ABORTED; +} + +/** + Writes a buffer to variable storage space, in the working block. + + This function writes a buffer to variable storage space into a firmware + volume block device. The destination is specified by parameter + VariableBase. Fault Tolerant Write protocol is used for writing. + + @param VariableBase Base address of variable to write + @param Buffer Point to the data buffer. + @param BufferSize The number of bytes of the data Buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol. + @retval EFI_ABORTED The function could not complete successfully. + +**/ +EFI_STATUS +FtwVariableSpace ( + IN EFI_PHYSICAL_ADDRESS VariableBase, + IN UINT8 *Buffer, + IN UINTN BufferSize + ) +{ + EFI_STATUS Status; + EFI_HANDLE FvbHandle; + EFI_LBA VarLba; + UINTN VarOffset; + UINT8 *FtwBuffer; + UINTN FtwBufferSize; + EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; + + // + // Locate fault tolerant write protocol. + // + Status = GetFtwProtocol((VOID **) &FtwProtocol); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + // + // Locate Fvb handle by address. + // + Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get LBA and Offset by address. + // + Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Prepare for the variable data. + // + FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size; + FtwBuffer = AllocatePool (FtwBufferSize); + if (FtwBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff); + CopyMem (FtwBuffer, Buffer, BufferSize); + + // + // FTW write record. + // + Status = FtwProtocol->Write ( + FtwProtocol, + VarLba, // LBA + VarOffset, // Offset + FtwBufferSize, // NumBytes + NULL, // PrivateData NULL + FvbHandle, // Fvb Handle + FtwBuffer // write buffer + ); + + FreePool (FtwBuffer); + return Status; +} diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c new file mode 100644 index 0000000000..136bafefec --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c @@ -0,0 +1,2618 @@ +/** @file + The common variable operation routines shared by DXE_RINTIME variable + module and DXE_SMM variable module. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Variable.h" +#include "AuthService.h" + +VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; + +/// +/// Define a memory cache that improves the search performance for a variable. +/// +VARIABLE_STORE_HEADER *mNvVariableCache = NULL; + +/// +/// The memory entry used for variable statistics data. +/// +VARIABLE_INFO_ENTRY *gVariableInfo = NULL; + + +/** + Routine used to track statistical information about variable usage. + The data is stored in the EFI system table so it can be accessed later. + VariableInfo.efi can dump out the table. Only Boot Services variable + accesses are tracked by this code. The PcdVariableCollectStatistics + build flag controls if this feature is enabled. + + A read that hits in the cache will have Read and Cache true for + the transaction. Data is allocated by this routine, but never + freed. + + @param[in] VariableName Name of the Variable to track. + @param[in] VendorGuid Guid of the Variable to track. + @param[in] Volatile TRUE if volatile FALSE if non-volatile. + @param[in] Read TRUE if GetVariable() was called. + @param[in] Write TRUE if SetVariable() was called. + @param[in] Delete TRUE if deleted via SetVariable(). + @param[in] Cache TRUE for a cache hit. + +**/ +VOID +UpdateVariableInfo ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN BOOLEAN Volatile, + IN BOOLEAN Read, + IN BOOLEAN Write, + IN BOOLEAN Delete, + IN BOOLEAN Cache + ) +{ + VARIABLE_INFO_ENTRY *Entry; + + if (FeaturePcdGet (PcdVariableCollectStatistics)) { + + if (AtRuntime ()) { + // Don't collect statistics at runtime. + return; + } + + if (gVariableInfo == NULL) { + // + // On the first call allocate a entry and place a pointer to it in + // the EFI System Table. + // + gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); + ASSERT (gVariableInfo != NULL); + + CopyGuid (&gVariableInfo->VendorGuid, VendorGuid); + gVariableInfo->Name = AllocatePool (StrSize (VariableName)); + ASSERT (gVariableInfo->Name != NULL); + StrCpy (gVariableInfo->Name, VariableName); + gVariableInfo->Volatile = Volatile; + } + + + for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) { + if (CompareGuid (VendorGuid, &Entry->VendorGuid)) { + if (StrCmp (VariableName, Entry->Name) == 0) { + if (Read) { + Entry->ReadCount++; + } + if (Write) { + Entry->WriteCount++; + } + if (Delete) { + Entry->DeleteCount++; + } + if (Cache) { + Entry->CacheCount++; + } + + return; + } + } + + if (Entry->Next == NULL) { + // + // If the entry is not in the table add it. + // Next iteration of the loop will fill in the data. + // + Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); + ASSERT (Entry->Next != NULL); + + CopyGuid (&Entry->Next->VendorGuid, VendorGuid); + Entry->Next->Name = AllocatePool (StrSize (VariableName)); + ASSERT (Entry->Next->Name != NULL); + StrCpy (Entry->Next->Name, VariableName); + Entry->Next->Volatile = Volatile; + } + + } + } +} + + +/** + + This code checks if variable header is valid or not. + + @param Variable Pointer to the Variable Header. + + @retval TRUE Variable header is valid. + @retval FALSE Variable header is not valid. + +**/ +BOOLEAN +IsValidVariableHeader ( + IN VARIABLE_HEADER *Variable + ) +{ + if (Variable == NULL || Variable->StartId != VARIABLE_DATA) { + return FALSE; + } + + return TRUE; +} + + +/** + + This function writes data to the FWH at the correct LBA even if the LBAs + are fragmented. + + @param Global Pointer to VARAIBLE_GLOBAL structure. + @param Volatile Point out the Variable is Volatile or Non-Volatile. + @param SetByIndex TRUE if target pointer is given as index. + FALSE if target pointer is absolute. + @param Fvb Pointer to the writable FVB protocol. + @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER + structure. + @param DataSize Size of data to be written. + @param Buffer Pointer to the buffer from which data is written. + + @retval EFI_INVALID_PARAMETER Parameters not valid. + @retval EFI_SUCCESS Variable store successfully updated. + +**/ +EFI_STATUS +UpdateVariableStore ( + IN VARIABLE_GLOBAL *Global, + IN BOOLEAN Volatile, + IN BOOLEAN SetByIndex, + IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb, + IN UINTN DataPtrIndex, + IN UINT32 DataSize, + IN UINT8 *Buffer + ) +{ + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + UINTN BlockIndex2; + UINTN LinearOffset; + UINTN CurrWriteSize; + UINTN CurrWritePtr; + UINT8 *CurrBuffer; + EFI_LBA LbaNumber; + UINTN Size; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + VARIABLE_STORE_HEADER *VolatileBase; + EFI_PHYSICAL_ADDRESS FvVolHdr; + EFI_PHYSICAL_ADDRESS DataPtr; + EFI_STATUS Status; + + FwVolHeader = NULL; + DataPtr = DataPtrIndex; + + // + // Check if the Data is Volatile. + // + if (!Volatile) { + ASSERT (Fvb != NULL); + Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr); + ASSERT_EFI_ERROR (Status); + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr); + // + // Data Pointer should point to the actual Address where data is to be + // written. + // + if (SetByIndex) { + DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase; + } + + if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) { + return EFI_INVALID_PARAMETER; + } + } else { + // + // Data Pointer should point to the actual Address where data is to be + // written. + // + VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); + if (SetByIndex) { + DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase; + } + + if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) { + return EFI_INVALID_PARAMETER; + } + + // + // If Volatile Variable just do a simple mem copy. + // + CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize); + return EFI_SUCCESS; + } + + // + // If we are here we are dealing with Non-Volatile Variables. + // + LinearOffset = (UINTN) FwVolHeader; + CurrWritePtr = (UINTN) DataPtr; + CurrWriteSize = DataSize; + CurrBuffer = Buffer; + LbaNumber = 0; + + if (CurrWritePtr < LinearOffset) { + return EFI_INVALID_PARAMETER; + } + + for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { + for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) { + // + // Check to see if the Variable Writes are spanning through multiple + // blocks. + // + if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) { + if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) { + Status = Fvb->Write ( + Fvb, + LbaNumber, + (UINTN) (CurrWritePtr - LinearOffset), + &CurrWriteSize, + CurrBuffer + ); + return Status; + } else { + Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr); + Status = Fvb->Write ( + Fvb, + LbaNumber, + (UINTN) (CurrWritePtr - LinearOffset), + &Size, + CurrBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length; + CurrBuffer = CurrBuffer + Size; + CurrWriteSize = CurrWriteSize - Size; + } + } + + LinearOffset += PtrBlockMapEntry->Length; + LbaNumber++; + } + } + + return EFI_SUCCESS; +} + + +/** + + This code gets the current status of Variable Store. + + @param VarStoreHeader Pointer to the Variable Store Header. + + @retval EfiRaw Variable store status is raw. + @retval EfiValid Variable store status is valid. + @retval EfiInvalid Variable store status is invalid. + +**/ +VARIABLE_STORE_STATUS +GetVariableStoreStatus ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) && + VarStoreHeader->Format == VARIABLE_STORE_FORMATTED && + VarStoreHeader->State == VARIABLE_STORE_HEALTHY + ) { + + return EfiValid; + } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff && + ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff && + VarStoreHeader->Size == 0xffffffff && + VarStoreHeader->Format == 0xff && + VarStoreHeader->State == 0xff + ) { + + return EfiRaw; + } else { + return EfiInvalid; + } +} + + +/** + + This code gets the size of name of variable. + + @param Variable Pointer to the Variable Header. + + @return UINTN Size of variable in bytes. + +**/ +UINTN +NameSizeOfVariable ( + IN VARIABLE_HEADER *Variable + ) +{ + if (Variable->State == (UINT8) (-1) || + Variable->DataSize == (UINT32) (-1) || + Variable->NameSize == (UINT32) (-1) || + Variable->Attributes == (UINT32) (-1)) { + return 0; + } + return (UINTN) Variable->NameSize; +} + +/** + + This code gets the size of variable data. + + @param Variable Pointer to the Variable Header. + + @return Size of variable in bytes. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable + ) +{ + if (Variable->State == (UINT8) (-1) || + Variable->DataSize == (UINT32) (-1) || + Variable->NameSize == (UINT32) (-1) || + Variable->Attributes == (UINT32) (-1)) { + return 0; + } + return (UINTN) Variable->DataSize; +} + +/** + + This code gets the pointer to the variable name. + + @param Variable Pointer to the Variable Header. + + @return Pointer to Variable Name which is Unicode encoding. + +**/ +CHAR16 * +GetVariableNamePtr ( + IN VARIABLE_HEADER *Variable + ) +{ + + return (CHAR16 *) (Variable + 1); +} + +/** + + This code gets the pointer to the variable data. + + @param Variable Pointer to the Variable Header. + + @return Pointer to Variable Data. + +**/ +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable + ) +{ + UINTN Value; + + // + // Be careful about pad size for alignment. + // + Value = (UINTN) GetVariableNamePtr (Variable); + Value += NameSizeOfVariable (Variable); + Value += GET_PAD_SIZE (NameSizeOfVariable (Variable)); + + return (UINT8 *) Value; +} + + +/** + + This code gets the pointer to the next variable header. + + @param Variable Pointer to the Variable Header. + + @return Pointer to next variable header. + +**/ +VARIABLE_HEADER * +GetNextVariablePtr ( + IN VARIABLE_HEADER *Variable + ) +{ + UINTN Value; + + if (!IsValidVariableHeader (Variable)) { + return NULL; + } + + Value = (UINTN) GetVariableDataPtr (Variable); + Value += DataSizeOfVariable (Variable); + Value += GET_PAD_SIZE (DataSizeOfVariable (Variable)); + + // + // Be careful about pad size for alignment. + // + return (VARIABLE_HEADER *) HEADER_ALIGN (Value); +} + +/** + + Gets the pointer to the first variable header in given variable store area. + + @param VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the first variable header. + +**/ +VARIABLE_HEADER * +GetStartPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The end of variable store. + // + return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1); +} + +/** + + Gets the pointer to the end of the variable storage area. + + This function gets pointer to the end of the variable storage + area, according to the input variable store header. + + @param VarStoreHeader Pointer to the Variable Store Header. + + @return Pointer to the end of the variable storage area. + +**/ +VARIABLE_HEADER * +GetEndPointer ( + IN VARIABLE_STORE_HEADER *VarStoreHeader + ) +{ + // + // The end of variable store + // + return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size); +} + + +/** + + Variable store garbage collection and reclaim operation. + + @param VariableBase Base address of variable store. + @param LastVariableOffset Offset of last variable. + @param IsVolatile The variable store is volatile or not; + if it is non-volatile, need FTW. + @param UpdatingVariable Pointer to updating variable. + + @return EFI_OUT_OF_RESOURCES + @return EFI_SUCCESS + @return Others + +**/ +EFI_STATUS +Reclaim ( + IN EFI_PHYSICAL_ADDRESS VariableBase, + OUT UINTN *LastVariableOffset, + IN BOOLEAN IsVolatile, + IN VARIABLE_HEADER *UpdatingVariable + ) +{ + VARIABLE_HEADER *Variable; + VARIABLE_HEADER *AddedVariable; + VARIABLE_HEADER *NextVariable; + VARIABLE_HEADER *NextAddedVariable; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINT8 *ValidBuffer; + UINTN MaximumBufferSize; + UINTN VariableSize; + UINTN VariableNameSize; + UINTN UpdatingVariableNameSize; + UINTN NameSize; + UINT8 *CurrPtr; + VOID *Point0; + VOID *Point1; + BOOLEAN FoundAdded; + EFI_STATUS Status; + CHAR16 *VariableNamePtr; + CHAR16 *UpdatingVariableNamePtr; + + VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase); + // + // Recalculate the total size of Common/HwErr type variables in non-volatile area. + // + if (!IsVolatile) { + mVariableModuleGlobal->CommonVariableTotalSize = 0; + mVariableModuleGlobal->HwErrVariableTotalSize = 0; + } + + // + // Start Pointers for the variable. + // + Variable = GetStartPointer (VariableStoreHeader); + MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER); + + while (IsValidVariableHeader (Variable)) { + NextVariable = GetNextVariablePtr (Variable); + if (Variable->State == VAR_ADDED || + Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) + ) { + VariableSize = (UINTN) NextVariable - (UINTN) Variable; + MaximumBufferSize += VariableSize; + } + + Variable = NextVariable; + } + + // + // Reserve the 1 Bytes with Oxff to identify the + // end of the variable buffer. + // + MaximumBufferSize += 1; + ValidBuffer = AllocatePool (MaximumBufferSize); + if (ValidBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SetMem (ValidBuffer, MaximumBufferSize, 0xff); + + // + // Copy variable store header. + // + CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER)); + CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer); + + // + // Reinstall all ADDED variables as long as they are not identical to Updating Variable. + // + Variable = GetStartPointer (VariableStoreHeader); + while (IsValidVariableHeader (Variable)) { + NextVariable = GetNextVariablePtr (Variable); + if (Variable->State == VAR_ADDED) { + if (UpdatingVariable != NULL) { + if (UpdatingVariable == Variable) { + Variable = NextVariable; + continue; + } + + VariableNameSize = NameSizeOfVariable(Variable); + UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable); + + VariableNamePtr = GetVariableNamePtr (Variable); + UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable); + if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) && + VariableNameSize == UpdatingVariableNameSize && + CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) { + Variable = NextVariable; + continue; + } + } + VariableSize = (UINTN) NextVariable - (UINTN) Variable; + CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); + CurrPtr += VariableSize; + if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; + } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->CommonVariableTotalSize += VariableSize; + } + } + Variable = NextVariable; + } + + // + // Reinstall the variable being updated if it is not NULL. + // + if (UpdatingVariable != NULL) { + VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable; + CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize); + CurrPtr += VariableSize; + if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; + } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->CommonVariableTotalSize += VariableSize; + } + } + + // + // Reinstall all in delete transition variables. + // + Variable = GetStartPointer (VariableStoreHeader); + while (IsValidVariableHeader (Variable)) { + NextVariable = GetNextVariablePtr (Variable); + if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + + // + // Buffer has cached all ADDED variable. + // Per IN_DELETED variable, we have to guarantee that + // no ADDED one in previous buffer. + // + + FoundAdded = FALSE; + AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer); + while (IsValidVariableHeader (AddedVariable)) { + NextAddedVariable = GetNextVariablePtr (AddedVariable); + NameSize = NameSizeOfVariable (AddedVariable); + if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) && + NameSize == NameSizeOfVariable (Variable) + ) { + Point0 = (VOID *) GetVariableNamePtr (AddedVariable); + Point1 = (VOID *) GetVariableNamePtr (Variable); + if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) { + FoundAdded = TRUE; + break; + } + } + AddedVariable = NextAddedVariable; + } + if (!FoundAdded) { + // + // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED. + // + VariableSize = (UINTN) NextVariable - (UINTN) Variable; + CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize); + ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED; + CurrPtr += VariableSize; + if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize; + } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->CommonVariableTotalSize += VariableSize; + } + } + } + + Variable = NextVariable; + } + + if (IsVolatile) { + // + // If volatile variable store, just copy valid buffer. + // + SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff); + CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)); + Status = EFI_SUCCESS; + } else { + // + // If non-volatile variable store, perform FTW here. + // + Status = FtwVariableSpace ( + VariableBase, + ValidBuffer, + (UINTN) (CurrPtr - (UINT8 *) ValidBuffer) + ); + CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableBase, VariableStoreHeader->Size); + } + if (!EFI_ERROR (Status)) { + *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer); + } else { + *LastVariableOffset = 0; + } + + FreePool (ValidBuffer); + + return Status; +} + + +/** + Finds variable in storage blocks of volatile and non-volatile storage areas. + + This code finds variable in storage blocks of volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + Otherwise, VariableName and VendorGuid are compared. + + @param VariableName Name of the variable to be found. + @param VendorGuid Vendor GUID to be found. + @param PtrTrack VARIABLE_POINTER_TRACK structure for output, + including the range searched and the target position. + @param Global Pointer to VARIABLE_GLOBAL structure, including + base of volatile variable storage area, base of + NV variable storage area, and a lock. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while + VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_NOT_FOUND Variable not found + +**/ +EFI_STATUS +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN VARIABLE_GLOBAL *Global + ) +{ + VARIABLE_HEADER *Variable[2]; + VARIABLE_HEADER *InDeletedVariable; + VARIABLE_STORE_HEADER *VariableStoreHeader[2]; + UINTN InDeletedStorageIndex; + UINTN Index; + VOID *Point; + + // + // 0: Volatile, 1: Non-Volatile. + // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName + // make use of this mapping to implement search algorithm. + // + VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); + VariableStoreHeader[1] = mNvVariableCache; + + // + // Start Pointers for the variable. + // Actual Data Pointer where data can be written. + // + Variable[0] = GetStartPointer (VariableStoreHeader[0]); + Variable[1] = GetStartPointer (VariableStoreHeader[1]); + + if (VariableName[0] != 0 && VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Find the variable by walk through volatile and then non-volatile variable store. + // + InDeletedVariable = NULL; + InDeletedStorageIndex = 0; + for (Index = 0; Index < 2; Index++) { + while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) { + if (Variable[Index]->State == VAR_ADDED || + Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED) + ) { + if (!AtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) { + if (VariableName[0] == 0) { + if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + InDeletedVariable = Variable[Index]; + InDeletedStorageIndex = Index; + } else { + PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]); + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = (BOOLEAN)(Index == 0); + + return EFI_SUCCESS; + } + } else { + if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) { + Point = (VOID *) GetVariableNamePtr (Variable[Index]); + + ASSERT (NameSizeOfVariable (Variable[Index]) != 0); + if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) { + if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) { + InDeletedVariable = Variable[Index]; + InDeletedStorageIndex = Index; + } else { + PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]); + PtrTrack->CurrPtr = Variable[Index]; + PtrTrack->Volatile = (BOOLEAN)(Index == 0); + + return EFI_SUCCESS; + } + } + } + } + } + } + + Variable[Index] = GetNextVariablePtr (Variable[Index]); + } + if (InDeletedVariable != NULL) { + PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]); + PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]); + PtrTrack->CurrPtr = InDeletedVariable; + PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0); + return EFI_SUCCESS; + } + } + PtrTrack->CurrPtr = NULL; + return EFI_NOT_FOUND; +} + +/** + Get index from supported language codes according to language string. + + This code is used to get corresponding index in supported language codes. It can handle + RFC4646 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index. + In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index. + + For example: + SupportedLang = "engfraengfra" + Lang = "eng" + Iso639Language = TRUE + The return value is "0". + Another example: + SupportedLang = "en;fr;en-US;fr-FR" + Lang = "fr-FR" + Iso639Language = FALSE + The return value is "3". + + @param SupportedLang Platform supported language codes. + @param Lang Configured language. + @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646. + + @retval The index of language in the language codes. + +**/ +UINTN +GetIndexFromSupportedLangCodes( + IN CHAR8 *SupportedLang, + IN CHAR8 *Lang, + IN BOOLEAN Iso639Language + ) +{ + UINTN Index; + UINTN CompareLength; + UINTN LanguageLength; + + if (Iso639Language) { + CompareLength = ISO_639_2_ENTRY_SIZE; + for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) { + if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) { + // + // Successfully find the index of Lang string in SupportedLang string. + // + Index = Index / CompareLength; + return Index; + } + } + ASSERT (FALSE); + return 0; + } else { + // + // Compare RFC4646 language code + // + Index = 0; + for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++); + + for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) { + // + // Skip ';' characters in SupportedLang + // + for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++); + // + // Determine the length of the next language code in SupportedLang + // + for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++); + + if ((CompareLength == LanguageLength) && + (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) { + // + // Successfully find the index of Lang string in SupportedLang string. + // + return Index; + } + } + ASSERT (FALSE); + return 0; + } +} + +/** + Get language string from supported language codes according to index. + + This code is used to get corresponding language strings in supported language codes. It can handle + RFC4646 and ISO639 language tags. + In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index. + In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index. + + For example: + SupportedLang = "engfraengfra" + Index = "1" + Iso639Language = TRUE + The return value is "fra". + Another example: + SupportedLang = "en;fr;en-US;fr-FR" + Index = "1" + Iso639Language = FALSE + The return value is "fr". + + @param SupportedLang Platform supported language codes. + @param Index The index in supported language codes. + @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646. + + @retval The language string in the language codes. + +**/ +CHAR8 * +GetLangFromSupportedLangCodes ( + IN CHAR8 *SupportedLang, + IN UINTN Index, + IN BOOLEAN Iso639Language +) +{ + UINTN SubIndex; + UINTN CompareLength; + CHAR8 *Supported; + + SubIndex = 0; + Supported = SupportedLang; + if (Iso639Language) { + // + // According to the index of Lang string in SupportedLang string to get the language. + // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation. + // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string. + // + CompareLength = ISO_639_2_ENTRY_SIZE; + mVariableModuleGlobal->Lang[CompareLength] = '\0'; + return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength); + + } else { + while (TRUE) { + // + // Take semicolon as delimitation, sequentially traverse supported language codes. + // + for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) { + Supported++; + } + if ((*Supported == '\0') && (SubIndex != Index)) { + // + // Have completed the traverse, but not find corrsponding string. + // This case is not allowed to happen. + // + ASSERT(FALSE); + return NULL; + } + if (SubIndex == Index) { + // + // According to the index of Lang string in SupportedLang string to get the language. + // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation. + // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string. + // + mVariableModuleGlobal->PlatformLang[CompareLength] = '\0'; + return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength); + } + SubIndex++; + + // + // Skip ';' characters in Supported + // + for (; *Supported != '\0' && *Supported == ';'; Supported++); + } + } +} + +/** + Returns a pointer to an allocated buffer that contains the best matching language + from a set of supported languages. + + This function supports both ISO 639-2 and RFC 4646 language codes, but language + code types may not be mixed in a single call to this function. This function + supports a variable argument list that allows the caller to pass in a prioritized + list of language codes to test against all the language codes in SupportedLanguages. + + If SupportedLanguages is NULL, then ASSERT(). + + @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that + contains a set of language codes in the format + specified by Iso639Language. + @param[in] Iso639Language If TRUE, then all language codes are assumed to be + in ISO 639-2 format. If FALSE, then all language + codes are assumed to be in RFC 4646 language format + @param[in] ... A variable argument list that contains pointers to + Null-terminated ASCII strings that contain one or more + language codes in the format specified by Iso639Language. + The first language code from each of these language + code lists is used to determine if it is an exact or + close match to any of the language codes in + SupportedLanguages. Close matches only apply to RFC 4646 + language codes, and the matching algorithm from RFC 4647 + is used to determine if a close match is present. If + an exact or close match is found, then the matching + language code from SupportedLanguages is returned. If + no matches are found, then the next variable argument + parameter is evaluated. The variable argument list + is terminated by a NULL. + + @retval NULL The best matching language could not be found in SupportedLanguages. + @retval NULL There are not enough resources available to return the best matching + language. + @retval Other A pointer to a Null-terminated ASCII string that is the best matching + language in SupportedLanguages. + +**/ +CHAR8 * +EFIAPI +VariableGetBestLanguage ( + IN CONST CHAR8 *SupportedLanguages, + IN BOOLEAN Iso639Language, + ... + ) +{ + VA_LIST Args; + CHAR8 *Language; + UINTN CompareLength; + UINTN LanguageLength; + CONST CHAR8 *Supported; + CHAR8 *Buffer; + + ASSERT (SupportedLanguages != NULL); + + VA_START (Args, Iso639Language); + while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) { + // + // Default to ISO 639-2 mode + // + CompareLength = 3; + LanguageLength = MIN (3, AsciiStrLen (Language)); + + // + // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language + // + if (!Iso639Language) { + for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++); + } + + // + // Trim back the length of Language used until it is empty + // + while (LanguageLength > 0) { + // + // Loop through all language codes in SupportedLanguages + // + for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) { + // + // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages + // + if (!Iso639Language) { + // + // Skip ';' characters in Supported + // + for (; *Supported != '\0' && *Supported == ';'; Supported++); + // + // Determine the length of the next language code in Supported + // + for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++); + // + // If Language is longer than the Supported, then skip to the next language + // + if (LanguageLength > CompareLength) { + continue; + } + } + // + // See if the first LanguageLength characters in Supported match Language + // + if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) { + VA_END (Args); + + Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang; + Buffer[CompareLength] = '\0'; + return CopyMem (Buffer, Supported, CompareLength); + } + } + + if (Iso639Language) { + // + // If ISO 639 mode, then each language can only be tested once + // + LanguageLength = 0; + } else { + // + // If RFC 4646 mode, then trim Language from the right to the next '-' character + // + for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--); + } + } + } + VA_END (Args); + + // + // No matches were found + // + return NULL; +} + +/** + Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang. + + When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes. + + According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization, + and are read-only. Therefore, in variable driver, only store the original value for other use. + + @param[in] VariableName Name of variable. + + @param[in] Data Variable data. + + @param[in] DataSize Size of data. 0 means delete. + +**/ +VOID +AutoUpdateLangVariable( + IN CHAR16 *VariableName, + IN VOID *Data, + IN UINTN DataSize + ) +{ + EFI_STATUS Status; + CHAR8 *BestPlatformLang; + CHAR8 *BestLang; + UINTN Index; + UINT32 Attributes; + VARIABLE_POINTER_TRACK Variable; + BOOLEAN SetLanguageCodes; + + // + // Don't do updates for delete operation + // + if (DataSize == 0) { + return; + } + + SetLanguageCodes = FALSE; + + if (StrCmp (VariableName, L"PlatformLangCodes") == 0) { + // + // PlatformLangCodes is a volatile variable, so it can not be updated at runtime. + // + if (AtRuntime ()) { + return; + } + + SetLanguageCodes = TRUE; + + // + // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only + // Therefore, in variable driver, only store the original value for other use. + // + if (mVariableModuleGlobal->PlatformLangCodes != NULL) { + FreePool (mVariableModuleGlobal->PlatformLangCodes); + } + mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data); + ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL); + + // + // PlatformLang holds a single language from PlatformLangCodes, + // so the size of PlatformLangCodes is enough for the PlatformLang. + // + if (mVariableModuleGlobal->PlatformLang != NULL) { + FreePool (mVariableModuleGlobal->PlatformLang); + } + mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize); + ASSERT (mVariableModuleGlobal->PlatformLang != NULL); + + } else if (StrCmp (VariableName, L"LangCodes") == 0) { + // + // LangCodes is a volatile variable, so it can not be updated at runtime. + // + if (AtRuntime ()) { + return; + } + + SetLanguageCodes = TRUE; + + // + // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only + // Therefore, in variable driver, only store the original value for other use. + // + if (mVariableModuleGlobal->LangCodes != NULL) { + FreePool (mVariableModuleGlobal->LangCodes); + } + mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data); + ASSERT (mVariableModuleGlobal->LangCodes != NULL); + } + + if (SetLanguageCodes + && (mVariableModuleGlobal->PlatformLangCodes != NULL) + && (mVariableModuleGlobal->LangCodes != NULL)) { + // + // Update Lang if PlatformLang is already set + // Update PlatformLang if Lang is already set + // + Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *) mVariableModuleGlobal); + if (!EFI_ERROR (Status)) { + // + // Update Lang + // + VariableName = L"PlatformLang"; + Data = GetVariableDataPtr (Variable.CurrPtr); + DataSize = Variable.CurrPtr->DataSize; + } else { + Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *) mVariableModuleGlobal); + if (!EFI_ERROR (Status)) { + // + // Update PlatformLang + // + VariableName = L"Lang"; + Data = GetVariableDataPtr (Variable.CurrPtr); + DataSize = Variable.CurrPtr->DataSize; + } else { + // + // Neither PlatformLang nor Lang is set, directly return + // + return; + } + } + } + + // + // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions. + // + Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; + + if (StrCmp (VariableName, L"PlatformLang") == 0) { + // + // Update Lang when PlatformLangCodes/LangCodes were set. + // + if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) { + // + // When setting PlatformLang, firstly get most matched language string from supported language codes. + // + BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL); + if (BestPlatformLang != NULL) { + // + // Get the corresponding index in language codes. + // + Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE); + + // + // Get the corresponding ISO639 language tag according to RFC4646 language tag. + // + BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE); + + // + // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously. + // + FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal); + + Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang, + ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL); + + DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang)); + + ASSERT_EFI_ERROR(Status); + } + } + + } else if (StrCmp (VariableName, L"Lang") == 0) { + // + // Update PlatformLang when PlatformLangCodes/LangCodes were set. + // + if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) { + // + // When setting Lang, firstly get most matched language string from supported language codes. + // + BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL); + if (BestLang != NULL) { + // + // Get the corresponding index in language codes. + // + Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE); + + // + // Get the corresponding RFC4646 language tag according to ISO639 language tag. + // + BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE); + + // + // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously. + // + FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal); + + Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang, + AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL); + + DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang)); + ASSERT_EFI_ERROR (Status); + } + } + } +} + +/** + Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set, + index of associated public key is needed. + + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] Data Variable data. + @param[in] DataSize Size of data. 0 means delete. + @param[in] Attributes Attributes of the variable. + @param[in] KeyIndex Index of associated public key. + @param[in] MonotonicCount Value of associated monotonic count. + @param[in] CacheVariable The variable information which is used to keep track of variable usage. + @param[in] TimeStamp Value of associated TimeStamp. + + @retval EFI_SUCCESS The update operation is success. + @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region. + +**/ +EFI_STATUS +UpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL, + IN UINT32 KeyIndex OPTIONAL, + IN UINT64 MonotonicCount OPTIONAL, + IN VARIABLE_POINTER_TRACK *CacheVariable, + IN EFI_TIME *TimeStamp OPTIONAL + ) +{ + EFI_STATUS Status; + VARIABLE_HEADER *NextVariable; + UINTN ScratchSize; + UINTN ScratchDataSize; + UINTN NonVolatileVarableStoreSize; + UINTN VarNameOffset; + UINTN VarDataOffset; + UINTN VarNameSize; + UINTN VarSize; + BOOLEAN Volatile; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + UINT8 State; + BOOLEAN Reclaimed; + VARIABLE_POINTER_TRACK *Variable; + VARIABLE_POINTER_TRACK NvVariable; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINTN CacheOffset; + UINTN BufSize; + UINTN DataOffset; + UINTN RevBufSize; + + if (mVariableModuleGlobal->FvbInstance == NULL) { + // + // The FVB protocol is not installed, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed. + // + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + // + // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL + // + return EFI_NOT_AVAILABLE_YET; + } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL + // The authenticated variable perhaps is not initialized, just return here. + // + return EFI_NOT_AVAILABLE_YET; + } + } + + if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) { + Variable = CacheVariable; + } else { + // + // Update/Delete existing NV variable. + // CacheVariable points to the variable in the memory copy of Flash area + // Now let Variable points to the same variable in Flash area. + // + VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase); + Variable = &NvVariable; + Variable->StartPtr = GetStartPointer (VariableStoreHeader); + Variable->EndPtr = GetEndPointer (VariableStoreHeader); + Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr)); + Variable->Volatile = FALSE; + } + + Fvb = mVariableModuleGlobal->FvbInstance; + Reclaimed = FALSE; + + // + // Tricky part: Use scratch data area at the end of volatile variable store + // as a temporary storage. + // + NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)); + ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); + ScratchDataSize = ScratchSize - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName)); + + if (Variable->CurrPtr != NULL) { + // + // Update/Delete existing variable. + // + if (AtRuntime ()) { + // + // If AtRuntime and the variable is Volatile and Runtime Access, + // the volatile is ReadOnly, and SetVariable should be aborted and + // return EFI_WRITE_PROTECTED. + // + if (Variable->Volatile) { + Status = EFI_WRITE_PROTECTED; + goto Done; + } + // + // Only variable that have NV attributes can be updated/deleted in Runtime. + // + if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } + + // + // Setting a data variable with no access, or zero DataSize attributes + // causes it to be deleted. + // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will + // not delete the variable. + // + if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))|| ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) { + State = Variable->CurrPtr->State; + State &= VAR_DELETED; + + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + Variable->Volatile, + FALSE, + Fvb, + (UINTN) &Variable->CurrPtr->State, + sizeof (UINT8), + &State + ); + if (!EFI_ERROR (Status)) { + UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE); + if (!Variable->Volatile) { + CacheVariable->CurrPtr->State = State; + } + } + goto Done; + } + // + // If the variable is marked valid, and the same data has been passed in, + // then return to the caller immediately. + // + if (DataSizeOfVariable (Variable->CurrPtr) == DataSize && + (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0) && + ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) { + + UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE); + Status = EFI_SUCCESS; + goto Done; + } else if ((Variable->CurrPtr->State == VAR_ADDED) || + (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) { + + // + // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable + // + if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) { + + BufSize = Variable->CurrPtr->DataSize + DataSize; + RevBufSize = MIN (PcdGet32 (PcdMaxAppendVariableSize), ScratchDataSize); + + if (BufSize > RevBufSize) { + // + // If variable size (previous + current) is bigger than reserved buffer in runtime, + // return EFI_OUT_OF_RESOURCES. + // + return EFI_OUT_OF_RESOURCES; + } + + SetMem (mStorageArea, PcdGet32 (PcdMaxAppendVariableSize), 0xff); + // + // Cache the previous variable data into StorageArea. + // + DataOffset = sizeof (VARIABLE_HEADER) + Variable->CurrPtr->NameSize + GET_PAD_SIZE (Variable->CurrPtr->NameSize); + CopyMem (mStorageArea, (UINT8*)((UINTN)Variable->CurrPtr + DataOffset), Variable->CurrPtr->DataSize); + + // + // Append the new data to the end of previous data. + // + CopyMem ((UINT8*)((UINTN)mStorageArea + Variable->CurrPtr->DataSize), Data, DataSize); + + // + // Override Data and DataSize which are used for combined data area including previous and new data. + // + Data = mStorageArea; + DataSize = BufSize; + } + + // + // Mark the old variable as in delete transition. + // + State = Variable->CurrPtr->State; + State &= VAR_IN_DELETED_TRANSITION; + + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + Variable->Volatile, + FALSE, + Fvb, + (UINTN) &Variable->CurrPtr->State, + sizeof (UINT8), + &State + ); + if (EFI_ERROR (Status)) { + goto Done; + } + if (!Variable->Volatile) { + CacheVariable->CurrPtr->State = State; + } + } + } else { + // + // Not found existing variable. Create a new variable. + // + + // + // EFI_VARIABLE_APPEND_WRITE attribute only set for existing variable + // + if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Make sure we are trying to create a new variable. + // Setting a data variable with zero DataSize or no access attributes means to delete it. + // + if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { + Status = EFI_NOT_FOUND; + goto Done; + } + + // + // Only variable have NV|RT attribute can be created in Runtime. + // + if (AtRuntime () && + (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + } + + // + // Function part - create a new variable and copy the data. + // Both update a variable and create a variable will come here. + + SetMem (NextVariable, ScratchSize, 0xff); + + NextVariable->StartId = VARIABLE_DATA; + // + // NextVariable->State = VAR_ADDED; + // + NextVariable->Reserved = 0; + NextVariable->PubKeyIndex = KeyIndex; + NextVariable->MonotonicCount = MonotonicCount; + SetMem (&NextVariable->TimeStamp, sizeof (EFI_TIME), 0); + + if (((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && + ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) { + CopyMem (&NextVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME)); + } else if ( + ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) && + ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) { + // + // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only + // when the new TimeStamp value is later than the current timestamp associated + // with the variable, we need associate the new timestamp with the updated value. + // + if (CompareTimeStamp (&Variable->CurrPtr->TimeStamp, TimeStamp)) { + CopyMem (&NextVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME)); + } + } + + // + // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned + // Attributes bitmask parameter of a GetVariable() call. + // + NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE); + + VarNameOffset = sizeof (VARIABLE_HEADER); + VarNameSize = StrSize (VariableName); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarNameOffset), + VariableName, + VarNameSize + ); + VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize); + CopyMem ( + (UINT8 *) ((UINTN) NextVariable + VarDataOffset), + Data, + DataSize + ); + CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID)); + // + // There will be pad bytes after Data, the NextVariable->NameSize and + // NextVariable->DataSize should not include pad size so that variable + // service can get actual size in GetVariable. + // + NextVariable->NameSize = (UINT32)VarNameSize; + NextVariable->DataSize = (UINT32)DataSize; + + // + // The actual size of the variable that stores in storage should + // include pad size. + // + VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize); + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + // + // Create a nonvolatile variable. + // + Volatile = FALSE; + NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size; + if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) + && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize))) + || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) + && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) { + if (AtRuntime ()) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + // + // Perform garbage collection & reclaim operation. + // + Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, + &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // If still no enough space, return out of resources. + // + if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) + && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize))) + || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) + && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + Reclaimed = TRUE; + } + // + // Four steps + // 1. Write variable header + // 2. Set variable state to header valid + // 3. Write variable data + // 4. Set variable state to valid + // + // + // Step 1: + // + CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset; + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + FALSE, + TRUE, + Fvb, + mVariableModuleGlobal->NonVolatileLastVariableOffset, + sizeof (VARIABLE_HEADER), + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Step 2: + // + NextVariable->State = VAR_HEADER_VALID_ONLY; + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + FALSE, + TRUE, + Fvb, + mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State), + sizeof (UINT8), + &NextVariable->State + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Step 3: + // + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + FALSE, + TRUE, + Fvb, + mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER), + (UINT32) VarSize - sizeof (VARIABLE_HEADER), + (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER) + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Step 4: + // + NextVariable->State = VAR_ADDED; + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + FALSE, + TRUE, + Fvb, + mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State), + sizeof (UINT8), + &NextVariable->State + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize); + + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) { + mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize); + } else { + mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize); + } + // + // update the memory copy of Flash region. + // + CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize); + } else { + // + // Create a volatile variable. + // + Volatile = TRUE; + + if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) { + // + // Perform garbage collection & reclaim operation. + // + Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, + &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // If still no enough space, return out of resources. + // + if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) > + ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size + ) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + Reclaimed = TRUE; + } + + NextVariable->State = VAR_ADDED; + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + TRUE, + TRUE, + Fvb, + mVariableModuleGlobal->VolatileLastVariableOffset, + (UINT32) VarSize, + (UINT8 *) NextVariable + ); + + if (EFI_ERROR (Status)) { + goto Done; + } + + mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize); + } + + // + // Mark the old variable as deleted. + // + if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) { + State = Variable->CurrPtr->State; + State &= VAR_DELETED; + + Status = UpdateVariableStore ( + &mVariableModuleGlobal->VariableGlobal, + Variable->Volatile, + FALSE, + Fvb, + (UINTN) &Variable->CurrPtr->State, + sizeof (UINT8), + &State + ); + if (!EFI_ERROR (Status) && !Variable->Volatile) { + CacheVariable->CurrPtr->State = State; + } + } + + if (!EFI_ERROR (Status)) { + UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE); + } + +Done: + return Status; +} + +/** + + This code finds variable in storage blocks (Volatile or Non-Volatile). + + @param VariableName Name of Variable to be found. + @param VendorGuid Variable vendor GUID. + @param Attributes Attribute value of the variable found. + @param DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param Data Data pointer. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Find the specified variable. + @return EFI_NOT_FOUND Not found. + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +VariableServiceGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + EFI_STATUS Status; + VARIABLE_POINTER_TRACK Variable; + UINTN VarDataSize; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + goto Done; + } + + // + // Get data size + // + VarDataSize = DataSizeOfVariable (Variable.CurrPtr); + ASSERT (VarDataSize != 0); + + if (*DataSize >= VarDataSize) { + if (Data == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize); + if (Attributes != NULL) { + *Attributes = Variable.CurrPtr->Attributes; + } + + *DataSize = VarDataSize; + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE); + + Status = EFI_SUCCESS; + goto Done; + } else { + *DataSize = VarDataSize; + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + +Done: + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + return Status; +} + + + +/** + + This code Finds the Next available variable. + + @param VariableNameSize Size of the variable name. + @param VariableName Pointer to variable name. + @param VendorGuid Variable Vendor Guid. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Find the specified variable. + @return EFI_NOT_FOUND Not found. + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +VariableServiceGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +{ + VARIABLE_POINTER_TRACK Variable; + UINTN VarNameSize; + EFI_STATUS Status; + + if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); + if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { + goto Done; + } + + if (VariableName[0] != 0) { + // + // If variable name is not NULL, get next variable. + // + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + + while (TRUE) { + // + // If both volatile and non-volatile variable store are parsed, + // return not found. + // + if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) { + Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1)); + if (!Variable.Volatile) { + Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase); + Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)); + } else { + Status = EFI_NOT_FOUND; + goto Done; + } + + Variable.CurrPtr = Variable.StartPtr; + if (!IsValidVariableHeader (Variable.CurrPtr)) { + continue; + } + } + // + // Variable is found + // + if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) { + if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) { + VarNameSize = NameSizeOfVariable (Variable.CurrPtr); + ASSERT (VarNameSize != 0); + + if (VarNameSize <= *VariableNameSize) { + CopyMem ( + VariableName, + GetVariableNamePtr (Variable.CurrPtr), + VarNameSize + ); + CopyMem ( + VendorGuid, + &Variable.CurrPtr->VendorGuid, + sizeof (EFI_GUID) + ); + Status = EFI_SUCCESS; + } else { + Status = EFI_BUFFER_TOO_SMALL; + } + + *VariableNameSize = VarNameSize; + goto Done; + } + } + + Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr); + } + +Done: + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + return Status; +} + +/** + + This code sets variable in storage blocks (Volatile or Non-Volatile). + + @param VariableName Name of Variable to be found. + @param VendorGuid Variable vendor GUID. + @param Attributes Attribute value of the variable found + @param DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param Data Data pointer. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Set successfully. + @return EFI_OUT_OF_RESOURCES Resource not enough to set variable. + @return EFI_NOT_FOUND Not found. + @return EFI_WRITE_PROTECTED Variable is read-only. + +**/ +EFI_STATUS +EFIAPI +VariableServiceSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + VARIABLE_POINTER_TRACK Variable; + EFI_STATUS Status; + VARIABLE_HEADER *NextVariable; + EFI_PHYSICAL_ADDRESS Point; + UINTN PayloadSize; + + // + // Check input parameters. + // + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (DataSize != 0 && Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Make sure if runtime bit is set, boot service bit is set also. + // + if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { + return EFI_INVALID_PARAMETER; + } + + // + // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute + // cannot be set both. + // + if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) \ + && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { + return EFI_INVALID_PARAMETER; + } + + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { + if (DataSize < AUTHINFO_SIZE) { + // + // Try to write Authencated Variable without AuthInfo. + // + return EFI_SECURITY_VIOLATION; + } + PayloadSize = DataSize - AUTHINFO_SIZE; + } else { + PayloadSize = DataSize; + } + // + // The size of the VariableName, including the Unicode Null in bytes plus + // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize) + // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others. + // + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + if ((PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) { + return EFI_INVALID_PARAMETER; + } + // + // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX". + // + if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) { + return EFI_INVALID_PARAMETER; + } + } else { + // + // The size of the VariableName, including the Unicode Null in bytes plus + // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes. + // + if ((PayloadSize > PcdGet32 (PcdMaxVariableSize)) || + (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxVariableSize))) { + return EFI_INVALID_PARAMETER; + } + } + + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + // + // Consider reentrant in MCA/INIT/NMI. It needs be reupdated. + // + if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) { + Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase; + // + // Parse non-volatile variable data and get last variable offset. + // + NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point); + while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) + && IsValidVariableHeader (NextVariable)) { + NextVariable = GetNextVariablePtr (NextVariable); + } + mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point; + } + + // + // Check whether the input variable is already existed. + // + FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal); + + // + // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang. + // + AutoUpdateLangVariable (VariableName, Data, DataSize); + // + // Process PK, KEK, Sigdb seperately. + // + if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){ + Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, TRUE); + } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) { + Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE); + } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0)) { + Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes); + } else { + Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes); + } + + InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState); + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + return Status; +} + +/** + + This code returns information about the EFI variables. + + @param Attributes Attributes bitmask to specify the type of variables + on which to return information. + @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available + for the EFI variables associated with the attributes specified. + @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available + for EFI variables associated with the attributes specified. + @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables + associated with the attributes specified. + + @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied. + @return EFI_SUCCESS Query successfully. + @return EFI_UNSUPPORTED The attribute is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +VariableServiceQueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ) +{ + VARIABLE_HEADER *Variable; + VARIABLE_HEADER *NextVariable; + UINT64 VariableSize; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINT64 CommonVariableTotalSize; + UINT64 HwErrVariableTotalSize; + + CommonVariableTotalSize = 0; + HwErrVariableTotalSize = 0; + + if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) { + return EFI_INVALID_PARAMETER; + } + + if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) { + // + // Make sure the Attributes combination is supported by the platform. + // + return EFI_UNSUPPORTED; + } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) { + // + // Make sure if runtime bit is set, boot service bit is set also. + // + return EFI_INVALID_PARAMETER; + } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) { + // + // Make sure RT Attribute is set if we are in Runtime phase. + // + return EFI_INVALID_PARAMETER; + } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + // + // Make sure Hw Attribute is set with NV. + // + return EFI_INVALID_PARAMETER; + } + + AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + + if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) { + // + // Query is Volatile related. + // + VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); + } else { + // + // Query is Non-Volatile related. + // + VariableStoreHeader = mNvVariableCache; + } + + // + // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize + // with the storage size (excluding the storage header size). + // + *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER); + + // + // Harware error record variable needs larger size. + // + if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize); + *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER); + } else { + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size); + *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize); + } + + // + // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size. + // + *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER); + } + + // + // Point to the starting address of the variables. + // + Variable = GetStartPointer (VariableStoreHeader); + + // + // Now walk through the related variable store. + // + while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) { + NextVariable = GetNextVariablePtr (Variable); + VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable; + + if (AtRuntime ()) { + // + // We don't take the state of the variables in mind + // when calculating RemainingVariableStorageSize, + // since the space occupied by variables not marked with + // VAR_ADDED is not allowed to be reclaimed in Runtime. + // + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + HwErrVariableTotalSize += VariableSize; + } else { + CommonVariableTotalSize += VariableSize; + } + } else { + // + // Only care about Variables with State VAR_ADDED, because + // the space not marked as VAR_ADDED is reclaimable now. + // + if (Variable->State == VAR_ADDED) { + if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) { + HwErrVariableTotalSize += VariableSize; + } else { + CommonVariableTotalSize += VariableSize; + } + } + } + + // + // Go to the next one. + // + Variable = NextVariable; + } + + if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){ + *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize; + }else { + *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize; + } + + if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) { + *MaximumVariableSize = 0; + } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) { + *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER); + } + + ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock); + return EFI_SUCCESS; +} + + +/** + This function reclaims variable storage if free size is below the threshold. + +**/ +VOID +ReclaimForOS( + VOID + ) +{ + EFI_STATUS Status; + UINTN CommonVariableSpace; + UINTN RemainingCommonVariableSpace; + UINTN RemainingHwErrVariableSpace; + + Status = EFI_SUCCESS; + + CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space + + RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize; + + RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize; + // + // Check if the free area is blow a threshold. + // + if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize)) + || ((PcdGet32 (PcdHwErrStorageSize) != 0) && + (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){ + Status = Reclaim ( + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, + &mVariableModuleGlobal->NonVolatileLastVariableOffset, + FALSE, + NULL + ); + ASSERT_EFI_ERROR (Status); + } +} + + +/** + Initializes variable write service after FVB was ready. + + @retval EFI_SUCCESS Function successfully executed. + @retval Others Fail to initialize the variable service. + +**/ +EFI_STATUS +VariableWriteServiceInitialize ( + VOID + ) +{ + EFI_STATUS Status; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINTN Index; + UINT8 Data; + EFI_PHYSICAL_ADDRESS VariableStoreBase; + UINT64 VariableStoreLength; + + VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase; + VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase; + VariableStoreLength = VariableStoreHeader->Size; + + // + // Check if the free area is really free. + // + for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreLength; Index++) { + Data = ((UINT8 *) mNvVariableCache)[Index]; + if (Data != 0xff) { + // + // There must be something wrong in variable store, do reclaim operation. + // + Status = Reclaim ( + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, + &mVariableModuleGlobal->NonVolatileLastVariableOffset, + FALSE, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + break; + } + } + + // + // Authenticated variable initialize. + // + Status = AutenticatedVariableServiceInitialize (); + + return Status; +} + + +/** + Initializes variable store area for non-volatile and volatile variable. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + +**/ +EFI_STATUS +VariableCommonInitialize ( + VOID + ) +{ + EFI_STATUS Status; + VARIABLE_STORE_HEADER *VolatileVariableStore; + VARIABLE_STORE_HEADER *VariableStoreHeader; + VARIABLE_HEADER *NextVariable; + EFI_PHYSICAL_ADDRESS TempVariableStoreHeader; + EFI_PHYSICAL_ADDRESS VariableStoreBase; + UINT64 VariableStoreLength; + UINTN ScratchSize; + UINTN VariableSize; + + // + // Allocate runtime memory for variable driver global structure. + // + mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL)); + if (mVariableModuleGlobal == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY); + + // + // Note that in EdkII variable driver implementation, Hardware Error Record type variable + // is stored with common variable in the same NV region. So the platform integrator should + // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of + // PcdFlashNvStorageVariableSize. + // + ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize)); + + // + // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data. + // + ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); + VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize); + if (VolatileVariableStore == NULL) { + FreePool (mVariableModuleGlobal); + return EFI_OUT_OF_RESOURCES; + } + + SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff); + + // + // Initialize Variable Specific Data. + // + mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore; + mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore; + mVariableModuleGlobal->FvbInstance = NULL; + + CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid); + VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize); + VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED; + VolatileVariableStore->State = VARIABLE_STORE_HEALTHY; + VolatileVariableStore->Reserved = 0; + VolatileVariableStore->Reserved1 = 0; + + // + // Get non-volatile varaible store. + // + + TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); + if (TempVariableStoreHeader == 0) { + TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase); + } + VariableStoreBase = TempVariableStoreHeader + \ + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength); + VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \ + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength); + + mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase; + VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase; + if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) { + Status = EFI_VOLUME_CORRUPTED; + DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n")); + goto Done; + } + ASSERT(VariableStoreHeader->Size == VariableStoreLength); + + // + // Parse non-volatile variable data and get last variable offset. + // + NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase); + while (IsValidVariableHeader (NextVariable)) { + VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER); + if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) { + mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize); + } else { + mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize); + } + + NextVariable = GetNextVariablePtr (NextVariable); + } + + mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase; + + // + // Allocate runtime memory used for a memory copy of the FLASH region. + // Keep the memory and the FLASH in sync as updates occur + // + mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength); + if (mNvVariableCache == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength); + Status = EFI_SUCCESS; + +Done: + if (EFI_ERROR (Status)) { + FreePool (mVariableModuleGlobal); + FreePool (VolatileVariableStore); + } + + return Status; +} + + +/** + Get the proper fvb handle and/or fvb protocol by the given Flash address. + + @param[in] Address The Flash address. + @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle. + @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol. + +**/ +EFI_STATUS +GetFvbInfoByAddress ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT EFI_HANDLE *FvbHandle OPTIONAL, + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + EFI_PHYSICAL_ADDRESS FvbBaseAddress; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FVB_ATTRIBUTES_2 Attributes; + + // + // Get all FVB handles. + // + Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + // + // Get the FVB to access variable store. + // + Fvb = NULL; + for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) { + Status = GetFvbByHandle (HandleBuffer[Index], &Fvb); + if (EFI_ERROR (Status)) { + Status = EFI_NOT_FOUND; + break; + } + + // + // Ensure this FVB protocol supported Write operation. + // + Status = Fvb->GetAttributes (Fvb, &Attributes); + if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) { + continue; + } + + // + // Compare the address and select the right one. + // + Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress); + if (EFI_ERROR (Status)) { + continue; + } + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress); + if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + FwVolHeader->FvLength))) { + if (FvbHandle != NULL) { + *FvbHandle = HandleBuffer[Index]; + } + if (FvbProtocol != NULL) { + *FvbProtocol = Fvb; + } + Status = EFI_SUCCESS; + break; + } + } + FreePool (HandleBuffer); + + if (Fvb == NULL) { + Status = EFI_NOT_FOUND; + } + + return Status; +} + diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h new file mode 100644 index 0000000000..6865f0dc71 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h @@ -0,0 +1,491 @@ +/** @file + The internal header file includes the common header files, defines + internal structure and functions used by Variable modules. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _VARIABLE_H_ +#define _VARIABLE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VARIABLE_RECLAIM_THRESHOLD (1024) + +/// +/// The size of a 3 character ISO639 language code. +/// +#define ISO_639_2_ENTRY_SIZE 3 + +typedef struct { + VARIABLE_HEADER *CurrPtr; + VARIABLE_HEADER *EndPtr; + VARIABLE_HEADER *StartPtr; + BOOLEAN Volatile; +} VARIABLE_POINTER_TRACK; + +typedef struct { + EFI_PHYSICAL_ADDRESS VolatileVariableBase; + EFI_PHYSICAL_ADDRESS NonVolatileVariableBase; + EFI_LOCK VariableServicesLock; + UINT32 ReentrantState; +} VARIABLE_GLOBAL; + +typedef struct { + VARIABLE_GLOBAL VariableGlobal; + UINTN VolatileLastVariableOffset; + UINTN NonVolatileLastVariableOffset; + UINTN CommonVariableTotalSize; + UINTN HwErrVariableTotalSize; + CHAR8 *PlatformLangCodes; + CHAR8 *LangCodes; + CHAR8 *PlatformLang; + CHAR8 Lang[ISO_639_2_ENTRY_SIZE + 1]; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbInstance; +} VARIABLE_MODULE_GLOBAL; + +typedef struct { + EFI_GUID *Guid; + CHAR16 *Name; + UINT32 Attributes; + UINTN DataSize; + VOID *Data; +} VARIABLE_CACHE_ENTRY; + +/** + Writes a buffer to variable storage space, in the working block. + + This function writes a buffer to variable storage space into a firmware + volume block device. The destination is specified by the parameter + VariableBase. Fault Tolerant Write protocol is used for writing. + + @param VariableBase Base address of the variable to write. + @param Buffer Point to the data buffer. + @param BufferSize The number of bytes of the data Buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol. + @retval EFI_ABORTED The function could not complete successfully. + +**/ +EFI_STATUS +FtwVariableSpace ( + IN EFI_PHYSICAL_ADDRESS VariableBase, + IN UINT8 *Buffer, + IN UINTN BufferSize + ); + +/** + Finds variable in storage blocks of volatile and non-volatile storage areas. + + This code finds variable in storage blocks of volatile and non-volatile storage areas. + If VariableName is an empty string, then we just return the first + qualified variable without comparing VariableName and VendorGuid. + Otherwise, VariableName and VendorGuid are compared. + + @param VariableName Name of the variable to be found. + @param VendorGuid Vendor GUID to be found. + @param PtrTrack VARIABLE_POINTER_TRACK structure for output, + including the range searched and the target position. + @param Global Pointer to VARIABLE_GLOBAL structure, including + base of volatile variable storage area, base of + NV variable storage area, and a lock. + + @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while + VendorGuid is NULL. + @retval EFI_SUCCESS Variable successfully found. + @retval EFI_INVALID_PARAMETER Variable not found. + +**/ +EFI_STATUS +FindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VARIABLE_POINTER_TRACK *PtrTrack, + IN VARIABLE_GLOBAL *Global + ); + +/** + + This code gets the pointer to the variable data. + + @param Variable Pointer to the Variable Header. + + @return Pointer to Variable Data. + +**/ +UINT8 * +GetVariableDataPtr ( + IN VARIABLE_HEADER *Variable + ); + +/** + + This code gets the size of variable data. + + @param Variable Pointer to the Variable Header. + + @return Size of variable in bytes. + +**/ +UINTN +DataSizeOfVariable ( + IN VARIABLE_HEADER *Variable + ); + +/** + Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set, + index of associated public key is needed. + + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] Data Variable data. + @param[in] DataSize Size of data. 0 means delete. + @param[in] Attributes Attributes of the variable. + @param[in] KeyIndex Index of associated public key. + @param[in] MonotonicCount Value of associated monotonic count. + @param[in] Variable The variable information that is used to keep track of variable usage. + + @param[in] TimeStamp Value of associated TimeStamp. + + @retval EFI_SUCCESS The update operation is success. + @retval EFI_OUT_OF_RESOURCES Variable region is full, cannot write other data into this region. + +**/ +EFI_STATUS +UpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes OPTIONAL, + IN UINT32 KeyIndex OPTIONAL, + IN UINT64 MonotonicCount OPTIONAL, + IN VARIABLE_POINTER_TRACK *Variable, + IN EFI_TIME *TimeStamp OPTIONAL + ); + + +/** + Return TRUE if ExitBootServices () has been called. + + @retval TRUE If ExitBootServices () has been called. +**/ +BOOLEAN +AtRuntime ( + VOID + ); + +/** + Initializes a basic mutual exclusion lock. + + This function initializes a basic mutual exclusion lock to the released state + and returns the lock. Each lock provides mutual exclusion access at its task + priority level. Since there is no preemption or multiprocessor support in EFI, + acquiring the lock only consists of raising to the locks TPL. + If Lock is NULL, then ASSERT(). + If Priority is not a valid TPL value, then ASSERT(). + + @param Lock A pointer to the lock data structure to initialize. + @param Priority EFI TPL is associated with the lock. + + @return The lock. + +**/ +EFI_LOCK * +InitializeLock ( + IN OUT EFI_LOCK *Lock, + IN EFI_TPL Priority + ); + + +/** + Acquires lock only at boot time. Simply returns at runtime. + + This is a temperary function that will be removed when + EfiAcquireLock() in UefiLib can handle the call in UEFI + Runtimer driver in RT phase. + It calls EfiAcquireLock() at boot time, and simply returns + at runtime. + + @param Lock A pointer to the lock to acquire. + +**/ +VOID +AcquireLockOnlyAtBootTime ( + IN EFI_LOCK *Lock + ); + + +/** + Releases lock only at boot time. Simply returns at runtime. + + This is a temperary function which will be removed when + EfiReleaseLock() in UefiLib can handle the call in UEFI + Runtimer driver in RT phase. + It calls EfiReleaseLock() at boot time and simply returns + at runtime. + + @param Lock A pointer to the lock to release. + +**/ +VOID +ReleaseLockOnlyAtBootTime ( + IN EFI_LOCK *Lock + ); + +/** + Retrive the FVB protocol interface by HANDLE. + + @param[in] FvBlockHandle The handle of FVB protocol that provides services for + reading, writing, and erasing the target block. + @param[out] FvBlock The interface of FVB protocol + + @retval EFI_SUCCESS The interface information for the specified protocol was returned. + @retval EFI_UNSUPPORTED The device does not support the FVB protocol. + @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL. + +**/ +EFI_STATUS +GetFvbByHandle ( + IN EFI_HANDLE FvBlockHandle, + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock + ); + + +/** + Retrive the Swap Address Range protocol interface. + + @param[out] SarProtocol The interface of SAR protocol + + @retval EFI_SUCCESS The SAR protocol instance was found and returned in SarProtocol. + @retval EFI_NOT_FOUND The SAR protocol instance was not found. + @retval EFI_INVALID_PARAMETER SarProtocol is NULL. + +**/ +EFI_STATUS +GetSarProtocol ( + OUT VOID **SarProtocol + ); + +/** + Function returns an array of handles that support the FVB protocol + in a buffer allocated from pool. + + @param[out] NumberHandles The number of handles returned in Buffer. + @param[out] Buffer A pointer to the buffer to return the requested + array of handles that support FVB protocol. + + @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of + handles in Buffer was returned in NumberHandles. + @retval EFI_NOT_FOUND No FVB handle was found. + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results. + @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL. + +**/ +EFI_STATUS +GetFvbCountAndBuffer ( + OUT UINTN *NumberHandles, + OUT EFI_HANDLE **Buffer + ); + +/** + Initializes variable store area for non-volatile and volatile variable. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource. + +**/ +EFI_STATUS +VariableCommonInitialize ( + VOID + ); + +/** + This function reclaims variable storage if free size is below the threshold. + +**/ +VOID +ReclaimForOS( + VOID + ); + + +/** + Initializes variable write service after FVB was ready. + + @retval EFI_SUCCESS Function successfully executed. + @retval Others Fail to initialize the variable service. + +**/ +EFI_STATUS +VariableWriteServiceInitialize ( + VOID + ); + +/** + Retrive the SMM Fault Tolerent Write protocol interface. + + @param[out] FtwProtocol The interface of SMM Ftw protocol + + @retval EFI_SUCCESS The SMM SAR protocol instance was found and returned in SarProtocol. + @retval EFI_NOT_FOUND The SMM SAR protocol instance was not found. + @retval EFI_INVALID_PARAMETER SarProtocol is NULL. + +**/ +EFI_STATUS +GetFtwProtocol ( + OUT VOID **FtwProtocol + ); + +/** + Get the proper fvb handle and/or fvb protocol by the given Flash address. + + @param[in] Address The Flash address. + @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle. + @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol. + +**/ +EFI_STATUS +GetFvbInfoByAddress ( + IN EFI_PHYSICAL_ADDRESS Address, + OUT EFI_HANDLE *FvbHandle OPTIONAL, + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL + ); + +/** + + This code finds variable in storage blocks (Volatile or Non-Volatile). + + @param VariableName Name of Variable to be found. + @param VendorGuid Variable vendor GUID. + @param Attributes Attribute value of the variable found. + @param DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param Data Data pointer. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Find the specified variable. + @return EFI_NOT_FOUND Not found. + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +VariableServiceGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + + This code Finds the Next available variable. + + @param VariableNameSize Size of the variable name. + @param VariableName Pointer to variable name. + @param VendorGuid Variable Vendor Guid. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Find the specified variable. + @return EFI_NOT_FOUND Not found. + @return EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +VariableServiceGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ); + +/** + + This code sets variable in storage blocks (Volatile or Non-Volatile). + + @param VariableName Name of Variable to be found. + @param VendorGuid Variable vendor GUID. + @param Attributes Attribute value of the variable found + @param DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param Data Data pointer. + + @return EFI_INVALID_PARAMETER Invalid parameter. + @return EFI_SUCCESS Set successfully. + @return EFI_OUT_OF_RESOURCES Resource not enough to set variable. + @return EFI_NOT_FOUND Not found. + @return EFI_WRITE_PROTECTED Variable is read-only. + +**/ +EFI_STATUS +EFIAPI +VariableServiceSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + + This code returns information about the EFI variables. + + @param Attributes Attributes bitmask to specify the type of variables + on which to return information. + @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available + for the EFI variables associated with the attributes specified. + @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available + for EFI variables associated with the attributes specified. + @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables + associated with the attributes specified. + + @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied. + @return EFI_SUCCESS Query successfully. + @return EFI_UNSUPPORTED The attribute is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +VariableServiceQueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ); + +extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal; + +#endif diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c new file mode 100644 index 0000000000..7b88f15163 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c @@ -0,0 +1,433 @@ +/** @file + Implement all four UEFI Runtime Variable services for the nonvolatile + and volatile storage space and install variable architecture protocol. + +Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Variable.h" +#include "AuthService.h" + +extern VARIABLE_STORE_HEADER *mNvVariableCache; +extern VARIABLE_INFO_ENTRY *gVariableInfo; +EFI_HANDLE mHandle = NULL; +EFI_EVENT mVirtualAddressChangeEvent = NULL; +EFI_EVENT mFtwRegistration = NULL; + +/** + Return TRUE if ExitBootServices () has been called. + + @retval TRUE If ExitBootServices () has been called. +**/ +BOOLEAN +AtRuntime ( + VOID + ) +{ + return EfiAtRuntime (); +} + + +/** + Initializes a basic mutual exclusion lock. + + This function initializes a basic mutual exclusion lock to the released state + and returns the lock. Each lock provides mutual exclusion access at its task + priority level. Since there is no preemption or multiprocessor support in EFI, + acquiring the lock only consists of raising to the locks TPL. + If Lock is NULL, then ASSERT(). + If Priority is not a valid TPL value, then ASSERT(). + + @param Lock A pointer to the lock data structure to initialize. + @param Priority EFI TPL is associated with the lock. + + @return The lock. + +**/ +EFI_LOCK * +InitializeLock ( + IN OUT EFI_LOCK *Lock, + IN EFI_TPL Priority + ) +{ + return EfiInitializeLock (Lock, Priority); +} + + +/** + Acquires lock only at boot time. Simply returns at runtime. + + This is a temperary function that will be removed when + EfiAcquireLock() in UefiLib can handle the call in UEFI + Runtimer driver in RT phase. + It calls EfiAcquireLock() at boot time, and simply returns + at runtime. + + @param Lock A pointer to the lock to acquire. + +**/ +VOID +AcquireLockOnlyAtBootTime ( + IN EFI_LOCK *Lock + ) +{ + if (!AtRuntime ()) { + EfiAcquireLock (Lock); + } +} + + +/** + Releases lock only at boot time. Simply returns at runtime. + + This is a temperary function which will be removed when + EfiReleaseLock() in UefiLib can handle the call in UEFI + Runtimer driver in RT phase. + It calls EfiReleaseLock() at boot time and simply returns + at runtime. + + @param Lock A pointer to the lock to release. + +**/ +VOID +ReleaseLockOnlyAtBootTime ( + IN EFI_LOCK *Lock + ) +{ + if (!AtRuntime ()) { + EfiReleaseLock (Lock); + } +} + +/** + Retrive the Fault Tolerent Write protocol interface. + + @param[out] FtwProtocol The interface of Ftw protocol + + @retval EFI_SUCCESS The FTW protocol instance was found and returned in FtwProtocol. + @retval EFI_NOT_FOUND The FTW protocol instance was not found. + @retval EFI_INVALID_PARAMETER SarProtocol is NULL. + +**/ +EFI_STATUS +GetFtwProtocol ( + OUT VOID **FtwProtocol + ) +{ + EFI_STATUS Status; + + // + // Locate Fault Tolerent Write protocol + // + Status = gBS->LocateProtocol ( + &gEfiFaultTolerantWriteProtocolGuid, + NULL, + FtwProtocol + ); + return Status; +} + +/** + Retrive the FVB protocol interface by HANDLE. + + @param[in] FvBlockHandle The handle of FVB protocol that provides services for + reading, writing, and erasing the target block. + @param[out] FvBlock The interface of FVB protocol + + @retval EFI_SUCCESS The interface information for the specified protocol was returned. + @retval EFI_UNSUPPORTED The device does not support the FVB protocol. + @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL. + +**/ +EFI_STATUS +GetFvbByHandle ( + IN EFI_HANDLE FvBlockHandle, + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock + ) +{ + // + // To get the FVB protocol interface on the handle + // + return gBS->HandleProtocol ( + FvBlockHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) FvBlock + ); +} + + +/** + Function returns an array of handles that support the FVB protocol + in a buffer allocated from pool. + + @param[out] NumberHandles The number of handles returned in Buffer. + @param[out] Buffer A pointer to the buffer to return the requested + array of handles that support FVB protocol. + + @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of + handles in Buffer was returned in NumberHandles. + @retval EFI_NOT_FOUND No FVB handle was found. + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results. + @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL. + +**/ +EFI_STATUS +GetFvbCountAndBuffer ( + OUT UINTN *NumberHandles, + OUT EFI_HANDLE **Buffer + ) +{ + EFI_STATUS Status; + + // + // Locate all handles of Fvb protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, + NULL, + NumberHandles, + Buffer + ); + return Status; +} + + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + It convers pointer to new virtual address. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase); + EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal); + EfiConvertPointer (0x0, (VOID **) &mHashCtx); + EfiConvertPointer (0x0, (VOID **) &mStorageArea); + EfiConvertPointer (0x0, (VOID **) &mNvVariableCache); +} + + +/** + Notification function of EVT_GROUP_READY_TO_BOOT event group. + + This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group. + When the Boot Manager is about to load and execute a boot option, it reclaims variable + storage if free size is below the threshold. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +OnReadyToBoot ( + EFI_EVENT Event, + VOID *Context + ) +{ + ReclaimForOS (); + if (FeaturePcdGet (PcdVariableCollectStatistics)) { + gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo); + } +} + + +/** + Fault Tolerant Write protocol notification event handler. + + Non-Volatile variable write may needs FTW protocol to reclaim when + writting variable. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +FtwNotificationEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; + EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; + EFI_PHYSICAL_ADDRESS NvStorageVariableBase; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; + EFI_PHYSICAL_ADDRESS BaseAddress; + UINT64 Length; + EFI_PHYSICAL_ADDRESS VariableStoreBase; + UINT64 VariableStoreLength; + + // + // Ensure FTW protocol is installed. + // + Status = GetFtwProtocol ((VOID**) &FtwProtocol); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Find the proper FVB protocol for variable. + // + NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); + if (NvStorageVariableBase == 0) { + NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase); + } + Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol); + if (EFI_ERROR (Status)) { + return ; + } + mVariableModuleGlobal->FvbInstance = FvbProtocol; + + // + // Mark the variable storage region of the FLASH as RUNTIME. + // + VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase; + VariableStoreLength = ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase)->Size; + BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK); + Length = VariableStoreLength + (VariableStoreBase - BaseAddress); + Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK); + + Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n")); + } else { + Status = gDS->SetMemorySpaceAttributes ( + BaseAddress, + Length, + GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n")); + } + } + + Status = VariableWriteServiceInitialize (); + ASSERT_EFI_ERROR (Status); + + // + // Install the Variable Write Architectural protocol. + // + Status = gBS->InstallProtocolInterface ( + &mHandle, + &gEfiVariableWriteArchProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Close the notify event to avoid install gEfiVariableWriteArchProtocolGuid again. + // + gBS->CloseEvent (Event); + +} + + +/** + Variable Driver main entry point. The Variable driver places the 4 EFI + runtime services in the EFI System Table and installs arch protocols + for variable read and write services being available. It also registers + a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS Variable service successfully initialized. + +**/ +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT ReadyToBootEvent; + + Status = VariableCommonInitialize (); + ASSERT_EFI_ERROR (Status); + + SystemTable->RuntimeServices->GetVariable = VariableServiceGetVariable; + SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName; + SystemTable->RuntimeServices->SetVariable = VariableServiceSetVariable; + SystemTable->RuntimeServices->QueryVariableInfo = VariableServiceQueryVariableInfo; + + // + // Now install the Variable Runtime Architectural protocol on a new handle. + // + Status = gBS->InstallProtocolInterface ( + &mHandle, + &gEfiVariableArchProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // + // Register FtwNotificationEvent () notify function. + // + EfiCreateProtocolNotifyEvent ( + &gEfiFaultTolerantWriteProtocolGuid, + TPL_CALLBACK, + FtwNotificationEvent, + (VOID *)SystemTable, + &mFtwRegistration + ); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + VariableClassAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVirtualAddressChangeEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Register the event handling function to reclaim variable for OS usage. + // + Status = EfiCreateEventReadyToBootEx ( + TPL_NOTIFY, + OnReadyToBoot, + NULL, + &ReadyToBootEvent + ); + + return EFI_SUCCESS; +} + diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf new file mode 100644 index 0000000000..785808419d --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf @@ -0,0 +1,98 @@ +## @file +# Component description file for Authenticated Variable module. +# +# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VariableRuntimeDxe + FILE_GUID = 2226F30F-3D5B-402d-9936-A97184EB4516 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = VariableServiceInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# +# VIRTUAL_ADDRESS_MAP_CALLBACK = VariableClassAddressChangeEvent +# + +[Sources] + Reclaim.c + Variable.c + VariableDxe.c + Variable.h + AuthService.c + AuthService.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + SynchronizationLib + UefiLib + UefiBootServicesTableLib + BaseMemoryLib + DebugLib + UefiRuntimeLib + DxeServicesTableLib + UefiDriverEntryPoint + PcdLib + BaseCryptLib + PlatformSecureLib + +[Protocols] + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiVariableWriteArchProtocolGuid ## ALWAYS_PRODUCES + gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES + gEfiFaultTolerantWriteProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gEfiAuthenticatedVariableGuid ## PRODUCES ## Configuration Table Guid + gEfiGlobalVariableGuid ## PRODUCES ## Variable Guid + gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event + gEfiCertRsa2048Sha256Guid + gEfiImageSecurityDatabaseGuid + gEfiCertX509Guid + gEfiCertPkcs7Guid + gEfiCertRsa2048Guid + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize + gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize + gEfiSecurityPkgTokenSpaceGuid.PcdMaxAppendVariableSize + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## SOMETIME_CONSUMES (statistic the information of variable.) + +[Depex] + gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid + +# [Event] +# ## +# # Event will be signaled for VIRTUAL_ADDRESS_CHANGE event. +# # +# EVENT_TYPE_NOTIFY_SIGNAL ## PRODUCES +# +# + diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c new file mode 100644 index 0000000000..52d9aa041a --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c @@ -0,0 +1,587 @@ +/** @file + The sample implementation for SMM variable protocol. And this driver + implements an SMI handler to communicate with the DXE runtime driver + to provide variable services. + +Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +#include +#include +#include "Variable.h" + +extern VARIABLE_INFO_ENTRY *gVariableInfo; +EFI_HANDLE mSmmVariableHandle = NULL; +EFI_HANDLE mVariableHandle = NULL; +BOOLEAN mAtRuntime = FALSE; +EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}}; + +EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = { + VariableServiceGetVariable, + VariableServiceGetNextVariableName, + VariableServiceSetVariable, + VariableServiceQueryVariableInfo +}; + + +/** + Return TRUE if ExitBootServices () has been called. + + @retval TRUE If ExitBootServices () has been called. +**/ +BOOLEAN +AtRuntime ( + VOID + ) +{ + return mAtRuntime; +} + +/** + Initializes a basic mutual exclusion lock. + + This function initializes a basic mutual exclusion lock to the released state + and returns the lock. Each lock provides mutual exclusion access at its task + priority level. Since there is no preemption or multiprocessor support in EFI, + acquiring the lock only consists of raising to the locks TPL. + If Lock is NULL, then ASSERT(). + If Priority is not a valid TPL value, then ASSERT(). + + @param Lock A pointer to the lock data structure to initialize. + @param Priority EFI TPL is associated with the lock. + + @return The lock. + +**/ +EFI_LOCK * +InitializeLock ( + IN OUT EFI_LOCK *Lock, + IN EFI_TPL Priority + ) +{ + return Lock; +} + +/** + Acquires lock only at boot time. Simply returns at runtime. + + This is a temperary function that will be removed when + EfiAcquireLock() in UefiLib can handle the call in UEFI + Runtimer driver in RT phase. + It calls EfiAcquireLock() at boot time, and simply returns + at runtime. + + @param Lock A pointer to the lock to acquire. + +**/ +VOID +AcquireLockOnlyAtBootTime ( + IN EFI_LOCK *Lock + ) +{ + +} + + +/** + Releases lock only at boot time. Simply returns at runtime. + + This is a temperary function which will be removed when + EfiReleaseLock() in UefiLib can handle the call in UEFI + Runtimer driver in RT phase. + It calls EfiReleaseLock() at boot time and simply returns + at runtime. + + @param Lock A pointer to the lock to release. + +**/ +VOID +ReleaseLockOnlyAtBootTime ( + IN EFI_LOCK *Lock + ) +{ + +} + +/** + Retrive the SMM Fault Tolerent Write protocol interface. + + @param[out] FtwProtocol The interface of SMM Ftw protocol + + @retval EFI_SUCCESS The SMM FTW protocol instance was found and returned in FtwProtocol. + @retval EFI_NOT_FOUND The SMM FTW protocol instance was not found. + @retval EFI_INVALID_PARAMETER SarProtocol is NULL. + +**/ +EFI_STATUS +GetFtwProtocol ( + OUT VOID **FtwProtocol + ) +{ + EFI_STATUS Status; + + // + // Locate Smm Fault Tolerent Write protocol + // + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmFaultTolerantWriteProtocolGuid, + NULL, + FtwProtocol + ); + return Status; +} + + +/** + Retrive the SMM FVB protocol interface by HANDLE. + + @param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for + reading, writing, and erasing the target block. + @param[out] FvBlock The interface of SMM FVB protocol + + @retval EFI_SUCCESS The interface information for the specified protocol was returned. + @retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol. + @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL. + +**/ +EFI_STATUS +GetFvbByHandle ( + IN EFI_HANDLE FvBlockHandle, + OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock + ) +{ + // + // To get the SMM FVB protocol interface on the handle + // + return gSmst->SmmHandleProtocol ( + FvBlockHandle, + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + (VOID **) FvBlock + ); +} + + +/** + Function returns an array of handles that support the SMM FVB protocol + in a buffer allocated from pool. + + @param[out] NumberHandles The number of handles returned in Buffer. + @param[out] Buffer A pointer to the buffer to return the requested + array of handles that support SMM FVB protocol. + + @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of + handles in Buffer was returned in NumberHandles. + @retval EFI_NOT_FOUND No SMM FVB handle was found. + @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results. + @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL. + +**/ +EFI_STATUS +GetFvbCountAndBuffer ( + OUT UINTN *NumberHandles, + OUT EFI_HANDLE **Buffer + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + + if ((NumberHandles == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + BufferSize = 0; + *NumberHandles = 0; + *Buffer = NULL; + Status = gSmst->SmmLocateHandle ( + ByProtocol, + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + NULL, + &BufferSize, + *Buffer + ); + if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) { + return EFI_NOT_FOUND; + } + + *Buffer = AllocatePool (BufferSize); + if (*Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gSmst->SmmLocateHandle ( + ByProtocol, + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + NULL, + &BufferSize, + *Buffer + ); + + *NumberHandles = BufferSize / sizeof(EFI_HANDLE); + if (EFI_ERROR(Status)) { + *NumberHandles = 0; + } + + return Status; +} + + +/** + Get the variable statistics information from the information buffer pointed by gVariableInfo. + + @param[in, out] InfoEntry A pointer to the buffer of variable information entry. + On input, point to the variable information returned last time. if + InfoEntry->VendorGuid is zero, return the first information. + On output, point to the next variable information. + @param[in, out] InfoSize On input, the size of the variable information buffer. + On output, the returned variable information size. + + @retval EFI_SUCCESS The variable information is found and returned successfully. + @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The + PcdVariableCollectStatistics should be set TRUE to support it. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information. + +**/ +EFI_STATUS +SmmVariableGetStatistics ( + IN OUT VARIABLE_INFO_ENTRY *InfoEntry, + IN OUT UINTN *InfoSize + ) +{ + VARIABLE_INFO_ENTRY *VariableInfo; + UINTN NameLength; + UINTN StatisticsInfoSize; + CHAR16 *InfoName; + + ASSERT (InfoEntry != NULL); + VariableInfo = gVariableInfo; + if (VariableInfo == NULL) { + return EFI_UNSUPPORTED; + } + + StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name); + if (*InfoSize < sizeof (VARIABLE_INFO_ENTRY)) { + *InfoSize = StatisticsInfoSize; + return EFI_BUFFER_TOO_SMALL; + } + InfoName = (CHAR16 *)(InfoEntry + 1); + + if (CompareGuid (&InfoEntry->VendorGuid, &mZeroGuid)) { + // + // Return the first variable info + // + CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY)); + CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name)); + *InfoSize = StatisticsInfoSize; + return EFI_SUCCESS; + } + + // + // Get the next variable info + // + while (VariableInfo != NULL) { + if (CompareGuid (&VariableInfo->VendorGuid, &InfoEntry->VendorGuid)) { + NameLength = StrSize (VariableInfo->Name); + if (NameLength == StrSize (InfoName)) { + if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) { + // + // Find the match one + // + VariableInfo = VariableInfo->Next; + break; + } + } + } + VariableInfo = VariableInfo->Next; + }; + + if (VariableInfo == NULL) { + *InfoSize = 0; + return EFI_SUCCESS; + } + + // + // Output the new variable info + // + StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name); + if (*InfoSize < StatisticsInfoSize) { + *InfoSize = StatisticsInfoSize; + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY)); + CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name)); + *InfoSize = StatisticsInfoSize; + + return EFI_SUCCESS; +} + + +/** + Communication service SMI Handler entry. + + This SMI handler provides services for the variable wrapper driver. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] RegisterContext Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers + should still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should + still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still + be called. + @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced. +**/ +EFI_STATUS +EFIAPI +SmmVariableHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *RegisterContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; + SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName; + SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo; + VARIABLE_INFO_ENTRY *VariableInfo; + UINTN InfoSize; + + ASSERT (CommBuffer != NULL); + + SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer; + switch (SmmVariableFunctionHeader->Function) { + case SMM_VARIABLE_FUNCTION_GET_VARIABLE: + SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data; + Status = VariableServiceGetVariable ( + SmmVariableHeader->Name, + &SmmVariableHeader->Guid, + &SmmVariableHeader->Attributes, + &SmmVariableHeader->DataSize, + (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize + ); + break; + + case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME: + GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) SmmVariableFunctionHeader->Data; + Status = VariableServiceGetNextVariableName ( + &GetNextVariableName->NameSize, + GetNextVariableName->Name, + &GetNextVariableName->Guid + ); + break; + + case SMM_VARIABLE_FUNCTION_SET_VARIABLE: + SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data; + Status = VariableServiceSetVariable ( + SmmVariableHeader->Name, + &SmmVariableHeader->Guid, + SmmVariableHeader->Attributes, + SmmVariableHeader->DataSize, + (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize + ); + break; + + case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO: + QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data; + Status = VariableServiceQueryVariableInfo ( + QueryVariableInfo->Attributes, + &QueryVariableInfo->MaximumVariableStorageSize, + &QueryVariableInfo->RemainingVariableStorageSize, + &QueryVariableInfo->MaximumVariableSize + ); + break; + + case SMM_VARIABLE_FUNCTION_READY_TO_BOOT: + ReclaimForOS (); + Status = EFI_SUCCESS; + break; + + case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE: + mAtRuntime = TRUE; + Status = EFI_SUCCESS; + break; + + case SMM_VARIABLE_FUNCTION_GET_STATISTICS: + VariableInfo = (VARIABLE_INFO_ENTRY *) SmmVariableFunctionHeader->Data; + InfoSize = *CommBufferSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data); + Status = SmmVariableGetStatistics (VariableInfo, &InfoSize); + *CommBufferSize = InfoSize + OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data); + break; + + default: + ASSERT (FALSE); + Status = EFI_UNSUPPORTED; + } + + SmmVariableFunctionHeader->ReturnStatus = Status; + + return EFI_SUCCESS; +} + + +/** + SMM Fault Tolerant Write protocol notification event handler. + + Non-Volatile variable write may needs FTW protocol to reclaim when + writting variable. + + @param Protocol Points to the protocol's unique identifier + @param Interface Points to the interface instance + @param Handle The handle on which the interface was installed + + @retval EFI_SUCCESS SmmEventCallback runs successfully + @retval EFI_NOT_FOUND The Fvb protocol for variable is not found. + + **/ +EFI_STATUS +EFIAPI +SmmFtwNotificationEvent ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + EFI_STATUS Status; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; + EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol; + EFI_PHYSICAL_ADDRESS NvStorageVariableBase; + + if (mVariableModuleGlobal->FvbInstance != NULL) { + return EFI_SUCCESS; + } + + // + // Ensure SMM FTW protocol is installed. + // + Status = GetFtwProtocol ((VOID **)&FtwProtocol); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Find the proper FVB protocol for variable. + // + NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64); + if (NvStorageVariableBase == 0) { + NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase); + } + Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + mVariableModuleGlobal->FvbInstance = FvbProtocol; + + Status = VariableWriteServiceInitialize (); + ASSERT_EFI_ERROR (Status); + + // + // Notify the variable wrapper driver the variable write service is ready + // + Status = gBS->InstallProtocolInterface ( + &mSmmVariableHandle, + &gSmmVariableWriteGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + + +/** + Variable Driver main entry point. The Variable driver places the 4 EFI + runtime services in the EFI System Table and installs arch protocols + for variable read and write services being available. It also registers + a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS Variable service successfully initialized. + +**/ +EFI_STATUS +EFIAPI +VariableServiceInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE VariableHandle; + VOID *SmmFtwRegistration; + + // + // Variable initialize. + // + Status = VariableCommonInitialize (); + ASSERT_EFI_ERROR (Status); + + // + // Install the Smm Variable Protocol on a new handle. + // + VariableHandle = NULL; + Status = gSmst->SmmInstallProtocolInterface ( + &VariableHandle, + &gEfiSmmVariableProtocolGuid, + EFI_NATIVE_INTERFACE, + &gSmmVariable + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Register SMM variable SMI handler + /// + VariableHandle = NULL; + Status = gSmst->SmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle); + ASSERT_EFI_ERROR (Status); + + // + // Notify the variable wrapper driver the variable service is ready + // + Status = SystemTable->BootServices->InstallProtocolInterface ( + &mVariableHandle, + &gEfiSmmVariableProtocolGuid, + EFI_NATIVE_INTERFACE, + &gSmmVariable + ); + ASSERT_EFI_ERROR (Status); + + // + // Register FtwNotificationEvent () notify function. + // + Status = gSmst->SmmRegisterProtocolNotify ( + &gEfiSmmFaultTolerantWriteProtocolGuid, + SmmFtwNotificationEvent, + &SmmFtwRegistration + ); + ASSERT_EFI_ERROR (Status); + + SmmFtwNotificationEvent (NULL, NULL, NULL); + + return EFI_SUCCESS; +} + + diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf new file mode 100644 index 0000000000..63c34e4cf5 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf @@ -0,0 +1,96 @@ +## @file +# Component description file for SMM Authenticated Variable module. +# +# This module installs SMM variable protocol into SMM protocol database, +# which can be used by SMM driver, and installs SMM variable protocol +# into BS protocol database, which can be used to notify the SMM Runtime +# Dxe driver that the SMM variable service is ready. +# This module should be used with SMM Runtime DXE module together. The +# SMM Runtime DXE module would install variable arch protocol and variable +# write arch protocol based on SMM variable module. +# +# Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VariableSmm + FILE_GUID = D34BDC5E-968A-40f5-A48C-E594F45AE211 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = VariableServiceInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + + +[Sources] + Reclaim.c + Variable.c + VariableSmm.c + AuthService.c + Variable.h + AuthService.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + MemoryAllocationLib + BaseLib + SynchronizationLib + UefiLib + SmmServicesTableLib + BaseMemoryLib + DebugLib + DxeServicesTableLib + BaseCryptLib + PlatformSecureLib + +[Protocols] + gEfiSmmFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiSmmVariableProtocolGuid ## ALWAYS_PRODUCES + gEfiSmmFaultTolerantWriteProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + gEfiAuthenticatedVariableGuid ## PRODUCES ## Configuration Table Guid + gEfiGlobalVariableGuid ## PRODUCES ## Variable Guid + gSmmVariableWriteGuid ## PRODUCES ## SMM Variable Write Guid + gEfiCertRsa2048Sha256Guid + gEfiImageSecurityDatabaseGuid + gEfiCertX509Guid + gEfiCertPkcs7Guid + gEfiCertRsa2048Guid + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize + gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize + gEfiSecurityPkgTokenSpaceGuid.PcdMaxAppendVariableSize + +[FeaturePcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## SOMETIME_CONSUMES (statistic the information of variable.) + +[Depex] + TRUE + + diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c new file mode 100644 index 0000000000..212dd51102 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c @@ -0,0 +1,651 @@ +/** @file + Implement all four UEFI Runtime Variable services for the nonvolatile + and volatile storage space and install variable architecture protocol + based on SMM variable module. + +Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +EFI_HANDLE mHandle = NULL; +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL; +EFI_EVENT mVirtualAddressChangeEvent = NULL; +EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL; +UINT8 *mVariableBuffer = NULL; +UINT8 *mVariableBufferPhysical = NULL; +UINTN mVariableBufferSize; + + +/** + Initialize the communicate buffer using DataSize and Function. + + The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + + DataSize. + + @param[out] DataPtr Points to the data in the communicate buffer. + @param[in] DataSize The data size to send to SMM. + @param[in] Function The function number to initialize the communicate header. + + @retval EFI_INVALID_PARAMETER The data size is too big. + @retval EFI_SUCCESS Find the specified variable. + +**/ +EFI_STATUS +InitCommunicateBuffer ( + OUT VOID **DataPtr OPTIONAL, + IN UINTN DataSize, + IN UINTN Function + ) +{ + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + + + if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) { + return EFI_INVALID_PARAMETER; + } + + SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer; + CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid); + SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; + + SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data; + SmmVariableFunctionHeader->Function = Function; + if (DataPtr != NULL) { + *DataPtr = SmmVariableFunctionHeader->Data; + } + + return EFI_SUCCESS; +} + + +/** + Send the data in communicate buffer to SMM. + + @param[in] DataSize This size of the function header and the data. + + @retval EFI_SUCCESS Success is returned from the functin in SMM. + @retval Others Failure is returned from the function in SMM. + +**/ +EFI_STATUS +SendCommunicateBuffer ( + IN UINTN DataSize + ) +{ + EFI_STATUS Status; + UINTN CommSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; + + CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; + Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize); + ASSERT_EFI_ERROR (Status); + + SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer; + SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data; + return SmmVariableFunctionHeader->ReturnStatus; +} + + +/** + This code finds variable in storage blocks (Volatile or Non-Volatile). + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[out] Attributes Attribute value of the variable found. + @param[in, out] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[out] Data Data pointer. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_SUCCESS Find the specified variable. + @retval EFI_NOT_FOUND Not found. + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +RuntimeServiceGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; + + if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((*DataSize != 0) && (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Init the communicate buffer. The buffer data size is: + // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. + // + PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName); + Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (SmmVariableHeader != NULL); + + CopyGuid (&SmmVariableHeader->Guid, VendorGuid); + SmmVariableHeader->DataSize = *DataSize; + SmmVariableHeader->NameSize = StrSize (VariableName); + if (Attributes == NULL) { + SmmVariableHeader->Attributes = 0; + } else { + SmmVariableHeader->Attributes = *Attributes; + } + CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize); + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (PayloadSize); + + // + // Get data from SMM. + // + *DataSize = SmmVariableHeader->DataSize; + if (Attributes != NULL) { + *Attributes = SmmVariableHeader->Attributes; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize); + + return Status; +} + + +/** + This code Finds the Next available variable. + + @param[in, out] VariableNameSize Size of the variable name. + @param[in, out] VariableName Pointer to variable name. + @param[in, out] VendorGuid Variable Vendor Guid. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_SUCCESS Find the specified variable. + @retval EFI_NOT_FOUND Not found. + @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result. + +**/ +EFI_STATUS +EFIAPI +RuntimeServiceGetNextVariableName ( + IN OUT UINTN *VariableNameSize, + IN OUT CHAR16 *VariableName, + IN OUT EFI_GUID *VendorGuid + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName; + + if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Init the communicate buffer. The buffer data size is: + // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. + // + PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + *VariableNameSize; + Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (SmmGetNextVariableName != NULL); + + SmmGetNextVariableName->NameSize = *VariableNameSize; + CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid); + CopyMem (SmmGetNextVariableName->Name, VariableName, *VariableNameSize); + + // + // Send data to SMM + // + Status = SendCommunicateBuffer (PayloadSize); + + // + // Get data from SMM. + // + *VariableNameSize = SmmGetNextVariableName->NameSize; + if (EFI_ERROR (Status)) { + return Status; + } + + CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid); + CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); + + return Status; +} + +/** + This code sets variable in storage blocks (Volatile or Non-Volatile). + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Attributes Attribute value of the variable found + @param[in] DataSize Size of Data found. If size is less than the + data, this value contains the required size. + @param[in] Data Data pointer. + + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_SUCCESS Set successfully. + @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable. + @retval EFI_NOT_FOUND Not found. + @retval EFI_WRITE_PROTECTED Variable is read-only. + +**/ +EFI_STATUS +EFIAPI +RuntimeServiceSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader; + + // + // Check input parameters. + // + if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (DataSize != 0 && Data == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Init the communicate buffer. The buffer data size is: + // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize. + // + PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName) + DataSize; + Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (SmmVariableHeader != NULL); + + CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid); + SmmVariableHeader->DataSize = DataSize; + SmmVariableHeader->NameSize = StrSize (VariableName); + SmmVariableHeader->Attributes = Attributes; + CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize); + CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize); + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (PayloadSize); + + return Status; +} + + +/** + This code returns information about the EFI variables. + + @param[in] Attributes Attributes bitmask to specify the type of variables + on which to return information. + @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available + for the EFI variables associated with the attributes specified. + @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available + for EFI variables associated with the attributes specified. + @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables + associated with the attributes specified. + + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied. + @retval EFI_SUCCESS Query successfully. + @retval EFI_UNSUPPORTED The attribute is not supported on this platform. + +**/ +EFI_STATUS +EFIAPI +RuntimeServiceQueryVariableInfo ( + IN UINT32 Attributes, + OUT UINT64 *MaximumVariableStorageSize, + OUT UINT64 *RemainingVariableStorageSize, + OUT UINT64 *MaximumVariableSize + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo; + + if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Init the communicate buffer. The buffer data size is: + // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize; + // + PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO); + Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO); + if (EFI_ERROR (Status)) { + return Status; + } + ASSERT (SmmQueryVariableInfo != NULL); + + SmmQueryVariableInfo->Attributes = Attributes; + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (PayloadSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get data from SMM. + // + *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize; + *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize; + *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; + + return EFI_SUCCESS; +} + + +/** + Exit Boot Services Event notification handler. + + Notify SMM variable driver about the event. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +OnExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Init the communicate buffer. The buffer data size is: + // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE. + // + InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); + + // + // Send data to SMM. + // + SendCommunicateBuffer (0); +} + + +/** + On Ready To Boot Services Event notification handler. + + Notify SMM variable driver about the event. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Init the communicate buffer. The buffer data size is: + // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE. + // + InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT); + + // + // Send data to SMM. + // + SendCommunicateBuffer (0); +} + + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + It convers pointer to new virtual address. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +VariableAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EfiConvertPointer (0x0, (VOID **) &mVariableBuffer); + EfiConvertPointer (0x0, (VOID **) &mSmmCommunication); +} + + +/** + Initialize variable service and install Variable Architectural protocol. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +SmmVariableReady ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable); + if (EFI_ERROR (Status)) { + return; + } + + Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication); + ASSERT_EFI_ERROR (Status); + + // + // Allocate memory for variable store. + // + mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE; + mVariableBufferSize += MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)); + mVariableBuffer = AllocateRuntimePool (mVariableBufferSize); + ASSERT (mVariableBuffer != NULL); + + // + // Save the buffer physical address used for SMM conmunication. + // + mVariableBufferPhysical = mVariableBuffer; + + gRT->GetVariable = RuntimeServiceGetVariable; + gRT->GetNextVariableName = RuntimeServiceGetNextVariableName; + gRT->SetVariable = RuntimeServiceSetVariable; + gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo; + + // + // Install the Variable Architectural Protocol on a new handle. + // + Status = gBS->InstallProtocolInterface ( + &mHandle, + &gEfiVariableArchProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); +} + + +/** + SMM Non-Volatile variable write service is ready notify event handler. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +SmmVariableWriteReady ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *ProtocolOps; + + // + // Check whether the protocol is installed or not. + // + Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps); + if (EFI_ERROR (Status)) { + return; + } + + Status = gBS->InstallProtocolInterface ( + &mHandle, + &gEfiVariableWriteArchProtocolGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); +} + + +/** + Variable Driver main entry point. The Variable driver places the 4 EFI + runtime services in the EFI System Table and installs arch protocols + for variable read and write services being available. It also registers + a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS Variable service successfully initialized. + +**/ +EFI_STATUS +EFIAPI +VariableSmmRuntimeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *SmmVariableRegistration; + VOID *SmmVariableWriteRegistration; + EFI_EVENT OnReadyToBootEvent; + EFI_EVENT ExitBootServiceEvent; + + // + // Smm variable service is ready + // + EfiCreateProtocolNotifyEvent ( + &gEfiSmmVariableProtocolGuid, + TPL_CALLBACK, + SmmVariableReady, + NULL, + &SmmVariableRegistration + ); + + // + // Smm Non-Volatile variable write service is ready + // + EfiCreateProtocolNotifyEvent ( + &gSmmVariableWriteGuid, + TPL_CALLBACK, + SmmVariableWriteReady, + NULL, + &SmmVariableWriteRegistration + ); + + // + // Register the event to reclaim variable for OS usage. + // + EfiCreateEventReadyToBootEx ( + TPL_NOTIFY, + OnReadyToBoot, + NULL, + &OnReadyToBootEvent + ); + + // + // Register the event to inform SMM variable that it is at runtime. + // + gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServices, + NULL, + &gEfiEventExitBootServicesGuid, + &ExitBootServiceEvent + ); + + // + // Register the event to convert the pointer for runtime. + // + gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + VariableAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVirtualAddressChangeEvent + ); + + return EFI_SUCCESS; +} + diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf new file mode 100644 index 0000000000..c1fb6acae8 --- /dev/null +++ b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf @@ -0,0 +1,68 @@ +## @file +# Component description file for Authenticated Variable SmmRuntimeDxe module. +# +# This module is the Runtime DXE part correspond to SMM variable module. It +# installs variable arch protocol and variable write arch protocol and works +# with SMM variable module together. +# +# Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VariableSmmRuntimeDxe + FILE_GUID = 067E2381-7234-4798-B49C-D5FECBFF6D07 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = VariableSmmRuntimeInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# +# VIRTUAL_ADDRESS_MAP_CALLBACK = VariableAddressChangeEvent +# + +[Sources] + VariableSmmRuntimeDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiBootServicesTableLib + DebugLib + UefiRuntimeLib + DxeServicesTableLib + UefiDriverEntryPoint + PcdLib + +[Protocols] + gEfiVariableWriteArchProtocolGuid ## ALWAYS_PRODUCES + gEfiVariableArchProtocolGuid ## ALWAYS_PRODUCES + gEfiSmmCommunicationProtocolGuid + gEfiSmmVariableProtocolGuid + +[Guids] + gEfiEventVirtualAddressChangeGuid ## PRODUCES ## Event + gSmmVariableWriteGuid + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + +[Depex] + gEfiSmmCommunicationProtocolGuid -- 2.30.2