mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-01 12:53:27 +01:00
929 lines
30 KiB
C
929 lines
30 KiB
C
/** @file
|
|
Execute pending TPM2 requests from OS or BIOS.
|
|
|
|
Caution: This module requires additional review when modified.
|
|
This driver will have external input - variable.
|
|
This external input must be validated carefully to avoid security issue.
|
|
|
|
Tcg2ExecutePendingTpmRequest() will receive untrusted input and do validation.
|
|
|
|
Copyright (C) 2018, Red Hat, Inc.
|
|
Copyright (c) 2018, IBM Corporation. All rights reserved.<BR>
|
|
Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <PiDxe.h>
|
|
|
|
#include <Guid/Tcg2PhysicalPresenceData.h>
|
|
#include <IndustryStandard/QemuTpm.h>
|
|
#include <Protocol/Tcg2Protocol.h>
|
|
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/DxeServicesTableLib.h>
|
|
#include <Library/HiiLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/PrintLib.h>
|
|
#include <Library/QemuFwCfgLib.h>
|
|
#include <Library/Tpm2CommandLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Library/UefiBootManagerLib.h>
|
|
|
|
#include <Library/Tcg2PhysicalPresenceLib.h>
|
|
|
|
#define CONFIRM_BUFFER_SIZE 4096
|
|
|
|
EFI_HII_HANDLE mTcg2PpStringPackHandle;
|
|
|
|
#define TPM_PPI_FLAGS (QEMU_TPM_PPI_FUNC_ALLOWED_USR_REQ)
|
|
|
|
STATIC volatile QEMU_TPM_PPI *mPpi;
|
|
|
|
/**
|
|
Reads QEMU PPI config from fw_cfg.
|
|
|
|
@param[out] The Config structure to read to.
|
|
|
|
@retval EFI_SUCCESS Operation completed successfully.
|
|
@retval EFI_PROTOCOL_ERROR Invalid fw_cfg entry size.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
QemuTpmReadConfig (
|
|
OUT QEMU_FWCFG_TPM_CONFIG *Config
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
FIRMWARE_CONFIG_ITEM FwCfgItem;
|
|
UINTN FwCfgSize;
|
|
|
|
Status = QemuFwCfgFindFile ("etc/tpm/config", &FwCfgItem, &FwCfgSize);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (FwCfgSize != sizeof (*Config)) {
|
|
return EFI_PROTOCOL_ERROR;
|
|
}
|
|
|
|
QemuFwCfgSelectItem (FwCfgItem);
|
|
QemuFwCfgReadBytes (sizeof (*Config), Config);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Initializes QEMU PPI memory region.
|
|
|
|
@retval EFI_SUCCESS Operation completed successfully.
|
|
@retval EFI_PROTOCOL_ERROR PPI address is invalid.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
QemuTpmInitPPI (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
QEMU_FWCFG_TPM_CONFIG Config;
|
|
EFI_PHYSICAL_ADDRESS PpiAddress64;
|
|
EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
|
|
UINTN Idx;
|
|
|
|
if (mPpi != NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Status = QemuTpmReadConfig (&Config);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
mPpi = (QEMU_TPM_PPI *)(UINTN)Config.PpiAddress;
|
|
if (mPpi == NULL) {
|
|
return EFI_PROTOCOL_ERROR;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "[TPM2PP] mPpi=%p version=%d\n", mPpi, Config.TpmVersion));
|
|
|
|
PpiAddress64 = (UINTN)mPpi;
|
|
if ((PpiAddress64 & ~(UINT64)EFI_PAGE_MASK) !=
|
|
((PpiAddress64 + sizeof *mPpi - 1) & ~(UINT64)EFI_PAGE_MASK))
|
|
{
|
|
DEBUG ((DEBUG_ERROR, "[TPM2PP] mPpi crosses a page boundary\n"));
|
|
goto InvalidPpiAddress;
|
|
}
|
|
|
|
Status = gDS->GetMemorySpaceDescriptor (PpiAddress64, &Descriptor);
|
|
if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
|
|
ASSERT_EFI_ERROR (Status);
|
|
goto InvalidPpiAddress;
|
|
}
|
|
|
|
if (!EFI_ERROR (Status) &&
|
|
((Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) &&
|
|
(Descriptor.GcdMemoryType != EfiGcdMemoryTypeNonExistent)))
|
|
{
|
|
DEBUG ((DEBUG_ERROR, "[TPM2PP] mPpi has an invalid memory type\n"));
|
|
goto InvalidPpiAddress;
|
|
}
|
|
|
|
for (Idx = 0; Idx < ARRAY_SIZE (mPpi->Func); Idx++) {
|
|
mPpi->Func[Idx] = 0;
|
|
}
|
|
|
|
if (Config.TpmVersion == QEMU_TPM_VERSION_2) {
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_NO_ACTION] = TPM_PPI_FLAGS;
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_CLEAR] = TPM_PPI_FLAGS;
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR] = TPM_PPI_FLAGS;
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2] = TPM_PPI_FLAGS;
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3] = TPM_PPI_FLAGS;
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS] = TPM_PPI_FLAGS;
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_CHANGE_EPS] = TPM_PPI_FLAGS;
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS] = TPM_PPI_FLAGS;
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID] = TPM_PPI_FLAGS;
|
|
mPpi->Func[TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID] = TPM_PPI_FLAGS;
|
|
}
|
|
|
|
if (mPpi->In == 0) {
|
|
mPpi->In = 1;
|
|
mPpi->Request = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
|
|
mPpi->LastRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
|
|
mPpi->NextStep = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
InvalidPpiAddress:
|
|
mPpi = NULL;
|
|
return EFI_PROTOCOL_ERROR;
|
|
}
|
|
|
|
/**
|
|
Get string by string id from HII Interface.
|
|
|
|
@param[in] Id String ID.
|
|
|
|
@retval CHAR16 * String from ID.
|
|
@retval NULL If error occurs.
|
|
|
|
**/
|
|
STATIC
|
|
CHAR16 *
|
|
Tcg2PhysicalPresenceGetStringById (
|
|
IN EFI_STRING_ID Id
|
|
)
|
|
{
|
|
return HiiGetString (mTcg2PpStringPackHandle, Id, NULL);
|
|
}
|
|
|
|
/**
|
|
Send ClearControl and Clear command to TPM.
|
|
|
|
@param[in] PlatformAuth platform auth value. NULL means no platform auth change.
|
|
|
|
@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
|
|
EFIAPI
|
|
Tpm2CommandClear (
|
|
IN TPM2B_AUTH *PlatformAuth OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
TPMS_AUTH_COMMAND *AuthSession;
|
|
TPMS_AUTH_COMMAND LocalAuthSession;
|
|
|
|
if (PlatformAuth == NULL) {
|
|
AuthSession = NULL;
|
|
} else {
|
|
AuthSession = &LocalAuthSession;
|
|
ZeroMem (&LocalAuthSession, sizeof (LocalAuthSession));
|
|
LocalAuthSession.sessionHandle = TPM_RS_PW;
|
|
LocalAuthSession.hmac.size = PlatformAuth->size;
|
|
CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size);
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Tpm2ClearControl ... \n"));
|
|
Status = Tpm2ClearControl (TPM_RH_PLATFORM, AuthSession, NO);
|
|
DEBUG ((DEBUG_INFO, "Tpm2ClearControl - %r\n", Status));
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "Tpm2Clear ... \n"));
|
|
Status = Tpm2Clear (TPM_RH_PLATFORM, AuthSession);
|
|
DEBUG ((DEBUG_INFO, "Tpm2Clear - %r\n", Status));
|
|
|
|
Done:
|
|
ZeroMem (&LocalAuthSession.hmac, sizeof (LocalAuthSession.hmac));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Change EPS.
|
|
|
|
@param[in] PlatformAuth platform auth value. NULL means no platform auth change.
|
|
|
|
@retval EFI_SUCCESS Operation completed successfully.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
Tpm2CommandChangeEps (
|
|
IN TPM2B_AUTH *PlatformAuth OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
TPMS_AUTH_COMMAND *AuthSession;
|
|
TPMS_AUTH_COMMAND LocalAuthSession;
|
|
|
|
if (PlatformAuth == NULL) {
|
|
AuthSession = NULL;
|
|
} else {
|
|
AuthSession = &LocalAuthSession;
|
|
ZeroMem (&LocalAuthSession, sizeof (LocalAuthSession));
|
|
LocalAuthSession.sessionHandle = TPM_RS_PW;
|
|
LocalAuthSession.hmac.size = PlatformAuth->size;
|
|
CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size);
|
|
}
|
|
|
|
Status = Tpm2ChangeEPS (TPM_RH_PLATFORM, AuthSession);
|
|
DEBUG ((DEBUG_INFO, "Tpm2ChangeEPS - %r\n", Status));
|
|
|
|
ZeroMem (&LocalAuthSession.hmac, sizeof (LocalAuthSession.hmac));
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Execute physical presence operation requested by the OS.
|
|
|
|
@param[in] PlatformAuth platform auth value. NULL means no platform auth change.
|
|
@param[in] CommandCode Physical presence operation value.
|
|
@param[in] CommandParameter Physical presence operation parameter.
|
|
|
|
@retval TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE Unknown physical presence operation.
|
|
@retval TCG_PP_OPERATION_RESPONSE_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.
|
|
**/
|
|
STATIC
|
|
UINT32
|
|
Tcg2ExecutePhysicalPresence (
|
|
IN TPM2B_AUTH *PlatformAuth OPTIONAL,
|
|
IN UINT32 CommandCode,
|
|
IN UINT32 CommandParameter
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap;
|
|
UINT32 ActivePcrBanks;
|
|
|
|
switch (CommandCode) {
|
|
case TCG2_PHYSICAL_PRESENCE_CLEAR:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
|
|
Status = Tpm2CommandClear (PlatformAuth);
|
|
if (EFI_ERROR (Status)) {
|
|
return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
|
|
} else {
|
|
return TCG_PP_OPERATION_RESPONSE_SUCCESS;
|
|
}
|
|
|
|
case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
|
|
Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &ActivePcrBanks);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// PP spec requirements:
|
|
// Firmware should check that all requested (set) hashing algorithms are supported with respective PCR banks.
|
|
// Firmware has to ensure that at least one PCR banks is active.
|
|
// If not, an error is returned and no action is taken.
|
|
//
|
|
if ((CommandParameter == 0) || ((CommandParameter & (~TpmHashAlgorithmBitmap)) != 0)) {
|
|
DEBUG ((DEBUG_ERROR, "PCR banks %x to allocate are not supported by TPM. Skip operation\n", CommandParameter));
|
|
return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
|
|
}
|
|
|
|
Status = Tpm2PcrAllocateBanks (PlatformAuth, TpmHashAlgorithmBitmap, CommandParameter);
|
|
if (EFI_ERROR (Status)) {
|
|
return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
|
|
} else {
|
|
return TCG_PP_OPERATION_RESPONSE_SUCCESS;
|
|
}
|
|
|
|
case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
|
|
Status = Tpm2CommandChangeEps (PlatformAuth);
|
|
if (EFI_ERROR (Status)) {
|
|
return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
|
|
} else {
|
|
return TCG_PP_OPERATION_RESPONSE_SUCCESS;
|
|
}
|
|
|
|
case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS:
|
|
Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &ActivePcrBanks);
|
|
ASSERT_EFI_ERROR (Status);
|
|
Status = Tpm2PcrAllocateBanks (PlatformAuth, TpmHashAlgorithmBitmap, TpmHashAlgorithmBitmap);
|
|
if (EFI_ERROR (Status)) {
|
|
return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
|
|
} else {
|
|
return TCG_PP_OPERATION_RESPONSE_SUCCESS;
|
|
}
|
|
|
|
default:
|
|
if (CommandCode <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
|
|
return TCG_PP_OPERATION_RESPONSE_SUCCESS;
|
|
} else {
|
|
return TCG_PP_OPERATION_RESPONSE_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.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
Tcg2ReadUserKey (
|
|
IN BOOLEAN CautionKey
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_INPUT_KEY Key;
|
|
UINT16 InputKey;
|
|
|
|
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);
|
|
|
|
if (InputKey != SCAN_ESC) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Fill Buffer With BootHashAlg.
|
|
|
|
@param[in] Buffer Buffer to be filled.
|
|
@param[in] BufferSize Size of buffer.
|
|
@param[in] BootHashAlg BootHashAlg.
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
Tcg2FillBufferWithBootHashAlg (
|
|
IN UINT16 *Buffer,
|
|
IN UINTN BufferSize,
|
|
IN UINT32 BootHashAlg
|
|
)
|
|
{
|
|
Buffer[0] = 0;
|
|
if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {
|
|
if (Buffer[0] != 0) {
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA1", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
|
|
if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {
|
|
if (Buffer[0] != 0) {
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA256", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
|
|
if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {
|
|
if (Buffer[0] != 0) {
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA384", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
|
|
if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {
|
|
if (Buffer[0] != 0) {
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA512", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
|
|
if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {
|
|
if (Buffer[0] != 0) {
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
|
|
StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SM3_256", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Display the confirm text and get user confirmation.
|
|
|
|
@param[in] TpmPpCommand The requested TPM physical presence command.
|
|
@param[in] TpmPpCommandParameter The requested TPM physical presence command parameter.
|
|
|
|
@retval TRUE The user has confirmed the changes.
|
|
@retval FALSE The user doesn't confirm the changes.
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
Tcg2UserConfirm (
|
|
IN UINT32 TpmPpCommand,
|
|
IN UINT32 TpmPpCommandParameter
|
|
)
|
|
{
|
|
CHAR16 *ConfirmText;
|
|
CHAR16 *TmpStr1;
|
|
CHAR16 *TmpStr2;
|
|
UINTN BufSize;
|
|
BOOLEAN CautionKey;
|
|
BOOLEAN NoPpiInfo;
|
|
UINT16 Index;
|
|
CHAR16 DstStr[81];
|
|
CHAR16 TempBuffer[1024];
|
|
CHAR16 TempBuffer2[1024];
|
|
EFI_TCG2_PROTOCOL *Tcg2Protocol;
|
|
EFI_TCG2_BOOT_SERVICE_CAPABILITY ProtocolCapability;
|
|
UINT32 CurrentPCRBanks;
|
|
EFI_STATUS Status;
|
|
|
|
TmpStr2 = NULL;
|
|
CautionKey = FALSE;
|
|
NoPpiInfo = FALSE;
|
|
BufSize = CONFIRM_BUFFER_SIZE;
|
|
ConfirmText = AllocateZeroPool (BufSize);
|
|
ASSERT (ConfirmText != NULL);
|
|
|
|
mTcg2PpStringPackHandle = HiiAddPackages (&gEfiTcg2PhysicalPresenceGuid, gImageHandle, Tcg2PhysicalPresenceLibQemuStrings, NULL);
|
|
ASSERT (mTcg2PpStringPackHandle != NULL);
|
|
|
|
switch (TpmPpCommand) {
|
|
case TCG2_PHYSICAL_PRESENCE_CLEAR:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
|
|
CautionKey = TRUE;
|
|
TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
|
|
UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
|
|
FreePool (TmpStr1);
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
|
|
break;
|
|
|
|
case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
|
|
Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **)&Tcg2Protocol);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
ProtocolCapability.Size = sizeof (ProtocolCapability);
|
|
Status = Tcg2Protocol->GetCapability (
|
|
Tcg2Protocol,
|
|
&ProtocolCapability
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = Tcg2Protocol->GetActivePcrBanks (
|
|
Tcg2Protocol,
|
|
&CurrentPCRBanks
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
CautionKey = TRUE;
|
|
TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_SET_PCR_BANKS));
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
|
|
UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
|
|
FreePool (TmpStr1);
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_SET_PCR_BANKS_1));
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_SET_PCR_BANKS_2));
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
|
|
Tcg2FillBufferWithBootHashAlg (TempBuffer, sizeof (TempBuffer), TpmPpCommandParameter);
|
|
Tcg2FillBufferWithBootHashAlg (TempBuffer2, sizeof (TempBuffer2), CurrentPCRBanks);
|
|
|
|
TmpStr1 = AllocateZeroPool (BufSize);
|
|
ASSERT (TmpStr1 != NULL);
|
|
UnicodeSPrint (TmpStr1, BufSize, L"Current PCRBanks is 0x%x. (%s)\nNew PCRBanks is 0x%x. (%s)\n", CurrentPCRBanks, TempBuffer2, TpmPpCommandParameter, TempBuffer);
|
|
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
|
|
break;
|
|
|
|
case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
|
|
CautionKey = TRUE;
|
|
TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CHANGE_EPS));
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
|
|
UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
|
|
FreePool (TmpStr1);
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CHANGE_EPS_1));
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CHANGE_EPS_2));
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
|
|
break;
|
|
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID:
|
|
TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_ENABLE_BLOCK_SID));
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_HEAD_STR));
|
|
UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
|
|
FreePool (TmpStr1);
|
|
break;
|
|
|
|
case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID:
|
|
TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_DISABLE_BLOCK_SID));
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_HEAD_STR));
|
|
UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
|
|
FreePool (TmpStr1);
|
|
break;
|
|
|
|
default:
|
|
;
|
|
}
|
|
|
|
if (TmpStr2 == NULL) {
|
|
FreePool (ConfirmText);
|
|
return FALSE;
|
|
}
|
|
|
|
// Console for user interaction
|
|
// We need to connect all trusted consoles for TCG PP. Here we treat all consoles in OVMF to be trusted consoles.
|
|
EfiBootManagerConnectAllDefaultConsoles ();
|
|
|
|
if (TpmPpCommand < TCG2_PHYSICAL_PRESENCE_STORAGE_MANAGEMENT_BEGIN) {
|
|
if (CautionKey) {
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
|
|
} else {
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
|
|
}
|
|
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
|
|
if (NoPpiInfo) {
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO));
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
}
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_REJECT_KEY));
|
|
} else {
|
|
if (CautionKey) {
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_CAUTION_KEY));
|
|
} else {
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_ACCEPT_KEY));
|
|
}
|
|
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
|
|
if (NoPpiInfo) {
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_NO_PPI_INFO));
|
|
StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
|
|
FreePool (TmpStr1);
|
|
}
|
|
|
|
TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_REJECT_KEY));
|
|
}
|
|
|
|
BufSize -= StrSize (ConfirmText);
|
|
UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2);
|
|
|
|
DstStr[80] = L'\0';
|
|
for (Index = 0; Index < StrLen (ConfirmText); Index += 80) {
|
|
StrnCpyS (DstStr, sizeof (DstStr) / sizeof (CHAR16), ConfirmText + Index, sizeof (DstStr) / sizeof (CHAR16) - 1);
|
|
Print (DstStr);
|
|
}
|
|
|
|
FreePool (TmpStr1);
|
|
FreePool (TmpStr2);
|
|
FreePool (ConfirmText);
|
|
HiiRemovePackages (mTcg2PpStringPackHandle);
|
|
|
|
if (Tcg2ReadUserKey (CautionKey)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Check if there is a valid physical presence command request. Also updates parameter value
|
|
to whether the requested physical presence command already confirmed by user
|
|
|
|
@param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
|
|
True, it indicates the command doesn't require user confirm, or already confirmed
|
|
in last boot cycle by user.
|
|
False, it indicates the command need user confirm from UI.
|
|
|
|
@retval TRUE Physical Presence operation command is valid.
|
|
@retval FALSE Physical Presence operation command is invalid.
|
|
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
Tcg2HaveValidTpmRequest (
|
|
OUT BOOLEAN *RequestConfirmed
|
|
)
|
|
{
|
|
EFI_TCG2_PROTOCOL *Tcg2Protocol;
|
|
EFI_STATUS Status;
|
|
|
|
*RequestConfirmed = FALSE;
|
|
|
|
if (mPpi->Request <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
|
|
//
|
|
// Need TCG2 protocol.
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **)&Tcg2Protocol);
|
|
if (EFI_ERROR (Status)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
switch (mPpi->Request) {
|
|
case TCG2_PHYSICAL_PRESENCE_NO_ACTION:
|
|
case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS:
|
|
*RequestConfirmed = TRUE;
|
|
return TRUE;
|
|
|
|
case TCG2_PHYSICAL_PRESENCE_CLEAR:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
|
|
case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
|
|
case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID:
|
|
case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID:
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Wrong Physical Presence command
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Physical Presence command is correct
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
Check and execute the requested physical presence command.
|
|
|
|
@param[in] PlatformAuth platform auth value. NULL means no platform auth change.
|
|
**/
|
|
STATIC
|
|
VOID
|
|
Tcg2ExecutePendingTpmRequest (
|
|
IN TPM2B_AUTH *PlatformAuth OPTIONAL
|
|
)
|
|
{
|
|
BOOLEAN RequestConfirmed;
|
|
|
|
if (mPpi->Request == TCG2_PHYSICAL_PRESENCE_NO_ACTION) {
|
|
//
|
|
// No operation request
|
|
//
|
|
return;
|
|
}
|
|
|
|
if (!Tcg2HaveValidTpmRequest (&RequestConfirmed)) {
|
|
//
|
|
// Invalid operation request.
|
|
//
|
|
if (mPpi->Request <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
|
|
mPpi->Response = TCG_PP_OPERATION_RESPONSE_SUCCESS;
|
|
} else {
|
|
mPpi->Response = TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
|
|
}
|
|
|
|
mPpi->LastRequest = mPpi->Request;
|
|
mPpi->Request = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
|
|
mPpi->RequestParameter = 0;
|
|
return;
|
|
}
|
|
|
|
if (!RequestConfirmed) {
|
|
//
|
|
// Print confirm text and wait for approval.
|
|
//
|
|
RequestConfirmed = Tcg2UserConfirm (mPpi->Request, mPpi->RequestParameter);
|
|
}
|
|
|
|
//
|
|
// Execute requested physical presence command
|
|
//
|
|
mPpi->Response = TCG_PP_OPERATION_RESPONSE_USER_ABORT;
|
|
if (RequestConfirmed) {
|
|
mPpi->Response = Tcg2ExecutePhysicalPresence (
|
|
PlatformAuth,
|
|
mPpi->Request,
|
|
mPpi->RequestParameter
|
|
);
|
|
}
|
|
|
|
//
|
|
// Clear request
|
|
//
|
|
mPpi->LastRequest = mPpi->Request;
|
|
mPpi->Request = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
|
|
mPpi->RequestParameter = 0;
|
|
|
|
if (mPpi->Response == TCG_PP_OPERATION_RESPONSE_USER_ABORT) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Reset system to make new TPM settings in effect
|
|
//
|
|
switch (mPpi->LastRequest) {
|
|
case TCG2_PHYSICAL_PRESENCE_CLEAR:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
|
|
case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
|
|
case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
|
|
case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS:
|
|
break;
|
|
|
|
case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID:
|
|
case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID:
|
|
break;
|
|
|
|
default:
|
|
if (mPpi->Request != TCG2_PHYSICAL_PRESENCE_NO_ACTION) {
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
Print (L"Rebooting system to make TPM2 settings in effect\n");
|
|
gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
/**
|
|
Check and execute the pending TPM request.
|
|
|
|
The TPM request may come from OS or BIOS. This API will display request information and wait
|
|
for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
|
|
the TPM request is confirmed, and one or more reset may be required to make TPM request to
|
|
take effect.
|
|
|
|
This API should be invoked after console in and console out are all ready as they are required
|
|
to display request information and get user input to confirm the request.
|
|
|
|
@param[in] PlatformAuth platform auth value. NULL means no platform auth change.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
Tcg2PhysicalPresenceLibProcessRequest (
|
|
IN TPM2B_AUTH *PlatformAuth OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = QemuTpmInitPPI ();
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "[TPM2PP] no PPI\n"));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check S4 resume
|
|
//
|
|
if (GetBootModeHob () == BOOT_ON_S4_RESUME) {
|
|
DEBUG ((DEBUG_INFO, "S4 Resume, Skip TPM PP process!\n"));
|
|
return;
|
|
}
|
|
|
|
DEBUG ((DEBUG_INFO, "[TPM2PP] PPRequest=%x (PPRequestParameter=%x)\n", mPpi->Request, mPpi->RequestParameter));
|
|
Tcg2ExecutePendingTpmRequest (PlatformAuth);
|
|
}
|
|
|
|
/**
|
|
The handler for TPM physical presence function:
|
|
Return TPM Operation Response to OS Environment.
|
|
|
|
@param[out] MostRecentRequest Most recent operation request.
|
|
@param[out] Response Response to the most recent operation request.
|
|
|
|
@return Return Code for Return TPM Operation Response to OS Environment.
|
|
**/
|
|
UINT32
|
|
EFIAPI
|
|
Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
|
|
OUT UINT32 *MostRecentRequest,
|
|
OUT UINT32 *Response
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_INFO, "[TPM2PP] ReturnOperationResponseToOsFunction\n"));
|
|
|
|
Status = QemuTpmInitPPI ();
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "[TPM2PP] no PPI\n"));
|
|
*MostRecentRequest = 0;
|
|
*Response = 0;
|
|
return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE;
|
|
}
|
|
|
|
*MostRecentRequest = mPpi->LastRequest;
|
|
*Response = mPpi->Response;
|
|
|
|
return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
The handler for TPM physical presence function:
|
|
Submit TPM Operation Request to Pre-OS Environment and
|
|
Submit TPM Operation Request to Pre-OS Environment 2.
|
|
|
|
Caution: This function may receive untrusted input.
|
|
|
|
@param[in] OperationRequest TPM physical presence operation request.
|
|
@param[in] RequestParameter TPM physical presence operation request parameter.
|
|
|
|
@return Return Code for Submit TPM Operation Request to Pre-OS Environment and
|
|
Submit TPM Operation Request to Pre-OS Environment 2.
|
|
**/
|
|
UINT32
|
|
EFIAPI
|
|
Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (
|
|
IN UINT32 OperationRequest,
|
|
IN UINT32 RequestParameter
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
DEBUG ((DEBUG_INFO, "[TPM2PP] SubmitRequestToPreOSFunction, Request = %x, %x\n", OperationRequest, RequestParameter));
|
|
|
|
Status = QemuTpmInitPPI ();
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((DEBUG_INFO, "[TPM2PP] no PPI\n"));
|
|
return TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
|
|
}
|
|
|
|
mPpi->Request = OperationRequest;
|
|
mPpi->RequestParameter = RequestParameter;
|
|
|
|
return TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
|
|
}
|