/** @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.
Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}