diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SecurityPkg/Library')
161 files changed, 32680 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthService.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthService.c new file mode 100644 index 00000000..b035a343 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthService.c @@ -0,0 +1,2318 @@ +/** @file + Implement authentication services for the authenticated variables. + + Caution: This module requires additional review when modified. + This driver will have external input - variable data. It may be input in SMM mode. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + Variable attribute should also be checked to avoid authentication bypass. + The whole SMM authentication variable design relies on the integrity of flash part and SMM. + which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory + may not be modified without authorization. If platform fails to protect these resources, + the authentication service provided in this driver will be broken, and the behavior is undefined. + + ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do + variable authentication. + + VerifyTimeBasedPayloadAndUpdate() and VerifyCounterBasedPayload() are sub function to do verification. + They will do basic validation for authentication data structure, then call crypto library + to verify the signature. + +Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR> +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "AuthServiceInternal.h" + +#include <Protocol/VariablePolicy.h> +#include <Library/VariablePolicyLib.h> + +// +// Public Exponent of RSA Key. +// +CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 }; + +CONST UINT8 mSha256OidValue[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 }; + +// +// Requirement for different signature type which have been defined in UEFI spec. +// These data are used to perform SignatureList format check while setting PK/KEK variable. +// +EFI_SIGNATURE_ITEM mSupportSigItem[] = { +//{SigType, SigHeaderSize, SigDataSize } + {EFI_CERT_SHA256_GUID, 0, 32 }, + {EFI_CERT_RSA2048_GUID, 0, 256 }, + {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 }, + {EFI_CERT_SHA1_GUID, 0, 20 }, + {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 }, + {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)}, + {EFI_CERT_SHA224_GUID, 0, 28 }, + {EFI_CERT_SHA384_GUID, 0, 48 }, + {EFI_CERT_SHA512_GUID, 0, 64 }, + {EFI_CERT_X509_SHA256_GUID, 0, 48 }, + {EFI_CERT_X509_SHA384_GUID, 0, 64 }, + {EFI_CERT_X509_SHA512_GUID, 0, 80 } +}; + +/** + 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. + + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Variable vendor GUID to be found. + @param[out] Data Pointer to data address. + @param[out] DataSize Pointer to data size. + + @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 +AuthServiceInternalFindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VOID **Data, + OUT UINTN *DataSize + ) +{ + EFI_STATUS Status; + AUTH_VARIABLE_INFO AuthVariableInfo; + + ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo)); + Status = mAuthVarLibContextIn->FindVariable ( + VariableName, + VendorGuid, + &AuthVariableInfo + ); + *Data = AuthVariableInfo.Data; + *DataSize = AuthVariableInfo.DataSize; + return Status; +} + +/** + Update the variable region with Variable information. + + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data. + @param[in] Attributes Attribute value of the variable. + + @retval EFI_SUCCESS The update operation is success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_WRITE_PROTECTED Variable is write-protected. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +AuthServiceInternalUpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes + ) +{ + AUTH_VARIABLE_INFO AuthVariableInfo; + + ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo)); + AuthVariableInfo.VariableName = VariableName; + AuthVariableInfo.VendorGuid = VendorGuid; + AuthVariableInfo.Data = Data; + AuthVariableInfo.DataSize = DataSize; + AuthVariableInfo.Attributes = Attributes; + + return mAuthVarLibContextIn->UpdateVariable ( + &AuthVariableInfo + ); +} + +/** + Update the variable region with Variable information. + + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data. + @param[in] Attributes Attribute value of the variable. + @param[in] TimeStamp Value of associated TimeStamp. + + @retval EFI_SUCCESS The update operation is success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_WRITE_PROTECTED Variable is write-protected. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +AuthServiceInternalUpdateVariableWithTimeStamp ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes, + IN EFI_TIME *TimeStamp + ) +{ + EFI_STATUS FindStatus; + VOID *OrgData; + UINTN OrgDataSize; + AUTH_VARIABLE_INFO AuthVariableInfo; + + FindStatus = AuthServiceInternalFindVariable ( + VariableName, + VendorGuid, + &OrgData, + &OrgDataSize + ); + + // + // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable + // + if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) { + if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && + ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) || + (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) || + (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) { + // + // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of + // EFI_SIGNATURE_DATA values that are already part of the existing variable value. + // + FilterSignatureList ( + OrgData, + OrgDataSize, + Data, + &DataSize + ); + } + } + + ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo)); + AuthVariableInfo.VariableName = VariableName; + AuthVariableInfo.VendorGuid = VendorGuid; + AuthVariableInfo.Data = Data; + AuthVariableInfo.DataSize = DataSize; + AuthVariableInfo.Attributes = Attributes; + AuthVariableInfo.TimeStamp = TimeStamp; + return mAuthVarLibContextIn->UpdateVariable ( + &AuthVariableInfo + ); +} + +/** + Determine whether this operation needs a physical present user. + + @param[in] VariableName Name of the Variable. + @param[in] VendorGuid GUID of the Variable. + + @retval TRUE This variable is protected, only a physical present user could set this variable. + @retval FALSE This variable is not protected. + +**/ +BOOLEAN +NeedPhysicallyPresent( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ) +{ + // If the VariablePolicy engine is disabled, allow deletion of any authenticated variables. + if (IsVariablePolicyEnabled()) { + if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0)) + || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) { + return TRUE; + } + } + + return FALSE; +} + +/** + Determine whether the platform is operating in Custom Secure Boot mode. + + @retval TRUE The platform is operating in Custom mode. + @retval FALSE The platform is operating in Standard mode. + +**/ +BOOLEAN +InCustomMode ( + VOID + ) +{ + EFI_STATUS Status; + VOID *Data; + UINTN DataSize; + + Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize); + if (!EFI_ERROR (Status) && (*(UINT8 *) Data == CUSTOM_SECURE_BOOT_MODE)) { + return TRUE; + } + + return FALSE; +} + +/** + 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; + VOID *Data; + UINTN DataSize; + UINT8 SecureBootMode; + UINT8 SecureBootEnable; + UINTN VariableDataSize; + + Status = AuthServiceInternalFindVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &Data, + &DataSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Update the value of SetupMode variable by a simple mem copy, this could avoid possible + // variable storage reclaim at runtime. + // + mPlatformMode = (UINT8) Mode; + CopyMem (Data, &mPlatformMode, sizeof(UINT8)); + + if (mAuthVarLibContextIn->AtRuntime ()) { + // + // SecureBoot Variable indicates whether the platform firmware is operating + // in Secure boot mode (1) or not (0), so we should not change SecureBoot + // Variable in runtime. + // + 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 = AuthServiceInternalFindVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &Data, + &DataSize + ); + // + // 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 (EFI_ERROR (Status)) { + 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; + } + } + + Status = AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &SecureBootMode, + sizeof(UINT8), + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature. + // + Status = AuthServiceInternalFindVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &Data, + &DataSize + ); + + if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) { + // + // Create the "SecureBootEnable" variable as secure boot is enabled. + // + SecureBootEnable = SECURE_BOOT_ENABLE; + VariableDataSize = sizeof (SecureBootEnable); + } else { + // + // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot" + // variable is not in secure boot state. + // + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + SecureBootEnable = SECURE_BOOT_DISABLE; + VariableDataSize = 0; + } + + Status = AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &SecureBootEnable, + VariableDataSize, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + return Status; +} + +/** + Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable. + + @param[in] VariableName Name of Variable to be check. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Point to the variable data to be checked. + @param[in] DataSize Size of Data. + + @return EFI_INVALID_PARAMETER Invalid signature list format. + @return EFI_SUCCESS Passed signature list format check successfully. + +**/ +EFI_STATUS +CheckSignatureListFormat( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize + ) +{ + EFI_SIGNATURE_LIST *SigList; + UINTN SigDataSize; + UINT32 Index; + UINT32 SigCount; + BOOLEAN IsPk; + VOID *RsaContext; + EFI_SIGNATURE_DATA *CertData; + UINTN CertLen; + + if (DataSize == 0) { + return EFI_SUCCESS; + } + + ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL); + + if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){ + IsPk = TRUE; + } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) || + (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && + ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) || + (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)))) { + IsPk = FALSE; + } else { + return EFI_SUCCESS; + } + + SigCount = 0; + SigList = (EFI_SIGNATURE_LIST *) Data; + SigDataSize = DataSize; + RsaContext = NULL; + + // + // Walk through the input signature list and check the data format. + // If any signature is incorrectly formed, the whole check will fail. + // + while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) { + for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) { + if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) { + // + // The value of SignatureSize should always be 16 (size of SignatureOwner + // component) add the data length according to signature type. + // + if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) && + (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) { + return EFI_INVALID_PARAMETER; + } + if (mSupportSigItem[Index].SigHeaderSize != ((UINT32) ~0) && + SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) { + return EFI_INVALID_PARAMETER; + } + break; + } + } + + if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) { + // + // Undefined signature type. + // + return EFI_INVALID_PARAMETER; + } + + if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) { + // + // Try to retrieve the RSA public key from the X.509 certificate. + // If this operation fails, it's not a valid certificate. + // + RsaContext = RsaNew (); + if (RsaContext == NULL) { + return EFI_INVALID_PARAMETER; + } + CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize); + CertLen = SigList->SignatureSize - sizeof (EFI_GUID); + if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) { + RsaFree (RsaContext); + return EFI_INVALID_PARAMETER; + } + RsaFree (RsaContext); + } + + if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) { + return EFI_INVALID_PARAMETER; + } + SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize; + + SigDataSize -= SigList->SignatureListSize; + SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize); + } + + if (((UINTN) SigList - (UINTN) Data) != DataSize) { + return EFI_INVALID_PARAMETER; + } + + if (IsPk && SigCount > 1) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + Update "VendorKeys" variable to record the out of band secure boot key modification. + + @return EFI_SUCCESS Variable is updated successfully. + @return Others Failed to update variable. + +**/ +EFI_STATUS +VendorKeyIsModified ( + VOID + ) +{ + EFI_STATUS Status; + + if (mVendorKeyState == VENDOR_KEYS_MODIFIED) { + return EFI_SUCCESS; + } + mVendorKeyState = VENDOR_KEYS_MODIFIED; + + Status = AuthServiceInternalUpdateVariable ( + EFI_VENDOR_KEYS_NV_VARIABLE_NAME, + &gEfiVendorKeysNvGuid, + &mVendorKeyState, + sizeof (UINT8), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return AuthServiceInternalUpdateVariable ( + EFI_VENDOR_KEYS_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + &mVendorKeyState, + sizeof (UINT8), + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); +} + +/** + Process variable with platform key for verification. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. + + @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] 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 UINT32 Attributes OPTIONAL, + IN BOOLEAN IsPk + ) +{ + EFI_STATUS Status; + BOOLEAN Del; + UINT8 *Payload; + UINTN PayloadSize; + + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 || + (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) { + // + // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based + // authenticated variable. + // + return EFI_INVALID_PARAMETER; + } + + // + // Init state of Del. State may change due to secure check + // + Del = FALSE; + if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) { + Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data); + PayloadSize = DataSize - AUTHINFO2_SIZE (Data); + if (PayloadSize == 0) { + Del = TRUE; + } + + Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AuthServiceInternalUpdateVariableWithTimeStamp ( + VariableName, + VendorGuid, + Payload, + PayloadSize, + Attributes, + &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp + ); + if (EFI_ERROR(Status)) { + return Status; + } + + if ((mPlatformMode != SETUP_MODE) || IsPk) { + Status = VendorKeyIsModified (); + } + } else if (mPlatformMode == USER_MODE) { + // + // Verify against X509 Cert in PK database. + // + Status = VerifyTimeBasedPayloadAndUpdate ( + VariableName, + VendorGuid, + Data, + DataSize, + Attributes, + AuthVarTypePk, + &Del + ); + } else { + // + // Verify against the certificate in data payload. + // + Status = VerifyTimeBasedPayloadAndUpdate ( + VariableName, + VendorGuid, + Data, + DataSize, + Attributes, + AuthVarTypePayload, + &Del + ); + } + + if (!EFI_ERROR(Status) && IsPk) { + if (mPlatformMode == SETUP_MODE && !Del) { + // + // If enroll PK in setup mode, need change to user mode. + // + Status = UpdatePlatformMode (USER_MODE); + } else if (mPlatformMode == USER_MODE && Del){ + // + // If delete PK in user mode, need change to setup mode. + // + Status = UpdatePlatformMode (SETUP_MODE); + } + } + + return Status; +} + +/** + Process variable with key exchange key for verification. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. + + @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] 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 UINT32 Attributes OPTIONAL + ) +{ + EFI_STATUS Status; + UINT8 *Payload; + UINTN PayloadSize; + + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 || + (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) { + // + // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based + // authenticated variable. + // + return EFI_INVALID_PARAMETER; + } + + Status = EFI_SUCCESS; + if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) { + // + // Time-based, verify against X509 Cert KEK. + // + return VerifyTimeBasedPayloadAndUpdate ( + VariableName, + VendorGuid, + Data, + DataSize, + Attributes, + AuthVarTypeKek, + NULL + ); + } else { + // + // If in setup mode or custom secure boot mode, no authentication needed. + // + Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data); + PayloadSize = DataSize - AUTHINFO2_SIZE (Data); + + Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AuthServiceInternalUpdateVariableWithTimeStamp ( + VariableName, + VendorGuid, + Payload, + PayloadSize, + Attributes, + &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (mPlatformMode != SETUP_MODE) { + Status = VendorKeyIsModified (); + } + } + + return Status; +} + +/** + Check if it is to delete auth variable. + + @param[in] OrgAttributes Original attribute value of the variable. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data. + @param[in] Attributes Attribute value of the variable. + + @retval TRUE It is to delete auth variable. + @retval FALSE It is not to delete auth variable. + +**/ +BOOLEAN +IsDeleteAuthVariable ( + IN UINT32 OrgAttributes, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes + ) +{ + BOOLEAN Del; + UINTN PayloadSize; + + Del = FALSE; + + // + // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute, + // SetVariable must be used with attributes matching the existing variable + // and the DataSize set to the size of the AuthInfo descriptor. + // + if ((Attributes == OrgAttributes) && + ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) { + if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + PayloadSize = DataSize - AUTHINFO2_SIZE (Data); + if (PayloadSize == 0) { + Del = TRUE; + } + } else { + PayloadSize = DataSize - AUTHINFO_SIZE; + if (PayloadSize == 0) { + Del = TRUE; + } + } + } + + return Del; +} + +/** + Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. + + @param[in] VariableName Name of the variable. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data. + @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 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set. + @return EFI_OUT_OF_RESOURCES The Database to save the public key is full. + @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_TIME_BASED_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 UINT32 Attributes + ) +{ + EFI_STATUS Status; + AUTH_VARIABLE_INFO OrgVariableInfo; + + Status = EFI_SUCCESS; + + ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo)); + Status = mAuthVarLibContextIn->FindVariable ( + VariableName, + VendorGuid, + &OrgVariableInfo + ); + + // If the VariablePolicy engine is disabled, allow deletion of any authenticated variables. + if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && (UserPhysicalPresent() || !IsVariablePolicyEnabled())) { + // + // Allow the delete operation of common authenticated variable(AT or AW) at user physical presence. + // + Status = AuthServiceInternalUpdateVariable ( + VariableName, + VendorGuid, + NULL, + 0, + 0 + ); + if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) { + Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes); + } + + return Status; + } + + if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent()) { + // + // This variable is protected, only physical present user could modify its value. + // + return EFI_SECURITY_VIOLATION; + } + + // + if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // Reject Counter Based Auth Variable processing request. + // + return EFI_UNSUPPORTED; + } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + // + // Process Time-based Authenticated variable. + // + return VerifyTimeBasedPayloadAndUpdate ( + VariableName, + VendorGuid, + Data, + DataSize, + Attributes, + AuthVarTypePriv, + NULL + ); + } + + if ((OrgVariableInfo.Data != NULL) && + ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) { + // + // If the variable is already write-protected, it always needs authentication before update. + // + return EFI_WRITE_PROTECTED; + } + + // + // Not authenticated variable, just update variable as usual. + // + Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes); + return Status; + +} + +/** + Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data. + + @param[in] Data Pointer to original EFI_SIGNATURE_LIST. + @param[in] DataSize Size of Data buffer. + @param[in, out] NewData Pointer to new EFI_SIGNATURE_LIST. + @param[in, out] NewDataSize Size of NewData buffer. + +**/ +EFI_STATUS +FilterSignatureList ( + IN VOID *Data, + IN UINTN DataSize, + IN OUT VOID *NewData, + IN OUT UINTN *NewDataSize + ) +{ + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *Cert; + UINTN CertCount; + EFI_SIGNATURE_LIST *NewCertList; + EFI_SIGNATURE_DATA *NewCert; + UINTN NewCertCount; + UINTN Index; + UINTN Index2; + UINTN Size; + UINT8 *Tail; + UINTN CopiedCount; + UINTN SignatureListSize; + BOOLEAN IsNewCert; + UINT8 *TempData; + UINTN TempDataSize; + EFI_STATUS Status; + + if (*NewDataSize == 0) { + return EFI_SUCCESS; + } + + TempDataSize = *NewDataSize; + Status = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **) &TempData); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Tail = TempData; + + NewCertList = (EFI_SIGNATURE_LIST *) NewData; + while ((*NewDataSize > 0) && (*NewDataSize >= NewCertList->SignatureListSize)) { + NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize); + NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize; + + CopiedCount = 0; + for (Index = 0; Index < NewCertCount; Index++) { + IsNewCert = TRUE; + + Size = DataSize; + CertList = (EFI_SIGNATURE_LIST *) Data; + while ((Size > 0) && (Size >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) && + (CertList->SignatureSize == NewCertList->SignatureSize)) { + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; + for (Index2 = 0; Index2 < CertCount; Index2++) { + // + // Iterate each Signature Data in this Signature List. + // + if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) { + IsNewCert = FALSE; + break; + } + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); + } + } + + if (!IsNewCert) { + break; + } + Size -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + + if (IsNewCert) { + // + // New EFI_SIGNATURE_DATA, keep it. + // + if (CopiedCount == 0) { + // + // Copy EFI_SIGNATURE_LIST header for only once. + // + CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize); + Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize; + } + + CopyMem (Tail, NewCert, NewCertList->SignatureSize); + Tail += NewCertList->SignatureSize; + CopiedCount++; + } + + NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize); + } + + // + // Update SignatureListSize in the kept EFI_SIGNATURE_LIST. + // + if (CopiedCount != 0) { + SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize); + CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize); + CertList->SignatureListSize = (UINT32) SignatureListSize; + } + + *NewDataSize -= NewCertList->SignatureListSize; + NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize); + } + + TempDataSize = (Tail - (UINT8 *) TempData); + + CopyMem (NewData, TempData, TempDataSize); + *NewDataSize = TempDataSize; + + return EFI_SUCCESS; +} + +/** + 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 +AuthServiceInternalCompareTimeStamp ( + 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 < SecondTime->Minute); + } + + return (BOOLEAN) (FirstTime->Second <= SecondTime->Second); +} + +/** + Calculate SHA256 digest of SignerCert CommonName + ToplevelCert tbsCertificate + SignerCert and ToplevelCert are inside the signer certificate chain. + + @param[in] SignerCert A pointer to SignerCert data. + @param[in] SignerCertSize Length of SignerCert data. + @param[in] TopLevelCert A pointer to TopLevelCert data. + @param[in] TopLevelCertSize Length of TopLevelCert data. + @param[out] Sha256Digest Sha256 digest calculated. + + @return EFI_ABORTED Digest process failed. + @return EFI_SUCCESS SHA256 Digest is successfully calculated. + +**/ +EFI_STATUS +CalculatePrivAuthVarSignChainSHA256Digest( + IN UINT8 *SignerCert, + IN UINTN SignerCertSize, + IN UINT8 *TopLevelCert, + IN UINTN TopLevelCertSize, + OUT UINT8 *Sha256Digest + ) +{ + UINT8 *TbsCert; + UINTN TbsCertSize; + CHAR8 CertCommonName[128]; + UINTN CertCommonNameSize; + BOOLEAN CryptoStatus; + EFI_STATUS Status; + + CertCommonNameSize = sizeof(CertCommonName); + + // + // Get SignerCert CommonName + // + Status = X509GetCommonName(SignerCert, SignerCertSize, CertCommonName, &CertCommonNameSize); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_INFO, "%a Get SignerCert CommonName failed with status %x\n", __FUNCTION__, Status)); + return EFI_ABORTED; + } + + // + // Get TopLevelCert tbsCertificate + // + if (!X509GetTBSCert(TopLevelCert, TopLevelCertSize, &TbsCert, &TbsCertSize)) { + DEBUG((DEBUG_INFO, "%a Get Top-level Cert tbsCertificate failed!\n", __FUNCTION__)); + return EFI_ABORTED; + } + + // + // Digest SignerCert CN + TopLevelCert tbsCertificate + // + ZeroMem (Sha256Digest, SHA256_DIGEST_SIZE); + CryptoStatus = Sha256Init (mHashCtx); + if (!CryptoStatus) { + return EFI_ABORTED; + } + + // + // '\0' is forced in CertCommonName. No overflow issue + // + CryptoStatus = Sha256Update ( + mHashCtx, + CertCommonName, + AsciiStrLen (CertCommonName) + ); + if (!CryptoStatus) { + return EFI_ABORTED; + } + + CryptoStatus = Sha256Update (mHashCtx, TbsCert, TbsCertSize); + if (!CryptoStatus) { + return EFI_ABORTED; + } + + CryptoStatus = Sha256Final (mHashCtx, Sha256Digest); + if (!CryptoStatus) { + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +/** + Find matching signer's certificates for common authenticated variable + by corresponding VariableName and VendorGuid from "certdb" or "certdbv". + + The data format of "certdb" or "certdbv": + // + // UINT32 CertDbListSize; + // /// AUTH_CERT_DB_DATA Certs1[]; + // /// AUTH_CERT_DB_DATA Certs2[]; + // /// ... + // /// AUTH_CERT_DB_DATA Certsn[]; + // + + @param[in] VariableName Name of authenticated Variable. + @param[in] VendorGuid Vendor GUID of authenticated Variable. + @param[in] Data Pointer to variable "certdb" or "certdbv". + @param[in] DataSize Size of variable "certdb" or "certdbv". + @param[out] CertOffset Offset of matching CertData, from starting of Data. + @param[out] CertDataSize Length of CertData in bytes. + @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from + starting of Data. + @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes. + + @retval EFI_INVALID_PARAMETER Any input parameter is invalid. + @retval EFI_NOT_FOUND Fail to find matching certs. + @retval EFI_SUCCESS Find matching certs and output parameters. + +**/ +EFI_STATUS +FindCertsFromDb ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT8 *Data, + IN UINTN DataSize, + OUT UINT32 *CertOffset, OPTIONAL + OUT UINT32 *CertDataSize, OPTIONAL + OUT UINT32 *CertNodeOffset,OPTIONAL + OUT UINT32 *CertNodeSize OPTIONAL + ) +{ + UINT32 Offset; + AUTH_CERT_DB_DATA *Ptr; + UINT32 CertSize; + UINT32 NameSize; + UINT32 NodeSize; + UINT32 CertDbListSize; + + if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check whether DataSize matches recorded CertDbListSize. + // + if (DataSize < sizeof (UINT32)) { + return EFI_INVALID_PARAMETER; + } + + CertDbListSize = ReadUnaligned32 ((UINT32 *) Data); + + if (CertDbListSize != (UINT32) DataSize) { + return EFI_INVALID_PARAMETER; + } + + Offset = sizeof (UINT32); + + // + // Get corresponding certificates by VendorGuid and VariableName. + // + while (Offset < (UINT32) DataSize) { + Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset); + // + // Check whether VendorGuid matches. + // + if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) { + NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize); + NameSize = ReadUnaligned32 (&Ptr->NameSize); + CertSize = ReadUnaligned32 (&Ptr->CertDataSize); + + if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize + + sizeof (CHAR16) * NameSize) { + return EFI_INVALID_PARAMETER; + } + + Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3; + // + // Check whether VariableName matches. + // + if ((NameSize == StrLen (VariableName)) && + (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) { + Offset = Offset + NameSize * sizeof (CHAR16); + + if (CertOffset != NULL) { + *CertOffset = Offset; + } + + if (CertDataSize != NULL) { + *CertDataSize = CertSize; + } + + if (CertNodeOffset != NULL) { + *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data); + } + + if (CertNodeSize != NULL) { + *CertNodeSize = NodeSize; + } + + return EFI_SUCCESS; + } else { + Offset = Offset + NameSize * sizeof (CHAR16) + CertSize; + } + } else { + NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize); + Offset = Offset + NodeSize; + } + } + + return EFI_NOT_FOUND; +} + +/** + Retrieve signer's certificates for common authenticated variable + by corresponding VariableName and VendorGuid from "certdb" + or "certdbv" according to authenticated variable attributes. + + @param[in] VariableName Name of authenticated Variable. + @param[in] VendorGuid Vendor GUID of authenticated Variable. + @param[in] Attributes Attributes of authenticated variable. + @param[out] CertData Pointer to signer's certificates. + @param[out] CertDataSize Length of CertData in bytes. + + @retval EFI_INVALID_PARAMETER Any input parameter is invalid. + @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs. + @retval EFI_SUCCESS Get signer's certificates successfully. + +**/ +EFI_STATUS +GetCertsFromDb ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + OUT UINT8 **CertData, + OUT UINT32 *CertDataSize + ) +{ + EFI_STATUS Status; + UINT8 *Data; + UINTN DataSize; + UINT32 CertOffset; + CHAR16 *DbName; + + if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + // + // Get variable "certdb". + // + DbName = EFI_CERT_DB_NAME; + } else { + // + // Get variable "certdbv". + // + DbName = EFI_CERT_DB_VOLATILE_NAME; + } + + // + // Get variable "certdb" or "certdbv". + // + Status = AuthServiceInternalFindVariable ( + DbName, + &gEfiCertDbGuid, + (VOID **) &Data, + &DataSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((DataSize == 0) || (Data == NULL)) { + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + + Status = FindCertsFromDb ( + VariableName, + VendorGuid, + Data, + DataSize, + &CertOffset, + CertDataSize, + NULL, + NULL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + *CertData = Data + CertOffset; + return EFI_SUCCESS; +} + +/** + Delete matching signer's certificates when deleting common authenticated + variable by corresponding VariableName and VendorGuid from "certdb" or + "certdbv" according to authenticated variable attributes. + + @param[in] VariableName Name of authenticated Variable. + @param[in] VendorGuid Vendor GUID of authenticated Variable. + @param[in] Attributes Attributes of authenticated variable. + + @retval EFI_INVALID_PARAMETER Any input parameter is invalid. + @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs. + @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +DeleteCertsFromDb ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes + ) +{ + EFI_STATUS Status; + UINT8 *Data; + UINTN DataSize; + UINT32 VarAttr; + UINT32 CertNodeOffset; + UINT32 CertNodeSize; + UINT8 *NewCertDb; + UINT32 NewCertDbSize; + CHAR16 *DbName; + + if ((VariableName == NULL) || (VendorGuid == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + // + // Get variable "certdb". + // + DbName = EFI_CERT_DB_NAME; + VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + } else { + // + // Get variable "certdbv". + // + DbName = EFI_CERT_DB_VOLATILE_NAME; + VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + } + + Status = AuthServiceInternalFindVariable ( + DbName, + &gEfiCertDbGuid, + (VOID **) &Data, + &DataSize + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if ((DataSize == 0) || (Data == NULL)) { + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + + if (DataSize == sizeof (UINT32)) { + // + // There is no certs in "certdb" or "certdbv". + // + return EFI_SUCCESS; + } + + // + // Get corresponding cert node from "certdb" or "certdbv". + // + Status = FindCertsFromDb ( + VariableName, + VendorGuid, + Data, + DataSize, + NULL, + NULL, + &CertNodeOffset, + &CertNodeSize + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (DataSize < (CertNodeOffset + CertNodeSize)) { + return EFI_NOT_FOUND; + } + + // + // Construct new data content of variable "certdb" or "certdbv". + // + NewCertDbSize = (UINT32) DataSize - CertNodeSize; + NewCertDb = (UINT8*) mCertDbStore; + + // + // Copy the DB entries before deleting node. + // + CopyMem (NewCertDb, Data, CertNodeOffset); + // + // Update CertDbListSize. + // + CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32)); + // + // Copy the DB entries after deleting node. + // + if (DataSize > (CertNodeOffset + CertNodeSize)) { + CopyMem ( + NewCertDb + CertNodeOffset, + Data + CertNodeOffset + CertNodeSize, + DataSize - CertNodeOffset - CertNodeSize + ); + } + + // + // Set "certdb" or "certdbv". + // + Status = AuthServiceInternalUpdateVariable ( + DbName, + &gEfiCertDbGuid, + NewCertDb, + NewCertDbSize, + VarAttr + ); + + return Status; +} + +/** + Insert signer's certificates for common authenticated variable with VariableName + and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to + time based authenticated variable attributes. CertData is the SHA256 digest of + SignerCert CommonName + TopLevelCert tbsCertificate. + + @param[in] VariableName Name of authenticated Variable. + @param[in] VendorGuid Vendor GUID of authenticated Variable. + @param[in] Attributes Attributes of authenticated variable. + @param[in] SignerCert Signer certificate data. + @param[in] SignerCertSize Length of signer certificate. + @param[in] TopLevelCert Top-level certificate data. + @param[in] TopLevelCertSize Length of top-level certificate. + + @retval EFI_INVALID_PARAMETER Any input parameter is invalid. + @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName + and VendorGuid already exists. + @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources. + @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv" + +**/ +EFI_STATUS +InsertCertsToDb ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINT8 *SignerCert, + IN UINTN SignerCertSize, + IN UINT8 *TopLevelCert, + IN UINTN TopLevelCertSize + ) +{ + EFI_STATUS Status; + UINT8 *Data; + UINTN DataSize; + UINT32 VarAttr; + UINT8 *NewCertDb; + UINT32 NewCertDbSize; + UINT32 CertNodeSize; + UINT32 NameSize; + UINT32 CertDataSize; + AUTH_CERT_DB_DATA *Ptr; + CHAR16 *DbName; + UINT8 Sha256Digest[SHA256_DIGEST_SIZE]; + + if ((VariableName == NULL) || (VendorGuid == NULL) || (SignerCert == NULL) ||(TopLevelCert == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) { + // + // Get variable "certdb". + // + DbName = EFI_CERT_DB_NAME; + VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + } else { + // + // Get variable "certdbv". + // + DbName = EFI_CERT_DB_VOLATILE_NAME; + VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + } + + // + // Get variable "certdb" or "certdbv". + // + Status = AuthServiceInternalFindVariable ( + DbName, + &gEfiCertDbGuid, + (VOID **) &Data, + &DataSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((DataSize == 0) || (Data == NULL)) { + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + + // + // Find whether matching cert node already exists in "certdb" or "certdbv". + // If yes return error. + // + Status = FindCertsFromDb ( + VariableName, + VendorGuid, + Data, + DataSize, + NULL, + NULL, + NULL, + NULL + ); + + if (!EFI_ERROR (Status)) { + ASSERT (FALSE); + return EFI_ACCESS_DENIED; + } + + // + // Construct new data content of variable "certdb" or "certdbv". + // + NameSize = (UINT32) StrLen (VariableName); + CertDataSize = sizeof(Sha256Digest); + CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16); + NewCertDbSize = (UINT32) DataSize + CertNodeSize; + if (NewCertDbSize > mMaxCertDbSize) { + return EFI_OUT_OF_RESOURCES; + } + + Status = CalculatePrivAuthVarSignChainSHA256Digest( + SignerCert, + SignerCertSize, + TopLevelCert, + TopLevelCertSize, + Sha256Digest + ); + if (EFI_ERROR (Status)) { + return Status; + } + + NewCertDb = (UINT8*) mCertDbStore; + + // + // Copy the DB entries before inserting node. + // + CopyMem (NewCertDb, Data, DataSize); + // + // Update CertDbListSize. + // + CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32)); + // + // Construct new cert node. + // + Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize); + CopyGuid (&Ptr->VendorGuid, VendorGuid); + CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32)); + CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32)); + CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32)); + + CopyMem ( + (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA), + VariableName, + NameSize * sizeof (CHAR16) + ); + + CopyMem ( + (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16), + Sha256Digest, + CertDataSize + ); + + // + // Set "certdb" or "certdbv". + // + Status = AuthServiceInternalUpdateVariable ( + DbName, + &gEfiCertDbGuid, + NewCertDb, + NewCertDbSize, + VarAttr + ); + + return Status; +} + +/** + Clean up signer's certificates for common authenticated variable + by corresponding VariableName and VendorGuid from "certdb". + System may break down during Timebased Variable update & certdb update, + make them inconsistent, this function is called in AuthVariable Init + to ensure consistency. + + @retval EFI_NOT_FOUND Fail to find variable "certdb". + @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +CleanCertsFromDb ( + VOID + ) +{ + UINT32 Offset; + AUTH_CERT_DB_DATA *Ptr; + UINT32 NameSize; + UINT32 NodeSize; + CHAR16 *VariableName; + EFI_STATUS Status; + BOOLEAN CertCleaned; + UINT8 *Data; + UINTN DataSize; + EFI_GUID AuthVarGuid; + AUTH_VARIABLE_INFO AuthVariableInfo; + + Status = EFI_SUCCESS; + + // + // Get corresponding certificates by VendorGuid and VariableName. + // + do { + CertCleaned = FALSE; + + // + // Get latest variable "certdb" + // + Status = AuthServiceInternalFindVariable ( + EFI_CERT_DB_NAME, + &gEfiCertDbGuid, + (VOID **) &Data, + &DataSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((DataSize == 0) || (Data == NULL)) { + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + + Offset = sizeof (UINT32); + + while (Offset < (UINT32) DataSize) { + Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset); + NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize); + NameSize = ReadUnaligned32 (&Ptr->NameSize); + + // + // Get VarName tailed with '\0' + // + VariableName = AllocateZeroPool((NameSize + 1) * sizeof(CHAR16)); + if (VariableName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (VariableName, (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof(CHAR16)); + // + // Keep VarGuid aligned + // + CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof(EFI_GUID)); + + // + // Find corresponding time auth variable + // + ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo)); + Status = mAuthVarLibContextIn->FindVariable ( + VariableName, + &AuthVarGuid, + &AuthVariableInfo + ); + + if (EFI_ERROR(Status) || (AuthVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) { + // + // While cleaning certdb, always delete the variable in certdb regardless of it attributes. + // + Status = DeleteCertsFromDb( + VariableName, + &AuthVarGuid, + AuthVariableInfo.Attributes | EFI_VARIABLE_NON_VOLATILE + ); + CertCleaned = TRUE; + DEBUG((EFI_D_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid)); + FreePool(VariableName); + break; + } + + FreePool(VariableName); + Offset = Offset + NodeSize; + } + } while (CertCleaned); + + return Status; +} + +/** + Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + + @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] Attributes Attribute value of the variable. + @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload. + @param[in] OrgTimeStamp Pointer to original time stamp, + original variable is not found if NULL. + @param[out] VarPayloadPtr Pointer to variable payload address. + @param[out] VarPayloadSize Pointer to variable payload size. + + @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 UINT32 Attributes, + IN AUTHVAR_TYPE AuthVarType, + IN EFI_TIME *OrgTimeStamp, + OUT UINT8 **VarPayloadPtr, + OUT UINTN *VarPayloadSize + ) +{ + EFI_VARIABLE_AUTHENTICATION_2 *CertData; + UINT8 *SigData; + UINT32 SigDataSize; + UINT8 *PayloadPtr; + UINTN PayloadSize; + UINT32 Attr; + BOOLEAN VerifyStatus; + EFI_STATUS Status; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *Cert; + UINTN Index; + UINTN CertCount; + UINT32 KekDataSize; + UINT8 *NewData; + UINTN NewDataSize; + UINT8 *Buffer; + UINTN Length; + UINT8 *TopLevelCert; + UINTN TopLevelCertSize; + UINT8 *TrustedCert; + UINTN TrustedCertSize; + UINT8 *SignerCerts; + UINTN CertStackSize; + UINT8 *CertsInCertDb; + UINT32 CertsSizeinDb; + UINT8 Sha256Digest[SHA256_DIGEST_SIZE]; + EFI_CERT_DATA *CertDataPtr; + + // + // 1. TopLevelCert is the top-level issuer certificate in signature Signer Cert Chain + // 2. TrustedCert is the certificate which firmware trusts. It could be saved in protected + // storage or PK payload on PK init + // + VerifyStatus = FALSE; + CertData = NULL; + NewData = NULL; + Attr = Attributes; + SignerCerts = NULL; + TopLevelCert = NULL; + CertsInCertDb = NULL; + CertDataPtr = NULL; + + // + // 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; + + // + // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the + // TimeStamp value are set to zero. + // + if ((CertData->TimeStamp.Pad1 != 0) || + (CertData->TimeStamp.Nanosecond != 0) || + (CertData->TimeStamp.TimeZone != 0) || + (CertData->TimeStamp.Daylight != 0) || + (CertData->TimeStamp.Pad2 != 0)) { + return EFI_SECURITY_VIOLATION; + } + + if ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) { + if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) { + // + // 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 = CertData->AuthInfo.CertData; + SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)); + + // + // SignedData.digestAlgorithms shall contain the digest algorithm used when preparing the + // signature. Only a digest algorithm of SHA-256 is accepted. + // + // According to PKCS#7 Definition: + // SignedData ::= SEQUENCE { + // version Version, + // digestAlgorithms DigestAlgorithmIdentifiers, + // contentInfo ContentInfo, + // .... } + // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm + // in VARIABLE_AUTHENTICATION_2 descriptor. + // This field has the fixed offset (+13) and be calculated based on two bytes of length encoding. + // + if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + if (SigDataSize >= (13 + sizeof (mSha256OidValue))) { + if (((*(SigData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) || + (CompareMem (SigData + 13, &mSha256OidValue, sizeof (mSha256OidValue)) != 0)) { + return EFI_SECURITY_VIOLATION; + } + } + } + + // + // Find out the new data payload which follows Pkcs7 SignedData directly. + // + PayloadPtr = SigData + SigDataSize; + PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize; + + // If the VariablePolicy engine is disabled, allow deletion of any authenticated variables. + if (PayloadSize == 0 && (Attributes & EFI_VARIABLE_APPEND_WRITE) == 0 && !IsVariablePolicyEnabled()) { + VerifyStatus = TRUE; + goto Exit; + } + + // + // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes + // parameters of the SetVariable() call and the TimeStamp component of the + // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value + // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data) + // + NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) + + sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16); + + // + // Here is to reuse scratch data area(at the end of volatile variable store) + // to reduce SMRAM consumption for SMM variable driver. + // The scratch buffer is enough to hold the serialized data and safe to use, + // because it is only used at here to do verification temporarily first + // and then used in UpdateVariable() for a time based auth variable set. + // + Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **) &NewData); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + Buffer = NewData; + Length = StrLen (VariableName) * sizeof (CHAR16); + CopyMem (Buffer, VariableName, Length); + Buffer += Length; + + Length = sizeof (EFI_GUID); + CopyMem (Buffer, VendorGuid, Length); + Buffer += Length; + + Length = sizeof (UINT32); + CopyMem (Buffer, &Attr, Length); + Buffer += Length; + + Length = sizeof (EFI_TIME); + CopyMem (Buffer, &CertData->TimeStamp, Length); + Buffer += Length; + + CopyMem (Buffer, PayloadPtr, PayloadSize); + + if (AuthVarType == AuthVarTypePk) { + // + // Verify that the signature has been made with the current Platform Key (no chaining for PK). + // First, get signer's certificates from SignedData. + // + VerifyStatus = Pkcs7GetSigners ( + SigData, + SigDataSize, + &SignerCerts, + &CertStackSize, + &TopLevelCert, + &TopLevelCertSize + ); + if (!VerifyStatus) { + goto Exit; + } + + // + // Second, get the current platform key from variable. Check whether it's identical with signer's certificates + // in SignedData. If not, return error immediately. + // + Status = AuthServiceInternalFindVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid, + &Data, + &DataSize + ); + if (EFI_ERROR (Status)) { + VerifyStatus = FALSE; + goto Exit; + } + CertList = (EFI_SIGNATURE_LIST *) Data; + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + if ((TopLevelCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) || + (CompareMem (Cert->SignatureData, TopLevelCert, TopLevelCertSize) != 0)) { + VerifyStatus = FALSE; + goto Exit; + } + + // + // Verify Pkcs7 SignedData via Pkcs7Verify library. + // + VerifyStatus = Pkcs7Verify ( + SigData, + SigDataSize, + TopLevelCert, + TopLevelCertSize, + NewData, + NewDataSize + ); + + } else if (AuthVarType == AuthVarTypeKek) { + + // + // Get KEK database from variable. + // + Status = AuthServiceInternalFindVariable ( + EFI_KEY_EXCHANGE_KEY_NAME, + &gEfiGlobalVariableGuid, + &Data, + &DataSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList. + // + KekDataSize = (UINT32) DataSize; + CertList = (EFI_SIGNATURE_LIST *) Data; + 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 + // + TrustedCert = Cert->SignatureData; + TrustedCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1); + + // + // Verify Pkcs7 SignedData via Pkcs7Verify library. + // + VerifyStatus = Pkcs7Verify ( + SigData, + SigDataSize, + TrustedCert, + TrustedCertSize, + 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); + } + } else if (AuthVarType == AuthVarTypePriv) { + + // + // Process common authenticated variable except PK/KEK/DB/DBX/DBT. + // Get signer's certificates from SignedData. + // + VerifyStatus = Pkcs7GetSigners ( + SigData, + SigDataSize, + &SignerCerts, + &CertStackSize, + &TopLevelCert, + &TopLevelCertSize + ); + if (!VerifyStatus) { + goto Exit; + } + + // + // Get previously stored signer's certificates from certdb or certdbv for existing + // variable. Check whether they are identical with signer's certificates + // in SignedData. If not, return error immediately. + // + if (OrgTimeStamp != NULL) { + VerifyStatus = FALSE; + + Status = GetCertsFromDb (VariableName, VendorGuid, Attributes, &CertsInCertDb, &CertsSizeinDb); + if (EFI_ERROR (Status)) { + goto Exit; + } + + if (CertsSizeinDb == SHA256_DIGEST_SIZE) { + // + // Check hash of signer cert CommonName + Top-level issuer tbsCertificate against data in CertDb + // + CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1); + Status = CalculatePrivAuthVarSignChainSHA256Digest( + CertDataPtr->CertDataBuffer, + ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)), + TopLevelCert, + TopLevelCertSize, + Sha256Digest + ); + if (EFI_ERROR(Status) || CompareMem (Sha256Digest, CertsInCertDb, CertsSizeinDb) != 0){ + goto Exit; + } + } else { + // + // Keep backward compatible with previous solution which saves whole signer certs stack in CertDb + // + if ((CertStackSize != CertsSizeinDb) || + (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) { + goto Exit; + } + } + } + + VerifyStatus = Pkcs7Verify ( + SigData, + SigDataSize, + TopLevelCert, + TopLevelCertSize, + NewData, + NewDataSize + ); + if (!VerifyStatus) { + goto Exit; + } + + if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) { + // + // When adding a new common authenticated variable, always save Hash of cn of signer cert + tbsCertificate of Top-level issuer + // + CertDataPtr = (EFI_CERT_DATA *)(SignerCerts + 1); + Status = InsertCertsToDb ( + VariableName, + VendorGuid, + Attributes, + CertDataPtr->CertDataBuffer, + ReadUnaligned32 ((UINT32 *)&(CertDataPtr->CertDataLength)), + TopLevelCert, + TopLevelCertSize + ); + if (EFI_ERROR (Status)) { + VerifyStatus = FALSE; + goto Exit; + } + } + } else if (AuthVarType == AuthVarTypePayload) { + CertList = (EFI_SIGNATURE_LIST *) PayloadPtr; + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); + TrustedCert = Cert->SignatureData; + TrustedCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1); + // + // Verify Pkcs7 SignedData via Pkcs7Verify library. + // + VerifyStatus = Pkcs7Verify ( + SigData, + SigDataSize, + TrustedCert, + TrustedCertSize, + NewData, + NewDataSize + ); + } else { + return EFI_SECURITY_VIOLATION; + } + +Exit: + + if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) { + if (TopLevelCert != NULL) { + Pkcs7FreeSigners (TopLevelCert); + } + if (SignerCerts != NULL) { + Pkcs7FreeSigners (SignerCerts); + } + } + + if (!VerifyStatus) { + return EFI_SECURITY_VIOLATION; + } + + Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize); + if (EFI_ERROR (Status)) { + return Status; + } + + *VarPayloadPtr = PayloadPtr; + *VarPayloadSize = PayloadSize; + + return EFI_SUCCESS; +} + +/** + Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + + @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] Attributes Attribute value of the variable. + @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload. + @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 +VerifyTimeBasedPayloadAndUpdate ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes, + IN AUTHVAR_TYPE AuthVarType, + OUT BOOLEAN *VarDel + ) +{ + EFI_STATUS Status; + EFI_STATUS FindStatus; + UINT8 *PayloadPtr; + UINTN PayloadSize; + EFI_VARIABLE_AUTHENTICATION_2 *CertData; + AUTH_VARIABLE_INFO OrgVariableInfo; + BOOLEAN IsDel; + + ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo)); + FindStatus = mAuthVarLibContextIn->FindVariable ( + VariableName, + VendorGuid, + &OrgVariableInfo + ); + + Status = VerifyTimeBasedPayload ( + VariableName, + VendorGuid, + Data, + DataSize, + Attributes, + AuthVarType, + (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL, + &PayloadPtr, + &PayloadSize + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!EFI_ERROR(FindStatus) + && (PayloadSize == 0) + && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) { + IsDel = TRUE; + } else { + IsDel = FALSE; + } + + CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data; + + // + // Final step: Update/Append Variable if it pass Pkcs7Verify + // + Status = AuthServiceInternalUpdateVariableWithTimeStamp ( + VariableName, + VendorGuid, + PayloadPtr, + PayloadSize, + Attributes, + &CertData->TimeStamp + ); + + // + // Delete signer's certificates when delete the common authenticated variable. + // + if (IsDel && AuthVarType == AuthVarTypePriv && !EFI_ERROR(Status) ) { + Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes); + } + + if (VarDel != NULL) { + if (IsDel && !EFI_ERROR(Status)) { + *VarDel = TRUE; + } else { + *VarDel = FALSE; + } + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h new file mode 100644 index 00000000..7cbb1b73 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h @@ -0,0 +1,369 @@ +/** @file + The internal header file includes the common header files, defines + internal structure and functions used by AuthService module. + + Caution: This module requires additional review when modified. + This driver will have external input - variable data. It may be input in SMM mode. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + Variable attribute should also be checked to avoid authentication bypass. + The whole SMM authentication variable design relies on the integrity of flash part and SMM. + which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory + may not be modified without authorization. If platform fails to protect these resources, + the authentication service provided in this driver will be broken, and the behavior is undefined. + +Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _AUTHSERVICE_INTERNAL_H_ +#define _AUTHSERVICE_INTERNAL_H_ + +#include <Library/AuthVariableLib.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/PlatformSecureLib.h> + +#include <Guid/AuthenticatedVariableFormat.h> +#include <Guid/ImageAuthentication.h> + +#define TWO_BYTE_ENCODE 0x82 + +/// +/// Struct to record signature requirement defined by UEFI spec. +/// For SigHeaderSize and SigDataSize, ((UINT32) ~0) means NO exact length requirement for this field. +/// +typedef struct { + EFI_GUID SigType; + // Expected SignatureHeader size in Bytes. + UINT32 SigHeaderSize; + // Expected SignatureData size in Bytes. + UINT32 SigDataSize; +} EFI_SIGNATURE_ITEM; + +typedef enum { + AuthVarTypePk, + AuthVarTypeKek, + AuthVarTypePriv, + AuthVarTypePayload +} AUTHVAR_TYPE; + +/// +/// "certdb" variable stores the signer's certificates for non PK/KEK/DB/DBX +/// variables with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS|EFI_VARIABLE_NON_VOLATILE set. +/// "certdbv" variable stores the signer's certificates for non PK/KEK/DB/DBX +/// variables with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set +/// +/// GUID: gEfiCertDbGuid +/// +/// We need maintain atomicity. +/// +/// Format: +/// +----------------------------+ +/// | UINT32 | <-- CertDbListSize, including this UINT32 +/// +----------------------------+ +/// | AUTH_CERT_DB_DATA | <-- First CERT +/// +----------------------------+ +/// | ........ | +/// +----------------------------+ +/// | AUTH_CERT_DB_DATA | <-- Last CERT +/// +----------------------------+ +/// +#define EFI_CERT_DB_NAME L"certdb" +#define EFI_CERT_DB_VOLATILE_NAME L"certdbv" + +#pragma pack(1) +typedef struct { + EFI_GUID VendorGuid; + UINT32 CertNodeSize; + UINT32 NameSize; + UINT32 CertDataSize; + /// CHAR16 VariableName[NameSize]; + /// UINT8 CertData[CertDataSize]; +} AUTH_CERT_DB_DATA; +#pragma pack() + +extern UINT8 *mCertDbStore; +extern UINT32 mMaxCertDbSize; +extern UINT32 mPlatformMode; +extern UINT8 mVendorKeyState; + +extern VOID *mHashCtx; + +extern AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn; + + +/** + Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + + @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] Attributes Attribute value of the variable. + @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload. + @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 +VerifyTimeBasedPayloadAndUpdate ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes, + IN AUTHVAR_TYPE AuthVarType, + OUT BOOLEAN *VarDel + ); + +/** + Delete matching signer's certificates when deleting common authenticated + variable by corresponding VariableName and VendorGuid from "certdb" or + "certdbv" according to authenticated variable attributes. + + @param[in] VariableName Name of authenticated Variable. + @param[in] VendorGuid Vendor GUID of authenticated Variable. + @param[in] Attributes Attributes of authenticated variable. + + @retval EFI_INVALID_PARAMETER Any input parameter is invalid. + @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs. + @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources. + @retval EFI_SUCCESS The operation is completed successfully. + +**/ +EFI_STATUS +DeleteCertsFromDb ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes + ); + +/** + Clean up signer's certificates for common authenticated variable + by corresponding VariableName and VendorGuid from "certdb". + System may break down during Timebased Variable update & certdb update, + make them inconsistent, this function is called in AuthVariable Init to ensure + consistency + + @retval EFI_NOT_FOUND Fail to find matching certs. + @retval EFI_SUCCESS Find matching certs and output parameters. + +**/ +EFI_STATUS +CleanCertsFromDb ( + VOID + ); + +/** + Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data. + + @param[in] Data Pointer to original EFI_SIGNATURE_LIST. + @param[in] DataSize Size of Data buffer. + @param[in, out] NewData Pointer to new EFI_SIGNATURE_LIST. + @param[in, out] NewDataSize Size of NewData buffer. + +**/ +EFI_STATUS +FilterSignatureList ( + IN VOID *Data, + IN UINTN DataSize, + IN OUT VOID *NewData, + IN OUT UINTN *NewDataSize + ); + +/** + Process variable with platform key for verification. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. + + @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] 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 UINT32 Attributes OPTIONAL, + IN BOOLEAN IsPk + ); + +/** + Process variable with key exchange key for verification. + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. + + @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] 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 UINT32 Attributes OPTIONAL + ); + +/** + Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set + + Caution: This function may receive untrusted input. + This function may be invoked in SMM mode, and datasize and data are external input. + This function will do basic validation, before parse the data. + This function will parse the authentication carefully to avoid security issues, like + buffer overflow, integer overflow. + This function will check attribute carefully to avoid authentication bypass. + + @param[in] VariableName Name of the variable. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data. + @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 or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set. + @return EFI_OUT_OF_RESOURCES The Database to save the public key is full. + @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_TIME_BASED_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 UINT32 Attributes + ); + +/** + 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. + + @param[in] VariableName Name of the variable to be found. + @param[in] VendorGuid Variable vendor GUID to be found. + @param[out] Data Pointer to data address. + @param[out] DataSize Pointer to data size. + + @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 +AuthServiceInternalFindVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT VOID **Data, + OUT UINTN *DataSize + ); + +/** + Update the variable region with Variable information. + + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data. + @param[in] Attributes Attribute value of the variable. + + @retval EFI_SUCCESS The update operation is success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_WRITE_PROTECTED Variable is write-protected. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +AuthServiceInternalUpdateVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes + ); + +/** + Update the variable region with Variable information. + + @param[in] VariableName Name of variable. + @param[in] VendorGuid Guid of variable. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data. + @param[in] Attributes Attribute value of the variable. + @param[in] TimeStamp Value of associated TimeStamp. + + @retval EFI_SUCCESS The update operation is success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_WRITE_PROTECTED Variable is write-protected. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + +**/ +EFI_STATUS +AuthServiceInternalUpdateVariableWithTimeStamp ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes, + IN EFI_TIME *TimeStamp + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c new file mode 100644 index 00000000..b611ef9b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c @@ -0,0 +1,421 @@ +/** @file + Implement authentication services for the authenticated variables. + + Caution: This module requires additional review when modified. + This driver will have external input - variable data. It may be input in SMM mode. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + Variable attribute should also be checked to avoid authentication bypass. + The whole SMM authentication variable design relies on the integrity of flash part and SMM. + which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory + may not be modified without authorization. If platform fails to protect these resources, + the authentication service provided in this driver will be broken, and the behavior is undefined. + +Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "AuthServiceInternal.h" + +/// +/// Global database array for scratch +/// +UINT8 *mCertDbStore; +UINT32 mMaxCertDbSize; +UINT32 mPlatformMode; +UINT8 mVendorKeyState; + +EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID}; + +// +// Hash context pointer +// +VOID *mHashCtx = NULL; + +VARIABLE_ENTRY_PROPERTY mAuthVarEntry[] = { + { + &gEfiSecureBootEnableDisableGuid, + EFI_SECURE_BOOT_ENABLE_NAME, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + 0, + VARIABLE_ATTRIBUTE_NV_BS, + sizeof (UINT8), + sizeof (UINT8) + } + }, + { + &gEfiCustomModeEnableGuid, + EFI_CUSTOM_MODE_NAME, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + 0, + VARIABLE_ATTRIBUTE_NV_BS, + sizeof (UINT8), + sizeof (UINT8) + } + }, + { + &gEfiVendorKeysNvGuid, + EFI_VENDOR_KEYS_NV_VARIABLE_NAME, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY, + VARIABLE_ATTRIBUTE_NV_BS_RT_AT, + sizeof (UINT8), + sizeof (UINT8) + } + }, + { + &gEfiCertDbGuid, + EFI_CERT_DB_NAME, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY, + VARIABLE_ATTRIBUTE_NV_BS_RT_AT, + sizeof (UINT32), + MAX_UINTN + } + }, + { + &gEfiCertDbGuid, + EFI_CERT_DB_VOLATILE_NAME, + { + VAR_CHECK_VARIABLE_PROPERTY_REVISION, + VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY, + VARIABLE_ATTRIBUTE_BS_RT_AT, + sizeof (UINT32), + MAX_UINTN + } + }, +}; + +VOID **mAuthVarAddressPointer[9]; + +AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn = NULL; + +/** + Initialization for authenticated variable services. + If this initialization returns error status, other APIs will not work + and expect to be not called then. + + @param[in] AuthVarLibContextIn Pointer to input auth variable lib context. + @param[out] AuthVarLibContextOut Pointer to output auth variable lib context. + + @retval EFI_SUCCESS Function successfully executed. + @retval EFI_INVALID_PARAMETER If AuthVarLibContextIn == NULL or AuthVarLibContextOut == NULL. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource. + @retval EFI_UNSUPPORTED Unsupported to process authenticated variable. + +**/ +EFI_STATUS +EFIAPI +AuthVariableLibInitialize ( + IN AUTH_VAR_LIB_CONTEXT_IN *AuthVarLibContextIn, + OUT AUTH_VAR_LIB_CONTEXT_OUT *AuthVarLibContextOut + ) +{ + EFI_STATUS Status; + UINT32 VarAttr; + UINT8 *Data; + UINTN DataSize; + UINTN CtxSize; + UINT8 SecureBootMode; + UINT8 SecureBootEnable; + UINT8 CustomMode; + UINT32 ListSize; + + if ((AuthVarLibContextIn == NULL) || (AuthVarLibContextOut == NULL)) { + return EFI_INVALID_PARAMETER; + } + + mAuthVarLibContextIn = AuthVarLibContextIn; + + // + // Initialize hash context. + // + CtxSize = Sha256GetContextSize (); + mHashCtx = AllocateRuntimePool (CtxSize); + if (mHashCtx == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Reserve runtime buffer for certificate database. The size excludes variable header and name size. + // Use EFI_CERT_DB_VOLATILE_NAME size since it is longer. + // + mMaxCertDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (EFI_CERT_DB_VOLATILE_NAME)); + mCertDbStore = AllocateRuntimePool (mMaxCertDbSize); + if (mCertDbStore == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME)); + } else { + DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME)); + } + + // + // Create "SetupMode" variable with BS+RT attribute set. + // + if (EFI_ERROR (Status)) { + mPlatformMode = SETUP_MODE; + } else { + mPlatformMode = USER_MODE; + } + Status = AuthServiceInternalUpdateVariable ( + EFI_SETUP_MODE_NAME, + &gEfiGlobalVariableGuid, + &mPlatformMode, + sizeof(UINT8), + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Create "SignatureSupport" variable with BS+RT attribute set. + // + Status = AuthServiceInternalUpdateVariable ( + EFI_SIGNATURE_SUPPORT_NAME, + &gEfiGlobalVariableGuid, + mSignatureSupport, + sizeof(mSignatureSupport), + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // If "SecureBootEnable" variable exists, then update "SecureBoot" variable. + // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE. + // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE. + // + SecureBootEnable = SECURE_BOOT_DISABLE; + Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **) &Data, &DataSize); + if (!EFI_ERROR (Status)) { + if (mPlatformMode == USER_MODE){ + SecureBootEnable = *(UINT8 *) Data; + } + } else if (mPlatformMode == USER_MODE) { + // + // "SecureBootEnable" not exist, initialize it in USER_MODE. + // + SecureBootEnable = SECURE_BOOT_ENABLE; + Status = AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_ENABLE_NAME, + &gEfiSecureBootEnableDisableGuid, + &SecureBootEnable, + sizeof (UINT8), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Create "SecureBoot" variable with BS+RT attribute set. + // + if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) { + SecureBootMode = SECURE_BOOT_MODE_ENABLE; + } else { + SecureBootMode = SECURE_BOOT_MODE_DISABLE; + } + Status = AuthServiceInternalUpdateVariable ( + EFI_SECURE_BOOT_MODE_NAME, + &gEfiGlobalVariableGuid, + &SecureBootMode, + sizeof (UINT8), + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode)); + DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode)); + DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable)); + + // + // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state. + // + CustomMode = STANDARD_SECURE_BOOT_MODE; + Status = AuthServiceInternalUpdateVariable ( + EFI_CUSTOM_MODE_NAME, + &gEfiCustomModeEnableGuid, + &CustomMode, + sizeof (UINT8), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode)); + + // + // Check "certdb" variable's existence. + // If it doesn't exist, then create a new one with + // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set. + // + Status = AuthServiceInternalFindVariable ( + EFI_CERT_DB_NAME, + &gEfiCertDbGuid, + (VOID **) &Data, + &DataSize + ); + if (EFI_ERROR (Status)) { + VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + ListSize = sizeof (UINT32); + Status = AuthServiceInternalUpdateVariable ( + EFI_CERT_DB_NAME, + &gEfiCertDbGuid, + &ListSize, + sizeof (UINT32), + VarAttr + ); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + // + // Clean up Certs to make certDB & Time based auth variable consistent + // + Status = CleanCertsFromDb(); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Clean up CertDB fail! Status %x\n", Status)); + return Status; + } + } + + // + // Create "certdbv" variable with RT+BS+AT set. + // + VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + ListSize = sizeof (UINT32); + Status = AuthServiceInternalUpdateVariable ( + EFI_CERT_DB_VOLATILE_NAME, + &gEfiCertDbGuid, + &ListSize, + sizeof (UINT32), + VarAttr + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly. + // + Status = AuthServiceInternalFindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, (VOID **) &Data, &DataSize); + if (!EFI_ERROR (Status)) { + mVendorKeyState = *(UINT8 *)Data; + } else { + // + // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state. + // + mVendorKeyState = VENDOR_KEYS_VALID; + Status = AuthServiceInternalUpdateVariable ( + EFI_VENDOR_KEYS_NV_VARIABLE_NAME, + &gEfiVendorKeysNvGuid, + &mVendorKeyState, + sizeof (UINT8), + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Create "VendorKeys" variable with BS+RT attribute set. + // + Status = AuthServiceInternalUpdateVariable ( + EFI_VENDOR_KEYS_VARIABLE_NAME, + &gEfiGlobalVariableGuid, + &mVendorKeyState, + sizeof (UINT8), + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS + ); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_VENDOR_KEYS_VARIABLE_NAME, mVendorKeyState)); + + AuthVarLibContextOut->StructVersion = AUTH_VAR_LIB_CONTEXT_OUT_STRUCT_VERSION; + AuthVarLibContextOut->StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_OUT); + AuthVarLibContextOut->AuthVarEntry = mAuthVarEntry; + AuthVarLibContextOut->AuthVarEntryCount = ARRAY_SIZE (mAuthVarEntry); + mAuthVarAddressPointer[0] = (VOID **) &mCertDbStore; + mAuthVarAddressPointer[1] = (VOID **) &mHashCtx; + mAuthVarAddressPointer[2] = (VOID **) &mAuthVarLibContextIn; + mAuthVarAddressPointer[3] = (VOID **) &(mAuthVarLibContextIn->FindVariable), + mAuthVarAddressPointer[4] = (VOID **) &(mAuthVarLibContextIn->FindNextVariable), + mAuthVarAddressPointer[5] = (VOID **) &(mAuthVarLibContextIn->UpdateVariable), + mAuthVarAddressPointer[6] = (VOID **) &(mAuthVarLibContextIn->GetScratchBuffer), + mAuthVarAddressPointer[7] = (VOID **) &(mAuthVarLibContextIn->CheckRemainingSpaceForConsistency), + mAuthVarAddressPointer[8] = (VOID **) &(mAuthVarLibContextIn->AtRuntime), + AuthVarLibContextOut->AddressPointer = mAuthVarAddressPointer; + AuthVarLibContextOut->AddressPointerCount = ARRAY_SIZE (mAuthVarAddressPointer); + + return Status; +} + +/** + Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set. + + @param[in] VariableName Name of the variable. + @param[in] VendorGuid Variable vendor GUID. + @param[in] Data Data pointer. + @param[in] DataSize Size of Data. + @param[in] Attributes Attribute value of the variable. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_WRITE_PROTECTED Variable is write-protected. + @retval EFI_OUT_OF_RESOURCES There is not enough resource. + @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS + set, but the AuthInfo does NOT pass the validation + check carried out by the firmware. + @retval EFI_UNSUPPORTED Unsupported to process authenticated variable. + +**/ +EFI_STATUS +EFIAPI +AuthVariableLibProcessVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN DataSize, + IN UINT32 Attributes + ) +{ + EFI_STATUS Status; + + if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){ + Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, TRUE); + } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) { + Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE); + } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && + ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || + (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) || + (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) + )) { + Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE); + if (EFI_ERROR (Status)) { + Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, Attributes); + } + } else { + Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf new file mode 100644 index 00000000..6f94b63c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf @@ -0,0 +1,88 @@ +## @file +# Provides authenticated variable services. +# +# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2018, ARM Limited. All rights reserved.<BR> +# Copyright (c) Microsoft Corporation. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AuthVariableLib + MODULE_UNI_FILE = AuthVariableLib.uni + FILE_GUID = B23CF5FB-6FCC-4422-B145-D855DBC05457 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = AuthVariableLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER MM_STANDALONE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 AARCH64 +# + +[Sources] + AuthVariableLib.c + AuthService.c + AuthServiceInternal.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + BaseCryptLib + PlatformSecureLib + VariablePolicyLib + +[Guids] + ## CONSUMES ## Variable:L"SetupMode" + ## PRODUCES ## Variable:L"SetupMode" + ## SOMETIMES_CONSUMES ## Variable:L"PK" + ## SOMETIMES_CONSUMES ## Variable:L"KEK" + ## CONSUMES ## Variable:L"SecureBoot" + ## PRODUCES ## Variable:L"SecureBoot" + ## CONSUMES ## Variable:L"SignatureSupport" + ## PRODUCES ## Variable:L"SignatureSupport" + ## PRODUCES ## Variable:L"VendorKeys" + gEfiGlobalVariableGuid + + ## SOMETIMES_CONSUMES ## Variable:L"DB" + ## SOMETIMES_CONSUMES ## Variable:L"DBX" + ## SOMETIMES_CONSUMES ## Variable:L"DBT" + gEfiImageSecurityDatabaseGuid + + ## CONSUMES ## Variable:L"SecureBootEnable" + ## PRODUCES ## Variable:L"SecureBootEnable" + gEfiSecureBootEnableDisableGuid + + ## CONSUMES ## Variable:L"CustomMode" + ## PRODUCES ## Variable:L"CustomMode" + gEfiCustomModeEnableGuid + + ## CONSUMES ## Variable:L"certdb" + ## CONSUMES ## Variable:L"certdbv" + ## PRODUCES ## Variable:L"certdb" + ## PRODUCES ## Variable:L"certdbv" + gEfiCertDbGuid + + ## CONSUMES ## Variable:L"VendorKeysNv" + ## PRODUCES ## Variable:L"VendorKeysNv" + gEfiVendorKeysNvGuid + + ## CONSUMES ## Variable:L"AuthVarKeyDatabase" + ## PRODUCES ## Variable:L"AuthVarKeyDatabase" + gEfiAuthenticatedVariableGuid + + gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate. + gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate. + gEfiCertX509Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni new file mode 100644 index 00000000..b0884b35 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni @@ -0,0 +1,16 @@ +// /** @file
+// Provides authenticated variable services.
+//
+// Provides authenticated variable services.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides authenticated variable services"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides authenticated variable services."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.c new file mode 100644 index 00000000..297e5ae4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.c @@ -0,0 +1,70 @@ +/** @file + Implement image authentication status check in UEFI2.3.1. + +Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Library/SecurityManagementLib.h> + + +/** + Check image authentication status returned from Section Extraction Protocol + + @param[in] AuthenticationStatus This is the authentication status returned from + the Section Extraction Protocol when reading 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. + @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service. + + @retval EFI_SUCCESS The input file specified by File did authenticate, and the + platform policy dictates that the DXE Core may use File. + @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not + authenticate, and the platform policy dictates that the DXE + Foundation many not use File. + +**/ +EFI_STATUS +EFIAPI +DxeImageAuthenticationStatusHandler ( + IN UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File, OPTIONAL + IN VOID *FileBuffer, + IN UINTN FileSize, + IN BOOLEAN BootPolicy + ) +{ + if ((AuthenticationStatus & EFI_AUTH_STATUS_IMAGE_SIGNED) != 0) { + if ((AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) { + return EFI_ACCESS_DENIED; + } + } + + return EFI_SUCCESS; +} + + +/** + Register image authentication status check 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 +DxeImageAuthenticationStatusLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return RegisterSecurity2Handler ( + DxeImageAuthenticationStatusHandler, + EFI_AUTH_OPERATION_AUTHENTICATION_STATE + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.inf new file mode 100644 index 00000000..b99b8cf8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.inf @@ -0,0 +1,35 @@ +## @file +# Provides security service of image authentication status check +# +# Authentication Status Library module supports UEFI2.3.1 +# +# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeImageAuthenticationStatusLib + MODULE_UNI_FILE = DxeImageAuthenticationStatusLib.uni + FILE_GUID = EB92D1DE-7C36-4680-BB88-A67E96049F72 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = DxeImageAuthenticationStatusLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + DxeImageAuthenticationStatusLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + SecurityManagementLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.uni new file mode 100644 index 00000000..99b25081 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.uni @@ -0,0 +1,16 @@ +// /** @file
+// Provides security service of image authentication status check
+//
+// Authentication Status Library module supports UEFI2.3.1
+//
+// Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service of image authentication status check"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The Authentication Status Library module supports UEFI2.3.1."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c new file mode 100644 index 00000000..275e86f6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c @@ -0,0 +1,2081 @@ +/** @file + Implement image verification services for secure boot service + + Caution: This file requires additional review when modified. + This library will have external input - PE/COFF image. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + DxeImageVerificationLibImageRead() function will make sure the PE/COFF image content + read is within the image buffer. + + DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept + untrusted PE/COFF image and validate its data structure within this image buffer before use. + +Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DxeImageVerificationLib.h" + +// +// Caution: This is used by a function which may receive untrusted input. +// These global variables hold PE/COFF image data, and they should be validated before use. +// +EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader; +UINT32 mPeCoffHeaderOffset; +EFI_GUID mCertType; + +// +// Information on current PE/COFF image +// +UINTN mImageSize; +UINT8 *mImageBase = NULL; +UINT8 mImageDigest[MAX_DIGEST_SIZE]; +UINTN mImageDigestSize; + +// +// 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[] = { + 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[] = { +#ifndef DISABLE_SHA1_DEPRECATED_INTERFACES + { L"SHA1", 20, &mHashOidValue[0], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final }, +#else + { L"SHA1", 20, &mHashOidValue[0], 5, NULL, NULL, NULL, NULL }, +#endif + { L"SHA224", 28, &mHashOidValue[5], 9, NULL, NULL, NULL, NULL }, + { L"SHA256", 32, &mHashOidValue[14], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final}, + { L"SHA384", 48, &mHashOidValue[23], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final}, + { L"SHA512", 64, &mHashOidValue[32], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final} +}; + +EFI_STRING mHashTypeStr; + +/** + SecureBoot Hook for processing image verification. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @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. + +**/ +VOID +EFIAPI +SecureBootHook ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + Reads contents of a PE/COFF image in memory buffer. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will make sure the PE/COFF image content + read is within the image 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 +DxeImageVerificationLibImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + UINTN EndPosition; + + if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (MAX_ADDRESS - FileOffset < *ReadSize) { + return EFI_INVALID_PARAMETER; + } + + EndPosition = FileOffset + *ReadSize; + if (EndPosition > mImageSize) { + *ReadSize = (UINT32)(mImageSize - FileOffset); + } + + if (FileOffset >= mImageSize) { + *ReadSize = 0; + } + + CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize); + + return EFI_SUCCESS; +} + + +/** + 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; + + if (File == NULL) { + return IMAGE_UNKNOWN; + } + + // + // 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; +} + +/** + Calculate hash of Pe/Coff image based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in + its caller function DxeImageVerificationHandler(). + + @param[in] HashAlg Hash algorithm type. + + @retval TRUE Successfully hash image. + @retval FALSE Fail in hash image. + +**/ +BOOLEAN +HashPeImage ( + IN UINT32 HashAlg + ) +{ + BOOLEAN Status; + EFI_IMAGE_SECTION_HEADER *Section; + VOID *HashCtx; + UINTN CtxSize; + UINT8 *HashBase; + UINTN HashSize; + UINTN SumOfBytesHashed; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINTN Index; + UINTN Pos; + UINT32 CertSize; + UINT32 NumberOfRvaAndSizes; + + HashCtx = NULL; + SectionHeader = NULL; + Status = FALSE; + + if ((HashAlg >= HASHALG_MAX)) { + return FALSE; + } + + // + // Initialize context of hash. + // + ZeroMem (mImageDigest, MAX_DIGEST_SIZE); + + switch (HashAlg) { +#ifndef DISABLE_SHA1_DEPRECATED_INTERFACES + case HASHALG_SHA1: + mImageDigestSize = SHA1_DIGEST_SIZE; + mCertType = gEfiCertSha1Guid; + break; +#endif + + case HASHALG_SHA256: + mImageDigestSize = SHA256_DIGEST_SIZE; + mCertType = gEfiCertSha256Guid; + break; + + case HASHALG_SHA384: + mImageDigestSize = SHA384_DIGEST_SIZE; + mCertType = gEfiCertSha384Guid; + break; + + case HASHALG_SHA512: + mImageDigestSize = SHA512_DIGEST_SIZE; + mCertType = gEfiCertSha512Guid; + break; + + default: + return FALSE; + } + + mHashTypeStr = mHash[HashAlg].Name; + CtxSize = mHash[HashAlg].GetContextSize(); + + HashCtx = AllocatePool (CtxSize); + if (HashCtx == NULL) { + return FALSE; + } + + // 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 + // + + // + // 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 (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase; + NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes; + } else if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // + // Use PE32+ offset. + // + HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase; + NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + } else { + // + // Invalid header magic number. + // + Status = FALSE; + goto Done; + } + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + + // + // 5. Skip over the image checksum (it occupies a single ULONG). + // + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + // + // 6. Since there is no Cert Directory in optional header, hash everything + // from the end of the checksum to the end of image header. + // + if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase); + } + + if (HashSize != 0) { + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + } + } else { + // + // 7. Hash everything from the end of the checksum to the start of the Cert Directory. + // + if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase; + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase; + } + + if (HashSize != 0) { + 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 (mNtHeader.Pe32->OptionalHeader.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) HashBase - (UINTN) mImageBase); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase); + } + + if (HashSize != 0) { + 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 (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders; + } else { + // + // Use PE32+ offset + // + SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders; + } + + + Section = (EFI_IMAGE_SECTION_HEADER *) ( + mImageBase + + mPeCoffHeaderOffset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader + ); + + // + // 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); + if (SectionHeader == NULL) { + Status = FALSE; + goto Done; + } + // + // 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. + // + 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 (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + CertSize = 0; + } else { + if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } else { + // + // Use PE32+ offset. + // + CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } + } + + if (mImageSize > CertSize + SumOfBytesHashed) { + HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed); + + Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize); + if (!Status) { + goto Done; + } + } else if (mImageSize < CertSize + SumOfBytesHashed) { + Status = FALSE; + 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 calculate hash of + Pe/Coff image based on the authenticode image hashing in PE/COFF Specification + 8.0 Appendix A + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image. + @param[in] AuthDataSize Size of the Authenticode Signature in bytes. + + @retval EFI_UNSUPPORTED Hash algorithm is not supported. + @retval EFI_SUCCESS Hash successfully. + +**/ +EFI_STATUS +HashPeImageByType ( + IN UINT8 *AuthData, + IN UINTN AuthDataSize + ) +{ + UINT8 Index; + + 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. + // Fixed offset (+32) is calculated based on two bytes of length encoding. + // + if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) { + // + // Only support two bytes of Long Form of Length Encoding. + // + continue; + } + + if (AuthDataSize < 32 + mHash[Index].OidLength) { + return EFI_UNSUPPORTED; + } + + if (CompareMem (AuthData + 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. Must be zero if Signature is NULL. + +**/ +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_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable; + EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable; + EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry; + UINTN ImageExeInfoTableSize; + UINTN NewImageExeInfoEntrySize; + UINTN NameStringLen; + UINTN DevicePathSize; + CHAR16 *NameStr; + + ImageExeInfoTable = NULL; + NewImageExeInfoTable = NULL; + ImageExeInfoEntry = NULL; + NameStringLen = 0; + NameStr = NULL; + + if (DevicePath == NULL) { + return ; + } + + if (Name != NULL) { + NameStringLen = StrSize (Name); + } else { + NameStringLen = sizeof (CHAR16); + } + + EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable); + if (ImageExeInfoTable != NULL) { + // + // The table has been found! + // We must enlarge the table to accommodate 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); + + // + // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align + // + ASSERT (Signature != NULL || SignatureSize == 0); + NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize; + + NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize); + if (NewImageExeInfoTable == NULL) { + return ; + } + + 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 information. + // + WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action); + WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize); + + NameStr = (CHAR16 *)(ImageExeInfoEntry + 1); + if (Name != NULL) { + CopyMem ((UINT8 *) NameStr, Name, NameStringLen); + } else { + ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16)); + } + + CopyMem ( + (UINT8 *) NameStr + NameStringLen, + DevicePath, + DevicePathSize + ); + if (Signature != NULL) { + CopyMem ( + (UINT8 *) NameStr + NameStringLen + DevicePathSize, + Signature, + SignatureSize + ); + } + // + // Update/replace the image execution table. + // + gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable); + + // + // Free Old table data! + // + if (ImageExeInfoTable != NULL) { + FreePool (ImageExeInfoTable); + } +} + +/** + Check whether the hash of an given X.509 certificate is in forbidden database (DBX). + + @param[in] Certificate Pointer to X.509 Certificate that is searched for. + @param[in] CertSize Size of X.509 Certificate. + @param[in] SignatureList Pointer to the Signature List in forbidden database. + @param[in] SignatureListSize Size of Signature List. + @param[out] RevocationTime Return the time that the certificate was revoked. + @param[out] IsFound Search result. Only valid if EFI_SUCCESS returned. + + @retval EFI_SUCCESS Finished the search without any error. + @retval Others Error occurred in the search of database. + +**/ +EFI_STATUS +IsCertHashFoundInDbx ( + IN UINT8 *Certificate, + IN UINTN CertSize, + IN EFI_SIGNATURE_LIST *SignatureList, + IN UINTN SignatureListSize, + OUT EFI_TIME *RevocationTime, + OUT BOOLEAN *IsFound + ) +{ + EFI_STATUS Status; + EFI_SIGNATURE_LIST *DbxList; + UINTN DbxSize; + EFI_SIGNATURE_DATA *CertHash; + UINTN CertHashCount; + UINTN Index; + UINT32 HashAlg; + VOID *HashCtx; + UINT8 CertDigest[MAX_DIGEST_SIZE]; + UINT8 *DbxCertHash; + UINTN SiglistHeaderSize; + UINT8 *TBSCert; + UINTN TBSCertSize; + + Status = EFI_ABORTED; + *IsFound = FALSE; + DbxList = SignatureList; + DbxSize = SignatureListSize; + HashCtx = NULL; + HashAlg = HASHALG_MAX; + + if ((RevocationTime == NULL) || (DbxList == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Retrieve the TBSCertificate from the X.509 Certificate. + // + if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) { + return Status; + } + + while ((DbxSize > 0) && (SignatureListSize >= DbxList->SignatureListSize)) { + // + // Determine Hash Algorithm of Certificate in the forbidden database. + // + if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) { + HashAlg = HASHALG_SHA256; + } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) { + HashAlg = HASHALG_SHA384; + } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) { + HashAlg = HASHALG_SHA512; + } else { + DbxSize -= DbxList->SignatureListSize; + DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize); + continue; + } + + // + // Calculate the hash value of current TBSCertificate for comparision. + // + if (mHash[HashAlg].GetContextSize == NULL) { + goto Done; + } + ZeroMem (CertDigest, MAX_DIGEST_SIZE); + HashCtx = AllocatePool (mHash[HashAlg].GetContextSize ()); + if (HashCtx == NULL) { + goto Done; + } + if (!mHash[HashAlg].HashInit (HashCtx)) { + goto Done; + } + if (!mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize)) { + goto Done; + } + if (!mHash[HashAlg].HashFinal (HashCtx, CertDigest)) { + goto Done; + } + + FreePool (HashCtx); + HashCtx = NULL; + + SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize; + CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize); + CertHashCount = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize; + for (Index = 0; Index < CertHashCount; Index++) { + // + // Iterate each Signature Data Node within this CertList for verify. + // + DbxCertHash = CertHash->SignatureData; + if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) { + // + // Hash of Certificate is found in forbidden database. + // + Status = EFI_SUCCESS; + *IsFound = TRUE; + + // + // Return the revocation time. + // + CopyMem (RevocationTime, (EFI_TIME *)(DbxCertHash + mHash[HashAlg].DigestLength), sizeof (EFI_TIME)); + goto Done; + } + CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize); + } + + DbxSize -= DbxList->SignatureListSize; + DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize); + } + + Status = EFI_SUCCESS; + +Done: + if (HashCtx != NULL) { + FreePool (HashCtx); + } + + 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 algorithm. + @param[in] SignatureSize Size of Signature. + @param[out] IsFound Search result. Only valid if EFI_SUCCESS returned + + @retval EFI_SUCCESS Finished the search without any error. + @retval Others Error occurred in the search of database. + +**/ +EFI_STATUS +IsSignatureFoundInDatabase ( + IN CHAR16 *VariableName, + IN UINT8 *Signature, + IN EFI_GUID *CertType, + IN UINTN SignatureSize, + OUT BOOLEAN *IsFound + ) +{ + EFI_STATUS Status; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *Cert; + UINTN DataSize; + UINT8 *Data; + UINTN Index; + UINTN CertCount; + + // + // Read signature database variable. + // + *IsFound = FALSE; + Data = NULL; + DataSize = 0; + Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL); + if (Status != EFI_BUFFER_TOO_SMALL) { + if (Status == EFI_NOT_FOUND) { + // + // No database, no need to search. + // + Status = EFI_SUCCESS; + } + + return Status; + } + + Data = (UINT8 *) AllocateZeroPool (DataSize); + if (Data == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data); + if (EFI_ERROR (Status)) { + goto Done; + } + // + // Enumerate all signature data in SigDB to check if signature exists for executable. + // + CertList = (EFI_SIGNATURE_LIST *) Data; + while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { + CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - 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; + // + // Entries in UEFI_IMAGE_SECURITY_DATABASE that are used to validate image should be measured + // + if (StrCmp(VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) { + SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert); + } + 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 Status; +} + +/** + Check whether the timestamp is valid by comparing the signing time and the revocation time. + + @param SigningTime A pointer to the signing time. + @param RevocationTime A pointer to the revocation time. + + @retval TRUE The SigningTime is not later than the RevocationTime. + @retval FALSE The SigningTime is later than the RevocationTime. + +**/ +BOOLEAN +IsValidSignatureByTimestamp ( + IN EFI_TIME *SigningTime, + IN EFI_TIME *RevocationTime + ) +{ + if (SigningTime->Year != RevocationTime->Year) { + return (BOOLEAN) (SigningTime->Year < RevocationTime->Year); + } else if (SigningTime->Month != RevocationTime->Month) { + return (BOOLEAN) (SigningTime->Month < RevocationTime->Month); + } else if (SigningTime->Day != RevocationTime->Day) { + return (BOOLEAN) (SigningTime->Day < RevocationTime->Day); + } else if (SigningTime->Hour != RevocationTime->Hour) { + return (BOOLEAN) (SigningTime->Hour < RevocationTime->Hour); + } else if (SigningTime->Minute != RevocationTime->Minute) { + return (BOOLEAN) (SigningTime->Minute < RevocationTime->Minute); + } + + return (BOOLEAN) (SigningTime->Second <= RevocationTime->Second); +} + +/** + Check if the given time value is zero. + + @param[in] Time Pointer of a time value. + + @retval TRUE The Time is Zero. + @retval FALSE The Time is not Zero. + +**/ +BOOLEAN +IsTimeZero ( + IN EFI_TIME *Time + ) +{ + if ((Time->Year == 0) && (Time->Month == 0) && (Time->Day == 0) && + (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0)) { + return TRUE; + } + + return FALSE; +} + +/** + Check whether the timestamp signature is valid and the signing time is also earlier than + the revocation time. + + @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image. + @param[in] AuthDataSize Size of the Authenticode signature in bytes. + @param[in] RevocationTime The time that the certificate was revoked. + + @retval TRUE Timestamp signature is valid and signing time is no later than the + revocation time. + @retval FALSE Timestamp signature is not valid or the signing time is later than the + revocation time. + +**/ +BOOLEAN +PassTimestampCheck ( + IN UINT8 *AuthData, + IN UINTN AuthDataSize, + IN EFI_TIME *RevocationTime + ) +{ + EFI_STATUS Status; + BOOLEAN VerifyStatus; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *Cert; + UINT8 *DbtData; + UINTN DbtDataSize; + UINT8 *RootCert; + UINTN RootCertSize; + UINTN Index; + UINTN CertCount; + EFI_TIME SigningTime; + + // + // Variable Initialization + // + VerifyStatus = FALSE; + DbtData = NULL; + CertList = NULL; + Cert = NULL; + RootCert = NULL; + RootCertSize = 0; + + // + // If RevocationTime is zero, the certificate shall be considered to always be revoked. + // + if (IsTimeZero (RevocationTime)) { + return FALSE; + } + + // + // RevocationTime is non-zero, the certificate should be considered to be revoked from that time and onwards. + // Using the dbt to get the trusted TSA certificates. + // + DbtDataSize = 0; + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, NULL); + if (Status != EFI_BUFFER_TOO_SMALL) { + goto Done; + } + DbtData = (UINT8 *) AllocateZeroPool (DbtDataSize); + if (DbtData == NULL) { + goto Done; + } + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, (VOID *) DbtData); + if (EFI_ERROR (Status)) { + goto Done; + } + + CertList = (EFI_SIGNATURE_LIST *) DbtData; + while ((DbtDataSize > 0) && (DbtDataSize >= 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 verify. + // + RootCert = Cert->SignatureData; + RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID); + // + // Get the signing time if the timestamp signature is valid. + // + if (ImageTimestampVerify (AuthData, AuthDataSize, RootCert, RootCertSize, &SigningTime)) { + // + // The signer signature is valid only when the signing time is earlier than revocation time. + // + if (IsValidSignatureByTimestamp (&SigningTime, RevocationTime)) { + VerifyStatus = TRUE; + goto Done; + } + } + Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); + } + } + DbtDataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + +Done: + if (DbtData != NULL) { + FreePool (DbtData); + } + + return VerifyStatus; +} + +/** + Check whether the image signature is forbidden by the forbidden database (dbx). + The image is forbidden to load if any certificates for signing are revoked before signing time. + + @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image. + @param[in] AuthDataSize Size of the Authenticode signature in bytes. + + @retval TRUE Image is forbidden by dbx. + @retval FALSE Image is not forbidden by dbx. + +**/ +BOOLEAN +IsForbiddenByDbx ( + IN UINT8 *AuthData, + IN UINTN AuthDataSize + ) +{ + EFI_STATUS Status; + BOOLEAN IsForbidden; + BOOLEAN IsFound; + UINT8 *Data; + UINTN DataSize; + EFI_SIGNATURE_LIST *CertList; + UINTN CertListSize; + EFI_SIGNATURE_DATA *CertData; + UINT8 *RootCert; + UINTN RootCertSize; + UINTN CertCount; + UINTN Index; + UINT8 *CertBuffer; + UINTN BufferLength; + UINT8 *TrustedCert; + UINTN TrustedCertLength; + UINT8 CertNumber; + UINT8 *CertPtr; + UINT8 *Cert; + UINTN CertSize; + EFI_TIME RevocationTime; + // + // Variable Initialization + // + IsForbidden = TRUE; + Data = NULL; + CertList = NULL; + CertData = NULL; + RootCert = NULL; + RootCertSize = 0; + Cert = NULL; + CertBuffer = NULL; + BufferLength = 0; + TrustedCert = NULL; + TrustedCertLength = 0; + + // + // The image will not be forbidden if dbx can't be got. + // + DataSize = 0; + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL); + ASSERT (EFI_ERROR (Status)); + if (Status != EFI_BUFFER_TOO_SMALL) { + if (Status == EFI_NOT_FOUND) { + // + // Evidently not in dbx if the database doesn't exist. + // + IsForbidden = FALSE; + } + return IsForbidden; + } + Data = (UINT8 *) AllocateZeroPool (DataSize); + if (Data == NULL) { + return IsForbidden; + } + + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Verify image signature with RAW X509 certificates in DBX database. + // If passed, the image will be forbidden. + // + CertList = (EFI_SIGNATURE_LIST *) Data; + CertListSize = DataSize; + while ((CertListSize > 0) && (CertListSize >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { + CertData = (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 verify. + // + RootCert = CertData->SignatureData; + RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID); + + // + // Call AuthenticodeVerify library to Verify Authenticode struct. + // + IsForbidden = AuthenticodeVerify ( + AuthData, + AuthDataSize, + RootCert, + RootCertSize, + mImageDigest, + mImageDigestSize + ); + if (IsForbidden) { + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is forbidden by DBX.\n")); + goto Done; + } + + CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize); + } + } + + CertListSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + + // + // Check X.509 Certificate Hash & Possible Timestamp. + // + + // + // Retrieve the certificate stack from AuthData + // The output CertStack format will be: + // UINT8 CertNumber; + // UINT32 Cert1Length; + // UINT8 Cert1[]; + // UINT32 Cert2Length; + // UINT8 Cert2[]; + // ... + // UINT32 CertnLength; + // UINT8 Certn[]; + // + Pkcs7GetSigners (AuthData, AuthDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength); + if ((BufferLength == 0) || (CertBuffer == NULL) || (*CertBuffer) == 0) { + IsForbidden = TRUE; + goto Done; + } + + // + // Check if any hash of certificates embedded in AuthData is in the forbidden database. + // + CertNumber = (UINT8) (*CertBuffer); + CertPtr = CertBuffer + 1; + for (Index = 0; Index < CertNumber; Index++) { + CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr); + Cert = (UINT8 *)CertPtr + sizeof (UINT32); + // + // Advance CertPtr to the next cert in image signer's cert list + // + CertPtr = CertPtr + sizeof (UINT32) + CertSize; + + Status = IsCertHashFoundInDbx (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime, &IsFound); + if (EFI_ERROR (Status)) { + // + // Error in searching dbx. Consider it as 'found'. RevocationTime might + // not be valid in such situation. + // + IsForbidden = TRUE; + } else if (IsFound) { + // + // Found Cert in dbx successfully. Check the timestamp signature and + // signing time to determine if the image can be trusted. + // + if (PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime)) { + IsForbidden = FALSE; + // + // Pass DBT check. Continue to check other certs in image signer's cert list against DBX, DBT + // + continue; + } else { + IsForbidden = TRUE; + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature failed the timestamp check.\n")); + goto Done; + } + } + + } + + IsForbidden = FALSE; + +Done: + if (Data != NULL) { + FreePool (Data); + } + + Pkcs7FreeSigners (CertBuffer); + Pkcs7FreeSigners (TrustedCert); + + return IsForbidden; +} + + +/** + Check whether the image signature can be verified by the trusted certificates in DB database. + + @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image. + @param[in] AuthDataSize Size of the Authenticode signature in bytes. + + @retval TRUE Image passed verification using certificate in db. + @retval FALSE Image didn't pass verification using certificate in db. + +**/ +BOOLEAN +IsAllowedByDb ( + IN UINT8 *AuthData, + IN UINTN AuthDataSize + ) +{ + EFI_STATUS Status; + BOOLEAN VerifyStatus; + BOOLEAN IsFound; + EFI_SIGNATURE_LIST *CertList; + EFI_SIGNATURE_DATA *CertData; + UINTN DataSize; + UINT8 *Data; + UINT8 *RootCert; + UINTN RootCertSize; + UINTN Index; + UINTN CertCount; + UINTN DbxDataSize; + UINT8 *DbxData; + EFI_TIME RevocationTime; + + Data = NULL; + CertList = NULL; + CertData = NULL; + RootCert = NULL; + DbxData = NULL; + RootCertSize = 0; + VerifyStatus = FALSE; + + // + // Fetch 'db' content. If 'db' doesn't exist or encounters problem to get the + // data, return not-allowed-by-db (FALSE). + // + DataSize = 0; + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL); + ASSERT (EFI_ERROR (Status)); + if (Status != EFI_BUFFER_TOO_SMALL) { + return VerifyStatus; + } + + Data = (UINT8 *) AllocateZeroPool (DataSize); + if (Data == NULL) { + return VerifyStatus; + } + + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Fetch 'dbx' content. If 'dbx' doesn't exist, continue to check 'db'. + // If any other errors occurred, no need to check 'db' but just return + // not-allowed-by-db (FALSE) to avoid bypass. + // + DbxDataSize = 0; + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL); + ASSERT (EFI_ERROR (Status)); + if (Status != EFI_BUFFER_TOO_SMALL) { + if (Status != EFI_NOT_FOUND) { + goto Done; + } + // + // 'dbx' does not exist. Continue to check 'db'. + // + } else { + // + // 'dbx' exists. Get its content. + // + DbxData = (UINT8 *) AllocateZeroPool (DbxDataSize); + if (DbxData == NULL) { + goto Done; + } + + Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data. + // + CertList = (EFI_SIGNATURE_LIST *) Data; + while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) { + if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { + CertData = (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 verify. + // + RootCert = CertData->SignatureData; + RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID); + + // + // Call AuthenticodeVerify library to Verify Authenticode struct. + // + VerifyStatus = AuthenticodeVerify ( + AuthData, + AuthDataSize, + RootCert, + RootCertSize, + mImageDigest, + mImageDigestSize + ); + if (VerifyStatus) { + // + // The image is signed and its signature is found in 'db'. + // + if (DbxData != NULL) { + // + // Here We still need to check if this RootCert's Hash is revoked + // + Status = IsCertHashFoundInDbx (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime, &IsFound); + if (EFI_ERROR (Status)) { + // + // Error in searching dbx. Consider it as 'found'. RevocationTime might + // not be valid in such situation. + // + VerifyStatus = FALSE; + } else if (IsFound) { + // + // Check the timestamp signature and signing time to determine if the RootCert can be trusted. + // + VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime); + if (!VerifyStatus) { + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed and signature is accepted by DB, but its root cert failed the timestamp check.\n")); + } + } + } + + // + // There's no 'dbx' to check revocation time against (must-be pass), + // or, there's revocation time found in 'dbx' and checked againt 'dbt' + // (maybe pass or fail, depending on timestamp compare result). Either + // way the verification job has been completed at this point. + // + goto Done; + } + + CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize); + } + } + + DataSize -= CertList->SignatureListSize; + CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); + } + +Done: + + if (VerifyStatus) { + SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData); + } + + if (Data != NULL) { + FreePool (Data); + } + if (DbxData != NULL) { + FreePool (DbxData); + } + + return VerifyStatus; +} + +/** + 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. + + The image verification policy is: + If the image is signed, + At least one valid signature or at least one hash value of the image must match a record + in the security database "db", and no valid signature nor any hash value of the image may + be reflected in the security database "dbx". + Otherwise, the image is not signed, + The SHA256 hash value of the image must match a record in the security database "db", and + not be reflected in the security data base "dbx". + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + @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. + @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service. + + @retval EFI_SUCCESS The file specified by DevicePath and non-NULL + FileBuffer did authenticate, and the platform policy dictates + that the DXE Foundation may use the file. + @retval EFI_SUCCESS The device path specified by NULL device path DevicePath + and non-NULL FileBuffer did authenticate, and the platform + policy dictates that the DXE Foundation may execute the image in + FileBuffer. + @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. The image has been added to the file + execution table. + @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not + authenticate, and the platform policy dictates that the DXE + Foundation may not use File. The image has + been added to the file execution table. + +**/ +EFI_STATUS +EFIAPI +DxeImageVerificationHandler ( + IN UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File, OPTIONAL + IN VOID *FileBuffer, + IN UINTN FileSize, + IN BOOLEAN BootPolicy + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + BOOLEAN IsVerified; + EFI_SIGNATURE_LIST *SignatureList; + UINTN SignatureListSize; + EFI_SIGNATURE_DATA *Signature; + EFI_IMAGE_EXECUTION_ACTION Action; + WIN_CERTIFICATE *WinCertificate; + UINT32 Policy; + UINT8 *SecureBoot; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINT32 NumberOfRvaAndSizes; + WIN_CERTIFICATE_EFI_PKCS *PkcsCertData; + WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid; + UINT8 *AuthData; + UINTN AuthDataSize; + EFI_IMAGE_DATA_DIRECTORY *SecDataDir; + UINT32 SecDataDirEnd; + UINT32 SecDataDirLeft; + UINT32 OffSet; + CHAR16 *NameStr; + RETURN_STATUS PeCoffStatus; + EFI_STATUS HashStatus; + EFI_STATUS DbStatus; + BOOLEAN IsFound; + + SignatureList = NULL; + SignatureListSize = 0; + WinCertificate = NULL; + SecDataDir = NULL; + PkcsCertData = NULL; + Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED; + IsVerified = FALSE; + IsFound = FALSE; + + // + // 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; + } + if (Policy == NEVER_EXECUTE) { + return EFI_ACCESS_DENIED; + } + + // + // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION + // violates the UEFI spec and has been removed. + // + ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION); + if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) { + CpuDeadLoop (); + } + + GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL); + // + // Skip verification if SecureBoot variable doesn't exist. + // + if (SecureBoot == NULL) { + return EFI_SUCCESS; + } + + // + // Skip verification if SecureBoot is disabled but not AuditMode + // + if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) { + FreePool (SecureBoot); + return EFI_SUCCESS; + } + FreePool (SecureBoot); + + // + // Read the Dos header. + // + if (FileBuffer == NULL) { + return EFI_ACCESS_DENIED; + } + + mImageBase = (UINT8 *) FileBuffer; + mImageSize = FileSize; + + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead; + + // + // Get information about the image being loaded + // + PeCoffStatus = PeCoffLoaderGetImageInfo (&ImageContext); + if (RETURN_ERROR (PeCoffStatus)) { + // + // The information can't be got from the invalid PeImage + // + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: PeImage invalid. Cannot retrieve image information.\n")); + goto Failed; + } + + 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. + // + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Not a valid PE/COFF image.\n")); + goto Failed; + } + + if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes; + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + } else { + // + // Use PE32+ offset. + // + NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]; + } + } + + // + // Start Image Validation. + // + if (SecDataDir == NULL || SecDataDir->Size == 0) { + // + // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db", + // and not be reflected in the security data base "dbx". + // + if (!HashPeImage (HASHALG_SHA256)) { + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Failed to hash this image using %s.\n", mHashTypeStr)); + goto Failed; + } + + DbStatus = IsSignatureFoundInDatabase ( + EFI_IMAGE_SECURITY_DATABASE1, + mImageDigest, + &mCertType, + mImageDigestSize, + &IsFound + ); + if (EFI_ERROR (DbStatus) || IsFound) { + // + // Image Hash is in forbidden database (DBX). + // + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is forbidden by DBX.\n", mHashTypeStr)); + goto Failed; + } + + DbStatus = IsSignatureFoundInDatabase ( + EFI_IMAGE_SECURITY_DATABASE, + mImageDigest, + &mCertType, + mImageDigestSize, + &IsFound + ); + if (!EFI_ERROR (DbStatus) && IsFound) { + // + // Image Hash is in allowed database (DB). + // + return EFI_SUCCESS; + } + + // + // Image Hash is not found in both forbidden and allowed database. + // + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is not found in DB/DBX.\n", mHashTypeStr)); + goto Failed; + } + + // + // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7 + // "Attribute Certificate Table". + // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file. + // + SecDataDirEnd = SecDataDir->VirtualAddress + SecDataDir->Size; + for (OffSet = SecDataDir->VirtualAddress; + OffSet < SecDataDirEnd; + OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) { + SecDataDirLeft = SecDataDirEnd - OffSet; + if (SecDataDirLeft <= sizeof (WIN_CERTIFICATE)) { + break; + } + WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet); + if (SecDataDirLeft < WinCertificate->dwLength || + (SecDataDirLeft - WinCertificate->dwLength < + ALIGN_SIZE (WinCertificate->dwLength))) { + break; + } + + // + // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported. + // + if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) { + // + // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the + // Authenticode specification. + // + PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate; + if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) { + break; + } + AuthData = PkcsCertData->CertData; + AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr); + } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) { + // + // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec. + // + WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate; + if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) { + break; + } + if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) { + continue; + } + AuthData = WinCertUefiGuid->CertData; + AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData); + } else { + if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) { + break; + } + continue; + } + + HashStatus = HashPeImageByType (AuthData, AuthDataSize); + if (EFI_ERROR (HashStatus)) { + continue; + } + + // + // Check the digital signature against the revoked certificate in forbidden database (dbx). + // + if (IsForbiddenByDbx (AuthData, AuthDataSize)) { + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED; + IsVerified = FALSE; + break; + } + + // + // Check the digital signature against the valid certificate in allowed database (db). + // + if (!IsVerified) { + if (IsAllowedByDb (AuthData, AuthDataSize)) { + IsVerified = TRUE; + } + } + + // + // Check the image's hash value. + // + DbStatus = IsSignatureFoundInDatabase ( + EFI_IMAGE_SECURITY_DATABASE1, + mImageDigest, + &mCertType, + mImageDigestSize, + &IsFound + ); + if (EFI_ERROR (DbStatus) || IsFound) { + Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND; + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but %s hash of image is found in DBX.\n", mHashTypeStr)); + IsVerified = FALSE; + break; + } + + if (!IsVerified) { + DbStatus = IsSignatureFoundInDatabase ( + EFI_IMAGE_SECURITY_DATABASE, + mImageDigest, + &mCertType, + mImageDigestSize, + &IsFound + ); + if (!EFI_ERROR (DbStatus) && IsFound) { + IsVerified = TRUE; + } else { + DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is not allowed by DB and %s hash of image is not found in DB/DBX.\n", mHashTypeStr)); + } + } + } + + if (OffSet != SecDataDirEnd) { + // + // The Size in Certificate Table or the attribute certificate table is corrupted. + // + IsVerified = FALSE; + } + + if (IsVerified) { + return EFI_SUCCESS; + } + if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) { + // + // Get image hash value as signature of executable. + // + SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize; + SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize); + if (SignatureList == NULL) { + SignatureListSize = 0; + goto Failed; + } + SignatureList->SignatureHeaderSize = 0; + SignatureList->SignatureListSize = (UINT32) SignatureListSize; + SignatureList->SignatureSize = (UINT32) (sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize); + CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID)); + Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST)); + CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize); + } + +Failed: + // + // Policy decides to defer or reject the image; add its information in image + // executable information table in either case. + // + NameStr = ConvertDevicePathToText (File, FALSE, TRUE); + AddImageExeInfo (Action, NameStr, File, SignatureList, SignatureListSize); + if (NameStr != NULL) { + DEBUG ((DEBUG_INFO, "The image doesn't pass verification: %s\n", NameStr)); + FreePool(NameStr); + } + + if (SignatureList != NULL) { + FreePool (SignatureList); + } + + if (Policy == DEFER_EXECUTE_ON_SECURITY_VIOLATION) { + return EFI_SECURITY_VIOLATION; + } + return EFI_ACCESS_DENIED; +} + +/** + On Ready To Boot Services Event notification handler. + + Add the image execution information table if it is not in system configuration table. + + @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_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable; + UINTN ImageExeInfoTableSize; + + EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable); + if (ImageExeInfoTable != NULL) { + return; + } + + ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE); + ImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize); + if (ImageExeInfoTable == NULL) { + return ; + } + + ImageExeInfoTable->NumberOfImages = 0; + gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) ImageExeInfoTable); + +} + +/** + 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 + ) +{ + EFI_EVENT Event; + + // + // Register the event to publish the image execution table. + // + EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + OnReadyToBoot, + NULL, + &Event + ); + + return RegisterSecurity2Handler ( + DxeImageVerificationHandler, + EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h new file mode 100644 index 00000000..6a879e12 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/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 - 2014, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __IMAGEVERIFICATIONLIB_H__ +#define __IMAGEVERIFICATIONLIB_H__ + +#include <Library/UefiDriverEntryPoint.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/BaseLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/PcdLib.h> +#include <Library/DevicePathLib.h> +#include <Library/SecurityManagementLib.h> +#include <Library/PeCoffLib.h> +#include <Protocol/FirmwareVolume2.h> +#include <Protocol/DevicePath.h> +#include <Protocol/BlockIo.h> +#include <Protocol/SimpleFileSystem.h> +#include <Protocol/VariableWrite.h> +#include <Guid/ImageAuthentication.h> +#include <Guid/AuthenticatedVariableFormat.h> +#include <IndustryStandard/PeImage.h> + +#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256 +#define EFI_CERT_TYPE_RSA2048_SIZE 256 +#define MAX_NOTIFY_STRING_LEN 64 +#define TWO_BYTE_ENCODE 0x82 + +#define ALIGNMENT_SIZE 8 +#define ALIGN_SIZE(a) (((a) % ALIGNMENT_SIZE) ? ALIGNMENT_SIZE - ((a) % ALIGNMENT_SIZE) : 0) + +// +// 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 SHA512 Output (64 bytes) by far +// +#define MAX_DIGEST_SIZE SHA512_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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf new file mode 100644 index 00000000..e520d7e3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf @@ -0,0 +1,95 @@ +## @file +# Provides security service of image verification +# +# This library hooks LoadImage() API to verify every image by the verification policy. +# +# Caution: This module requires additional review when modified. +# This library will have external input - PE/COFF image. +# This external input must be validated carefully to avoid security issues such as +# buffer overflow or integer overflow. +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeImageVerificationLib + MODULE_UNI_FILE = DxeImageVerificationLib.uni + FILE_GUID = 0CA970E1-43FA-4402-BC0A-81AF336BFFD6 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER DXE_RUNTIME_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 EBC +# + +[Sources] + DxeImageVerificationLib.c + DxeImageVerificationLib.h + Measurement.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + DevicePathLib + BaseCryptLib + SecurityManagementLib + PeCoffLib + TpmMeasurementLib + +[Protocols] + gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + ## SOMETIMES_CONSUMES ## Variable:L"DB" + ## SOMETIMES_CONSUMES ## Variable:L"DBX" + ## SOMETIMES_CONSUMES ## Variable:L"DBT" + ## PRODUCES ## SystemTable + ## CONSUMES ## SystemTable + gEfiImageSecurityDatabaseGuid + + ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. + ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature. + gEfiCertSha1Guid + + ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. + ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature. + gEfiCertSha256Guid + + ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. + ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature. + gEfiCertSha384Guid + + ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. + ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature. + gEfiCertSha512Guid + + gEfiCertX509Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. + gEfiCertX509Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. + gEfiCertX509Sha384Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. + gEfiCertX509Sha512Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature. + gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate. + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy ## SOMETIMES_CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.uni new file mode 100644 index 00000000..6739b2ab --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.uni @@ -0,0 +1,21 @@ +// /** @file
+// Provides security service of image verification
+//
+// This library hooks LoadImage() API to verify every image by the verification policy.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - PE/COFF image.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service of image verification"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library hooks LoadImage() API to verify every image by the verification policy. Caution: This module requires additional review when modified. This library will have external input - PE/COFF image. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c new file mode 100644 index 00000000..4603e9d4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c @@ -0,0 +1,315 @@ +/** @file + Measure TCG required variable. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Guid/ImageAuthentication.h> +#include <IndustryStandard/UefiTcgPlatform.h> + +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseLib.h> +#include <Library/TpmMeasurementLib.h> + +typedef struct { + CHAR16 *VariableName; + EFI_GUID *VendorGuid; +} VARIABLE_TYPE; + +typedef struct { + CHAR16 *VariableName; + EFI_GUID *VendorGuid; + VOID *Data; + UINTN Size; +} VARIABLE_RECORD; + +#define MEASURED_AUTHORITY_COUNT_MAX 0x100 + +UINTN mMeasuredAuthorityCount = 0; +UINTN mMeasuredAuthorityCountMax = 0; +VARIABLE_RECORD *mMeasuredAuthorityList = NULL; + +VARIABLE_TYPE mVariableType[] = { + {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid}, +}; + +/** + This function will check if VarName should be recorded and return the address of VarName if it is needed. + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + + @return the address of VarName. +**/ +CHAR16 * +AssignVarName ( + IN CHAR16 *VarName + ) +{ + UINTN Index; + + for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) { + if (StrCmp (VarName, mVariableType[Index].VariableName) == 0) { + return mVariableType[Index].VariableName; + } + } + + return NULL; +} + +/** + This function will check if VendorGuid should be recorded and return the address of VendorGuid if it is needed. + + @param[in] VendorGuid A unique identifier for the vendor. + + @return the address of VendorGuid. +**/ +EFI_GUID * +AssignVendorGuid ( + IN EFI_GUID *VendorGuid + ) +{ + UINTN Index; + + for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) { + if (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid)) { + return mVariableType[Index].VendorGuid; + } + } + + return NULL; +} + +/** + This function will add variable information to MeasuredAuthorityList. + + @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. +**/ +EFI_STATUS +AddDataMeasured ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN Size + ) +{ + VARIABLE_RECORD *NewMeasuredAuthorityList; + + ASSERT (mMeasuredAuthorityCount <= mMeasuredAuthorityCountMax); + if (mMeasuredAuthorityCount == mMeasuredAuthorityCountMax) { + // + // Need enlarge + // + NewMeasuredAuthorityList = AllocateZeroPool (sizeof(VARIABLE_RECORD) * (mMeasuredAuthorityCountMax + MEASURED_AUTHORITY_COUNT_MAX)); + if (NewMeasuredAuthorityList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + if (mMeasuredAuthorityList != NULL) { + CopyMem (NewMeasuredAuthorityList, mMeasuredAuthorityList, sizeof(VARIABLE_RECORD) * mMeasuredAuthorityCount); + FreePool (mMeasuredAuthorityList); + } + mMeasuredAuthorityList = NewMeasuredAuthorityList; + mMeasuredAuthorityCountMax += MEASURED_AUTHORITY_COUNT_MAX; + } + + // + // Add new entry + // + mMeasuredAuthorityList[mMeasuredAuthorityCount].VariableName = AssignVarName (VarName); + mMeasuredAuthorityList[mMeasuredAuthorityCount].VendorGuid = AssignVendorGuid (VendorGuid); + mMeasuredAuthorityList[mMeasuredAuthorityCount].Size = Size; + mMeasuredAuthorityList[mMeasuredAuthorityCount].Data = AllocatePool (Size); + if (mMeasuredAuthorityList[mMeasuredAuthorityCount].Data == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CopyMem (mMeasuredAuthorityList[mMeasuredAuthorityCount].Data, Data, Size); + mMeasuredAuthorityCount++; + + return EFI_SUCCESS; +} + +/** + This function will return if this variable is already measured. + + @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 TRUE The data is already measured. + @retval FALSE The data is not measured yet. +**/ +BOOLEAN +IsDataMeasured ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + IN VOID *Data, + IN UINTN Size + ) +{ + UINTN Index; + + for (Index = 0; Index < mMeasuredAuthorityCount; Index++) { + if ((StrCmp (VarName, mMeasuredAuthorityList[Index].VariableName) == 0) && + (CompareGuid (VendorGuid, mMeasuredAuthorityList[Index].VendorGuid)) && + (CompareMem (Data, mMeasuredAuthorityList[Index].Data, Size) == 0) && + (Size == mMeasuredAuthorityList[Index].Size)) { + return TRUE; + } + } + + return FALSE; +} + +/** + This function will return if this variable is SecureAuthority Variable. + + @param[in] VariableName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + + @retval TRUE This is SecureAuthority Variable + @retval FALSE This is not SecureAuthority Variable +**/ +BOOLEAN +IsSecureAuthorityVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid + ) +{ + UINTN Index; + + for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) { + if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) && + (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) { + return TRUE; + } + } + return FALSE; +} + +/** + Measure and log an EFI variable, and extend the measurement result into a specific PCR. + + @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 CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + IN VOID *VarData, + IN UINTN VarSize + ) +{ + EFI_STATUS Status; + UINTN VarNameLength; + UEFI_VARIABLE_DATA *VarLog; + UINT32 VarLogSize; + + // + // The UEFI_VARIABLE_DATA.VariableData value shall be the EFI_SIGNATURE_DATA value + // from the EFI_SIGNATURE_LIST that contained the authority that was used to validate the image + // + VarNameLength = StrLen (VarName); + VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize + - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); + + VarLog = (UEFI_VARIABLE_DATA *) AllocateZeroPool (VarLogSize); + if (VarLog == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (&VarLog->VariableName, VendorGuid, sizeof(VarLog->VariableName)); + VarLog->UnicodeNameLength = VarNameLength; + VarLog->VariableDataLength = VarSize; + CopyMem ( + VarLog->UnicodeName, + VarName, + VarNameLength * sizeof (*VarName) + ); + CopyMem ( + (CHAR16 *)VarLog->UnicodeName + VarNameLength, + VarData, + VarSize + ); + + DEBUG ((EFI_D_INFO, "DxeImageVerification: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_AUTHORITY)); + DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); + + Status = TpmMeasureAndLogData ( + 7, + EV_EFI_VARIABLE_AUTHORITY, + VarLog, + VarLogSize, + VarLog, + VarLogSize + ); + FreePool (VarLog); + + return Status; +} + +/** + SecureBoot Hook for processing image verification. + + @param[in] VariableName Name of Variable to be found. + @param[in] VendorGuid Variable vendor GUID. + @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. + +**/ +VOID +EFIAPI +SecureBootHook ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINTN DataSize, + IN VOID *Data + ) +{ + EFI_STATUS Status; + + if (!IsSecureAuthorityVariable (VariableName, VendorGuid)) { + return ; + } + + if (IsDataMeasured (VariableName, VendorGuid, Data, DataSize)) { + DEBUG ((EFI_D_ERROR, "MeasureSecureAuthorityVariable - IsDataMeasured\n")); + return ; + } + + Status = MeasureVariable ( + VariableName, + VendorGuid, + Data, + DataSize + ); + DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status)); + + if (!EFI_ERROR (Status)) { + AddDataMeasured (VariableName, VendorGuid, Data, DataSize); + } + + return ; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c new file mode 100644 index 00000000..801f17d5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c @@ -0,0 +1,396 @@ +/** @file + + This library registers RSA 2048 SHA 256 guided section handler + to parse RSA 2048 SHA 256 encapsulation section and extract raw data. + It uses the BaseCryptLib based on OpenSSL to authenticate the signature. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Protocol/Hash.h> +#include <Protocol/SecurityPolicy.h> +#include <Library/ExtractGuidedSectionLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/PcdLib.h> +#include <Guid/WinCertificate.h> +#include <Library/BaseCryptLib.h> +#include <Library/PerformanceLib.h> +#include <Guid/SecurityPkgTokenSpace.h> + +/// +/// RSA 2048 SHA 256 Guided Section header +/// +typedef struct { + EFI_GUID_DEFINED_SECTION GuidedSectionHeader; ///< EFI guided section header + EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature +} RSA_2048_SHA_256_SECTION_HEADER; + +typedef struct { + EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header + EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature +} RSA_2048_SHA_256_SECTION2_HEADER; + +/// +/// Public Exponent of RSA Key. +/// +CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 }; + +/** + + GetInfo gets raw data size and attribute of the input guided section. + It first checks whether the input guid section is supported. + If not, EFI_INVALID_PARAMETER will return. + + @param InputSection Buffer containing the input GUIDed section to be processed. + @param OutputBufferSize The size of OutputBuffer. + @param ScratchBufferSize The size of ScratchBuffer. + @param SectionAttribute The attribute of the input guided section. + + @retval EFI_SUCCESS The size of destination buffer, the size of scratch buffer and + the attribute of the input section are successfully retrieved. + @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid. + +**/ +EFI_STATUS +EFIAPI +Rsa2048Sha256GuidedSectionGetInfo ( + IN CONST VOID *InputSection, + OUT UINT32 *OutputBufferSize, + OUT UINT32 *ScratchBufferSize, + OUT UINT16 *SectionAttribute + ) +{ + if (IS_SECTION2 (InputSection)) { + // + // Check whether the input guid section is recognized. + // + if (!CompareGuid ( + &gEfiCertTypeRsa2048Sha256Guid, + &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) { + return EFI_INVALID_PARAMETER; + } + // + // Retrieve the size and attribute of the input section data. + // + *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes; + *ScratchBufferSize = 0; + *OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION2_HEADER); + } else { + // + // Check whether the input guid section is recognized. + // + if (!CompareGuid ( + &gEfiCertTypeRsa2048Sha256Guid, + &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) { + return EFI_INVALID_PARAMETER; + } + // + // Retrieve the size and attribute of the input section data. + // + *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes; + *ScratchBufferSize = 0; + *OutputBufferSize = SECTION_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION_HEADER); + } + + return EFI_SUCCESS; +} + +/** + + Extraction handler tries to extract raw data from the input guided section. + It also does authentication check for RSA 2048 SHA 256 signature in the input guided section. + It first checks whether the input guid section is supported. + If not, EFI_INVALID_PARAMETER will return. + + @param InputSection Buffer containing the input GUIDed section to be processed. + @param OutputBuffer Buffer to contain the output raw data allocated by the caller. + @param ScratchBuffer A pointer to a caller-allocated buffer for function internal use. + @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the + authentication status of the output buffer. + + @retval EFI_SUCCESS Section Data and Auth Status is extracted successfully. + @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid. + +**/ +EFI_STATUS +EFIAPI +Rsa2048Sha256GuidedSectionHandler ( + IN CONST VOID *InputSection, + OUT VOID **OutputBuffer, + IN VOID *ScratchBuffer, OPTIONAL + OUT UINT32 *AuthenticationStatus + ) +{ + EFI_STATUS Status; + UINT32 OutputBufferSize; + VOID *DummyInterface; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlockRsa2048Sha256; + BOOLEAN CryptoStatus; + UINT8 Digest[SHA256_DIGEST_SIZE]; + UINT8 *PublicKey; + UINTN PublicKeyBufferSize; + VOID *HashContext; + VOID *Rsa; + + HashContext = NULL; + Rsa = NULL; + + if (IS_SECTION2 (InputSection)) { + // + // Check whether the input guid section is recognized. + // + if (!CompareGuid ( + &gEfiCertTypeRsa2048Sha256Guid, + &(((EFI_GUID_DEFINED_SECTION2 *)InputSection)->SectionDefinitionGuid))) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the RSA 2048 SHA 256 information. + // + CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION2_HEADER *) InputSection)->CertBlockRsa2048Sha256; + OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION2_HEADER); + if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) { + PERF_INMODULE_BEGIN ("DxeRsaCopy"); + CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER), OutputBufferSize); + PERF_INMODULE_END ("DxeRsaCopy"); + } else { + *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER); + } + + // + // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set + // + ASSERT ((((EFI_GUID_DEFINED_SECTION2 *)InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0); + *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED; + } else { + // + // Check whether the input guid section is recognized. + // + if (!CompareGuid ( + &gEfiCertTypeRsa2048Sha256Guid, + &(((EFI_GUID_DEFINED_SECTION *)InputSection)->SectionDefinitionGuid))) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the RSA 2048 SHA 256 information. + // + CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION_HEADER *)InputSection)->CertBlockRsa2048Sha256; + OutputBufferSize = SECTION_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION_HEADER); + if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) { + PERF_INMODULE_BEGIN ("DxeRsaCopy"); + CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER), OutputBufferSize); + PERF_INMODULE_END ("DxeRsaCopy"); + } else { + *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER); + } + + // + // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set + // + ASSERT ((((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0); + *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED; + } + + // + // Check whether there exists EFI_SECURITY_POLICY_PROTOCOL_GUID. + // + Status = gBS->LocateProtocol (&gEfiSecurityPolicyProtocolGuid, NULL, &DummyInterface); + if (!EFI_ERROR (Status)) { + // + // If SecurityPolicy Protocol exist, AUTH platform override bit is set. + // + *AuthenticationStatus |= EFI_AUTH_STATUS_PLATFORM_OVERRIDE; + + return EFI_SUCCESS; + } + + // + // All paths from here return EFI_SUCCESS and result is returned in AuthenticationStatus + // + Status = EFI_SUCCESS; + + // + // Fail if the HashType is not SHA 256 + // + if (!CompareGuid (&gEfiHashAlgorithmSha256Guid, &CertBlockRsa2048Sha256->HashType)) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: HASH type of section is not supported\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Allocate hash context buffer required for SHA 256 + // + HashContext = AllocatePool (Sha256GetContextSize ()); + if (HashContext == NULL) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Can not allocate hash context\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Hash public key from data payload with SHA256. + // + ZeroMem (Digest, SHA256_DIGEST_SIZE); + CryptoStatus = Sha256Init (HashContext); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Init() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey)); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Update() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + CryptoStatus = Sha256Final (HashContext, Digest); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Final() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Fail if the PublicKey is not one of the public keys in PcdRsa2048Sha256PublicKeyBuffer + // + PublicKey = (UINT8 *)PcdGetPtr (PcdRsa2048Sha256PublicKeyBuffer); + DEBUG ((DEBUG_VERBOSE, "DxePcdRsa2048Sha256: PublicKeyBuffer = %p\n", PublicKey)); + ASSERT (PublicKey != NULL); + DEBUG ((DEBUG_VERBOSE, "DxePcdRsa2048Sha256: PublicKeyBuffer Token = %08x\n", PcdToken (PcdRsa2048Sha256PublicKeyBuffer))); + PublicKeyBufferSize = PcdGetSize (PcdRsa2048Sha256PublicKeyBuffer); + DEBUG ((DEBUG_VERBOSE, "DxePcdRsa2048Sha256: PublicKeyBuffer Size = %08x\n", PublicKeyBufferSize)); + ASSERT ((PublicKeyBufferSize % SHA256_DIGEST_SIZE) == 0); + CryptoStatus = FALSE; + while (PublicKeyBufferSize != 0) { + if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) { + CryptoStatus = TRUE; + break; + } + PublicKey = PublicKey + SHA256_DIGEST_SIZE; + PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE; + } + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Public key in section is not supported\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Generate & Initialize RSA Context. + // + Rsa = RsaNew (); + if (Rsa == NULL) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaNew() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Set RSA Key Components. + // NOTE: Only N and E are needed to be set as RSA public key for signature verification. + // + CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey)); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE)); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Hash data payload with SHA256. + // + ZeroMem (Digest, SHA256_DIGEST_SIZE); + CryptoStatus = Sha256Init (HashContext); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Init() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + PERF_INMODULE_BEGIN ("DxeRsaShaData"); + CryptoStatus = Sha256Update (HashContext, *OutputBuffer, OutputBufferSize); + PERF_INMODULE_END ("DxeRsaShaData"); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Update() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + CryptoStatus = Sha256Final (HashContext, Digest); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Final() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Verify the RSA 2048 SHA 256 signature. + // + PERF_INMODULE_BEGIN ("DxeRsaVerify"); + CryptoStatus = RsaPkcs1Verify ( + Rsa, + Digest, + SHA256_DIGEST_SIZE, + CertBlockRsa2048Sha256->Signature, + sizeof (CertBlockRsa2048Sha256->Signature) + ); + PERF_INMODULE_END ("DxeRsaVerify"); + if (!CryptoStatus) { + // + // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set. + // + DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaPkcs1Verify() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + } + +Done: + // + // Free allocated resources used to perform RSA 2048 SHA 256 signature verification + // + if (Rsa != NULL) { + RsaFree (Rsa); + } + if (HashContext != NULL) { + FreePool (HashContext); + } + + DEBUG ((DEBUG_VERBOSE, "DxeRsa2048Sha256: Status = %r AuthenticationStatus = %08x\n", Status, *AuthenticationStatus)); + + return Status; +} + +/** + Register the handler to extract RSA 2048 SHA 256 guided section. + + @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 Not enough memory to register this handler. +**/ +EFI_STATUS +EFIAPI +DxeRsa2048Sha256GuidedSectionExtractLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return ExtractGuidedSectionRegisterHandlers ( + &gEfiCertTypeRsa2048Sha256Guid, + Rsa2048Sha256GuidedSectionGetInfo, + Rsa2048Sha256GuidedSectionHandler + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.inf new file mode 100644 index 00000000..72f254f7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.inf @@ -0,0 +1,57 @@ +## @file +# This library doesn't produce any library class. The constructor function uses +# ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler +# that parses RSA 2048 SHA 256 encapsulation section and extracts raw data. +# +# It uses the BaseCryptLib based on OpenSSL to authenticate the signature. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeRsa2048Sha256GuidedSectionExtractLib + FILE_GUID = 0AD6C423-4732-4cf3-9CE3-0A5416D634A5 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = DxeRsa2048Sha256GuidedSectionExtractLibConstructor + MODULE_UNI_FILE = DxeRsa2048Sha256GuidedSectionExtractLib.uni + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + DxeRsa2048Sha256GuidedSectionExtractLib.c + +[Packages] + MdePkg/MdePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + ExtractGuidedSectionLib + UefiBootServicesTableLib + DebugLib + BaseMemoryLib + MemoryAllocationLib + BaseCryptLib + PcdLib + PerformanceLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdRsa2048Sha256PublicKeyBuffer ## SOMETIMES_CONSUMES + +[Protocols] + gEfiSecurityPolicyProtocolGuid ## SOMETIMES_CONSUMES (Set platform override AUTH status if exist) + +[Guids] + gEfiCertTypeRsa2048Sha256Guid ## PRODUCES ## UNDEFINED # Specifies RSA 2048 SHA 256 authentication algorithm. + gEfiHashAlgorithmSha256Guid ## SOMETIMES_CONSUMES ## UNDEFINED + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.uni new file mode 100644 index 00000000..f0294a68 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.uni @@ -0,0 +1,19 @@ +// /** @file
+// This library doesn't produce any library class. The constructor function uses
+//
+// ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler
+// that parses RSA 2048 SHA 256 encapsulation section and extracts raw data.
+//
+// It uses the BaseCryptLib based on OpenSSL to authenticate the signature.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service of RSA 2048 SHA 256 guided section verification"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library doesn't produce any library class. The constructor function uses ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler that parses RSA2048 SHA256 encapsulation section and extracts raw data. It uses the BaseCryptLib based on OpenSSL to authenticate the signature."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c new file mode 100644 index 00000000..59948712 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c @@ -0,0 +1,1234 @@ +/** @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. + + Tpm2ExecutePendingTpmRequest() will receive untrusted input and do validation. + +Copyright (c) 2013 - 2020, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include <Protocol/Tcg2Protocol.h> +#include <Protocol/VariableLock.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PrintLib.h> +#include <Library/HiiLib.h> +#include <Library/HobLib.h> +#include <Guid/EventGroup.h> +#include <Guid/Tcg2PhysicalPresenceData.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tcg2PhysicalPresenceLib.h> +#include <Library/Tcg2PpVendorLib.h> + +#define CONFIRM_BUFFER_SIZE 4096 + +EFI_HII_HANDLE mTcg2PpStringPackHandle; + +/** + Get string by string id from HII Interface. + + @param[in] Id String ID. + + @retval CHAR16 * String from ID. + @retval NULL If error occurs. + +**/ +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 ((EFI_D_INFO, "Tpm2ClearControl ... \n")); + Status = Tpm2ClearControl (TPM_RH_PLATFORM, AuthSession, NO); + DEBUG ((EFI_D_INFO, "Tpm2ClearControl - %r\n", Status)); + if (EFI_ERROR (Status)) { + goto Done; + } + DEBUG ((EFI_D_INFO, "Tpm2Clear ... \n")); + Status = Tpm2Clear (TPM_RH_PLATFORM, AuthSession); + DEBUG ((EFI_D_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. +**/ +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 ((EFI_D_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. + @param[in, out] PpiFlags The physical presence interface flags. + + @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. +**/ +UINT32 +Tcg2ExecutePhysicalPresence ( + IN TPM2B_AUTH *PlatformAuth, OPTIONAL + IN UINT32 CommandCode, + IN UINT32 CommandParameter, + IN OUT EFI_TCG2_PHYSICAL_PRESENCE_FLAGS *PpiFlags + ) +{ + 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_PP_REQUIRED_FOR_CLEAR_TRUE: + PpiFlags->PPFlags |= TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR; + return TCG_PP_OPERATION_RESPONSE_SUCCESS; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_FALSE: + PpiFlags->PPFlags &= ~TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR; + 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; + } + + case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID: + PpiFlags->PPFlags |= TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID; + return TCG_PP_OPERATION_RESPONSE_SUCCESS; + + case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID: + PpiFlags->PPFlags &= ~TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID; + return TCG_PP_OPERATION_RESPONSE_SUCCESS; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE: + PpiFlags->PPFlags |= TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID; + return TCG_PP_OPERATION_RESPONSE_SUCCESS; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE: + PpiFlags->PPFlags &= ~TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID; + return TCG_PP_OPERATION_RESPONSE_SUCCESS; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE: + PpiFlags->PPFlags |= TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID; + return TCG_PP_OPERATION_RESPONSE_SUCCESS; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE: + PpiFlags->PPFlags &= ~TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID; + 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. +**/ +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. + +**/ +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. +**/ +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, DxeTcg2PhysicalPresenceLibStrings, 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_PP_REQUIRED_FOR_CLEAR_FALSE: + CautionKey = TRUE; + NoPpiInfo = TRUE; + TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR)); + + TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_CLEAR)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + 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; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE: + NoPpiInfo = TRUE; + TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_PP_ENABLE_BLOCK_SID)); + + TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_PPI_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE: + NoPpiInfo = TRUE; + TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_PP_DISABLE_BLOCK_SID)); + + TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_PPI_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + break; + + default: + ; + } + + if (TmpStr2 == NULL) { + FreePool (ConfirmText); + return FALSE; + } + + 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[in] TcgPpData EFI Tcg2 Physical Presence request data. + @param[in] Flags The physical presence interface flags. + @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. + +**/ +BOOLEAN +Tcg2HaveValidTpmRequest ( + IN EFI_TCG2_PHYSICAL_PRESENCE *TcgPpData, + IN EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags, + OUT BOOLEAN *RequestConfirmed + ) +{ + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_STATUS Status; + BOOLEAN IsRequestValid; + + *RequestConfirmed = FALSE; + + if (TcgPpData->PPRequest <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) { + // + // Need TCG2 protocol. + // + Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol); + if (EFI_ERROR (Status)) { + return FALSE; + } + } + + switch (TcgPpData->PPRequest) { + case TCG2_PHYSICAL_PRESENCE_NO_ACTION: + *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: + if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR) == 0) { + *RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_TRUE: + *RequestConfirmed = TRUE; + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_FALSE: + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS: + if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_PCRS) == 0) { + *RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS: + if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_EPS) == 0) { + *RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS: + *RequestConfirmed = TRUE; + break; + + case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID: + if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) == 0) { + *RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID: + if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) == 0) { + *RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE: + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE: + *RequestConfirmed = TRUE; + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE: + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE: + break; + + default: + if (TcgPpData->PPRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + IsRequestValid = Tcg2PpVendorLibHasValidRequest (TcgPpData->PPRequest, Flags.PPFlags, RequestConfirmed); + if (!IsRequestValid) { + return FALSE; + } else { + break; + } + } else { + // + // Wrong Physical Presence command + // + return FALSE; + } + } + + if ((Flags.PPFlags & TCG2_LIB_PP_FLAG_RESET_TRACK) != 0) { + // + // It had been confirmed in last boot, it doesn't need confirm again. + // + *RequestConfirmed = TRUE; + } + + // + // Physical Presence command is correct + // + return TRUE; +} + + +/** + Check and execute the requested physical presence command. + + Caution: This function may receive untrusted input. + TcgPpData variable is external input, so this function will validate + its data structure to be valid value. + + @param[in] PlatformAuth platform auth value. NULL means no platform auth change. + @param[in, out] TcgPpData Pointer to the physical presence NV variable. + @param[in, out] Flags Pointer to the physical presence interface flags. +**/ +VOID +Tcg2ExecutePendingTpmRequest ( + IN TPM2B_AUTH *PlatformAuth, OPTIONAL + IN OUT EFI_TCG2_PHYSICAL_PRESENCE *TcgPpData, + IN OUT EFI_TCG2_PHYSICAL_PRESENCE_FLAGS *Flags + ) +{ + EFI_STATUS Status; + UINTN DataSize; + BOOLEAN RequestConfirmed; + EFI_TCG2_PHYSICAL_PRESENCE_FLAGS NewFlags; + BOOLEAN ResetRequired; + UINT32 NewPPFlags; + + if (TcgPpData->PPRequest == TCG2_PHYSICAL_PRESENCE_NO_ACTION) { + // + // No operation request + // + return; + } + + if (!Tcg2HaveValidTpmRequest(TcgPpData, *Flags, &RequestConfirmed)) { + // + // Invalid operation request. + // + if (TcgPpData->PPRequest <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) { + TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_SUCCESS; + } else { + TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE; + } + TcgPpData->LastPPRequest = TcgPpData->PPRequest; + TcgPpData->PPRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION; + TcgPpData->PPRequestParameter = 0; + + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = gRT->SetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + TcgPpData + ); + return; + } + + ResetRequired = FALSE; + if (TcgPpData->PPRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + NewFlags = *Flags; + NewPPFlags = NewFlags.PPFlags; + TcgPpData->PPResponse = Tcg2PpVendorLibExecutePendingRequest (PlatformAuth, TcgPpData->PPRequest, &NewPPFlags, &ResetRequired); + NewFlags.PPFlags = NewPPFlags; + } else { + if (!RequestConfirmed) { + // + // Print confirm text and wait for approval. + // + RequestConfirmed = Tcg2UserConfirm (TcgPpData->PPRequest, TcgPpData->PPRequestParameter); + } + + // + // Execute requested physical presence command + // + TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_USER_ABORT; + NewFlags = *Flags; + if (RequestConfirmed) { + TcgPpData->PPResponse = Tcg2ExecutePhysicalPresence ( + PlatformAuth, + TcgPpData->PPRequest, + TcgPpData->PPRequestParameter, + &NewFlags + ); + } + } + + // + // Save the flags if it is updated. + // + if (CompareMem (Flags, &NewFlags, sizeof(EFI_TCG2_PHYSICAL_PRESENCE_FLAGS)) != 0) { + *Flags = NewFlags; + Status = gRT->SetVariable ( + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS), + &NewFlags + ); + } + + // + // Clear request + // + if ((NewFlags.PPFlags & TCG2_LIB_PP_FLAG_RESET_TRACK) == 0) { + TcgPpData->LastPPRequest = TcgPpData->PPRequest; + TcgPpData->PPRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION; + TcgPpData->PPRequestParameter = 0; + } + + // + // Save changes + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = gRT->SetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + TcgPpData + ); + if (EFI_ERROR (Status)) { + return; + } + + if (TcgPpData->PPResponse == TCG_PP_OPERATION_RESPONSE_USER_ABORT) { + return; + } + + // + // Reset system to make new TPM settings in effect + // + switch (TcgPpData->LastPPRequest) { + 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; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE: + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE: + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE: + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE: + return; + + default: + if (TcgPpData->LastPPRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + if (ResetRequired) { + break; + } else { + return ; + } + } + if (TcgPpData->PPRequest != 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; + UINTN DataSize; + EFI_TCG2_PHYSICAL_PRESENCE TcgPpData; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol; + EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags; + + // + // This flags variable controls whether physical presence is required for TPM command. + // It should be protected from malicious software. We set it as read-only variable here. + // + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol); + if (!EFI_ERROR (Status)) { + Status = VariableLockProtocol->RequestToLock ( + VariableLockProtocol, + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[TPM2] Error when lock variable %s, Status = %r\n", TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status)); + ASSERT_EFI_ERROR (Status); + } + } + + // + // Check S4 resume + // + if (GetBootModeHob () == BOOT_ON_S4_RESUME) { + DEBUG ((EFI_D_INFO, "S4 Resume, Skip TPM PP process!\n")); + return ; + } + + // + // Initialize physical presence flags. + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS); + Status = gRT->GetVariable ( + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpiFlags + ); + if (EFI_ERROR (Status)) { + PpiFlags.PPFlags = PcdGet32(PcdTcg2PhysicalPresenceFlags); + Status = gRT->SetVariable ( + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS), + &PpiFlags + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence flag failed, Status = %r\n", Status)); + return ; + } + DEBUG((DEBUG_INFO, "[TPM2] Initial physical presence flags value is 0x%x\n", PpiFlags.PPFlags)); + } + + // + // Initialize physical presence variable. + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &TcgPpData + ); + if (EFI_ERROR (Status)) { + ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData)); + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = gRT->SetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &TcgPpData + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence variable failed, Status = %r\n", Status)); + return ; + } + } + + DEBUG ((EFI_D_INFO, "[TPM2] Flags=%x, PPRequest=%x (LastPPRequest=%x)\n", PpiFlags.PPFlags, TcgPpData.PPRequest, TcgPpData.LastPPRequest)); + + // + // Execute pending TPM request. + // + Tcg2ExecutePendingTpmRequest (PlatformAuth, &TcgPpData, &PpiFlags); + DEBUG ((EFI_D_INFO, "[TPM2] PPResponse = %x (LastPPRequest=%x, Flags=%x)\n", TcgPpData.PPResponse, TcgPpData.LastPPRequest, PpiFlags.PPFlags)); + +} + +/** + Check if the pending TPM request needs user input to confirm. + + The TPM request may come from OS. This API will check if TPM request exists and need user + input to confirmation. + + @retval TRUE TPM needs input to confirm user physical presence. + @retval FALSE TPM doesn't need input to confirm user physical presence. + +**/ +BOOLEAN +EFIAPI +Tcg2PhysicalPresenceLibNeedUserConfirm( + VOID + ) +{ + EFI_STATUS Status; + EFI_TCG2_PHYSICAL_PRESENCE TcgPpData; + UINTN DataSize; + BOOLEAN RequestConfirmed; + EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags; + + // + // Check S4 resume + // + if (GetBootModeHob () == BOOT_ON_S4_RESUME) { + DEBUG ((EFI_D_INFO, "S4 Resume, Skip TPM PP process!\n")); + return FALSE; + } + + // + // Check Tpm requests + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &TcgPpData + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS); + Status = gRT->GetVariable ( + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpiFlags + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + if (TcgPpData.PPRequest == TCG2_PHYSICAL_PRESENCE_NO_ACTION) { + // + // No operation request + // + return FALSE; + } + + if (!Tcg2HaveValidTpmRequest(&TcgPpData, PpiFlags, &RequestConfirmed)) { + // + // Invalid operation request. + // + return FALSE; + } + + if (!RequestConfirmed) { + // + // Need UI to confirm + // + return TRUE; + } + + return FALSE; +} + + +/** + 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; + UINTN DataSize; + EFI_TCG2_PHYSICAL_PRESENCE PpData; + + DEBUG ((EFI_D_INFO, "[TPM2] ReturnOperationResponseToOsFunction\n")); + + // + // Get the Physical Presence variable + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + *MostRecentRequest = 0; + *Response = 0; + DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); + return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE; + } + + *MostRecentRequest = PpData.LastPPRequest; + *Response = PpData.PPResponse; + + 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; + UINTN DataSize; + EFI_TCG2_PHYSICAL_PRESENCE PpData; + EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags; + + DEBUG ((EFI_D_INFO, "[TPM2] SubmitRequestToPreOSFunction, Request = %x, %x\n", OperationRequest, RequestParameter)); + + // + // Get the Physical Presence variable + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); + return TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; + } + + if ((OperationRequest > TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) && + (OperationRequest < TCG2_PHYSICAL_PRESENCE_STORAGE_MANAGEMENT_BEGIN) ) { + return TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED; + } + + if ((PpData.PPRequest != OperationRequest) || + (PpData.PPRequestParameter != RequestParameter)) { + PpData.PPRequest = (UINT8)OperationRequest; + PpData.PPRequestParameter = RequestParameter; + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = gRT->SetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[TPM2] Set PP variable failure! Status = %r\n", Status)); + return TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; + } + } + + if (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS); + Status = gRT->GetVariable ( + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &Flags + ); + if (EFI_ERROR (Status)) { + Flags.PPFlags = PcdGet32(PcdTcg2PhysicalPresenceFlags); + } + return Tcg2PpVendorLibSubmitRequestToPreOSFunction (OperationRequest, Flags.PPFlags, RequestParameter); + } + + return TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS; +} + +/** + Return TPM2 ManagementFlags set by PP interface. + + @retval ManagementFlags TPM2 Management Flags. +**/ +UINT32 +EFIAPI +Tcg2PhysicalPresenceLibGetManagementFlags ( + VOID + ) +{ + EFI_STATUS Status; + EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags; + UINTN DataSize; + + DEBUG ((EFI_D_INFO, "[TPM2] GetManagementFlags\n")); + + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS); + Status = gRT->GetVariable ( + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpiFlags + ); + if (EFI_ERROR (Status)) { + PpiFlags.PPFlags = PcdGet32(PcdTcg2PhysicalPresenceFlags); + } + return PpiFlags.PPFlags; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf new file mode 100644 index 00000000..7e5b051c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf @@ -0,0 +1,67 @@ +## @file +# Executes TPM 2.0 requests from OS or BIOS +# +# This library will check and execute TPM 2.0 request from OS or BIOS. The request may +# ask for user confirmation before execution. +# +# 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. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeTcg2PhysicalPresenceLib + MODULE_UNI_FILE = DxeTcg2PhysicalPresenceLib.uni + FILE_GUID = 7E507A86-DE8B-4AD3-BC4C-0498389098D3 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tcg2PhysicalPresenceLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + DxeTcg2PhysicalPresenceLib.c + PhysicalPresenceStrings.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + PrintLib + HiiLib + HobLib + Tpm2CommandLib + Tcg2PpVendorLib + +[Protocols] + gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES + gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2PhysicalPresenceFlags ## SOMETIMES_CONSUMES + +[Guids] + ## SOMETIMES_CONSUMES ## HII + ## SOMETIMES_PRODUCES ## Variable:L"Tcg2PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"Tcg2PhysicalPresence" + ## SOMETIMES_PRODUCES ## Variable:L"Tcg2PhysicalPresenceFlags" + ## SOMETIMES_CONSUMES ## Variable:L"Tcg2PhysicalPresenceFlags" + gEfiTcg2PhysicalPresenceGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.uni new file mode 100644 index 00000000..9f31966a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.uni @@ -0,0 +1,22 @@ +// /** @file
+// Executes TPM 2.0 requests from OS or BIOS
+//
+// This library will check and execute TPM 2.0 request from OS or BIOS. The request may
+// ask for user confirmation before execution.
+//
+// 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.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Executes TPM 2.0 requests from OS or BIOS"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library will check and execute TPM 2.0 request from OS or BIOS. The request may ask for user confirmation before execution.\n"
+ "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."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni new file mode 100644 index 00000000..765a7b3b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni @@ -0,0 +1,55 @@ +/** @file
+ String definitions for TPM 2.0 physical presence confirm text.
+
+Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#langdef en-US "English"
+
+#string TPM_HEAD_STR #language en-US "A configuration change was requested to %s this computer's TPM (Trusted Platform Module)\n\n"
+#string TPM_PPI_HEAD_STR #language en-US "A configuration change was requested to allow the Operating System to %s the computer's TPM (Trusted Platform Module) without asking for user confirmation in the future.\n\n"
+
+#string TPM_ACCEPT_KEY #language en-US "Press F10 "
+#string TPM_CAUTION_KEY #language en-US "Press F12 "
+#string TPM_REJECT_KEY #language en-US "to %s the TPM \nPress ESC to reject this change request and continue\n"
+
+#string TPM_ENABLE #language en-US "enable"
+#string TPM_DISABLE #language en-US "disable"
+#string TPM_CLEAR #language en-US "clear"
+#string TPM_SET_PCR_BANKS #language en-US "change the boot measurements to use PCR bank(s) of"
+#string TPM_CHANGE_EPS #language en-US "clear and change identity of"
+#string TPM_DISABLE_ENDORSEMENT_ENABLE_STORAGE #language en-US "disable access to some secrets stored in"
+
+#string TPM_NO_PPI_MAINTAIN #language en-US "maintain"
+#string TPM_NO_PPI_TURN_ON #language en-US "turn on"
+#string TPM_NO_PPI_TURN_OFF #language en-US "turn off"
+#string TPM_NO_PPI_INFO #language en-US "to approve future Operating System requests "
+
+#string TPM_WARNING_DISABLE #language en-US "WARNING: Doing so might prevent security applications that rely on the TPM from functioning as expected.\n\n"
+#string TPM_WARNING_CLEAR #language en-US "WARNING: Clearing erases information stored on the TPM. You will lose all created keys and access to data encrypted by these keys. "
+#string TPM_NOTE_CLEAR #language en-US "NOTE: This action does not clear the TPM, but by approving this configuration change, future actions to clear the TPM will not require user confirmation.\n\n"
+#string TPM_WARNING_SET_PCR_BANKS_1 #language en-US "WARNING: Changing the PCR bank(s) of the boot measurements may prevent the Operating System from properly processing the measurements. Please check if your Operating System supports the new PCR bank(s).\n\n"
+#string TPM_WARNING_SET_PCR_BANKS_2 #language en-US "WARNING: Secrets in the TPM that are bound to the boot state of your machine may become unusable.\n\n"
+#string TPM_WARNING_CHANGE_EPS_1 #language en-US "WARNING: Clearing erases information stored on the TPM. You will lose all created keys and access to data encrypted with these keys.\n\n"
+#string TPM_WARNING_CHANGE_EPS_2 #language en-US "WARNING: Changing the identity of the TPM may require additional steps to establish trust into the new identity.\n\n"
+#string TPM_WARNING_PP_CHANGE_PCRS_FALSE #language en-US "WARNING: Allowing future changes to format of the boot measurement log may affect the Operating System.\n\n"
+#string TPM_WARNING_PP_CHANGE_EPS_FALSE_1 #language en-US "WARNING: Allowing future changes to the TPM's firmware may affect the operation of the TPM and may erase information stored on the TPM.\n\n"
+#string TPM_WARNING_PP_CHANGE_EPS_FALSE_2 #language en-US "You may lose all created keys and access to data encrypted by these keys.\n\n"
+#string TPM_WARNING_DISABLE_ENDORSEMENT_ENABLE_STORAGE #language en-US "WARNING: Doing so might prevent security applications that rely on the TPM from functioning as expected.\n\n"
+
+#string TCG_STORAGE_HEAD_STR #language en-US "A configuration change was requested to %s on subsequent boots\n\n"
+#string TCG_STORAGE_PPI_HEAD_STR #language en-US "A configuration change was requested to allow the Operating System to %s without asking for user confirmation in the future.\n\n"
+
+#string TCG_STORAGE_ACCEPT_KEY #language en-US "Press F10 "
+#string TCG_STORAGE_CAUTION_KEY #language en-US "Press F12 "
+#string TCG_STORAGE_REJECT_KEY #language en-US "to %s\nPress ESC to reject this change request and continue\n"
+
+#string TCG_STORAGE_NO_PPI_INFO #language en-US "to approve future Operating System requests "
+
+#string TCG_STORAGE_ENABLE_BLOCK_SID #language en-US "issue a Block SID authentication command"
+#string TCG_STORAGE_DISABLE_BLOCK_SID #language en-US "disable issuing a Block SID authentication command"
+
+#string TCG_STORAGE_PP_ENABLE_BLOCK_SID #language en-US "enable blocking SID authentication"
+#string TCG_STORAGE_PP_DISABLE_BLOCK_SID #language en-US "disable blocking SID authentication"
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c new file mode 100644 index 00000000..e70b49d9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c @@ -0,0 +1,1400 @@ +/** @file + + Execute pending TPM requests from OS or BIOS and Lock TPM. + + 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. + + ExecutePendingTpmRequest() will receive untrusted input and do validation. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include <Protocol/TcgService.h> +#include <Protocol/VariableLock.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PrintLib.h> +#include <Library/HiiLib.h> +#include <Guid/EventGroup.h> +#include <Guid/PhysicalPresenceData.h> +#include <Library/TcgPpVendorLib.h> + +#define CONFIRM_BUFFER_SIZE 4096 + +EFI_HII_HANDLE mPpStringPackHandle; + +/** + Get string by string id from HII Interface. + + @param[in] Id String ID. + + @retval CHAR16 * String from ID. + @retval NULL If error occurs. + +**/ +CHAR16 * +PhysicalPresenceGetStringById ( + IN EFI_STRING_ID Id + ) +{ + return HiiGetString (mPpStringPackHandle, Id, NULL); +} + +/** + Get TPM physical presence permanent flags. + + @param[in] TcgProtocol EFI TCG Protocol instance. + @param[out] LifetimeLock physicalPresenceLifetimeLock permanent flag. + @param[out] CmdEnable physicalPresenceCMDEnable permanent flag. + + @retval EFI_SUCCESS Flags were returns successfully. + @retval other Failed to locate EFI TCG Protocol. + +**/ +EFI_STATUS +GetTpmCapability ( + IN EFI_TCG_PROTOCOL *TcgProtocol, + OUT BOOLEAN *LifetimeLock, + OUT BOOLEAN *CmdEnable + ) +{ + EFI_STATUS Status; + 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]; + + // + // Fill request header + // + TpmRsp = (TPM_RSP_COMMAND_HDR*)RecvBuffer; + TpmRqu = (TPM_RQU_COMMAND_HDR*)SendBuffer; + + TpmRqu->tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + TpmRqu->paramSize = SwapBytes32 (sizeof (SendBuffer)); + TpmRqu->ordinal = SwapBytes32 (TPM_ORD_GetCapability); + + // + // Set request parameter + // + SendBufPtr = (UINT32*)(TpmRqu + 1); + WriteUnaligned32 (SendBufPtr++, SwapBytes32 (TPM_CAP_FLAG)); + WriteUnaligned32 (SendBufPtr++, SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT))); + WriteUnaligned32 (SendBufPtr, SwapBytes32 (TPM_CAP_FLAG_PERMANENT)); + + Status = TcgProtocol->PassThroughToTpm ( + TcgProtocol, + sizeof (SendBuffer), + (UINT8*)TpmRqu, + sizeof (RecvBuffer), + (UINT8*)&RecvBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((TpmRsp->tag != SwapBytes16 (TPM_TAG_RSP_COMMAND)) || (TpmRsp->returnCode != 0)) { + return EFI_DEVICE_ERROR; + } + + 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] TcgProtocol EFI TCG Protocol instance. + @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 EFI_TCG_PROTOCOL *TcgProtocol, + IN TPM_PHYSICAL_PRESENCE PhysicalPresence + ) +{ + EFI_STATUS Status; + TPM_RQU_COMMAND_HDR *TpmRqu; + TPM_PHYSICAL_PRESENCE *TpmPp; + TPM_RSP_COMMAND_HDR TpmRsp; + UINT8 Buffer[sizeof (*TpmRqu) + sizeof (*TpmPp)]; + + TpmRqu = (TPM_RQU_COMMAND_HDR*)Buffer; + TpmPp = (TPM_PHYSICAL_PRESENCE*)(TpmRqu + 1); + + TpmRqu->tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + TpmRqu->paramSize = SwapBytes32 (sizeof (Buffer)); + TpmRqu->ordinal = SwapBytes32 (TSC_ORD_PhysicalPresence); + WriteUnaligned16 (TpmPp, (TPM_PHYSICAL_PRESENCE) SwapBytes16 (PhysicalPresence)); + + Status = TcgProtocol->PassThroughToTpm ( + TcgProtocol, + sizeof (Buffer), + (UINT8*)TpmRqu, + sizeof (TpmRsp), + (UINT8*)&TpmRsp + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (TpmRsp.tag != SwapBytes16 (TPM_TAG_RSP_COMMAND)) { + return EFI_DEVICE_ERROR; + } + + 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 parameters. + + @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. + +**/ +UINT32 +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 TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE; + } + + TpmRqu->tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Size = (UINT32)(sizeof (*TpmRqu) + AdditionalParameterSize); + TpmRqu->paramSize = SwapBytes32 (Size); + TpmRqu->ordinal = SwapBytes32 (Ordinal); + 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 != SwapBytes16 (TPM_TAG_RSP_COMMAND))) { + return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE; + } + return SwapBytes32 (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 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. + +**/ +UINT32 +ExecutePhysicalPresence ( + IN EFI_TCG_PROTOCOL *TcgProtocol, + IN UINT32 CommandCode, + IN OUT EFI_PHYSICAL_PRESENCE_FLAGS *PpiFlags + ) +{ + BOOLEAN BoolVal; + UINT32 TpmResponse; + UINT32 InData[5]; + + switch (CommandCode) { + case PHYSICAL_PRESENCE_ENABLE: + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_PhysicalEnable, + 0, + NULL + ); + + case PHYSICAL_PRESENCE_DISABLE: + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_PhysicalDisable, + 0, + NULL + ); + + case PHYSICAL_PRESENCE_ACTIVATE: + BoolVal = FALSE; + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_PhysicalSetDeactivated, + sizeof (BoolVal), + &BoolVal + ); + + case PHYSICAL_PRESENCE_DEACTIVATE: + BoolVal = TRUE; + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_PhysicalSetDeactivated, + sizeof (BoolVal), + &BoolVal + ); + + case PHYSICAL_PRESENCE_CLEAR: + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_ForceClear, + 0, + NULL + ); + + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE: + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE, PpiFlags); + if (TpmResponse == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ACTIVATE, PpiFlags); + } + return TpmResponse; + + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE: + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_DEACTIVATE, PpiFlags); + if (TpmResponse == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_DISABLE, PpiFlags); + } + return TpmResponse; + + case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE: + BoolVal = TRUE; + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_SetOwnerInstall, + sizeof (BoolVal), + &BoolVal + ); + + case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE: + BoolVal = FALSE; + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_SetOwnerInstall, + sizeof (BoolVal), + &BoolVal + ); + + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE: + // + // PHYSICAL_PRESENCE_ENABLE_ACTIVATE + PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE + // PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE will be executed after reboot + // + if ((PpiFlags->PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE_ACTIVATE, PpiFlags); + PpiFlags->PPFlags |= TCG_VENDOR_LIB_FLAG_RESET_TRACK; + } else { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE, PpiFlags); + PpiFlags->PPFlags &= ~TCG_VENDOR_LIB_FLAG_RESET_TRACK; + } + return TpmResponse; + + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE: + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE, PpiFlags); + if (TpmResponse == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_DEACTIVATE_DISABLE, PpiFlags); + } + return TpmResponse; + + case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + InData[0] = SwapBytes32 (TPM_SET_STCLEAR_DATA); // CapabilityArea + InData[1] = SwapBytes32 (sizeof(UINT32)); // SubCapSize + InData[2] = SwapBytes32 (TPM_SD_DEFERREDPHYSICALPRESENCE); // SubCap + InData[3] = SwapBytes32 (sizeof(UINT32)); // SetValueSize + InData[4] = SwapBytes32 (1); // UnownedFieldUpgrade; bit0 + return TpmCommandNoReturnData ( + TcgProtocol, + TPM_ORD_SetCapability, + sizeof (UINT32) * 5, + InData + ); + + case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH: + // + // TPM_SetOperatorAuth + // This command requires UI to prompt user for Auth data + // Here it is NOT implemented + // + return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE; + + case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE: + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_CLEAR, PpiFlags); + if (TpmResponse == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE_ACTIVATE, PpiFlags); + } + return TpmResponse; + + case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE: + PpiFlags->PPFlags &= ~TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION; + return 0; + + case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_TRUE: + PpiFlags->PPFlags |= TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION; + return 0; + + case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE: + PpiFlags->PPFlags &= ~TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR; + return 0; + + case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE: + PpiFlags->PPFlags |= TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR; + return 0; + + case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE: + PpiFlags->PPFlags &= ~TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE; + return 0; + + case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_TRUE: + PpiFlags->PPFlags |= TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE; + return 0; + + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR: + // + // PHYSICAL_PRESENCE_ENABLE_ACTIVATE + PHYSICAL_PRESENCE_CLEAR + // PHYSICAL_PRESENCE_CLEAR will be executed after reboot. + // + if ((PpiFlags->PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE_ACTIVATE, PpiFlags); + PpiFlags->PPFlags |= TCG_VENDOR_LIB_FLAG_RESET_TRACK; + } else { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_CLEAR, PpiFlags); + PpiFlags->PPFlags &= ~TCG_VENDOR_LIB_FLAG_RESET_TRACK; + } + return TpmResponse; + + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + // + // PHYSICAL_PRESENCE_ENABLE_ACTIVATE + PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE + // PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE will be executed after reboot. + // + if ((PpiFlags->PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) == 0) { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE_ACTIVATE, PpiFlags); + PpiFlags->PPFlags |= TCG_VENDOR_LIB_FLAG_RESET_TRACK; + } else { + TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE, PpiFlags); + PpiFlags->PPFlags &= ~TCG_VENDOR_LIB_FLAG_RESET_TRACK; + } + return TpmResponse; + + default: + ; + } + 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 or device error. + +**/ +BOOLEAN +ReadUserKey ( + IN BOOLEAN CautionKey + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + UINT16 InputKey; + UINTN Index; + + InputKey = 0; + do { + Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + if (Status == EFI_NOT_READY) { + gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index); + continue; + } + + if (Status == EFI_DEVICE_ERROR) { + return FALSE; + } + + 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; +} + +/** + The constructor function register UNI strings into imageHandle. + + It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor successfully added string package. + @retval Other value The constructor can't add string package. + +**/ +EFI_STATUS +EFIAPI +TcgPhysicalPresenceLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + mPpStringPackHandle = HiiAddPackages (&gEfiPhysicalPresenceGuid, ImageHandle, DxeTcgPhysicalPresenceLibStrings, NULL); + ASSERT (mPpStringPackHandle != NULL); + + return EFI_SUCCESS; +} + +/** + 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 UINT32 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); + + switch (TpmPpCommand) { + case PHYSICAL_PRESENCE_ENABLE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ENABLE)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_DISABLE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_DISABLE)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_ACTIVATE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACTIVATE)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_DEACTIVATE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_DEACTIVATE)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_CLEAR: + CautionKey = TRUE; + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (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); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ENABLE_ACTIVATE)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_ON)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_DEACTIVATE_DISABLE)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_OFF)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ALLOW_TAKE_OWNERSHIP)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_DISALLOW_TAKE_OWNERSHIP)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_TURN_ON)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_ON)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_TURN_OFF)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_OFF)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + CautionKey = TRUE; + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_UNOWNED_FIELD_UPGRADE)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_UPGRADE_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_MAINTAIN)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH: + // + // TPM_SetOperatorAuth + // This command requires UI to prompt user for Auth data + // Here it is NOT implemented + // + break; + + case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE: + CautionKey = TRUE; + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR_TURN_ON)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_ON)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR_CONT)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_TRUE: + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_PROVISION)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE: + CautionKey = TRUE; + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_CLEAR)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (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); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_TRUE: + CautionKey = TRUE; + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_MAINTAIN)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_MAINTAIN)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR: + CautionKey = TRUE; + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (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); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + CautionKey = TRUE; + TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE)); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR)); + UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_ON)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR_CONT)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY)); + StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1); + FreePool (TmpStr1); + break; + + default: + ; + } + + if (TmpStr2 == NULL) { + FreePool (ConfirmText); + return FALSE; + } + + TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_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); + + if (ReadUserKey (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[in] TcgPpData EFI TCG Physical Presence request data. + @param[in] Flags The physical presence interface flags. + @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. + +**/ +BOOLEAN +HaveValidTpmRequest ( + IN EFI_PHYSICAL_PRESENCE *TcgPpData, + IN EFI_PHYSICAL_PRESENCE_FLAGS Flags, + OUT BOOLEAN *RequestConfirmed + ) +{ + BOOLEAN IsRequestValid; + + *RequestConfirmed = FALSE; + + switch (TcgPpData->PPRequest) { + case PHYSICAL_PRESENCE_NO_ACTION: + *RequestConfirmed = TRUE; + return TRUE; + case PHYSICAL_PRESENCE_ENABLE: + case PHYSICAL_PRESENCE_DISABLE: + case PHYSICAL_PRESENCE_ACTIVATE: + case PHYSICAL_PRESENCE_DEACTIVATE: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE: + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE: + case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE: + case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE: + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE: + case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH: + if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) { + *RequestConfirmed = TRUE; + } + break; + + case PHYSICAL_PRESENCE_CLEAR: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR: + if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) { + *RequestConfirmed = TRUE; + } + break; + + case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE) != 0) { + *RequestConfirmed = TRUE; + } + break; + + case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0 && (Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) { + *RequestConfirmed = TRUE; + } + break; + + case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE: + case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE: + case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE: + *RequestConfirmed = TRUE; + break; + + case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_TRUE: + case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE: + case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_TRUE: + break; + + default: + if (TcgPpData->PPRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + IsRequestValid = TcgPpVendorLibHasValidRequest (TcgPpData->PPRequest, Flags.PPFlags, RequestConfirmed); + if (!IsRequestValid) { + return FALSE; + } else { + break; + } + } else { + // + // Wrong Physical Presence command + // + return FALSE; + } + } + + if ((Flags.PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) != 0) { + // + // It had been confirmed in last boot, it doesn't need confirm again. + // + *RequestConfirmed = TRUE; + } + + // + // Physical Presence command is correct + // + return TRUE; +} + + +/** + Check and execute the requested physical presence command. + + Caution: This function may receive untrusted input. + TcgPpData variable is external input, so this function will validate + its data structure to be valid value. + + @param[in] TcgProtocol EFI TCG Protocol instance. + @param[in] TcgPpData Point to the physical presence NV variable. + @param[in] Flags The physical presence interface flags. + +**/ +VOID +ExecutePendingTpmRequest ( + IN EFI_TCG_PROTOCOL *TcgProtocol, + IN EFI_PHYSICAL_PRESENCE *TcgPpData, + IN EFI_PHYSICAL_PRESENCE_FLAGS Flags + ) +{ + EFI_STATUS Status; + UINTN DataSize; + BOOLEAN RequestConfirmed; + EFI_PHYSICAL_PRESENCE_FLAGS NewFlags; + BOOLEAN ResetRequired; + UINT32 NewPPFlags; + + if (!HaveValidTpmRequest(TcgPpData, Flags, &RequestConfirmed)) { + // + // Invalid operation request. + // + TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE; + TcgPpData->LastPPRequest = TcgPpData->PPRequest; + TcgPpData->PPRequest = PHYSICAL_PRESENCE_NO_ACTION; + 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 + ); + return; + } + + ResetRequired = FALSE; + if (TcgPpData->PPRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + NewFlags = Flags; + NewPPFlags = NewFlags.PPFlags; + TcgPpData->PPResponse = TcgPpVendorLibExecutePendingRequest (TcgPpData->PPRequest, &NewPPFlags, &ResetRequired); + NewFlags.PPFlags = (UINT8)NewPPFlags; + } else { + if (!RequestConfirmed) { + // + // Print confirm text and wait for approval. + // + RequestConfirmed = UserConfirm (TcgPpData->PPRequest); + } + + // + // Execute requested physical presence command + // + TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_USER_ABORT; + NewFlags = Flags; + if (RequestConfirmed) { + TcgPpData->PPResponse = ExecutePhysicalPresence (TcgProtocol, TcgPpData->PPRequest, &NewFlags); + } + } + + // + // Save the flags if it is updated. + // + if (CompareMem (&Flags, &NewFlags, sizeof(EFI_PHYSICAL_PRESENCE_FLAGS)) != 0) { + Status = gRT->SetVariable ( + PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EFI_PHYSICAL_PRESENCE_FLAGS), + &NewFlags + ); + if (EFI_ERROR (Status)) { + return; + } + } + + // + // Clear request + // + if ((NewFlags.PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) == 0) { + TcgPpData->LastPPRequest = TcgPpData->PPRequest; + TcgPpData->PPRequest = PHYSICAL_PRESENCE_NO_ACTION; + } + + // + // 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 == TCG_PP_OPERATION_RESPONSE_USER_ABORT) { + return; + } + + // + // Reset system to make new TPM settings in effect + // + switch (TcgPpData->LastPPRequest) { + case PHYSICAL_PRESENCE_ACTIVATE: + case PHYSICAL_PRESENCE_DEACTIVATE: + case PHYSICAL_PRESENCE_CLEAR: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE: + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE: + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE: + case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + break; + default: + if (TcgPpData->LastPPRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + if (ResetRequired) { + break; + } else { + return ; + } + } + if (TcgPpData->PPRequest != PHYSICAL_PRESENCE_NO_ACTION) { + 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 pending TPM request and Lock TPM. + + 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. At last, it will lock TPM to prevent TPM state change by malware. + + 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. This API should also + be invoked as early as possible as TPM is locked in this function. + +**/ +VOID +EFIAPI +TcgPhysicalPresenceLibProcessRequest ( + VOID + ) +{ + EFI_STATUS Status; + BOOLEAN LifetimeLock; + BOOLEAN CmdEnable; + UINTN DataSize; + EFI_PHYSICAL_PRESENCE TcgPpData; + EFI_TCG_PROTOCOL *TcgProtocol; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol; + EFI_PHYSICAL_PRESENCE_FLAGS PpiFlags; + + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Initialize physical presence flags. + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS); + Status = gRT->GetVariable ( + PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &PpiFlags + ); + if (EFI_ERROR (Status)) { + PpiFlags.PPFlags = TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION; + Status = gRT->SetVariable ( + PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (EFI_PHYSICAL_PRESENCE_FLAGS), + &PpiFlags + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[TPM] Set physical presence flag failed, Status = %r\n", Status)); + return ; + } + } + DEBUG ((EFI_D_INFO, "[TPM] PpiFlags = %x\n", PpiFlags.PPFlags)); + + // + // This flags variable controls whether physical presence is required for TPM command. + // It should be protected from malicious software. We set it as read-only variable here. + // + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol); + if (!EFI_ERROR (Status)) { + Status = VariableLockProtocol->RequestToLock ( + VariableLockProtocol, + PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiPhysicalPresenceGuid + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[TPM] Error when lock variable %s, Status = %r\n", PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status)); + ASSERT_EFI_ERROR (Status); + } + } + + // + // Initialize physical presence variable. + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &TcgPpData + ); + if (EFI_ERROR (Status)) { + ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData)); + 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)) { + DEBUG ((EFI_D_ERROR, "[TPM] Set physical presence variable failed, Status = %r\n", Status)); + return; + } + } + + DEBUG ((EFI_D_INFO, "[TPM] Flags=%x, PPRequest=%x\n", PpiFlags.PPFlags, TcgPpData.PPRequest)); + + if (TcgPpData.PPRequest == PHYSICAL_PRESENCE_NO_ACTION) { + // + // No operation request + // + return; + } + + Status = GetTpmCapability (TcgProtocol, &LifetimeLock, &CmdEnable); + if (EFI_ERROR (Status)) { + return ; + } + + if (!CmdEnable) { + if (LifetimeLock) { + // + // physicalPresenceCMDEnable is locked, can't execute physical presence command. + // + return ; + } + Status = TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_CMD_ENABLE); + if (EFI_ERROR (Status)) { + return ; + } + } + + // + // Set operator physical presence flags + // + Status = TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_PRESENT); + if (EFI_ERROR (Status)) { + return; + } + + // + // Execute pending TPM request. + // + ExecutePendingTpmRequest (TcgProtocol, &TcgPpData, PpiFlags); + DEBUG ((EFI_D_INFO, "[TPM] PPResponse = %x\n", TcgPpData.PPResponse)); + + // + // Lock physical presence. + // + TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_NOTPRESENT | TPM_PHYSICAL_PRESENCE_LOCK); +} + +/** + Check if the pending TPM request needs user input to confirm. + + The TPM request may come from OS. This API will check if TPM request exists and need user + input to confirmation. + + @retval TRUE TPM needs input to confirm user physical presence. + @retval FALSE TPM doesn't need input to confirm user physical presence. + +**/ +BOOLEAN +EFIAPI +TcgPhysicalPresenceLibNeedUserConfirm( + VOID + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_PRESENCE TcgPpData; + UINTN DataSize; + BOOLEAN RequestConfirmed; + BOOLEAN LifetimeLock; + BOOLEAN CmdEnable; + EFI_TCG_PROTOCOL *TcgProtocol; + EFI_PHYSICAL_PRESENCE_FLAGS PpiFlags; + + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol); + if (EFI_ERROR (Status)) { + return FALSE; + } + + // + // Check Tpm requests + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &TcgPpData + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS); + Status = gRT->GetVariable ( + PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &PpiFlags + ); + if (EFI_ERROR (Status)) { + return FALSE; + } + + if (TcgPpData.PPRequest == PHYSICAL_PRESENCE_NO_ACTION) { + // + // No operation request + // + return FALSE; + } + + if (!HaveValidTpmRequest(&TcgPpData, PpiFlags, &RequestConfirmed)) { + // + // Invalid operation request. + // + return FALSE; + } + + // + // Check Tpm Capability + // + Status = GetTpmCapability (TcgProtocol, &LifetimeLock, &CmdEnable); + if (EFI_ERROR (Status)) { + return FALSE; + } + + if (!CmdEnable) { + if (LifetimeLock) { + // + // physicalPresenceCMDEnable is locked, can't execute physical presence command. + // + return FALSE; + } + } + + if (!RequestConfirmed) { + // + // Need UI to confirm + // + return TRUE; + } + + return FALSE; +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf new file mode 100644 index 00000000..6683bfb2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf @@ -0,0 +1,64 @@ +## @file +# Executes pending TPM 1.2 requests from OS or BIOS and Locks TPM +# +# This library will check and execute TPM 1.2 request from OS or BIOS. The request may +# ask for user confirmation before execution. This Library will also lock TPM physical +# presence at last. +# +# 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. +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeTcgPhysicalPresenceLib + MODULE_UNI_FILE = DxeTcgPhysicalPresenceLib.uni + FILE_GUID = EBC43A46-34AC-4F07-A7F5-A5394619361C + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = TcgPhysicalPresenceLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = TcgPhysicalPresenceLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + DxeTcgPhysicalPresenceLib.c + PhysicalPresenceStrings.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + PrintLib + HiiLib + TcgPpVendorLib + +[Protocols] + gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES + gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES + +[Guids] + ## SOMETIMES_CONSUMES ## HII + ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence" + ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresenceFlags" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags" + gEfiPhysicalPresenceGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.uni new file mode 100644 index 00000000..c7fcca5c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.uni @@ -0,0 +1,22 @@ +// /** @file
+// Executes pending TPM 1.2 requests from OS or BIOS and Locks TPM
+//
+// This library will check and execute TPM 1.2 request from OS or BIOS. The request may
+// ask for user confirmation before execution. This Library will also lock TPM physical
+// presence at last.
+//
+// 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.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Executes pending TPM 1.2 requests from OS or BIOS and Locks TPM"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library will ask for user confirmation for the pending TPM physical present requests. Once confirmed, it will execute the request, and locks TPM physical presence at last. 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."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni new file mode 100644 index 00000000..9d17432e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni @@ -0,0 +1,46 @@ +/** @file
+ String definitions for TPM 1.2 physical presence confirm text.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#langdef en-US "English"
+
+#string TPM_HEAD_STR #language en-US "A configuration change was requested to %s this computer's TPM (Trusted Platform Module)\n\n"
+#string TPM_PPI_HEAD_STR #language en-US "A configuration change was requested to allow the Operating System to %s the computer's TPM (Trusted Platform Module) without asking for user confirmation in the future.\n\n"
+#string TPM_UPGRADE_HEAD_STR #language en-US "A configuration change was requested to %s to the TPM's (Trusted Platform Module) firmware.\n\n"
+
+#string TPM_ACCEPT_KEY #language en-US "Press F10 "
+#string TPM_CAUTION_KEY #language en-US "Press F12 "
+#string TPM_REJECT_KEY #language en-US "to %s the TPM \nPress ESC to reject this change request and continue\n"
+
+#string TPM_ENABLE #language en-US "enable"
+#string TPM_DISABLE #language en-US "disable"
+#string TPM_ACTIVATE #language en-US "activate"
+#string TPM_DEACTIVATE #language en-US "deactivate"
+#string TPM_CLEAR #language en-US "clear"
+#string TPM_ENABLE_ACTIVATE #language en-US "enable and activate"
+#string TPM_DEACTIVATE_DISABLE #language en-US "deactivate and disable"
+#string TPM_ALLOW_TAKE_OWNERSHIP #language en-US "allow a user to take ownership of"
+#string TPM_DISALLOW_TAKE_OWNERSHIP #language en-US "disallow a user to take ownership of"
+#string TPM_TURN_ON #language en-US "enable, activate, and allow a user to take ownership of"
+#string TPM_TURN_OFF #language en-US "deactivate, disable, and disallow a user to take ownership of"
+#string TPM_CLEAR_TURN_ON #language en-US "clear, enable, and activate"
+#string TPM_ENABLE_ACTIVATE_CLEAR #language en-US "enable, activate and clear"
+#string TPM_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE #language en-US "enable, activate, clear, enable, and activate"
+#string TPM_UNOWNED_FIELD_UPGRADE #language en-US "allow field upgrade"
+
+#string TPM_NO_PPI_PROVISION #language en-US "provision"
+#string TPM_NO_PPI_MAINTAIN #language en-US "maintain"
+#string TPM_NO_PPI_INFO #language en-US "to approve future Operating System requests "
+
+#string TPM_WARNING_MAINTAIN #language en-US "WARNING: Allowing changes to the TPM's firmware may affect the operation of the TPM and may erase information stored on the TPM.\nYou may lose all created keys and access to data encrypted by these keys.\n\n"
+#string TPM_WARNING #language en-US "WARNING: Doing so might prevent security applications that rely on the TPM from functioning as expected\n\n"
+#string TPM_WARNING_CLEAR #language en-US "WARNING: Clearing erases information stored on the TPM. You will lose all created keys and access to data encrypted by these keys. "
+#string TPM_WARNING_CLEAR_CONT #language en-US "Take ownership as soon as possible after this step.\n\n"
+#string TPM_NOTE_OFF #language en-US "NOTE: This action will turn off the TPM\n\n"
+#string TPM_NOTE_ON #language en-US "NOTE: This action will turn on the TPM\n\n"
+#string TPM_NOTE_CLEAR #language en-US "NOTE: This action does not clear the TPM, but by approving this configuration change, future actions to clear the TPM will not require user confirmation.\n\n"
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c new file mode 100644 index 00000000..4174bda8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c @@ -0,0 +1,703 @@ +/** @file + The library instance provides security service of TPM2 measure boot. + + Caution: This file requires additional review when modified. + This library will have external input - PE/COFF image and GPT partition. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content + read is within the image buffer. + + Tcg2MeasurePeImage() function will accept untrusted PE/COFF image and validate its + data structure within this image buffer before use. + + Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse + partition data carefully. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include <Protocol/Tcg2Protocol.h> +#include <Protocol/BlockIo.h> +#include <Protocol/DiskIo.h> +#include <Protocol/DevicePathToText.h> +#include <Protocol/FirmwareVolumeBlock.h> + +#include <Guid/MeasuredFvHob.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DevicePathLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/PeCoffLib.h> +#include <Library/SecurityManagementLib.h> +#include <Library/HobLib.h> + +// +// Flag to check GPT partition. It only need be measured once. +// +BOOLEAN mTcg2MeasureGptTableFlag = FALSE; +UINTN mTcg2MeasureGptCount = 0; +VOID *mTcg2FileBuffer; +UINTN mTcg2ImageSize; +// +// Measured FV handle cache +// +EFI_HANDLE mTcg2CacheMeasuredHandle = NULL; +MEASURED_HOB_DATA *mTcg2MeasuredHobData = NULL; + +/** + Reads contents of a PE/COFF image in memory buffer. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will make sure the PE/COFF image content + read is within the image 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 +DxeTpm2MeasureBootLibImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + UINTN EndPosition; + + if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (MAX_ADDRESS - FileOffset < *ReadSize) { + return EFI_INVALID_PARAMETER; + } + + EndPosition = FileOffset + *ReadSize; + if (EndPosition > mTcg2ImageSize) { + *ReadSize = (UINT32)(mTcg2ImageSize - FileOffset); + } + + if (FileOffset >= mTcg2ImageSize) { + *ReadSize = 0; + } + + CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize); + + return EFI_SUCCESS; +} + +/** + Measure GPT table data into TPM log. + + Caution: This function may receive untrusted input. + The GPT partition table is external input, so this function should parse partition data carefully. + + @param Tcg2Protocol Pointer to the located TCG2 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 +Tcg2MeasureGptTable ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol, + 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; + EFI_TCG2_EVENT *Tcg2Event; + EFI_GPT_DATA *GptData; + UINT32 EventSize; + + if (mTcg2MeasureGptCount > 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 (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) { + NumberOfPartition++; + } + PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry); + } + + // + // Prepare Data for Measurement + // + EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) + + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry); + Tcg2Event = (EFI_TCG2_EVENT *) AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event)); + if (Tcg2Event == NULL) { + FreePool (PrimaryHeader); + FreePool (EntryPtr); + return EFI_OUT_OF_RESOURCES; + } + + Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event); + Tcg2Event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + Tcg2Event->Header.PCRIndex = 5; + Tcg2Event->Header.EventType = EV_EFI_GPT_EVENT; + GptData = (EFI_GPT_DATA *) Tcg2Event->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 (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) { + CopyMem ( + (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry, + (UINT8 *)PartitionEntry, + PrimaryHeader->SizeOfPartitionEntry + ); + NumberOfPartition++; + } + PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry); + } + + // + // Measure the GPT data + // + Status = Tcg2Protocol->HashLogExtendEvent ( + Tcg2Protocol, + 0, + (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData, + (UINT64) EventSize, + Tcg2Event + ); + if (!EFI_ERROR (Status)) { + mTcg2MeasureGptCount++; + } + + FreePool (PrimaryHeader); + FreePool (EntryPtr); + FreePool (Tcg2Event); + + return Status; +} + +/** + Measure PE image into TPM log based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + @param[in] Tcg2Protocol Pointer to the located TCG2 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 EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format. + @retval other error value + +**/ +EFI_STATUS +EFIAPI +Tcg2MeasurePeImage ( + IN EFI_TCG2_PROTOCOL *Tcg2Protocol, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + IN UINTN LinkTimeBase, + IN UINT16 ImageType, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath + ) +{ + EFI_STATUS Status; + EFI_TCG2_EVENT *Tcg2Event; + EFI_IMAGE_LOAD_EVENT *ImageLoad; + UINT32 FilePathSize; + UINT32 EventSize; + + Status = EFI_UNSUPPORTED; + ImageLoad = NULL; + FilePathSize = (UINT32) GetDevicePathSize (FilePath); + + // + // Determine destination PCR by BootPolicy + // + EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize; + Tcg2Event = AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event)); + if (Tcg2Event == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event); + Tcg2Event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + ImageLoad = (EFI_IMAGE_LOAD_EVENT *) Tcg2Event->Event; + + switch (ImageType) { + case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: + Tcg2Event->Header.EventType = EV_EFI_BOOT_SERVICES_APPLICATION; + Tcg2Event->Header.PCRIndex = 4; + break; + case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + Tcg2Event->Header.EventType = EV_EFI_BOOT_SERVICES_DRIVER; + Tcg2Event->Header.PCRIndex = 2; + break; + case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + Tcg2Event->Header.EventType = EV_EFI_RUNTIME_SERVICES_DRIVER; + Tcg2Event->Header.PCRIndex = 2; + break; + default: + DEBUG (( + EFI_D_ERROR, + "Tcg2MeasurePeImage: Unknown subsystem type %d", + ImageType + )); + goto Finish; + } + + ImageLoad->ImageLocationInMemory = ImageAddress; + ImageLoad->ImageLengthInMemory = ImageSize; + ImageLoad->ImageLinkTimeAddress = LinkTimeBase; + ImageLoad->LengthOfDevicePath = FilePathSize; + if ((FilePath != NULL) && (FilePathSize != 0)) { + CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize); + } + + // + // Log the PE data + // + Status = Tcg2Protocol->HashLogExtendEvent ( + Tcg2Protocol, + PE_COFF_IMAGE, + ImageAddress, + ImageSize, + Tcg2Event + ); + if (Status == EFI_VOLUME_FULL) { + // + // Volume full here means the image is hashed and its result is extended to PCR. + // But the event log can't be saved since log area is full. + // Just return EFI_SUCCESS in order not to block the image load. + // + Status = EFI_SUCCESS; + } + +Finish: + FreePool (Tcg2Event); + + 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 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. + + If check image specified by FileBuffer and File is NULL meanwhile, return EFI_ACCESS_DENIED. + + @param[in] 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. + @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service. + + @retval EFI_SUCCESS The file specified by DevicePath and non-NULL + FileBuffer did authenticate, and the platform policy dictates + that the DXE Foundation may use the file. + @retval other error value +**/ +EFI_STATUS +EFIAPI +DxeTpm2MeasureBootHandler ( + IN UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File, OPTIONAL + IN VOID *FileBuffer, + IN UINTN FileSize, + IN BOOLEAN BootPolicy + ) +{ + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_STATUS Status; + EFI_TCG2_BOOT_SERVICE_CAPABILITY ProtocolCapability; + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode; + EFI_HANDLE Handle; + EFI_HANDLE TempHandle; + BOOLEAN ApplicationRequired; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; + EFI_PHYSICAL_ADDRESS FvAddress; + UINT32 Index; + + Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol); + if (EFI_ERROR (Status)) { + // + // Tcg2 protocol is not installed. So, TPM2 is not present. + // Don't do any measurement, and directly return EFI_SUCCESS. + // + DEBUG ((EFI_D_VERBOSE, "DxeTpm2MeasureBootHandler - Tcg2 - %r\n", Status)); + return EFI_SUCCESS; + } + + ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability); + Status = Tcg2Protocol->GetCapability ( + Tcg2Protocol, + &ProtocolCapability + ); + if (EFI_ERROR (Status) || (!ProtocolCapability.TPMPresentFlag)) { + // + // TPM device doesn't work or activate. + // + DEBUG ((EFI_D_ERROR, "DxeTpm2MeasureBootHandler (%r) - TPMPresentFlag - %x\n", Status, ProtocolCapability.TPMPresentFlag)); + return EFI_SUCCESS; + } + + // + // Copy File Device Path + // + OrigDevicePathNode = DuplicateDevicePath (File); + + // + // 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) && !mTcg2MeasureGptTableFlag) { + // + // Find the gpt partition on the given devicepath + // + DevicePathNode = OrigDevicePathNode; + ASSERT (DevicePathNode != NULL); + 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 = Tcg2MeasureGptTable (Tcg2Protocol, Handle); + DEBUG ((EFI_D_INFO, "DxeTpm2MeasureBootHandler - Tcg2MeasureGptTable - %r\n", Status)); + if (!EFI_ERROR (Status)) { + // + // GPT disk check done. + // + mTcg2MeasureGptTableFlag = 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 FVB protocol. + // + DevicePathNode = OrigDevicePathNode; + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &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 PE image from unmeasured Firmware volume need be measured + // The PE image from measured Firmware volume will be measured according to policy below. + // If it is driver, do not measure + // If it is application, still measure. + // + ApplicationRequired = TRUE; + + if (mTcg2CacheMeasuredHandle != Handle && mTcg2MeasuredHobData != NULL) { + // + // Search for Root FV of this PE image + // + TempHandle = Handle; + do { + Status = gBS->HandleProtocol( + TempHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID**)&FvbProtocol + ); + TempHandle = FvbProtocol->ParentHandle; + } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL); + + // + // Search in measured FV Hob + // + Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress); + if (EFI_ERROR(Status)){ + return Status; + } + + ApplicationRequired = FALSE; + + for (Index = 0; Index < mTcg2MeasuredHobData->Num; Index++) { + if(mTcg2MeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) { + // + // Cache measured FV for next measurement + // + mTcg2CacheMeasuredHandle = Handle; + ApplicationRequired = TRUE; + break; + } + } + } + } + + // + // File is not found. + // + if (FileBuffer == NULL) { + Status = EFI_SECURITY_VIOLATION; + goto Finish; + } + + mTcg2ImageSize = FileSize; + mTcg2FileBuffer = FileBuffer; + + // + // Measure PE Image + // + DevicePathNode = OrigDevicePathNode; + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpm2MeasureBootLibImageRead; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + // + // Check for invalid parameters. + // + if (File == NULL) { + Status = EFI_ACCESS_DENIED; + } + + // + // 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; + ToText = ConvertDevicePathToText ( + DevicePathNode, + FALSE, + TRUE + ); + if (ToText != NULL) { + DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText)); + FreePool (ToText); + } + DEBUG_CODE_END (); + + // + // Measure PE image into TPM log. + // + Status = Tcg2MeasurePeImage ( + Tcg2Protocol, + (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, + FileSize, + (UINTN) ImageContext.ImageAddress, + ImageContext.ImageType, + DevicePathNode + ); + DEBUG ((EFI_D_INFO, "DxeTpm2MeasureBootHandler - Tcg2MeasurePeImage - %r\n", Status)); + } + + // + // Done, free the allocated resource. + // +Finish: + if (OrigDevicePathNode != NULL) { + FreePool (OrigDevicePathNode); + } + + DEBUG ((EFI_D_INFO, "DxeTpm2MeasureBootHandler - %r\n", Status)); + + 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 +DxeTpm2MeasureBootLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = NULL; + + GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid); + + if (GuidHob != NULL) { + mTcg2MeasuredHobData = GET_GUID_HOB_DATA (GuidHob); + } + + return RegisterSecurity2Handler ( + DxeTpm2MeasureBootHandler, + EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf new file mode 100644 index 00000000..915bf3d8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf @@ -0,0 +1,67 @@ +## @file +# Provides security service for TPM 2.0 measured boot +# +# Spec Compliance Info: +# "TCG PC Client Platform Firmware Profile Specification for TPM Family 2.0 Level 00 Revision 1.03 v51" +# along with +# "Errata for PC Client Specific Platform Firmware Profile Specification Version 1.0 Revision 1.03" +# +# This library instance hooks LoadImage() API to measure every image that +# is not measured in PEI phase. And, it will also measure GPT partition. +# +# Caution: This module requires additional review when modified. +# This library will have external input - PE/COFF image and GPT partition. +# This external input must be validated carefully to avoid security issues such +# as buffer overflow or integer overflow. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeTpm2MeasureBootLib + MODULE_UNI_FILE = DxeTpm2MeasureBootLib.uni + FILE_GUID = 778CE4F4-36BD-4ae7-B8F0-10B420B0D174 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = DxeTpm2MeasureBootLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + DxeTpm2MeasureBootLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + MemoryAllocationLib + DevicePathLib + UefiBootServicesTableLib + BaseCryptLib + PeCoffLib + BaseLib + SecurityManagementLib + HobLib + +[Guids] + gMeasuredFvHobGuid ## SOMETIMES_CONSUMES ## HOB + +[Protocols] + gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.uni new file mode 100644 index 00000000..d887e8d3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.uni @@ -0,0 +1,22 @@ +// /** @file
+// Provides security service for TPM 2.0 measured boot
+//
+// This library instance hooks LoadImage() API to measure every image that
+// is not measured in PEI phase. And, it will also measure GPT partition.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - PE/COFF image and GPT partition.
+// This external input must be validated carefully to avoid security issues such
+// as buffer overflow or integer overflow.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service for TPM 2.0 measured boot"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library instance hooks LoadImage() API to measure every image that is not measured in PEI phase. And, it will also measure GPT partition. Caution: This module requires additional review when modified. This library will have external input - PE/COFF image and GPT partition. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c new file mode 100644 index 00000000..38f26ef5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c @@ -0,0 +1,997 @@ +/** @file + The library instance provides security service of TPM measure boot. + + Caution: This file requires additional review when modified. + This library will have external input - PE/COFF image and GPT partition. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content + read is within the image buffer. + + TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its + data structure within this image buffer before use. + + TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse + partition data carefully. + +Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include <Protocol/TcgService.h> +#include <Protocol/BlockIo.h> +#include <Protocol/DiskIo.h> +#include <Protocol/FirmwareVolumeBlock.h> + +#include <Guid/MeasuredFvHob.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DevicePathLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/PeCoffLib.h> +#include <Library/SecurityManagementLib.h> +#include <Library/HobLib.h> + +// +// Flag to check GPT partition. It only need be measured once. +// +BOOLEAN mMeasureGptTableFlag = FALSE; +UINTN mMeasureGptCount = 0; +VOID *mFileBuffer; +UINTN mTpmImageSize; +// +// Measured FV handle cache +// +EFI_HANDLE mCacheMeasuredHandle = NULL; +MEASURED_HOB_DATA *mMeasuredHobData = NULL; + +/** + Reads contents of a PE/COFF image in memory buffer. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will make sure the PE/COFF image content + read is within the image 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 +DxeTpmMeasureBootLibImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + UINTN EndPosition; + + if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (MAX_ADDRESS - FileOffset < *ReadSize) { + return EFI_INVALID_PARAMETER; + } + + EndPosition = FileOffset + *ReadSize; + if (EndPosition > mTpmImageSize) { + *ReadSize = (UINT32)(mTpmImageSize - FileOffset); + } + + if (FileOffset >= mTpmImageSize) { + *ReadSize = 0; + } + + CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize); + + return EFI_SUCCESS; +} + +/** + Measure GPT table data into TPM log. + + Caution: This function may receive untrusted input. + The GPT partition table is external input, so this function should parse partition data carefully. + + @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 (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) { + NumberOfPartition++; + } + PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry); + } + + // + // Prepare 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_HDR)); + 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 (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) { + CopyMem ( + (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry, + (UINT8 *)PartitionEntry, + PrimaryHeader->SizeOfPartitionEntry + ); + NumberOfPartition++; + } + PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry); + } + + // + // 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. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in + its caller function DxeTpmMeasureBootHandler(). + + @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 EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format. + @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; + UINTN Pos; + UINT32 EventSize; + UINT32 EventNumber; + EFI_PHYSICAL_ADDRESS EventLogLastEntry; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + UINT32 NumberOfRvaAndSizes; + BOOLEAN HashStatus; + UINT32 CertSize; + + Status = EFI_UNSUPPORTED; + 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 + )); + goto Finish; + } + + ImageLoad->ImageLocationInMemory = ImageAddress; + ImageLoad->ImageLengthInMemory = ImageSize; + ImageLoad->ImageLinkTimeAddress = LinkTimeBase; + ImageLoad->LengthOfDevicePath = FilePathSize; + if ((FilePath != NULL) && (FilePathSize != 0)) { + 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; + } + + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset); + if (Hdr.Pe32->Signature != EFI_IMAGE_NT_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; + } + + HashStatus = Sha1Init (Sha1Ctx); + if (!HashStatus) { + goto Finish; + } + + // + // Measuring PE/COFF Image Header; + // But CheckSum field and SECURITY data directory (certificate) are excluded + // + + // + // 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 (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase; + } else { + // + // Use PE32+ offset + // + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase; + } + + HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); + if (!HashStatus) { + goto Finish; + } + + // + // 5. Skip over the image checksum (it occupies a single ULONG). + // + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + // + // 6. Since there is no Cert Directory in optional header, hash everything + // from the end of the checksum to the end of image header. + // + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } + + if (HashSize != 0) { + HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); + if (!HashStatus) { + goto Finish; + } + } + } else { + // + // 7. Hash everything from the end of the checksum to the start of the Cert Directory. + // + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase; + } else { + // + // Use PE32+ offset + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase; + } + + if (HashSize != 0) { + HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); + if (!HashStatus) { + goto Finish; + } + } + + // + // 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 (Hdr.Pe32->OptionalHeader.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) (HashBase - ImageAddress); + } else { + // + // Use PE32+ offset + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } + + if (HashSize != 0) { + HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); + if (!HashStatus) { + goto Finish; + } + } + } + + // + // 10. Set the SUM_OF_BYTES_HASHED to the size of the header + // + if (Hdr.Pe32->OptionalHeader.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; + + HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); + if (!HashStatus) { + goto Finish; + } + + 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 (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + CertSize = 0; + } else { + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } else { + // + // Use PE32+ offset. + // + CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } + } + + if (ImageSize > CertSize + SumOfBytesHashed) { + HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed); + + HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize); + if (!HashStatus) { + goto Finish; + } + } else if (ImageSize < CertSize + SumOfBytesHashed) { + goto Finish; + } + } + + // + // 17. Finalize the SHA hash. + // + HashStatus = Sha1Final (Sha1Ctx, (UINT8 *) &TcgEvent->Digest); + if (!HashStatus) { + goto Finish; + } + + // + // Log the PE data + // + EventNumber = 1; + Status = TcgProtocol->HashLogExtendEvent ( + TcgProtocol, + (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL, + 0, + TPM_ALG_SHA, + TcgEvent, + &EventNumber, + &EventLogLastEntry + ); + if (Status == EFI_OUT_OF_RESOURCES) { + // + // Out of resource here means the image is hashed and its result is extended to PCR. + // But the event log can't be saved since log area is full. + // Just return EFI_SUCCESS in order not to block the image load. + // + Status = EFI_SUCCESS; + } + +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 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. + + If check image specified by FileBuffer and File is NULL meanwhile, return EFI_ACCESS_DENIED. + + @param[in] 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. + @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service. + + @retval EFI_SUCCESS The file specified by DevicePath and non-NULL + FileBuffer did authenticate, and the platform policy dictates + that the DXE Foundation may use the file. + @retval other error value +**/ +EFI_STATUS +EFIAPI +DxeTpmMeasureBootHandler ( + IN UINT32 AuthenticationStatus, + IN CONST EFI_DEVICE_PATH_PROTOCOL *File, OPTIONAL + IN VOID *FileBuffer, + IN UINTN FileSize, + IN BOOLEAN BootPolicy + ) +{ + 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; + EFI_HANDLE TempHandle; + BOOLEAN ApplicationRequired; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol; + EFI_PHYSICAL_ADDRESS FvAddress; + UINT32 Index; + + 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 || (!ProtocolCapability.TPMPresentFlag)) { + // + // TPM device doesn't work or activate. + // + return EFI_SUCCESS; + } + + // + // Copy File Device Path + // + OrigDevicePathNode = DuplicateDevicePath (File); + + // + // 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 partition on the given devicepath + // + DevicePathNode = OrigDevicePathNode; + ASSERT (DevicePathNode != NULL); + 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 FVB protocol. + // + DevicePathNode = OrigDevicePathNode; + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &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 PE image from unmeasured Firmware volume need be measured + // The PE image from measured Firmware volume will be measured according to policy below. + // If it is driver, do not measure + // If it is application, still measure. + // + ApplicationRequired = TRUE; + + if (mCacheMeasuredHandle != Handle && mMeasuredHobData != NULL) { + // + // Search for Root FV of this PE image + // + TempHandle = Handle; + do { + Status = gBS->HandleProtocol( + TempHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID**)&FvbProtocol + ); + TempHandle = FvbProtocol->ParentHandle; + } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL); + + // + // Search in measured FV Hob + // + Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress); + if (EFI_ERROR(Status)){ + return Status; + } + + ApplicationRequired = FALSE; + + for (Index = 0; Index < mMeasuredHobData->Num; Index++) { + if(mMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) { + // + // Cache measured FV for next measurement + // + mCacheMeasuredHandle = Handle; + ApplicationRequired = TRUE; + break; + } + } + } + } + + // + // File is not found. + // + if (FileBuffer == NULL) { + Status = EFI_SECURITY_VIOLATION; + goto Finish; + } + + mTpmImageSize = FileSize; + mFileBuffer = FileBuffer; + + // + // Measure PE Image + // + DevicePathNode = OrigDevicePathNode; + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) FileBuffer; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + // + // Check for invalid parameters. + // + if (File == NULL) { + return EFI_ACCESS_DENIED; + } + + // + // 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; + ToText = ConvertDevicePathToText ( + DevicePathNode, + FALSE, + TRUE + ); + if (ToText != NULL) { + DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText)); + FreePool (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: + if (OrigDevicePathNode != NULL) { + 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 + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + + GuidHob = NULL; + + GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid); + + if (GuidHob != NULL) { + mMeasuredHobData = GET_GUID_HOB_DATA (GuidHob); + } + + return RegisterSecurity2Handler ( + DxeTpmMeasureBootHandler, + EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf new file mode 100644 index 00000000..46da9b31 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf @@ -0,0 +1,62 @@ +## @file +# Provides security service for TPM 1.2 measured boot +# +# This library instance hooks LoadImage() API to measure every image that +# is not measured in PEI phase. And, it will also measure GPT partition. +# +# Caution: This module requires additional review when modified. +# This library will have external input - PE/COFF image and GPT partition. +# This external input must be validated carefully to avoid security issues such +# as buffer overflow or integer overflow. +# +# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeTpmMeasureBootLib + MODULE_UNI_FILE = DxeTpmMeasureBootLib.uni + FILE_GUID = 6C60C7D0-922A-4b7c-87D7-E503EDD73BBF + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|DXE_DRIVER DXE_RUNTIME_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 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 + HobLib + +[Guids] + gMeasuredFvHobGuid ## SOMETIMES_CONSUMES ## HOB + +[Protocols] + gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES + gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.uni new file mode 100644 index 00000000..fc09e19b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.uni @@ -0,0 +1,22 @@ +// /** @file
+// Provides security service for TPM 1.2 measured boot
+//
+// This library instance hooks LoadImage() API to measure every image that
+// is not measured in PEI phase. And, it will also measure GPT partition.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - PE/COFF image and GPT partition.
+// This external input must be validated carefully to avoid security issues such
+// as buffer overflow or integer overflow.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service for TPM 1.2 measured boot"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library instance hooks LoadImage() API to measure every image that is not measured in PEI phase. And, it will also measure GPT partition. Caution: This module requires additional review when modified. This library will have external input - PE/COFF image and GPT partition. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.c new file mode 100644 index 00000000..7573c0f5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.c @@ -0,0 +1,207 @@ +/** @file + This library is used by other modules to measure data to TPM. + +Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> + +#include <Protocol/TcgService.h> +#include <Protocol/Tcg2Protocol.h> + +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/TpmMeasurementLib.h> + +#include <Guid/Acpi.h> +#include <IndustryStandard/Acpi.h> + + + +/** + Tpm12 measure and log data, and extend the measurement result into a specific PCR. + + @param[in] PcrIndex PCR Index. + @param[in] EventType Event type. + @param[in] EventLog Measurement event log. + @param[in] LogLen Event log length in bytes. + @param[in] HashData The start of the data buffer to be hashed, extended. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED TPM device not available. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. +**/ +EFI_STATUS +Tpm12MeasureAndLogData ( + IN UINT32 PcrIndex, + IN UINT32 EventType, + IN VOID *EventLog, + IN UINT32 LogLen, + IN VOID *HashData, + IN UINT64 HashDataLen + ) +{ + EFI_STATUS Status; + EFI_TCG_PROTOCOL *TcgProtocol; + TCG_PCR_EVENT *TcgEvent; + EFI_PHYSICAL_ADDRESS EventLogLastEntry; + UINT32 EventNumber; + + TcgEvent = NULL; + + // + // Tpm activation state is checked in HashLogExtendEvent + // + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol); + if (EFI_ERROR(Status)){ + return Status; + } + + TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (sizeof (TCG_PCR_EVENT_HDR) + LogLen); + if(TcgEvent == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TcgEvent->PCRIndex = PcrIndex; + TcgEvent->EventType = EventType; + TcgEvent->EventSize = LogLen; + CopyMem (&TcgEvent->Event[0], EventLog, LogLen); + EventNumber = 1; + Status = TcgProtocol->HashLogExtendEvent ( + TcgProtocol, + (EFI_PHYSICAL_ADDRESS)(UINTN)HashData, + HashDataLen, + TPM_ALG_SHA, + TcgEvent, + &EventNumber, + &EventLogLastEntry + ); + + FreePool (TcgEvent); + + return Status; +} + +/** + Tpm20 measure and log data, and extend the measurement result into a specific PCR. + + @param[in] PcrIndex PCR Index. + @param[in] EventType Event type. + @param[in] EventLog Measurement event log. + @param[in] LogLen Event log length in bytes. + @param[in] HashData The start of the data buffer to be hashed, extended. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED TPM device not available. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. +**/ +EFI_STATUS +Tpm20MeasureAndLogData ( + IN UINT32 PcrIndex, + IN UINT32 EventType, + IN VOID *EventLog, + IN UINT32 LogLen, + IN VOID *HashData, + IN UINT64 HashDataLen + ) +{ + EFI_STATUS Status; + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_TCG2_EVENT *Tcg2Event; + + // + // TPMPresentFlag is checked in HashLogExtendEvent + // + Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol); + if (EFI_ERROR (Status)) { + return Status; + } + + Tcg2Event = (EFI_TCG2_EVENT *) AllocateZeroPool (LogLen + sizeof (EFI_TCG2_EVENT)); + if(Tcg2Event == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Tcg2Event->Size = (UINT32)LogLen + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event); + Tcg2Event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER); + Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION; + Tcg2Event->Header.PCRIndex = PcrIndex; + Tcg2Event->Header.EventType = EventType; + CopyMem (&Tcg2Event->Event[0], EventLog, LogLen); + + Status = Tcg2Protocol->HashLogExtendEvent ( + Tcg2Protocol, + 0, + (EFI_PHYSICAL_ADDRESS)(UINTN)HashData, + HashDataLen, + Tcg2Event + ); + FreePool (Tcg2Event); + + return Status; +} + +/** + Tpm measure and log data, and extend the measurement result into a specific PCR. + + @param[in] PcrIndex PCR Index. + @param[in] EventType Event type. + @param[in] EventLog Measurement event log. + @param[in] LogLen Event log length in bytes. + @param[in] HashData The start of the data buffer to be hashed, extended. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED TPM device not available. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. +**/ +EFI_STATUS +EFIAPI +TpmMeasureAndLogData ( + IN UINT32 PcrIndex, + IN UINT32 EventType, + IN VOID *EventLog, + IN UINT32 LogLen, + IN VOID *HashData, + IN UINT64 HashDataLen + ) +{ + EFI_STATUS Status; + + // + // Try to measure using Tpm20 protocol + // + Status = Tpm20MeasureAndLogData( + PcrIndex, + EventType, + EventLog, + LogLen, + HashData, + HashDataLen + ); + + if (EFI_ERROR (Status)) { + // + // Try to measure using Tpm1.2 protocol + // + Status = Tpm12MeasureAndLogData( + PcrIndex, + EventType, + EventLog, + LogLen, + HashData, + HashDataLen + ); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf new file mode 100644 index 00000000..53b17d76 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf @@ -0,0 +1,44 @@ +## @file +# Provides TPM measurement functions for TPM1.2 and TPM 2.0 +# +# This library provides TpmMeasureAndLogData() to measure and log data, and +# extend the measurement result into a specific PCR. +# +# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DxeTpmMeasurementLib + FILE_GUID = 30930D10-AF5B-4abf-80E6-EB4FFC0AE9D1 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = TpmMeasurementLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + MODULE_UNI_FILE = DxeTpmMeasurementLib.uni + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + DxeTpmMeasurementLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + UefiBootServicesTableLib + +[Protocols] + gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES + gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.uni new file mode 100644 index 00000000..a1139810 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.uni @@ -0,0 +1,17 @@ +// /** @file
+// Provides TPM measurement functions for TPM1.2 and TPM 2.0
+//
+// This library provides TpmMeasureAndLogData() to to measure and log data, and
+// extend the measurement result into a specific PCR.
+//
+// Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM measurement functions for TPM1.2 and TPM 2.0"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provides TpmMeasureAndLogData() to to measure and log data, and extend the measurement result into a specific PCR."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.c new file mode 100644 index 00000000..71775bab --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.c @@ -0,0 +1,216 @@ +/** @file + FMP Authentication PKCS7 handler. + Provide generic FMP authentication functions for DXE/PEI post memory phase. + + Caution: This module requires additional review when modified. + This module will have external input - capsule image. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + FmpAuthenticatedHandlerPkcs7(), AuthenticateFmpImage() will receive + untrusted input and do basic validation. + + Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> + +#include <Guid/SystemResourceTable.h> +#include <Guid/FirmwareContentsSigned.h> +#include <Guid/WinCertificate.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/FmpAuthenticationLib.h> +#include <Library/PcdLib.h> +#include <Protocol/FirmwareManagement.h> +#include <Guid/SystemResourceTable.h> + +/** + The handler is used to do the authentication for FMP capsule based upon + EFI_FIRMWARE_IMAGE_AUTHENTICATION. + + Caution: This function may receive untrusted input. + + This function assumes the caller AuthenticateFmpImage() + already did basic validation for EFI_FIRMWARE_IMAGE_AUTHENTICATION. + + @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION. + @param[in] ImageSize Size of the authentication image in bytes. + @param[in] PublicKeyData The public key data used to validate the signature. + @param[in] PublicKeyDataLength The length of the public key data. + + @retval RETURN_SUCCESS Authentication pass. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS. + @retval RETURN_SECURITY_VIOLATION Authentication fail. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR. + @retval RETURN_INVALID_PARAMETER The image is in an invalid format. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT. + @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES. +**/ +RETURN_STATUS +FmpAuthenticatedHandlerPkcs7 ( + IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image, + IN UINTN ImageSize, + IN CONST UINT8 *PublicKeyData, + IN UINTN PublicKeyDataLength + ) +{ + RETURN_STATUS Status; + BOOLEAN CryptoStatus; + VOID *P7Data; + UINTN P7Length; + VOID *TempBuffer; + + DEBUG((DEBUG_INFO, "FmpAuthenticatedHandlerPkcs7 - Image: 0x%08x - 0x%08x\n", (UINTN)Image, (UINTN)ImageSize)); + + P7Length = Image->AuthInfo.Hdr.dwLength - (OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)); + P7Data = Image->AuthInfo.CertData; + + // It is a signature across the variable data and the Monotonic Count value. + TempBuffer = AllocatePool(ImageSize - Image->AuthInfo.Hdr.dwLength); + if (TempBuffer == NULL) { + DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerPkcs7: TempBuffer == NULL\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + + CopyMem( + TempBuffer, + (UINT8 *)Image + sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength, + ImageSize - sizeof(Image->MonotonicCount) - Image->AuthInfo.Hdr.dwLength + ); + CopyMem( + (UINT8 *)TempBuffer + ImageSize - sizeof(Image->MonotonicCount) - Image->AuthInfo.Hdr.dwLength, + &Image->MonotonicCount, + sizeof(Image->MonotonicCount) + ); + CryptoStatus = Pkcs7Verify( + P7Data, + P7Length, + PublicKeyData, + PublicKeyDataLength, + (UINT8 *)TempBuffer, + ImageSize - Image->AuthInfo.Hdr.dwLength + ); + FreePool(TempBuffer); + if (!CryptoStatus) { + // + // If PKCS7 signature verification fails, AUTH tested failed bit is set. + // + DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerPkcs7: Pkcs7Verify() failed\n")); + Status = RETURN_SECURITY_VIOLATION; + goto Done; + } + DEBUG((DEBUG_INFO, "FmpAuthenticatedHandlerPkcs7: PASS verification\n")); + + Status = RETURN_SUCCESS; + +Done: + return Status; +} + +/** + The function is used to do the authentication for FMP capsule based upon + EFI_FIRMWARE_IMAGE_AUTHENTICATION. + + The FMP capsule image should start with EFI_FIRMWARE_IMAGE_AUTHENTICATION, + followed by the payload. + + If the return status is RETURN_SUCCESS, the caller may continue the rest + FMP update process. + If the return status is NOT RETURN_SUCCESS, the caller should stop the FMP + update process and convert the return status to LastAttemptStatus + to indicate that FMP update fails. + The LastAttemptStatus can be got from ESRT table or via + EFI_FIRMWARE_MANAGEMENT_PROTOCOL.GetImageInfo(). + + Caution: This function may receive untrusted input. + + @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION. + @param[in] ImageSize Size of the authentication image in bytes. + @param[in] PublicKeyData The public key data used to validate the signature. + @param[in] PublicKeyDataLength The length of the public key data. + + @retval RETURN_SUCCESS Authentication pass. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS. + @retval RETURN_SECURITY_VIOLATION Authentication fail. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR. + @retval RETURN_INVALID_PARAMETER The image is in an invalid format. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT. + @retval RETURN_UNSUPPORTED No Authentication handler associated with CertType. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT. + @retval RETURN_UNSUPPORTED Image or ImageSize is invalid. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT. + @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES. +**/ +RETURN_STATUS +EFIAPI +AuthenticateFmpImage ( + IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image, + IN UINTN ImageSize, + IN CONST UINT8 *PublicKeyData, + IN UINTN PublicKeyDataLength + ) +{ + GUID *CertType; + EFI_STATUS Status; + + if ((Image == NULL) || (ImageSize == 0)) { + return RETURN_UNSUPPORTED; + } + + if (ImageSize < sizeof(EFI_FIRMWARE_IMAGE_AUTHENTICATION)) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n")); + return RETURN_INVALID_PARAMETER; + } + if (Image->AuthInfo.Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too small\n")); + return RETURN_INVALID_PARAMETER; + } + if ((UINTN) Image->AuthInfo.Hdr.dwLength > MAX_UINTN - sizeof(UINT64)) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too big\n")); + return RETURN_INVALID_PARAMETER; + } + if (ImageSize <= sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n")); + return RETURN_INVALID_PARAMETER; + } + if (Image->AuthInfo.Hdr.wRevision != 0x0200) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wRevision: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wRevision, (UINTN)0x0200)); + return RETURN_INVALID_PARAMETER; + } + if (Image->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wCertificateType: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wCertificateType, (UINTN)WIN_CERT_TYPE_EFI_GUID)); + return RETURN_INVALID_PARAMETER; + } + + CertType = &Image->AuthInfo.CertType; + DEBUG((DEBUG_INFO, "AuthenticateFmpImage - CertType: %g\n", CertType)); + + if (CompareGuid (&gEfiCertPkcs7Guid, CertType)) { + // + // Call the match handler to extract raw data for the input section data. + // + Status = FmpAuthenticatedHandlerPkcs7 ( + Image, + ImageSize, + PublicKeyData, + PublicKeyDataLength + ); + return Status; + } + + // + // Not found, the input guided section is not supported. + // + return RETURN_UNSUPPORTED; +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf new file mode 100644 index 00000000..65e5648a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf @@ -0,0 +1,43 @@ +## @file +# FMP Authentication PKCS7 handler. +# +# Instance of FmpAuthentication Library for DXE/PEI post memory phase. +# +# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FmpAuthenticationLibPkcs7 + MODULE_UNI_FILE = FmpAuthenticationLibPkcs7.uni + FILE_GUID = F4EA205B-7345-452C-9D62-53BA6F3B8910 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FmpAuthenticationLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + FmpAuthenticationLibPkcs7.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + BaseCryptLib + +[Guids] + gEfiCertPkcs7Guid ## CONSUMES ## GUID diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.uni new file mode 100644 index 00000000..e499b6d4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.uni @@ -0,0 +1,21 @@ +// /** @file
+// FMP Authentication PKCS7 handler.
+//
+// This library provide FMP Authentication PKCS7 handler to verify EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - capsule image.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "FMP Authentication PKCS7 handler."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provide FMP Authentication PKCS7 handler to verify EFI_FIRMWARE_IMAGE_AUTHENTICATION."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.c new file mode 100644 index 00000000..f32fc486 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.c @@ -0,0 +1,354 @@ +/** @file + FMP Authentication RSA2048SHA256 handler. + Provide generic FMP authentication functions for DXE/PEI post memory phase. + + Caution: This module requires additional review when modified. + This module will have external input - capsule image. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + + FmpAuthenticatedHandlerRsa2048Sha256(), AuthenticateFmpImage() will receive + untrusted input and do basic validation. + + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> + +#include <Guid/SystemResourceTable.h> +#include <Guid/FirmwareContentsSigned.h> +#include <Guid/WinCertificate.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/FmpAuthenticationLib.h> +#include <Library/PcdLib.h> +#include <Protocol/FirmwareManagement.h> +#include <Guid/SystemResourceTable.h> + +/// +/// Public Exponent of RSA Key. +/// +STATIC CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 }; + +/** + The handler is used to do the authentication for FMP capsule based upon + EFI_FIRMWARE_IMAGE_AUTHENTICATION. + + Caution: This function may receive untrusted input. + + This function assumes the caller AuthenticateFmpImage() + already did basic validation for EFI_FIRMWARE_IMAGE_AUTHENTICATION. + + @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION. + @param[in] ImageSize Size of the authentication image in bytes. + @param[in] PublicKeyData The public key data used to validate the signature. + @param[in] PublicKeyDataLength The length of the public key data. + + @retval RETURN_SUCCESS Authentication pass. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS. + @retval RETURN_SECURITY_VIOLATION Authentication fail. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR. + @retval RETURN_INVALID_PARAMETER The image is in an invalid format. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT. + @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES. +**/ +RETURN_STATUS +FmpAuthenticatedHandlerRsa2048Sha256 ( + IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image, + IN UINTN ImageSize, + IN CONST UINT8 *PublicKeyData, + IN UINTN PublicKeyDataLength + ) +{ + RETURN_STATUS Status; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlockRsa2048Sha256; + BOOLEAN CryptoStatus; + UINT8 Digest[SHA256_DIGEST_SIZE]; + UINT8 *PublicKey; + UINTN PublicKeyBufferSize; + VOID *HashContext; + VOID *Rsa; + + DEBUG ((DEBUG_INFO, "FmpAuthenticatedHandlerRsa2048Sha256 - Image: 0x%08x - 0x%08x\n", (UINTN)Image, (UINTN)ImageSize)); + + if (Image->AuthInfo.Hdr.dwLength != OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof(EFI_CERT_BLOCK_RSA_2048_SHA256)) { + DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256 - dwLength: 0x%04x, dwLength - 0x%04x\n", (UINTN)Image->AuthInfo.Hdr.dwLength, (UINTN)OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof(EFI_CERT_BLOCK_RSA_2048_SHA256))); + return RETURN_INVALID_PARAMETER; + } + + CertBlockRsa2048Sha256 = (EFI_CERT_BLOCK_RSA_2048_SHA256 *)Image->AuthInfo.CertData; + if (!CompareGuid(&CertBlockRsa2048Sha256->HashType, &gEfiHashAlgorithmSha256Guid)) { + DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256 - HashType: %g, expect - %g\n", &CertBlockRsa2048Sha256->HashType, &gEfiHashAlgorithmSha256Guid)); + return RETURN_INVALID_PARAMETER; + } + + HashContext = NULL; + Rsa = NULL; + + // + // Allocate hash context buffer required for SHA 256 + // + HashContext = AllocatePool (Sha256GetContextSize ()); + if (HashContext == NULL) { + CryptoStatus = FALSE; + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Can not allocate hash context\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + + // + // Hash public key from data payload with SHA256. + // + ZeroMem (Digest, SHA256_DIGEST_SIZE); + CryptoStatus = Sha256Init (HashContext); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Init() failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey)); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Update() failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + CryptoStatus = Sha256Final (HashContext, Digest); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Final() failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + + // + // Fail if the PublicKey is not one of the public keys in the input PublicKeyData. + // + PublicKey = (VOID *)PublicKeyData; + PublicKeyBufferSize = PublicKeyDataLength; + CryptoStatus = FALSE; + while (PublicKeyBufferSize != 0) { + if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) { + CryptoStatus = TRUE; + break; + } + PublicKey = PublicKey + SHA256_DIGEST_SIZE; + PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE; + } + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Public key in section is not supported\n")); + Status = RETURN_SECURITY_VIOLATION; + goto Done; + } + + // + // Generate & Initialize RSA Context. + // + Rsa = RsaNew (); + if (Rsa == NULL) { + CryptoStatus = FALSE; + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaNew() failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + + // + // Set RSA Key Components. + // NOTE: Only N and E are needed to be set as RSA public key for signature verification. + // + CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey)); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE)); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + + // + // Hash data payload with SHA256. + // + ZeroMem (Digest, SHA256_DIGEST_SIZE); + CryptoStatus = Sha256Init (HashContext); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Init() failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + + // It is a signature across the variable data and the Monotonic Count value. + CryptoStatus = Sha256Update ( + HashContext, + (UINT8 *)Image + sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength, + ImageSize - sizeof(Image->MonotonicCount) - Image->AuthInfo.Hdr.dwLength + ); + if (!CryptoStatus) { + DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Update() failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + CryptoStatus = Sha256Update ( + HashContext, + (UINT8 *)&Image->MonotonicCount, + sizeof(Image->MonotonicCount) + ); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Update() failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + CryptoStatus = Sha256Final (HashContext, Digest); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Final() failed\n")); + Status = RETURN_OUT_OF_RESOURCES; + goto Done; + } + + // + // Verify the RSA 2048 SHA 256 signature. + // + CryptoStatus = RsaPkcs1Verify ( + Rsa, + Digest, + SHA256_DIGEST_SIZE, + CertBlockRsa2048Sha256->Signature, + sizeof (CertBlockRsa2048Sha256->Signature) + ); + if (!CryptoStatus) { + // + // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set. + // + DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaPkcs1Verify() failed\n")); + Status = RETURN_SECURITY_VIOLATION; + goto Done; + } + DEBUG ((DEBUG_INFO, "FmpAuthenticatedHandlerRsa2048Sha256: PASS verification\n")); + + Status = RETURN_SUCCESS; + +Done: + // + // Free allocated resources used to perform RSA 2048 SHA 256 signature verification + // + if (Rsa != NULL) { + RsaFree (Rsa); + } + if (HashContext != NULL) { + FreePool (HashContext); + } + + return Status; +} + +/** + The function is used to do the authentication for FMP capsule based upon + EFI_FIRMWARE_IMAGE_AUTHENTICATION. + + The FMP capsule image should start with EFI_FIRMWARE_IMAGE_AUTHENTICATION, + followed by the payload. + + If the return status is RETURN_SUCCESS, the caller may continue the rest + FMP update process. + If the return status is NOT RETURN_SUCCESS, the caller should stop the FMP + update process and convert the return status to LastAttemptStatus + to indicate that FMP update fails. + The LastAttemptStatus can be got from ESRT table or via + EFI_FIRMWARE_MANAGEMENT_PROTOCOL.GetImageInfo(). + + Caution: This function may receive untrusted input. + + @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION. + @param[in] ImageSize Size of the authentication image in bytes. + @param[in] PublicKeyData The public key data used to validate the signature. + @param[in] PublicKeyDataLength The length of the public key data. + + @retval RETURN_SUCCESS Authentication pass. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS. + @retval RETURN_SECURITY_VIOLATION Authentication fail. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR. + @retval RETURN_INVALID_PARAMETER The image is in an invalid format. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT. + @retval RETURN_UNSUPPORTED No Authentication handler associated with CertType. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT. + @retval RETURN_UNSUPPORTED Image or ImageSize is invalid. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT. + @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType. + The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES. +**/ +RETURN_STATUS +EFIAPI +AuthenticateFmpImage ( + IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image, + IN UINTN ImageSize, + IN CONST UINT8 *PublicKeyData, + IN UINTN PublicKeyDataLength + ) +{ + GUID *CertType; + EFI_STATUS Status; + + if ((Image == NULL) || (ImageSize == 0)) { + return RETURN_UNSUPPORTED; + } + + if ((PublicKeyDataLength % SHA256_DIGEST_SIZE) != 0) { + DEBUG ((DEBUG_ERROR, "PublicKeyDataLength is not multiple SHA256 size\n")); + return RETURN_UNSUPPORTED; + } + + if (ImageSize < sizeof(EFI_FIRMWARE_IMAGE_AUTHENTICATION)) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n")); + return RETURN_INVALID_PARAMETER; + } + if (Image->AuthInfo.Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too small\n")); + return RETURN_INVALID_PARAMETER; + } + if ((UINTN) Image->AuthInfo.Hdr.dwLength > MAX_UINTN - sizeof(UINT64)) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too big\n")); + return RETURN_INVALID_PARAMETER; + } + if (ImageSize <= sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n")); + return RETURN_INVALID_PARAMETER; + } + if (Image->AuthInfo.Hdr.wRevision != 0x0200) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wRevision: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wRevision, (UINTN)0x0200)); + return RETURN_INVALID_PARAMETER; + } + if (Image->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) { + DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wCertificateType: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wCertificateType, (UINTN)WIN_CERT_TYPE_EFI_GUID)); + return RETURN_INVALID_PARAMETER; + } + + CertType = &Image->AuthInfo.CertType; + DEBUG((DEBUG_INFO, "AuthenticateFmpImage - CertType: %g\n", CertType)); + + if (CompareGuid (&gEfiCertTypeRsa2048Sha256Guid, CertType)) { + // + // Call the match handler to extract raw data for the input section data. + // + Status = FmpAuthenticatedHandlerRsa2048Sha256 ( + Image, + ImageSize, + PublicKeyData, + PublicKeyDataLength + ); + return Status; + } + + // + // Not found, the input guided section is not supported. + // + return RETURN_UNSUPPORTED; +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.inf new file mode 100644 index 00000000..f5fc4a8e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.inf @@ -0,0 +1,44 @@ +## @file +# FMP Authentication RSA2048SHA256 handler. +# +# Instance of FmpAuthentication Library for DXE/PEI post memory phase. +# +# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FmpAuthenticationLibRsa2048Sha256 + MODULE_UNI_FILE = FmpAuthenticationLibRsa2048Sha256.uni + FILE_GUID = 105FF0EA-A0C0-48A8-B8F7-E8B4D62A1019 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FmpAuthenticationLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + FmpAuthenticationLibRsa2048Sha256.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + BaseCryptLib + +[Guids] + gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate. + gEfiHashAlgorithmSha256Guid ## SOMETIMES_CONSUMES ## GUID diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.uni new file mode 100644 index 00000000..c7bb5be9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.uni @@ -0,0 +1,21 @@ +// /** @file
+// FMP Authentication RSA2048SHA256 handler.
+//
+// This library provide FMP Authentication RSA2048SHA256 handler to verify EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - capsule image.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "FMP Authentication RSA2048SHA256 handler."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provide FMP Authentication RSA2048SHA256 handler to verify EFI_FIRMWARE_IMAGE_AUTHENTICATION."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c new file mode 100644 index 00000000..9b43b577 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c @@ -0,0 +1,149 @@ +/** @file + This library is BaseCrypto SHA1 hash instance. + It can be registered to BaseCrypto router, to serve as hash engine. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/HashLib.h> + +/** + The function set SHA1 to digest list. + + @param DigestList digest list + @param Sha1Digest SHA1 digest +**/ +VOID +Tpm2SetSha1ToDigestList ( + IN TPML_DIGEST_VALUES *DigestList, + IN UINT8 *Sha1Digest + ) +{ + DigestList->count = 1; + DigestList->digests[0].hashAlg = TPM_ALG_SHA1; + CopyMem ( + DigestList->digests[0].digest.sha1, + Sha1Digest, + SHA1_DIGEST_SIZE + ); +} + +/** + Start hash sequence. + + @param HashHandle Hash handle. + + @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. + @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. +**/ +EFI_STATUS +EFIAPI +Sha1HashInit ( + OUT HASH_HANDLE *HashHandle + ) +{ + VOID *Sha1Ctx; + UINTN CtxSize; + + CtxSize = Sha1GetContextSize (); + Sha1Ctx = AllocatePool (CtxSize); + ASSERT (Sha1Ctx != NULL); + + Sha1Init (Sha1Ctx); + + *HashHandle = (HASH_HANDLE)Sha1Ctx; + + return EFI_SUCCESS; +} + +/** + Update hash sequence data. + + @param HashHandle Hash handle. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + + @retval EFI_SUCCESS Hash sequence updated. +**/ +EFI_STATUS +EFIAPI +Sha1HashUpdate ( + IN HASH_HANDLE HashHandle, + IN VOID *DataToHash, + IN UINTN DataToHashLen + ) +{ + VOID *Sha1Ctx; + + Sha1Ctx = (VOID *)HashHandle; + Sha1Update (Sha1Ctx, DataToHash, DataToHashLen); + + return EFI_SUCCESS; +} + +/** + Complete hash sequence complete. + + @param HashHandle Hash handle. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +Sha1HashFinal ( + IN HASH_HANDLE HashHandle, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + UINT8 Digest[SHA1_DIGEST_SIZE]; + VOID *Sha1Ctx; + + Sha1Ctx = (VOID *)HashHandle; + Sha1Final (Sha1Ctx, Digest); + + FreePool (Sha1Ctx); + + Tpm2SetSha1ToDigestList (DigestList, Digest); + + return EFI_SUCCESS; +} + +HASH_INTERFACE mSha1InternalHashInstance = { + HASH_ALGORITHM_SHA1_GUID, + Sha1HashInit, + Sha1HashUpdate, + Sha1HashFinal, +}; + +/** + The function register SHA1 instance. + + @retval EFI_SUCCESS SHA1 instance is registered, or system does not support register SHA1 instance +**/ +EFI_STATUS +EFIAPI +HashInstanceLibSha1Constructor ( + VOID + ) +{ + EFI_STATUS Status; + + Status = RegisterHashInterfaceLib (&mSha1InternalHashInstance); + if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) { + // + // Unsupported means platform policy does not need this instance enabled. + // + return EFI_SUCCESS; + } + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf new file mode 100644 index 00000000..44b9b12b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf @@ -0,0 +1,41 @@ +## @file +# Provides BaseCrypto SHA1 hash service +# +# This library can be registered to BaseCrypto router, to serve as hash engine. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HashInstanceLibSha1 + MODULE_UNI_FILE = HashInstanceLibSha1.uni + FILE_GUID = 9A7A6AB4-9DA6-4aa4-90CB-6D4B79EDA7B9 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL + CONSTRUCTOR = HashInstanceLibSha1Constructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + HashInstanceLibSha1.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + MemoryAllocationLib + BaseCryptLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.uni new file mode 100644 index 00000000..663a354c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.uni @@ -0,0 +1,16 @@ +// /** @file
+// Provides BaseCrypto SHA1 hash service
+//
+// This library can be registered to BaseCrypto router, to serve as hash engine.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides BaseCrypto SHA1 hash service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to BaseCrypto router, to serve as hash engine."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c new file mode 100644 index 00000000..aab25166 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c @@ -0,0 +1,149 @@ +/** @file + This library is BaseCrypto SHA256 hash instance. + It can be registered to BaseCrypto router, to serve as hash engine. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/HashLib.h> + +/** + The function set SHA256 to digest list. + + @param DigestList digest list + @param Sha256Digest SHA256 digest +**/ +VOID +Tpm2SetSha256ToDigestList ( + IN TPML_DIGEST_VALUES *DigestList, + IN UINT8 *Sha256Digest + ) +{ + DigestList->count = 1; + DigestList->digests[0].hashAlg = TPM_ALG_SHA256; + CopyMem ( + DigestList->digests[0].digest.sha256, + Sha256Digest, + SHA256_DIGEST_SIZE + ); +} + +/** + Start hash sequence. + + @param HashHandle Hash handle. + + @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. + @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. +**/ +EFI_STATUS +EFIAPI +Sha256HashInit ( + OUT HASH_HANDLE *HashHandle + ) +{ + VOID *Sha256Ctx; + UINTN CtxSize; + + CtxSize = Sha256GetContextSize (); + Sha256Ctx = AllocatePool (CtxSize); + ASSERT (Sha256Ctx != NULL); + + Sha256Init (Sha256Ctx); + + *HashHandle = (HASH_HANDLE)Sha256Ctx; + + return EFI_SUCCESS; +} + +/** + Update hash sequence data. + + @param HashHandle Hash handle. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + + @retval EFI_SUCCESS Hash sequence updated. +**/ +EFI_STATUS +EFIAPI +Sha256HashUpdate ( + IN HASH_HANDLE HashHandle, + IN VOID *DataToHash, + IN UINTN DataToHashLen + ) +{ + VOID *Sha256Ctx; + + Sha256Ctx = (VOID *)HashHandle; + Sha256Update (Sha256Ctx, DataToHash, DataToHashLen); + + return EFI_SUCCESS; +} + +/** + Complete hash sequence complete. + + @param HashHandle Hash handle. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +Sha256HashFinal ( + IN HASH_HANDLE HashHandle, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + UINT8 Digest[SHA256_DIGEST_SIZE]; + VOID *Sha256Ctx; + + Sha256Ctx = (VOID *)HashHandle; + Sha256Final (Sha256Ctx, Digest); + + FreePool (Sha256Ctx); + + Tpm2SetSha256ToDigestList (DigestList, Digest); + + return EFI_SUCCESS; +} + +HASH_INTERFACE mSha256InternalHashInstance = { + HASH_ALGORITHM_SHA256_GUID, + Sha256HashInit, + Sha256HashUpdate, + Sha256HashFinal, +}; + +/** + The function register SHA256 instance. + + @retval EFI_SUCCESS SHA256 instance is registered, or system does not support register SHA256 instance +**/ +EFI_STATUS +EFIAPI +HashInstanceLibSha256Constructor ( + VOID + ) +{ + EFI_STATUS Status; + + Status = RegisterHashInterfaceLib (&mSha256InternalHashInstance); + if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) { + // + // Unsupported means platform policy does not need this instance enabled. + // + return EFI_SUCCESS; + } + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf new file mode 100644 index 00000000..cecd7841 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf @@ -0,0 +1,41 @@ +## @file +# Provides BaseCrypto SHA256 hash service +# +# This library can be registered to BaseCrypto router, to serve as hash engine. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HashInstanceLibSha256 + MODULE_UNI_FILE = HashInstanceLibSha256.uni + FILE_GUID = 5810798A-ED30-4080-8DD7-B9667A748C02 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL + CONSTRUCTOR = HashInstanceLibSha256Constructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + HashInstanceLibSha256.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + MemoryAllocationLib + BaseCryptLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.uni new file mode 100644 index 00000000..601330a0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.uni @@ -0,0 +1,16 @@ +// /** @file
+// Provides BaseCrypto SHA256 hash service
+//
+// This library can be registered to BaseCrypto router, to serve as hash engine.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides BaseCrypto SHA256 hash service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to BaseCrypto router, to serve as hash engine."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.c new file mode 100644 index 00000000..502a8e20 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.c @@ -0,0 +1,149 @@ +/** @file + This library is BaseCrypto SHA384 hash instance. + It can be registered to BaseCrypto router, to serve as hash engine. + +Copyright (c) 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/HashLib.h> + +/** + The function set SHA384 to digest list. + + @param DigestList digest list + @param Sha384Digest SHA384 digest +**/ +VOID +Tpm2SetSha384ToDigestList ( + IN TPML_DIGEST_VALUES *DigestList, + IN UINT8 *Sha384Digest + ) +{ + DigestList->count = 1; + DigestList->digests[0].hashAlg = TPM_ALG_SHA384; + CopyMem ( + DigestList->digests[0].digest.sha384, + Sha384Digest, + SHA384_DIGEST_SIZE + ); +} + +/** + Start hash sequence. + + @param HashHandle Hash handle. + + @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. + @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. +**/ +EFI_STATUS +EFIAPI +Sha384HashInit ( + OUT HASH_HANDLE *HashHandle + ) +{ + VOID *Sha384Ctx; + UINTN CtxSize; + + CtxSize = Sha384GetContextSize (); + Sha384Ctx = AllocatePool (CtxSize); + ASSERT (Sha384Ctx != NULL); + + Sha384Init (Sha384Ctx); + + *HashHandle = (HASH_HANDLE)Sha384Ctx; + + return EFI_SUCCESS; +} + +/** + Update hash sequence data. + + @param HashHandle Hash handle. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + + @retval EFI_SUCCESS Hash sequence updated. +**/ +EFI_STATUS +EFIAPI +Sha384HashUpdate ( + IN HASH_HANDLE HashHandle, + IN VOID *DataToHash, + IN UINTN DataToHashLen + ) +{ + VOID *Sha384Ctx; + + Sha384Ctx = (VOID *)HashHandle; + Sha384Update (Sha384Ctx, DataToHash, DataToHashLen); + + return EFI_SUCCESS; +} + +/** + Complete hash sequence complete. + + @param HashHandle Hash handle. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +Sha384HashFinal ( + IN HASH_HANDLE HashHandle, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + UINT8 Digest[SHA384_DIGEST_SIZE]; + VOID *Sha384Ctx; + + Sha384Ctx = (VOID *)HashHandle; + Sha384Final (Sha384Ctx, Digest); + + FreePool (Sha384Ctx); + + Tpm2SetSha384ToDigestList (DigestList, Digest); + + return EFI_SUCCESS; +} + +HASH_INTERFACE mSha384InternalHashInstance = { + HASH_ALGORITHM_SHA384_GUID, + Sha384HashInit, + Sha384HashUpdate, + Sha384HashFinal, +}; + +/** + The function register SHA384 instance. + + @retval EFI_SUCCESS SHA384 instance is registered, or system does not support register SHA384 instance +**/ +EFI_STATUS +EFIAPI +HashInstanceLibSha384Constructor ( + VOID + ) +{ + EFI_STATUS Status; + + Status = RegisterHashInterfaceLib (&mSha384InternalHashInstance); + if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) { + // + // Unsupported means platform policy does not need this instance enabled. + // + return EFI_SUCCESS; + } + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.inf new file mode 100644 index 00000000..63d178e0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.inf @@ -0,0 +1,40 @@ +## @file +# Provides BaseCrypto SHA384 hash service +# +# This library can be registered to BaseCrypto router, to serve as hash engine. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HashInstanceLibSha384 + MODULE_UNI_FILE = HashInstanceLibSha384.uni + FILE_GUID = 74223710-17A9-478F-9B24-E354496B968B + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL + CONSTRUCTOR = HashInstanceLibSha384Constructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + HashInstanceLibSha384.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + BaseCryptLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.uni new file mode 100644 index 00000000..9cd02212 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha384/HashInstanceLibSha384.uni @@ -0,0 +1,16 @@ +// /** @file
+// Provides BaseCrypto SHA384 hash service
+//
+// This library can be registered to BaseCrypto router, to serve as hash engine.
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides BaseCrypto SHA384 hash service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to BaseCrypto router, to serve as hash engine."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.c new file mode 100644 index 00000000..afd7c4bc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.c @@ -0,0 +1,148 @@ +/** @file + This library is BaseCrypto SHA512 hash instance. + It can be registered to BaseCrypto router, to serve as hash engine. + +Copyright (c) 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/HashLib.h> + +/** + The function set SHA512 to digest list. + + @param DigestList digest list + @param Sha512Digest SHA512 digest +**/ +VOID +Tpm2SetSha512ToDigestList ( + IN TPML_DIGEST_VALUES *DigestList, + IN UINT8 *Sha512Digest + ) +{ + DigestList->count = 1; + DigestList->digests[0].hashAlg = TPM_ALG_SHA512; + CopyMem ( + DigestList->digests[0].digest.sha512, + Sha512Digest, + SHA512_DIGEST_SIZE + ); +} + +/** + Start hash sequence. + + @param HashHandle Hash handle. + + @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. + @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. +**/ +EFI_STATUS +EFIAPI +Sha512HashInit ( + OUT HASH_HANDLE *HashHandle + ) +{ + VOID *Sha512Ctx; + UINTN CtxSize; + + CtxSize = Sha512GetContextSize (); + Sha512Ctx = AllocatePool (CtxSize); + ASSERT (Sha512Ctx != NULL); + + Sha512Init (Sha512Ctx); + + *HashHandle = (HASH_HANDLE)Sha512Ctx; + + return EFI_SUCCESS; +} + +/** + Update hash sequence data. + + @param HashHandle Hash handle. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + + @retval EFI_SUCCESS Hash sequence updated. +**/ +EFI_STATUS +EFIAPI +Sha512HashUpdate ( + IN HASH_HANDLE HashHandle, + IN VOID *DataToHash, + IN UINTN DataToHashLen + ) +{ + VOID *Sha512Ctx; + + Sha512Ctx = (VOID *)HashHandle; + Sha512Update (Sha512Ctx, DataToHash, DataToHashLen); + + return EFI_SUCCESS; +} + +/** + Complete hash sequence complete. + + @param HashHandle Hash handle. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +Sha512HashFinal ( + IN HASH_HANDLE HashHandle, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + UINT8 Digest[SHA512_DIGEST_SIZE]; + VOID *Sha512Ctx; + + Sha512Ctx = (VOID *)HashHandle; + Sha512Final (Sha512Ctx, Digest); + + FreePool (Sha512Ctx); + + Tpm2SetSha512ToDigestList (DigestList, Digest); + + return EFI_SUCCESS; +} + +HASH_INTERFACE mSha512InternalHashInstance = { + HASH_ALGORITHM_SHA512_GUID, + Sha512HashInit, + Sha512HashUpdate, + Sha512HashFinal, +}; + +/** + The function register SHA512 instance. + + @retval EFI_SUCCESS SHA512 instance is registered, or system does not support register SHA512 instance +**/ +EFI_STATUS +EFIAPI +HashInstanceLibSha512Constructor ( + VOID + ) +{ + EFI_STATUS Status; + + Status = RegisterHashInterfaceLib (&mSha512InternalHashInstance); + if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) { + // + // Unsupported means platform policy does not need this instance enabled. + // + return EFI_SUCCESS; + } + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.inf new file mode 100644 index 00000000..256152a5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.inf @@ -0,0 +1,40 @@ +## @file +# Provides BaseCrypto SHA512 hash service +# +# This library can be registered to BaseCrypto router, to serve as hash engine. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HashInstanceLibSha512 + MODULE_UNI_FILE = HashInstanceLibSha512.uni + FILE_GUID = 959C3685-AC3F-4F3E-AC5B-7E2A64BADD36 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL + CONSTRUCTOR = HashInstanceLibSha512Constructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + HashInstanceLibSha512.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + BaseCryptLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.uni new file mode 100644 index 00000000..b4c4b4c2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSha512/HashInstanceLibSha512.uni @@ -0,0 +1,16 @@ +// /** @file
+// Provides BaseCrypto SHA512 hash service
+//
+// This library can be registered to BaseCrypto router, to serve as hash engine.
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides BaseCrypto SHA512 hash service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to BaseCrypto router, to serve as hash engine."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.c new file mode 100644 index 00000000..be175bf1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.c @@ -0,0 +1,150 @@ +/** @file + BaseCrypto SM3 hash instance library. + It can be registered to BaseCrypto router, to serve as hash engine. + + Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <PiPei.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/HashLib.h> + +/** + The function set SM3 to digest list. + + @param DigestList digest list + @param Sm3Digest SM3 digest +**/ +VOID +Tpm2SetSm3ToDigestList ( + IN TPML_DIGEST_VALUES *DigestList, + IN UINT8 *Sm3Digest + ) +{ + DigestList->count = 1; + DigestList->digests[0].hashAlg = TPM_ALG_SM3_256; + CopyMem ( + DigestList->digests[0].digest.sm3_256, + Sm3Digest, + SM3_256_DIGEST_SIZE + ); +} + +/** + Start hash sequence. + + @param HashHandle Hash handle. + + @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. + @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. +**/ +EFI_STATUS +EFIAPI +Sm3HashInit ( + OUT HASH_HANDLE *HashHandle + ) +{ + VOID *Sm3Ctx; + UINTN CtxSize; + + CtxSize = Sm3GetContextSize (); + Sm3Ctx = AllocatePool (CtxSize); + if (Sm3Ctx == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Sm3Init (Sm3Ctx); + + *HashHandle = (HASH_HANDLE)Sm3Ctx; + + return EFI_SUCCESS; +} + +/** + Update hash sequence data. + + @param HashHandle Hash handle. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + + @retval EFI_SUCCESS Hash sequence updated. +**/ +EFI_STATUS +EFIAPI +Sm3HashUpdate ( + IN HASH_HANDLE HashHandle, + IN VOID *DataToHash, + IN UINTN DataToHashLen + ) +{ + VOID *Sm3Ctx; + + Sm3Ctx = (VOID *)HashHandle; + Sm3Update (Sm3Ctx, DataToHash, DataToHashLen); + + return EFI_SUCCESS; +} + +/** + Complete hash sequence complete. + + @param HashHandle Hash handle. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +Sm3HashFinal ( + IN HASH_HANDLE HashHandle, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + UINT8 Digest[SM3_256_DIGEST_SIZE]; + VOID *Sm3Ctx; + + Sm3Ctx = (VOID *)HashHandle; + Sm3Final (Sm3Ctx, Digest); + + FreePool (Sm3Ctx); + + Tpm2SetSm3ToDigestList (DigestList, Digest); + + return EFI_SUCCESS; +} + +HASH_INTERFACE mSm3InternalHashInstance = { + HASH_ALGORITHM_SM3_256_GUID, + Sm3HashInit, + Sm3HashUpdate, + Sm3HashFinal, +}; + +/** + The function register SM3 instance. + + @retval EFI_SUCCESS SM3 instance is registered, or system dose not support register SM3 instance +**/ +EFI_STATUS +EFIAPI +HashInstanceLibSm3Constructor ( + VOID + ) +{ + EFI_STATUS Status; + + Status = RegisterHashInterfaceLib (&mSm3InternalHashInstance); + if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) { + // + // Unsupported means platform policy does not need this instance enabled. + // + return EFI_SUCCESS; + } + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf new file mode 100644 index 00000000..c82ab49d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.inf @@ -0,0 +1,41 @@ +## @file +# Provides BaseCrypto SM3 hash service +# +# This library can be registered to BaseCrypto router, to serve as hash engine. +# +# Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HashInstanceLibSm3 + MODULE_UNI_FILE = HashInstanceLibSm3.uni + FILE_GUID = C5865D5D-9ACE-39FB-DC7C-0511891D40F9 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL + CONSTRUCTOR = HashInstanceLibSm3Constructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + HashInstanceLibSm3.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + MemoryAllocationLib + BaseCryptLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.uni new file mode 100644 index 00000000..07a5c53d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashInstanceLibSm3/HashInstanceLibSm3.uni @@ -0,0 +1,15 @@ +// /** @file
+// Provides BaseCrypto SM3 hash service
+//
+// This library can be registered to BaseCrypto router, to serve as hash engine.
+//
+// Copyright (c) 2013 - 2019, Intel Corporation. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides BaseCrypto SM3 hash service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to BaseCrypto router, to serve as hash engine."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c new file mode 100644 index 00000000..2e550e64 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c @@ -0,0 +1,72 @@ +/** @file + This is BaseCrypto router support function. + +Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/HashLib.h> +#include <Protocol/Tcg2Protocol.h> + +typedef struct { + EFI_GUID Guid; + UINT32 Mask; +} TPM2_HASH_MASK; + +TPM2_HASH_MASK mTpm2HashMask[] = { + {HASH_ALGORITHM_SHA1_GUID, HASH_ALG_SHA1}, + {HASH_ALGORITHM_SHA256_GUID, HASH_ALG_SHA256}, + {HASH_ALGORITHM_SHA384_GUID, HASH_ALG_SHA384}, + {HASH_ALGORITHM_SHA512_GUID, HASH_ALG_SHA512}, + {HASH_ALGORITHM_SM3_256_GUID, HASH_ALG_SM3_256}, +}; + +/** + The function get hash mask info from algorithm. + + @param HashGuid Hash Guid + + @return HashMask +**/ +UINT32 +EFIAPI +Tpm2GetHashMaskFromAlgo ( + IN EFI_GUID *HashGuid + ) +{ + UINTN Index; + for (Index = 0; Index < sizeof(mTpm2HashMask)/sizeof(mTpm2HashMask[0]); Index++) { + if (CompareGuid (HashGuid, &mTpm2HashMask[Index].Guid)) { + return mTpm2HashMask[Index].Mask; + } + } + return 0; +} + +/** + The function set digest to digest list. + + @param DigestList digest list + @param Digest digest data +**/ +VOID +EFIAPI +Tpm2SetHashToDigestList ( + IN OUT TPML_DIGEST_VALUES *DigestList, + IN TPML_DIGEST_VALUES *Digest + ) +{ + CopyMem ( + &DigestList->digests[DigestList->count], + &Digest->digests[0], + sizeof(Digest->digests[0]) + ); + DigestList->count ++; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.h new file mode 100644 index 00000000..6af53aa2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.h @@ -0,0 +1,38 @@ +/** @file + This is BaseCrypto router support function definition. + +Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _HASH_LIB_BASE_CRYPTO_ROUTER_COMMON_H_ +#define _HASH_LIB_BASE_CRYPTO_ROUTER_COMMON_H_ + +/** + The function get hash mask info from algorithm. + + @param HashGuid Hash Guid + + @return HashMask +**/ +UINT32 +EFIAPI +Tpm2GetHashMaskFromAlgo ( + IN EFI_GUID *HashGuid + ); + +/** + The function set digest to digest list. + + @param DigestList digest list + @param Digest digest data +**/ +VOID +EFIAPI +Tpm2SetHashToDigestList ( + IN OUT TPML_DIGEST_VALUES *DigestList, + IN TPML_DIGEST_VALUES *Digest + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c new file mode 100644 index 00000000..f44edffa --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c @@ -0,0 +1,300 @@ +/** @file + This library is BaseCrypto router. It will redirect hash request to each individual + hash handler registered, such as SHA1, SHA256. + Platform can use PcdTpm2HashMask to mask some hash engines. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> +#include <Library/HashLib.h> + +#include "HashLibBaseCryptoRouterCommon.h" + +HASH_INTERFACE mHashInterface[HASH_COUNT] = {{{0}, NULL, NULL, NULL}}; +UINTN mHashInterfaceCount = 0; + +UINT32 mSupportedHashMaskLast = 0; +UINT32 mSupportedHashMaskCurrent = 0; + +/** + Check mismatch of supported HashMask between modules + that may link different HashInstanceLib instances. + +**/ +VOID +CheckSupportedHashMaskMismatch ( + VOID + ) +{ + if (mSupportedHashMaskCurrent != mSupportedHashMaskLast) { + DEBUG (( + DEBUG_WARN, + "WARNING: There is mismatch of supported HashMask (0x%x - 0x%x) between modules\n", + mSupportedHashMaskCurrent, + mSupportedHashMaskLast + )); + DEBUG ((DEBUG_WARN, "that are linking different HashInstanceLib instances!\n")); + } +} + +/** + Start hash sequence. + + @param HashHandle Hash handle. + + @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. + @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. +**/ +EFI_STATUS +EFIAPI +HashStart ( + OUT HASH_HANDLE *HashHandle + ) +{ + HASH_HANDLE *HashCtx; + UINTN Index; + UINT32 HashMask; + + if (mHashInterfaceCount == 0) { + return EFI_UNSUPPORTED; + } + + CheckSupportedHashMaskMismatch (); + + HashCtx = AllocatePool (sizeof(*HashCtx) * mHashInterfaceCount); + ASSERT (HashCtx != NULL); + + for (Index = 0; Index < mHashInterfaceCount; Index++) { + HashMask = Tpm2GetHashMaskFromAlgo (&mHashInterface[Index].HashGuid); + if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) { + mHashInterface[Index].HashInit (&HashCtx[Index]); + } + } + + *HashHandle = (HASH_HANDLE)HashCtx; + + return EFI_SUCCESS; +} + +/** + Update hash sequence data. + + @param HashHandle Hash handle. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + + @retval EFI_SUCCESS Hash sequence updated. +**/ +EFI_STATUS +EFIAPI +HashUpdate ( + IN HASH_HANDLE HashHandle, + IN VOID *DataToHash, + IN UINTN DataToHashLen + ) +{ + HASH_HANDLE *HashCtx; + UINTN Index; + UINT32 HashMask; + + if (mHashInterfaceCount == 0) { + return EFI_UNSUPPORTED; + } + + CheckSupportedHashMaskMismatch (); + + HashCtx = (HASH_HANDLE *)HashHandle; + + for (Index = 0; Index < mHashInterfaceCount; Index++) { + HashMask = Tpm2GetHashMaskFromAlgo (&mHashInterface[Index].HashGuid); + if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) { + mHashInterface[Index].HashUpdate (HashCtx[Index], DataToHash, DataToHashLen); + } + } + + return EFI_SUCCESS; +} + +/** + Hash sequence complete and extend to PCR. + + @param HashHandle Hash handle. + @param PcrIndex PCR to be extended. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +HashCompleteAndExtend ( + IN HASH_HANDLE HashHandle, + IN TPMI_DH_PCR PcrIndex, + IN VOID *DataToHash, + IN UINTN DataToHashLen, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + TPML_DIGEST_VALUES Digest; + HASH_HANDLE *HashCtx; + UINTN Index; + EFI_STATUS Status; + UINT32 HashMask; + + if (mHashInterfaceCount == 0) { + return EFI_UNSUPPORTED; + } + + CheckSupportedHashMaskMismatch (); + + HashCtx = (HASH_HANDLE *)HashHandle; + ZeroMem (DigestList, sizeof(*DigestList)); + + for (Index = 0; Index < mHashInterfaceCount; Index++) { + HashMask = Tpm2GetHashMaskFromAlgo (&mHashInterface[Index].HashGuid); + if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) { + mHashInterface[Index].HashUpdate (HashCtx[Index], DataToHash, DataToHashLen); + mHashInterface[Index].HashFinal (HashCtx[Index], &Digest); + Tpm2SetHashToDigestList (DigestList, &Digest); + } + } + + FreePool (HashCtx); + + Status = Tpm2PcrExtend ( + PcrIndex, + DigestList + ); + return Status; +} + +/** + Hash data and extend to PCR. + + @param PcrIndex PCR to be extended. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash data and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +HashAndExtend ( + IN TPMI_DH_PCR PcrIndex, + IN VOID *DataToHash, + IN UINTN DataToHashLen, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + HASH_HANDLE HashHandle; + EFI_STATUS Status; + + if (mHashInterfaceCount == 0) { + return EFI_UNSUPPORTED; + } + + CheckSupportedHashMaskMismatch (); + + HashStart (&HashHandle); + HashUpdate (HashHandle, DataToHash, DataToHashLen); + Status = HashCompleteAndExtend (HashHandle, PcrIndex, NULL, 0, DigestList); + + return Status; +} + +/** + This service register Hash. + + @param HashInterface Hash interface + + @retval EFI_SUCCESS This hash interface is registered successfully. + @retval EFI_UNSUPPORTED System does not support register this interface. + @retval EFI_ALREADY_STARTED System already register this interface. +**/ +EFI_STATUS +EFIAPI +RegisterHashInterfaceLib ( + IN HASH_INTERFACE *HashInterface + ) +{ + UINTN Index; + UINT32 HashMask; + EFI_STATUS Status; + + // + // Check allow + // + HashMask = Tpm2GetHashMaskFromAlgo (&HashInterface->HashGuid); + if ((HashMask & PcdGet32 (PcdTpm2HashMask)) == 0) { + return EFI_UNSUPPORTED; + } + + if (mHashInterfaceCount >= sizeof(mHashInterface)/sizeof(mHashInterface[0])) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Check duplication + // + for (Index = 0; Index < mHashInterfaceCount; Index++) { + if (CompareGuid (&mHashInterface[Index].HashGuid, &HashInterface->HashGuid)) { + DEBUG ((DEBUG_ERROR, "Hash Interface (%g) has been registered\n", &HashInterface->HashGuid)); + return EFI_ALREADY_STARTED; + } + } + + // + // Record hash algorithm bitmap of CURRENT module which consumes HashLib. + // + mSupportedHashMaskCurrent = PcdGet32 (PcdTcg2HashAlgorithmBitmap) | HashMask; + Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, mSupportedHashMaskCurrent); + ASSERT_EFI_ERROR (Status); + + CopyMem (&mHashInterface[mHashInterfaceCount], HashInterface, sizeof(*HashInterface)); + mHashInterfaceCount ++; + + return EFI_SUCCESS; +} + +/** + The constructor function of HashLibBaseCryptoRouterDxe. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor executed correctly. + +**/ +EFI_STATUS +EFIAPI +HashLibBaseCryptoRouterDxeConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Record hash algorithm bitmap of LAST module which also consumes HashLib. + // + mSupportedHashMaskLast = PcdGet32 (PcdTcg2HashAlgorithmBitmap); + + // + // Set PcdTcg2HashAlgorithmBitmap to 0 in CONSTRUCTOR for CURRENT module. + // + Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, 0); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf new file mode 100644 index 00000000..548576f9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf @@ -0,0 +1,51 @@ +## @file +# Provides hash service by registered hash handler +# +# This library is BaseCrypto router. It will redirect hash request to each individual +# hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to +# mask some hash engines. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HashLibBaseCryptoRouterDxe + MODULE_UNI_FILE = HashLibBaseCryptoRouterDxe.uni + FILE_GUID = 158DC712-F15A-44dc-93BB-1675045BE066 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = HashLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = HashLibBaseCryptoRouterDxeConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + HashLibBaseCryptoRouterCommon.h + HashLibBaseCryptoRouterCommon.c + HashLibBaseCryptoRouterDxe.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + MemoryAllocationLib + PcdLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask ## CONSUMES + ## SOMETIMES_CONSUMES + ## SOMETIMES_PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni new file mode 100644 index 00000000..d8b03ea4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni @@ -0,0 +1,18 @@ +// /** @file
+// Provides hash service by registered hash handler
+//
+// This library is BaseCrypto router. It will redirect hash request to each individual
+// hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to
+// mask some hash engines.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides hash service by registered hash handler"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is BaseCrypto router. It will redirect hash request to each individual hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to mask some hash engines."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c new file mode 100644 index 00000000..5e3d0ba5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c @@ -0,0 +1,433 @@ +/** @file + This library is BaseCrypto router. It will redirect hash request to each individual + hash handler registered, such as SHA1, SHA256. + Platform can use PcdTpm2HashMask to mask some hash engines. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> +#include <Library/HobLib.h> +#include <Library/HashLib.h> +#include <Guid/ZeroGuid.h> + +#include "HashLibBaseCryptoRouterCommon.h" + +#define HASH_LIB_PEI_ROUTER_GUID \ + { 0x84681c08, 0x6873, 0x46f3, { 0x8b, 0xb7, 0xab, 0x66, 0x18, 0x95, 0xa1, 0xb3 } } + +EFI_GUID mHashLibPeiRouterGuid = HASH_LIB_PEI_ROUTER_GUID; + +typedef struct { + // + // If gZeroGuid, SupportedHashMask is 0 for FIRST module which consumes HashLib + // or the hash algorithm bitmap of LAST module which consumes HashLib. + // HashInterfaceCount and HashInterface are all 0. + // If gEfiCallerIdGuid, HashInterfaceCount, HashInterface and SupportedHashMask + // are the hash interface information of CURRENT module which consumes HashLib. + // + EFI_GUID Identifier; + UINTN HashInterfaceCount; + HASH_INTERFACE HashInterface[HASH_COUNT]; + UINT32 SupportedHashMask; +} HASH_INTERFACE_HOB; + +/** + This function gets hash interface hob. + + @param Identifier Identifier to get hash interface hob. + + @retval hash interface hob. +**/ +HASH_INTERFACE_HOB * +InternalGetHashInterfaceHob ( + EFI_GUID *Identifier + ) +{ + EFI_PEI_HOB_POINTERS Hob; + HASH_INTERFACE_HOB *HashInterfaceHob; + + Hob.Raw = GetFirstGuidHob (&mHashLibPeiRouterGuid); + while (Hob.Raw != NULL) { + HashInterfaceHob = GET_GUID_HOB_DATA (Hob); + if (CompareGuid (&HashInterfaceHob->Identifier, Identifier)) { + // + // Found the matched one. + // + return HashInterfaceHob; + } + Hob.Raw = GET_NEXT_HOB (Hob); + Hob.Raw = GetNextGuidHob (&mHashLibPeiRouterGuid, Hob.Raw); + } + return NULL; +} + +/** + This function creates hash interface hob. + + @param Identifier Identifier to create hash interface hob. + + @retval hash interface hob. +**/ +HASH_INTERFACE_HOB * +InternalCreateHashInterfaceHob ( + EFI_GUID *Identifier + ) +{ + HASH_INTERFACE_HOB LocalHashInterfaceHob; + + ZeroMem (&LocalHashInterfaceHob, sizeof(LocalHashInterfaceHob)); + CopyGuid (&LocalHashInterfaceHob.Identifier, Identifier); + return BuildGuidDataHob (&mHashLibPeiRouterGuid, &LocalHashInterfaceHob, sizeof(LocalHashInterfaceHob)); +} + +/** + Check mismatch of supported HashMask between modules + that may link different HashInstanceLib instances. + + @param HashInterfaceHobCurrent Pointer to hash interface hob for CURRENT module. + +**/ +VOID +CheckSupportedHashMaskMismatch ( + IN HASH_INTERFACE_HOB *HashInterfaceHobCurrent + ) +{ + HASH_INTERFACE_HOB *HashInterfaceHobLast; + + HashInterfaceHobLast = InternalGetHashInterfaceHob (&gZeroGuid); + ASSERT (HashInterfaceHobLast != NULL); + + if ((HashInterfaceHobLast->SupportedHashMask != 0) && + (HashInterfaceHobCurrent->SupportedHashMask != HashInterfaceHobLast->SupportedHashMask)) { + DEBUG (( + DEBUG_WARN, + "WARNING: There is mismatch of supported HashMask (0x%x - 0x%x) between modules\n", + HashInterfaceHobCurrent->SupportedHashMask, + HashInterfaceHobLast->SupportedHashMask + )); + DEBUG ((DEBUG_WARN, "that are linking different HashInstanceLib instances!\n")); + } +} + +/** + Start hash sequence. + + @param HashHandle Hash handle. + + @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. + @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. +**/ +EFI_STATUS +EFIAPI +HashStart ( + OUT HASH_HANDLE *HashHandle + ) +{ + HASH_INTERFACE_HOB *HashInterfaceHob; + HASH_HANDLE *HashCtx; + UINTN Index; + UINT32 HashMask; + + HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid); + if (HashInterfaceHob == NULL) { + return EFI_UNSUPPORTED; + } + + if (HashInterfaceHob->HashInterfaceCount == 0) { + return EFI_UNSUPPORTED; + } + + CheckSupportedHashMaskMismatch (HashInterfaceHob); + + HashCtx = AllocatePool (sizeof(*HashCtx) * HashInterfaceHob->HashInterfaceCount); + ASSERT (HashCtx != NULL); + + for (Index = 0; Index < HashInterfaceHob->HashInterfaceCount; Index++) { + HashMask = Tpm2GetHashMaskFromAlgo (&HashInterfaceHob->HashInterface[Index].HashGuid); + if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) { + HashInterfaceHob->HashInterface[Index].HashInit (&HashCtx[Index]); + } + } + + *HashHandle = (HASH_HANDLE)HashCtx; + + return EFI_SUCCESS; +} + +/** + Update hash sequence data. + + @param HashHandle Hash handle. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + + @retval EFI_SUCCESS Hash sequence updated. +**/ +EFI_STATUS +EFIAPI +HashUpdate ( + IN HASH_HANDLE HashHandle, + IN VOID *DataToHash, + IN UINTN DataToHashLen + ) +{ + HASH_INTERFACE_HOB *HashInterfaceHob; + HASH_HANDLE *HashCtx; + UINTN Index; + UINT32 HashMask; + + HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid); + if (HashInterfaceHob == NULL) { + return EFI_UNSUPPORTED; + } + + if (HashInterfaceHob->HashInterfaceCount == 0) { + return EFI_UNSUPPORTED; + } + + CheckSupportedHashMaskMismatch (HashInterfaceHob); + + HashCtx = (HASH_HANDLE *)HashHandle; + + for (Index = 0; Index < HashInterfaceHob->HashInterfaceCount; Index++) { + HashMask = Tpm2GetHashMaskFromAlgo (&HashInterfaceHob->HashInterface[Index].HashGuid); + if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) { + HashInterfaceHob->HashInterface[Index].HashUpdate (HashCtx[Index], DataToHash, DataToHashLen); + } + } + + return EFI_SUCCESS; +} + +/** + Hash sequence complete and extend to PCR. + + @param HashHandle Hash handle. + @param PcrIndex PCR to be extended. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +HashCompleteAndExtend ( + IN HASH_HANDLE HashHandle, + IN TPMI_DH_PCR PcrIndex, + IN VOID *DataToHash, + IN UINTN DataToHashLen, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + TPML_DIGEST_VALUES Digest; + HASH_INTERFACE_HOB *HashInterfaceHob; + HASH_HANDLE *HashCtx; + UINTN Index; + EFI_STATUS Status; + UINT32 HashMask; + + HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid); + if (HashInterfaceHob == NULL) { + return EFI_UNSUPPORTED; + } + + if (HashInterfaceHob->HashInterfaceCount == 0) { + return EFI_UNSUPPORTED; + } + + CheckSupportedHashMaskMismatch (HashInterfaceHob); + + HashCtx = (HASH_HANDLE *)HashHandle; + ZeroMem (DigestList, sizeof(*DigestList)); + + for (Index = 0; Index < HashInterfaceHob->HashInterfaceCount; Index++) { + HashMask = Tpm2GetHashMaskFromAlgo (&HashInterfaceHob->HashInterface[Index].HashGuid); + if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) { + HashInterfaceHob->HashInterface[Index].HashUpdate (HashCtx[Index], DataToHash, DataToHashLen); + HashInterfaceHob->HashInterface[Index].HashFinal (HashCtx[Index], &Digest); + Tpm2SetHashToDigestList (DigestList, &Digest); + } + } + + FreePool (HashCtx); + + Status = Tpm2PcrExtend ( + PcrIndex, + DigestList + ); + return Status; +} + +/** + Hash data and extend to PCR. + + @param PcrIndex PCR to be extended. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash data and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +HashAndExtend ( + IN TPMI_DH_PCR PcrIndex, + IN VOID *DataToHash, + IN UINTN DataToHashLen, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + HASH_INTERFACE_HOB *HashInterfaceHob; + HASH_HANDLE HashHandle; + EFI_STATUS Status; + + HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid); + if (HashInterfaceHob == NULL) { + return EFI_UNSUPPORTED; + } + + if (HashInterfaceHob->HashInterfaceCount == 0) { + return EFI_UNSUPPORTED; + } + + CheckSupportedHashMaskMismatch (HashInterfaceHob); + + HashStart (&HashHandle); + HashUpdate (HashHandle, DataToHash, DataToHashLen); + Status = HashCompleteAndExtend (HashHandle, PcrIndex, NULL, 0, DigestList); + + return Status; +} + +/** + This service register Hash. + + @param HashInterface Hash interface + + @retval EFI_SUCCESS This hash interface is registered successfully. + @retval EFI_UNSUPPORTED System does not support register this interface. + @retval EFI_ALREADY_STARTED System already register this interface. +**/ +EFI_STATUS +EFIAPI +RegisterHashInterfaceLib ( + IN HASH_INTERFACE *HashInterface + ) +{ + UINTN Index; + HASH_INTERFACE_HOB *HashInterfaceHob; + UINT32 HashMask; + EFI_STATUS Status; + + // + // Check allow + // + HashMask = Tpm2GetHashMaskFromAlgo (&HashInterface->HashGuid); + if ((HashMask & PcdGet32 (PcdTpm2HashMask)) == 0) { + return EFI_UNSUPPORTED; + } + + HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid); + if (HashInterfaceHob == NULL) { + HashInterfaceHob = InternalCreateHashInterfaceHob (&gEfiCallerIdGuid); + if (HashInterfaceHob == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + if (HashInterfaceHob->HashInterfaceCount >= HASH_COUNT) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Check duplication + // + for (Index = 0; Index < HashInterfaceHob->HashInterfaceCount; Index++) { + if (CompareGuid (&HashInterfaceHob->HashInterface[Index].HashGuid, &HashInterface->HashGuid)) { + DEBUG ((DEBUG_ERROR, "Hash Interface (%g) has been registered\n", &HashInterface->HashGuid)); + return EFI_ALREADY_STARTED; + } + } + + // + // Record hash algorithm bitmap of CURRENT module which consumes HashLib. + // + HashInterfaceHob->SupportedHashMask = PcdGet32 (PcdTcg2HashAlgorithmBitmap) | HashMask; + Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, HashInterfaceHob->SupportedHashMask); + ASSERT_EFI_ERROR (Status); + + CopyMem (&HashInterfaceHob->HashInterface[HashInterfaceHob->HashInterfaceCount], HashInterface, sizeof(*HashInterface)); + HashInterfaceHob->HashInterfaceCount ++; + + return EFI_SUCCESS; +} + +/** + The constructor function of HashLibBaseCryptoRouterPei. + + @param FileHandle The handle of FFS header the loaded driver. + @param PeiServices The pointer to the PEI services. + + @retval EFI_SUCCESS The constructor executes successfully. + @retval EFI_OUT_OF_RESOURCES There is no enough resource for the constructor. + +**/ +EFI_STATUS +EFIAPI +HashLibBaseCryptoRouterPeiConstructor ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + HASH_INTERFACE_HOB *HashInterfaceHob; + + HashInterfaceHob = InternalGetHashInterfaceHob (&gZeroGuid); + if (HashInterfaceHob == NULL) { + // + // No HOB with gZeroGuid Identifier has been created, + // this is FIRST module which consumes HashLib. + // Create the HOB with gZeroGuid Identifier. + // + HashInterfaceHob = InternalCreateHashInterfaceHob (&gZeroGuid); + if (HashInterfaceHob == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } else { + // + // Record hash algorithm bitmap of LAST module which also consumes HashLib. + // + HashInterfaceHob->SupportedHashMask = PcdGet32 (PcdTcg2HashAlgorithmBitmap); + } + + HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid); + if (HashInterfaceHob != NULL) { + // + // In PEI phase, some modules may call RegisterForShadow and will be + // shadowed and executed again after memory is discovered. + // This is the second execution of this module, clear the hash interface + // information registered at its first execution. + // + ZeroMem (&HashInterfaceHob->HashInterface, sizeof (HashInterfaceHob->HashInterface)); + HashInterfaceHob->HashInterfaceCount = 0; + HashInterfaceHob->SupportedHashMask = 0; + } + + // + // Set PcdTcg2HashAlgorithmBitmap to 0 in CONSTRUCTOR for CURRENT module. + // + Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, 0); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf new file mode 100644 index 00000000..57502427 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf @@ -0,0 +1,57 @@ +## @file +# Provides hash service by registered hash handler +# +# This library is BaseCrypto router. It will redirect hash request to each individual +# hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to +# mask some hash engines. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HashLibBaseCryptoRouterPei + MODULE_UNI_FILE = HashLibBaseCryptoRouterPei.uni + FILE_GUID = DDCBCFBA-8EEB-488a-96D6-097831A6E50B + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = HashLib|PEIM + CONSTRUCTOR = HashLibBaseCryptoRouterPeiConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + HashLibBaseCryptoRouterCommon.h + HashLibBaseCryptoRouterCommon.c + HashLibBaseCryptoRouterPei.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + MemoryAllocationLib + PcdLib + HobLib + +[Guids] + ## SOMETIMES_CONSUMES ## GUID + gZeroGuid + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask ## CONSUMES + ## SOMETIMES_CONSUMES + ## SOMETIMES_PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni new file mode 100644 index 00000000..d8b03ea4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni @@ -0,0 +1,18 @@ +// /** @file
+// Provides hash service by registered hash handler
+//
+// This library is BaseCrypto router. It will redirect hash request to each individual
+// hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to
+// mask some hash engines.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides hash service by registered hash handler"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is BaseCrypto router. It will redirect hash request to each individual hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to mask some hash engines."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c new file mode 100644 index 00000000..cec8d684 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c @@ -0,0 +1,336 @@ +/** @file + This library uses TPM2 device to calculation hash. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/HashLib.h> +#include <Library/PcdLib.h> + +typedef struct { + TPM_ALG_ID AlgoId; + UINT32 Mask; +} TPM2_HASH_MASK; + +TPM2_HASH_MASK mTpm2HashMask[] = { + {TPM_ALG_SHA1, HASH_ALG_SHA1}, + {TPM_ALG_SHA256, HASH_ALG_SHA256}, + {TPM_ALG_SHA384, HASH_ALG_SHA384}, + {TPM_ALG_SHA512, HASH_ALG_SHA512}, +}; + +/** + The function get algorithm from hash mask info. + + @return Hash algorithm +**/ +TPM_ALG_ID +Tpm2GetAlgoFromHashMask ( + VOID + ) +{ + UINT32 HashMask; + UINTN Index; + + HashMask = PcdGet32 (PcdTpm2HashMask); + for (Index = 0; Index < sizeof(mTpm2HashMask)/sizeof(mTpm2HashMask[0]); Index++) { + if (mTpm2HashMask[Index].Mask == HashMask) { + return mTpm2HashMask[Index].AlgoId; + } + } + + return TPM_ALG_NULL; +} + +/** + Start hash sequence. + + @param HashHandle Hash handle. + + @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. + @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. +**/ +EFI_STATUS +EFIAPI +HashStart ( + OUT HASH_HANDLE *HashHandle + ) +{ + TPMI_DH_OBJECT SequenceHandle; + EFI_STATUS Status; + TPM_ALG_ID AlgoId; + + AlgoId = Tpm2GetAlgoFromHashMask (); + + Status = Tpm2HashSequenceStart (AlgoId, &SequenceHandle); + if (!EFI_ERROR (Status)) { + *HashHandle = (HASH_HANDLE)SequenceHandle; + } + return Status; +} + +/** + Update hash sequence data. + + @param HashHandle Hash handle. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + + @retval EFI_SUCCESS Hash sequence updated. +**/ +EFI_STATUS +EFIAPI +HashUpdate ( + IN HASH_HANDLE HashHandle, + IN VOID *DataToHash, + IN UINTN DataToHashLen + ) +{ + UINT8 *Buffer; + UINT64 HashLen; + TPM2B_MAX_BUFFER HashBuffer; + EFI_STATUS Status; + + Buffer = (UINT8 *)(UINTN)DataToHash; + for (HashLen = DataToHashLen; HashLen > sizeof(HashBuffer.buffer); HashLen -= sizeof(HashBuffer.buffer)) { + + HashBuffer.size = sizeof(HashBuffer.buffer); + CopyMem(HashBuffer.buffer, Buffer, sizeof(HashBuffer.buffer)); + Buffer += sizeof(HashBuffer.buffer); + + Status = Tpm2SequenceUpdate((TPMI_DH_OBJECT)HashHandle, &HashBuffer); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + } + + // + // Last one + // + HashBuffer.size = (UINT16)HashLen; + CopyMem(HashBuffer.buffer, Buffer, (UINTN)HashLen); + Status = Tpm2SequenceUpdate((TPMI_DH_OBJECT)HashHandle, &HashBuffer); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Hash sequence complete and extend to PCR. + + @param HashHandle Hash handle. + @param PcrIndex PCR to be extended. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +HashCompleteAndExtend ( + IN HASH_HANDLE HashHandle, + IN TPMI_DH_PCR PcrIndex, + IN VOID *DataToHash, + IN UINTN DataToHashLen, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + UINT8 *Buffer; + UINT64 HashLen; + TPM2B_MAX_BUFFER HashBuffer; + EFI_STATUS Status; + TPM_ALG_ID AlgoId; + TPM2B_DIGEST Result; + + AlgoId = Tpm2GetAlgoFromHashMask (); + + Buffer = (UINT8 *)(UINTN)DataToHash; + for (HashLen = DataToHashLen; HashLen > sizeof(HashBuffer.buffer); HashLen -= sizeof(HashBuffer.buffer)) { + + HashBuffer.size = sizeof(HashBuffer.buffer); + CopyMem(HashBuffer.buffer, Buffer, sizeof(HashBuffer.buffer)); + Buffer += sizeof(HashBuffer.buffer); + + Status = Tpm2SequenceUpdate((TPMI_DH_OBJECT)HashHandle, &HashBuffer); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + } + + // + // Last one + // + HashBuffer.size = (UINT16)HashLen; + CopyMem(HashBuffer.buffer, Buffer, (UINTN)HashLen); + + ZeroMem(DigestList, sizeof(*DigestList)); + DigestList->count = HASH_COUNT; + + if (AlgoId == TPM_ALG_NULL) { + Status = Tpm2EventSequenceComplete ( + PcrIndex, + (TPMI_DH_OBJECT)HashHandle, + &HashBuffer, + DigestList + ); + } else { + Status = Tpm2SequenceComplete ( + (TPMI_DH_OBJECT)HashHandle, + &HashBuffer, + &Result + ); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + + DigestList->count = 1; + DigestList->digests[0].hashAlg = AlgoId; + CopyMem (&DigestList->digests[0].digest, Result.buffer, Result.size); + Status = Tpm2PcrExtend ( + PcrIndex, + DigestList + ); + } + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + return EFI_SUCCESS; +} + +/** + Hash data and extend to PCR. + + @param PcrIndex PCR to be extended. + @param DataToHash Data to be hashed. + @param DataToHashLen Data size. + @param DigestList Digest list. + + @retval EFI_SUCCESS Hash data and DigestList is returned. +**/ +EFI_STATUS +EFIAPI +HashAndExtend ( + IN TPMI_DH_PCR PcrIndex, + IN VOID *DataToHash, + IN UINTN DataToHashLen, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + EFI_STATUS Status; + UINT8 *Buffer; + UINT64 HashLen; + TPMI_DH_OBJECT SequenceHandle; + TPM2B_MAX_BUFFER HashBuffer; + TPM_ALG_ID AlgoId; + TPM2B_EVENT EventData; + TPM2B_DIGEST Result; + + DEBUG((EFI_D_VERBOSE, "\n HashAndExtend Entry \n")); + + SequenceHandle = 0xFFFFFFFF; // Know bad value + + AlgoId = Tpm2GetAlgoFromHashMask (); + + if ((AlgoId == TPM_ALG_NULL) && (DataToHashLen <= sizeof(EventData.buffer))) { + EventData.size = (UINT16)DataToHashLen; + CopyMem (EventData.buffer, DataToHash, DataToHashLen); + Status = Tpm2PcrEvent (PcrIndex, &EventData, DigestList); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + return EFI_SUCCESS; + } + + Status = Tpm2HashSequenceStart(AlgoId, &SequenceHandle); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + DEBUG((EFI_D_VERBOSE, "\n Tpm2HashSequenceStart Success \n")); + + Buffer = (UINT8 *)(UINTN)DataToHash; + for (HashLen = DataToHashLen; HashLen > sizeof(HashBuffer.buffer); HashLen -= sizeof(HashBuffer.buffer)) { + + HashBuffer.size = sizeof(HashBuffer.buffer); + CopyMem(HashBuffer.buffer, Buffer, sizeof(HashBuffer.buffer)); + Buffer += sizeof(HashBuffer.buffer); + + Status = Tpm2SequenceUpdate(SequenceHandle, &HashBuffer); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + } + DEBUG((EFI_D_VERBOSE, "\n Tpm2SequenceUpdate Success \n")); + + HashBuffer.size = (UINT16)HashLen; + CopyMem(HashBuffer.buffer, Buffer, (UINTN)HashLen); + + ZeroMem(DigestList, sizeof(*DigestList)); + DigestList->count = HASH_COUNT; + + if (AlgoId == TPM_ALG_NULL) { + Status = Tpm2EventSequenceComplete ( + PcrIndex, + SequenceHandle, + &HashBuffer, + DigestList + ); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + DEBUG((EFI_D_VERBOSE, "\n Tpm2EventSequenceComplete Success \n")); + } else { + Status = Tpm2SequenceComplete ( + SequenceHandle, + &HashBuffer, + &Result + ); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + DEBUG((EFI_D_VERBOSE, "\n Tpm2SequenceComplete Success \n")); + + DigestList->count = 1; + DigestList->digests[0].hashAlg = AlgoId; + CopyMem (&DigestList->digests[0].digest, Result.buffer, Result.size); + Status = Tpm2PcrExtend ( + PcrIndex, + DigestList + ); + if (EFI_ERROR(Status)) { + return EFI_DEVICE_ERROR; + } + DEBUG((EFI_D_VERBOSE, "\n Tpm2PcrExtend Success \n")); + } + + return EFI_SUCCESS; +} + +/** + This service register Hash. + + @param HashInterface Hash interface + + @retval EFI_SUCCESS This hash interface is registered successfully. + @retval EFI_UNSUPPORTED System does not support register this interface. + @retval EFI_ALREADY_STARTED System already register this interface. +**/ +EFI_STATUS +EFIAPI +RegisterHashInterfaceLib ( + IN HASH_INTERFACE *HashInterface + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.inf new file mode 100644 index 00000000..7d34b526 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.inf @@ -0,0 +1,44 @@ +## @file +# Provides hash service using TPM2 device +# +# This library uses TPM2 device to calculate hash. Platform can use PcdTpm2HashMask to +# mask some hash calculation. +# +# Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HashLibTpm2 + MODULE_UNI_FILE = HashLibTpm2.uni + FILE_GUID = 1317F0D5-7842-475c-B1CA-6EDC20DCBE7D + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = HashLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + HashLibTpm2.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + MemoryAllocationLib + PcdLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.uni new file mode 100644 index 00000000..5c5484d8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.uni @@ -0,0 +1,17 @@ +// /** @file
+// Provides hash service using TPM2 device
+//
+// This library uses TPM2 device to calculate hash. Platform can use PcdTpm2HashMask to
+// mask some hash calculation.
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides hash service using TPM2 device"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library uses TPM2 device to calculate hash. Platform can use PcdTpm2HashMask to mask some hash calculation."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c new file mode 100644 index 00000000..85b1c249 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c @@ -0,0 +1,381 @@ +/** @file + + This library registers RSA 2048 SHA 256 guided section handler + to parse RSA 2048 SHA 256 encapsulation section and extract raw data. + It uses the BaseCryptLib based on OpenSSL to authenticate the signature. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Protocol/Hash.h> +#include <Library/ExtractGuidedSectionLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> +#include <Guid/WinCertificate.h> +#include <Library/BaseCryptLib.h> +#include <Library/PerformanceLib.h> +#include <Guid/SecurityPkgTokenSpace.h> + +/// +/// RSA 2048 SHA 256 Guided Section header +/// +typedef struct { + EFI_GUID_DEFINED_SECTION GuidedSectionHeader; ///< EFI guided section header + EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature +} RSA_2048_SHA_256_SECTION_HEADER; + +typedef struct { + EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header + EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature +} RSA_2048_SHA_256_SECTION2_HEADER; + +/// +/// Public Exponent of RSA Key. +/// +CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 }; + +/** + + GetInfo gets raw data size and attribute of the input guided section. + It first checks whether the input guid section is supported. + If not, EFI_INVALID_PARAMETER will return. + + @param InputSection Buffer containing the input GUIDed section to be processed. + @param OutputBufferSize The size of OutputBuffer. + @param ScratchBufferSize The size of ScratchBuffer. + @param SectionAttribute The attribute of the input guided section. + + @retval EFI_SUCCESS The size of destination buffer, the size of scratch buffer and + the attribute of the input section are successfully retrieved. + @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid. + +**/ +EFI_STATUS +EFIAPI +Rsa2048Sha256GuidedSectionGetInfo ( + IN CONST VOID *InputSection, + OUT UINT32 *OutputBufferSize, + OUT UINT32 *ScratchBufferSize, + OUT UINT16 *SectionAttribute + ) +{ + if (IS_SECTION2 (InputSection)) { + // + // Check whether the input guid section is recognized. + // + if (!CompareGuid ( + &gEfiCertTypeRsa2048Sha256Guid, + &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) { + return EFI_INVALID_PARAMETER; + } + // + // Retrieve the size and attribute of the input section data. + // + *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes; + *ScratchBufferSize = 0; + *OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION2_HEADER); + } else { + // + // Check whether the input guid section is recognized. + // + if (!CompareGuid ( + &gEfiCertTypeRsa2048Sha256Guid, + &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) { + return EFI_INVALID_PARAMETER; + } + // + // Retrieve the size and attribute of the input section data. + // + *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes; + *ScratchBufferSize = 0; + *OutputBufferSize = SECTION_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION_HEADER); + } + + return EFI_SUCCESS; +} + +/** + + Extraction handler tries to extract raw data from the input guided section. + It also does authentication check for RSA 2048 SHA 256 signature in the input guided section. + It first checks whether the input guid section is supported. + If not, EFI_INVALID_PARAMETER will return. + + @param InputSection Buffer containing the input GUIDed section to be processed. + @param OutputBuffer Buffer to contain the output raw data allocated by the caller. + @param ScratchBuffer A pointer to a caller-allocated buffer for function internal use. + @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the + authentication status of the output buffer. + + @retval EFI_SUCCESS Section Data and Auth Status is extracted successfully. + @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid. + +**/ +EFI_STATUS +EFIAPI +Rsa2048Sha256GuidedSectionHandler ( + IN CONST VOID *InputSection, + OUT VOID **OutputBuffer, + IN VOID *ScratchBuffer, OPTIONAL + OUT UINT32 *AuthenticationStatus + ) +{ + EFI_STATUS Status; + UINT32 OutputBufferSize; + EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlockRsa2048Sha256; + BOOLEAN CryptoStatus; + UINT8 Digest[SHA256_DIGEST_SIZE]; + UINT8 *PublicKey; + UINTN PublicKeyBufferSize; + VOID *HashContext; + VOID *Rsa; + + HashContext = NULL; + Rsa = NULL; + + if (IS_SECTION2 (InputSection)) { + // + // Check whether the input guid section is recognized. + // + if (!CompareGuid ( + &gEfiCertTypeRsa2048Sha256Guid, + &(((EFI_GUID_DEFINED_SECTION2 *)InputSection)->SectionDefinitionGuid))) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the RSA 2048 SHA 256 information. + // + CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION2_HEADER *) InputSection)->CertBlockRsa2048Sha256; + OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION2_HEADER); + if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) { + PERF_INMODULE_BEGIN ("PeiRsaCopy"); + CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER), OutputBufferSize); + PERF_INMODULE_END ("PeiRsaCopy"); + } else { + *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER); + } + + // + // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set + // + ASSERT ((((EFI_GUID_DEFINED_SECTION2 *)InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0); + *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED; + } else { + // + // Check whether the input guid section is recognized. + // + if (!CompareGuid ( + &gEfiCertTypeRsa2048Sha256Guid, + &(((EFI_GUID_DEFINED_SECTION *)InputSection)->SectionDefinitionGuid))) { + return EFI_INVALID_PARAMETER; + } + + // + // Get the RSA 2048 SHA 256 information. + // + CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION_HEADER *)InputSection)->CertBlockRsa2048Sha256; + OutputBufferSize = SECTION_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION_HEADER); + if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) { + PERF_INMODULE_BEGIN ("PeiRsaCopy"); + CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER), OutputBufferSize); + PERF_INMODULE_END ("PeiRsaCopy"); + } else { + *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER); + } + + // + // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set + // + ASSERT ((((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0); + *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED; + } + + // + // All paths from here return EFI_SUCCESS and result is returned in AuthenticationStatus + // + Status = EFI_SUCCESS; + + // + // Fail if the HashType is not SHA 256 + // + if (!CompareGuid (&gEfiHashAlgorithmSha256Guid, &CertBlockRsa2048Sha256->HashType)) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: HASH type of section is not supported\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Allocate hash context buffer required for SHA 256 + // + HashContext = AllocatePool (Sha256GetContextSize ()); + if (HashContext == NULL) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Can not allocate hash context\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Hash public key from data payload with SHA256. + // + ZeroMem (Digest, SHA256_DIGEST_SIZE); + CryptoStatus = Sha256Init (HashContext); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Init() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey)); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Update() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + CryptoStatus = Sha256Final (HashContext, Digest); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Final() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Fail if the PublicKey is not one of the public keys in PcdRsa2048Sha256PublicKeyBuffer + // + PublicKey = (UINT8 *)PcdGetPtr (PcdRsa2048Sha256PublicKeyBuffer); + DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer = %p\n", PublicKey)); + ASSERT (PublicKey != NULL); + DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer Token = %08x\n", PcdToken (PcdRsa2048Sha256PublicKeyBuffer))); + PublicKeyBufferSize = PcdGetSize (PcdRsa2048Sha256PublicKeyBuffer); + DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer Size = %08x\n", PublicKeyBufferSize)); + ASSERT ((PublicKeyBufferSize % SHA256_DIGEST_SIZE) == 0); + CryptoStatus = FALSE; + while (PublicKeyBufferSize != 0) { + if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) { + CryptoStatus = TRUE; + break; + } + PublicKey = PublicKey + SHA256_DIGEST_SIZE; + PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE; + } + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Public key in section is not supported\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Generate & Initialize RSA Context. + // + Rsa = RsaNew (); + if (Rsa == NULL) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaNew() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Set RSA Key Components. + // NOTE: Only N and E are needed to be set as RSA public key for signature verification. + // + CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey)); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE)); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Hash data payload with SHA256. + // + ZeroMem (Digest, SHA256_DIGEST_SIZE); + CryptoStatus = Sha256Init (HashContext); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Init() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + PERF_INMODULE_BEGIN ("PeiRsaShaData"); + CryptoStatus = Sha256Update (HashContext, *OutputBuffer, OutputBufferSize); + PERF_INMODULE_END ("PeiRsaShaData"); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Update() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + CryptoStatus = Sha256Final (HashContext, Digest); + if (!CryptoStatus) { + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Final() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + goto Done; + } + + // + // Verify the RSA 2048 SHA 256 signature. + // + PERF_INMODULE_BEGIN ("PeiRsaVerify"); + CryptoStatus = RsaPkcs1Verify ( + Rsa, + Digest, + SHA256_DIGEST_SIZE, + CertBlockRsa2048Sha256->Signature, + sizeof (CertBlockRsa2048Sha256->Signature) + ); + PERF_INMODULE_END ("PeiRsaVerify"); + if (!CryptoStatus) { + // + // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set. + // + DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaPkcs1Verify() failed\n")); + *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED; + } + +Done: + // + // Free allocated resources used to perform RSA 2048 SHA 256 signature verification + // + if (Rsa != NULL) { + RsaFree (Rsa); + } + if (HashContext != NULL) { + FreePool (HashContext); + } + + DEBUG ((DEBUG_VERBOSE, "PeiRsa2048Sha256: Status = %r AuthenticationStatus = %08x\n", Status, *AuthenticationStatus)); + + return Status; +} + +/** + Register the handler to extract RSA 2048 SHA 256 guided section. + + @param FileHandle The handle of FFS header the loaded driver. + @param PeiServices The pointer to the PEI services. + + @retval EFI_SUCCESS Register successfully. + @retval EFI_OUT_OF_RESOURCES Not enough memory to register this handler. + +**/ +EFI_STATUS +EFIAPI +PeiRsa2048Sha256GuidedSectionExtractLibConstructor ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + return ExtractGuidedSectionRegisterHandlers ( + &gEfiCertTypeRsa2048Sha256Guid, + Rsa2048Sha256GuidedSectionGetInfo, + Rsa2048Sha256GuidedSectionHandler + ); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.inf new file mode 100644 index 00000000..c296bce2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.inf @@ -0,0 +1,53 @@ +## @file +# This library doesn't produce any library class. The constructor function uses +# ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler +# that parses RSA 2048 SHA 256 encapsulation section and extracts raw data. +# +# It uses the BaseCryptLib based on OpenSSL to authenticate the signature. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiRsa2048Sha256GuidedSectionExtractLib + FILE_GUID = FD5F2C91-4878-4007-BBA1-1B91DD325438 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL|PEI_CORE PEIM + CONSTRUCTOR = PeiRsa2048Sha256GuidedSectionExtractLibConstructor + MODULE_UNI_FILE = PeiRsa2048Sha256GuidedSectionExtractLib.uni + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + PeiRsa2048Sha256GuidedSectionExtractLib.c + +[Packages] + MdePkg/MdePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + ExtractGuidedSectionLib + DebugLib + BaseMemoryLib + MemoryAllocationLib + BaseCryptLib + PcdLib + PerformanceLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdRsa2048Sha256PublicKeyBuffer ## SOMETIMES_CONSUMES + +[Guids] + gEfiCertTypeRsa2048Sha256Guid ## PRODUCES ## UNDEFINED # Specifies RSA 2048 SHA 256 authentication algorithm. + gEfiHashAlgorithmSha256Guid ## SOMETIMES_CONSUMES ## UNDEFINED + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.uni new file mode 100644 index 00000000..f0294a68 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.uni @@ -0,0 +1,19 @@ +// /** @file
+// This library doesn't produce any library class. The constructor function uses
+//
+// ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler
+// that parses RSA 2048 SHA 256 encapsulation section and extracts raw data.
+//
+// It uses the BaseCryptLib based on OpenSSL to authenticate the signature.
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service of RSA 2048 SHA 256 guided section verification"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library doesn't produce any library class. The constructor function uses ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler that parses RSA2048 SHA256 encapsulation section and extracts raw data. It uses the BaseCryptLib based on OpenSSL to authenticate the signature."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.c new file mode 100644 index 00000000..c5560bd8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.c @@ -0,0 +1,53 @@ +/** @file + Get TPM 2.0 physical presence information. + + This library will get TPM 2.0 physical presence information. + +Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> + +#include <Guid/Tcg2PhysicalPresenceData.h> +#include <Ppi/ReadOnlyVariable2.h> + +#include <Library/DebugLib.h> +#include <Library/PeiServicesLib.h> +#include <Library/PeiServicesTablePointerLib.h> +#include <Library/Tcg2PhysicalPresenceLib.h> + +/** + Return TPM2 ManagementFlags set by PP interface. + + @retval ManagementFlags TPM2 Management Flags. +**/ +UINT32 +EFIAPI +Tcg2PhysicalPresenceLibGetManagementFlags ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi; + EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags; + UINTN DataSize; + + Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi); + ASSERT_EFI_ERROR (Status); + + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS); + Status = VariablePpi->GetVariable ( + VariablePpi, + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpiFlags + ); + if (EFI_ERROR (Status)) { + PpiFlags.PPFlags = PcdGet32(PcdTcg2PhysicalPresenceFlags); + } + return PpiFlags.PPFlags; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf new file mode 100644 index 00000000..40b710bf --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf @@ -0,0 +1,50 @@ +## @file +# Get TPM 2.0 physical presence information. +# +# This library will get TPM 2.0 physical presence information. +# +# Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiTcg2PhysicalPresenceLib + MODULE_UNI_FILE = PeiTcg2PhysicalPresenceLib.uni + FILE_GUID = AB82E7BE-0970-480b-93EB-3D332B89F99E + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tcg2PhysicalPresenceLib|PEIM + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + PeiTcg2PhysicalPresenceLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + DebugLib + PeiServicesLib + PeiServicesTablePointerLib + +[Guids] + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags" + gEfiTcg2PhysicalPresenceGuid + +[Ppis] + gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2PhysicalPresenceFlags ## SOMETIMES_CONSUMES + +[Depex] + gEfiPeiReadOnlyVariable2PpiGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.uni new file mode 100644 index 00000000..f8db628d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.uni @@ -0,0 +1,16 @@ +// /** @file
+// Get TPM 2.0 physical presence information.
+//
+// This library will get TPM 2.0 physical presence information.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Get TPM 2.0 physical presence information."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library will get TPM 2.0 physical presence information."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTpmMeasurementLib/PeiTpmMeasurementLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTpmMeasurementLib/PeiTpmMeasurementLib.c new file mode 100644 index 00000000..9636cbe8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTpmMeasurementLib/PeiTpmMeasurementLib.c @@ -0,0 +1,74 @@ +/** @file + This library is used by other modules to measure data to TPM. + +Copyright (c) 2020, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> + +#include <Library/BaseMemoryLib.h> +#include <Library/PeiServicesLib.h> +#include <Library/PeiServicesTablePointerLib.h> +#include <Library/DebugLib.h> +#include <Library/HobLib.h> +#include <Library/TpmMeasurementLib.h> + +#include <Ppi/Tcg.h> +#include <IndustryStandard/UefiTcgPlatform.h> + +/** + Tpm measure and log data, and extend the measurement result into a specific PCR. + + @param[in] PcrIndex PCR Index. + @param[in] EventType Event type. + @param[in] EventLog Measurement event log. + @param[in] LogLen Event log length in bytes. + @param[in] HashData The start of the data buffer to be hashed, extended. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED TPM device not available. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. +**/ +EFI_STATUS +EFIAPI +TpmMeasureAndLogData ( + IN UINT32 PcrIndex, + IN UINT32 EventType, + IN VOID *EventLog, + IN UINT32 LogLen, + IN VOID *HashData, + IN UINT64 HashDataLen + ) +{ + EFI_STATUS Status; + EDKII_TCG_PPI *TcgPpi; + TCG_PCR_EVENT_HDR TcgEventHdr; + + Status = PeiServicesLocatePpi ( + &gEdkiiTcgPpiGuid, + 0, + NULL, + (VOID**)&TcgPpi + ); + if (EFI_ERROR(Status)) { + return Status; + } + + TcgEventHdr.PCRIndex = PcrIndex; + TcgEventHdr.EventType = EventType; + TcgEventHdr.EventSize = LogLen; + + Status = TcgPpi->HashLogExtendEvent ( + TcgPpi, + 0, + HashData, + (UINTN)HashDataLen, + &TcgEventHdr, + EventLog + ); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTpmMeasurementLib/PeiTpmMeasurementLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTpmMeasurementLib/PeiTpmMeasurementLib.inf new file mode 100644 index 00000000..e83c737f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTpmMeasurementLib/PeiTpmMeasurementLib.inf @@ -0,0 +1,49 @@ +## @file +# Provides TPM measurement functions for TPM1.2 and TPM 2.0 +# +# This library provides TpmMeasureAndLogData() to measure and log data, and +# extend the measurement result into a specific PCR. +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PeiTpmMeasurementLib + FILE_GUID = 9A62C49D-C45A-4322-9F3C-45958DF0056B + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = TpmMeasurementLib|PEIM + MODULE_UNI_FILE = PeiTpmMeasurementLib.uni + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + PeiTpmMeasurementLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + HobLib + DebugLib + PcdLib + PrintLib + PeiServicesLib + PeiServicesTablePointerLib + +[Ppis] + gEdkiiTcgPpiGuid ## CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTpmMeasurementLib/PeiTpmMeasurementLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTpmMeasurementLib/PeiTpmMeasurementLib.uni new file mode 100644 index 00000000..7b4341b4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PeiTpmMeasurementLib/PeiTpmMeasurementLib.uni @@ -0,0 +1,17 @@ +// /** @file
+// Provides TPM measurement functions for TPM1.2 and TPM 2.0
+//
+// This library provides TpmMeasureAndLogData() to to measure and log data, and
+// extend the measurement result into a specific PCR.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM measurement functions for TPM1.2 and TPM 2.0"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provides TpmMeasureAndLogData() to to measure and log data, and extend the measurement result into a specific PCR."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c new file mode 100644 index 00000000..4d1180d9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c @@ -0,0 +1,59 @@ +/** @file + NULL PlatformSecureLib instance does NOT really detect whether a physical present + user exists but return TRUE directly. This instance can be used to verify security + related features during platform enabling and development. It should be replaced + by a platform-specific method(e.g. Button pressed) in a real platform for product. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi/UefiBaseType.h> + +BOOLEAN mUserPhysicalPresence = FALSE; + +/** + + This function provides a platform-specific method to detect whether the platform + is operating by a physically present user. + + Programmatic changing of platform security policy (such as disable Secure Boot, + or switch between Standard/Custom Secure Boot mode) MUST NOT be possible during + Boot Services or after exiting EFI Boot Services. Only a physically present user + is allowed to perform these operations. + + 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 is operated by a physically present user. + @retval FALSE The platform is NOT operated by a physically present user. + +**/ +BOOLEAN +EFIAPI +UserPhysicalPresent ( + VOID + ) +{ + return mUserPhysicalPresence; +} + + +/** + Save user physical presence state from a PCD to mUserPhysicalPresence. + + @retval EFI_SUCCESS PcdUserPhysicalPresence is got successfully. + +**/ +RETURN_STATUS +EFIAPI +PlatformSecureLibNullConstructor ( + VOID + ) +{ + + mUserPhysicalPresence = PcdGetBool(PcdUserPhysicalPresence); + + return RETURN_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf new file mode 100644 index 00000000..e7640618 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf @@ -0,0 +1,39 @@ +## @file +# NULL platform secure library instance that always returns TRUE for a user physical present +# +# NULL PlatformSecureLib instance does NOT really detect whether a physical present +# user exists but returns TRUE directly. This instance can be used to verify security +# related features during platform enabling and development. It should be replaced +# by a platform-specific method(e.g. Button pressed) in a real platform for product. +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformSecureLibNull + MODULE_UNI_FILE = PlatformSecureLibNull.uni + FILE_GUID = 7FA68D82-10A4-4e71-9524-D3D9500D3CDF + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = PlatformSecureLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER MM_STANDALONE + CONSTRUCTOR = PlatformSecureLibNullConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + PlatformSecureLibNull.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdUserPhysicalPresence ## CONSUMES + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni new file mode 100644 index 00000000..860b8cbb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni @@ -0,0 +1,19 @@ +// /** @file
+// NULL platform secure library instance that always returns TRUE for a user physical present
+//
+// NULL PlatformSecureLib instance does NOT really detect whether a physical present
+// user exists but returns TRUE directly. This instance can be used to verify security
+// related features during platform enabling and development. It should be replaced
+// by a platform-specific method(e.g. Button pressed) in a real platform for product.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL platform secure library instance that always returns TRUE for a user physical present"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL PlatformSecureLib instance does NOT really detect whether a physical present user exists but returns TRUE directly. This instance can be used to verify security related features during platform enabling and development. It should be replaced by a platform-specific method(e.g. Button pressed) in a real platform for product."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c new file mode 100644 index 00000000..00a9d6b3 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.c @@ -0,0 +1,47 @@ +/** @file + NULL RpmcLib instance for build purpose. + +Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/DebugLib.h> +#include <Library/RpmcLib.h> + +/** + Requests the monotonic counter from the designated RPMC counter. + + @param[out] CounterValue A pointer to a buffer to store the RPMC value. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to update the counter. + @retval EFI_UNSUPPORTED The operation is un-supported. +**/ +EFI_STATUS +EFIAPI +RequestMonotonicCounter ( + OUT UINT32 *CounterValue + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +/** + Increments the monotonic counter in the SPI flash device by 1. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_DEVICE_ERROR A device error occurred while attempting to update the counter. + @retval EFI_UNSUPPORTED The operation is un-supported. +**/ +EFI_STATUS +EFIAPI +IncrementMonotonicCounter ( + VOID + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.inf new file mode 100644 index 00000000..3a4a982f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/RpmcLibNull/RpmcLibNull.inf @@ -0,0 +1,33 @@ +## @file +# Provides Null version of RpmcLib for build purpose. +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010029 + BASE_NAME = RpmcLibNull + FILE_GUID = FAE0BA22-92E2-4334-8F0F-96AFF9BAE360 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = RpmcLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 Arm AArch64 +# + +[Sources] + RpmcLibNull.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/MmTcg2PhysicalPresenceLibCommon.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/MmTcg2PhysicalPresenceLibCommon.c new file mode 100644 index 00000000..12334b2c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/MmTcg2PhysicalPresenceLibCommon.c @@ -0,0 +1,398 @@ +/** @file + Handle TPM 2.0 physical presence requests from OS. + + This library will handle TPM 2.0 physical presence request from OS. + + 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. + + Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction() and Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction() + will receive untrusted input and do validation. + +Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include <Guid/Tcg2PhysicalPresenceData.h> + +#include <Protocol/SmmVariable.h> + +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tcg2PpVendorLib.h> +#include <Library/MmServicesTableLib.h> + +#define PP_INF_VERSION_1_2 "1.2" + +EFI_SMM_VARIABLE_PROTOCOL *mTcg2PpSmmVariable; +BOOLEAN mIsTcg2PPVerLowerThan_1_3 = FALSE; +UINT32 mTcg2PhysicalPresenceFlags; + +/** + The handler for TPM physical presence function: + Return TPM Operation Response to OS Environment. + + This API should be invoked in OS runtime phase to interface with ACPI method. + + @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; + UINTN DataSize; + EFI_TCG2_PHYSICAL_PRESENCE PpData; + + DEBUG ((DEBUG_INFO, "[TPM2] ReturnOperationResponseToOsFunction\n")); + + // + // Get the Physical Presence variable + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = mTcg2PpSmmVariable->SmmGetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + *MostRecentRequest = 0; + *Response = 0; + DEBUG ((DEBUG_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); + return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE; + } + + *MostRecentRequest = PpData.LastPPRequest; + *Response = PpData.PPResponse; + + 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. + + This API should be invoked in OS runtime phase to interface with ACPI method. + + Caution: This function may receive untrusted input. + + @param[in, out] Pointer to OperationRequest TPM physical presence operation request. + @param[in, out] Pointer to 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 +Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx ( + IN OUT UINT32 *OperationRequest, + IN OUT UINT32 *RequestParameter + ) +{ + EFI_STATUS Status; + UINT32 ReturnCode; + UINTN DataSize; + EFI_TCG2_PHYSICAL_PRESENCE PpData; + EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags; + + DEBUG ((DEBUG_INFO, "[TPM2] SubmitRequestToPreOSFunction, Request = %x, %x\n", *OperationRequest, *RequestParameter)); + ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS; + + // + // Get the Physical Presence variable + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = mTcg2PpSmmVariable->SmmGetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); + ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; + goto EXIT; + } + + if ((*OperationRequest > TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) && + (*OperationRequest < TCG2_PHYSICAL_PRESENCE_STORAGE_MANAGEMENT_BEGIN) ) { + ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED; + goto EXIT; + } + + if ((PpData.PPRequest != *OperationRequest) || + (PpData.PPRequestParameter != *RequestParameter)) { + PpData.PPRequest = (UINT8)*OperationRequest; + PpData.PPRequestParameter = *RequestParameter; + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = mTcg2PpSmmVariable->SmmSetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[TPM2] Set PP variable failure! Status = %r\n", Status)); + ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; + goto EXIT; + } + } + + if (*OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS); + Status = mTcg2PpSmmVariable->SmmGetVariable ( + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &Flags + ); + if (EFI_ERROR (Status)) { + Flags.PPFlags = mTcg2PhysicalPresenceFlags; + } + ReturnCode = Tcg2PpVendorLibSubmitRequestToPreOSFunction (*OperationRequest, Flags.PPFlags, *RequestParameter); + } + +EXIT: + // + // Sync PPRQ/PPRM from PP Variable if PP submission fails + // + if (ReturnCode != TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) { + DEBUG ((DEBUG_ERROR, "[TPM2] Submit PP Request failure! Sync PPRQ/PPRM with PP variable.\n", Status)); + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + ZeroMem(&PpData, DataSize); + Status = mTcg2PpSmmVariable->SmmGetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + *OperationRequest = (UINT32)PpData.PPRequest; + *RequestParameter = PpData.PPRequestParameter; + } + + return ReturnCode; +} + +/** + 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. + + This API should be invoked in OS runtime phase to interface with ACPI method. + + 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 + ) +{ + UINT32 TempOperationRequest; + UINT32 TempRequestParameter; + + TempOperationRequest = OperationRequest; + TempRequestParameter = RequestParameter; + + return Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx(&TempOperationRequest, &TempRequestParameter); +} + +/** + The handler for TPM physical presence function: + Get User Confirmation Status for Operation. + + This API should be invoked in OS runtime phase to interface with ACPI method. + + Caution: This function may receive untrusted input. + + @param[in] OperationRequest TPM physical presence operation request. + + @return Return Code for Get User Confirmation Status for Operation. +**/ +UINT32 +EFIAPI +Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction ( + IN UINT32 OperationRequest + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_TCG2_PHYSICAL_PRESENCE PpData; + EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags; + BOOLEAN RequestConfirmed; + + DEBUG ((DEBUG_INFO, "[TPM2] GetUserConfirmationStatusFunction, Request = %x\n", OperationRequest)); + + // + // Get the Physical Presence variable + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE); + Status = mTcg2PpSmmVariable->SmmGetVariable ( + TCG2_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); + return TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; + } + // + // Get the Physical Presence flags + // + DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS); + Status = mTcg2PpSmmVariable->SmmGetVariable ( + TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTcg2PhysicalPresenceGuid, + NULL, + &DataSize, + &Flags + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[TPM2] Get PP flags failure! Status = %r\n", Status)); + return TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; + } + + RequestConfirmed = FALSE; + + switch (OperationRequest) { + 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: + if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR) == 0) { + RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_NO_ACTION: + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_TRUE: + RequestConfirmed = TRUE; + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_FALSE: + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS: + if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_PCRS) == 0) { + RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS: + if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_EPS) == 0) { + RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS: + RequestConfirmed = TRUE; + break; + + case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID: + if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) == 0) { + RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID: + if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) == 0) { + RequestConfirmed = TRUE; + } + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE: + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE: + RequestConfirmed = TRUE; + break; + + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE: + case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE: + break; + + default: + if (!mIsTcg2PPVerLowerThan_1_3) { + if (OperationRequest < TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + // + // TCG2 PP1.3 spec defined operations that are reserved or un-implemented + // + return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED; + } + } else { + // + // TCG PP lower than 1.3. (1.0, 1.1, 1.2) + // + if (OperationRequest <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) { + RequestConfirmed = TRUE; + } else if (OperationRequest < TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED; + } + } + break; + } + + if (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + return Tcg2PpVendorLibGetUserConfirmationStatusFunction (OperationRequest, Flags.PPFlags); + } + + if (RequestConfirmed) { + return TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED; + } else { + return TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED; + } +} + +/** + The constructor function locates SmmVariable protocol. + + It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. + + @retval EFI_SUCCESS The constructor successfully added string package. + @retval Other value The constructor can't add string package. +**/ +EFI_STATUS +Tcg2PhysicalPresenceLibCommonConstructor ( + VOID + ) +{ + EFI_STATUS Status; + + if (AsciiStrnCmp(PP_INF_VERSION_1_2, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer), sizeof(PP_INF_VERSION_1_2) - 1) >= 0) { + mIsTcg2PPVerLowerThan_1_3 = TRUE; + } + + // + // Locate SmmVariableProtocol. + // + Status = gMmst->MmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mTcg2PpSmmVariable); + ASSERT_EFI_ERROR (Status); + + mTcg2PhysicalPresenceFlags = PcdGet32(PcdTcg2PhysicalPresenceFlags); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/MmTcg2PhysicalPresenceLibCommon.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/MmTcg2PhysicalPresenceLibCommon.h new file mode 100644 index 00000000..5dabb4c2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/MmTcg2PhysicalPresenceLibCommon.h @@ -0,0 +1,34 @@ +/** @file + Handle TPM 2.0 physical presence requests from OS. + + This library will handle TPM 2.0 physical presence request from OS. + + 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. + + Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction() and Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction() + will receive untrusted input and do validation. + +Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _MM_TCG2_PHYSICAL_PRESENCE_LIB_COMMON_H_ +#define _MM_TCG2_PHYSICAL_PRESENCE_LIB_COMMON_H_ + +/** + The constructor function locates MmVariable protocol. + + It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. + + @retval EFI_SUCCESS The constructor successfully added string package. + @retval Other value The constructor can't add string package. +**/ +EFI_STATUS +Tcg2PhysicalPresenceLibCommonConstructor ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c new file mode 100644 index 00000000..d43f1611 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c @@ -0,0 +1,41 @@ +/** @file + Handle TPM 2.0 physical presence requests from OS. + + This library will handle TPM 2.0 physical presence request from OS. + + 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. + + Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction() and Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction() + will receive untrusted input and do validation. + +Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiSmm.h> + +#include "MmTcg2PhysicalPresenceLibCommon.h" + +/** + The constructor function locates SmmVariable protocol. + + It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor successfully added string package. + @retval Other value The constructor can't add string package. +**/ +EFI_STATUS +EFIAPI +Tcg2PhysicalPresenceLibTraditionalConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + return Tcg2PhysicalPresenceLibCommonConstructor (); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf new file mode 100644 index 00000000..b60073cc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf @@ -0,0 +1,58 @@ +## @file +# Handle TPM 2.0 physical presence requests from OS. +# +# This library will handle TPM 2.0 physical presence request from OS. +# +# 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. +# +# Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = SmmTcg2PhysicalPresenceLib + MODULE_UNI_FILE = SmmTcg2PhysicalPresenceLib.uni + FILE_GUID = AAE02741-858B-4964-9887-CA870489D944 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tcg2PhysicalPresenceLib|DXE_SMM_DRIVER + CONSTRUCTOR = Tcg2PhysicalPresenceLibTraditionalConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + SmmTcg2PhysicalPresenceLib.c + MmTcg2PhysicalPresenceLibCommon.c + MmTcg2PhysicalPresenceLibCommon.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + DebugLib + Tcg2PpVendorLib + MmServicesTableLib + BaseMemoryLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags" + gEfiTcg2PhysicalPresenceGuid + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2PhysicalPresenceFlags ## SOMETIMES_CONSUMES + +[Depex] + gEfiSmmVariableProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.uni new file mode 100644 index 00000000..2428b773 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.uni @@ -0,0 +1,21 @@ +// /** @file
+// Handle TPM 2.0 physical presence requests from OS.
+//
+// This library will handle TPM 2.0 physical presence request from OS.
+//
+// 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.
+//
+// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Handle TPM 2.0 physical presence requests from OS"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library will handle TPM 2.0 physical presence request from OS.\n"
+ "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."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/StandaloneMmTcg2PhysicalPresenceLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/StandaloneMmTcg2PhysicalPresenceLib.c new file mode 100644 index 00000000..87d9e634 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/StandaloneMmTcg2PhysicalPresenceLib.c @@ -0,0 +1,42 @@ +/** @file + Handle TPM 2.0 physical presence requests from OS. + + This library will handle TPM 2.0 physical presence request from OS. + + 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. + + Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction() and Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction() + will receive untrusted input and do validation. + +Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR> +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiMm.h> + +#include "MmTcg2PhysicalPresenceLibCommon.h" + +/** + The constructor function locates SmmVariable protocol. + + It will ASSERT() if that operation fails and it will always return EFI_SUCCESS. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor successfully added string package. + @retval Other value The constructor can't add string package. +**/ +EFI_STATUS +EFIAPI +Tcg2PhysicalPresenceLibStandaloneMmConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_MM_SYSTEM_TABLE *SystemTable + ) +{ + return Tcg2PhysicalPresenceLibCommonConstructor (); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/StandaloneMmTcg2PhysicalPresenceLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/StandaloneMmTcg2PhysicalPresenceLib.inf new file mode 100644 index 00000000..1b69efe8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/StandaloneMmTcg2PhysicalPresenceLib.inf @@ -0,0 +1,62 @@ +## @file +# Handle TPM 2.0 physical presence requests from OS. +# +# This library will handle TPM 2.0 physical presence request from OS. +# +# 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. +# +# Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR> +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = StandaloneMmTcg2PhysicalPresenceLib + FILE_GUID = 75E3D07B-689C-4F42-A8A0-46AFAE868A6F + MODULE_TYPE = MM_STANDALONE + PI_SPECIFICATION_VERSION = 0x00010032 + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tcg2PhysicalPresenceLib|MM_STANDALONE + CONSTRUCTOR = Tcg2PhysicalPresenceLibStandaloneMmConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + StandaloneMmTcg2PhysicalPresenceLib.c + MmTcg2PhysicalPresenceLibCommon.c + MmTcg2PhysicalPresenceLibCommon.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + DebugLib + Tcg2PpVendorLib + MmServicesTableLib + BaseMemoryLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags" + gEfiTcg2PhysicalPresenceGuid + +[Protocols] + gEfiSmmVariableProtocolGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2PhysicalPresenceFlags ## SOMETIMES_CONSUMES + +[Depex] + gEfiSmmVariableProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.c new file mode 100644 index 00000000..de3d8374 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.c @@ -0,0 +1,127 @@ +/** @file + NULL Tcg2 PP Vendor library instance that does not support any vendor specific PPI. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/DebugLib.h> +#include <Library/Tcg2PpVendorLib.h> + +/** + Check and execute the requested physical presence command. + + This API should be invoked in BIOS boot phase to process pending request. + + Caution: This function may receive untrusted input. + + If OperationRequest < 128, then ASSERT(). + + @param[in] PlatformAuth platform auth value. NULL means no platform auth change. + @param[in] OperationRequest TPM physical presence operation request. + @param[in, out] ManagementFlags BIOS TPM Management Flags. + @param[out] ResetRequired If reset is required to vendor settings in effect. + True, it indicates the reset is required. + False, it indicates the reset is not required. + + @return TPM Operation Response to OS Environment. +**/ +UINT32 +EFIAPI +Tcg2PpVendorLibExecutePendingRequest ( + IN TPM2B_AUTH *PlatformAuth, OPTIONAL + IN UINT32 OperationRequest, + IN OUT UINT32 *ManagementFlags, + OUT BOOLEAN *ResetRequired + ) +{ + ASSERT (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION); + return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE; +} + +/** + Check if there is a valid physical presence command request. + + This API should be invoked in BIOS boot phase to process pending request. + + Caution: This function may receive untrusted input. + + If OperationRequest < 128, then ASSERT(). + + @param[in] OperationRequest TPM physical presence operation request. + @param[in] ManagementFlags BIOS TPM Management Flags. + @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI. + True, it indicates the command doesn't require user confirm. + 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. +**/ +BOOLEAN +EFIAPI +Tcg2PpVendorLibHasValidRequest ( + IN UINT32 OperationRequest, + IN UINT32 ManagementFlags, + OUT BOOLEAN *RequestConfirmed + ) +{ + ASSERT (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION); + return FALSE; +} + +/** + The callback for TPM vendor specific physical presence which is called for + Submit TPM Operation Request to Pre-OS Environment and + Submit TPM Operation Request to Pre-OS Environment 2. + + This API should be invoked in OS runtime phase to interface with ACPI method. + + Caution: This function may receive untrusted input. + + If OperationRequest < 128, then ASSERT(). + + @param[in] OperationRequest TPM physical presence operation request. + @param[in] ManagementFlags BIOS TPM Management Flags. + @param[in] RequestParameter Extra parameter from the passed package. + + @return Return Code for Submit TPM Operation Request to Pre-OS Environment and + Submit TPM Operation Request to Pre-OS Environment 2. +**/ +UINT32 +EFIAPI +Tcg2PpVendorLibSubmitRequestToPreOSFunction ( + IN UINT32 OperationRequest, + IN UINT32 ManagementFlags, + IN UINT32 RequestParameter + ) +{ + ASSERT (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION); + return TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED; +} + +/** + The callback for TPM vendor specific physical presence which is called for + Get User Confirmation Status for Operation. + + This API should be invoked in OS runtime phase to interface with ACPI method. + + Caution: This function may receive untrusted input. + + If OperationRequest < 128, then ASSERT(). + + @param[in] OperationRequest TPM physical presence operation request. + @param[in] ManagementFlags BIOS TPM Management Flags. + + @return Return Code for Get User Confirmation Status for Operation. +**/ +UINT32 +EFIAPI +Tcg2PpVendorLibGetUserConfirmationStatusFunction ( + IN UINT32 OperationRequest, + IN UINT32 ManagementFlags + ) +{ + ASSERT (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION); + return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.inf new file mode 100644 index 00000000..71ab0862 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.inf @@ -0,0 +1,32 @@ +## @file +# NULL Tcg PP Vendor library instance that does not support any vendor specific PPI +# +# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tcg2PpVendorLibNull + MODULE_UNI_FILE = Tcg2PpVendorLibNull.uni + FILE_GUID = 51924AE9-BE81-4820-94BA-7C9546E702D0 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tcg2PpVendorLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER MM_STANDALONE + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + Tcg2PpVendorLibNull.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + DebugLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.uni new file mode 100644 index 00000000..f8140ab1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.uni @@ -0,0 +1,13 @@ +// /** @file
+// NULL Tcg PP Vendor library instance that does not support any vendor specific PPI
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL Tcg PP Vendor library instance that does not support any vendor specific PPI"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL Tcg PP Vendor library instance that does not support any vendor specific PPI."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.c new file mode 100644 index 00000000..02dbbeb9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.c @@ -0,0 +1,197 @@ +/** @file + This library is used by other modules to measure data to TPM. + +Copyright (c) 2020, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi/UefiBaseType.h> +#include <Pi/PiFirmwareVolume.h> + +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/ReportStatusCodeLib.h> +#include <Library/PcdLib.h> +#include <Library/PrintLib.h> +#include <Library/TcgEventLogRecordLib.h> +#include <Library/TpmMeasurementLib.h> + +#include <IndustryStandard/UefiTcgPlatform.h> + +/** + Get the FvName from the FV header. + + Causion: The FV is untrusted input. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + + @return FvName pointer + @retval NULL FvName is NOT found +**/ +VOID * +TpmMeasurementGetFvName ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; + + if (FvBase >= MAX_ADDRESS) { + return NULL; + } + if (FvLength >= MAX_ADDRESS - FvBase) { + return NULL; + } + if (FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) { + return NULL; + } + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase; + if (FvHeader->Signature != EFI_FVH_SIGNATURE) { + return NULL; + } + if (FvHeader->ExtHeaderOffset < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) { + return NULL; + } + if (FvHeader->ExtHeaderOffset + sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER) > FvLength) { + return NULL; + } + FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(UINTN)(FvBase + FvHeader->ExtHeaderOffset); + + return &FvExtHeader->FvName; +} + +/** + Measure a FirmwareBlob. + + @param[in] PcrIndex PcrIndex of the measurement. + @param[in] Description Description for this FirmwareBlob. + @param[in] FirmwareBlobBase Base address of this FirmwareBlob. + @param[in] FirmwareBlobLength Size in bytes of this FirmwareBlob. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED TPM device not available. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. +**/ +EFI_STATUS +EFIAPI +MeasureFirmwareBlob ( + IN UINT32 PcrIndex, + IN CHAR8 *Description OPTIONAL, + IN EFI_PHYSICAL_ADDRESS FirmwareBlobBase, + IN UINT64 FirmwareBlobLength + ) +{ + EFI_PLATFORM_FIRMWARE_BLOB FvBlob; + PLATFORM_FIRMWARE_BLOB2_STRUCT FvBlob2; + VOID *FvName; + UINT32 EventType; + VOID *EventLog; + UINT32 EventLogSize; + EFI_STATUS Status; + + FvName = TpmMeasurementGetFvName (FirmwareBlobBase, FirmwareBlobLength); + + if (((Description != NULL) || (FvName != NULL)) && + (PcdGet32(PcdTcgPfpMeasurementRevision) >= TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2_REV_105)) { + if (Description != NULL) { + AsciiSPrint((CHAR8*)FvBlob2.BlobDescription, sizeof(FvBlob2.BlobDescription), "%a", Description); + } else { + AsciiSPrint((CHAR8*)FvBlob2.BlobDescription, sizeof(FvBlob2.BlobDescription), "Fv(%g)", FvName); + } + + FvBlob2.BlobDescriptionSize = sizeof(FvBlob2.BlobDescription); + FvBlob2.BlobBase = FirmwareBlobBase; + FvBlob2.BlobLength = FirmwareBlobLength; + + EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB2; + EventLog = &FvBlob2; + EventLogSize = sizeof(FvBlob2); + } else { + FvBlob.BlobBase = FirmwareBlobBase; + FvBlob.BlobLength = FirmwareBlobLength; + + EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; + EventLog = &FvBlob; + EventLogSize = sizeof(FvBlob); + } + + Status = TpmMeasureAndLogData ( + PcrIndex, + EventType, + EventLog, + EventLogSize, + (VOID*)(UINTN)FirmwareBlobBase, + FirmwareBlobLength + ); + + return Status; +} + +/** + Measure a HandoffTable. + + @param[in] PcrIndex PcrIndex of the measurement. + @param[in] Description Description for this HandoffTable. + @param[in] TableGuid GUID of this HandoffTable. + @param[in] TableAddress Base address of this HandoffTable. + @param[in] TableLength Size in bytes of this HandoffTable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED TPM device not available. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. +**/ +EFI_STATUS +EFIAPI +MeasureHandoffTable ( + IN UINT32 PcrIndex, + IN CHAR8 *Description OPTIONAL, + IN EFI_GUID *TableGuid, + IN VOID *TableAddress, + IN UINTN TableLength + ) +{ + EFI_HANDOFF_TABLE_POINTERS HandoffTables; + HANDOFF_TABLE_POINTERS2_STRUCT HandoffTables2; + UINT32 EventType; + VOID *EventLog; + UINT32 EventLogSize; + EFI_STATUS Status; + + if ((Description != NULL) && + (PcdGet32(PcdTcgPfpMeasurementRevision) >= TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2_REV_105)) { + AsciiSPrint((CHAR8*)HandoffTables2.TableDescription, sizeof(HandoffTables2.TableDescription), "%a", Description); + + HandoffTables2.TableDescriptionSize = sizeof(HandoffTables2.TableDescription); + HandoffTables2.NumberOfTables = 1; + CopyGuid (&(HandoffTables2.TableEntry[0].VendorGuid), TableGuid); + HandoffTables2.TableEntry[0].VendorTable = TableAddress; + + EventType = EV_EFI_HANDOFF_TABLES2; + EventLog = &HandoffTables2; + EventLogSize = sizeof(HandoffTables2); + } else { + HandoffTables.NumberOfTables = 1; + CopyGuid (&(HandoffTables.TableEntry[0].VendorGuid), TableGuid); + HandoffTables.TableEntry[0].VendorTable = TableAddress; + + EventType = EV_EFI_HANDOFF_TABLES; + EventLog = &HandoffTables; + EventLogSize = sizeof(HandoffTables); + } + + Status = TpmMeasureAndLogData ( + PcrIndex, + EventType, + EventLog, + EventLogSize, + TableAddress, + TableLength + ); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.inf new file mode 100644 index 00000000..567cb436 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.inf @@ -0,0 +1,40 @@ +## @file +# Provides interface for firmwware TPM measurement +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgEventLogRecordLib + MODULE_UNI_FILE = TcgEventLogRecordLib.uni + FILE_GUID = F8125B2A-3922-4A22-A6F8-3B6159A25A3B + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + TcgEventLogRecordLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + PcdLib + TpmMeasurementLib + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.uni new file mode 100644 index 00000000..b1ca4100 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgEventLogRecordLib/TcgEventLogRecordLib.uni @@ -0,0 +1,17 @@ +// /** @file
+// Provides interface for firmwware TPM measurement
+//
+// This library provides MeasureFirmwareBlob() and MeasureHandoffTable()
+// to measure and log data, and extend the measurement result into a specific PCR.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides Firmware TPM measurement functions for TPM1.2 and TPM 2.0"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provides MeasureFirmwareBlob() and MeasureHandoffTable() to measure and log data, and extend the measurement result into a specific PCR."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.c new file mode 100644 index 00000000..2dd8c0c7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.c @@ -0,0 +1,123 @@ +/** @file + NULL TCG PP Vendor library instance that does not support any vendor specific PPI. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/DebugLib.h> +#include <Library/TcgPpVendorLib.h> + +/** + Check and execute the requested physical presence command. + + This API should be invoked in BIOS boot phase to process pending request. + + Caution: This function may receive untrusted input. + + If OperationRequest < 128, then ASSERT(). + + @param[in] OperationRequest TPM physical presence operation request. + @param[in, out] ManagementFlags BIOS TPM Management Flags. + @param[out] ResetRequired If reset is required to vendor settings in effect. + True, it indicates the reset is required. + False, it indicates the reset is not required. + + @return TPM Operation Response to OS Environment. +**/ +UINT32 +EFIAPI +TcgPpVendorLibExecutePendingRequest ( + IN UINT32 OperationRequest, + IN OUT UINT32 *ManagementFlags, + OUT BOOLEAN *ResetRequired + ) +{ + ASSERT (OperationRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION); + return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE; +} + +/** + Check if there is a valid physical presence command request. + + This API should be invoked in BIOS boot phase to process pending request. + + Caution: This function may receive untrusted input. + + If OperationRequest < 128, then ASSERT(). + + @param[in] OperationRequest TPM physical presence operation request. + @param[in] ManagementFlags BIOS TPM Management Flags. + @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI. + True, it indicates the command doesn't require user confirm. + 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. +**/ +BOOLEAN +EFIAPI +TcgPpVendorLibHasValidRequest ( + IN UINT32 OperationRequest, + IN UINT32 ManagementFlags, + OUT BOOLEAN *RequestConfirmed + ) +{ + ASSERT (OperationRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION); + return FALSE; +} + +/** + The callback for TPM vendor specific physical presence which is called for + Submit TPM Operation Request to Pre-OS Environment and + Submit TPM Operation Request to Pre-OS Environment 2. + + This API should be invoked in OS runtime phase to interface with ACPI method. + + Caution: This function may receive untrusted input. + + If OperationRequest < 128, then ASSERT(). + + @param[in] OperationRequest TPM physical presence operation request. + @param[in] ManagementFlags BIOS TPM Management Flags. + + @return Return Code for Submit TPM Operation Request to Pre-OS Environment and + Submit TPM Operation Request to Pre-OS Environment 2. +**/ +UINT32 +EFIAPI +TcgPpVendorLibSubmitRequestToPreOSFunction ( + IN UINT32 OperationRequest, + IN UINT32 ManagementFlags + ) +{ + ASSERT (OperationRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION); + return TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED; +} + +/** + The callback for TPM vendor specific physical presence which is called for + Get User Confirmation Status for Operation. + + This API should be invoked in OS runtime phase to interface with ACPI method. + + Caution: This function may receive untrusted input. + + If OperationRequest < 128, then ASSERT(). + + @param[in] OperationRequest TPM physical presence operation request. + @param[in] ManagementFlags BIOS TPM Management Flags. + + @return Return Code for Get User Confirmation Status for Operation. +**/ +UINT32 +EFIAPI +TcgPpVendorLibGetUserConfirmationStatusFunction ( + IN UINT32 OperationRequest, + IN UINT32 ManagementFlags + ) +{ + ASSERT (OperationRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION); + return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf new file mode 100644 index 00000000..1f95596a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf @@ -0,0 +1,32 @@ +## @file +# NULL TCG PP Vendor library instance that does not support any vendor specific PPI +# +# Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgPpVendorLibNull + MODULE_UNI_FILE = TcgPpVendorLibNull.uni + FILE_GUID = 8489334D-4219-4CA1-9B42-1D46B0B75861 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = TcgPpVendorLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 EBC +# + +[Sources] + TcgPpVendorLibNull.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + DebugLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.uni new file mode 100644 index 00000000..53e6ef4d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.uni @@ -0,0 +1,13 @@ +// /** @file
+// NULL TCG PP Vendor library instance that does not support any vendor specific PPI
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL TCG PP Vendor library instance that does not support any vendor specific PPI"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL TCG PP Vendor library instance that does not support any vendor specific PPI."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c new file mode 100644 index 00000000..8f759312 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c @@ -0,0 +1,1646 @@ +/** @file + Provide functions to provide tcg storage core spec related functions. + +Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/TcgStorageCoreLib.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +//#include <Library/PrintLib.h> + +/** + Required to be called before calling any other Tcg functions with the TCG_CREATE_STRUCT. + Initializes the packet variables to NULL. Additionally, the buffer will be memset. + + @param [in/out] CreateStruct Structure to initialize + @param [in] Buffer Buffer allocated by client of library. It will contain the Tcg encoded packet. This cannot be null. + @param [in] BufferSize Size of buffer provided. It cannot be 0. + + @retval Return the action result. +**/ +TCG_RESULT +EFIAPI +TcgInitTcgCreateStruct( + TCG_CREATE_STRUCT *CreateStruct, + VOID *Buffer, + UINT32 BufferSize + ) +{ + NULL_CHECK(CreateStruct); + NULL_CHECK(Buffer); + + if (BufferSize == 0) { + DEBUG ((DEBUG_INFO, "BufferSize=0\n")); + return (TcgResultFailureZeroSize); + } + + ZeroMem(Buffer, BufferSize); + CreateStruct->BufferSize = BufferSize; + CreateStruct->Buffer = Buffer; + CreateStruct->ComPacket = NULL; + CreateStruct->CurPacket = NULL; + CreateStruct->CurSubPacket = NULL; + + return (TcgResultSuccess); +} + +/** + + Encodes the ComPacket header to the data structure. + + @param[in/out] CreateStruct Structure to initialize + @param[in] ComId ComID of the Tcg ComPacket. + @param[in] ComIdExtension ComID Extension of the Tcg ComPacket. + +**/ +TCG_RESULT +EFIAPI +TcgStartComPacket( + TCG_CREATE_STRUCT *CreateStruct, + UINT16 ComId, + UINT16 ComIdExtension + ) +{ + NULL_CHECK(CreateStruct); + + if (CreateStruct->ComPacket != NULL || + CreateStruct->CurPacket != NULL || + CreateStruct->CurSubPacket != NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, + CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + if (sizeof(TCG_COM_PACKET) > CreateStruct->BufferSize) { + DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize)); + return (TcgResultFailureBufferTooSmall); + } + + CreateStruct->ComPacket = (TCG_COM_PACKET*)CreateStruct->Buffer; + CreateStruct->ComPacket->ComIDBE = SwapBytes16(ComId); + CreateStruct->ComPacket->ComIDExtensionBE = SwapBytes16(ComIdExtension); + + return (TcgResultSuccess); +} + +/** + + Starts a new ComPacket in the Data structure. + + @param [in/out] CreateStruct Structure used to add Tcg Packet + @param[in] Tsn Packet Tper session number + @param[in] Hsn Packet Host session number + @param[in] SeqNumber Packet Sequence Number + @param[in] AckType Packet Acknowledge Type + @param[in] Ack Packet Acknowledge + +**/ +TCG_RESULT +EFIAPI +TcgStartPacket( + TCG_CREATE_STRUCT *CreateStruct, + UINT32 Tsn, + UINT32 Hsn, + UINT32 SeqNumber, + UINT16 AckType, + UINT32 Ack + ) +{ + UINT32 AddedSize; + NULL_CHECK(CreateStruct); + + AddedSize = 0; + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket != NULL || + CreateStruct->CurSubPacket != NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + // update TCG_COM_PACKET and packet lengths + AddedSize = sizeof(TCG_PACKET); + + if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize) > CreateStruct->BufferSize) { + DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize)); + return (TcgResultFailureBufferTooSmall); + } + + CreateStruct->CurPacket = (TCG_PACKET*)(CreateStruct->ComPacket->Payload + SwapBytes32(CreateStruct->ComPacket->LengthBE)); + + CreateStruct->CurPacket->TperSessionNumberBE = SwapBytes32( Tsn ); + CreateStruct->CurPacket->HostSessionNumberBE = SwapBytes32( Hsn ); + CreateStruct->CurPacket->SequenceNumberBE = SwapBytes32( SeqNumber ); + CreateStruct->CurPacket->AckTypeBE = SwapBytes16( AckType ); + CreateStruct->CurPacket->AcknowledgementBE = SwapBytes32( Ack ); + + CreateStruct->CurPacket->LengthBE = 0; + + // update TCG_COM_PACKET Length for next pointer + CreateStruct->ComPacket->LengthBE = SwapBytes32( SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize ); + + return (TcgResultSuccess); +} + +/** + + Starts a new SubPacket in the Data structure. + + @param[in/out] CreateStruct Structure used to start Tcg SubPacket + @param[in] Kind SubPacket kind + +**/ +TCG_RESULT +EFIAPI +TcgStartSubPacket( + TCG_CREATE_STRUCT *CreateStruct, + UINT16 Kind + ) +{ + UINT32 AddedSize; + + NULL_CHECK(CreateStruct); + + AddedSize = 0; + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket == NULL || + CreateStruct->CurSubPacket != NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + AddedSize = sizeof(TCG_SUB_PACKET); + + if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize) > CreateStruct->BufferSize) { + DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize)); + return (TcgResultFailureBufferTooSmall); + } + + CreateStruct->CurSubPacket = (TCG_SUB_PACKET*)(CreateStruct->CurPacket->Payload + SwapBytes32(CreateStruct->CurPacket->LengthBE)); + CreateStruct->CurSubPacket->KindBE = SwapBytes16(Kind); + + // update lengths + CreateStruct->CurSubPacket->LengthBE = 0; + + // update TCG_COM_PACKET and packet lengths + CreateStruct->ComPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize); + CreateStruct->CurPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurPacket->LengthBE) + AddedSize); + + return (TcgResultSuccess); +} + +/** + + Ends the current SubPacket in the Data structure. This function will also perform the 4-byte padding + required for Subpackets. + + @param[in/out] CreateStruct Structure used to end the current Tcg SubPacket + +**/ +TCG_RESULT +EFIAPI +TcgEndSubPacket( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + UINT32 PadSize; + + NULL_CHECK(CreateStruct); + + PadSize = 0; + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket == NULL || + CreateStruct->CurSubPacket == NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + // align to 4-byte boundaries, so shift padding + // pad Size does not apply to subpacket Length + PadSize = TCG_SUBPACKET_ALIGNMENT - (SwapBytes32(CreateStruct->CurSubPacket->LengthBE) & (TCG_SUBPACKET_ALIGNMENT - 1)); + + if (PadSize == TCG_SUBPACKET_ALIGNMENT) { + PadSize = 0; + } + + if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + PadSize) > CreateStruct->BufferSize) { + DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize)); + return (TcgResultFailureBufferTooSmall); + } + + CreateStruct->CurPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurPacket->LengthBE) + PadSize); + CreateStruct->ComPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->ComPacket->LengthBE) + PadSize); + + CreateStruct->CurSubPacket = NULL; + + return (TcgResultSuccess); +} + +/** + + Ends the current Packet in the Data structure. + + @param[in/out] CreateStruct Structure used to end the current Tcg Packet + +**/ +TCG_RESULT +EFIAPI +TcgEndPacket( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + NULL_CHECK(CreateStruct); + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket == NULL || + CreateStruct->CurSubPacket != NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + CreateStruct->CurPacket = NULL; + + return (TcgResultSuccess); +} + +/** + + Ends the ComPacket in the Data structure and ret + + @param [in/out] CreateStruct Structure used to end the Tcg ComPacket + @param [in/out] Size Describes the Size of the entire ComPacket (Header and payload). Filled out by function. + +**/ +TCG_RESULT +EFIAPI +TcgEndComPacket( + TCG_CREATE_STRUCT *CreateStruct, + UINT32 *Size + ) +{ + NULL_CHECK(CreateStruct); + NULL_CHECK(Size); + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket != NULL || + CreateStruct->CurSubPacket != NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + *Size = SwapBytes32(CreateStruct->ComPacket->LengthBE) + sizeof(*CreateStruct->ComPacket); + CreateStruct->ComPacket = NULL; + + return (TcgResultSuccess); +} + +/** + Adds raw Data with optional Header + + @param CreateStruct The create structure. + @param Header The header structure. + @param HeaderSize The header size. + @param Data The data need to add. + @param DataSize The data size. + @param ByteSwapData Whether byte or swap data. + +**/ +TCG_RESULT +TcgAddRawTokenData( + TCG_CREATE_STRUCT *CreateStruct, + const VOID *Header, + UINT8 HeaderSize, + const VOID *Data, + UINT32 DataSize, + BOOLEAN ByteSwapData + ) +{ + UINT32 AddedSize; + UINT8* Dest; + const UINT8* DataBytes; + UINT32 Index; + + AddedSize = 0; + Index = 0; + Dest = NULL; + + NULL_CHECK(CreateStruct); + + if ((HeaderSize != 0 && Header == NULL) || + (DataSize != 0 && Data == NULL) + ) { + DEBUG ((DEBUG_INFO, "HeaderSize=0x%X Header=%p DataSize=0x%X Data=%p\n", HeaderSize, Header, DataSize, Data)); + return (TcgResultFailureNullPointer); + } + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket == NULL || + CreateStruct->CurSubPacket == NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + // verify there is enough Buffer Size + AddedSize = HeaderSize + DataSize; + if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize) > CreateStruct->BufferSize) { + return (TcgResultFailureBufferTooSmall); + } + + // Get a pointer to where the new bytes should go + Dest = CreateStruct->ComPacket->Payload + SwapBytes32(CreateStruct->ComPacket->LengthBE); + + switch (HeaderSize) { + case sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM): + case sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM): + case sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM): + CopyMem(Dest, Header, HeaderSize); + Dest += HeaderSize; + case 0: // no Header is valid + break; + // invalid Header Size + default: + DEBUG ((DEBUG_INFO, "unsupported HeaderSize=%u\n", HeaderSize)); + return TcgResultFailure; + } + + // copy the Data bytes + if (ByteSwapData) { + DataBytes = (const UINT8*)Data; + for (Index = 0; Index < DataSize; Index++) { + Dest[Index] = DataBytes[DataSize - 1 - Index]; + } + } else { + CopyMem(Dest, Data, DataSize); + } + + // Update all the packet sizes + CreateStruct->ComPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize); + CreateStruct->CurPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurPacket->LengthBE) + AddedSize); + CreateStruct->CurSubPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurSubPacket->LengthBE) + AddedSize); + + return (TcgResultSuccess); +} + +/** + + Adds a single raw token byte to the Data structure. + + @param[in/out] CreateStruct Structure used to add the byte + @param[in] Byte Byte to add + +**/ +TCG_RESULT +EFIAPI +TcgAddRawByte( + TCG_CREATE_STRUCT *CreateStruct, + UINT8 Byte + ) +{ + return TcgAddRawTokenData(CreateStruct, NULL, 0, &Byte, 1, FALSE); +} + + +/** + simple tokens - atoms: tiny, short, medium, long and empty atoms. + tiny atom can be a signed or unsigned integer. + short, medium, long can be a signed or unsigned integer OR a complete or non-final byte sequence. + + @param CreateStruct The create structure. + @param Data The data need to add. + @param DataSize The data size. + @param ByteOrInt, Data format is byte or int. + @param SignOrCont sign or cont. + + +**/ +TCG_RESULT +TcgAddAtom( + TCG_CREATE_STRUCT *CreateStruct, + const VOID *Data, + UINT32 DataSize, + UINT8 ByteOrInt, + UINT8 SignOrCont + ) +{ + const UINT8* DataBytes; + TCG_SIMPLE_TOKEN_TINY_ATOM TinyAtom; + TCG_SIMPLE_TOKEN_SHORT_ATOM ShortAtom; + TCG_SIMPLE_TOKEN_MEDIUM_ATOM MediumAtom; + TCG_SIMPLE_TOKEN_LONG_ATOM LongAtom; + + NULL_CHECK(CreateStruct); + + if (DataSize == 0) { + if (ByteOrInt == TCG_ATOM_TYPE_INTEGER) { + DEBUG ((DEBUG_INFO, "0-Size integer not allowed\n")); + return TcgResultFailure; + } + } else { + // if DataSize != 0, Data must be valid + NULL_CHECK(Data); + } + + // encode Data using the shortest possible atom + DataBytes = (const UINT8*)Data; + if ((DataSize == 1) && + (ByteOrInt == TCG_ATOM_TYPE_INTEGER) && + ((SignOrCont != 0 && ((TCG_TOKEN_TINYATOM_SIGNED_MIN_VALUE <= *(INT8*)Data) && (*(INT8*)Data <= TCG_TOKEN_TINYATOM_SIGNED_MAX_VALUE))) || + (SignOrCont == 0 && ((*DataBytes <= TCG_TOKEN_TINYATOM_UNSIGNED_MAX_VALUE)))) + ) { + TinyAtom.TinyAtomBits.IsZero = 0; + TinyAtom.TinyAtomBits.Sign = SignOrCont; + TinyAtom.TinyAtomBits.Data = *DataBytes & TCG_TOKEN_TINYATOM_UNSIGNED_MAX_VALUE; + return TcgAddRawTokenData(CreateStruct, NULL, 0, (UINT8*)&TinyAtom, sizeof(TCG_SIMPLE_TOKEN_TINY_ATOM), FALSE); + } + + if (DataSize <= TCG_TOKEN_SHORTATOM_MAX_BYTE_SIZE) { + ShortAtom.ShortAtomBits.IsOne = 1; + ShortAtom.ShortAtomBits.IsZero = 0; + ShortAtom.ShortAtomBits.ByteOrInt = ByteOrInt; + ShortAtom.ShortAtomBits.SignOrCont = SignOrCont; + ShortAtom.ShortAtomBits.Length = DataSize & 0x0F; + return TcgAddRawTokenData(CreateStruct, &ShortAtom, sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM), Data, DataSize, ByteOrInt == TCG_ATOM_TYPE_INTEGER); + } + + if (DataSize <= TCG_TOKEN_MEDIUMATOM_MAX_BYTE_SIZE) { + MediumAtom.MediumAtomBits.IsOne1 = 1; + MediumAtom.MediumAtomBits.IsOne2 = 1; + MediumAtom.MediumAtomBits.IsZero = 0; + MediumAtom.MediumAtomBits.ByteOrInt = ByteOrInt; + MediumAtom.MediumAtomBits.SignOrCont = SignOrCont; + MediumAtom.MediumAtomBits.LengthLow = DataSize & 0xFF; + MediumAtom.MediumAtomBits.LengthHigh = (DataSize >> TCG_MEDIUM_ATOM_LENGTH_HIGH_SHIFT) & TCG_MEDIUM_ATOM_LENGTH_HIGH_MASK; + return TcgAddRawTokenData(CreateStruct, &MediumAtom, sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM), Data, DataSize, ByteOrInt == TCG_ATOM_TYPE_INTEGER); + } + + LongAtom.LongAtomBits.IsOne1 = 1; + LongAtom.LongAtomBits.IsOne2 = 1; + LongAtom.LongAtomBits.IsOne3 = 1; + LongAtom.LongAtomBits.IsZero = 0; + LongAtom.LongAtomBits.ByteOrInt = ByteOrInt; + LongAtom.LongAtomBits.SignOrCont = SignOrCont; + LongAtom.LongAtomBits.LengthLow = DataSize & 0xFF; + LongAtom.LongAtomBits.LengthMid = (DataSize >> TCG_LONG_ATOM_LENGTH_MID_SHIFT) & 0xFF; + LongAtom.LongAtomBits.LengthHigh = (DataSize >> TCG_LONG_ATOM_LENGTH_HIGH_SHIFT) & 0xFF; + return TcgAddRawTokenData(CreateStruct, &LongAtom, sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM), Data, DataSize, ByteOrInt == TCG_ATOM_TYPE_INTEGER); +} + +/** + + Adds the Data parameter as a byte sequence to the Data structure. + + @param[in/out] CreateStruct Structure used to add the byte sequence + @param[in] Data Byte sequence that will be encoded and copied into Data structure + @param[in] DataSize Length of Data provided + @param[in] Continued TRUE if byte sequence is continued or + FALSE if the Data contains the entire byte sequence to be encoded + +**/ +TCG_RESULT +EFIAPI +TcgAddByteSequence( + TCG_CREATE_STRUCT *CreateStruct, + const VOID *Data, + UINT32 DataSize, + BOOLEAN Continued + ) +{ + return TcgAddAtom(CreateStruct, Data, DataSize, TCG_ATOM_TYPE_BYTE, Continued ? 1 : 0); +} + +/** + + Adds an arbitrary-Length integer to the Data structure. + The integer will be encoded using the shortest possible atom. + + @param[in/out] CreateStruct Structure used to add the integer + @param[in] Data Integer in host byte order that will be encoded and copied into Data structure + @param[in] DataSize Length in bytes of the Data provided + @param[in] SignedInteger TRUE if the integer is signed or FALSE if the integer is unsigned + +**/ +TCG_RESULT +EFIAPI +TcgAddInteger( + TCG_CREATE_STRUCT *CreateStruct, + const VOID *Data, + UINT32 DataSize, + BOOLEAN SignedInteger + ) +{ + const UINT8* DataBytes; + UINT32 ActualDataSize; + BOOLEAN ValueIsNegative; + + NULL_CHECK(CreateStruct); + NULL_CHECK(Data); + + if (DataSize == 0) { + DEBUG ((DEBUG_INFO, "invalid DataSize=0\n")); + return TcgResultFailure; + } + + DataBytes = (const UINT8*)Data; + + // integer should be represented by smallest atom possible + // so calculate real Data Size + ValueIsNegative = SignedInteger && DataBytes[ DataSize - 1 ] & 0x80; + + // assumes native Data is little endian + // shorten Data to smallest byte representation + for (ActualDataSize = DataSize; ActualDataSize > 1; ActualDataSize--) { + // ignore sign extended FFs + if (ValueIsNegative && (DataBytes[ActualDataSize - 1] != 0xFF)) { + break; + } else if (!ValueIsNegative && (DataBytes[ActualDataSize - 1] != 0)) { + // ignore extended 00s + break; + } + } + + return TcgAddAtom(CreateStruct, Data, ActualDataSize, TCG_ATOM_TYPE_INTEGER, SignedInteger ? 1 : 0); +} + +/** + Adds an 8-bit unsigned integer to the Data structure. + + @param[in/out] CreateStruct Structure used to add the integer + @param[in] Value Integer Value to add + +**/ +TCG_RESULT +EFIAPI +TcgAddUINT8( + TCG_CREATE_STRUCT *CreateStruct, + UINT8 Value + ) +{ + return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE); +} + +/** + + Adds a 16-bit unsigned integer to the Data structure. + + @param[in/out] CreateStruct Structure used to add the integer + @param[in] Value Integer Value to add + +**/ +TCG_RESULT +EFIAPI +TcgAddUINT16 ( + TCG_CREATE_STRUCT *CreateStruct, + UINT16 Value + ) +{ + return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE); +} + +/** + + Adds a 32-bit unsigned integer to the Data structure. + + @param[in/out] CreateStruct Structure used to add the integer + @param[in] Value Integer Value to add + +**/ +TCG_RESULT +EFIAPI +TcgAddUINT32( + TCG_CREATE_STRUCT *CreateStruct, + UINT32 Value + ) +{ + return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE); +} + + +/** + + Adds a 64-bit unsigned integer to the Data structure. + + @param[in/out] CreateStruct Structure used to add the integer + @param[in] Value Integer Value to add + +**/ +TCG_RESULT +EFIAPI +TcgAddUINT64( + TCG_CREATE_STRUCT *CreateStruct, + UINT64 Value + ) +{ + return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE); +} + +/** + Adds a BOOLEAN to the Data structure. + + @param[in/out] CreateStruct Structure used to add the integer + @param[in] Value BOOLEAN Value to add + +**/ +TCG_RESULT +EFIAPI +TcgAddBOOLEAN( + TCG_CREATE_STRUCT *CreateStruct, + BOOLEAN Value + ) +{ + return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE); +} + +/** + Add tcg uid info. + + @param [in/out] CreateStruct Structure used to add the integer + @param Uid Input uid info. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddTcgUid( + TCG_CREATE_STRUCT *CreateStruct, + TCG_UID Uid + ) +{ + return TcgAddByteSequence(CreateStruct, &Uid, sizeof(TCG_UID), FALSE); +} + +/** + Add start list. + + @param [in/out] CreateStruct Structure used to add the integer + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddStartList( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + return TcgAddRawByte(CreateStruct, TCG_TOKEN_STARTLIST); +} + +/** + Add end list. + + @param [in/out] CreateStruct Structure used to add the integer + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddEndList( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDLIST); +} + +/** + Add start name. + + @param [in/out] CreateStruct Structure used to add the integer + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddStartName( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + return TcgAddRawByte(CreateStruct, TCG_TOKEN_STARTNAME); +} + +/** + Add end name. + + @param [in/out] CreateStruct Structure used to add the integer + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddEndName( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDNAME); +} + +/** + Add end call. + + @param [in/out] CreateStruct Structure used to add the integer + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddCall( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + return TcgAddRawByte(CreateStruct, TCG_TOKEN_CALL); +} + +/** + Add end of data. + + @param [in/out] CreateStruct Structure used to add the integer + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddEndOfData( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDDATA); +} + +/** + Add end of session. + + @param [in/out] CreateStruct Structure used to add the integer + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddEndOfSession( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDSESSION); +} + +/** + Add start transaction. + + @param [in/out] CreateStruct Structure used to add the integer + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddStartTransaction( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + return TcgAddRawByte(CreateStruct, TCG_TOKEN_STARTTRANSACTION); +} + +/** + Add end transaction. + + @param [in/out] CreateStruct Structure used to add the integer + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgAddEndTransaction( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDTRANSACTION); +} + +/** + Initial the tcg parse structure. + + @param ParseStruct Input parse structure. + @param Buffer Input buffer data. + @param BufferSize Input buffer size. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgInitTcgParseStruct( + TCG_PARSE_STRUCT *ParseStruct, + const VOID *Buffer, + UINT32 BufferSize + ) +{ + UINT32 ComPacketLength; + UINT32 PacketLength; + + NULL_CHECK(ParseStruct); + NULL_CHECK(Buffer); + + if (BufferSize < sizeof(TCG_COM_PACKET)) { + return (TcgResultFailureBufferTooSmall); + } + + ParseStruct->ComPacket = (TCG_COM_PACKET*)Buffer; + + ComPacketLength = SwapBytes32(ParseStruct->ComPacket->LengthBE); + + if ((BufferSize - sizeof(TCG_COM_PACKET)) < ComPacketLength) { + DEBUG ((DEBUG_INFO, "Buffer %u too small for ComPacket %u\n", BufferSize, ComPacketLength)); + return (TcgResultFailureBufferTooSmall); + } + + ParseStruct->BufferSize = BufferSize; + ParseStruct->Buffer = Buffer; + + ParseStruct->CurPacket = NULL; + ParseStruct->CurSubPacket = NULL; + ParseStruct->CurPtr = NULL; + + // if payload > 0, then must have a packet + if (ComPacketLength != 0) { + if (ComPacketLength < sizeof(TCG_PACKET)) { + DEBUG ((DEBUG_INFO, "ComPacket too small for Packet\n")); + return (TcgResultFailureBufferTooSmall); + } + ParseStruct->CurPacket = (TCG_PACKET*)ParseStruct->ComPacket->Payload; + + PacketLength = SwapBytes32(ParseStruct->CurPacket->LengthBE); + + if (PacketLength > 0) { + if (PacketLength < sizeof(TCG_SUB_PACKET)) { + DEBUG ((DEBUG_INFO, "Packet too small for SubPacket\n")); + return (TcgResultFailureBufferTooSmall); + } + + ParseStruct->CurSubPacket = (TCG_SUB_PACKET*)ParseStruct->CurPacket->Payload; + } + } + + //TODO should check for method status list at this point? + + return (TcgResultSuccess); +} + +/** + Get next token info. + + @param ParseStruct Input parse structure info. + @param TcgToken return the tcg token info. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextToken( + TCG_PARSE_STRUCT *ParseStruct, + TCG_TOKEN *TcgToken + ) +{ + const UINT8* EndOfSubPacket; + UINT8* TokenEnd; + UINT8 Hdr; + TCG_SIMPLE_TOKEN_SHORT_ATOM* TmpShort; + const TCG_SIMPLE_TOKEN_MEDIUM_ATOM* TmpMed; + const TCG_SIMPLE_TOKEN_LONG_ATOM* TmpLong; + + NULL_CHECK(ParseStruct); + NULL_CHECK(TcgToken); + + if (ParseStruct->ComPacket == NULL || + ParseStruct->CurPacket == NULL || + ParseStruct->CurSubPacket == NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", ParseStruct->ComPacket, ParseStruct->CurPacket, ParseStruct->CurSubPacket)); + return TcgResultFailureInvalidAction; + } + + // initial call, start at sub packet + if (ParseStruct->CurPtr == NULL) { + ParseStruct->CurPtr = ParseStruct->CurSubPacket->Payload; + } + + EndOfSubPacket = ParseStruct->CurSubPacket->Payload + SwapBytes32(ParseStruct->CurSubPacket->LengthBE); + TokenEnd = NULL; + + // confirmed that subpacket Length falls within end of Buffer and TCG_COM_PACKET, + // so simply need to verify the loop stays within current subpacket + if (ParseStruct->CurPtr >= EndOfSubPacket) { + DEBUG ((DEBUG_INFO, "ParseStruct->CurPtr >= EndOfSubPacket\n")); + return (TcgResultFailureEndBuffer); + } + + Hdr = *ParseStruct->CurPtr; + TcgToken->HdrStart = ParseStruct->CurPtr; + + // Tiny Atom range + if (Hdr <= 0x7F) { + // tiny atom Header is only 1 byte, so don't need to verify Size before cast and access + TcgToken->Type = TcgTokenTypeTinyAtom; + + TokenEnd = TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_TINY_ATOM); + + // verify caller will have enough Size to reference token + if (TokenEnd >= EndOfSubPacket) { + DEBUG ((DEBUG_INFO, "Tiny Atom TokenEnd >= EndOfSubPacket\n")); + return (TcgResultFailureEndBuffer); + } + } + // Short Atom Range + else if (0x80 <= Hdr && Hdr <= 0xBF) { + // short atom Header is only 1 byte, so don't need to verify Size before cast and access + TmpShort = (TCG_SIMPLE_TOKEN_SHORT_ATOM*)(ParseStruct->CurPtr); + TcgToken->Type = TcgTokenTypeShortAtom; + + TokenEnd = (TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM) + TmpShort->ShortAtomBits.Length); + + // verify caller will have enough Size to reference token + if (TokenEnd >= EndOfSubPacket) { + DEBUG ((DEBUG_INFO, "Short Atom TokenEnd >= EndOfSubPacket\n")); + return (TcgResultFailureEndBuffer); + } + } + // Medium Atom Range + else if (0xC0 <= Hdr && Hdr <= 0xDF) { + if (TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM) >= EndOfSubPacket) { + return (TcgResultFailureEndBuffer); + } + TmpMed = (const TCG_SIMPLE_TOKEN_MEDIUM_ATOM*)ParseStruct->CurPtr; + TcgToken->Type = TcgTokenTypeMediumAtom; + TokenEnd = TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM) + + ((TmpMed->MediumAtomBits.LengthHigh << TCG_MEDIUM_ATOM_LENGTH_HIGH_SHIFT) | + TmpMed->MediumAtomBits.LengthLow); + + // verify caller will have enough Size to reference token + if (TokenEnd >= EndOfSubPacket) { + DEBUG ((DEBUG_INFO, "Medium Atom TokenEnd >= EndOfSubPacket\n")); + return (TcgResultFailureEndBuffer); + } + } + // Long Atom Range + else if (0xE0 <= Hdr && Hdr <= 0xE3) { + if (TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM) >= EndOfSubPacket) { + return (TcgResultFailureEndBuffer); + } + TmpLong = (const TCG_SIMPLE_TOKEN_LONG_ATOM*)ParseStruct->CurPtr; + TcgToken->Type = TcgTokenTypeLongAtom; + + TokenEnd = TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM) + + ((TmpLong->LongAtomBits.LengthHigh << TCG_LONG_ATOM_LENGTH_HIGH_SHIFT) | + (TmpLong->LongAtomBits.LengthMid << TCG_LONG_ATOM_LENGTH_MID_SHIFT) | + TmpLong->LongAtomBits.LengthLow); + + // verify caller will have enough Size to reference token + if (TokenEnd >= EndOfSubPacket) { + DEBUG ((DEBUG_INFO, "Long Atom TokenEnd >= EndOfSubPacket\n")); + return (TcgResultFailureEndBuffer); + } + } else { + // single byte tokens + switch (Hdr) { + case TCG_TOKEN_STARTLIST: + TcgToken->Type = TcgTokenTypeStartList; + break; + case TCG_TOKEN_ENDLIST: + TcgToken->Type = TcgTokenTypeEndList; + break; + case TCG_TOKEN_STARTNAME: + TcgToken->Type = TcgTokenTypeStartName; + break; + case TCG_TOKEN_ENDNAME: + TcgToken->Type = TcgTokenTypeEndName; + break; + case TCG_TOKEN_CALL: + TcgToken->Type = TcgTokenTypeCall; + break; + case TCG_TOKEN_ENDDATA: + TcgToken->Type = TcgTokenTypeEndOfData; + break; + case TCG_TOKEN_ENDSESSION: + TcgToken->Type = TcgTokenTypeEndOfSession; + break; + case TCG_TOKEN_STARTTRANSACTION: + TcgToken->Type = TcgTokenTypeStartTransaction; + break; + case TCG_TOKEN_ENDTRANSACTION: + TcgToken->Type = TcgTokenTypeEndTransaction; + break; + case TCG_TOKEN_EMPTY: + TcgToken->Type = TcgTokenTypeEmptyAtom; + break; + default: + DEBUG ((DEBUG_INFO, "WARNING: reserved token Type 0x%02X\n", Hdr)); + TcgToken->Type = TcgTokenTypeReserved; + break; + } + ParseStruct->CurPtr++; + TokenEnd = TcgToken->HdrStart + 1; + } + + // increment curptr for next call + ParseStruct->CurPtr = TokenEnd; + return (TcgResultSuccess); +} + +/** + Get atom info. + + @param TcgToken Input token info. + @param HeaderLength return the header length. + @param DataLength return the data length. + @param ByteOrInt return the atom Type. + @param SignOrCont return the sign or count info. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetAtomInfo( + const TCG_TOKEN *TcgToken, + UINT32 *HeaderLength, + UINT32 *DataLength, + UINT8 *ByteOrInt, + UINT8 *SignOrCont + ) +{ + TCG_SIMPLE_TOKEN_TINY_ATOM* TinyAtom; + TCG_SIMPLE_TOKEN_SHORT_ATOM* ShortAtom; + TCG_SIMPLE_TOKEN_MEDIUM_ATOM* MediumAtom; + TCG_SIMPLE_TOKEN_LONG_ATOM* LongAtom; + + NULL_CHECK(TcgToken); + NULL_CHECK(HeaderLength); + NULL_CHECK(DataLength); + NULL_CHECK(ByteOrInt); + NULL_CHECK(SignOrCont); + + switch (TcgToken->Type) { + case TcgTokenTypeTinyAtom: { + TinyAtom = (TCG_SIMPLE_TOKEN_TINY_ATOM*)TcgToken->HdrStart; + *ByteOrInt = TCG_ATOM_TYPE_INTEGER; + *SignOrCont = TinyAtom->TinyAtomBits.Sign; + *HeaderLength = 0; + *DataLength = 0; // tiny atom must be handled as a special case - Header and Data in the same byte + return TcgResultSuccess; + } + + case TcgTokenTypeShortAtom: { + ShortAtom = (TCG_SIMPLE_TOKEN_SHORT_ATOM*)TcgToken->HdrStart; + *ByteOrInt = ShortAtom->ShortAtomBits.ByteOrInt; + *SignOrCont = ShortAtom->ShortAtomBits.SignOrCont; + *HeaderLength = sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM); + *DataLength = ShortAtom->ShortAtomBits.Length; + return TcgResultSuccess; + } + + case TcgTokenTypeMediumAtom: { + MediumAtom = (TCG_SIMPLE_TOKEN_MEDIUM_ATOM*)TcgToken->HdrStart; + *ByteOrInt = MediumAtom->MediumAtomBits.ByteOrInt; + *SignOrCont = MediumAtom->MediumAtomBits.SignOrCont; + *HeaderLength = sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM); + *DataLength = (MediumAtom->MediumAtomBits.LengthHigh << TCG_MEDIUM_ATOM_LENGTH_HIGH_SHIFT) | MediumAtom->MediumAtomBits.LengthLow; + return TcgResultSuccess; + } + + case TcgTokenTypeLongAtom: { + LongAtom = (TCG_SIMPLE_TOKEN_LONG_ATOM*)TcgToken->HdrStart; + *ByteOrInt = LongAtom->LongAtomBits.ByteOrInt; + *SignOrCont = LongAtom->LongAtomBits.SignOrCont; + *HeaderLength = sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM); + *DataLength = (LongAtom->LongAtomBits.LengthHigh << TCG_LONG_ATOM_LENGTH_HIGH_SHIFT) | + (LongAtom->LongAtomBits.LengthMid << TCG_LONG_ATOM_LENGTH_MID_SHIFT) | + LongAtom->LongAtomBits.LengthLow; + return TcgResultSuccess; + } + + default: + DEBUG ((DEBUG_INFO, "Token Type is not simple atom (%d)\n", TcgToken->Type)); + return (TcgResultFailureInvalidType); + } +} + +/** + Get token specified value. + + @param TcgToken Input token info. + @param Value return the value. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetTokenUINT64( + const TCG_TOKEN *TcgToken, + UINT64 *Value + ) +{ + UINT32 HdrLength; + UINT32 DataLength; + UINT8 ByteOrInt; + UINT8 IsSigned; + TCG_SIMPLE_TOKEN_TINY_ATOM* TmpTiny; + const UINT8* Data; + UINT32 Index; + + NULL_CHECK(TcgToken); + NULL_CHECK(Value); + + Index = 0; + *Value = 0; + ERROR_CHECK(TcgGetAtomInfo(TcgToken, &HdrLength, &DataLength, &ByteOrInt, &IsSigned)); + + if (ByteOrInt != TCG_ATOM_TYPE_INTEGER) { + DEBUG ((DEBUG_INFO, "Invalid Type, expected integer not byte sequence\n")); + return TcgResultFailureInvalidType; + } + + if (IsSigned != 0) { + DEBUG ((DEBUG_INFO, "Integer is signed, expected unsigned\n")); + return TcgResultFailureInvalidType; + } + + // special case for tiny atom + // Header and Data are in one byte, so extract only the Data bitfield + if (TcgToken->Type == TcgTokenTypeTinyAtom) { + TmpTiny = (TCG_SIMPLE_TOKEN_TINY_ATOM*)TcgToken->HdrStart; + *Value = TmpTiny->TinyAtomBits.Data; + return TcgResultSuccess; + } + + if (DataLength > sizeof(UINT64)) { + DEBUG ((DEBUG_INFO, "Length %d is greater than Size of UINT64\n", DataLength)); + return TcgResultFailureBufferTooSmall; + } + + // read big-endian integer + Data = TcgToken->HdrStart + HdrLength; + for (Index = 0; Index < DataLength; Index++) { + *Value = LShiftU64(*Value, 8) | Data[Index]; + } + + return TcgResultSuccess; +} + +/** + Get token byte sequence. + + @param TcgToken Input token info. + @param Length Input the length info. + + @retval Return the value data. + +**/ +UINT8* +EFIAPI +TcgGetTokenByteSequence( + const TCG_TOKEN *TcgToken, + UINT32 *Length + ) +{ + UINT32 HdrLength; + UINT8 ByteOrInt; + UINT8 SignOrCont; + + if (TcgToken == NULL || Length == NULL) { + return NULL; + } + + *Length = 0; + if (TcgGetAtomInfo(TcgToken, &HdrLength, Length, &ByteOrInt, &SignOrCont) != TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "Failed to get simple token info\n")); + return NULL; + } + + if (ByteOrInt != TCG_ATOM_TYPE_BYTE) { + DEBUG ((DEBUG_INFO, "Invalid Type, expected byte sequence not integer\n")); + return NULL; + } + + return (TcgToken->HdrStart + HdrLength); +} + +/** + Get next specify value. + + @param ParseStruct Input parse structure. + @param Value Return value. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextUINT8( + TCG_PARSE_STRUCT *ParseStruct, + UINT8 *Value + ) +{ + UINT64 Value64; + TCG_TOKEN Tok; + + NULL_CHECK(Value); + + ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok)); + ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64)); + + if (Value64 > MAX_UINT8) { + return TcgResultFailure; + } + + *Value = (UINT8)Value64; + + return TcgResultSuccess; +} + +/** + Get next specify value. + + @param ParseStruct Input parse structure. + @param Value Return value. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextUINT16( + TCG_PARSE_STRUCT *ParseStruct, + UINT16 *Value + ) +{ + UINT64 Value64; + TCG_TOKEN Tok; + + NULL_CHECK(Value); + + ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok)); + ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64)); + + if (Value64 > MAX_UINT16) { + return TcgResultFailure; + } + + *Value = (UINT16)Value64; + + return TcgResultSuccess; +} + +/** + Get next specify value. + + @param ParseStruct Input parse structure. + @param Value Return value. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextUINT32( + TCG_PARSE_STRUCT *ParseStruct, + UINT32 *Value + ) +{ + UINT64 Value64; + TCG_TOKEN Tok; + + NULL_CHECK(Value); + + ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok)); + ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64)); + + if (Value64 > MAX_UINT32) { + return TcgResultFailure; + } + + *Value = (UINT32)Value64; + + return TcgResultSuccess; +} + +/** + Get next specify value. + + @param ParseStruct Input parse structure. + @param Value Return value. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextUINT64( + TCG_PARSE_STRUCT *ParseStruct, + UINT64 *Value + ) +{ + TCG_TOKEN Tok; + ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok)); + ERROR_CHECK(TcgGetTokenUINT64(&Tok, Value)); + return TcgResultSuccess; +} + +/** + Get next specify value. + + @param ParseStruct Input parse structure. + @param Value Return value. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextBOOLEAN( + TCG_PARSE_STRUCT *ParseStruct, + BOOLEAN *Value + ) +{ + UINT64 Value64; + TCG_TOKEN Tok; + + NULL_CHECK(Value); + + ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok)); + ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64)); + + if (Value64 > 1) { + return TcgResultFailure; + } + + *Value = (BOOLEAN)Value64; + + return TcgResultSuccess; +} + +/** + Get next tcg uid info. + + @param ParseStruct Input parse structure. + @param Uid Get the uid info. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextTcgUid( + TCG_PARSE_STRUCT *ParseStruct, + TCG_UID *Uid + ) +{ + TCG_TOKEN Tok; + UINT32 Length; + const UINT8* ByteSeq; + + NULL_CHECK(Uid); + + ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok)); + ByteSeq = TcgGetTokenByteSequence(&Tok, &Length); + + if (Length != sizeof(TCG_UID)) { + DEBUG ((DEBUG_INFO, "Token Length %u != TCG_UID Size %u\n", Length, (UINT32)sizeof(TCG_UID))); + return TcgResultFailure; + } + + ASSERT (ByteSeq != NULL); + + CopyMem(Uid, ByteSeq, sizeof(TCG_UID)); + + return TcgResultSuccess; +} + +/** + Get next byte sequence. + + @param ParseStruct Input parse structure. + @param Data return the data. + @param Length return the length. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextByteSequence( + TCG_PARSE_STRUCT *ParseStruct, + const VOID **Data, + UINT32 *Length + ) +{ + TCG_TOKEN Tok; + const UINT8* Bs; + + ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok)); + Bs = TcgGetTokenByteSequence(&Tok, Length); + + if (Bs == NULL) { + return TcgResultFailure; + } + *Data = Bs; + return TcgResultSuccess; +} + +/** + Get next token Type. + + @param ParseStruct Input parse structure. + @param Type Input the type need to check. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextTokenType( + TCG_PARSE_STRUCT *ParseStruct, + TCG_TOKEN_TYPE Type + ) +{ + TCG_TOKEN Tok; + ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok)); + if (Tok.Type != Type) { + DEBUG ((DEBUG_INFO, "expected Type %u, got Type %u\n", Type, Tok.Type)); + return TcgResultFailure; + } + return TcgResultSuccess; +} + +/** + Get next start list. + + @param ParseStruct Input parse structure. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextStartList( + TCG_PARSE_STRUCT *ParseStruct + ) +{ + return TcgGetNextTokenType(ParseStruct, TcgTokenTypeStartList); +} + +/** + Get next end list. + + @param ParseStruct Input parse structure. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextEndList( + TCG_PARSE_STRUCT *ParseStruct + ) +{ + return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndList); +} + +/** + Get next start name. + + @param ParseStruct Input parse structure. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextStartName( + TCG_PARSE_STRUCT *ParseStruct + ) +{ + return TcgGetNextTokenType(ParseStruct, TcgTokenTypeStartName); +} + +/** + Get next end name. + + @param ParseStruct Input parse structure. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextEndName( + TCG_PARSE_STRUCT *ParseStruct + ) +{ + return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndName); +} + +/** + Get next call. + + @param ParseStruct Input parse structure. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextCall( + TCG_PARSE_STRUCT *ParseStruct + ) +{ + return TcgGetNextTokenType(ParseStruct, TcgTokenTypeCall); +} + +/** + Get next end data. + + @param ParseStruct Input parse structure. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextEndOfData( + TCG_PARSE_STRUCT *ParseStruct + ) +{ + return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndOfData); +} + +/** + Get next end of session. + + @param ParseStruct Input parse structure. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextEndOfSession( + TCG_PARSE_STRUCT *ParseStruct + ) +{ + return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndOfSession); +} + +/** + Get next start transaction. + + @param ParseStruct Input parse structure. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextStartTransaction( + TCG_PARSE_STRUCT *ParseStruct + ) +{ + return TcgGetNextTokenType(ParseStruct, TcgTokenTypeStartTransaction); +} + +/** + Get next end transaction. + + @param ParseStruct Input parse structure. + + @retval return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgGetNextEndTransaction( + TCG_PARSE_STRUCT *ParseStruct + ) +{ + return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndTransaction); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf new file mode 100644 index 00000000..3fa57149 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf @@ -0,0 +1,33 @@ +## @file +# This is a Tcg Storage core library. +# +# This module is used to provide API used by Opal password solution. +# +# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = TcgStorageCoreLib + FILE_GUID = ad63b09b-1fc9-4789-af0c-5af8a3fb1f9c + VERSION_STRING = 1.0 + MODULE_TYPE = BASE + LIBRARY_CLASS = TcgStorageCoreLib +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[LibraryClasses] + BaseLib + BaseMemoryLib + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[Sources] + TcgStorageCore.c + TcgStorageUtil.c diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageUtil.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageUtil.c new file mode 100644 index 00000000..5a975057 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageUtil.c @@ -0,0 +1,901 @@ +/** @file + Provide functions to provide tcg storage core spec related functions. + +Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/TcgStorageCoreLib.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> + +typedef struct { + UINT16 FeatureCode; + TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER *Feature; + UINTN FeatureSize; +} TCG_FIND_FEATURE_CTX; + +/** + Returns a human-readable string representing a method status return code. + + @param[in] MethodStatus Method status to translate to a string + + + @retval return the string info. +**/ +CHAR8* +EFIAPI +TcgMethodStatusString( + UINT8 MethodStatus + ) +{ + switch (MethodStatus) { + #define C(status) case TCG_METHOD_STATUS_CODE_ ## status: return #status + C(SUCCESS); + C(NOT_AUTHORIZED); + C(OBSOLETE); + C(SP_BUSY); + C(SP_FAILED); + C(SP_DISABLED); + C(SP_FROZEN); + C(NO_SESSIONS_AVAILABLE); + C(UNIQUENESS_CONFLICT); + C(INSUFFICIENT_SPACE); + C(INSUFFICIENT_ROWS); + C(INVALID_PARAMETER); + C(OBSOLETE2); + C(OBSOLETE3); + C(TPER_MALFUNCTION); + C(TRANSACTION_FAILURE); + C(RESPONSE_OVERFLOW); + C(AUTHORITY_LOCKED_OUT); + C(FAIL); + #undef C + } + return "unknown"; +} + + +/** + adds call token and method Header (invoking id, and method id). + + @param CreateStruct The input create structure. + @param InvokingId Invoking id. + @param MethodId Method id. + +**/ +TCG_RESULT +EFIAPI +TcgStartMethodCall( + TCG_CREATE_STRUCT *CreateStruct, + TCG_UID InvokingId, + TCG_UID MethodId + ) +{ + NULL_CHECK(CreateStruct); + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket == NULL || + CreateStruct->CurSubPacket == NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + ERROR_CHECK(TcgAddCall(CreateStruct)); + ERROR_CHECK(TcgAddTcgUid(CreateStruct, InvokingId)); + ERROR_CHECK(TcgAddTcgUid(CreateStruct, MethodId)); + + return TcgResultSuccess; +} + +/** + Adds START LIST token. + + @param CreateStruct The input create structure. + +**/ +TCG_RESULT +EFIAPI +TcgStartParameters( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + NULL_CHECK(CreateStruct); + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket == NULL || + CreateStruct->CurSubPacket == NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + return TcgAddStartList(CreateStruct); +} + +/** + Adds END LIST token. + + @param CreateStruct The input create structure. + +**/ +TCG_RESULT +EFIAPI +TcgEndParameters( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + NULL_CHECK(CreateStruct); + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket == NULL || + CreateStruct->CurSubPacket == NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + return TcgAddEndList(CreateStruct); +} + +/** + Adds END Data token and method list. + + @param CreateStruct The input create structure. + +**/ +TCG_RESULT +EFIAPI +TcgEndMethodCall( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + NULL_CHECK(CreateStruct); + + if (CreateStruct->ComPacket == NULL || + CreateStruct->CurPacket == NULL || + CreateStruct->CurSubPacket == NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket)); + return (TcgResultFailureInvalidAction); + } + + ERROR_CHECK(TcgAddEndOfData(CreateStruct)); + + ERROR_CHECK(TcgAddStartList(CreateStruct)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x00)); // expected to complete properly + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x00)); // reserved + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x00)); // reserved + ERROR_CHECK(TcgAddEndList(CreateStruct)); + + return TcgResultSuccess; +} + +/** + Retrieves the comID and Extended comID of the ComPacket in the Tcg response. + It is intended to be used to confirm the received Tcg response is intended for user that received it. + + @param [in] ParseStruct Structure used to parse received TCG response. + @param [in/out] ComId comID retrieved from received ComPacket. + @param [in/out] ComIdExtension Extended comID retrieved from received ComPacket + +**/ +TCG_RESULT +EFIAPI +TcgGetComIds( + const TCG_PARSE_STRUCT *ParseStruct, + UINT16 *ComId, + UINT16 *ComIdExtension + ) +{ + NULL_CHECK(ParseStruct); + NULL_CHECK(ComId); + NULL_CHECK(ComIdExtension); + + if (ParseStruct->ComPacket == NULL) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p\n", ParseStruct->ComPacket)); + return TcgResultFailureInvalidAction; + } + + *ComId = SwapBytes16(ParseStruct->ComPacket->ComIDBE); + *ComIdExtension = SwapBytes16(ParseStruct->ComPacket->ComIDExtensionBE); + + return TcgResultSuccess; +} + +/** + Checks if the ComIDs of the response match the expected values. + + @param[in] ParseStruct Structure used to parse received TCG response + @param[in] ExpectedComId Expected comID + @param[in] ExpectedComIdExtension Expected extended comID + +**/ +TCG_RESULT +EFIAPI +TcgCheckComIds( + const TCG_PARSE_STRUCT *ParseStruct, + UINT16 ExpectedComId, + UINT16 ExpectedComIdExtension + ) +{ + UINT16 ParseComId; + UINT16 ParseComIdExtension; + + ERROR_CHECK(TcgGetComIds(ParseStruct, &ParseComId, &ParseComIdExtension)); + if (ParseComId != ExpectedComId || ParseComIdExtension != ExpectedComIdExtension) { + DEBUG ((DEBUG_INFO, "Com ID: Actual 0x%02X Expected 0x%02X\n", ParseComId, ExpectedComId)); + DEBUG ((DEBUG_INFO, "Extended Com ID: 0x%02X Expected 0x%02X\n", ParseComIdExtension, ExpectedComIdExtension)); + return TcgResultFailure; + } + return TcgResultSuccess; +} + +/** + Returns the method status of the current subpacket. Does not affect the current position + in the ComPacket. In other words, it can be called whenever you have a valid SubPacket. + + @param [in/out] ParseStruct Structure used to parse received TCG response + @param [in/out] MethodStatus Method status retrieved of the current SubPacket + +**/ +TCG_RESULT +EFIAPI +TcgGetMethodStatus( + const TCG_PARSE_STRUCT *ParseStruct, + UINT8 *MethodStatus + ) +{ + TCG_PARSE_STRUCT TmpParseStruct; + TCG_TOKEN TcgToken; + UINT8 Reserved1, Reserved2; + + NULL_CHECK(ParseStruct); + NULL_CHECK(MethodStatus); + + if (ParseStruct->ComPacket == NULL || + ParseStruct->CurPacket == NULL || + ParseStruct->CurSubPacket == NULL + ) { + DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", ParseStruct->ComPacket, ParseStruct->CurPacket, ParseStruct->CurSubPacket)); + return TcgResultFailureInvalidAction; + } + + // duplicate ParseStruct, then don't need to "reset" location cur ptr + CopyMem (&TmpParseStruct, ParseStruct, sizeof(TCG_PARSE_STRUCT)); + + // method status list exists after the end method call in the subpacket + // skip tokens until ENDDATA is found + do { + ERROR_CHECK(TcgGetNextToken(&TmpParseStruct, &TcgToken)); + } while (TcgToken.Type != TcgTokenTypeEndOfData); + + // only reach here if enddata is found + // at this point, the curptr is pointing at method status list beginning + ERROR_CHECK(TcgGetNextStartList(&TmpParseStruct)); + ERROR_CHECK(TcgGetNextUINT8(&TmpParseStruct, MethodStatus)); + ERROR_CHECK(TcgGetNextUINT8(&TmpParseStruct, &Reserved1)); + ERROR_CHECK(TcgGetNextUINT8(&TmpParseStruct, &Reserved2)); + ERROR_CHECK(TcgGetNextEndList(&TmpParseStruct)); + + if (Reserved1 != 0) { + DEBUG ((DEBUG_INFO, "Method status reserved1 = 0x%02X (expected 0)\n", Reserved1)); + return TcgResultFailure; + } + + if (Reserved2 != 0) { + DEBUG ((DEBUG_INFO, "Method status reserved2 = 0x%02X (expected 0)\n", Reserved1)); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + Return the toke type string info. + + @param Type Input the type info. + + @retval Return the string for this type. + +**/ +CHAR8* +EFIAPI +TcgTokenTypeString( + TCG_TOKEN_TYPE Type + ) +{ + switch (Type) { + case TcgTokenTypeReserved: return "Reserved"; + case TcgTokenTypeTinyAtom: return "Tiny Atom"; + case TcgTokenTypeShortAtom: return "Short Atom"; + case TcgTokenTypeMediumAtom: return "Medium Atom"; + case TcgTokenTypeLongAtom: return "Long Atom"; + case TcgTokenTypeStartList: return "Start List"; + case TcgTokenTypeEndList: return "End List"; + case TcgTokenTypeStartName: return "Start Name"; + case TcgTokenTypeEndName: return "End Name"; + case TcgTokenTypeCall: return "Call"; + case TcgTokenTypeEndOfData: return "End of Data"; + case TcgTokenTypeEndOfSession: return "End of Session"; + case TcgTokenTypeStartTransaction: return "Start Transaction"; + case TcgTokenTypeEndTransaction: return "End Transaction"; + case TcgTokenTypeEmptyAtom: return "Empty atom"; + } + return "Unknown"; +} + + +/** + + Adds Start Session call to the data structure. This creates the entire ComPacket structure and + returns the size of the entire compacket in the size parameter. + + @param [in/out] CreateStruct Structure used to add the start session call + @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function. + @param [in] ComId ComID for the ComPacket + @param [in] ComIdExtension Extended ComID for the ComPacket + @param [in] HostSessionId Host Session ID + @param [in] SpId Security Provider to start session with + @param [in] Write Write option for start session. TRUE = start session requests write access + @param [in] HostChallengeLength Length of the host challenge. Length should be 0 if hostChallenge is NULL + @param [in] HostChallenge Host challenge for Host Signing Authority. If NULL, then no Host Challenge shall be sent. + @param [in] HostSigningAuthority Host Signing Authority used for start session. If NULL, then no Host Signing Authority shall be sent. + +**/ +TCG_RESULT +EFIAPI +TcgCreateStartSession( + TCG_CREATE_STRUCT *CreateStruct, + UINT32 *Size, + UINT16 ComId, + UINT16 ComIdExtension, + UINT32 HostSessionId, + TCG_UID SpId, + BOOLEAN Write, + UINT32 HostChallengeLength, + const VOID *HostChallenge, + TCG_UID HostSigningAuthority + ) +{ + ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension)); + ERROR_CHECK(TcgStartPacket(CreateStruct, 0x0, 0x0, 0x0, 0x0, 0x0)) ; + ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(CreateStruct, TCG_UID_SMUID, TCG_UID_SM_START_SESSION)); + ERROR_CHECK(TcgStartParameters(CreateStruct)); + ERROR_CHECK(TcgAddUINT32(CreateStruct, HostSessionId)); + ERROR_CHECK(TcgAddTcgUid(CreateStruct, SpId)); + ERROR_CHECK(TcgAddBOOLEAN(CreateStruct, Write)); + + // optional parameters + if (HostChallenge != NULL && HostChallengeLength != 0) { + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x00)); //TODO Create Enum for Method Optional Parameters? + ERROR_CHECK(TcgAddByteSequence(CreateStruct, HostChallenge, HostChallengeLength, FALSE)); + ERROR_CHECK(TcgAddEndName(CreateStruct)); + } + // optional parameters + if (HostSigningAuthority != 0) { + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x03)); //TODO Create Enum for Method Optional Parameters? + ERROR_CHECK(TcgAddTcgUid(CreateStruct, HostSigningAuthority)); + ERROR_CHECK(TcgAddEndName(CreateStruct)); + } + + ERROR_CHECK(TcgEndParameters(CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(CreateStruct)); + ERROR_CHECK(TcgEndPacket(CreateStruct)); + ERROR_CHECK(TcgEndComPacket(CreateStruct, Size)); + + return TcgResultSuccess; +} + +/** + Parses the Sync Session response contained in the parseStruct to retrieve Tper session ID. If the Sync Session response + parameters do not match the comID, extended ComID and host session ID then a failure is returned. + + @param[in/out] ParseStruct Structure used to parse received TCG response, contains Sync Session response. + @param[in] ComId Expected ComID that is compared to actual ComID of response + @param[in] ComIdExtension Expected Extended ComID that is compared to actual Extended ComID of response + @param[in] HostSessionId Expected Host Session ID that is compared to actual Host Session ID of response + @param[in/out] TperSessionId Tper Session ID retrieved from the Sync Session response. + +**/ +TCG_RESULT +EFIAPI +TcgParseSyncSession( + const TCG_PARSE_STRUCT *ParseStruct, + UINT16 ComId, + UINT16 ComIdExtension, + UINT32 HostSessionId, + UINT32 *TperSessionId + ) +{ + UINT8 MethodStatus; + TCG_PARSE_STRUCT TmpParseStruct; + UINT16 ParseComId; + UINT16 ParseExtComId; + TCG_UID InvokingUID; + TCG_UID MethodUID; + UINT32 RecvHostSessionId; + + NULL_CHECK(ParseStruct); + NULL_CHECK(TperSessionId); + + CopyMem (&TmpParseStruct, ParseStruct, sizeof(TCG_PARSE_STRUCT)); + + // verify method status is good + ERROR_CHECK(TcgGetMethodStatus(&TmpParseStruct, &MethodStatus)); + METHOD_STATUS_ERROR_CHECK (MethodStatus, TcgResultFailure); + + // verify comids + ERROR_CHECK(TcgGetComIds(&TmpParseStruct, &ParseComId, &ParseExtComId)); + + if ((ComId != ParseComId) || (ComIdExtension != ParseExtComId)) { + DEBUG ((DEBUG_INFO, "unmatched comid (exp: 0x%X recv: 0x%X) or comid extension (exp: 0x%X recv: 0x%X)\n", ComId, ParseComId, ComIdExtension, ParseExtComId)); + return TcgResultFailure; + } + ERROR_CHECK(TcgGetNextCall(&TmpParseStruct)); + ERROR_CHECK(TcgGetNextTcgUid(&TmpParseStruct, &InvokingUID)); + ERROR_CHECK(TcgGetNextTcgUid(&TmpParseStruct, &MethodUID)); + ERROR_CHECK(TcgGetNextStartList(&TmpParseStruct)); + ERROR_CHECK(TcgGetNextUINT32(&TmpParseStruct, &RecvHostSessionId)); + ERROR_CHECK(TcgGetNextUINT32(&TmpParseStruct, TperSessionId)); + ERROR_CHECK(TcgGetNextEndList(&TmpParseStruct)); + ERROR_CHECK(TcgGetNextEndOfData(&TmpParseStruct)); + + if (InvokingUID != TCG_UID_SMUID) { + DEBUG ((DEBUG_INFO, "Invoking UID did not match UID_SMUID\n")); + return TcgResultFailure; + } + + if (MethodUID != TCG_UID_SM_SYNC_SESSION) { + DEBUG ((DEBUG_INFO, "Method UID did not match UID_SM_SYNC_SESSION\n")); + return TcgResultFailure; + } + + if (HostSessionId != RecvHostSessionId) { + DEBUG ((DEBUG_INFO, "unmatched HostSessionId (exp: 0x%X recv: 0x%X)\n", HostSessionId, RecvHostSessionId)); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + + Creates ComPacket with EndSession. + This assumes a start session has already been opened. + + @param [in/out] CreateStruct Structure used to add Endsession + @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function. + @param [in] ComId ComID for the ComPacket + @param [in] ComIdExtension Extended ComID for the ComPacket + @param [in] HostSessionId Host Session ID for the Packet + @param [in] TpSessionId Tper Session ID for the Packet + +**/ +TCG_RESULT +EFIAPI +TcgCreateEndSession( + TCG_CREATE_STRUCT *CreateStruct, + UINT32 *Size, + UINT16 ComId, + UINT16 ComIdExtension, + UINT32 HostSessionId, + UINT32 TpSessionId + ) +{ + ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension)); + ERROR_CHECK(TcgStartPacket(CreateStruct, TpSessionId, HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0)); + ERROR_CHECK(TcgAddEndOfSession(CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(CreateStruct)); + ERROR_CHECK(TcgEndPacket(CreateStruct)); + ERROR_CHECK(TcgEndComPacket(CreateStruct, Size)); + + return TcgResultSuccess; +} + +/** + Set start method. + + @param CreateStruct Input create structure. + @param Row Input the row info. + @param ColumnNumber the column info. + +**/ +TCG_RESULT +EFIAPI +TcgStartMethodSet( + TCG_CREATE_STRUCT *CreateStruct, + TCG_UID Row, + UINT32 ColumnNumber + ) +{ + ERROR_CHECK(TcgStartMethodCall(CreateStruct, Row, TCG_UID_METHOD_SET)); + ERROR_CHECK(TcgStartParameters(CreateStruct)); + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x01)); // "Values" + ERROR_CHECK(TcgAddStartList(CreateStruct)); + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddUINT32(CreateStruct, ColumnNumber)); + return TcgResultSuccess; +} + +/** + Set end method. + + @param CreateStruct Input create structure. + +**/ +TCG_RESULT +EFIAPI +TcgEndMethodSet( + TCG_CREATE_STRUCT *CreateStruct + ) +{ + ERROR_CHECK(TcgAddEndName(CreateStruct)); + ERROR_CHECK(TcgAddEndList(CreateStruct)); + ERROR_CHECK(TcgAddEndName(CreateStruct)); + ERROR_CHECK(TcgEndParameters(CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(CreateStruct)); + return TcgResultSuccess; +} + +/** + Creates ComPacket with a Method call that sets the PIN column for the row specified. + This assumes a start session has already been opened with the desired SP. + + @param [in/out] CreateStruct Structure used to add method call. + @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function. + @param [in] ComId ComID for the ComPacket + @param [in] ComIdExtension Extended ComID for the ComPacket + @param [in] TperSession Tper Session ID for the Packet + @param [in] HostSession Host Session ID for the Packet + @param [in] SidRow UID of row of current SP to set PIN column + @param [in] Password value of PIN to set + @param [in] PasswordSize Size of PIN + +**/ +TCG_RESULT +EFIAPI +TcgCreateSetCPin( + TCG_CREATE_STRUCT *CreateStruct, + UINT32 *Size, + UINT16 ComId, + UINT16 ComIdExtension, + UINT32 TperSession, + UINT32 HostSession, + TCG_UID SidRow, + const VOID *Password, + UINT32 PasswordSize + ) +{ + // set new SID Password + ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension)); + ERROR_CHECK(TcgStartPacket(CreateStruct, TperSession, HostSession, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodSet(CreateStruct, SidRow, 0x03)); // "PIN" + ERROR_CHECK(TcgAddByteSequence(CreateStruct, Password, PasswordSize, FALSE)); + ERROR_CHECK(TcgEndMethodSet(CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(CreateStruct)); + ERROR_CHECK(TcgEndPacket(CreateStruct)); + ERROR_CHECK(TcgEndComPacket(CreateStruct, Size)); + return TcgResultSuccess; +} + +/** + Creates ComPacket with a Method call that sets the "Enabled" column for the row specified using the value specified. + This assumes a start session has already been opened with the desired SP. + + @param [in/out] CreateStruct Structure used to add method call + @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function. + @param [in] ComId ComID for the ComPacket + @param [in] ComIdExtension Extended ComID for the ComPacket + @param [in] TperSession Tper Session ID for the Packet + @param [in] HostSession Host Session ID for the Packet + @param [in] AuthorityUid Authority UID to modify the "Enabled" column for + @param [in] Enabled Value to set the "Enabled" column to + +**/ +TCG_RESULT +EFIAPI +TcgSetAuthorityEnabled( + TCG_CREATE_STRUCT *CreateStruct, + UINT32 *Size, + UINT16 ComId, + UINT16 ComIdExtension, + UINT32 TperSession, + UINT32 HostSession, + TCG_UID AuthorityUid, + BOOLEAN Enabled + ) +{ + ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension)); + ERROR_CHECK(TcgStartPacket(CreateStruct, TperSession, HostSession, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodSet(CreateStruct, AuthorityUid, 0x05)); // "Enabled" + ERROR_CHECK(TcgAddBOOLEAN(CreateStruct, Enabled)); + ERROR_CHECK(TcgEndMethodSet(CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(CreateStruct)); + ERROR_CHECK(TcgEndPacket(CreateStruct)); + ERROR_CHECK(TcgEndComPacket(CreateStruct, Size)); + return TcgResultSuccess; +} + +/** + Create set ace. + + @param CreateStruct Input create structure. + @param Size size info. + @param ComId ComId info. + @param ComIdExtension ComId extension info. + @param TperSession Tper session data. + @param HostSession Host session data. + @param AceRow Ace row info. + @param Authority1 Authority 1 info. + @param LogicalOperator Logical operator info. + @param Authority2 Authority 2 info. + + @retval Return the action result. + +**/ +TCG_RESULT +EFIAPI +TcgCreateSetAce( + TCG_CREATE_STRUCT *CreateStruct, + UINT32 *Size, + UINT16 ComId, + UINT16 ComIdExtension, + UINT32 TperSession, + UINT32 HostSession, + TCG_UID AceRow, + TCG_UID Authority1, + BOOLEAN LogicalOperator, + TCG_UID Authority2 + ) +{ + UINT8 HalfUidAuthorityObjectRef[4]; + UINT8 HalfUidBooleanAce[4]; + + HalfUidAuthorityObjectRef[0] = 0x0; + HalfUidAuthorityObjectRef[1] = 0x0; + HalfUidAuthorityObjectRef[2] = 0xC; + HalfUidAuthorityObjectRef[3] = 0x5; + + HalfUidBooleanAce[0] = 0x0; + HalfUidBooleanAce[1] = 0x0; + HalfUidBooleanAce[2] = 0x4; + HalfUidBooleanAce[3] = 0xE; + + ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension)); + ERROR_CHECK(TcgStartPacket(CreateStruct, TperSession, HostSession, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodSet(CreateStruct, AceRow, 0x03)); // "BooleanExpr" + ERROR_CHECK(TcgAddStartList(CreateStruct)); + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddByteSequence(CreateStruct, HalfUidAuthorityObjectRef, sizeof(HalfUidAuthorityObjectRef), FALSE)); + ERROR_CHECK(TcgAddTcgUid(CreateStruct, Authority1)); + ERROR_CHECK(TcgAddEndName(CreateStruct)); + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddByteSequence(CreateStruct, HalfUidAuthorityObjectRef, sizeof(HalfUidAuthorityObjectRef), FALSE)); + ERROR_CHECK(TcgAddTcgUid(CreateStruct, Authority2)); + ERROR_CHECK(TcgAddEndName(CreateStruct)); + + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddByteSequence(CreateStruct, HalfUidBooleanAce, sizeof(HalfUidBooleanAce), FALSE)); + ERROR_CHECK(TcgAddBOOLEAN(CreateStruct, LogicalOperator)); + ERROR_CHECK(TcgAddEndName(CreateStruct)); + ERROR_CHECK(TcgAddEndList(CreateStruct)); + ERROR_CHECK(TcgEndMethodSet(CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(CreateStruct)); + ERROR_CHECK(TcgEndPacket(CreateStruct)); + ERROR_CHECK(TcgEndComPacket(CreateStruct, Size)); + return TcgResultSuccess; +} + +/** + Enum level 0 discovery. + + @param DiscoveryHeader Discovery header. + @param Callback Callback function. + @param Context The context for the function. + + @retval return true if the callback return TRUE, else return FALSE. + +**/ +BOOLEAN +EFIAPI +TcgEnumLevel0Discovery( + const TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader, + TCG_LEVEL0_ENUM_CALLBACK Callback, + VOID *Context + ) +{ + UINT32 BytesLeft; + const UINT8 *DiscoveryBufferPtr; + UINT32 FeatLength; + TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER *Feat; + + // + // Total bytes including descriptors but not including the Length field + // + BytesLeft = SwapBytes32(DiscoveryHeader->LengthBE); + + // + // If discovery Header is not valid, exit + // + if (BytesLeft == 0) { + return FALSE; + } + + // + // Subtract the Length of the Header, except the Length field, which is not included + // + BytesLeft -= (sizeof(TCG_LEVEL0_DISCOVERY_HEADER) - sizeof(DiscoveryHeader->LengthBE)); + + // + // Move ptr to first descriptor + // + DiscoveryBufferPtr = (const UINT8*)DiscoveryHeader + sizeof(TCG_LEVEL0_DISCOVERY_HEADER); + + while (BytesLeft > sizeof(TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER)) { + // + // Pointer to beginning of descriptor (including common Header) + // + Feat = (TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER*)DiscoveryBufferPtr; + + FeatLength = Feat->Length + sizeof(TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER); + + // + // Not enough bytes left for Feature descriptor + // + if (BytesLeft < FeatLength) { + break; + } + + // + // Report the Feature to the callback + // + if (Callback(DiscoveryHeader, Feat, FeatLength, Context)) { + return TRUE; + } + + // + // Descriptor Length only describes Data after common Header + // + BytesLeft -= FeatLength; + DiscoveryBufferPtr += FeatLength; + } + + return FALSE; +} + +/** + The callback function for Get Feature function. + + @param DiscoveryHeader Input discovery header. + @param Feature Input Feature. + @param FeatureSize Input Feature size. + @param Context The context. + +**/ +BOOLEAN +EFIAPI +TcgFindFeatureCallback( + const TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader, + TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER *Feature, + UINTN FeatureSize, + VOID *Context + ) +{ + TCG_FIND_FEATURE_CTX* FindCtx; + + FindCtx = (TCG_FIND_FEATURE_CTX*)Context; + if ( SwapBytes16( Feature->FeatureCode_BE ) == FindCtx->FeatureCode ) { + FindCtx->Feature = Feature; + FindCtx->FeatureSize = FeatureSize; + return TRUE; // done enumerating features + } + return FALSE; // continue enumerating +} + +/** + Get Feature code from the header. + + @param DiscoveryHeader The discovery header. + @param FeatureCode return the Feature code. + @param FeatureSize return the Feature size. + + @retval return the Feature code data. +**/ +TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER* +EFIAPI +TcgGetFeature( + const TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader, + UINT16 FeatureCode, + UINTN *FeatureSize + ) +{ + TCG_FIND_FEATURE_CTX FindCtx; + + FindCtx.FeatureCode = FeatureCode; + FindCtx.Feature = NULL; + FindCtx.FeatureSize = 0; + + TcgEnumLevel0Discovery(DiscoveryHeader, TcgFindFeatureCallback, &FindCtx); + if (FeatureSize != NULL) { + *FeatureSize = FindCtx.FeatureSize; + } + return FindCtx.Feature; +} + +/** + Determines if the protocol provided is part of the provided supported protocol list. + + @param[in] ProtocolList Supported protocol list to investigate + @param[in] Protocol Protocol value to determine if supported + + @return TRUE = protocol is supported, FALSE = protocol is not supported +**/ +BOOLEAN +EFIAPI +TcgIsProtocolSupported( + const TCG_SUPPORTED_SECURITY_PROTOCOLS *ProtocolList, + UINT16 Protocol + ) +{ + UINT16 Index; + UINT16 ListLength; + + ListLength = SwapBytes16(ProtocolList->ListLength_BE); + + if (ListLength > sizeof(ProtocolList->List)) { + DEBUG ((DEBUG_INFO, "WARNING: list Length is larger than max allowed Value; truncating\n")); + ListLength = sizeof(ProtocolList->List); + } + + for (Index = 0; Index < ListLength; Index++) { + if (ProtocolList->List[Index] == Protocol) { + return TRUE; + } + } + + return FALSE; +} + +/** + Check whether lock or not. + + @param Discovery + + @retval TRUE if lock, FALSE if not lock. +**/ +BOOLEAN +EFIAPI +TcgIsLocked( + const TCG_LEVEL0_DISCOVERY_HEADER *Discovery + ) +{ + UINTN Size; + TCG_LOCKING_FEATURE_DESCRIPTOR *LockDescriptor; + + Size = 0; + LockDescriptor =(TCG_LOCKING_FEATURE_DESCRIPTOR*) TcgGetFeature (Discovery, TCG_FEATURE_LOCKING, &Size); + + if (LockDescriptor != NULL && Size >= sizeof(*LockDescriptor)) { + DEBUG ((DEBUG_INFO, "locked: %d\n", LockDescriptor->Locked)); + return LockDescriptor->Locked; + } + + // + // Descriptor was not found + // + return FALSE; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c new file mode 100644 index 00000000..d21e8630 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c @@ -0,0 +1,1989 @@ +/** @file + Public API for Opal Core library. + +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/TimerLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/TcgStorageOpalLib.h> + +#include "TcgStorageOpalLibInternal.h" + +#pragma pack(1) +typedef struct { + UINT8 HardwareReset : 1; + UINT8 Reserved : 7; +} TCG_BLOCK_SID_CLEAR_EVENTS; +#pragma pack() + +#define TRUSTED_COMMAND_TIMEOUT_NS ((UINT64) 5 * ((UINT64)(1000000)) * 1000) // 5 seconds +#define BUFFER_SIZE 512 + +/** + The function performs a Trusted Send of a Buffer containing a TCG_COM_PACKET. + + @param[in] Sscp The input Ssc Protocol. + @param[in] MediaId The input Media id info used by Ssc Protocol. + @param[in] SecurityProtocol Security Protocol + @param[in] SpSpecific Security Protocol Specific + @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512 + @param[in] Buffer Address of Data to transfer + @param[in] BufferSize Full Size of Buffer, including space that may be used for padding. + +**/ +TCG_RESULT +OpalTrustedSend( + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp, + UINT32 MediaId, + UINT8 SecurityProtocol, + UINT16 SpSpecific, + UINTN TransferLength, + VOID *Buffer, + UINTN BufferSize + ) +{ + UINTN TransferLength512; + EFI_STATUS Status; + + // + // Round transferLength up to a 512-byte multiple + // + TransferLength512 = (TransferLength + 511) & ~(UINTN)511; + + if (TransferLength512 > BufferSize) { + return TcgResultFailureBufferTooSmall; + } + + ZeroMem((UINT8*)Buffer + TransferLength, TransferLength512 - TransferLength); + + Status = Sscp->SendData( + Sscp, + MediaId, + TRUSTED_COMMAND_TIMEOUT_NS, + SecurityProtocol, + SwapBytes16(SpSpecific), + TransferLength512, + Buffer + ); + + return Status == EFI_SUCCESS ? TcgResultSuccess : TcgResultFailure; +} + +/** + + The function performs a Trusted Receive of a Buffer containing a TCG_COM_PACKET. + + @param[in] Sscp The input Ssc Protocol. + @param[in] MediaId The input Media id info used by Ssc Protocol. + @param[in] SecurityProtocol Security Protocol + @param[in] SpSpecific Security Protocol Specific + @param[in] Buffer Address of Data to transfer + @param[in] BufferSize Full Size of Buffer, including space that may be used for padding. + @param[in] EstimateTimeCost Estimate the time needed. + +**/ +TCG_RESULT +OpalTrustedRecv( + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp, + UINT32 MediaId, + UINT8 SecurityProtocol, + UINT16 SpSpecific, + VOID *Buffer, + UINTN BufferSize, + UINT32 EstimateTimeCost + ) +{ + UINTN TransferLength512; + UINT32 Tries; + TCG_COM_PACKET *ComPacket; + UINT32 Length; + UINT32 OutstandingData; + EFI_STATUS Status; + UINTN TransferSize; + + // + // Round Buffer Size down to a 512-byte multiple + // + TransferLength512 = BufferSize & ~(UINTN)511; + Tries = 0; + ComPacket = NULL; + Length = 0; + OutstandingData = 0; + + if (TransferLength512 < sizeof(TCG_COM_PACKET)) { + DEBUG ((DEBUG_INFO, "transferLength %u too small for ComPacket\n", TransferLength512)); + return TcgResultFailureBufferTooSmall; + } + + // + // Some devices respond with Length = 0 and OutstandingData = 1 to indicate that processing is not yet completed, + // so we need to retry the IF-RECV to get the actual Data. + // See TCG Core Spec v2 Table 45 IF-RECV ComPacket Field Values Summary + // This is an arbitrary number of retries, not from the spec. + // + // if user input estimate time cost(second level) value bigger than 10s, base on user input value to wait. + // Else, Use a max timeout of 10 seconds to wait, 5000 tries * 2ms = 10s + // + if (EstimateTimeCost > 10) { + Tries = EstimateTimeCost * 500; // 500 = 1000 * 1000 / 2000; + } else { + Tries = 5000; + } + while ((Tries--) > 0) { + ZeroMem( Buffer, BufferSize ); + TransferSize = 0; + + Status = Sscp->ReceiveData( + Sscp, + MediaId, + TRUSTED_COMMAND_TIMEOUT_NS, + SecurityProtocol, + SwapBytes16(SpSpecific), + TransferLength512, + Buffer, + &TransferSize + ); + if (EFI_ERROR (Status)) { + return TcgResultFailure; + } + + if (SecurityProtocol != TCG_OPAL_SECURITY_PROTOCOL_1 && SecurityProtocol != TCG_OPAL_SECURITY_PROTOCOL_2) { + return TcgResultSuccess; + } + + if (SpSpecific == TCG_SP_SPECIFIC_PROTOCOL_LEVEL0_DISCOVERY) { + return TcgResultSuccess; + } + + ComPacket = (TCG_COM_PACKET*) Buffer; + Length = SwapBytes32(ComPacket->LengthBE); + OutstandingData = SwapBytes32( ComPacket->OutstandingDataBE ); + + if (Length != 0 && OutstandingData == 0) { + return TcgResultSuccess; + } + + // + // Delay for 2 ms + // + MicroSecondDelay (2000); + } + + return TcgResultFailure; +} + +/** + The function performs send, recv, check comIDs, check method status action. + + @param[in] Session OPAL_SESSION related to this method.. + @param[in] SendSize Transfer Length of Buffer (in bytes) - always a multiple of 512 + @param[in] Buffer Address of Data to transfer + @param[in] BufferSize Full Size of Buffer, including space that may be used for padding. + @param[in] ParseStruct Structure used to parse received TCG response. + @param[in] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + @param[in] EstimateTimeCost Estimate the time need to for the method. +**/ +TCG_RESULT +EFIAPI +OpalPerformMethod ( + OPAL_SESSION *Session, + UINT32 SendSize, + VOID *Buffer, + UINT32 BufferSize, + TCG_PARSE_STRUCT *ParseStruct, + UINT8 *MethodStatus, + UINT32 EstimateTimeCost + ) +{ + NULL_CHECK(Session); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(OpalTrustedSend( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, + Session->OpalBaseComId, + SendSize, + Buffer, + BufferSize + )); + + ERROR_CHECK(OpalTrustedRecv( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, + Session->OpalBaseComId, + Buffer, + BufferSize, + EstimateTimeCost + )); + + ERROR_CHECK(TcgInitTcgParseStruct(ParseStruct, Buffer, BufferSize)); + ERROR_CHECK(TcgCheckComIds(ParseStruct, Session->OpalBaseComId, Session->ComIdExtension)); + ERROR_CHECK(TcgGetMethodStatus(ParseStruct, MethodStatus)); + + return TcgResultSuccess; +} + +/** + Trig the block sid action. + + @param[in] Session OPAL_SESSION related to this method.. + @param[in] HardwareReset Whether need to do hardware reset. + +**/ +TCG_RESULT +EFIAPI +OpalBlockSid( + OPAL_SESSION *Session, + BOOLEAN HardwareReset + ) +{ + UINT8 Buffer[BUFFER_SIZE]; + TCG_BLOCK_SID_CLEAR_EVENTS *ClearEvents; + + NULL_CHECK(Session); + + // + // Set Hardware Reset bit + // + ClearEvents = (TCG_BLOCK_SID_CLEAR_EVENTS *) &Buffer[0]; + + ClearEvents->Reserved = 0; + ClearEvents->HardwareReset = HardwareReset; + + return(OpalTrustedSend( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_2, + TCG_BLOCKSID_COMID, // hardcode ComID 0x0005 + 1, + Buffer, + BUFFER_SIZE + )); +} + +/** + + Reverts device using Admin SP Revert method. + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert. + +**/ +TCG_RESULT +EFIAPI +OpalPsidRevert( + OPAL_SESSION *AdminSpSession + ) +{ + // + // Now that base comid is known, start Session + // we'll attempt to start Session as PSID authority + // verify PSID Authority is defined in ADMIN SP authority table... is this possible? + // + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 Buffer[BUFFER_SIZE]; + UINT8 MethodStatus; + + NULL_CHECK(AdminSpSession); + + // + // Send Revert action on Admin SP + // + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE)); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP, OPAL_ADMIN_SP_REVERT_METHOD)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send Revert Method Call + // + ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus, 0)); + METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure); + + return TcgResultSuccess; +} + +/** + + Reverts device using Admin SP Revert method. + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert. + @param[in] EstimateTimeCost Estimate the time needed. + +**/ +TCG_RESULT +OpalPyrite2PsidRevert( + OPAL_SESSION *AdminSpSession, + UINT32 EstimateTimeCost + ) +{ + // + // Now that base comid is known, start Session + // we'll attempt to start Session as PSID authority + // verify PSID Authority is defined in ADMIN SP authority table... is this possible? + // + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 Buffer[BUFFER_SIZE]; + UINT8 MethodStatus; + + + NULL_CHECK(AdminSpSession); + + // + // Send Revert action on Admin SP + // + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE)); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP, OPAL_ADMIN_SP_REVERT_METHOD)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send Revert Method Call + // + ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus, EstimateTimeCost)); + METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure); + + return TcgResultSuccess; +} + +/** + + The function fills in the provided Buffer with the level 0 discovery Header + of the device specified. + + @param[in] Session OPAL_SESSION data. + @param[in] BufferSize Size of Buffer provided (in bytes) + @param[in] BuffAddress Buffer address to fill with Level 0 Discovery response + +**/ +TCG_RESULT +EFIAPI +OpalRetrieveLevel0DiscoveryHeader( + OPAL_SESSION *Session, + UINTN BufferSize, + VOID *BuffAddress + ) +{ + return (OpalTrustedRecv( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, // SP + TCG_SP_SPECIFIC_PROTOCOL_LEVEL0_DISCOVERY, // SP_Specific + BuffAddress, + BufferSize, + 0 + )); +} + +/** + + The function fills in the provided Buffer with the supported protocol list + of the device specified. + + @param[in] Session OPAL_SESSION data. + @param[in] BufferSize Size of Buffer provided (in bytes) + @param[in] BuffAddress Buffer address to fill with security protocol list + +**/ +TCG_RESULT +EFIAPI +OpalRetrieveSupportedProtocolList( + OPAL_SESSION *Session, + UINTN BufferSize, + VOID *BuffAddress + ) +{ + return (OpalTrustedRecv( + Session->Sscp, + Session->MediaId, + TCG_SECURITY_PROTOCOL_INFO, // SP + TCG_SP_SPECIFIC_PROTOCOL_LIST, // SP_Specific + BuffAddress, + BufferSize, + 0 + )); +} + +/** + Starts a session with a security provider (SP). + + If a session is started successfully, the caller must end the session with OpalEndSession when finished + performing Opal actions. + + @param[in/out] Session OPAL_SESSION to initialize. + @param[in] SpId Security provider ID to start the session with. + @param[in] Write Whether the session should be read-only (FALSE) or read/write (TRUE). + @param[in] HostChallengeLength Length of the host challenge. Length should be 0 if hostChallenge is NULL + @param[in] HostChallenge Host challenge for Host Signing Authority. If NULL, then no Host Challenge will be sent. + @param[in] HostSigningAuthority Host Signing Authority used for start session. If NULL, then no Host Signing Authority will be sent. + @param[in/out] MethodStatus Status of the StartSession method; only valid if TcgResultSuccess is returned. + + @return TcgResultSuccess indicates that the function completed without any internal errors. + The caller must inspect the MethodStatus field to determine whether the method completed successfully. + +**/ +TCG_RESULT +EFIAPI +OpalStartSession( + OPAL_SESSION *Session, + TCG_UID SpId, + BOOLEAN Write, + UINT32 HostChallengeLength, + const VOID *HostChallenge, + TCG_UID HostSigningAuthority, + UINT8 *MethodStatus + ) +{ + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 Buf[BUFFER_SIZE]; + UINT16 ComIdExtension; + UINT32 HostSessionId; + + ComIdExtension = 0; + HostSessionId = 1; + + NULL_CHECK(Session); + NULL_CHECK(MethodStatus); + + Session->ComIdExtension = ComIdExtension; + Session->HostSessionId = HostSessionId; + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateStartSession( + &CreateStruct, + &Size, + Session->OpalBaseComId, + ComIdExtension, + HostSessionId, + SpId, + Write, + HostChallengeLength, + HostChallenge, + HostSigningAuthority + )); + ERROR_CHECK(OpalPerformMethod(Session, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + return TcgResultSuccess; // return early if method failed - user must check MethodStatus + } + + if (TcgParseSyncSession(&ParseStruct, Session->OpalBaseComId, ComIdExtension, HostSessionId, &Session->TperSessionId) != TcgResultSuccess) { + OpalEndSession(Session); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + Close a session opened with OpalStartSession. + + @param[in/out] Session OPAL_SESSION to end. + +**/ +TCG_RESULT +EFIAPI +OpalEndSession( + OPAL_SESSION *Session + ) +{ + UINT8 Buffer[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + UINT32 Size; + TCG_PARSE_STRUCT ParseStruct; + + NULL_CHECK(Session); + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, sizeof(Buffer))); + ERROR_CHECK(TcgCreateEndSession( + &CreateStruct, + &Size, + Session->OpalBaseComId, + Session->ComIdExtension, + Session->HostSessionId, + Session->TperSessionId + )); + + ERROR_CHECK(OpalTrustedSend( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, + Session->OpalBaseComId, + Size, + Buffer, + sizeof(Buffer) + )); + + ERROR_CHECK(OpalTrustedRecv( + Session->Sscp, + Session->MediaId, + TCG_OPAL_SECURITY_PROTOCOL_1, + Session->OpalBaseComId, + Buffer, + sizeof(Buffer), + 0 + )); + + ERROR_CHECK(TcgInitTcgParseStruct(&ParseStruct, Buffer, sizeof(Buffer))); + ERROR_CHECK(TcgCheckComIds(&ParseStruct, Session->OpalBaseComId, Session->ComIdExtension)); + + ERROR_CHECK(TcgGetNextEndOfSession(&ParseStruct)); + return TcgResultSuccess; +} + +/** + + The function retrieves the MSID from the device specified + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert. + @param[in] MsidBufferSize Allocated Buffer Size (in bytes) for MSID allocated by caller + @param[in] Msid Variable Length byte sequence representing MSID of device + @param[in] MsidLength Actual Length of MSID retrieved from device + +**/ +TCG_RESULT +EFIAPI +OpalGetMsid( + OPAL_SESSION *AdminSpSession, + UINT32 MsidBufferSize, + UINT8 *Msid, + UINT32 *MsidLength + ) +{ + // + // now that base comid is known, start Session + // we'll attempt to start Session as PSID authority + // verify PSID Authority is defined in ADMIN SP authority table... is this possible? + // + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 MethodStatus; + UINT32 Col; + const VOID *RecvMsid; + UINT8 Buffer[BUFFER_SIZE]; + + NULL_CHECK(AdminSpSession); + NULL_CHECK(Msid); + NULL_CHECK(MsidLength); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE)); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP_C_PIN_MSID, TCG_UID_METHOD_GET)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgAddStartList(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_PIN_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_PIN_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddEndList(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send MSID Method Call + // + ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus, 0)); + METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure); + + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartName(&ParseStruct)); + ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, &Col)); + ERROR_CHECK(TcgGetNextByteSequence(&ParseStruct, &RecvMsid, MsidLength)); + ERROR_CHECK(TcgGetNextEndName(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct)); + + if (Col != OPAL_ADMIN_SP_PIN_COL) { + DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_ADMIN_SP_PIN_COL)); + return TcgResultFailure; + } + + if (RecvMsid == NULL) { + return TcgResultFailure; + } + + if (MsidBufferSize < *MsidLength) { + DEBUG ((DEBUG_INFO, "Buffer too small MsidBufferSize: %d MsidLength: %d\n", MsidBufferSize, *MsidLength)); + return TcgResultFailureBufferTooSmall; + } + + // + // copy msid into Buffer + // + CopyMem(Msid, RecvMsid, *MsidLength); + return TcgResultSuccess; +} + +/** + + The function retrieves the MSID from the device specified + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_ANYBODY_AUTHORITY + @param[out] ActiveDataRemovalMechanism Active Data Removal Mechanism that the device will use for Revert/RevertSP calls. + +**/ +TCG_RESULT +OpalPyrite2GetActiveDataRemovalMechanism ( + IN OPAL_SESSION *AdminSpSession, + OUT UINT8 *ActiveDataRemovalMechanism + ) +{ + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 MethodStatus; + UINT32 Col; + UINT8 RecvActiveDataRemovalMechanism; + UINT8 Buffer[BUFFER_SIZE]; + + NULL_CHECK(AdminSpSession); + NULL_CHECK(ActiveDataRemovalMechanism); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE)); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP_DATA_REMOVAL_MECHANISM, TCG_UID_METHOD_GET)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgAddStartList(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_ACTIVE_DATA_REMOVAL_MECHANISM_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_ACTIVE_DATA_REMOVAL_MECHANISM_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddEndList(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send Get Active Data Removal Mechanism Method Call + // + ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus, 0)); + METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure); + + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartName(&ParseStruct)); + ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, &Col)); + ERROR_CHECK(TcgGetNextUINT8(&ParseStruct, &RecvActiveDataRemovalMechanism)); + ERROR_CHECK(TcgGetNextEndName(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct)); + + if (Col != OPAL_ADMIN_SP_ACTIVE_DATA_REMOVAL_MECHANISM_COL) { + DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_ADMIN_SP_ACTIVE_DATA_REMOVAL_MECHANISM_COL)); + return TcgResultFailure; + } + + if (RecvActiveDataRemovalMechanism >= ResearvedMechanism) { + return TcgResultFailure; + } + + // + // Copy active data removal mechanism into Buffer + // + CopyMem(ActiveDataRemovalMechanism, &RecvActiveDataRemovalMechanism, sizeof(RecvActiveDataRemovalMechanism)); + return TcgResultSuccess; +} + +/** + + The function calls the Admin SP RevertSP method on the Locking SP. If KeepUserData is True, then the optional parameter + to keep the user Data is set to True, otherwise the optional parameter is not provided. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to revertSP + @param[in] KeepUserData Specifies whether or not to keep user Data when performing RevertSP action. True = keeps user Data. + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalAdminRevert( + OPAL_SESSION *LockingSpSession, + BOOLEAN KeepUserData, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + UINT32 Size; + TCG_PARSE_STRUCT ParseStruct; + TCG_RESULT Ret; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + // + // ReadLocked or WriteLocked must be False (per Opal spec) to guarantee revertSP can keep user Data + // + if (KeepUserData) { + // + // set readlocked and writelocked to false + // + Ret = OpalUpdateGlobalLockingRange( + LockingSpSession, + FALSE, + FALSE, + MethodStatus); + + if (Ret != TcgResultSuccess || *MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + // + // bail out + // + return Ret; + } + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, TCG_UID_THIS_SP, OPAL_LOCKING_SP_REVERTSP_METHOD)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + + if (KeepUserData) { + // + // optional parameter to keep Data after revert + // + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT32(&CreateStruct, 0x060000)); // weird Value but that's what spec says + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, KeepUserData)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + } + + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send RevertSP method call + // + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + // + // Session is immediately ended by device after successful revertsp, so no need to end Session + // + if (*MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + // + // Caller should take ownership again + // + return TcgResultSuccess; + } else { + // + // End Session + // + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); // exit with success on method failure - user must inspect MethodStatus + } + + return TcgResultSuccess; +} + + +/** + + The function calls the Admin SP RevertSP method on the Locking SP. If KeepUserData is True, then the optional parameter + to keep the user Data is set to True, otherwise the optional parameter is not provided. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to revertSP + @param[in] KeepUserData Specifies whether or not to keep user Data when performing RevertSP action. True = keeps user Data. + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + @param[in] EstimateTimeCost Estimate the time needed. + +**/ +TCG_RESULT +OpalPyrite2AdminRevert( + OPAL_SESSION *LockingSpSession, + BOOLEAN KeepUserData, + UINT8 *MethodStatus, + UINT32 EstimateTimeCost + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + UINT32 Size; + TCG_PARSE_STRUCT ParseStruct; + TCG_RESULT Ret; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + // + // ReadLocked or WriteLocked must be False (per Opal spec) to guarantee revertSP can keep user Data + // + if (KeepUserData) { + // + // set readlocked and writelocked to false + // + Ret = OpalUpdateGlobalLockingRange( + LockingSpSession, + FALSE, + FALSE, + MethodStatus); + + if (Ret != TcgResultSuccess || *MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + // + // bail out + // + return Ret; + } + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, TCG_UID_THIS_SP, OPAL_LOCKING_SP_REVERTSP_METHOD)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + + if (KeepUserData) { + // + // optional parameter to keep Data after revert + // + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT32(&CreateStruct, 0x060000)); // weird Value but that's what spec says + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, KeepUserData)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + } + + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send RevertSP method call + // + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, EstimateTimeCost)); + + // + // Session is immediately ended by device after successful revertsp, so no need to end Session + // + if (*MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + // + // Caller should take ownership again + // + return TcgResultSuccess; + } else { + // + // End Session + // + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); // exit with success on method failure - user must inspect MethodStatus + } + + return TcgResultSuccess; +} + +/** + + The function activates the Locking SP. + Once activated, per Opal spec, the ADMIN SP SID PIN is copied over to the ADMIN1 LOCKING SP PIN. + If the Locking SP is already enabled, then TcgResultSuccess is returned and no action occurs. + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY to activate Locking SP + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalActivateLockingSp( + OPAL_SESSION *AdminSpSession, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + UINT32 Size; + TCG_PARSE_STRUCT ParseStruct; + + NULL_CHECK(AdminSpSession); + NULL_CHECK(MethodStatus); + + // + // Call Activate method on Locking SP + // + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_LOCKING_SP, OPAL_ADMIN_SP_ACTIVATE_METHOD)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + // + // Send Activate method call + // + ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); // exit with success on method failure - user must inspect MethodStatus + + return TcgResultSuccess; +} + +/** + + The function sets the PIN column of the specified cpinRowUid (authority) with the newPin Value. + + @param[in/out] Session OPAL_SESSION to set password + @param[in] CpinRowUid UID of row (authority) to update PIN column + @param[in] NewPin New Pin to set for cpinRowUid specified + @param[in] NewPinLength Length in bytes of newPin + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalSetPassword( + OPAL_SESSION *Session, + TCG_UID CpinRowUid, + const VOID *NewPin, + UINT32 NewPinLength, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + + NULL_CHECK(Session); + NULL_CHECK(NewPin); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetCPin( + &CreateStruct, + &Size, + Session->OpalBaseComId, + Session->ComIdExtension, + Session->TperSessionId, + Session->HostSessionId, + CpinRowUid, + NewPin, + NewPinLength + )); + + ERROR_CHECK(OpalPerformMethod(Session, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + // exit with success on method failure - user must inspect MethodStatus + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); + + return TcgResultSuccess; +} + +/** + + The function sets the Enabled column to TRUE for the authorityUid provided and updates the PIN column for the cpinRowUid provided + using the newPin provided. AuthorityUid and cpinRowUid should describe the same authority. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to update + @param[in] CpinRowUid Row UID of C_PIN table of Locking SP to update PIN + @param[in] AuthorityUid UID of Locking SP authority to update Pin column with + @param[in] NewPin New Password used to set Pin column + @param[in] NewPinLength Length in bytes of new password + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalSetLockingSpAuthorityEnabledAndPin( + OPAL_SESSION *LockingSpSession, + TCG_UID CpinRowUid, + TCG_UID AuthorityUid, + const VOID *NewPin, + UINT32 NewPinLength, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + TCG_UID ActiveKey; + TCG_RESULT Ret; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(NewPin); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgSetAuthorityEnabled( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + AuthorityUid, + TRUE)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Send Set Authority error\n")); + return TcgResultFailure; + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + + ERROR_CHECK(TcgCreateSetCPin( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + CpinRowUid, + NewPin, + NewPinLength)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + // + // allow user1 to set global range to unlocked/locked by modifying ACE_Locking_GlobalRange_SetRdLocked/SetWrLocked + // + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetAce( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_SET_RDLOCKED, + OPAL_LOCKING_SP_USER1_AUTHORITY, + TCG_ACE_EXPRESSION_OR, + OPAL_LOCKING_SP_ADMINS_AUTHORITY + )); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Update ACE for RDLOCKED failed\n")); + return TcgResultFailure; + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetAce( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_SET_WRLOCKED, + OPAL_LOCKING_SP_USER1_AUTHORITY, + TCG_ACE_EXPRESSION_OR, + OPAL_LOCKING_SP_ADMINS_AUTHORITY + )); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Update ACE for WRLOCKED failed\n")); + return TcgResultFailure; + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(OpalCreateRetrieveGlobalLockingRangeActiveKey(LockingSpSession, &CreateStruct, &Size)); + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + // + // For Pyrite type SSC, it not supports Active Key. + // So here add check logic before enable it. + // + Ret = OpalParseRetrieveGlobalLockingRangeActiveKey(&ParseStruct, &ActiveKey); + if (Ret == TcgResultSuccess) { + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetAce( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + (ActiveKey == OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY) ? OPAL_LOCKING_SP_ACE_K_AES_256_GLOBALRANGE_GENKEY : OPAL_LOCKING_SP_ACE_K_AES_128_GLOBALRANGE_GENKEY, + OPAL_LOCKING_SP_USER1_AUTHORITY, + TCG_ACE_EXPRESSION_OR, + OPAL_LOCKING_SP_ADMINS_AUTHORITY + )); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Update ACE for GLOBALRANGE_GENKEY failed\n")); + // + // Disable user1 if all permissions are not granted. + // + return TcgResultFailure; + } + } + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgCreateSetAce( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_GET_ALL, + OPAL_LOCKING_SP_USER1_AUTHORITY, + TCG_ACE_EXPRESSION_OR, + OPAL_LOCKING_SP_ADMINS_AUTHORITY + )); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Update ACE for OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_GET_ALL failed\n")); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + + The function sets the Enabled column to FALSE for the USER1 authority. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to disable User1 + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalDisableUser( + OPAL_SESSION *LockingSpSession, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgSetAuthorityEnabled( + &CreateStruct, + &Size, + LockingSpSession->OpalBaseComId, + LockingSpSession->ComIdExtension, + LockingSpSession->TperSessionId, + LockingSpSession->HostSessionId, + OPAL_LOCKING_SP_USER1_AUTHORITY, + FALSE)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + return TcgResultSuccess; +} + +/** + + The function retrieves the active key of the global locking range + and calls the GenKey method on the active key retrieved. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalGlobalLockingRangeGenKey( + OPAL_SESSION *LockingSpSession, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + TCG_UID ActiveKey; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + // + // retrieve the activekey in order to know which globalrange key to generate + // + ERROR_CHECK(OpalCreateRetrieveGlobalLockingRangeActiveKey(LockingSpSession, &CreateStruct, &Size)); + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); + + ERROR_CHECK(OpalParseRetrieveGlobalLockingRangeActiveKey(&ParseStruct, &ActiveKey)); + + // + // call genkey on ActiveKey UID + // + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, ActiveKey, TCG_UID_METHOD_GEN_KEY)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + + return TcgResultSuccess; +} + +/** + + The function updates the ReadLocked and WriteLocked columns of the Global Locking Range. + This function is required for a user1 authority, since a user1 authority shall only have access to ReadLocked and WriteLocked columns + (not ReadLockEnabled and WriteLockEnabled columns). + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key + @param[in] ReadLocked Value to set ReadLocked column for Global Locking Range + @param[in] WriteLocked Value to set WriteLocked column for Global Locking Range + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalUpdateGlobalLockingRange( + OPAL_SESSION *LockingSpSession, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + + // + // set global locking range values + // + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, TCG_UID_METHOD_SET)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x01)); // "Values" + ERROR_CHECK(TcgAddStartList(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x07)); // "ReadLocked" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLocked)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x08)); // "WriteLocked" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLocked)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddEndList(&CreateStruct)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); + + return TcgResultSuccess; +} + +/** + + The function updates the RangeStart, RangeLength, ReadLockedEnabled, WriteLockedEnabled, ReadLocked and WriteLocked columns + of the specified Locking Range. This function requires admin authority of a locking SP session. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key + @param[in] LockingRangeUid Locking range UID to set values + @param[in] RangeStart Value to set RangeStart column for Locking Range + @param[in] RangeLength Value to set RangeLength column for Locking Range + @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range + @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range + @param[in] ReadLocked Value to set ReadLocked column for Locking Range + @param[in] WriteLocked Value to set WriteLocked column for Locking Range + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + +**/ +TCG_RESULT +EFIAPI +OpalSetLockingRange( + OPAL_SESSION *LockingSpSession, + TCG_UID LockingRangeUid, + UINT64 RangeStart, + UINT64 RangeLength, + BOOLEAN ReadLockEnabled, + BOOLEAN WriteLockEnabled, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked, + UINT8 *MethodStatus + ) +{ + UINT8 Buf[BUFFER_SIZE]; + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(MethodStatus); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + + // + // set locking range values + // + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, LockingRangeUid, TCG_UID_METHOD_SET)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x01)); // "Values" + ERROR_CHECK(TcgAddStartList(&CreateStruct)); + + // + // range start and range Length only apply to non-global locking ranges + // + if (LockingRangeUid != OPAL_LOCKING_SP_LOCKING_GLOBALRANGE) { + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x03)); // "RangeStart" + ERROR_CHECK(TcgAddUINT64(&CreateStruct, RangeStart)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x04)); // "RangeLength" + ERROR_CHECK(TcgAddUINT64(&CreateStruct, RangeLength)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + } + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x05)); // "ReadLockEnabled" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLockEnabled)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x06)); // "WriteLockEnabled" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLockEnabled)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x07)); // "ReadLocked" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLocked)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x08)); // "WriteLocked" + ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLocked)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + + ERROR_CHECK(TcgAddEndList(&CreateStruct)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus, 0)); + // Exit with success on method failure - user must inspect MethodStatus + METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); + + return TcgResultSuccess; +} + +/** + + The function populates the CreateStruct with a payload that will retrieve the global locking range active key. + It is intended to be called with a session that is already started with a valid credential. + The function does not send the payload. + + @param[in] Session OPAL_SESSION to populate command for, needs ComId + @param[in/out] CreateStruct Structure to populate with encoded TCG command + @param[in/out] Size Size in bytes of the command created. + +**/ +TCG_RESULT +EFIAPI +OpalCreateRetrieveGlobalLockingRangeActiveKey( + const OPAL_SESSION *Session, + TCG_CREATE_STRUCT *CreateStruct, + UINT32 *Size + ) +{ + NULL_CHECK(Session); + NULL_CHECK(CreateStruct); + NULL_CHECK(Size); + + // Retrieve the activekey in order to know which globalrange key to generate + ERROR_CHECK(TcgStartComPacket(CreateStruct, Session->OpalBaseComId, Session->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(CreateStruct, Session->TperSessionId, Session->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(CreateStruct, OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, TCG_UID_METHOD_GET)); + ERROR_CHECK(TcgStartParameters(CreateStruct)); + ERROR_CHECK(TcgAddStartList(CreateStruct)); + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x0A)); // ActiveKey + ERROR_CHECK(TcgAddEndName(CreateStruct)); + ERROR_CHECK(TcgAddStartName(CreateStruct)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x0A)); + ERROR_CHECK(TcgAddEndName(CreateStruct)); + ERROR_CHECK(TcgAddEndList(CreateStruct)); + ERROR_CHECK(TcgEndParameters(CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(CreateStruct)); + ERROR_CHECK(TcgEndPacket(CreateStruct)); + ERROR_CHECK(TcgEndComPacket(CreateStruct, Size)); + + return TcgResultSuccess; +} + +/** + + The function acquires the activeKey specified for the Global Locking Range from the ParseStruct. + + @param[in] ParseStruct Structure that contains the device's response with the activekey + @param[in/out] ActiveKey The UID of the active key retrieved + +**/ +TCG_RESULT +EFIAPI +OpalParseRetrieveGlobalLockingRangeActiveKey( + TCG_PARSE_STRUCT *ParseStruct, + TCG_UID *ActiveKey + ) +{ + UINT32 ColumnName; + + NULL_CHECK(ParseStruct); + NULL_CHECK(ActiveKey); + + // parse response + ERROR_CHECK(TcgGetNextStartList(ParseStruct)); + ERROR_CHECK(TcgGetNextStartList(ParseStruct)); + ERROR_CHECK(TcgGetNextStartName(ParseStruct)); + ERROR_CHECK(TcgGetNextUINT32(ParseStruct, &ColumnName)); + ERROR_CHECK(TcgGetNextTcgUid(ParseStruct, ActiveKey)); + ERROR_CHECK(TcgGetNextEndName(ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(ParseStruct)); + ERROR_CHECK(TcgGetNextEndOfData(ParseStruct)); + + if (ColumnName != 0x0A) { + DEBUG ((DEBUG_INFO, "Unexpected column name %u (exp 0x0A)\n", ColumnName)); + return TcgResultFailure; + } + + if (*ActiveKey != OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY && *ActiveKey != OPAL_LOCKING_SP_K_AES_128_GLOBALRANGE_KEY) { + DEBUG ((DEBUG_INFO, "Unexpected gen key %u (exp %u or %u)\n", *ActiveKey, OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY, OPAL_LOCKING_SP_K_AES_128_GLOBALRANGE_KEY)); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + + The function retrieves the TryLimit column for the specified rowUid (authority). + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve try limit + @param[in] RowUid Row UID of the Locking SP C_PIN table to retrieve TryLimit column + @param[in/out] TryLimit Value from TryLimit column + +**/ +TCG_RESULT +EFIAPI +OpalGetTryLimit( + OPAL_SESSION *LockingSpSession, + TCG_UID RowUid, + UINT32 *TryLimit + ) +{ + TCG_CREATE_STRUCT CreateStruct; + TCG_PARSE_STRUCT ParseStruct; + UINT32 Size; + UINT8 MethodStatus; + UINT8 Buf[BUFFER_SIZE]; + UINT32 Col; + + NULL_CHECK(LockingSpSession); + NULL_CHECK(TryLimit); + + ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf))); + ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension)); + ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0)); + ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0)); + ERROR_CHECK(TcgStartMethodCall(&CreateStruct, RowUid, TCG_UID_METHOD_GET)); + ERROR_CHECK(TcgStartParameters(&CreateStruct)); + ERROR_CHECK(TcgAddStartList(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddStartName(&CreateStruct)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME)); + ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL)); + ERROR_CHECK(TcgAddEndName(&CreateStruct)); + ERROR_CHECK(TcgAddEndList(&CreateStruct)); + ERROR_CHECK(TcgEndParameters(&CreateStruct)); + ERROR_CHECK(TcgEndMethodCall(&CreateStruct)); + ERROR_CHECK(TcgEndSubPacket(&CreateStruct)); + ERROR_CHECK(TcgEndPacket(&CreateStruct)); + ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size)); + + ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, &MethodStatus, 0)); + METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure); + + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartList(&ParseStruct)); + ERROR_CHECK(TcgGetNextStartName(&ParseStruct)); + ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, &Col)); + ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, TryLimit)); + ERROR_CHECK(TcgGetNextEndName(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndList(&ParseStruct)); + ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct)); + + if (Col != OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL) { + DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL)); + return TcgResultFailure; + } + + return TcgResultSuccess; +} + +/** + + Get the support attribute info. + + @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info. + @param[out] SupportedAttributes Return the support attribute info. + @param[out] OpalBaseComId Return the base com id info. + +**/ +TCG_RESULT +EFIAPI +OpalGetSupportedAttributesInfo( + IN OPAL_SESSION *Session, + OUT OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + OUT UINT16 *OpalBaseComId + ) +{ + UINT8 Buffer[BUFFER_SIZE]; + TCG_SUPPORTED_SECURITY_PROTOCOLS *SupportedProtocols; + TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader; + OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat; + OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat2; + UINTN Size; + UINTN Size2; + + NULL_CHECK(Session); + NULL_CHECK(SupportedAttributes); + NULL_CHECK(OpalBaseComId); + + ZeroMem(Buffer, BUFFER_SIZE); + ASSERT(sizeof(Buffer) >= sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS)); + + // + // Retrieve supported protocols verify security protocol 1 is supported + // + SupportedProtocols = (TCG_SUPPORTED_SECURITY_PROTOCOLS*) Buffer; + + // + // Get list of supported protocols + // + if (OpalRetrieveSupportedProtocolList (Session, sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS), SupportedProtocols) == TcgResultFailure) { + DEBUG ((DEBUG_INFO, "OpalRetrieveSupportedProtocolList failed\n")); + return TcgResultFailure; + } + + SupportedAttributes->Sp1 = TcgIsProtocolSupported (SupportedProtocols, TCG_OPAL_SECURITY_PROTOCOL_1); + SupportedAttributes->Sp2 = TcgIsProtocolSupported (SupportedProtocols, TCG_OPAL_SECURITY_PROTOCOL_2); + SupportedAttributes->SpIeee1667 = TcgIsProtocolSupported (SupportedProtocols, TCG_SECURITY_PROTOCOL_IEEE_1667); + + DEBUG ((DEBUG_INFO, "Supported Protocols: Sp1 %d Sp2: %d SpIeee1667 %d \n", + SupportedAttributes->Sp1, + SupportedAttributes->Sp2, + SupportedAttributes->SpIeee1667 + )); + + // + // Perform level 0 discovery and assign desired feature info to Opal Disk structure + // + ZeroMem (Buffer, BUFFER_SIZE); + if (OpalRetrieveLevel0DiscoveryHeader (Session, BUFFER_SIZE, Buffer) == TcgResultFailure) { + DEBUG ((DEBUG_INFO, "OpalRetrieveLevel0DiscoveryHeader failed\n")); + return TcgResultFailure; + } + + // + // Check for required feature descriptors + // + DiscoveryHeader = (TCG_LEVEL0_DISCOVERY_HEADER*) Buffer; + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_V2_0_0, &Size); + SupportedAttributes->OpalSsc2 = (Feat != NULL); + + *OpalBaseComId = TCG_RESERVED_COMID; + + // + // Check Opal SCC V2 has valid settings for SID C_PIN on revert + // + if (SupportedAttributes->OpalSsc2 && Size >= sizeof (OPAL_SSCV2_FEATURE_DESCRIPTOR)) { + // + // Want opposite polarity b/c Value is greater than a bit, but we only care about non-zero vs zero + // + SupportedAttributes->InitCpinIndicator = (Feat->OpalSscV2.InitialCPINSIDPIN == 0); + SupportedAttributes->CpinUponRevert = (Feat->OpalSscV2.CPINSIDPINRevertBehavior == 0); + DEBUG ((DEBUG_INFO, "Opal SSC V2 InitCpinIndicator %d CpinUponRevert %d \n", + SupportedAttributes->InitCpinIndicator, + SupportedAttributes->CpinUponRevert + )); + *OpalBaseComId = SwapBytes16 (Feat->OpalSscV2.BaseComdIdBE); + } + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_LITE, &Size); + SupportedAttributes->OpalSscLite = (Feat != NULL); + + if (Feat != NULL && Size >= sizeof (OPAL_SSCLITE_FEATURE_DESCRIPTOR)) { + if (*OpalBaseComId == TCG_RESERVED_COMID) { + // + // Pin values used always match up with ComId used + // + *OpalBaseComId = SwapBytes16 (Feat->OpalSscLite.BaseComdIdBE); + SupportedAttributes->InitCpinIndicator = (Feat->OpalSscV2.InitialCPINSIDPIN == 0); + SupportedAttributes->CpinUponRevert = (Feat->OpalSscV2.CPINSIDPINRevertBehavior == 0); + DEBUG ((DEBUG_INFO, "Opal SSC Lite InitCpinIndicator %d CpinUponRevert %d \n", + SupportedAttributes->InitCpinIndicator, + SupportedAttributes->CpinUponRevert + )); + } + } + + // + // For some pyrite 2.0 device, it contains both pyrite 1.0 and 2.0 feature data. + // so here try to get data from pyrite 2.0 feature data first. + // + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_PYRITE_SSC, &Size); + Size2 = 0; + Feat2 = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_PYRITE_SSC_V2_0_0, &Size2); + if (Feat2 != NULL && Size2 >= sizeof (PYRITE_SSCV2_FEATURE_DESCRIPTOR)) { + SupportedAttributes->PyriteSscV2 = TRUE; + if (*OpalBaseComId == TCG_RESERVED_COMID) { + *OpalBaseComId = SwapBytes16 (Feat2->PyriteSscV2.BaseComdIdBE); + SupportedAttributes->InitCpinIndicator = (Feat2->PyriteSscV2.InitialCPINSIDPIN == 0); + SupportedAttributes->CpinUponRevert = (Feat2->PyriteSscV2.CPINSIDPINRevertBehavior == 0); + DEBUG ((DEBUG_INFO, "Pyrite SSC V2 InitCpinIndicator %d CpinUponRevert %d \n", + SupportedAttributes->InitCpinIndicator, + SupportedAttributes->CpinUponRevert + )); + } + } else { + SupportedAttributes->PyriteSsc = (Feat != NULL); + if (Feat != NULL && Size >= sizeof (PYRITE_SSC_FEATURE_DESCRIPTOR)) { + if (*OpalBaseComId == TCG_RESERVED_COMID) { + *OpalBaseComId = SwapBytes16 (Feat->PyriteSsc.BaseComdIdBE); + SupportedAttributes->InitCpinIndicator = (Feat->PyriteSsc.InitialCPINSIDPIN == 0); + SupportedAttributes->CpinUponRevert = (Feat->PyriteSsc.CPINSIDPINRevertBehavior == 0); + DEBUG ((DEBUG_INFO, "Pyrite SSC InitCpinIndicator %d CpinUponRevert %d \n", + SupportedAttributes->InitCpinIndicator, + SupportedAttributes->CpinUponRevert + )); + } + } + } + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_V1_0_0, &Size); + SupportedAttributes->OpalSsc1 = (Feat != NULL); + if (Feat != NULL && Size >= sizeof (OPAL_SSCV1_FEATURE_DESCRIPTOR)) { + if (*OpalBaseComId == TCG_RESERVED_COMID) { + *OpalBaseComId = SwapBytes16 (Feat->OpalSscV1.BaseComdIdBE); + } + } + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_LOCKING, &Size); + if (Feat != NULL && Size >= sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)) { + SupportedAttributes->MediaEncryption = Feat->Locking.MediaEncryption; + DEBUG ((DEBUG_INFO, "SupportedAttributes->MediaEncryption 0x%X \n", SupportedAttributes->MediaEncryption)); + } + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_BLOCK_SID, &Size); + if (Feat != NULL && Size >= sizeof (TCG_BLOCK_SID_FEATURE_DESCRIPTOR)) { + SupportedAttributes->BlockSid = TRUE; + DEBUG ((DEBUG_INFO, "BlockSid Supported!!! Current Status is 0x%X \n", Feat->BlockSid.SIDBlockedState)); + } else { + DEBUG ((DEBUG_INFO, "BlockSid Unsupported!!!")); + } + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_DATA_REMOVAL, &Size); + if (Feat != NULL && Size >= sizeof (DATA_REMOVAL_FEATURE_DESCRIPTOR)) { + SupportedAttributes->DataRemoval = TRUE; + DEBUG ((DEBUG_INFO, "DataRemoval Feature Supported!\n")); + DEBUG ((DEBUG_INFO, "Operation Processing = 0x%x\n", Feat->DataRemoval.OperationProcessing)); + DEBUG ((DEBUG_INFO, "RemovalMechanism = 0x%x\n", Feat->DataRemoval.RemovalMechanism)); + DEBUG ((DEBUG_INFO, "BIT0 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit0, SwapBytes16 (Feat->DataRemoval.TimeBit0))); + DEBUG ((DEBUG_INFO, "BIT1 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit1, SwapBytes16 (Feat->DataRemoval.TimeBit1))); + DEBUG ((DEBUG_INFO, "BIT2 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit2, SwapBytes16 (Feat->DataRemoval.TimeBit2))); + DEBUG ((DEBUG_INFO, "BIT3 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit3, SwapBytes16 (Feat->DataRemoval.TimeBit3))); + DEBUG ((DEBUG_INFO, "BIT4 :: Format = 0x%x, Time = 0x%x\n", Feat->DataRemoval.FormatBit4, SwapBytes16 (Feat->DataRemoval.TimeBit4))); + } + + DEBUG ((DEBUG_INFO, "Base COMID 0x%04X \n", *OpalBaseComId)); + + return TcgResultSuccess; +} + +/** + + Get the support attribute info. + + @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info. + @param[in/out] LockingFeature Return the Locking info. + +**/ +TCG_RESULT +EFIAPI +OpalGetLockingInfo( + OPAL_SESSION *Session, + TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ) +{ + UINT8 Buffer[BUFFER_SIZE]; + TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader; + OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat; + UINTN Size; + + NULL_CHECK(Session); + NULL_CHECK(LockingFeature); + + ZeroMem(Buffer, BUFFER_SIZE); + ASSERT(sizeof(Buffer) >= sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS)); + + if (OpalRetrieveLevel0DiscoveryHeader (Session, BUFFER_SIZE, Buffer) == TcgResultFailure) { + DEBUG ((DEBUG_INFO, "OpalRetrieveLevel0DiscoveryHeader failed\n")); + return TcgResultFailure; + } + DiscoveryHeader = (TCG_LEVEL0_DISCOVERY_HEADER*) Buffer; + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_LOCKING, &Size); + if (Feat != NULL && Size >= sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)) { + CopyMem (LockingFeature, &Feat->Locking, sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)); + } + + return TcgResultSuccess; +} + +/** + + Get the descriptor for the specific feature code. + + @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info. + @param[in] FeatureCode The feature code user request. + @param[in, out] DataSize The data size. + @param[out] Data The data buffer used to save the feature descriptor. + +**/ +TCG_RESULT +OpalGetFeatureDescriptor ( + IN OPAL_SESSION *Session, + IN UINT16 FeatureCode, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + UINT8 Buffer[BUFFER_SIZE]; + TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader; + OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat; + UINTN Size; + + NULL_CHECK(Session); + NULL_CHECK(DataSize); + NULL_CHECK(Data); + + ZeroMem(Buffer, BUFFER_SIZE); + ASSERT(sizeof(Buffer) >= sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS)); + + if (OpalRetrieveLevel0DiscoveryHeader (Session, BUFFER_SIZE, Buffer) == TcgResultFailure) { + DEBUG ((DEBUG_INFO, "OpalRetrieveLevel0DiscoveryHeader failed\n")); + return TcgResultFailure; + } + DiscoveryHeader = (TCG_LEVEL0_DISCOVERY_HEADER*) Buffer; + + Size = 0; + Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, FeatureCode, &Size); + if (Feat != NULL) { + if (Size > *DataSize) { + *DataSize = Size; + return TcgResultFailureBufferTooSmall; + } + + *DataSize = Size; + CopyMem (Data, Feat, Size); + } + + return TcgResultSuccess; +} + +/** + + The function determines whether or not all of the requirements for the Opal Feature (not full specification) + are met by the specified device. + + @param[in] SupportedAttributes Opal device attribute. + +**/ +BOOLEAN +EFIAPI +OpalFeatureSupported( + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes + ) +{ + NULL_CHECK(SupportedAttributes); + + if (SupportedAttributes->Sp1 == 0) { + return FALSE; + } + + if (SupportedAttributes->OpalSscLite == 0 && + SupportedAttributes->OpalSsc1 == 0 && + SupportedAttributes->OpalSsc2 == 0 && + SupportedAttributes->PyriteSsc == 0 && + SupportedAttributes->PyriteSscV2 == 0 + ) { + return FALSE; + } + + return TRUE; +} + +/** + + The function returns whether or not the device is Opal Enabled. + TRUE means that the device is partially or fully locked. + This will perform a Level 0 Discovery and parse the locking feature descriptor + + @param[in] SupportedAttributes Opal device attribute. + @param[in] LockingFeature Opal device locking status. + + +**/ +BOOLEAN +EFIAPI +OpalFeatureEnabled( + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ) +{ + NULL_CHECK(SupportedAttributes); + NULL_CHECK(LockingFeature); + + if (!OpalFeatureSupported (SupportedAttributes)) { + return FALSE; + } + + if (LockingFeature->LockingSupported && LockingFeature->LockingEnabled) { + return TRUE; + } + + return FALSE; +} + +/** + + The function returns whether or not the device is Opal Locked. + TRUE means that the device is partially or fully locked. + This will perform a Level 0 Discovery and parse the locking feature descriptor + + @param[in] SupportedAttributes Opal device attribute. + @param[in] LockingFeature Opal device locking status. + +**/ +BOOLEAN +OpalDeviceLocked( + OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ) +{ + NULL_CHECK(SupportedAttributes); + NULL_CHECK(LockingFeature); + + if (!OpalFeatureEnabled (SupportedAttributes, LockingFeature)) { + return FALSE; + } + + return LockingFeature->Locked; +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf new file mode 100644 index 00000000..9936ba8e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf @@ -0,0 +1,39 @@ +## @file +# This is a Tcg storage Opal library. +# +# This module is used to provide API used by Opal password solution. +# +# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION = 0x00010017 + BASE_NAME = TcgStorageOpalLib + FILE_GUID = F8B56221-FD5D-4215-B578-C3574AD1E253 + VERSION_STRING = 1.0 + MODULE_TYPE = BASE + LIBRARY_CLASS = TcgStorageOpalLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + TcgStorageOpalCore.c + TcgStorageOpalUtil.c + TcgStorageOpalLibInternal.h + +[LibraryClasses] + BaseLib + BaseMemoryLib + PrintLib + DebugLib + TimerLib + TcgStorageCoreLib + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLibInternal.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLibInternal.h new file mode 100644 index 00000000..6b7ab98a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLibInternal.h @@ -0,0 +1,91 @@ +/** @file + Internal functions for Opal Core library. + +Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _OPAL_INTERNAL_H_ +#define _OPAL_INTERNAL_H_ + +#include <Library/TcgStorageOpalLib.h> + + +/** + + The function retrieves the MSID from the device specified + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_ANYBODY_AUTHORITY + @param[out] ActiveDataRemovalMechanism Active Data Removal Mechanism that the device will use for Revert/RevertSP calls. + +**/ +TCG_RESULT +OpalPyrite2GetActiveDataRemovalMechanism ( + OPAL_SESSION *AdminSpSession, + UINT8 *ActiveDataRemovalMechanism + ); + +/** + + Get the support attribute info. + + @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info. + @param[in] FeatureCode The feature code user request. + @param[in, out] DataSize The data size. + @param[out] Data The data buffer used to save the feature descriptor. + +**/ +TCG_RESULT +OpalGetFeatureDescriptor ( + IN OPAL_SESSION *Session, + IN UINT16 FeatureCode, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + Get revert timeout value. + + @param[in] Session The session info for one opal device. + +**/ +UINT32 +GetRevertTimeOut ( + IN OPAL_SESSION *Session + ); + +/** + + Reverts device using Admin SP Revert method. + + @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert. + @param[in] EstimateTimeCost Input the timeout value. + +**/ +TCG_RESULT +OpalPyrite2PsidRevert( + OPAL_SESSION *AdminSpSession, + UINT32 EstimateTimeCost + ); + +/** + + The function calls the Admin SP RevertSP method on the Locking SP. If KeepUserData is True, then the optional parameter + to keep the user Data is set to True, otherwise the optional parameter is not provided. + + @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to revertSP + @param[in] KeepUserData Specifies whether or not to keep user Data when performing RevertSP action. True = keeps user Data. + @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS. + @param[in] EstimateTimeCost Input the timeout value. + +**/ +TCG_RESULT +OpalPyrite2AdminRevert( + OPAL_SESSION *LockingSpSession, + BOOLEAN KeepUserData, + UINT8 *MethodStatus, + UINT32 EstimateTimeCost + ); + +#endif // _OPAL_CORE_H_ diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c new file mode 100644 index 00000000..a3444441 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c @@ -0,0 +1,1123 @@ +/** @file + Public API for Opal Core library. + +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/TcgStorageOpalLib.h> +#include "TcgStorageOpalLibInternal.h" + +#define OPAL_MSID_LENGTH 128 + +/** + Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method. + + @param[in] Session, The session info for one opal device. + @param[in] Psid PSID of device to revert. + @param[in] PsidLength Length of PSID in bytes. + +**/ +TCG_RESULT +EFIAPI +OpalUtilPsidRevert( + OPAL_SESSION *Session, + const VOID *Psid, + UINT32 PsidLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + UINT32 RemovalTimeOut; + + NULL_CHECK(Session); + NULL_CHECK(Psid); + + RemovalTimeOut = GetRevertTimeOut (Session); + DEBUG ((DEBUG_INFO, "OpalUtilPsidRevert: Timeout value = %d\n", RemovalTimeOut)); + + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + PsidLength, + Psid, + OPAL_ADMIN_SP_PSID_AUTHORITY, + &MethodStatus); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalPyrite2PsidRevert(Session, RemovalTimeOut); + if (Ret != TcgResultSuccess) { + // + // If revert was successful, session was already ended by TPer, so only end session on failure + // + OpalEndSession(Session); + } + } + + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + + return Ret; +} + +/** + Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY, + sets the OPAL_UID_ADMIN_SP_C_PIN_SID column with the new password, + and activates the locking SP to copy SID PIN to Admin1 Locking SP PIN + + @param[in] Session, The session info for one opal device. + @param[in] GeneratedSid Generated SID of disk + @param[in] SidLength Length of generatedSid in bytes + @param[in] Password New admin password to set + @param[in] PassLength Length of password in bytes + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetAdminPasswordAsSid( + OPAL_SESSION *Session, + const VOID *GeneratedSid, + UINT32 SidLength, + const VOID *Password, + UINT32 PassLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(GeneratedSid); + NULL_CHECK(Password); + + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + SidLength, + GeneratedSid, + OPAL_ADMIN_SP_SID_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "start session with admin SP as SID authority failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus)); + goto done; + } + + // + // 1. Update SID = new Password + // + Ret = OpalSetPassword( + Session, + OPAL_UID_ADMIN_SP_C_PIN_SID, + Password, + PassLength, + &MethodStatus + ); + + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + OpalEndSession(Session); + DEBUG ((DEBUG_INFO, "set Password failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus)); + goto done; + } + + // + // 2. Activate locking SP + // + Ret = OpalActivateLockingSp(Session, &MethodStatus); + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "activate locking SP failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus)); + goto done; + } + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + + Opens a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + and updates the specified locking range with the provided column values + + @param[in] Session, The session info for one opal device. + @param[in] Password New admin password to set + @param[in] PassLength Length of password in bytes + @param[in] LockingRangeUid Locking range UID to set values + @param[in] RangeStart Value to set RangeStart column for Locking Range + @param[in] RangeLength Value to set RangeLength column for Locking Range + @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range + @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range + @param[in] ReadLocked Value to set ReadLocked column for Locking Range + @param[in] WriteLocked Value to set WriteLocked column for Locking Range + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetOpalLockingRange( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PassLength, + TCG_UID LockingRangeUid, + UINT64 RangeStart, + UINT64 RangeLength, + BOOLEAN ReadLockEnabled, + BOOLEAN WriteLockEnabled, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + + // + // Start session with Locking SP using current admin Password + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PassLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus); + if ((Ret != TcgResultSuccess) || (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS)) { + DEBUG ((DEBUG_INFO, "start session with locking SP failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus)); + goto done; + } + + // + // Enable locking range + // + Ret = OpalSetLockingRange( + Session, + LockingRangeUid, + RangeStart, + RangeLength, + ReadLockEnabled, + WriteLockEnabled, + ReadLocked, + WriteLocked, + &MethodStatus); + + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "set locking range failed: Ret=%d MethodStatus=0x%x\n", Ret, MethodStatus)); + } + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY, + sets OPAL_UID_ADMIN_SP_C_PIN_SID with the new password, + and sets OPAL_LOCKING_SP_C_PIN_ADMIN1 with the new password. + + @param[in] Session, The session info for one opal device. + @param[in] OldPassword Current admin password + @param[in] OldPasswordLength Length of current admin password in bytes + @param[in] NewPassword New admin password to set + @param[in] NewPasswordLength Length of new password in bytes + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetAdminPassword( + OPAL_SESSION *Session, + const VOID *OldPassword, + UINT32 OldPasswordLength, + const VOID *NewPassword, + UINT32 NewPasswordLength + ) +{ + TCG_RESULT Ret; + UINT8 MethodStatus; + + NULL_CHECK(Session); + NULL_CHECK(OldPassword); + NULL_CHECK(NewPassword); + + // + // Unknown ownership + // + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + OldPasswordLength, + OldPassword, + OPAL_ADMIN_SP_SID_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "start session with admin SP using old Password failed\n")); + goto done; + } + + // + // Update SID = new pw + // + Ret = OpalSetPassword(Session, OPAL_UID_ADMIN_SP_C_PIN_SID, NewPassword, NewPasswordLength, &MethodStatus); + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "set new admin SP Password failed\n")); + goto done; + } + + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + OldPasswordLength, + OldPassword, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "start session with locking SP using old Password failed\n")); + goto done; + } + + // + // Update admin locking SP to new pw + // + Ret = OpalSetPassword(Session, OPAL_LOCKING_SP_C_PIN_ADMIN1, NewPassword, NewPasswordLength, &MethodStatus); + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "set new locking SP Password failed\n")); + goto done; + } + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and sets the User1 SP authority to enabled and sets the User1 password. + + @param[in] Session, The session info for one opal device. + @param[in] OldPassword Current admin password + @param[in] OldPasswordLength Length of current admin password in bytes + @param[in] NewPassword New admin password to set + @param[in] NewPasswordLength Length of new password in bytes + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetUserPassword( + OPAL_SESSION *Session, + const VOID *OldPassword, + UINT32 OldPasswordLength, + const VOID *NewPassword, + UINT32 NewPasswordLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(OldPassword); + NULL_CHECK(NewPassword); + + // + // See if updating user1 authority + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + OldPasswordLength, + OldPassword, + OPAL_LOCKING_SP_USER1_AUTHORITY, + &MethodStatus + ); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalSetPassword( + Session, + OPAL_LOCKING_SP_C_PIN_USER1, + NewPassword, + NewPasswordLength, + &MethodStatus + ); + OpalEndSession(Session); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + return Ret; + } + } + + // + // Setting Password for first time or setting Password as admin + // + + // + // Start session with Locking SP using current admin Password + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + OldPasswordLength, + OldPassword, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "StartSession with locking SP as admin1 authority failed\n")); + goto done; + } + + // + // Enable User1 and set its PIN + // + Ret = OpalSetLockingSpAuthorityEnabledAndPin( + Session, + OPAL_LOCKING_SP_C_PIN_USER1, + OPAL_LOCKING_SP_USER1_AUTHORITY, + NewPassword, + NewPasswordLength, + &MethodStatus + ); + OpalEndSession(Session); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "OpalSetLockingSpAuthorityEnabledAndPin failed\n")); + goto done; + } + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + Verify whether user input the correct password. + + @param[in] Session, The session info for one opal device. + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[in/out] HostSigningAuthority Use the Host signing authority type. + +**/ +TCG_RESULT +EFIAPI +OpalUtilVerifyPassword ( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + TCG_UID HostSigningAuthority + ) +{ + TCG_RESULT Ret; + UINT8 MethodStatus; + + NULL_CHECK(Session); + NULL_CHECK(Password); + + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + HostSigningAuthority, + &MethodStatus); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + OpalEndSession(Session); + return TcgResultSuccess; + } + + return TcgResultFailure; +} + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY + and generates a new global locking range key to erase the Data. + + @param[in] Session, The session info for one opal device. + @param[in] Password Admin or user password + @param[in] PasswordLength Length of password in bytes + @param[in/out] PasswordFailed indicates if password failed (start session didn't work) + +**/ +TCG_RESULT +EFIAPI +OpalUtilSecureErase( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN *PasswordFailed + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + NULL_CHECK(PasswordFailed); + + // + // Try to generate a new key with admin1 + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalGlobalLockingRangeGenKey(Session, &MethodStatus); + *PasswordFailed = FALSE; + OpalEndSession(Session); + } else { + // + // Try to generate a new key with user1 + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_USER1_AUTHORITY, + &MethodStatus + ); + + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalGlobalLockingRangeGenKey(Session, &MethodStatus); + *PasswordFailed = FALSE; + OpalEndSession(Session); + } else { + *PasswordFailed = TRUE; + } + } + + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority. + + @param[in] Session, The session info for one opal device. + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[in/out] PasswordFailed indicates if password failed (start session didn't work) + +**/ +TCG_RESULT +EFIAPI +OpalUtilDisableUser( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN *PasswordFailed + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + NULL_CHECK(PasswordFailed); + + // + // Start session with Locking SP using current admin Password + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "StartSession with Locking SP as Admin1 failed\n")); + *PasswordFailed = TRUE; + goto done; + } + + *PasswordFailed = FALSE; + Ret = OpalDisableUser(Session, &MethodStatus); + OpalEndSession(Session); + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method. + + @param[in] Session, The session info for one opal device. + @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it + @param[in] Password Admin password + @param[in] PasswordLength Length of password in bytes + @param[in/out] PasswordFailed indicates if password failed (start session didn't work) + @param[in] Msid Msid info. + @param[in] MsidLength Msid data length. + +**/ +TCG_RESULT +EFIAPI +OpalUtilRevert( + OPAL_SESSION *Session, + BOOLEAN KeepUserData, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN *PasswordFailed, + UINT8 *Msid, + UINT32 MsidLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + UINT32 RemovalTimeOut; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(Password); + NULL_CHECK(PasswordFailed); + + RemovalTimeOut = GetRevertTimeOut (Session); + DEBUG ((DEBUG_INFO, "OpalUtilRevert: Timeout value = %d\n", RemovalTimeOut)); + + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "error starting session: Ret=%d, MethodStatus=%u\n", Ret, MethodStatus)); + *PasswordFailed = TRUE; + goto done; + } + + *PasswordFailed = FALSE; + // + // Try to revert with admin1 + // + Ret = OpalPyrite2AdminRevert(Session, KeepUserData, &MethodStatus, RemovalTimeOut); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + // + // Device ends the session on successful revert, so only call OpalEndSession when fail. + // + DEBUG ((DEBUG_INFO, "OpalAdminRevert as admin failed\n")); + OpalEndSession(Session); + } + + Ret = OpalUtilSetSIDtoMSID (Session, Password, PasswordLength, Msid, MsidLength); + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; +} + +/** + After revert success, set SID to MSID. + + @param Session, The session info for one opal device. + @param Password, Input password info. + @param PasswordLength, Input password length. + @param Msid Msid info. + @param MsidLength Msid data length. + +**/ +TCG_RESULT +EFIAPI +OpalUtilSetSIDtoMSID ( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + UINT8 *Msid, + UINT32 MsidLength + ) +{ + TCG_RESULT Ret; + UINT8 MethodStatus; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(Password); + + // + // Start session with admin sp to update SID to MSID + // + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + PasswordLength, + Password, + OPAL_ADMIN_SP_SID_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + goto done; + } + + // + // Update SID pin + // + Ret = OpalSetPassword(Session, OPAL_UID_ADMIN_SP_C_PIN_SID, Msid, MsidLength, &MethodStatus); + OpalEndSession(Session); + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + + return Ret; +} + +/** + Update global locking range. + + @param Session, The session info for one opal device. + @param Password, Input password info. + @param PasswordLength, Input password length. + @param ReadLocked, Read lock info. + @param WriteLocked write lock info. + +**/ +TCG_RESULT +EFIAPI +OpalUtilUpdateGlobalLockingRange( + OPAL_SESSION *Session, + const VOID *Password, + UINT32 PasswordLength, + BOOLEAN ReadLocked, + BOOLEAN WriteLocked + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Password); + + // + // Try to start session with Locking SP as admin1 authority + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_ADMIN1_AUTHORITY, + &MethodStatus + ); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = OpalUpdateGlobalLockingRange( + Session, + ReadLocked, + WriteLocked, + &MethodStatus + ); + OpalEndSession(Session); + if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) { + goto done; + } + } + + if (MethodStatus == TCG_METHOD_STATUS_CODE_AUTHORITY_LOCKED_OUT) { + DEBUG ((DEBUG_INFO, "unlock as admin failed with AUTHORITY_LOCKED_OUT\n")); + } + + // + // Try user1 authority + // + Ret = OpalStartSession( + Session, + OPAL_UID_LOCKING_SP, + TRUE, + PasswordLength, + Password, + OPAL_LOCKING_SP_USER1_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "StartSession with Locking SP as User1 failed\n")); + goto done; + } + + Ret = OpalUpdateGlobalLockingRange(Session, ReadLocked, WriteLocked, &MethodStatus); + OpalEndSession(Session); + +done: + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + if (MethodStatus == TCG_METHOD_STATUS_CODE_AUTHORITY_LOCKED_OUT) { + // + // Caller need to know this special error, but return status not has type for it. + // so here use TcgResultFailureInvalidType as an replacement. + // + Ret = TcgResultFailureInvalidType; + } else { + Ret = TcgResultFailure; + } + } + return Ret; +} + +/** + Update global locking range. + + @param Session, The session info for one opal device. + @param Msid, The data buffer to save Msid info. + @param MsidBufferLength, The data buffer length for Msid. + @param MsidLength, The actual data length for Msid. + +**/ +TCG_RESULT +EFIAPI +OpalUtilGetMsid( + OPAL_SESSION *Session, + UINT8 *Msid, + UINT32 MsidBufferLength, + UINT32 *MsidLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(MsidLength); + + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + 0, + NULL, + TCG_UID_NULL, + &MethodStatus + ); + if ((Ret == TcgResultSuccess) && (MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS)) { + Ret = OpalGetMsid (Session, MsidBufferLength, Msid, MsidLength); + OpalEndSession (Session); + } + + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + + return Ret; +} + +/** + + The function determines who owns the device by attempting to start a session with different credentials. + If the SID PIN matches the MSID PIN, the no one owns the device. + If the SID PIN matches the ourSidPin, then "Us" owns the device. Otherwise it is unknown. + + + @param[in] Session The session info for one opal device. + @param Msid, The Msid info. + @param MsidLength, The data length for Msid. + +**/ +OPAL_OWNER_SHIP +EFIAPI +OpalUtilDetermineOwnership( + OPAL_SESSION *Session, + UINT8 *Msid, + UINT32 MsidLength + ) +{ + UINT8 MethodStatus; + TCG_RESULT Ret; + OPAL_OWNER_SHIP Owner; + + if ((Session == NULL) || (Msid == NULL)) { + return OpalOwnershipUnknown; + } + + Owner = OpalOwnershipUnknown; + // + // Start Session as SID_UID with ADMIN_SP using MSID PIN + // + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + MsidLength, + Msid, + OPAL_ADMIN_SP_SID_AUTHORITY, + &MethodStatus); + if ((Ret == TcgResultSuccess) && (MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS)) { + // + // now we know that SID PIN == MSID PIN + // + Owner = OpalOwnershipNobody; + + OpalEndSession(Session); + } + + return Owner; +} + +/** + + The function returns if admin password exists. + + @param[in] OwnerShip The owner ship of the opal device. + @param[in] LockingFeature The locking info of the opal device. + + @retval TRUE Admin password existed. + @retval FALSE Admin password not existed. + +**/ +BOOLEAN +EFIAPI +OpalUtilAdminPasswordExists( + IN UINT16 OwnerShip, + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature + ) +{ + NULL_CHECK(LockingFeature); + + // if it is Unknown who owns the device + // then someone has set password previously through our UI + // because the SID would no longer match the generated SID (ownership us) + // or someone has set password using 3rd party software + + // + // Locking sp enabled is checked b/c it must be enabled to change the PIN of the Admin1. + // + return (OwnerShip == OpalOwnershipUnknown && LockingFeature->LockingEnabled); +} + +/** + Get Active Data Removal Mechanism Value. + + @param[in] Session The session info for one opal device. + @param[in] GeneratedSid Generated SID of disk + @param[in] SidLength Length of generatedSid in bytes + @param[out] ActiveDataRemovalMechanism Return the active data removal mechanism. + +**/ +TCG_RESULT +EFIAPI +OpalUtilGetActiveDataRemovalMechanism ( + OPAL_SESSION *Session, + const VOID *GeneratedSid, + UINT32 SidLength, + UINT8 *ActiveDataRemovalMechanism + ) +{ + TCG_RESULT Ret; + UINT8 MethodStatus; + + NULL_CHECK(Session); + NULL_CHECK(GeneratedSid); + NULL_CHECK(ActiveDataRemovalMechanism); + + Ret = OpalStartSession( + Session, + OPAL_UID_ADMIN_SP, + TRUE, + SidLength, + GeneratedSid, + OPAL_ADMIN_SP_ANYBODY_AUTHORITY, + &MethodStatus + ); + if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + DEBUG ((DEBUG_INFO, "Start session with admin SP as SID authority failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus)); + if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) { + Ret = TcgResultFailure; + } + return Ret; + } + + Ret = OpalPyrite2GetActiveDataRemovalMechanism ( + Session, + ActiveDataRemovalMechanism + ); + + if (Ret != TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "Pyrite2 Get Active Data Removal Mechanism failed: Ret=%d\n", Ret)); + } + + OpalEndSession(Session); + + return Ret; +} + +/** + Calculate the estimated time. + + @param[in] IsMinute Whether the input time value is minute type or second type. + @param[in] Time The input time value. + +**/ +UINT32 +CalculateDataRemovalTime ( + IN BOOLEAN IsMinute, + IN UINT16 Time + ) +{ + if (IsMinute) { + return Time * 2 * 60; + } else { + return Time * 2; + } +} + +/** + Return the estimated time for specific type. + + @param[in] Index The input data removal type. + @param[in] Descriptor DATA_REMOVAL_FEATURE_DESCRIPTOR + +**/ +UINT32 +GetDataRemovalTime ( + IN UINT8 Index, + IN DATA_REMOVAL_FEATURE_DESCRIPTOR *Descriptor + ) +{ + switch (Index) { + case OverwriteDataErase: + return CalculateDataRemovalTime (Descriptor->FormatBit0, SwapBytes16 (Descriptor->TimeBit0)); + + case BlockErase: + return CalculateDataRemovalTime (Descriptor->FormatBit1, SwapBytes16 (Descriptor->TimeBit1)); + + case CryptoErase: + return CalculateDataRemovalTime (Descriptor->FormatBit2, SwapBytes16 (Descriptor->TimeBit2)); + + case Unmap: + return CalculateDataRemovalTime (Descriptor->FormatBit3, SwapBytes16 (Descriptor->TimeBit3)); + + case ResetWritePointers: + return CalculateDataRemovalTime (Descriptor->FormatBit4, SwapBytes16 (Descriptor->TimeBit4)); + + case VendorSpecificErase: + return CalculateDataRemovalTime (Descriptor->FormatBit5, SwapBytes16 (Descriptor->TimeBit5)); + + default: + return 0; + } +} + +/** + Get the supported Data Removal Mechanism list. + + @param[in] Session The session info for one opal device. + @param[out] RemovalMechanismLists Return the supported data removal mechanism lists. + +**/ +TCG_RESULT +EFIAPI +OpalUtilGetDataRemovalMechanismLists ( + IN OPAL_SESSION *Session, + OUT UINT32 *RemovalMechanismLists + ) +{ + TCG_RESULT Ret; + UINTN DataSize; + DATA_REMOVAL_FEATURE_DESCRIPTOR Descriptor; + UINT8 Index; + UINT8 BitValue; + + NULL_CHECK(Session); + NULL_CHECK(RemovalMechanismLists); + + DataSize = sizeof (Descriptor); + Ret = OpalGetFeatureDescriptor (Session, TCG_FEATURE_DATA_REMOVAL, &DataSize, &Descriptor); + if (Ret != TcgResultSuccess) { + return TcgResultFailure; + } + + ASSERT (Descriptor.RemovalMechanism != 0); + + for (Index = 0; Index < ResearvedMechanism; Index ++) { + BitValue = (BOOLEAN) BitFieldRead8 (Descriptor.RemovalMechanism, Index, Index); + + if (BitValue == 0) { + RemovalMechanismLists[Index] = 0; + } else { + RemovalMechanismLists[Index] = GetDataRemovalTime (Index, &Descriptor); + } + } + + return TcgResultSuccess; +} + +/** + Get revert timeout value. + + @param[in] Session The session info for one opal device. + +**/ +UINT32 +GetRevertTimeOut ( + IN OPAL_SESSION *Session + ) +{ + TCG_RESULT TcgResult; + OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes; + UINT16 BaseComId; + UINT32 MsidLength; + UINT8 Msid[OPAL_MSID_LENGTH]; + UINT32 RemovalMechanishLists[ResearvedMechanism]; + UINT8 ActiveDataRemovalMechanism; + + TcgResult = OpalGetSupportedAttributesInfo (Session, &SupportedAttributes, &BaseComId); + if (TcgResult != TcgResultSuccess || SupportedAttributes.DataRemoval == 0) { + return 0; + } + + TcgResult = OpalUtilGetMsid (Session, Msid, OPAL_MSID_LENGTH, &MsidLength); + if (TcgResult != TcgResultSuccess) { + return 0; + } + + TcgResult = OpalUtilGetDataRemovalMechanismLists (Session, RemovalMechanishLists); + if (TcgResult != TcgResultSuccess) { + return 0; + } + + TcgResult = OpalUtilGetActiveDataRemovalMechanism (Session, Msid, MsidLength, &ActiveDataRemovalMechanism); + if (TcgResult != TcgResultSuccess) { + return 0; + } + + return RemovalMechanishLists[ActiveDataRemovalMechanism]; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf new file mode 100644 index 00000000..09678c15 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf @@ -0,0 +1,45 @@ +## @file +# Provides some TPM 1.2 commands +# +# This library is used by other modules to send TPM 1.2 command. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm12CommandLib + MODULE_UNI_FILE = Tpm12CommandLib.uni + FILE_GUID = C595047C-70B3-4731-99CC-A014E956D7A7 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm12CommandLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm12Startup.c + Tpm12Ownership.c + Tpm12NvStorage.c + Tpm12GetCapability.c + Tpm12Pcr.c + Tpm12PhysicalPresence.c + Tpm12SelfTest.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + IoLib + TimerLib + DebugLib + Tpm12DeviceLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.uni new file mode 100644 index 00000000..3f02db62 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.uni @@ -0,0 +1,16 @@ +// /** @file
+// Provides some TPM 1.2 commands
+//
+// This library is used by other modules to send TPM 1.2 command.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides some TPM 1.2 command functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is used by other modules to send TPM 1.2 command."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12GetCapability.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12GetCapability.c new file mode 100644 index 00000000..69203654 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12GetCapability.c @@ -0,0 +1,131 @@ +/** @file + Implement TPM1.2 Get Capabilities related commands. + +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/Tpm12CommandLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm12DeviceLib.h> + +#pragma pack(1) + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + UINT32 Capability; + UINT32 CapabilityFlagSize; + UINT32 CapabilityFlag; +} TPM_CMD_GET_CAPABILITY; + +typedef struct { + TPM_RSP_COMMAND_HDR Hdr; + UINT32 ResponseSize; + TPM_PERMANENT_FLAGS Flags; +} TPM_RSP_GET_CAPABILITY_PERMANENT_FLAGS; + +typedef struct { + TPM_RSP_COMMAND_HDR Hdr; + UINT32 ResponseSize; + TPM_STCLEAR_FLAGS Flags; +} TPM_RSP_GET_CAPABILITY_STCLEAR_FLAGS; + +#pragma pack() + +/** +Get TPM capability permanent flags. + +@param[out] TpmPermanentFlags Pointer to the buffer for returned flag structure. + +@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 +Tpm12GetCapabilityFlagPermanent ( + OUT TPM_PERMANENT_FLAGS *TpmPermanentFlags + ) +{ + EFI_STATUS Status; + TPM_CMD_GET_CAPABILITY Command; + TPM_RSP_GET_CAPABILITY_PERMANENT_FLAGS Response; + UINT32 Length; + + // + // send Tpm command TPM_ORD_GetCapability + // + Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.Hdr.paramSize = SwapBytes32 (sizeof (Command)); + Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_GetCapability); + Command.Capability = SwapBytes32 (TPM_CAP_FLAG); + Command.CapabilityFlagSize = SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT)); + Command.CapabilityFlag = SwapBytes32 (TPM_CAP_FLAG_PERMANENT); + Length = sizeof (Response); + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + + if (SwapBytes32 (Response.Hdr.returnCode) != TPM_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Tpm12GetCapabilityFlagPermanent: Response Code error! 0x%08x\r\n", SwapBytes32 (Response.Hdr.returnCode))); + return EFI_DEVICE_ERROR; + } + + ZeroMem (TpmPermanentFlags, sizeof (*TpmPermanentFlags)); + CopyMem (TpmPermanentFlags, &Response.Flags, MIN (sizeof (*TpmPermanentFlags), SwapBytes32(Response.ResponseSize))); + + return Status; +} + +/** +Get TPM capability volatile flags. + +@param[out] VolatileFlags Pointer to the buffer for returned flag structure. + +@retval EFI_SUCCESS Operation completed successfully. +@retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +Tpm12GetCapabilityFlagVolatile ( + OUT TPM_STCLEAR_FLAGS *VolatileFlags + ) +{ + EFI_STATUS Status; + TPM_CMD_GET_CAPABILITY Command; + TPM_RSP_GET_CAPABILITY_STCLEAR_FLAGS Response; + UINT32 Length; + + // + // send Tpm command TPM_ORD_GetCapability + // + Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.Hdr.paramSize = SwapBytes32 (sizeof (Command)); + Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_GetCapability); + Command.Capability = SwapBytes32 (TPM_CAP_FLAG); + Command.CapabilityFlagSize = SwapBytes32 (sizeof (TPM_CAP_FLAG_VOLATILE)); + Command.CapabilityFlag = SwapBytes32 (TPM_CAP_FLAG_VOLATILE); + Length = sizeof (Response); + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + + if (SwapBytes32 (Response.Hdr.returnCode) != TPM_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Tpm12GetCapabilityFlagVolatile: Response Code error! 0x%08x\r\n", SwapBytes32 (Response.Hdr.returnCode))); + return EFI_DEVICE_ERROR; + } + + ZeroMem (VolatileFlags, sizeof (*VolatileFlags)); + CopyMem (VolatileFlags, &Response.Flags, MIN (sizeof (*VolatileFlags), SwapBytes32(Response.ResponseSize))); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c new file mode 100644 index 00000000..5a4ebefd --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c @@ -0,0 +1,228 @@ +/** @file + Implement TPM1.2 NV storage related command. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved. <BR> +(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/Tpm12CommandLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm12DeviceLib.h> + +// +// Max TPM NV value length +// +#define TPMNVVALUELENGTH 1024 + +#pragma pack(1) + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM12_NV_DATA_PUBLIC PubInfo; + TPM_ENCAUTH EncAuth; +} TPM_CMD_NV_DEFINE_SPACE; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_NV_INDEX NvIndex; + UINT32 Offset; + UINT32 DataSize; +} TPM_CMD_NV_READ_VALUE; + +typedef struct { + TPM_RSP_COMMAND_HDR Hdr; + UINT32 DataSize; + UINT8 Data[TPMNVVALUELENGTH]; +} TPM_RSP_NV_READ_VALUE; + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_NV_INDEX NvIndex; + UINT32 Offset; + UINT32 DataSize; + UINT8 Data[TPMNVVALUELENGTH]; +} TPM_CMD_NV_WRITE_VALUE; + +#pragma pack() + +/** + Send NV DefineSpace command to TPM1.2. + + @param PubInfo The public parameters of the NV area. + @param EncAuth The encrypted AuthData, only valid if the attributes require subsequent authorization. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm12NvDefineSpace ( + IN TPM12_NV_DATA_PUBLIC *PubInfo, + IN TPM_ENCAUTH *EncAuth + ) +{ + EFI_STATUS Status; + TPM_CMD_NV_DEFINE_SPACE Command; + TPM_RSP_COMMAND_HDR Response; + UINT32 Length; + + // + // send Tpm command TPM_ORD_NV_DefineSpace + // + Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.Hdr.paramSize = SwapBytes32 (sizeof (Command)); + Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_NV_DefineSpace); + Command.PubInfo.tag = SwapBytes16 (PubInfo->tag); + Command.PubInfo.nvIndex = SwapBytes32 (PubInfo->nvIndex); + Command.PubInfo.pcrInfoRead.pcrSelection.sizeOfSelect = SwapBytes16 (PubInfo->pcrInfoRead.pcrSelection.sizeOfSelect); + Command.PubInfo.pcrInfoRead.pcrSelection.pcrSelect[0] = PubInfo->pcrInfoRead.pcrSelection.pcrSelect[0]; + Command.PubInfo.pcrInfoRead.pcrSelection.pcrSelect[1] = PubInfo->pcrInfoRead.pcrSelection.pcrSelect[1]; + Command.PubInfo.pcrInfoRead.pcrSelection.pcrSelect[2] = PubInfo->pcrInfoRead.pcrSelection.pcrSelect[2]; + Command.PubInfo.pcrInfoRead.localityAtRelease = PubInfo->pcrInfoRead.localityAtRelease; + CopyMem (&Command.PubInfo.pcrInfoRead.digestAtRelease, &PubInfo->pcrInfoRead.digestAtRelease, sizeof(PubInfo->pcrInfoRead.digestAtRelease)); + Command.PubInfo.pcrInfoWrite.pcrSelection.sizeOfSelect = SwapBytes16 (PubInfo->pcrInfoWrite.pcrSelection.sizeOfSelect); + Command.PubInfo.pcrInfoWrite.pcrSelection.pcrSelect[0] = PubInfo->pcrInfoWrite.pcrSelection.pcrSelect[0]; + Command.PubInfo.pcrInfoWrite.pcrSelection.pcrSelect[1] = PubInfo->pcrInfoWrite.pcrSelection.pcrSelect[1]; + Command.PubInfo.pcrInfoWrite.pcrSelection.pcrSelect[2] = PubInfo->pcrInfoWrite.pcrSelection.pcrSelect[2]; + Command.PubInfo.pcrInfoWrite.localityAtRelease = PubInfo->pcrInfoWrite.localityAtRelease; + CopyMem (&Command.PubInfo.pcrInfoWrite.digestAtRelease, &PubInfo->pcrInfoWrite.digestAtRelease, sizeof(PubInfo->pcrInfoWrite.digestAtRelease)); + Command.PubInfo.permission.tag = SwapBytes16 (PubInfo->permission.tag); + Command.PubInfo.permission.attributes = SwapBytes32 (PubInfo->permission.attributes); + Command.PubInfo.bReadSTClear = PubInfo->bReadSTClear; + Command.PubInfo.bWriteSTClear = PubInfo->bWriteSTClear; + Command.PubInfo.bWriteDefine = PubInfo->bWriteDefine; + Command.PubInfo.dataSize = SwapBytes32 (PubInfo->dataSize); + CopyMem (&Command.EncAuth, EncAuth, sizeof(*EncAuth)); + Length = sizeof (Response); + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + DEBUG ((DEBUG_INFO, "Tpm12NvDefineSpace - ReturnCode = %x\n", SwapBytes32 (Response.returnCode))); + switch (SwapBytes32 (Response.returnCode)) { + case TPM_SUCCESS: + return EFI_SUCCESS; + default: + return EFI_DEVICE_ERROR; + } +} + +/** + Send NV ReadValue command to TPM1.2. + + @param NvIndex The index of the area to set. + @param Offset The offset into the area. + @param DataSize The size of the data area. + @param Data The data to set the area to. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm12NvReadValue ( + IN TPM_NV_INDEX NvIndex, + IN UINT32 Offset, + IN OUT UINT32 *DataSize, + OUT UINT8 *Data + ) +{ + EFI_STATUS Status; + TPM_CMD_NV_READ_VALUE Command; + TPM_RSP_NV_READ_VALUE Response; + UINT32 Length; + + // + // send Tpm command TPM_ORD_NV_ReadValue + // + Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.Hdr.paramSize = SwapBytes32 (sizeof (Command)); + Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_NV_ReadValue); + Command.NvIndex = SwapBytes32 (NvIndex); + Command.Offset = SwapBytes32 (Offset); + Command.DataSize = SwapBytes32 (*DataSize); + Length = sizeof (Response); + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + DEBUG ((DEBUG_INFO, "Tpm12NvReadValue - ReturnCode = %x\n", SwapBytes32 (Response.Hdr.returnCode))); + switch (SwapBytes32 (Response.Hdr.returnCode)) { + case TPM_SUCCESS: + break; + default: + return EFI_DEVICE_ERROR; + } + + // + // Return the response + // + if (SwapBytes32 (Response.DataSize) > *DataSize) { + return EFI_BUFFER_TOO_SMALL; + } + *DataSize = SwapBytes32 (Response.DataSize); + ZeroMem (Data, *DataSize); + CopyMem (Data, &Response.Data, *DataSize); + + return EFI_SUCCESS; +} + +/** + Send NV WriteValue command to TPM1.2. + + @param NvIndex The index of the area to set. + @param Offset The offset into the NV Area. + @param DataSize The size of the data parameter. + @param Data The data to set the area to. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm12NvWriteValue ( + IN TPM_NV_INDEX NvIndex, + IN UINT32 Offset, + IN UINT32 DataSize, + IN UINT8 *Data + ) +{ + EFI_STATUS Status; + TPM_CMD_NV_WRITE_VALUE Command; + UINT32 CommandLength; + TPM_RSP_COMMAND_HDR Response; + UINT32 ResponseLength; + + if (DataSize > sizeof (Command.Data)) { + return EFI_UNSUPPORTED; + } + + // + // send Tpm command TPM_ORD_NV_WriteValue + // + Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + CommandLength = sizeof (Command) - sizeof(Command.Data) + DataSize; + Command.Hdr.paramSize = SwapBytes32 (CommandLength); + Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_NV_WriteValue); + Command.NvIndex = SwapBytes32 (NvIndex); + Command.Offset = SwapBytes32 (Offset); + Command.DataSize = SwapBytes32 (DataSize); + CopyMem (Command.Data, Data, DataSize); + ResponseLength = sizeof (Response); + Status = Tpm12SubmitCommand (CommandLength, (UINT8 *)&Command, &ResponseLength, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + DEBUG ((DEBUG_INFO, "Tpm12NvWriteValue - ReturnCode = %x\n", SwapBytes32 (Response.returnCode))); + switch (SwapBytes32 (Response.returnCode)) { + case TPM_SUCCESS: + return EFI_SUCCESS; + default: + return EFI_DEVICE_ERROR; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c new file mode 100644 index 00000000..9959a9c0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c @@ -0,0 +1,49 @@ +/** @file + Implement TPM1.2 Ownership related command. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/Tpm12DeviceLib.h> + +/** + Send ForceClear command to TPM1.2. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm12ForceClear ( + VOID + ) +{ + EFI_STATUS Status; + TPM_RQU_COMMAND_HDR Command; + TPM_RSP_COMMAND_HDR Response; + UINT32 Length; + + // + // send Tpm command TPM_ORD_ForceClear + // + Command.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.paramSize = SwapBytes32 (sizeof (Command)); + Command.ordinal = SwapBytes32 (TPM_ORD_ForceClear); + Length = sizeof (Response); + + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + switch (SwapBytes32 (Response.returnCode)) { + case TPM_SUCCESS: + return EFI_SUCCESS; + default: + return EFI_DEVICE_ERROR; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12Pcr.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12Pcr.c new file mode 100644 index 00000000..3b52a347 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12Pcr.c @@ -0,0 +1,81 @@ +/** @file + Implement TPM1.2 PCR related commands. + +Copyright (c) 2016, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/Tpm12CommandLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/Tpm12DeviceLib.h> + +#pragma pack(1) + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_PCRINDEX PcrIndex; + TPM_DIGEST TpmDigest; +} TPM_CMD_EXTEND; + +typedef struct { + TPM_RSP_COMMAND_HDR Hdr; + TPM_DIGEST TpmDigest; +} TPM_RSP_EXTEND; + +#pragma pack() + +/** +Extend a TPM PCR. + +@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 +EFIAPI +Tpm12Extend ( + IN TPM_DIGEST *DigestToExtend, + IN TPM_PCRINDEX PcrIndex, + OUT TPM_DIGEST *NewPcrValue + ) +{ + EFI_STATUS Status; + TPM_CMD_EXTEND Command; + TPM_RSP_EXTEND Response; + UINT32 Length; + + // + // send Tpm command TPM_ORD_Extend + // + Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.Hdr.paramSize = SwapBytes32 (sizeof (Command)); + Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_Extend); + Command.PcrIndex = SwapBytes32 (PcrIndex); + CopyMem (&Command.TpmDigest, DigestToExtend, sizeof (Command.TpmDigest)); + Length = sizeof (Response); + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + + if (SwapBytes32(Response.Hdr.returnCode) != TPM_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm12Extend: Response Code error! 0x%08x\r\n", SwapBytes32(Response.Hdr.returnCode))); + return EFI_DEVICE_ERROR; + } + + if (NewPcrValue != NULL) { + CopyMem (NewPcrValue, &Response.TpmDigest, sizeof (*NewPcrValue)); + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12PhysicalPresence.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12PhysicalPresence.c new file mode 100644 index 00000000..25942dea --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12PhysicalPresence.c @@ -0,0 +1,66 @@ +/** @file + Implement TPM1.2 Physical Presence related command. + +Copyright (c) 2016, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/Tpm12CommandLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/Tpm12DeviceLib.h> + +#pragma pack(1) + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_PHYSICAL_PRESENCE PhysicalPresence; +} TPM_CMD_PHYSICAL_PRESENCE; + +#pragma pack() + +/** +Send TSC_PhysicalPresence command to TPM. + +@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 +EFIAPI +Tpm12PhysicalPresence ( + IN TPM_PHYSICAL_PRESENCE PhysicalPresence + ) +{ + EFI_STATUS Status; + TPM_CMD_PHYSICAL_PRESENCE Command; + TPM_RSP_COMMAND_HDR Response; + UINT32 Length; + + // + // send Tpm command TSC_ORD_PhysicalPresence + // + Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.Hdr.paramSize = SwapBytes32 (sizeof (Command)); + Command.Hdr.ordinal = SwapBytes32 (TSC_ORD_PhysicalPresence); + Command.PhysicalPresence = SwapBytes16 (PhysicalPresence); + Length = sizeof (Response); + + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + + if (SwapBytes32(Response.returnCode) != TPM_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm12PhysicalPresence: Response Code error! 0x%08x\r\n", SwapBytes32(Response.returnCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12SelfTest.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12SelfTest.c new file mode 100644 index 00000000..b1c80b6a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12SelfTest.c @@ -0,0 +1,54 @@ +/** @file + Implement TPM1.2 NV Self Test related commands. + +Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved. <BR> +(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/Tpm12CommandLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/Tpm12DeviceLib.h> + +/** +Send TPM_ContinueSelfTest command to TPM. + +@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 +Tpm12ContinueSelfTest ( + VOID + ) +{ + EFI_STATUS Status; + TPM_RQU_COMMAND_HDR Command; + TPM_RSP_COMMAND_HDR Response; + UINT32 Length; + + // + // send Tpm command TPM_ORD_ContinueSelfTest + // + Command.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.paramSize = SwapBytes32 (sizeof (Command)); + Command.ordinal = SwapBytes32 (TPM_ORD_ContinueSelfTest); + Length = sizeof (Response); + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + + if (SwapBytes32 (Response.returnCode) != TPM_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Tpm12ContinueSelfTest: Response Code error! 0x%08x\r\n", SwapBytes32 (Response.returnCode))); + return EFI_DEVICE_ERROR; + } + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c new file mode 100644 index 00000000..4cf8a028 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c @@ -0,0 +1,103 @@ +/** @file + Implement TPM1.2 Startup related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved. <BR> +(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiPei.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/Tpm12DeviceLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM_RQU_COMMAND_HDR Hdr; + TPM_STARTUP_TYPE TpmSt; +} TPM_CMD_START_UP; + +#pragma pack() + +/** + Send Startup command to TPM1.2. + + @param TpmSt Startup Type. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm12Startup ( + IN TPM_STARTUP_TYPE TpmSt + ) +{ + EFI_STATUS Status; + TPM_CMD_START_UP Command; + TPM_RSP_COMMAND_HDR Response; + UINT32 Length; + + // + // send Tpm command TPM_ORD_Startup + // + Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.Hdr.paramSize = SwapBytes32 (sizeof (Command)); + Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_Startup); + Command.TpmSt = SwapBytes16 (TpmSt); + Length = sizeof (Response); + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + switch (SwapBytes32(Response.returnCode)) { + case TPM_SUCCESS: + DEBUG ((DEBUG_INFO, "TPM12Startup: TPM_SUCCESS\n")); + return EFI_SUCCESS; + case TPM_INVALID_POSTINIT: + // In warm reset, TPM may response TPM_INVALID_POSTINIT + DEBUG ((DEBUG_INFO, "TPM12Startup: TPM_INVALID_POSTINIT\n")); + return EFI_SUCCESS; + default: + return EFI_DEVICE_ERROR; + } +} + +/** + Send SaveState command to TPM1.2. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm12SaveState ( + VOID + ) +{ + EFI_STATUS Status; + TPM_RQU_COMMAND_HDR Command; + TPM_RSP_COMMAND_HDR Response; + UINT32 Length; + + // + // send Tpm command TPM_ORD_SaveState + // + Command.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND); + Command.paramSize = SwapBytes32 (sizeof (Command)); + Command.ordinal = SwapBytes32 (TPM_ORD_SaveState); + Length = sizeof (Response); + Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response); + if (EFI_ERROR (Status)) { + return Status; + } + switch (SwapBytes32 (Response.returnCode)) { + case TPM_SUCCESS: + return EFI_SUCCESS; + default: + return EFI_DEVICE_ERROR; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf new file mode 100644 index 00000000..5eee5340 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf @@ -0,0 +1,43 @@ +## @file +# Provides TPM 1.2 TIS functions +# +# This library implements TIS (TPM Interface Specification) functions which is +# used for every TPM 1.2 command. Choosing this library means platform uses and +# only uses TPM 1.2 device. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm12DeviceLibDTpm + MODULE_UNI_FILE = Tpm12DeviceLibDTpm.uni + FILE_GUID = BC2B7672-A48B-4d58-B39E-AEE3707B5A23 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm12DeviceLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm12Tis.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + IoLib + TimerLib + DebugLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.uni new file mode 100644 index 00000000..4594f60b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.uni @@ -0,0 +1,18 @@ +// /** @file
+// Provides TPM 1.2 TIS functions
+//
+// This library implements TIS (TPM Interface Specification) functions which is
+// used for every TPM 1.2 command. Choosing this library means platform uses and
+// only uses TPM 1.2 device.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM 1.2 TIS functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library implements TIS (TPM Interface Specification) functions which is used for every TPM 1.2 command. Choosing this library means platform uses and only uses TPM 1.2 device."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c new file mode 100644 index 00000000..5cab57e5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c @@ -0,0 +1,544 @@ +/** @file + TIS (TPM Interface Specification) functions used by TPM1.2. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <IndustryStandard/Tpm12.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/DebugLib.h> +#include <Library/Tpm12CommandLib.h> +#include <Library/PcdLib.h> + +#include <IndustryStandard/TpmPtp.h> +#include <IndustryStandard/TpmTis.h> + +typedef enum { + PtpInterfaceTis, + PtpInterfaceFifo, + PtpInterfaceCrb, + PtpInterfaceMax, +} PTP_INTERFACE_TYPE; + +// +// Max TPM command/response length +// +#define TPMCMDBUFLENGTH 1024 + +/** + 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 +Tpm12TisPcPresenceCheck ( + IN TIS_PC_REGISTERS_PTR TisReg + ) +{ + UINT8 RegRead; + + RegRead = MmioRead8 ((UINTN)&TisReg->Access); + return (BOOLEAN)(RegRead != (UINT8)-1); +} + +/** + Return PTP interface type. + + @param[in] Register Pointer to PTP register. + + @return PTP interface type. +**/ +PTP_INTERFACE_TYPE +Tpm12GetPtpInterface ( + IN VOID *Register + ) +{ + PTP_CRB_INTERFACE_IDENTIFIER InterfaceId; + PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability; + + if (!Tpm12TisPcPresenceCheck (Register)) { + return PtpInterfaceMax; + } + // + // Check interface id + // + InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId); + InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability); + + if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) && + (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) && + (InterfaceId.Bits.CapCRB != 0)) { + return PtpInterfaceCrb; + } + if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) && + (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) && + (InterfaceId.Bits.CapFIFO != 0) && + (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) { + return PtpInterfaceFifo; + } + return PtpInterfaceTis; +} + +/** + 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 +Tpm12TisPcWaitRegisterBits ( + 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 register + 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 BurstCount. + + @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 +Tpm12TisPcReadBurstCount ( + 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 +Tpm12TisPcPrepareCommand ( + 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 = Tpm12TisPcWaitRegisterBits ( + &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_A. + + @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 +Tpm12TisPcRequestUseTpm ( + IN TIS_PC_REGISTERS_PTR TisReg + ) +{ + EFI_STATUS Status; + + if (TisReg == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!Tpm12TisPcPresenceCheck (TisReg)) { + return EFI_NOT_FOUND; + } + + MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE); + Status = Tpm12TisPcWaitRegisterBits ( + &TisReg->Access, + (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID), + 0, + TIS_TIMEOUT_A + ); + return Status; +} + +/** + Send a command to TPM for execution and return response data. + + @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_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + @retval EFI_UNSUPPORTED Unsupported TPM version + +**/ +EFI_STATUS +Tpm12TisTpmCommand ( + 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; + UINT16 RspTag; + + DEBUG_CODE ( + UINTN DebugSize; + + DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand Send - ")); + if (SizeIn > 0x100) { + DebugSize = 0x40; + } else { + DebugSize = SizeIn; + } + for (Index = 0; Index < DebugSize; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index])); + } + if (DebugSize != SizeIn) { + DEBUG ((EFI_D_VERBOSE, "...... ")); + for (Index = SizeIn - 0x20; Index < SizeIn; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index])); + } + } + DEBUG ((EFI_D_VERBOSE, "\n")); + ); + TpmOutSize = 0; + + Status = Tpm12TisPcPrepareCommand (TisReg); + if (EFI_ERROR (Status)){ + DEBUG ((DEBUG_ERROR, "Tpm12 is not ready for command!\n")); + return EFI_DEVICE_ERROR; + } + // + // Send the command data to Tpm + // + Index = 0; + while (Index < SizeIn) { + Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + 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 = Tpm12TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) TIS_PC_VALID, + TIS_PC_STS_EXPECT, + TIS_TIMEOUT_C + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Tpm12 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 = Tpm12TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA), + 0, + TIS_TIMEOUT_B + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Wait for Tpm12 response data time out!!\n")); + Status = EFI_DEVICE_ERROR; + goto Exit; + } + // + // Get response data header + // + Index = 0; + BurstCount = 0; + while (Index < sizeof (TPM_RSP_COMMAND_HDR)) { + Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + for (; BurstCount > 0; BurstCount--) { + *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo); + Index++; + if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break; + } + } + DEBUG_CODE ( + DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand ReceiveHeader - ")); + for (Index = 0; Index < sizeof (TPM_RSP_COMMAND_HDR); Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index])); + } + DEBUG ((EFI_D_VERBOSE, "\n")); + ); + // + // Check the response data header (tag, parasize and returncode) + // + CopyMem (&Data16, BufferOut, sizeof (UINT16)); + RspTag = SwapBytes16 (Data16); + if (RspTag != TPM_TAG_RSP_COMMAND && RspTag != TPM_TAG_RSP_AUTH1_COMMAND && RspTag != TPM_TAG_RSP_AUTH2_COMMAND) { + DEBUG ((EFI_D_ERROR, "TPM12: Response tag error - current tag value is %x\n", RspTag)); + Status = EFI_UNSUPPORTED; + 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 = Tpm12TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + } +Exit: + DEBUG_CODE ( + DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand Receive - ")); + for (Index = 0; Index < TpmOutSize; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index])); + } + DEBUG ((EFI_D_VERBOSE, "\n")); + ); + MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY); + return Status; +} + +/** + This service enables the sending of commands to the TPM12. + + @param[in] InputParameterBlockSize Size of the TPM12 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM12 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +Tpm12SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + PTP_INTERFACE_TYPE PtpInterface; + + // + // Special handle for TPM1.2 to check PTP too, because PTP/TIS share same register address. + // + PtpInterface = Tpm12GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + switch (PtpInterface) { + case PtpInterfaceFifo: + case PtpInterfaceTis: + return Tpm12TisTpmCommand ( + (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress), + InputParameterBlock, + InputParameterBlockSize, + OutputParameterBlock, + OutputParameterBlockSize + ); + case PtpInterfaceCrb: + // + // No need to support CRB because it is only accept TPM2 command. + // + default: + return EFI_DEVICE_ERROR; + } + +} + +/** + 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 +Tpm12PtpCrbWaitRegisterBits ( + IN UINT32 *Register, + IN UINT32 BitSet, + IN UINT32 BitClear, + IN UINT32 TimeOut + ) +{ + UINT32 RegRead; + UINT32 WaitTime; + + for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){ + RegRead = MmioRead32 ((UINTN)Register); + if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0) { + return EFI_SUCCESS; + } + MicroSecondDelay (30); + } + return EFI_TIMEOUT; +} + +/** + Get the control of TPM chip. + + @param[in] CrbReg Pointer to CRB register. + + @retval EFI_SUCCESS Get the control of TPM chip. + @retval EFI_INVALID_PARAMETER CrbReg is NULL. + @retval EFI_NOT_FOUND TPM chip doesn't exit. + @retval EFI_TIMEOUT Can't get the TPM control in time. +**/ +EFI_STATUS +Tpm12PtpCrbRequestUseTpm ( + IN PTP_CRB_REGISTERS_PTR CrbReg + ) +{ + EFI_STATUS Status; + + MmioWrite32((UINTN)&CrbReg->LocalityControl, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS); + Status = Tpm12PtpCrbWaitRegisterBits ( + &CrbReg->LocalityStatus, + PTP_CRB_LOCALITY_STATUS_GRANTED, + 0, + PTP_TIMEOUT_A + ); + return Status; +} + +/** + This service requests use TPM12. + + @retval EFI_SUCCESS Get the control of TPM12 chip. + @retval EFI_NOT_FOUND TPM12 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm12RequestUseTpm ( + VOID + ) +{ + PTP_INTERFACE_TYPE PtpInterface; + + // + // Special handle for TPM1.2 to check PTP too, because PTP/TIS share same register address. + // Some other program might leverage this function to check the existence of TPM chip. + // + PtpInterface = Tpm12GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + switch (PtpInterface) { + case PtpInterfaceCrb: + return Tpm12PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + case PtpInterfaceFifo: + case PtpInterfaceTis: + return Tpm12TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + default: + return EFI_NOT_FOUND; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.c new file mode 100644 index 00000000..cecd7234 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.c @@ -0,0 +1,102 @@ +/** @file + This library is TPM12 TCG protocol lib. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Uefi.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/Tpm12DeviceLib.h> +#include <Protocol/TcgService.h> +#include <IndustryStandard/Tpm12.h> + +EFI_TCG_PROTOCOL *mTcgProtocol = NULL; + +/** + This service enables the sending of commands to the TPM12. + + @param[in] InputParameterBlockSize Size of the TPM12 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM12 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +Tpm12SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + EFI_STATUS Status; + TPM_RSP_COMMAND_HDR *Header; + + if (mTcgProtocol == NULL) { + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &mTcgProtocol); + if (EFI_ERROR (Status)) { + // + // TCG protocol is not installed. So, TPM12 is not present. + // + DEBUG ((EFI_D_ERROR, "Tpm12SubmitCommand - TCG - %r\n", Status)); + return EFI_NOT_FOUND; + } + } + // + // Assume when TCG Protocol is ready, RequestUseTpm already done. + // + Status = mTcgProtocol->PassThroughToTpm ( + mTcgProtocol, + InputParameterBlockSize, + InputParameterBlock, + *OutputParameterBlockSize, + OutputParameterBlock + ); + if (EFI_ERROR (Status)) { + return Status; + } + Header = (TPM_RSP_COMMAND_HDR *)OutputParameterBlock; + *OutputParameterBlockSize = SwapBytes32 (Header->paramSize); + + return EFI_SUCCESS; +} + +/** + This service requests use TPM12. + + @retval EFI_SUCCESS Get the control of TPM12 chip. + @retval EFI_NOT_FOUND TPM12 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm12RequestUseTpm ( + VOID + ) +{ + EFI_STATUS Status; + + if (mTcgProtocol == NULL) { + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &mTcgProtocol); + if (EFI_ERROR (Status)) { + // + // TCG protocol is not installed. So, TPM12 is not present. + // + DEBUG ((EFI_D_ERROR, "Tpm12RequestUseTpm - TCG - %r\n", Status)); + return EFI_NOT_FOUND; + } + } + // + // Assume when TCG Protocol is ready, RequestUseTpm already done. + // + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf new file mode 100644 index 00000000..d00a92cd --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf @@ -0,0 +1,41 @@ +## @file +# Provides function interfaces to communicate with TPM 1.2 device +# +# This library helps to use TPM 1.2 device in library function API +# based on TCG protocol. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm12DeviceLibTcg + MODULE_UNI_FILE = Tpm12DeviceLibTcg.uni + FILE_GUID = 4D8B77D9-E923-48f8-B070-4053D78B7E56 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm12DeviceLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm12DeviceLibTcg.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + UefiBootServicesTableLib + +[Protocols] + gEfiTcgProtocolGuid ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.uni new file mode 100644 index 00000000..cc5fdfe1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.uni @@ -0,0 +1,17 @@ +// /** @file
+// Provides function interfaces to communicate with TPM 1.2 device
+//
+// This library helps to use TPM 1.2 device in library function API
+// based on TCG protocol.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides function interfaces to communicate with TPM 1.2 device"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library helps to use TPM 1.2 device in library function API based on TCG protocol."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c new file mode 100644 index 00000000..d33540fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c @@ -0,0 +1,889 @@ +/** @file + Implement TPM2 Capability related command. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPM_CAP Capability; + UINT32 Property; + UINT32 PropertyCount; +} TPM2_GET_CAPABILITY_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + TPMI_YES_NO MoreData; + TPMS_CAPABILITY_DATA CapabilityData; +} TPM2_GET_CAPABILITY_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMT_PUBLIC_PARMS Parameters; +} TPM2_TEST_PARMS_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; +} TPM2_TEST_PARMS_RESPONSE; + +#pragma pack() + +#define TPMA_CC_COMMANDINDEX_MASK 0x2000FFFF + +/** + This command returns various information regarding the TPM and its current state. + + The capability parameter determines the category of data returned. The property parameter + selects the first value of the selected category to be returned. If there is no property + that corresponds to the value of property, the next higher value is returned, if it exists. + The moreData parameter will have a value of YES if there are more values of the requested + type that were not returned. + If no next capability exists, the TPM will return a zero-length list and moreData will have + a value of NO. + + NOTE: + To simplify this function, leave returned CapabilityData for caller to unpack since there are + many capability categories and only few categories will be used in firmware. It means the caller + need swap the byte order for the fields in CapabilityData. + + @param[in] Capability Group selection; determines the format of the response. + @param[in] Property Further definition of information. + @param[in] PropertyCount Number of properties of the indicated type to return. + @param[out] MoreData Flag to indicate if there are more values of this type. + @param[out] CapabilityData The capability data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapability ( + IN TPM_CAP Capability, + IN UINT32 Property, + IN UINT32 PropertyCount, + OUT TPMI_YES_NO *MoreData, + OUT TPMS_CAPABILITY_DATA *CapabilityData + ) +{ + EFI_STATUS Status; + TPM2_GET_CAPABILITY_COMMAND SendBuffer; + TPM2_GET_CAPABILITY_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_GetCapability); + + SendBuffer.Capability = SwapBytes32 (Capability); + SendBuffer.Property = SwapBytes32 (Property); + SendBuffer.PropertyCount = SwapBytes32 (PropertyCount); + + SendBufferSize = (UINT32) sizeof (SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize <= sizeof (TPM2_RESPONSE_HEADER) + sizeof (UINT8)) { + return EFI_DEVICE_ERROR; + } + + // + // Fail if command failed + // + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2GetCapability: Response Code error! 0x%08x\r\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Return the response + // + *MoreData = RecvBuffer.MoreData; + // + // Does not unpack all possible property here, the caller should unpack it and note the byte order. + // + CopyMem (CapabilityData, &RecvBuffer.CapabilityData, RecvBufferSize - sizeof (TPM2_RESPONSE_HEADER) - sizeof (UINT8)); + + return EFI_SUCCESS; +} + +/** + This command returns the information of TPM Family. + + This function parse the value got from TPM2_GetCapability and return the Family. + + @param[out] Family The Family of TPM. (a 4-octet character string) + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityFamily ( + OUT CHAR8 *Family + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_FAMILY_INDICATOR, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + CopyMem (Family, &TpmCap.data.tpmProperties.tpmProperty->value, 4); + + return EFI_SUCCESS; +} + +/** + This command returns the information of TPM manufacture ID. + + This function parse the value got from TPM2_GetCapability and return the TPM manufacture ID. + + @param[out] ManufactureId The manufacture ID of TPM. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityManufactureID ( + OUT UINT32 *ManufactureId + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_MANUFACTURER, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + *ManufactureId = TpmCap.data.tpmProperties.tpmProperty->value; + + return EFI_SUCCESS; +} + +/** + This command returns the information of TPM FirmwareVersion. + + This function parse the value got from TPM2_GetCapability and return the TPM FirmwareVersion. + + @param[out] FirmwareVersion1 The FirmwareVersion1. + @param[out] FirmwareVersion2 The FirmwareVersion2. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityFirmwareVersion ( + OUT UINT32 *FirmwareVersion1, + OUT UINT32 *FirmwareVersion2 + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_FIRMWARE_VERSION_1, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + *FirmwareVersion1 = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value); + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_FIRMWARE_VERSION_2, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + *FirmwareVersion2 = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value); + + return EFI_SUCCESS; +} + +/** + This command returns the information of the maximum value for commandSize and responseSize in a command. + + This function parse the value got from TPM2_GetCapability and return the max command size and response size + + @param[out] MaxCommandSize The maximum value for commandSize in a command. + @param[out] MaxResponseSize The maximum value for responseSize in a command. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityMaxCommandResponseSize ( + OUT UINT32 *MaxCommandSize, + OUT UINT32 *MaxResponseSize + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_MAX_COMMAND_SIZE, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *MaxCommandSize = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value); + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_MAX_RESPONSE_SIZE, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *MaxResponseSize = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value); + return EFI_SUCCESS; +} + +/** + This command returns Returns a list of TPMS_ALG_PROPERTIES. Each entry is an + algorithm ID and a set of properties of the algorithm. + + This function parse the value got from TPM2_GetCapability and return the list. + + @param[out] AlgList List of algorithm. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilitySupportedAlg ( + OUT TPML_ALG_PROPERTY *AlgList + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + UINTN Index; + EFI_STATUS Status; + + Status = Tpm2GetCapability ( + TPM_CAP_ALGS, + 1, + MAX_CAP_ALGS, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (AlgList, &TpmCap.data.algorithms, sizeof (TPML_ALG_PROPERTY)); + + AlgList->count = SwapBytes32 (AlgList->count); + if (AlgList->count > MAX_CAP_ALGS) { + DEBUG ((DEBUG_ERROR, "Tpm2GetCapabilitySupportedAlg - AlgList->count error %x\n", AlgList->count)); + return EFI_DEVICE_ERROR; + } + + for (Index = 0; Index < AlgList->count; Index++) { + AlgList->algProperties[Index].alg = SwapBytes16 (AlgList->algProperties[Index].alg); + WriteUnaligned32 ((UINT32 *)&AlgList->algProperties[Index].algProperties, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&AlgList->algProperties[Index].algProperties))); + } + + return EFI_SUCCESS; +} + +/** + This command returns the information of TPM LockoutCounter. + + This function parse the value got from TPM2_GetCapability and return the LockoutCounter. + + @param[out] LockoutCounter The LockoutCounter of TPM. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityLockoutCounter ( + OUT UINT32 *LockoutCounter + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_LOCKOUT_COUNTER, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + *LockoutCounter = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value); + + return EFI_SUCCESS; +} + +/** + This command returns the information of TPM LockoutInterval. + + This function parse the value got from TPM2_GetCapability and return the LockoutInterval. + + @param[out] LockoutInterval The LockoutInterval of TPM. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityLockoutInterval ( + OUT UINT32 *LockoutInterval + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_LOCKOUT_INTERVAL, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + *LockoutInterval = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value); + + return EFI_SUCCESS; +} + +/** + This command returns the information of TPM InputBufferSize. + + This function parse the value got from TPM2_GetCapability and return the InputBufferSize. + + @param[out] InputBufferSize The InputBufferSize of TPM. + the maximum size of a parameter (typically, a TPM2B_MAX_BUFFER) + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityInputBufferSize ( + OUT UINT32 *InputBufferSize + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_INPUT_BUFFER, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + *InputBufferSize = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value); + + return EFI_SUCCESS; +} + +/** + This command returns the information of TPM PCRs. + + This function parse the value got from TPM2_GetCapability and return the PcrSelection. + + @param[out] Pcrs The Pcr Selection + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityPcrs ( + OUT TPML_PCR_SELECTION *Pcrs + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + UINTN Index; + + Status = Tpm2GetCapability ( + TPM_CAP_PCRS, + 0, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Pcrs->count = SwapBytes32 (TpmCap.data.assignedPCR.count); + if (Pcrs->count > HASH_COUNT) { + DEBUG ((DEBUG_ERROR, "Tpm2GetCapabilityPcrs - Pcrs->count error %x\n", Pcrs->count)); + return EFI_DEVICE_ERROR; + } + + for (Index = 0; Index < Pcrs->count; Index++) { + Pcrs->pcrSelections[Index].hash = SwapBytes16 (TpmCap.data.assignedPCR.pcrSelections[Index].hash); + Pcrs->pcrSelections[Index].sizeofSelect = TpmCap.data.assignedPCR.pcrSelections[Index].sizeofSelect; + if (Pcrs->pcrSelections[Index].sizeofSelect > PCR_SELECT_MAX) { + DEBUG ((DEBUG_ERROR, "Tpm2GetCapabilityPcrs - sizeofSelect error %x\n", Pcrs->pcrSelections[Index].sizeofSelect)); + return EFI_DEVICE_ERROR; + } + CopyMem (Pcrs->pcrSelections[Index].pcrSelect, TpmCap.data.assignedPCR.pcrSelections[Index].pcrSelect, Pcrs->pcrSelections[Index].sizeofSelect); + } + + return EFI_SUCCESS; +} + +/** + This function will query the TPM to determine which hashing algorithms + are supported and which PCR banks are currently active. + + @param[out] TpmHashAlgorithmBitmap A bitmask containing the algorithms supported by the TPM. + @param[out] ActivePcrBanks A bitmask containing the PCRs currently allocated. + + @retval EFI_SUCCESS TPM was successfully queried and return values can be trusted. + @retval Others An error occurred, likely in communication with the TPM. + +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilitySupportedAndActivePcrs ( + OUT UINT32 *TpmHashAlgorithmBitmap, + OUT UINT32 *ActivePcrBanks + ) +{ + EFI_STATUS Status; + TPML_PCR_SELECTION Pcrs; + UINTN Index; + + // + // Get supported PCR and current Active PCRs. + // + Status = Tpm2GetCapabilityPcrs (&Pcrs); + + // + // If error, assume that we have at least SHA-1 (and return the error.) + // + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "GetSupportedAndActivePcrs - Tpm2GetCapabilityPcrs fail!\n")); + *TpmHashAlgorithmBitmap = HASH_ALG_SHA1; + *ActivePcrBanks = HASH_ALG_SHA1; + } + // + // Otherwise, process the return data to determine what algorithms are supported + // and currently allocated. + // + else { + DEBUG ((EFI_D_INFO, "GetSupportedAndActivePcrs - Count = %08x\n", Pcrs.count)); + *TpmHashAlgorithmBitmap = 0; + *ActivePcrBanks = 0; + for (Index = 0; Index < Pcrs.count; Index++) { + switch (Pcrs.pcrSelections[Index].hash) { + case TPM_ALG_SHA1: + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA1 present.\n")); + *TpmHashAlgorithmBitmap |= HASH_ALG_SHA1; + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA1 active.\n")); + *ActivePcrBanks |= HASH_ALG_SHA1; + } + break; + case TPM_ALG_SHA256: + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA256 present.\n")); + *TpmHashAlgorithmBitmap |= HASH_ALG_SHA256; + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA256 active.\n")); + *ActivePcrBanks |= HASH_ALG_SHA256; + } + break; + case TPM_ALG_SHA384: + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA384 present.\n")); + *TpmHashAlgorithmBitmap |= HASH_ALG_SHA384; + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA384 active.\n")); + *ActivePcrBanks |= HASH_ALG_SHA384; + } + break; + case TPM_ALG_SHA512: + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA512 present.\n")); + *TpmHashAlgorithmBitmap |= HASH_ALG_SHA512; + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA512 active.\n")); + *ActivePcrBanks |= HASH_ALG_SHA512; + } + break; + case TPM_ALG_SM3_256: + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SM3_256 present.\n")); + *TpmHashAlgorithmBitmap |= HASH_ALG_SM3_256; + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SM3_256 active.\n")); + *ActivePcrBanks |= HASH_ALG_SM3_256; + } + break; + } + } + } + + return Status; +} + +/** + This command returns the information of TPM AlgorithmSet. + + This function parse the value got from TPM2_GetCapability and return the AlgorithmSet. + + @param[out] AlgorithmSet The AlgorithmSet of TPM. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityAlgorithmSet ( + OUT UINT32 *AlgorithmSet + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + + Status = Tpm2GetCapability ( + TPM_CAP_TPM_PROPERTIES, + TPM_PT_ALGORITHM_SET, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + *AlgorithmSet = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value); + + return EFI_SUCCESS; +} + +/** + This function will query if the command is supported. + + @param[In] Command TPM_CC command starts from TPM_CC_FIRST. + @param[out] IsCmdImpl The command is supported or not. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2GetCapabilityIsCommandImplemented ( + IN TPM_CC Command, + OUT BOOLEAN *IsCmdImpl + ) +{ + TPMS_CAPABILITY_DATA TpmCap; + TPMI_YES_NO MoreData; + EFI_STATUS Status; + UINT32 Attribute; + + Status = Tpm2GetCapability ( + TPM_CAP_COMMANDS, + Command, + 1, + &MoreData, + &TpmCap + ); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem (&Attribute, &TpmCap.data.command.commandAttributes[0], sizeof (UINT32)); + *IsCmdImpl = (Command == (SwapBytes32(Attribute) & TPMA_CC_COMMANDINDEX_MASK)); + + return EFI_SUCCESS; +} + +/** + This command is used to check to see if specific combinations of algorithm parameters are supported. + + @param[in] Parameters Algorithm parameters to be validated + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2TestParms ( + IN TPMT_PUBLIC_PARMS *Parameters + ) +{ + EFI_STATUS Status; + TPM2_TEST_PARMS_COMMAND SendBuffer; + TPM2_TEST_PARMS_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_TestParms); + + Buffer = (UINT8 *)&SendBuffer.Parameters; + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->type)); + Buffer += sizeof(UINT16); + switch (Parameters->type) { + case TPM_ALG_KEYEDHASH: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.scheme)); + Buffer += sizeof(UINT16); + switch (Parameters->parameters.keyedHashDetail.scheme.scheme) { + case TPM_ALG_HMAC: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.details.hmac.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_XOR: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.details.xor.hashAlg)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.details.xor.kdf)); + Buffer += sizeof(UINT16); + break; + default: + return EFI_INVALID_PARAMETER; + } + case TPM_ALG_SYMCIPHER: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.algorithm)); + Buffer += sizeof(UINT16); + switch (Parameters->parameters.symDetail.algorithm) { + case TPM_ALG_AES: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.keyBits.aes)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.mode.aes)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_SM4: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.keyBits.SM4)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.mode.SM4)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_XOR: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.keyBits.xor)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_INVALID_PARAMETER; + } + break; + case TPM_ALG_RSA: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.algorithm)); + Buffer += sizeof(UINT16); + switch (Parameters->parameters.rsaDetail.symmetric.algorithm) { + case TPM_ALG_AES: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.keyBits.aes)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.mode.aes)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_SM4: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.keyBits.SM4)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.mode.SM4)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_INVALID_PARAMETER; + } + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.scheme)); + Buffer += sizeof(UINT16); + switch (Parameters->parameters.rsaDetail.scheme.scheme) { + case TPM_ALG_RSASSA: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.details.rsassa.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_RSAPSS: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.details.rsapss.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_RSAES: + break; + case TPM_ALG_OAEP: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.details.oaep.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_INVALID_PARAMETER; + } + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.keyBits)); + Buffer += sizeof(UINT16); + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (Parameters->parameters.rsaDetail.exponent)); + Buffer += sizeof(UINT32); + break; + case TPM_ALG_ECC: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.algorithm)); + Buffer += sizeof(UINT16); + switch (Parameters->parameters.eccDetail.symmetric.algorithm) { + case TPM_ALG_AES: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.keyBits.aes)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.mode.aes)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_SM4: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.keyBits.SM4)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.mode.SM4)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_INVALID_PARAMETER; + } + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.scheme)); + Buffer += sizeof(UINT16); + switch (Parameters->parameters.eccDetail.scheme.scheme) { + case TPM_ALG_ECDSA: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.details.ecdsa.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_ECDAA: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.details.ecdaa.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_ECSCHNORR: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.details.ecSchnorr.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_ECDH: + break; + case TPM_ALG_NULL: + break; + default: + return EFI_INVALID_PARAMETER; + } + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.curveID)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.scheme)); + Buffer += sizeof(UINT16); + switch (Parameters->parameters.eccDetail.kdf.scheme) { + case TPM_ALG_MGF1: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.mgf1.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_KDF1_SP800_108: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.kdf1_sp800_108.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_KDF1_SP800_56a: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.kdf1_SP800_56a.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_KDF2: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.kdf2.hashAlg)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_INVALID_PARAMETER; + } + break; + default: + return EFI_INVALID_PARAMETER; + } + + SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2TestParms - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2TestParms - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf new file mode 100644 index 00000000..5c957676 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf @@ -0,0 +1,50 @@ +## @file +# Provides some TPM 2.0 commands +# +# This library is used by other modules to send TPM 2.0 command. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm2CommandLib + MODULE_UNI_FILE = Tpm2CommandLib.uni + FILE_GUID = 2F572F32-8BE5-4868-BD1D-7438AD97DC27 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm2CommandLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm2Capability.c + Tpm2Sequences.c + Tpm2Integrity.c + Tpm2Hierarchy.c + Tpm2NVStorage.c + Tpm2Startup.c + Tpm2Session.c + Tpm2Context.c + Tpm2EnhancedAuthorization.c + Tpm2Test.c + Tpm2DictionaryAttack.c + Tpm2Object.c + Tpm2Miscellaneous.c + Tpm2Help.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + Tpm2DeviceLib diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.uni new file mode 100644 index 00000000..2bcd50e7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.uni @@ -0,0 +1,16 @@ +// /** @file
+// Provides some TPM 2.0 commands
+//
+// This library is used by other modules to send TPM 2.0 command.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides some TPM 2.0 command functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is used by other modules to send TPM 2.0 command."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Context.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Context.c new file mode 100644 index 00000000..101f51eb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Context.c @@ -0,0 +1,80 @@ +/** @file + Implement TPM2 Context related command. + +Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_DH_CONTEXT FlushHandle; +} TPM2_FLUSH_CONTEXT_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; +} TPM2_FLUSH_CONTEXT_RESPONSE; + +#pragma pack() + +/** + This command causes all context associated with a loaded object or session to be removed from TPM memory. + + @param[in] FlushHandle The handle of the item to flush. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2FlushContext ( + IN TPMI_DH_CONTEXT FlushHandle + ) +{ + EFI_STATUS Status; + TPM2_FLUSH_CONTEXT_COMMAND SendBuffer; + TPM2_FLUSH_CONTEXT_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_FlushContext); + + SendBuffer.FlushHandle = SwapBytes32 (FlushHandle); + + SendBufferSize = (UINT32) sizeof (SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2FlushContext - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2FlushContext - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c new file mode 100644 index 00000000..442aaf25 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c @@ -0,0 +1,213 @@ +/** @file + Implement TPM2 DictionaryAttack related command. + +Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_LOCKOUT LockHandle; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; +} TPM2_DICTIONARY_ATTACK_LOCK_RESET_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_DICTIONARY_ATTACK_LOCK_RESET_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_LOCKOUT LockHandle; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; + UINT32 NewMaxTries; + UINT32 NewRecoveryTime; + UINT32 LockoutRecovery; +} TPM2_DICTIONARY_ATTACK_PARAMETERS_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_DICTIONARY_ATTACK_PARAMETERS_RESPONSE; + +#pragma pack() + +/** + This command cancels the effect of a TPM lockout due to a number of successive authorization failures. + If this command is properly authorized, the lockout counter is set to zero. + + @param[in] LockHandle TPM_RH_LOCKOUT + @param[in] AuthSession Auth Session context + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2DictionaryAttackLockReset ( + IN TPMI_RH_LOCKOUT LockHandle, + IN TPMS_AUTH_COMMAND *AuthSession + ) +{ + EFI_STATUS Status; + TPM2_DICTIONARY_ATTACK_LOCK_RESET_COMMAND SendBuffer; + TPM2_DICTIONARY_ATTACK_LOCK_RESET_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_DictionaryAttackLockReset); + + SendBuffer.LockHandle = SwapBytes32 (LockHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackLockReset - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackLockReset - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} + +/** + This command cancels the effect of a TPM lockout due to a number of successive authorization failures. + If this command is properly authorized, the lockout counter is set to zero. + + @param[in] LockHandle TPM_RH_LOCKOUT + @param[in] AuthSession Auth Session context + @param[in] NewMaxTries Count of authorization failures before the lockout is imposed + @param[in] NewRecoveryTime Time in seconds before the authorization failure count is automatically decremented + @param[in] LockoutRecovery Time in seconds after a lockoutAuth failure before use of lockoutAuth is allowed + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2DictionaryAttackParameters ( + IN TPMI_RH_LOCKOUT LockHandle, + IN TPMS_AUTH_COMMAND *AuthSession, + IN UINT32 NewMaxTries, + IN UINT32 NewRecoveryTime, + IN UINT32 LockoutRecovery + ) +{ + EFI_STATUS Status; + TPM2_DICTIONARY_ATTACK_PARAMETERS_COMMAND SendBuffer; + TPM2_DICTIONARY_ATTACK_PARAMETERS_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_DictionaryAttackParameters); + + SendBuffer.LockHandle = SwapBytes32 (LockHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + // + // Real data + // + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(NewMaxTries)); + Buffer += sizeof(UINT32); + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(NewRecoveryTime)); + Buffer += sizeof(UINT32); + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(LockoutRecovery)); + Buffer += sizeof(UINT32); + + SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackParameters - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackParameters - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBufferSize, sizeof(SendBufferSize)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2EnhancedAuthorization.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2EnhancedAuthorization.c new file mode 100644 index 00000000..f28bd0b6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2EnhancedAuthorization.c @@ -0,0 +1,396 @@ +/** @file + Implement TPM2 EnhancedAuthorization related command. + +Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_DH_ENTITY AuthHandle; + TPMI_SH_POLICY PolicySession; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; + TPM2B_NONCE NonceTPM; + TPM2B_DIGEST CpHashA; + TPM2B_NONCE PolicyRef; + INT32 Expiration; +} TPM2_POLICY_SECRET_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPM2B_TIMEOUT Timeout; + TPMT_TK_AUTH PolicyTicket; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_POLICY_SECRET_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_SH_POLICY PolicySession; + TPML_DIGEST HashList; +} TPM2_POLICY_OR_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; +} TPM2_POLICY_OR_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_SH_POLICY PolicySession; + TPM_CC Code; +} TPM2_POLICY_COMMAND_CODE_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; +} TPM2_POLICY_COMMAND_CODE_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_SH_POLICY PolicySession; +} TPM2_POLICY_GET_DIGEST_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + TPM2B_DIGEST PolicyHash; +} TPM2_POLICY_GET_DIGEST_RESPONSE; + +#pragma pack() + +/** + This command includes a secret-based authorization to a policy. + The caller proves knowledge of the secret value using an authorization + session using the authValue associated with authHandle. + + @param[in] AuthHandle Handle for an entity providing the authorization + @param[in] PolicySession Handle for the policy session being extended. + @param[in] AuthSession Auth Session context + @param[in] NonceTPM The policy nonce for the session. + @param[in] CpHashA Digest of the command parameters to which this authorization is limited. + @param[in] PolicyRef A reference to a policy relating to the authorization. + @param[in] Expiration Time when authorization will expire, measured in seconds from the time that nonceTPM was generated. + @param[out] Timeout Time value used to indicate to the TPM when the ticket expires. + @param[out] PolicyTicket A ticket that includes a value indicating when the authorization expires. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2PolicySecret ( + IN TPMI_DH_ENTITY AuthHandle, + IN TPMI_SH_POLICY PolicySession, + IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL + IN TPM2B_NONCE *NonceTPM, + IN TPM2B_DIGEST *CpHashA, + IN TPM2B_NONCE *PolicyRef, + IN INT32 Expiration, + OUT TPM2B_TIMEOUT *Timeout, + OUT TPMT_TK_AUTH *PolicyTicket + ) +{ + EFI_STATUS Status; + TPM2_POLICY_SECRET_COMMAND SendBuffer; + TPM2_POLICY_SECRET_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicySecret); + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + SendBuffer.PolicySession = SwapBytes32 (PolicySession); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + // + // Real data + // + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(NonceTPM->size)); + Buffer += sizeof(UINT16); + CopyMem (Buffer, NonceTPM->buffer, NonceTPM->size); + Buffer += NonceTPM->size; + + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(CpHashA->size)); + Buffer += sizeof(UINT16); + CopyMem (Buffer, CpHashA->buffer, CpHashA->size); + Buffer += CpHashA->size; + + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(PolicyRef->size)); + Buffer += sizeof(UINT16); + CopyMem (Buffer, PolicyRef->buffer, PolicyRef->size); + Buffer += PolicyRef->size; + + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32((UINT32)Expiration)); + Buffer += sizeof(UINT32); + + SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2PolicySecret - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2PolicySecret - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + // + // Return the response + // + Buffer = (UINT8 *)&RecvBuffer.Timeout; + Timeout->size = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer)); + if (Timeout->size > sizeof(UINT64)) { + DEBUG ((DEBUG_ERROR, "Tpm2PolicySecret - Timeout->size error %x\n", Timeout->size)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + Buffer += sizeof(UINT16); + CopyMem (Timeout->buffer, Buffer, Timeout->size); + + PolicyTicket->tag = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + PolicyTicket->hierarchy = SwapBytes32(ReadUnaligned32 ((UINT32 *)Buffer)); + Buffer += sizeof(UINT32); + PolicyTicket->digest.size = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + if (PolicyTicket->digest.size > sizeof(TPMU_HA)) { + DEBUG ((DEBUG_ERROR, "Tpm2PolicySecret - digest.size error %x\n", PolicyTicket->digest.size)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + CopyMem (PolicyTicket->digest.buffer, Buffer, PolicyTicket->digest.size); + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} + +/** + This command allows options in authorizations without requiring that the TPM evaluate all of the options. + If a policy may be satisfied by different sets of conditions, the TPM need only evaluate one set that + satisfies the policy. This command will indicate that one of the required sets of conditions has been + satisfied. + + @param[in] PolicySession Handle for the policy session being extended. + @param[in] HashList the list of hashes to check for a match. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2PolicyOR ( + IN TPMI_SH_POLICY PolicySession, + IN TPML_DIGEST *HashList + ) +{ + EFI_STATUS Status; + TPM2_POLICY_OR_COMMAND SendBuffer; + TPM2_POLICY_OR_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINTN Index; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyOR); + + SendBuffer.PolicySession = SwapBytes32 (PolicySession); + Buffer = (UINT8 *)&SendBuffer.HashList; + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (HashList->count)); + Buffer += sizeof(UINT32); + for (Index = 0; Index < HashList->count; Index++) { + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (HashList->digests[Index].size)); + Buffer += sizeof(UINT16); + CopyMem (Buffer, HashList->digests[Index].buffer, HashList->digests[Index].size); + Buffer += HashList->digests[Index].size; + } + + SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2PolicyOR - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2PolicyOR - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + This command indicates that the authorization will be limited to a specific command code. + + @param[in] PolicySession Handle for the policy session being extended. + @param[in] Code The allowed commandCode. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2PolicyCommandCode ( + IN TPMI_SH_POLICY PolicySession, + IN TPM_CC Code + ) +{ + EFI_STATUS Status; + TPM2_POLICY_COMMAND_CODE_COMMAND SendBuffer; + TPM2_POLICY_COMMAND_CODE_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyCommandCode); + + SendBuffer.PolicySession = SwapBytes32 (PolicySession); + SendBuffer.Code = SwapBytes32 (Code); + + SendBufferSize = (UINT32) sizeof (SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2PolicyCommandCode - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2PolicyCommandCode - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + This command returns the current policyDigest of the session. This command allows the TPM + to be used to perform the actions required to precompute the authPolicy for an object. + + @param[in] PolicySession Handle for the policy session. + @param[out] PolicyHash the current value of the policyHash of policySession. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2PolicyGetDigest ( + IN TPMI_SH_POLICY PolicySession, + OUT TPM2B_DIGEST *PolicyHash + ) +{ + EFI_STATUS Status; + TPM2_POLICY_GET_DIGEST_COMMAND SendBuffer; + TPM2_POLICY_GET_DIGEST_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyGetDigest); + + SendBuffer.PolicySession = SwapBytes32 (PolicySession); + + SendBufferSize = (UINT32) sizeof (SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2PolicyGetDigest - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2PolicyGetDigest - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Return the response + // + PolicyHash->size = SwapBytes16 (RecvBuffer.PolicyHash.size); + if (PolicyHash->size > sizeof(TPMU_HA)) { + DEBUG ((DEBUG_ERROR, "Tpm2PolicyGetDigest - PolicyHash->size error %x\n", PolicyHash->size)); + return EFI_DEVICE_ERROR; + } + + CopyMem (PolicyHash->buffer, &RecvBuffer.PolicyHash.buffer, PolicyHash->size); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c new file mode 100644 index 00000000..510ad426 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c @@ -0,0 +1,344 @@ +/** @file + Implement TPM2 help. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +typedef struct { + TPMI_ALG_HASH HashAlgo; + UINT16 HashSize; + UINT32 HashMask; +} INTERNAL_HASH_INFO; + +STATIC INTERNAL_HASH_INFO mHashInfo[] = { + {TPM_ALG_SHA1, SHA1_DIGEST_SIZE, HASH_ALG_SHA1}, + {TPM_ALG_SHA256, SHA256_DIGEST_SIZE, HASH_ALG_SHA256}, + {TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE, HASH_ALG_SM3_256}, + {TPM_ALG_SHA384, SHA384_DIGEST_SIZE, HASH_ALG_SHA384}, + {TPM_ALG_SHA512, SHA512_DIGEST_SIZE, HASH_ALG_SHA512}, +}; + +/** + Return size of digest. + + @param[in] HashAlgo Hash algorithm + + @return size of digest +**/ +UINT16 +EFIAPI +GetHashSizeFromAlgo ( + IN TPMI_ALG_HASH HashAlgo + ) +{ + UINTN Index; + + for (Index = 0; Index < sizeof(mHashInfo)/sizeof(mHashInfo[0]); Index++) { + if (mHashInfo[Index].HashAlgo == HashAlgo) { + return mHashInfo[Index].HashSize; + } + } + return 0; +} + +/** + Get hash mask from algorithm. + + @param[in] HashAlgo Hash algorithm + + @return Hash mask +**/ +UINT32 +EFIAPI +GetHashMaskFromAlgo ( + IN TPMI_ALG_HASH HashAlgo + ) +{ + UINTN Index; + + for (Index = 0; Index < sizeof(mHashInfo)/sizeof(mHashInfo[0]); Index++) { + if (mHashInfo[Index].HashAlgo == HashAlgo) { + return mHashInfo[Index].HashMask; + } + } + return 0; +} + +/** + Copy AuthSessionIn to TPM2 command buffer. + + @param [in] AuthSessionIn Input AuthSession data + @param [out] AuthSessionOut Output AuthSession data in TPM2 command buffer + + @return AuthSession size +**/ +UINT32 +EFIAPI +CopyAuthSessionCommand ( + IN TPMS_AUTH_COMMAND *AuthSessionIn, OPTIONAL + OUT UINT8 *AuthSessionOut + ) +{ + UINT8 *Buffer; + + Buffer = (UINT8 *)AuthSessionOut; + + // + // Add in Auth session + // + if (AuthSessionIn != NULL) { + // sessionHandle + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(AuthSessionIn->sessionHandle)); + Buffer += sizeof(UINT32); + + // nonce + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthSessionIn->nonce.size)); + Buffer += sizeof(UINT16); + + CopyMem (Buffer, AuthSessionIn->nonce.buffer, AuthSessionIn->nonce.size); + Buffer += AuthSessionIn->nonce.size; + + // sessionAttributes + *(UINT8 *)Buffer = *(UINT8 *)&AuthSessionIn->sessionAttributes; + Buffer++; + + // hmac + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthSessionIn->hmac.size)); + Buffer += sizeof(UINT16); + + CopyMem (Buffer, AuthSessionIn->hmac.buffer, AuthSessionIn->hmac.size); + Buffer += AuthSessionIn->hmac.size; + } else { + // sessionHandle + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(TPM_RS_PW)); + Buffer += sizeof(UINT32); + + // nonce = nullNonce + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0)); + Buffer += sizeof(UINT16); + + // sessionAttributes = 0 + *(UINT8 *)Buffer = 0x00; + Buffer++; + + // hmac = nullAuth + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0)); + Buffer += sizeof(UINT16); + } + + return (UINT32)((UINTN)Buffer - (UINTN)AuthSessionOut); +} + +/** + Copy AuthSessionIn from TPM2 response buffer. + + @param [in] AuthSessionIn Input AuthSession data in TPM2 response buffer + @param [out] AuthSessionOut Output AuthSession data + + @return 0 copy failed + else AuthSession size +**/ +UINT32 +EFIAPI +CopyAuthSessionResponse ( + IN UINT8 *AuthSessionIn, + OUT TPMS_AUTH_RESPONSE *AuthSessionOut OPTIONAL + ) +{ + UINT8 *Buffer; + TPMS_AUTH_RESPONSE LocalAuthSessionOut; + + if (AuthSessionOut == NULL) { + AuthSessionOut = &LocalAuthSessionOut; + } + + Buffer = (UINT8 *)AuthSessionIn; + + // nonce + AuthSessionOut->nonce.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + if (AuthSessionOut->nonce.size > sizeof(TPMU_HA)) { + DEBUG ((DEBUG_ERROR, "CopyAuthSessionResponse - nonce.size error %x\n", AuthSessionOut->nonce.size)); + return 0; + } + + CopyMem (AuthSessionOut->nonce.buffer, Buffer, AuthSessionOut->nonce.size); + Buffer += AuthSessionOut->nonce.size; + + // sessionAttributes + *(UINT8 *)&AuthSessionOut->sessionAttributes = *(UINT8 *)Buffer; + Buffer++; + + // hmac + AuthSessionOut->hmac.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + if (AuthSessionOut->hmac.size > sizeof(TPMU_HA)) { + DEBUG ((DEBUG_ERROR, "CopyAuthSessionResponse - hmac.size error %x\n", AuthSessionOut->hmac.size)); + return 0; + } + + CopyMem (AuthSessionOut->hmac.buffer, Buffer, AuthSessionOut->hmac.size); + Buffer += AuthSessionOut->hmac.size; + + return (UINT32)((UINTN)Buffer - (UINTN)AuthSessionIn); +} + +/** + Return if hash alg is supported in HashAlgorithmMask. + + @param HashAlg Hash algorithm to be checked. + @param HashAlgorithmMask Bitfield of allowed hash algorithms. + + @retval TRUE Hash algorithm is supported. + @retval FALSE Hash algorithm is not supported. +**/ +BOOLEAN +EFIAPI +IsHashAlgSupportedInHashAlgorithmMask( + IN TPMI_ALG_HASH HashAlg, + IN UINT32 HashAlgorithmMask + ) +{ + switch (HashAlg) { + case TPM_ALG_SHA1: + if ((HashAlgorithmMask & HASH_ALG_SHA1) != 0) { + return TRUE; + } + break; + case TPM_ALG_SHA256: + if ((HashAlgorithmMask & HASH_ALG_SHA256) != 0) { + return TRUE; + } + break; + case TPM_ALG_SHA384: + if ((HashAlgorithmMask & HASH_ALG_SHA384) != 0) { + return TRUE; + } + break; + case TPM_ALG_SHA512: + if ((HashAlgorithmMask & HASH_ALG_SHA512) != 0) { + return TRUE; + } + break; + case TPM_ALG_SM3_256: + if ((HashAlgorithmMask & HASH_ALG_SM3_256) != 0) { + return TRUE; + } + break; + } + + return FALSE; +} + +/** + Copy TPML_DIGEST_VALUES into a buffer + + @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary. + @param[in] DigestList TPML_DIGEST_VALUES to be copied. + @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy. + + @return The end of buffer to hold TPML_DIGEST_VALUES. +**/ +VOID * +EFIAPI +CopyDigestListToBuffer ( + IN OUT VOID *Buffer, + IN TPML_DIGEST_VALUES *DigestList, + IN UINT32 HashAlgorithmMask + ) +{ + UINTN Index; + UINT16 DigestSize; + UINT32 DigestListCount; + UINT32 *DigestListCountPtr; + + DigestListCountPtr = (UINT32 *) Buffer; + DigestListCount = 0; + Buffer = (UINT8 *)Buffer + sizeof(DigestList->count); + for (Index = 0; Index < DigestList->count; Index++) { + if (!IsHashAlgSupportedInHashAlgorithmMask(DigestList->digests[Index].hashAlg, HashAlgorithmMask)) { + DEBUG ((EFI_D_ERROR, "WARNING: TPM2 Event log has HashAlg unsupported by PCR bank (0x%x)\n", DigestList->digests[Index].hashAlg)); + continue; + } + CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof(DigestList->digests[Index].hashAlg)); + Buffer = (UINT8 *)Buffer + sizeof(DigestList->digests[Index].hashAlg); + DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg); + CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize); + Buffer = (UINT8 *)Buffer + DigestSize; + DigestListCount++; + } + WriteUnaligned32 (DigestListCountPtr, DigestListCount); + + return Buffer; +} + +/** + Get TPML_DIGEST_VALUES data size. + + @param[in] DigestList TPML_DIGEST_VALUES data. + + @return TPML_DIGEST_VALUES data size. +**/ +UINT32 +EFIAPI +GetDigestListSize ( + IN TPML_DIGEST_VALUES *DigestList + ) +{ + UINTN Index; + UINT16 DigestSize; + UINT32 TotalSize; + + TotalSize = sizeof(DigestList->count); + for (Index = 0; Index < DigestList->count; Index++) { + DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg); + TotalSize += sizeof(DigestList->digests[Index].hashAlg) + DigestSize; + } + + return TotalSize; +} + +/** + This function get digest from digest list. + + @param[in] HashAlg Digest algorithm + @param[in] DigestList Digest list + @param[out] Digest Digest + + @retval EFI_SUCCESS Digest is found and returned. + @retval EFI_NOT_FOUND Digest is not found. +**/ +EFI_STATUS +EFIAPI +GetDigestFromDigestList ( + IN TPMI_ALG_HASH HashAlg, + IN TPML_DIGEST_VALUES *DigestList, + OUT VOID *Digest + ) +{ + UINTN Index; + UINT16 DigestSize; + + DigestSize = GetHashSizeFromAlgo (HashAlg); + for (Index = 0; Index < DigestList->count; Index++) { + if (DigestList->digests[Index].hashAlg == HashAlg) { + CopyMem ( + Digest, + &DigestList->digests[Index].digest, + DigestSize + ); + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c new file mode 100644 index 00000000..039bc503 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c @@ -0,0 +1,797 @@ +/** @file + Implement TPM2 Hierarchy related command. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_HIERARCHY_AUTH AuthHandle; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; + TPM2B_DIGEST AuthPolicy; + TPMI_ALG_HASH HashAlg; +} TPM2_SET_PRIMARY_POLICY_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_SET_PRIMARY_POLICY_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_CLEAR AuthHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSession; +} TPM2_CLEAR_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_CLEAR_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_CLEAR AuthHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSession; + TPMI_YES_NO Disable; +} TPM2_CLEAR_CONTROL_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_CLEAR_CONTROL_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_HIERARCHY_AUTH AuthHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSession; + TPM2B_AUTH NewAuth; +} TPM2_HIERARCHY_CHANGE_AUTH_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_HIERARCHY_CHANGE_AUTH_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_PLATFORM AuthHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSession; +} TPM2_CHANGE_EPS_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_CHANGE_EPS_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_PLATFORM AuthHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSession; +} TPM2_CHANGE_PPS_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_CHANGE_PPS_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_HIERARCHY AuthHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSession; + TPMI_RH_HIERARCHY Hierarchy; + TPMI_YES_NO State; +} TPM2_HIERARCHY_CONTROL_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_HIERARCHY_CONTROL_RESPONSE; + +#pragma pack() + +/** + This command allows setting of the authorization policy for the platform hierarchy (platformPolicy), the + storage hierarchy (ownerPolicy), and and the endorsement hierarchy (endorsementPolicy). + + @param[in] AuthHandle TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} parameters to be validated + @param[in] AuthSession Auth Session context + @param[in] AuthPolicy An authorization policy hash + @param[in] HashAlg The hash algorithm to use for the policy + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2SetPrimaryPolicy ( + IN TPMI_RH_HIERARCHY_AUTH AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession, + IN TPM2B_DIGEST *AuthPolicy, + IN TPMI_ALG_HASH HashAlg + ) +{ + EFI_STATUS Status; + TPM2_SET_PRIMARY_POLICY_COMMAND SendBuffer; + TPM2_SET_PRIMARY_POLICY_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_SetPrimaryPolicy); + + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + // + // Real data + // + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(AuthPolicy->size)); + Buffer += sizeof(UINT16); + CopyMem (Buffer, AuthPolicy->buffer, AuthPolicy->size); + Buffer += AuthPolicy->size; + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(HashAlg)); + Buffer += sizeof(UINT16); + + SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2SetPrimaryPolicy - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2SetPrimaryPolicy - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} + +/** + This command removes all TPM context associated with a specific Owner. + + @param[in] AuthHandle TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} + @param[in] AuthSession Auth Session context + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2Clear ( + IN TPMI_RH_CLEAR AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL + ) +{ + EFI_STATUS Status; + TPM2_CLEAR_COMMAND Cmd; + TPM2_CLEAR_RESPONSE Res; + UINT32 ResultBufSize; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_Clear); + Cmd.AuthHandle = SwapBytes32(AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&Cmd.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + goto Done; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Clear: Failed ExecuteCommand: Buffer Too Small\r\n")); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Clear: Response size too large! %d\r\n", RespSize)); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Clear: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + // + // Unmarshal the response + // + + // None +Done: + // + // Clear AuthSession Content + // + ZeroMem (&Cmd, sizeof(Cmd)); + ZeroMem (&Res, sizeof(Res)); + return Status; +} + +/** + Disables and enables the execution of TPM2_Clear(). + + @param[in] AuthHandle TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP} + @param[in] AuthSession Auth Session context + @param[in] Disable YES if the disableOwnerClear flag is to be SET, + NO if the flag is to be CLEAR. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2ClearControl ( + IN TPMI_RH_CLEAR AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL + IN TPMI_YES_NO Disable + ) +{ + EFI_STATUS Status; + TPM2_CLEAR_CONTROL_COMMAND Cmd; + TPM2_CLEAR_CONTROL_RESPONSE Res; + UINT32 ResultBufSize; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_ClearControl); + Cmd.AuthHandle = SwapBytes32(AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&Cmd.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + // disable + *(UINT8 *)Buffer = Disable; + Buffer++; + + CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + goto Done; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "ClearControl: Failed ExecuteCommand: Buffer Too Small\r\n")); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "ClearControl: Response size too large! %d\r\n", RespSize)); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "ClearControl: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + // + // Unmarshal the response + // + + // None +Done: + // + // Clear AuthSession Content + // + ZeroMem (&Cmd, sizeof(Cmd)); + ZeroMem (&Res, sizeof(Res)); + return Status; +} + +/** + This command allows the authorization secret for a hierarchy or lockout to be changed using the current + authorization value as the command authorization. + + @param[in] AuthHandle TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + @param[in] AuthSession Auth Session context + @param[in] NewAuth New authorization secret + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2HierarchyChangeAuth ( + IN TPMI_RH_HIERARCHY_AUTH AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession, + IN TPM2B_AUTH *NewAuth + ) +{ + EFI_STATUS Status; + TPM2_HIERARCHY_CHANGE_AUTH_COMMAND Cmd; + TPM2_HIERARCHY_CHANGE_AUTH_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + UINT8 *ResultBuf; + UINT32 ResultBufSize; + + // + // Construct command + // + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd)); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_HierarchyChangeAuth); + Cmd.AuthHandle = SwapBytes32(AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&Cmd.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + // New Authorization size + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(NewAuth->size)); + Buffer += sizeof(UINT16); + + // New Authorization + CopyMem(Buffer, NewAuth->buffer, NewAuth->size); + Buffer += NewAuth->size; + + CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + ResultBuf = (UINT8 *) &Res; + ResultBufSize = sizeof(Res); + + // + // Call the TPM + // + Status = Tpm2SubmitCommand ( + CmdSize, + (UINT8 *)&Cmd, + &ResultBufSize, + ResultBuf + ); + if (EFI_ERROR(Status)) { + goto Done; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "HierarchyChangeAuth: Failed ExecuteCommand: Buffer Too Small\r\n")); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "HierarchyChangeAuth: Response size too large! %d\r\n", RespSize)); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG((EFI_D_ERROR,"HierarchyChangeAuth: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&Cmd, sizeof(Cmd)); + ZeroMem (&Res, sizeof(Res)); + return Status; +} + +/** + This replaces the current EPS with a value from the RNG and sets the Endorsement hierarchy controls to + their default initialization values. + + @param[in] AuthHandle TPM_RH_PLATFORM+{PP} + @param[in] AuthSession Auth Session context + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2ChangeEPS ( + IN TPMI_RH_PLATFORM AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession + ) +{ + EFI_STATUS Status; + TPM2_CHANGE_EPS_COMMAND Cmd; + TPM2_CHANGE_EPS_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + UINT8 *ResultBuf; + UINT32 ResultBufSize; + + // + // Construct command + // + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd)); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_ChangeEPS); + Cmd.AuthHandle = SwapBytes32(AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&Cmd.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + ResultBuf = (UINT8 *) &Res; + ResultBufSize = sizeof(Res); + + // + // Call the TPM + // + Status = Tpm2SubmitCommand ( + CmdSize, + (UINT8 *)&Cmd, + &ResultBufSize, + ResultBuf + ); + if (EFI_ERROR(Status)) { + goto Done; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "ChangeEPS: Failed ExecuteCommand: Buffer Too Small\r\n")); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "ChangeEPS: Response size too large! %d\r\n", RespSize)); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG((EFI_D_ERROR,"ChangeEPS: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&Cmd, sizeof(Cmd)); + ZeroMem (&Res, sizeof(Res)); + return Status; +} + +/** + This replaces the current PPS with a value from the RNG and sets platformPolicy to the default + initialization value (the Empty Buffer). + + @param[in] AuthHandle TPM_RH_PLATFORM+{PP} + @param[in] AuthSession Auth Session context + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2ChangePPS ( + IN TPMI_RH_PLATFORM AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession + ) +{ + EFI_STATUS Status; + TPM2_CHANGE_PPS_COMMAND Cmd; + TPM2_CHANGE_PPS_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + UINT8 *ResultBuf; + UINT32 ResultBufSize; + + // + // Construct command + // + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd)); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_ChangePPS); + Cmd.AuthHandle = SwapBytes32(AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&Cmd.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + ResultBuf = (UINT8 *) &Res; + ResultBufSize = sizeof(Res); + + // + // Call the TPM + // + Status = Tpm2SubmitCommand ( + CmdSize, + (UINT8 *)&Cmd, + &ResultBufSize, + ResultBuf + ); + if (EFI_ERROR(Status)) { + goto Done; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "ChangePPS: Failed ExecuteCommand: Buffer Too Small\r\n")); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "ChangePPS: Response size too large! %d\r\n", RespSize)); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG((EFI_D_ERROR,"ChangePPS: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&Cmd, sizeof(Cmd)); + ZeroMem (&Res, sizeof(Res)); + return Status; +} + +/** + This command enables and disables use of a hierarchy. + + @param[in] AuthHandle TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} + @param[in] AuthSession Auth Session context + @param[in] Hierarchy Hierarchy of the enable being modified + @param[in] State YES if the enable should be SET, + NO if the enable should be CLEAR + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2HierarchyControl ( + IN TPMI_RH_HIERARCHY AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession, + IN TPMI_RH_HIERARCHY Hierarchy, + IN TPMI_YES_NO State + ) +{ + EFI_STATUS Status; + TPM2_HIERARCHY_CONTROL_COMMAND Cmd; + TPM2_HIERARCHY_CONTROL_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + UINT8 *ResultBuf; + UINT32 ResultBufSize; + + // + // Construct command + // + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd)); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_HierarchyControl); + Cmd.AuthHandle = SwapBytes32(AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&Cmd.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(Hierarchy)); + Buffer += sizeof(UINT32); + + *(UINT8 *)Buffer = State; + Buffer++; + + CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + ResultBuf = (UINT8 *) &Res; + ResultBufSize = sizeof(Res); + + // + // Call the TPM + // + Status = Tpm2SubmitCommand ( + CmdSize, + (UINT8 *)&Cmd, + &ResultBufSize, + ResultBuf + ); + if (EFI_ERROR(Status)) { + goto Done; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "HierarchyControl: Failed ExecuteCommand: Buffer Too Small\r\n")); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "HierarchyControl: Response size too large! %d\r\n", RespSize)); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG((EFI_D_ERROR,"HierarchyControl: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&Cmd, sizeof(Cmd)); + ZeroMem (&Res, sizeof(Res)); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c new file mode 100644 index 00000000..4b51fb98 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c @@ -0,0 +1,689 @@ +/** @file + Implement TPM2 Integrity related command. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_DH_PCR PcrHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSessionPcr; + TPML_DIGEST_VALUES DigestValues; +} TPM2_PCR_EXTEND_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPMS_AUTH_RESPONSE AuthSessionPcr; +} TPM2_PCR_EXTEND_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_DH_PCR PcrHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSessionPcr; + TPM2B_EVENT EventData; +} TPM2_PCR_EVENT_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPML_DIGEST_VALUES Digests; + TPMS_AUTH_RESPONSE AuthSessionPcr; +} TPM2_PCR_EVENT_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPML_PCR_SELECTION PcrSelectionIn; +} TPM2_PCR_READ_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 PcrUpdateCounter; + TPML_PCR_SELECTION PcrSelectionOut; + TPML_DIGEST PcrValues; +} TPM2_PCR_READ_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_PLATFORM AuthHandle; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; + TPML_PCR_SELECTION PcrAllocation; +} TPM2_PCR_ALLOCATE_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMI_YES_NO AllocationSuccess; + UINT32 MaxPCR; + UINT32 SizeNeeded; + UINT32 SizeAvailable; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_PCR_ALLOCATE_RESPONSE; + +#pragma pack() + +/** + This command is used to cause an update to the indicated PCR. + The digests parameter contains one or more tagged digest value identified by an algorithm ID. + For each digest, the PCR associated with pcrHandle is Extended into the bank identified by the tag (hashAlg). + + @param[in] PcrHandle Handle of the PCR + @param[in] Digests List of tagged digest values to be extended + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2PcrExtend ( + IN TPMI_DH_PCR PcrHandle, + IN TPML_DIGEST_VALUES *Digests + ) +{ + EFI_STATUS Status; + TPM2_PCR_EXTEND_COMMAND Cmd; + TPM2_PCR_EXTEND_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT32 ResultBufSize; + UINT8 *Buffer; + UINTN Index; + UINT32 SessionInfoSize; + UINT16 DigestSize; + + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_PCR_Extend); + Cmd.PcrHandle = SwapBytes32(PcrHandle); + + + // + // Add in Auth session + // + Buffer = (UINT8 *)&Cmd.AuthSessionPcr; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (NULL, Buffer); + Buffer += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + //Digest Count + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(Digests->count)); + Buffer += sizeof(UINT32); + + //Digest + for (Index = 0; Index < Digests->count; Index++) { + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(Digests->digests[Index].hashAlg)); + Buffer += sizeof(UINT16); + DigestSize = GetHashSizeFromAlgo (Digests->digests[Index].hashAlg); + if (DigestSize == 0) { + DEBUG ((EFI_D_ERROR, "Unknown hash algorithm %d\r\n", Digests->digests[Index].hashAlg)); + return EFI_DEVICE_ERROR; + } + CopyMem( + Buffer, + &Digests->digests[Index].digest, + DigestSize + ); + Buffer += DigestSize; + } + + CmdSize = (UINT32)((UINTN)Buffer - (UINTN)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + return Status; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrExtend: Failed ExecuteCommand: Buffer Too Small\r\n")); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrExtend: Response size too large! %d\r\n", RespSize)); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrExtend: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Unmarshal the response + // + + // None + + return EFI_SUCCESS; +} + +/** + This command is used to cause an update to the indicated PCR. + The data in eventData is hashed using the hash algorithm associated with each bank in which the + indicated PCR has been allocated. After the data is hashed, the digests list is returned. If the pcrHandle + references an implemented PCR and not TPM_ALG_NULL, digests list is processed as in + TPM2_PCR_Extend(). + A TPM shall support an Event.size of zero through 1,024 inclusive. + + @param[in] PcrHandle Handle of the PCR + @param[in] EventData Event data in sized buffer + @param[out] Digests List of digest + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2PcrEvent ( + IN TPMI_DH_PCR PcrHandle, + IN TPM2B_EVENT *EventData, + OUT TPML_DIGEST_VALUES *Digests + ) +{ + EFI_STATUS Status; + TPM2_PCR_EVENT_COMMAND Cmd; + TPM2_PCR_EVENT_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT32 ResultBufSize; + UINT8 *Buffer; + UINTN Index; + UINT32 SessionInfoSize; + UINT16 DigestSize; + + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_PCR_Event); + Cmd.PcrHandle = SwapBytes32(PcrHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&Cmd.AuthSessionPcr; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (NULL, Buffer); + Buffer += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + // Event + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(EventData->size)); + Buffer += sizeof(UINT16); + + CopyMem (Buffer, EventData->buffer, EventData->size); + Buffer += EventData->size; + + CmdSize = (UINT32)((UINTN)Buffer - (UINTN)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + return Status; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrEvent: Failed ExecuteCommand: Buffer Too Small\r\n")); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrEvent: Response size too large! %d\r\n", RespSize)); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrEvent: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Unmarshal the response + // + Buffer = (UINT8 *)&Res.Digests; + + Digests->count = SwapBytes32 (ReadUnaligned32 ((UINT32 *)Buffer)); + if (Digests->count > HASH_COUNT) { + DEBUG ((DEBUG_ERROR, "Tpm2PcrEvent - Digests->count error %x\n", Digests->count)); + return EFI_DEVICE_ERROR; + } + + Buffer += sizeof(UINT32); + for (Index = 0; Index < Digests->count; Index++) { + Digests->digests[Index].hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + DigestSize = GetHashSizeFromAlgo (Digests->digests[Index].hashAlg); + if (DigestSize == 0) { + DEBUG ((EFI_D_ERROR, "Unknown hash algorithm %d\r\n", Digests->digests[Index].hashAlg)); + return EFI_DEVICE_ERROR; + } + CopyMem( + &Digests->digests[Index].digest, + Buffer, + DigestSize + ); + Buffer += DigestSize; + } + + return EFI_SUCCESS; +} + +/** + This command returns the values of all PCR specified in pcrSelect. + + @param[in] PcrSelectionIn The selection of PCR to read. + @param[out] PcrUpdateCounter The current value of the PCR update counter. + @param[out] PcrSelectionOut The PCR in the returned list. + @param[out] PcrValues The contents of the PCR indicated in pcrSelect. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2PcrRead ( + IN TPML_PCR_SELECTION *PcrSelectionIn, + OUT UINT32 *PcrUpdateCounter, + OUT TPML_PCR_SELECTION *PcrSelectionOut, + OUT TPML_DIGEST *PcrValues + ) +{ + EFI_STATUS Status; + TPM2_PCR_READ_COMMAND SendBuffer; + TPM2_PCR_READ_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINTN Index; + TPML_DIGEST *PcrValuesOut; + TPM2B_DIGEST *Digests; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PCR_Read); + + SendBuffer.PcrSelectionIn.count = SwapBytes32(PcrSelectionIn->count); + for (Index = 0; Index < PcrSelectionIn->count; Index++) { + SendBuffer.PcrSelectionIn.pcrSelections[Index].hash = SwapBytes16(PcrSelectionIn->pcrSelections[Index].hash); + SendBuffer.PcrSelectionIn.pcrSelections[Index].sizeofSelect = PcrSelectionIn->pcrSelections[Index].sizeofSelect; + CopyMem (&SendBuffer.PcrSelectionIn.pcrSelections[Index].pcrSelect, &PcrSelectionIn->pcrSelections[Index].pcrSelect, SendBuffer.PcrSelectionIn.pcrSelections[Index].sizeofSelect); + } + + SendBufferSize = sizeof(SendBuffer.Header) + sizeof(SendBuffer.PcrSelectionIn.count) + sizeof(SendBuffer.PcrSelectionIn.pcrSelections[0]) * PcrSelectionIn->count; + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_NOT_FOUND; + } + + // + // Return the response + // + + // + // PcrUpdateCounter + // + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER) + sizeof(RecvBuffer.PcrUpdateCounter)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + *PcrUpdateCounter = SwapBytes32(RecvBuffer.PcrUpdateCounter); + + // + // PcrSelectionOut + // + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER) + sizeof(RecvBuffer.PcrUpdateCounter) + sizeof(RecvBuffer.PcrSelectionOut.count)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + PcrSelectionOut->count = SwapBytes32(RecvBuffer.PcrSelectionOut.count); + if (PcrSelectionOut->count > HASH_COUNT) { + DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - PcrSelectionOut->count error %x\n", PcrSelectionOut->count)); + return EFI_DEVICE_ERROR; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER) + sizeof(RecvBuffer.PcrUpdateCounter) + sizeof(RecvBuffer.PcrSelectionOut.count) + sizeof(RecvBuffer.PcrSelectionOut.pcrSelections[0]) * PcrSelectionOut->count) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + for (Index = 0; Index < PcrSelectionOut->count; Index++) { + PcrSelectionOut->pcrSelections[Index].hash = SwapBytes16(RecvBuffer.PcrSelectionOut.pcrSelections[Index].hash); + PcrSelectionOut->pcrSelections[Index].sizeofSelect = RecvBuffer.PcrSelectionOut.pcrSelections[Index].sizeofSelect; + if (PcrSelectionOut->pcrSelections[Index].sizeofSelect > PCR_SELECT_MAX) { + return EFI_DEVICE_ERROR; + } + CopyMem (&PcrSelectionOut->pcrSelections[Index].pcrSelect, &RecvBuffer.PcrSelectionOut.pcrSelections[Index].pcrSelect, PcrSelectionOut->pcrSelections[Index].sizeofSelect); + } + + // + // PcrValues + // + PcrValuesOut = (TPML_DIGEST *)((UINT8 *)&RecvBuffer + sizeof (TPM2_RESPONSE_HEADER) + sizeof(RecvBuffer.PcrUpdateCounter) + sizeof(RecvBuffer.PcrSelectionOut.count) + sizeof(RecvBuffer.PcrSelectionOut.pcrSelections[0]) * PcrSelectionOut->count); + PcrValues->count = SwapBytes32(PcrValuesOut->count); + // + // The number of digests in list is not greater than 8 per TPML_DIGEST definition + // + if (PcrValues->count > 8) { + DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - PcrValues->count error %x\n", PcrValues->count)); + return EFI_DEVICE_ERROR; + } + Digests = PcrValuesOut->digests; + for (Index = 0; Index < PcrValues->count; Index++) { + PcrValues->digests[Index].size = SwapBytes16(Digests->size); + if (PcrValues->digests[Index].size > sizeof(TPMU_HA)) { + DEBUG ((DEBUG_ERROR, "Tpm2PcrRead - Digest.size error %x\n", PcrValues->digests[Index].size)); + return EFI_DEVICE_ERROR; + } + CopyMem (&PcrValues->digests[Index].buffer, &Digests->buffer, PcrValues->digests[Index].size); + Digests = (TPM2B_DIGEST *)((UINT8 *)Digests + sizeof(Digests->size) + PcrValues->digests[Index].size); + } + + return EFI_SUCCESS; +} + +/** + This command is used to set the desired PCR allocation of PCR and algorithms. + + @param[in] AuthHandle TPM_RH_PLATFORM+{PP} + @param[in] AuthSession Auth Session context + @param[in] PcrAllocation The requested allocation + @param[out] AllocationSuccess YES if the allocation succeeded + @param[out] MaxPCR maximum number of PCR that may be in a bank + @param[out] SizeNeeded number of octets required to satisfy the request + @param[out] SizeAvailable Number of octets available. Computed before the allocation + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2PcrAllocate ( + IN TPMI_RH_PLATFORM AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession, + IN TPML_PCR_SELECTION *PcrAllocation, + OUT TPMI_YES_NO *AllocationSuccess, + OUT UINT32 *MaxPCR, + OUT UINT32 *SizeNeeded, + OUT UINT32 *SizeAvailable + ) +{ + EFI_STATUS Status; + TPM2_PCR_ALLOCATE_COMMAND Cmd; + TPM2_PCR_ALLOCATE_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + UINT8 *ResultBuf; + UINT32 ResultBufSize; + UINTN Index; + + // + // Construct command + // + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd)); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_PCR_Allocate); + Cmd.AuthHandle = SwapBytes32(AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&Cmd.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + Cmd.AuthSessionSize = SwapBytes32(SessionInfoSize); + + // Count + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(PcrAllocation->count)); + Buffer += sizeof(UINT32); + for (Index = 0; Index < PcrAllocation->count; Index++) { + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(PcrAllocation->pcrSelections[Index].hash)); + Buffer += sizeof(UINT16); + *(UINT8 *)Buffer = PcrAllocation->pcrSelections[Index].sizeofSelect; + Buffer++; + CopyMem (Buffer, PcrAllocation->pcrSelections[Index].pcrSelect, PcrAllocation->pcrSelections[Index].sizeofSelect); + Buffer += PcrAllocation->pcrSelections[Index].sizeofSelect; + } + + CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + ResultBuf = (UINT8 *) &Res; + ResultBufSize = sizeof(Res); + + // + // Call the TPM + // + Status = Tpm2SubmitCommand ( + CmdSize, + (UINT8 *)&Cmd, + &ResultBufSize, + ResultBuf + ); + if (EFI_ERROR(Status)) { + goto Done; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrAllocate: Failed ExecuteCommand: Buffer Too Small\r\n")); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrAllocate: Response size too large! %d\r\n", RespSize)); + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG((EFI_D_ERROR,"Tpm2PcrAllocate: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + // + // Return the response + // + *AllocationSuccess = Res.AllocationSuccess; + *MaxPCR = SwapBytes32(Res.MaxPCR); + *SizeNeeded = SwapBytes32(Res.SizeNeeded); + *SizeAvailable = SwapBytes32(Res.SizeAvailable); + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&Cmd, sizeof(Cmd)); + ZeroMem (&Res, sizeof(Res)); + return Status; +} + +/** + Alloc PCR data. + + @param[in] PlatformAuth platform auth value. NULL means no platform auth change. + @param[in] SupportedPCRBanks Supported PCR banks + @param[in] PCRBanks PCR banks + + @retval EFI_SUCCESS Operation completed successfully. +**/ +EFI_STATUS +EFIAPI +Tpm2PcrAllocateBanks ( + IN TPM2B_AUTH *PlatformAuth, OPTIONAL + IN UINT32 SupportedPCRBanks, + IN UINT32 PCRBanks + ) +{ + EFI_STATUS Status; + TPMS_AUTH_COMMAND *AuthSession; + TPMS_AUTH_COMMAND LocalAuthSession; + TPML_PCR_SELECTION PcrAllocation; + TPMI_YES_NO AllocationSuccess; + UINT32 MaxPCR; + UINT32 SizeNeeded; + UINT32 SizeAvailable; + + 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); + } + + // + // Fill input + // + ZeroMem (&PcrAllocation, sizeof(PcrAllocation)); + if ((HASH_ALG_SHA1 & SupportedPCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA1; + PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; + if ((HASH_ALG_SHA1 & PCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; + } else { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; + } + PcrAllocation.count++; + } + if ((HASH_ALG_SHA256 & SupportedPCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA256; + PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; + if ((HASH_ALG_SHA256 & PCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; + } else { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; + } + PcrAllocation.count++; + } + if ((HASH_ALG_SHA384 & SupportedPCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA384; + PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; + if ((HASH_ALG_SHA384 & PCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; + } else { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; + } + PcrAllocation.count++; + } + if ((HASH_ALG_SHA512 & SupportedPCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA512; + PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; + if ((HASH_ALG_SHA512 & PCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; + } else { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; + } + PcrAllocation.count++; + } + if ((HASH_ALG_SM3_256 & SupportedPCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SM3_256; + PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX; + if ((HASH_ALG_SM3_256 & PCRBanks) != 0) { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF; + } else { + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00; + PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00; + } + PcrAllocation.count++; + } + Status = Tpm2PcrAllocate ( + TPM_RH_PLATFORM, + AuthSession, + &PcrAllocation, + &AllocationSuccess, + &MaxPCR, + &SizeNeeded, + &SizeAvailable + ); + DEBUG ((EFI_D_INFO, "Tpm2PcrAllocateBanks call Tpm2PcrAllocate - %r\n", Status)); + if (EFI_ERROR (Status)) { + goto Done; + } + + DEBUG ((EFI_D_INFO, "AllocationSuccess - %02x\n", AllocationSuccess)); + DEBUG ((EFI_D_INFO, "MaxPCR - %08x\n", MaxPCR)); + DEBUG ((EFI_D_INFO, "SizeNeeded - %08x\n", SizeNeeded)); + DEBUG ((EFI_D_INFO, "SizeAvailable - %08x\n", SizeAvailable)); + +Done: + ZeroMem(&LocalAuthSession.hmac, sizeof(LocalAuthSession.hmac)); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c new file mode 100644 index 00000000..cc5a7040 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c @@ -0,0 +1,116 @@ +/** @file + Implement TPM2 Miscellaneous related command. + +Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_HIERARCHY_AUTH AuthHandle; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; + UINT32 AlgorithmSet; +} TPM2_SET_ALGORITHM_SET_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_SET_ALGORITHM_SET_RESPONSE; + +#pragma pack() + +/** + This command allows the platform to change the set of algorithms that are used by the TPM. + The algorithmSet setting is a vendor-dependent value. + + @param[in] AuthHandle TPM_RH_PLATFORM + @param[in] AuthSession Auth Session context + @param[in] AlgorithmSet A TPM vendor-dependent value indicating the + algorithm set selection + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2SetAlgorithmSet ( + IN TPMI_RH_PLATFORM AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession, + IN UINT32 AlgorithmSet + ) +{ + EFI_STATUS Status; + TPM2_SET_ALGORITHM_SET_COMMAND SendBuffer; + TPM2_SET_ALGORITHM_SET_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_SetAlgorithmSet); + + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + // + // Real data + // + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(AlgorithmSet)); + Buffer += sizeof(UINT32); + + SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2SetAlgorithmSet - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2SetAlgorithmSet - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + Status = EFI_DEVICE_ERROR; + goto Done; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c new file mode 100644 index 00000000..9d171e6c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c @@ -0,0 +1,1042 @@ +/** @file + Implement TPM2 NVStorage related command. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +#define RC_NV_ReadPublic_nvIndex (TPM_RC_H + TPM_RC_1) + +#define RC_NV_DefineSpace_authHandle (TPM_RC_H + TPM_RC_1) +#define RC_NV_DefineSpace_auth (TPM_RC_P + TPM_RC_1) +#define RC_NV_DefineSpace_publicInfo (TPM_RC_P + TPM_RC_2) + +#define RC_NV_UndefineSpace_authHandle (TPM_RC_H + TPM_RC_1) +#define RC_NV_UndefineSpace_nvIndex (TPM_RC_H + TPM_RC_2) + +#define RC_NV_Read_authHandle (TPM_RC_H + TPM_RC_1) +#define RC_NV_Read_nvIndex (TPM_RC_H + TPM_RC_2) +#define RC_NV_Read_size (TPM_RC_P + TPM_RC_1) +#define RC_NV_Read_offset (TPM_RC_P + TPM_RC_2) + +#define RC_NV_Write_authHandle (TPM_RC_H + TPM_RC_1) +#define RC_NV_Write_nvIndex (TPM_RC_H + TPM_RC_2) +#define RC_NV_Write_data (TPM_RC_P + TPM_RC_1) +#define RC_NV_Write_offset (TPM_RC_P + TPM_RC_2) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_NV_INDEX NvIndex; +} TPM2_NV_READPUBLIC_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + TPM2B_NV_PUBLIC NvPublic; + TPM2B_NAME NvName; +} TPM2_NV_READPUBLIC_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_PROVISION AuthHandle; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; + TPM2B_AUTH Auth; + TPM2B_NV_PUBLIC NvPublic; +} TPM2_NV_DEFINESPACE_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_NV_DEFINESPACE_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_PROVISION AuthHandle; + TPMI_RH_NV_INDEX NvIndex; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; +} TPM2_NV_UNDEFINESPACE_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_NV_UNDEFINESPACE_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_NV_AUTH AuthHandle; + TPMI_RH_NV_INDEX NvIndex; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; + UINT16 Size; + UINT16 Offset; +} TPM2_NV_READ_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPM2B_MAX_BUFFER Data; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_NV_READ_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_NV_AUTH AuthHandle; + TPMI_RH_NV_INDEX NvIndex; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; + TPM2B_MAX_BUFFER Data; + UINT16 Offset; +} TPM2_NV_WRITE_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_NV_WRITE_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_NV_AUTH AuthHandle; + TPMI_RH_NV_INDEX NvIndex; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; +} TPM2_NV_READLOCK_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_NV_READLOCK_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_NV_AUTH AuthHandle; + TPMI_RH_NV_INDEX NvIndex; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; +} TPM2_NV_WRITELOCK_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_NV_WRITELOCK_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_RH_PROVISION AuthHandle; + UINT32 AuthSessionSize; + TPMS_AUTH_COMMAND AuthSession; +} TPM2_NV_GLOBALWRITELOCK_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 AuthSessionSize; + TPMS_AUTH_RESPONSE AuthSession; +} TPM2_NV_GLOBALWRITELOCK_RESPONSE; + +#pragma pack() + +/** + This command is used to read the public area and Name of an NV Index. + + @param[in] NvIndex The NV Index. + @param[out] NvPublic The public area of the index. + @param[out] NvName The Name of the nvIndex. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found. +**/ +EFI_STATUS +EFIAPI +Tpm2NvReadPublic ( + IN TPMI_RH_NV_INDEX NvIndex, + OUT TPM2B_NV_PUBLIC *NvPublic, + OUT TPM2B_NAME *NvName + ) +{ + EFI_STATUS Status; + TPM2_NV_READPUBLIC_COMMAND SendBuffer; + TPM2_NV_READPUBLIC_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT16 NvPublicSize; + UINT16 NvNameSize; + UINT8 *Buffer; + TPM_RC ResponseCode; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_ReadPublic); + + SendBuffer.NvIndex = SwapBytes32 (NvIndex); + + SendBufferSize = (UINT32) sizeof (SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + } + switch (ResponseCode) { + case TPM_RC_SUCCESS: + // return data + break; + case TPM_RC_HANDLE + RC_NV_ReadPublic_nvIndex: // TPM_RC_NV_DEFINED: + return EFI_NOT_FOUND; + case TPM_RC_VALUE + RC_NV_ReadPublic_nvIndex: + return EFI_INVALID_PARAMETER; + default: + return EFI_DEVICE_ERROR; + } + + if (RecvBufferSize <= sizeof (TPM2_RESPONSE_HEADER) + sizeof (UINT16) + sizeof(UINT16)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_NOT_FOUND; + } + + // + // Basic check + // + NvPublicSize = SwapBytes16 (RecvBuffer.NvPublic.size); + if (NvPublicSize > sizeof(TPMS_NV_PUBLIC)) { + DEBUG ((DEBUG_ERROR, "Tpm2NvReadPublic - NvPublic.size error %x\n", NvPublicSize)); + return EFI_DEVICE_ERROR; + } + + NvNameSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)((UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize))); + if (NvNameSize > sizeof(TPMU_NAME)){ + DEBUG ((DEBUG_ERROR, "Tpm2NvReadPublic - NvNameSize error %x\n", NvNameSize)); + return EFI_DEVICE_ERROR; + } + + if (RecvBufferSize != sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize + sizeof(UINT16) + NvNameSize) { + DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - NvPublicSize %x\n", RecvBufferSize)); + return EFI_NOT_FOUND; + } + + // + // Return the response + // + CopyMem (NvPublic, &RecvBuffer.NvPublic, sizeof(UINT16) + NvPublicSize); + NvPublic->size = NvPublicSize; + NvPublic->nvPublic.nvIndex = SwapBytes32 (NvPublic->nvPublic.nvIndex); + NvPublic->nvPublic.nameAlg = SwapBytes16 (NvPublic->nvPublic.nameAlg); + WriteUnaligned32 ((UINT32 *)&NvPublic->nvPublic.attributes, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&NvPublic->nvPublic.attributes))); + NvPublic->nvPublic.authPolicy.size = SwapBytes16 (NvPublic->nvPublic.authPolicy.size); + Buffer = (UINT8 *)&RecvBuffer.NvPublic.nvPublic.authPolicy; + Buffer += sizeof(UINT16) + NvPublic->nvPublic.authPolicy.size; + NvPublic->nvPublic.dataSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + + CopyMem (NvName->name, (UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize + sizeof(UINT16), NvNameSize); + NvName->size = NvNameSize; + + return EFI_SUCCESS; +} + +/** + This command defines the attributes of an NV Index and causes the TPM to + reserve space to hold the data associated with the index. + If a definition already exists at the index, the TPM will return TPM_RC_NV_DEFINED. + + @param[in] AuthHandle TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}. + @param[in] AuthSession Auth Session context + @param[in] Auth The authorization data. + @param[in] NvPublic The public area of the index. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_ALREADY_STARTED The command was returned successfully, but NvIndex is already defined. +**/ +EFI_STATUS +EFIAPI +Tpm2NvDefineSpace ( + IN TPMI_RH_PROVISION AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL + IN TPM2B_AUTH *Auth, + IN TPM2B_NV_PUBLIC *NvPublic + ) +{ + EFI_STATUS Status; + TPM2_NV_DEFINESPACE_COMMAND SendBuffer; + TPM2_NV_DEFINESPACE_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT16 NvPublicSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + TPM_RC ResponseCode; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_DefineSpace); + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + // + // IndexAuth + // + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(Auth->size)); + Buffer += sizeof(UINT16); + CopyMem(Buffer, Auth->buffer, Auth->size); + Buffer += Auth->size; + + // + // NvPublic + // + NvPublicSize = NvPublic->size; + + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NvPublicSize)); + Buffer += sizeof(UINT16); + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (NvPublic->nvPublic.nvIndex)); + Buffer += sizeof(UINT32); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NvPublic->nvPublic.nameAlg)); + Buffer += sizeof(UINT16); + WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&NvPublic->nvPublic.attributes))); + Buffer += sizeof(UINT32); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NvPublic->nvPublic.authPolicy.size)); + Buffer += sizeof(UINT16); + CopyMem (Buffer, NvPublic->nvPublic.authPolicy.buffer, NvPublic->nvPublic.authPolicy.size); + Buffer += NvPublic->nvPublic.authPolicy.size; + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NvPublic->nvPublic.dataSize)); + Buffer += sizeof(UINT16); + + SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvDefineSpace - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2NvDefineSpace - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + } + switch (ResponseCode) { + case TPM_RC_SUCCESS: + // return data + break; + case TPM_RC_SIZE + RC_NV_DefineSpace_publicInfo: + case TPM_RC_SIZE + RC_NV_DefineSpace_auth: + Status = EFI_BAD_BUFFER_SIZE; + break; + case TPM_RC_ATTRIBUTES: + case TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo: + Status = EFI_UNSUPPORTED; + break; + case TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_authHandle: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_NV_DEFINED: + Status = EFI_ALREADY_STARTED; + break; + case TPM_RC_VALUE + RC_NV_DefineSpace_publicInfo: + case TPM_RC_VALUE + RC_NV_DefineSpace_authHandle: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_NV_SPACE: + Status = EFI_OUT_OF_RESOURCES; + break; + default: + Status = EFI_DEVICE_ERROR; + break; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} + +/** + This command removes an index from the TPM. + + @param[in] AuthHandle TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}. + @param[in] NvIndex The NV Index. + @param[in] AuthSession Auth Session context + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found. +**/ +EFI_STATUS +EFIAPI +Tpm2NvUndefineSpace ( + IN TPMI_RH_PROVISION AuthHandle, + IN TPMI_RH_NV_INDEX NvIndex, + IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL + ) +{ + EFI_STATUS Status; + TPM2_NV_UNDEFINESPACE_COMMAND SendBuffer; + TPM2_NV_UNDEFINESPACE_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + TPM_RC ResponseCode; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_UndefineSpace); + + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + SendBuffer.NvIndex = SwapBytes32 (NvIndex); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvUndefineSpace - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2NvUndefineSpace - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + } + switch (ResponseCode) { + case TPM_RC_SUCCESS: + // return data + break; + case TPM_RC_ATTRIBUTES: + case TPM_RC_ATTRIBUTES + RC_NV_UndefineSpace_nvIndex: + Status = EFI_UNSUPPORTED; + break; + case TPM_RC_NV_AUTHORIZATION: + Status = EFI_SECURITY_VIOLATION; + break; + case TPM_RC_HANDLE + RC_NV_UndefineSpace_nvIndex: // TPM_RC_NV_DEFINED: + Status = EFI_NOT_FOUND; + break; + case TPM_RC_HANDLE + RC_NV_UndefineSpace_authHandle: // TPM_RC_NV_DEFINED: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_VALUE + RC_NV_UndefineSpace_authHandle: + case TPM_RC_VALUE + RC_NV_UndefineSpace_nvIndex: + Status = EFI_INVALID_PARAMETER; + break; + default: + Status = EFI_DEVICE_ERROR; + break; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} + +/** + This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace(). + + @param[in] AuthHandle the handle indicating the source of the authorization value. + @param[in] NvIndex The index to be read. + @param[in] AuthSession Auth Session context + @param[in] Size Number of bytes to read. + @param[in] Offset Byte offset into the area. + @param[in,out] OutData The data read. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found. +**/ +EFI_STATUS +EFIAPI +Tpm2NvRead ( + IN TPMI_RH_NV_AUTH AuthHandle, + IN TPMI_RH_NV_INDEX NvIndex, + IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL + IN UINT16 Size, + IN UINT16 Offset, + IN OUT TPM2B_MAX_BUFFER *OutData + ) +{ + EFI_STATUS Status; + TPM2_NV_READ_COMMAND SendBuffer; + TPM2_NV_READ_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + TPM_RC ResponseCode; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_Read); + + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + SendBuffer.NvIndex = SwapBytes32 (NvIndex); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Size)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Offset)); + Buffer += sizeof(UINT16); + + SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvRead - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2NvRead - responseCode - %x\n", ResponseCode)); + } + switch (ResponseCode) { + case TPM_RC_SUCCESS: + // return data + break; + case TPM_RC_NV_AUTHORIZATION: + Status = EFI_SECURITY_VIOLATION; + break; + case TPM_RC_NV_LOCKED: + Status = EFI_ACCESS_DENIED; + break; + case TPM_RC_NV_RANGE: + Status = EFI_BAD_BUFFER_SIZE; + break; + case TPM_RC_NV_UNINITIALIZED: + Status = EFI_NOT_READY; + break; + case TPM_RC_HANDLE + RC_NV_Read_nvIndex: // TPM_RC_NV_DEFINED: + Status = EFI_NOT_FOUND; + break; + case TPM_RC_HANDLE + RC_NV_Read_authHandle: // TPM_RC_NV_DEFINED: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_VALUE + RC_NV_Read_nvIndex: + case TPM_RC_VALUE + RC_NV_Read_authHandle: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_BAD_AUTH + RC_NV_Read_authHandle + TPM_RC_S: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_AUTH_UNAVAILABLE: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_AUTH_FAIL + RC_NV_Read_authHandle + TPM_RC_S: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_ATTRIBUTES + RC_NV_Read_authHandle + TPM_RC_S: + Status = EFI_UNSUPPORTED; + break; + default: + Status = EFI_DEVICE_ERROR; + break; + } + if (Status != EFI_SUCCESS) { + goto Done; + } + + // + // Return the response + // + OutData->size = SwapBytes16 (RecvBuffer.Data.size); + if (OutData->size > MAX_DIGEST_BUFFER) { + DEBUG ((DEBUG_ERROR, "Tpm2NvRead - OutData->size error %x\n", OutData->size)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + CopyMem (OutData->buffer, &RecvBuffer.Data.buffer, OutData->size); + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} + +/** + This command writes a value to an area in NV memory that was previously defined by TPM2_NV_DefineSpace(). + + @param[in] AuthHandle the handle indicating the source of the authorization value. + @param[in] NvIndex The NV Index of the area to write. + @param[in] AuthSession Auth Session context + @param[in] InData The data to write. + @param[in] Offset The offset into the NV Area. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found. +**/ +EFI_STATUS +EFIAPI +Tpm2NvWrite ( + IN TPMI_RH_NV_AUTH AuthHandle, + IN TPMI_RH_NV_INDEX NvIndex, + IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL + IN TPM2B_MAX_BUFFER *InData, + IN UINT16 Offset + ) +{ + EFI_STATUS Status; + TPM2_NV_WRITE_COMMAND SendBuffer; + TPM2_NV_WRITE_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + TPM_RC ResponseCode; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_Write); + + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + SendBuffer.NvIndex = SwapBytes32 (NvIndex); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (InData->size)); + Buffer += sizeof(UINT16); + CopyMem (Buffer, InData->buffer, InData->size); + Buffer += InData->size; + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Offset)); + Buffer += sizeof(UINT16); + + SendBufferSize = (UINT32) (Buffer - (UINT8 *)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvWrite - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2NvWrite - responseCode - %x\n", ResponseCode)); + } + switch (ResponseCode) { + case TPM_RC_SUCCESS: + // return data + break; + case TPM_RC_ATTRIBUTES: + Status = EFI_UNSUPPORTED; + break; + case TPM_RC_NV_AUTHORIZATION: + Status = EFI_SECURITY_VIOLATION; + break; + case TPM_RC_NV_LOCKED: + Status = EFI_ACCESS_DENIED; + break; + case TPM_RC_NV_RANGE: + Status = EFI_BAD_BUFFER_SIZE; + break; + case TPM_RC_HANDLE + RC_NV_Write_nvIndex: // TPM_RC_NV_DEFINED: + Status = EFI_NOT_FOUND; + break; + case TPM_RC_HANDLE + RC_NV_Write_authHandle: // TPM_RC_NV_DEFINED: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_VALUE + RC_NV_Write_nvIndex: + case TPM_RC_VALUE + RC_NV_Write_authHandle: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_BAD_AUTH + RC_NV_Write_authHandle + TPM_RC_S: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_AUTH_UNAVAILABLE: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_AUTH_FAIL + RC_NV_Write_authHandle + TPM_RC_S: + Status = EFI_INVALID_PARAMETER; + break; + case TPM_RC_ATTRIBUTES + RC_NV_Write_authHandle + TPM_RC_S: + Status = EFI_UNSUPPORTED; + break; + default: + Status = EFI_DEVICE_ERROR; + break; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} + +/** + This command may be used to prevent further reads of the Index until the next TPM2_Startup (TPM_SU_CLEAR). + + @param[in] AuthHandle the handle indicating the source of the authorization value. + @param[in] NvIndex The NV Index of the area to lock. + @param[in] AuthSession Auth Session context + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found. +**/ +EFI_STATUS +EFIAPI +Tpm2NvReadLock ( + IN TPMI_RH_NV_AUTH AuthHandle, + IN TPMI_RH_NV_INDEX NvIndex, + IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL + ) +{ + EFI_STATUS Status; + TPM2_NV_READLOCK_COMMAND SendBuffer; + TPM2_NV_READLOCK_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + TPM_RC ResponseCode; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_ReadLock); + + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + SendBuffer.NvIndex = SwapBytes32 (NvIndex); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvReadLock - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2NvReadLock - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + } + switch (ResponseCode) { + case TPM_RC_SUCCESS: + // return data + break; + default: + Status = EFI_DEVICE_ERROR; + break; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} + +/** + This command may be used to inhibit further writes of the Index. + + @param[in] AuthHandle the handle indicating the source of the authorization value. + @param[in] NvIndex The NV Index of the area to lock. + @param[in] AuthSession Auth Session context + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found. +**/ +EFI_STATUS +EFIAPI +Tpm2NvWriteLock ( + IN TPMI_RH_NV_AUTH AuthHandle, + IN TPMI_RH_NV_INDEX NvIndex, + IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL + ) +{ + EFI_STATUS Status; + TPM2_NV_WRITELOCK_COMMAND SendBuffer; + TPM2_NV_WRITELOCK_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + TPM_RC ResponseCode; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_WriteLock); + + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + SendBuffer.NvIndex = SwapBytes32 (NvIndex); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvWriteLock - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2NvWriteLock - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + } + switch (ResponseCode) { + case TPM_RC_SUCCESS: + // return data + break; + default: + Status = EFI_DEVICE_ERROR; + break; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} + +/** + The command will SET TPMA_NV_WRITELOCKED for all indexes that have their TPMA_NV_GLOBALLOCK attribute SET. + + @param[in] AuthHandle TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}. + @param[in] AuthSession Auth Session context + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found. +**/ +EFI_STATUS +EFIAPI +Tpm2NvGlobalWriteLock ( + IN TPMI_RH_PROVISION AuthHandle, + IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL + ) +{ + EFI_STATUS Status; + TPM2_NV_GLOBALWRITELOCK_COMMAND SendBuffer; + TPM2_NV_GLOBALWRITELOCK_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + UINT32 SessionInfoSize; + TPM_RC ResponseCode; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_GlobalWriteLock); + + SendBuffer.AuthHandle = SwapBytes32 (AuthHandle); + + // + // Add in Auth session + // + Buffer = (UINT8 *)&SendBuffer.AuthSession; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer); + Buffer += SessionInfoSize; + SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize); + + SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + goto Done; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvGlobalWriteLock - RecvBufferSize Error - %x\n", RecvBufferSize)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2NvGlobalWriteLock - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + } + switch (ResponseCode) { + case TPM_RC_SUCCESS: + // return data + break; + default: + Status = EFI_DEVICE_ERROR; + break; + } + +Done: + // + // Clear AuthSession Content + // + ZeroMem (&SendBuffer, sizeof(SendBuffer)); + ZeroMem (&RecvBuffer, sizeof(RecvBuffer)); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Object.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Object.c new file mode 100644 index 00000000..084473d1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Object.c @@ -0,0 +1,379 @@ +/** @file + Implement TPM2 Object related command. + +Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_DH_OBJECT ObjectHandle; +} TPM2_READ_PUBLIC_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + TPM2B_PUBLIC OutPublic; + TPM2B_NAME Name; + TPM2B_NAME QualifiedName; +} TPM2_READ_PUBLIC_RESPONSE; + +#pragma pack() + +/** + This command allows access to the public area of a loaded object. + + @param[in] ObjectHandle TPM handle of an object + @param[out] OutPublic Structure containing the public area of an object + @param[out] Name Name of the object + @param[out] QualifiedName The Qualified Name of the object + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2ReadPublic ( + IN TPMI_DH_OBJECT ObjectHandle, + OUT TPM2B_PUBLIC *OutPublic, + OUT TPM2B_NAME *Name, + OUT TPM2B_NAME *QualifiedName + ) +{ + EFI_STATUS Status; + TPM2_READ_PUBLIC_COMMAND SendBuffer; + TPM2_READ_PUBLIC_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + TPM_RC ResponseCode; + UINT8 *Buffer; + UINT16 OutPublicSize; + UINT16 NameSize; + UINT16 QualifiedNameSize; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_ReadPublic); + + SendBuffer.ObjectHandle = SwapBytes32 (ObjectHandle); + + SendBufferSize = (UINT32) sizeof (SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode); + if (ResponseCode != TPM_RC_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + } + switch (ResponseCode) { + case TPM_RC_SUCCESS: + // return data + break; + case TPM_RC_SEQUENCE: + // objectHandle references a sequence object + return EFI_INVALID_PARAMETER; + default: + return EFI_DEVICE_ERROR; + } + + // + // Basic check + // + OutPublicSize = SwapBytes16 (RecvBuffer.OutPublic.size); + if (OutPublicSize > sizeof(TPMT_PUBLIC)) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - OutPublicSize error %x\n", OutPublicSize)); + return EFI_DEVICE_ERROR; + } + + NameSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)((UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + + sizeof(UINT16) + OutPublicSize))); + if (NameSize > sizeof(TPMU_NAME)) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - NameSize error %x\n", NameSize)); + return EFI_DEVICE_ERROR; + } + + QualifiedNameSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)((UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + + sizeof(UINT16) + OutPublicSize + + sizeof(UINT16) + NameSize))); + if (QualifiedNameSize > sizeof(TPMU_NAME)) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - QualifiedNameSize error %x\n", QualifiedNameSize)); + return EFI_DEVICE_ERROR; + } + + if (RecvBufferSize != sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + OutPublicSize + sizeof(UINT16) + NameSize + sizeof(UINT16) + QualifiedNameSize) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - RecvBufferSize %x Error - OutPublicSize %x, NameSize %x, QualifiedNameSize %x\n", RecvBufferSize, OutPublicSize, NameSize, QualifiedNameSize)); + return EFI_DEVICE_ERROR; + } + + // + // Return the response + // + Buffer = (UINT8 *)&RecvBuffer.OutPublic; + CopyMem (OutPublic, &RecvBuffer.OutPublic, sizeof(UINT16) + OutPublicSize); + OutPublic->size = OutPublicSize; + OutPublic->publicArea.type = SwapBytes16 (OutPublic->publicArea.type); + OutPublic->publicArea.nameAlg = SwapBytes16 (OutPublic->publicArea.nameAlg); + WriteUnaligned32 ((UINT32 *)&OutPublic->publicArea.objectAttributes, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&OutPublic->publicArea.objectAttributes))); + Buffer = (UINT8 *)&RecvBuffer.OutPublic.publicArea.authPolicy; + OutPublic->publicArea.authPolicy.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + if (OutPublic->publicArea.authPolicy.size > sizeof(TPMU_HA)) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - authPolicy.size error %x\n", OutPublic->publicArea.authPolicy.size)); + return EFI_DEVICE_ERROR; + } + + CopyMem (OutPublic->publicArea.authPolicy.buffer, Buffer, OutPublic->publicArea.authPolicy.size); + Buffer += OutPublic->publicArea.authPolicy.size; + + // TPMU_PUBLIC_PARMS + switch (OutPublic->publicArea.type) { + case TPM_ALG_KEYEDHASH: + OutPublic->publicArea.parameters.keyedHashDetail.scheme.scheme = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + switch (OutPublic->publicArea.parameters.keyedHashDetail.scheme.scheme) { + case TPM_ALG_HMAC: + OutPublic->publicArea.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_XOR: + OutPublic->publicArea.parameters.keyedHashDetail.scheme.details.xor.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + OutPublic->publicArea.parameters.keyedHashDetail.scheme.details.xor.kdf = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + default: + return EFI_UNSUPPORTED; + } + case TPM_ALG_SYMCIPHER: + OutPublic->publicArea.parameters.symDetail.algorithm = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + switch (OutPublic->publicArea.parameters.symDetail.algorithm) { + case TPM_ALG_AES: + OutPublic->publicArea.parameters.symDetail.keyBits.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + OutPublic->publicArea.parameters.symDetail.mode.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_SM4: + OutPublic->publicArea.parameters.symDetail.keyBits.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + OutPublic->publicArea.parameters.symDetail.mode.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_XOR: + OutPublic->publicArea.parameters.symDetail.keyBits.xor = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_UNSUPPORTED; + } + break; + case TPM_ALG_RSA: + OutPublic->publicArea.parameters.rsaDetail.symmetric.algorithm = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + switch (OutPublic->publicArea.parameters.rsaDetail.symmetric.algorithm) { + case TPM_ALG_AES: + OutPublic->publicArea.parameters.rsaDetail.symmetric.keyBits.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + OutPublic->publicArea.parameters.rsaDetail.symmetric.mode.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_SM4: + OutPublic->publicArea.parameters.rsaDetail.symmetric.keyBits.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + OutPublic->publicArea.parameters.rsaDetail.symmetric.mode.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_UNSUPPORTED; + } + OutPublic->publicArea.parameters.rsaDetail.scheme.scheme = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + switch (OutPublic->publicArea.parameters.rsaDetail.scheme.scheme) { + case TPM_ALG_RSASSA: + OutPublic->publicArea.parameters.rsaDetail.scheme.details.rsassa.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_RSAPSS: + OutPublic->publicArea.parameters.rsaDetail.scheme.details.rsapss.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_RSAES: + break; + case TPM_ALG_OAEP: + OutPublic->publicArea.parameters.rsaDetail.scheme.details.oaep.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_UNSUPPORTED; + } + OutPublic->publicArea.parameters.rsaDetail.keyBits = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + OutPublic->publicArea.parameters.rsaDetail.exponent = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT32); + break; + case TPM_ALG_ECC: + OutPublic->publicArea.parameters.eccDetail.symmetric.algorithm = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + switch (OutPublic->publicArea.parameters.eccDetail.symmetric.algorithm) { + case TPM_ALG_AES: + OutPublic->publicArea.parameters.eccDetail.symmetric.keyBits.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + OutPublic->publicArea.parameters.eccDetail.symmetric.mode.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_SM4: + OutPublic->publicArea.parameters.eccDetail.symmetric.keyBits.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + OutPublic->publicArea.parameters.eccDetail.symmetric.mode.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_UNSUPPORTED; + } + OutPublic->publicArea.parameters.eccDetail.scheme.scheme = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + switch (OutPublic->publicArea.parameters.eccDetail.scheme.scheme) { + case TPM_ALG_ECDSA: + OutPublic->publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_ECDAA: + OutPublic->publicArea.parameters.eccDetail.scheme.details.ecdaa.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_ECSCHNORR: + OutPublic->publicArea.parameters.eccDetail.scheme.details.ecSchnorr.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_ECDH: + break; + case TPM_ALG_NULL: + break; + default: + return EFI_UNSUPPORTED; + } + OutPublic->publicArea.parameters.eccDetail.curveID = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + OutPublic->publicArea.parameters.eccDetail.kdf.scheme = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + switch (OutPublic->publicArea.parameters.eccDetail.kdf.scheme) { + case TPM_ALG_MGF1: + OutPublic->publicArea.parameters.eccDetail.kdf.details.mgf1.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_KDF1_SP800_108: + OutPublic->publicArea.parameters.eccDetail.kdf.details.kdf1_sp800_108.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_KDF1_SP800_56a: + OutPublic->publicArea.parameters.eccDetail.kdf.details.kdf1_SP800_56a.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_KDF2: + OutPublic->publicArea.parameters.eccDetail.kdf.details.kdf2.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_NULL: + break; + default: + return EFI_UNSUPPORTED; + } + break; + default: + return EFI_UNSUPPORTED; + } + + // TPMU_PUBLIC_ID + switch (OutPublic->publicArea.type) { + case TPM_ALG_KEYEDHASH: + OutPublic->publicArea.unique.keyedHash.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + if(OutPublic->publicArea.unique.keyedHash.size > sizeof(TPMU_HA)) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - keyedHash.size error %x\n", OutPublic->publicArea.unique.keyedHash.size)); + return EFI_DEVICE_ERROR; + } + CopyMem (OutPublic->publicArea.unique.keyedHash.buffer, Buffer, OutPublic->publicArea.unique.keyedHash.size); + Buffer += OutPublic->publicArea.unique.keyedHash.size; + break; + case TPM_ALG_SYMCIPHER: + OutPublic->publicArea.unique.sym.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + if(OutPublic->publicArea.unique.sym.size > sizeof(TPMU_HA)) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - sym.size error %x\n", OutPublic->publicArea.unique.sym.size)); + return EFI_DEVICE_ERROR; + } + CopyMem (OutPublic->publicArea.unique.sym.buffer, Buffer, OutPublic->publicArea.unique.sym.size); + Buffer += OutPublic->publicArea.unique.sym.size; + break; + case TPM_ALG_RSA: + OutPublic->publicArea.unique.rsa.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + if(OutPublic->publicArea.unique.rsa.size > MAX_RSA_KEY_BYTES) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - rsa.size error %x\n", OutPublic->publicArea.unique.rsa.size)); + return EFI_DEVICE_ERROR; + } + CopyMem (OutPublic->publicArea.unique.rsa.buffer, Buffer, OutPublic->publicArea.unique.rsa.size); + Buffer += OutPublic->publicArea.unique.rsa.size; + break; + case TPM_ALG_ECC: + OutPublic->publicArea.unique.ecc.x.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + if (OutPublic->publicArea.unique.ecc.x.size > MAX_ECC_KEY_BYTES) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - ecc.x.size error %x\n", OutPublic->publicArea.unique.ecc.x.size)); + return EFI_DEVICE_ERROR; + } + CopyMem (OutPublic->publicArea.unique.ecc.x.buffer, Buffer, OutPublic->publicArea.unique.ecc.x.size); + Buffer += OutPublic->publicArea.unique.ecc.x.size; + OutPublic->publicArea.unique.ecc.y.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + if (OutPublic->publicArea.unique.ecc.y.size > MAX_ECC_KEY_BYTES) { + DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - ecc.y.size error %x\n", OutPublic->publicArea.unique.ecc.y.size)); + return EFI_DEVICE_ERROR; + } + CopyMem (OutPublic->publicArea.unique.ecc.y.buffer, Buffer, OutPublic->publicArea.unique.ecc.y.size); + Buffer += OutPublic->publicArea.unique.ecc.y.size; + break; + default: + return EFI_UNSUPPORTED; + } + + CopyMem (Name->name, (UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + OutPublicSize + sizeof(UINT16), NameSize); + Name->size = NameSize; + + CopyMem (QualifiedName->name, (UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + OutPublicSize + sizeof(UINT16) + NameSize + sizeof(UINT16), QualifiedNameSize); + QualifiedName->size = QualifiedNameSize; + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c new file mode 100644 index 00000000..b9815723 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c @@ -0,0 +1,512 @@ +/** @file + Implement TPM2 Sequences related command. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPM2B_AUTH Auth; + TPMI_ALG_HASH HashAlg; +} TPM2_HASH_SEQUENCE_START_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + TPMI_DH_OBJECT SequenceHandle; +} TPM2_HASH_SEQUENCE_START_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_DH_OBJECT SequenceHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSessionSeq; + TPM2B_MAX_BUFFER Buffer; +} TPM2_SEQUENCE_UPDATE_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPMS_AUTH_RESPONSE AuthSessionSeq; +} TPM2_SEQUENCE_UPDATE_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_DH_PCR PcrHandle; + TPMI_DH_OBJECT SequenceHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSessionPcr; + TPMS_AUTH_COMMAND AuthSessionSeq; + TPM2B_MAX_BUFFER Buffer; +} TPM2_EVENT_SEQUENCE_COMPLETE_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPML_DIGEST_VALUES Results; + TPMS_AUTH_RESPONSE AuthSessionPcr; + TPMS_AUTH_RESPONSE AuthSessionSeq; +} TPM2_EVENT_SEQUENCE_COMPLETE_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_DH_OBJECT SequenceHandle; + UINT32 AuthorizationSize; + TPMS_AUTH_COMMAND AuthSessionSeq; + TPM2B_MAX_BUFFER Buffer; + TPMI_RH_HIERARCHY Hierarchy; +} TPM2_SEQUENCE_COMPLETE_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + UINT32 ParameterSize; + TPM2B_DIGEST Digest; + TPMS_AUTH_RESPONSE AuthSessionSeq; +} TPM2_SEQUENCE_COMPLETE_RESPONSE; + +#pragma pack() + +/** + This command starts a hash or an Event sequence. + If hashAlg is an implemented hash, then a hash sequence is started. + If hashAlg is TPM_ALG_NULL, then an Event sequence is started. + + @param[in] HashAlg The hash algorithm to use for the hash sequence + An Event sequence starts if this is TPM_ALG_NULL. + @param[out] SequenceHandle A handle to reference the sequence + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2HashSequenceStart ( + IN TPMI_ALG_HASH HashAlg, + OUT TPMI_DH_OBJECT *SequenceHandle + ) +{ + EFI_STATUS Status; + TPM2_HASH_SEQUENCE_START_COMMAND Cmd; + TPM2_HASH_SEQUENCE_START_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *Buffer; + UINT32 ResultBufSize; + + ZeroMem(&Cmd, sizeof(Cmd)); + + // + // Construct command + // + Cmd.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_HashSequenceStart); + + Buffer = (UINT8 *)&Cmd.Auth; + + // auth = nullAuth + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0)); + Buffer += sizeof(UINT16); + + // hashAlg + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(HashAlg)); + Buffer += sizeof(UINT16); + + CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + // + // Call the TPM + // + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + return Status; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "HashSequenceStart: Failed ExecuteCommand: Buffer Too Small\r\n")); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "HashSequenceStart: Response size too large! %d\r\n", RespSize)); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "HashSequenceStart: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Unmarshal the response + // + + // sequenceHandle + *SequenceHandle = SwapBytes32(Res.SequenceHandle); + + return EFI_SUCCESS; +} + +/** + This command is used to add data to a hash or HMAC sequence. + The amount of data in buffer may be any size up to the limits of the TPM. + NOTE: In all TPM, a buffer size of 1,024 octets is allowed. + + @param[in] SequenceHandle Handle for the sequence object + @param[in] Buffer Data to be added to hash + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2SequenceUpdate ( + IN TPMI_DH_OBJECT SequenceHandle, + IN TPM2B_MAX_BUFFER *Buffer + ) +{ + EFI_STATUS Status; + TPM2_SEQUENCE_UPDATE_COMMAND Cmd; + TPM2_SEQUENCE_UPDATE_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *BufferPtr; + UINT32 SessionInfoSize; + UINT32 ResultBufSize; + + ZeroMem(&Cmd, sizeof(Cmd)); + + // + // Construct command + // + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_SequenceUpdate); + Cmd.SequenceHandle = SwapBytes32(SequenceHandle); + + // + // Add in Auth session + // + BufferPtr = (UINT8 *)&Cmd.AuthSessionSeq; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr); + BufferPtr += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + // buffer.size + WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16(Buffer->size)); + BufferPtr += sizeof(UINT16); + + CopyMem(BufferPtr, &Buffer->buffer, Buffer->size); + BufferPtr += Buffer->size; + + CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + // + // Call the TPM + // + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd,&ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + return Status; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "SequenceUpdate: Failed ExecuteCommand: Buffer Too Small\r\n")); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "SequenceUpdate: Response size too large! %d\r\n", RespSize)); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "SequenceUpdate: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Unmarshal the response + // + + // None + + return EFI_SUCCESS; +} + +/** + This command adds the last part of data, if any, to an Event sequence and returns the result in a digest list. + If pcrHandle references a PCR and not TPM_RH_NULL, then the returned digest list is processed in + the same manner as the digest list input parameter to TPM2_PCR_Extend() with the pcrHandle in each + bank extended with the associated digest value. + + @param[in] PcrHandle PCR to be extended with the Event data + @param[in] SequenceHandle Authorization for the sequence + @param[in] Buffer Data to be added to the Event + @param[out] Results List of digests computed for the PCR + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2EventSequenceComplete ( + IN TPMI_DH_PCR PcrHandle, + IN TPMI_DH_OBJECT SequenceHandle, + IN TPM2B_MAX_BUFFER *Buffer, + OUT TPML_DIGEST_VALUES *Results + ) +{ + EFI_STATUS Status; + TPM2_EVENT_SEQUENCE_COMPLETE_COMMAND Cmd; + TPM2_EVENT_SEQUENCE_COMPLETE_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *BufferPtr; + UINT32 SessionInfoSize; + UINT32 SessionInfoSize2; + UINT32 Index; + UINT32 ResultBufSize; + UINT16 DigestSize; + + ZeroMem(&Cmd, sizeof(Cmd)); + + // + // Construct command + // + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_EventSequenceComplete); + Cmd.PcrHandle = SwapBytes32(PcrHandle); + Cmd.SequenceHandle = SwapBytes32(SequenceHandle); + + // + // Add in pcrHandle Auth session + // + BufferPtr = (UINT8 *)&Cmd.AuthSessionPcr; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr); + BufferPtr += SessionInfoSize; + + // sessionInfoSize + SessionInfoSize2 = CopyAuthSessionCommand (NULL, BufferPtr); + BufferPtr += SessionInfoSize2; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize + SessionInfoSize2); + + // buffer.size + WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16(Buffer->size)); + BufferPtr += sizeof(UINT16); + + CopyMem(BufferPtr, &Buffer->buffer[0], Buffer->size); + BufferPtr += Buffer->size; + + CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + // + // Call the TPM + // + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + return Status; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Failed ExecuteCommand: Buffer Too Small\r\n")); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Response size too large! %d\r\n", RespSize)); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Unmarshal the response + // + + BufferPtr = (UINT8 *)&Res.Results; + + // count + Results->count = SwapBytes32(ReadUnaligned32 ((UINT32 *)BufferPtr)); + if (Results->count > HASH_COUNT) { + DEBUG ((DEBUG_ERROR, "Tpm2EventSequenceComplete - Results->count error %x\n", Results->count)); + return EFI_DEVICE_ERROR; + } + + BufferPtr += sizeof(UINT32); + + for (Index = 0; Index < Results->count; Index++) { + Results->digests[Index].hashAlg = SwapBytes16(ReadUnaligned16 ((UINT16 *)BufferPtr)); + BufferPtr += sizeof(UINT16); + + DigestSize = GetHashSizeFromAlgo (Results->digests[Index].hashAlg); + if (DigestSize == 0) { + DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Unknown hash algorithm %d\r\n", Results->digests[Index].hashAlg)); + return EFI_DEVICE_ERROR; + } + CopyMem( + &Results->digests[Index].digest, + BufferPtr, + DigestSize + ); + BufferPtr += DigestSize; + } + + return EFI_SUCCESS; +} + +/** + This command adds the last part of data, if any, to a hash/HMAC sequence and returns the result. + + @param[in] SequenceHandle Authorization for the sequence + @param[in] Buffer Data to be added to the hash/HMAC + @param[out] Result The returned HMAC or digest in a sized buffer + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2SequenceComplete ( + IN TPMI_DH_OBJECT SequenceHandle, + IN TPM2B_MAX_BUFFER *Buffer, + OUT TPM2B_DIGEST *Result + ) +{ + EFI_STATUS Status; + TPM2_SEQUENCE_COMPLETE_COMMAND Cmd; + TPM2_SEQUENCE_COMPLETE_RESPONSE Res; + UINT32 CmdSize; + UINT32 RespSize; + UINT8 *BufferPtr; + UINT32 SessionInfoSize; + UINT32 ResultBufSize; + + ZeroMem(&Cmd, sizeof(Cmd)); + + // + // Construct command + // + Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_SequenceComplete); + Cmd.SequenceHandle = SwapBytes32(SequenceHandle); + + // + // Add in Auth session + // + BufferPtr = (UINT8 *)&Cmd.AuthSessionSeq; + + // sessionInfoSize + SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr); + BufferPtr += SessionInfoSize; + Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); + + // buffer.size + WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16(Buffer->size)); + BufferPtr += sizeof(UINT16); + + CopyMem(BufferPtr, &Buffer->buffer[0], Buffer->size); + BufferPtr += Buffer->size; + + // Hierarchy + WriteUnaligned32 ((UINT32 *)BufferPtr, SwapBytes32 (TPM_RH_NULL)); + BufferPtr += sizeof (UINT32); + + CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd); + Cmd.Header.paramSize = SwapBytes32(CmdSize); + + // + // Call the TPM + // + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + return Status; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "SequenceComplete: Failed ExecuteCommand: Buffer Too Small\r\n")); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Validate response headers + // + RespSize = SwapBytes32(Res.Header.paramSize); + if (RespSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "SequenceComplete: Response size too large! %d\r\n", RespSize)); + return EFI_BUFFER_TOO_SMALL; + } + + // + // Fail if command failed + // + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "SequenceComplete: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Unmarshal the response + // + + BufferPtr = (UINT8 *)&Res.Digest; + + // digestSize + Result->size = SwapBytes16(ReadUnaligned16 ((UINT16 *)BufferPtr)); + if (Result->size > sizeof(TPMU_HA)){ + DEBUG ((DEBUG_ERROR, "Tpm2SequenceComplete - Result->size error %x\n", Result->size)); + return EFI_DEVICE_ERROR; + } + + BufferPtr += sizeof(UINT16); + + CopyMem( + Result->buffer, + BufferPtr, + Result->size + ); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Session.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Session.c new file mode 100644 index 00000000..f25efe28 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Session.c @@ -0,0 +1,168 @@ +/** @file + Implement TPM2 Session related command. + +Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_DH_OBJECT TpmKey; + TPMI_DH_ENTITY Bind; + TPM2B_NONCE NonceCaller; + TPM2B_ENCRYPTED_SECRET Salt; + TPM_SE SessionType; + TPMT_SYM_DEF Symmetric; + TPMI_ALG_HASH AuthHash; +} TPM2_START_AUTH_SESSION_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; + TPMI_SH_AUTH_SESSION SessionHandle; + TPM2B_NONCE NonceTPM; +} TPM2_START_AUTH_SESSION_RESPONSE; + +#pragma pack() + +/** + This command is used to start an authorization session using alternative methods of + establishing the session key (sessionKey) that is used for authorization and encrypting value. + + @param[in] TpmKey Handle of a loaded decrypt key used to encrypt salt. + @param[in] Bind Entity providing the authValue. + @param[in] NonceCaller Initial nonceCaller, sets nonce size for the session. + @param[in] Salt Value encrypted according to the type of tpmKey. + @param[in] SessionType Indicates the type of the session. + @param[in] Symmetric The algorithm and key size for parameter encryption. + @param[in] AuthHash Hash algorithm to use for the session. + @param[out] SessionHandle Handle for the newly created session. + @param[out] NonceTPM The initial nonce from the TPM, used in the computation of the sessionKey. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. +**/ +EFI_STATUS +EFIAPI +Tpm2StartAuthSession ( + IN TPMI_DH_OBJECT TpmKey, + IN TPMI_DH_ENTITY Bind, + IN TPM2B_NONCE *NonceCaller, + IN TPM2B_ENCRYPTED_SECRET *Salt, + IN TPM_SE SessionType, + IN TPMT_SYM_DEF *Symmetric, + IN TPMI_ALG_HASH AuthHash, + OUT TPMI_SH_AUTH_SESSION *SessionHandle, + OUT TPM2B_NONCE *NonceTPM + ) +{ + EFI_STATUS Status; + TPM2_START_AUTH_SESSION_COMMAND SendBuffer; + TPM2_START_AUTH_SESSION_RESPONSE RecvBuffer; + UINT32 SendBufferSize; + UINT32 RecvBufferSize; + UINT8 *Buffer; + + // + // Construct command + // + SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_StartAuthSession); + + SendBuffer.TpmKey = SwapBytes32 (TpmKey); + SendBuffer.Bind = SwapBytes32 (Bind); + Buffer = (UINT8 *)&SendBuffer.NonceCaller; + + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NonceCaller->size)); + Buffer += sizeof(UINT16); + CopyMem (Buffer, NonceCaller->buffer, NonceCaller->size); + Buffer += NonceCaller->size; + + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Salt->size)); + Buffer += sizeof(UINT16); + CopyMem (Buffer, Salt->secret, Salt->size); + Buffer += Salt->size; + + *(TPM_SE *)Buffer = SessionType; + Buffer++; + + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->algorithm)); + Buffer += sizeof(UINT16); + switch (Symmetric->algorithm) { + case TPM_ALG_NULL: + break; + case TPM_ALG_AES: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->keyBits.aes)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->mode.aes)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_SM4: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->keyBits.SM4)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->mode.SM4)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_SYMCIPHER: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->keyBits.sym)); + Buffer += sizeof(UINT16); + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->mode.sym)); + Buffer += sizeof(UINT16); + break; + case TPM_ALG_XOR: + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->keyBits.xor)); + Buffer += sizeof(UINT16); + break; + default: + ASSERT (FALSE); + DEBUG ((EFI_D_ERROR, "Tpm2StartAuthSession - Symmetric->algorithm - %x\n", Symmetric->algorithm)); + return EFI_UNSUPPORTED; + } + + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthHash)); + Buffer += sizeof(UINT16); + + SendBufferSize = (UINT32) ((UINTN)Buffer - (UINTN)&SendBuffer); + SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize); + + // + // send Tpm command + // + RecvBufferSize = sizeof (RecvBuffer); + Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer); + if (EFI_ERROR (Status)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2StartAuthSession - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2StartAuthSession - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Return the response + // + *SessionHandle = SwapBytes32 (RecvBuffer.SessionHandle); + NonceTPM->size = SwapBytes16 (RecvBuffer.NonceTPM.size); + if (NonceTPM->size > sizeof(TPMU_HA)) { + DEBUG ((DEBUG_ERROR, "Tpm2StartAuthSession - NonceTPM->size error %x\n", NonceTPM->size)); + return EFI_DEVICE_ERROR; + } + + CopyMem (NonceTPM->buffer, &RecvBuffer.NonceTPM.buffer, NonceTPM->size); + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c new file mode 100644 index 00000000..d49647d8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c @@ -0,0 +1,121 @@ +/** @file + Implement TPM2 Startup related command. + +Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR> +(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPM_SU StartupType; +} TPM2_STARTUP_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; +} TPM2_STARTUP_RESPONSE; + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPM_SU ShutdownType; +} TPM2_SHUTDOWN_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; +} TPM2_SHUTDOWN_RESPONSE; + +#pragma pack() + +/** + Send Startup command to TPM2. + + @param[in] StartupType TPM_SU_CLEAR or TPM_SU_STATE + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2Startup ( + IN TPM_SU StartupType + ) +{ + EFI_STATUS Status; + TPM2_STARTUP_COMMAND Cmd; + TPM2_STARTUP_RESPONSE Res; + UINT32 ResultBufSize; + TPM_RC ResponseCode; + + Cmd.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd)); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_Startup); + Cmd.StartupType = SwapBytes16(StartupType); + + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (sizeof(Cmd), (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + return Status; + } + + ResponseCode = SwapBytes32(Res.Header.responseCode); + switch (ResponseCode) { + case TPM_RC_SUCCESS: + DEBUG ((DEBUG_INFO, "TPM2Startup: TPM_RC_SUCCESS\n")); + return EFI_SUCCESS; + case TPM_RC_INITIALIZE: + // TPM_RC_INITIALIZE can be returned if Tpm2Startup is not required. + DEBUG ((DEBUG_INFO, "TPM2Startup: TPM_RC_INITIALIZE\n")); + return EFI_SUCCESS; + default: + DEBUG ((EFI_D_ERROR, "Tpm2Startup: Response Code error! 0x%08x\r\n", ResponseCode)); + return EFI_DEVICE_ERROR; + } +} + +/** + Send Shutdown command to TPM2. + + @param[in] ShutdownType TPM_SU_CLEAR or TPM_SU_STATE. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2Shutdown ( + IN TPM_SU ShutdownType + ) +{ + EFI_STATUS Status; + TPM2_SHUTDOWN_COMMAND Cmd; + TPM2_SHUTDOWN_RESPONSE Res; + UINT32 ResultBufSize; + + Cmd.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd)); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_Shutdown); + Cmd.ShutdownType = SwapBytes16(ShutdownType); + + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (sizeof(Cmd), (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + if (EFI_ERROR(Status)) { + return Status; + } + + if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2Shutdown: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c new file mode 100644 index 00000000..c663f2e7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c @@ -0,0 +1,60 @@ +/** @file + Implement TPM2 Test related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/UefiTcgPlatform.h> +#include <Library/Tpm2CommandLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> + +#pragma pack(1) + +typedef struct { + TPM2_COMMAND_HEADER Header; + TPMI_YES_NO FullTest; +} TPM2_SELF_TEST_COMMAND; + +typedef struct { + TPM2_RESPONSE_HEADER Header; +} TPM2_SELF_TEST_RESPONSE; + +#pragma pack() + +/** + This command causes the TPM to perform a test of its capabilities. + If the fullTest is YES, the TPM will test all functions. + If fullTest = NO, the TPM will only test those functions that have not previously been tested. + + @param[in] FullTest YES if full test to be performed + NO if only test of untested functions required + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2SelfTest ( + IN TPMI_YES_NO FullTest + ) +{ + EFI_STATUS Status; + TPM2_SELF_TEST_COMMAND Cmd; + TPM2_SELF_TEST_RESPONSE Res; + UINT32 ResultBufSize; + + Cmd.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); + Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd)); + Cmd.Header.commandCode = SwapBytes32(TPM_CC_SelfTest); + Cmd.FullTest = FullTest; + + ResultBufSize = sizeof(Res); + Status = Tpm2SubmitCommand (sizeof(Cmd), (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c new file mode 100644 index 00000000..e15cbd72 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c @@ -0,0 +1,127 @@ +/** @file + This library is TPM2 DTPM device lib. + Choosing this library means platform uses and only uses DTPM device as TPM2 engine. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/PcdLib.h> + +#include "Tpm2DeviceLibDTpm.h" + +/** + This service enables the sending of commands to the TPM2. + + @param[in] InputParameterBlockSize Size of the TPM2 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM2 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +DTpm2SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ); + +/** + This service requests use TPM2. + + @retval EFI_SUCCESS Get the control of TPM2 chip. + @retval EFI_NOT_FOUND TPM2 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +DTpm2RequestUseTpm ( + VOID + ); + +/** + This service enables the sending of commands to the TPM2. + + @param[in] InputParameterBlockSize Size of the TPM2 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM2 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +Tpm2SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + return DTpm2SubmitCommand ( + InputParameterBlockSize, + InputParameterBlock, + OutputParameterBlockSize, + OutputParameterBlock + ); +} + +/** + This service requests use TPM2. + + @retval EFI_SUCCESS Get the control of TPM2 chip. + @retval EFI_NOT_FOUND TPM2 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2RequestUseTpm ( + VOID + ) +{ + return DTpm2RequestUseTpm (); +} + +/** + This service register TPM2 device. + + @param Tpm2Device TPM2 device + + @retval EFI_SUCCESS This TPM2 device is registered successfully. + @retval EFI_UNSUPPORTED System does not support register this TPM2 device. + @retval EFI_ALREADY_STARTED System already register this TPM2 device. +**/ +EFI_STATUS +EFIAPI +Tpm2RegisterTpm2DeviceLib ( + IN TPM2_DEVICE_INTERFACE *Tpm2Device + ) +{ + return EFI_UNSUPPORTED; +} + +/** + The function caches current active TPM interface type. + + @retval EFI_SUCCESS DTPM2.0 instance is registered, or system does not support register DTPM2.0 instance +**/ +EFI_STATUS +EFIAPI +Tpm2DeviceLibConstructor ( + VOID + ) +{ + return InternalTpm2DeviceLibDTpmCommonConstructor (); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.h new file mode 100644 index 00000000..bf62f339 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.h @@ -0,0 +1,67 @@ +/** @file + This header file includes common internal fuction prototypes. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _TPM2_DEVICE_LIB_DTPM_H_ +#define _TPM2_DEVICE_LIB_DTPM_H_ + +/** + Return PTP interface type. + + @param[in] Register Pointer to PTP register. + + @return PTP interface type. +**/ +TPM2_PTP_INTERFACE_TYPE +Tpm2GetPtpInterface ( + IN VOID *Register + ); + +/** + Return PTP CRB interface IdleByPass state. + + @param[in] Register Pointer to PTP register. + + @return PTP CRB interface IdleByPass state. +**/ +UINT8 +Tpm2GetIdleByPass ( + IN VOID *Register + ); + +/** + Return cached PTP interface type. + + @return Cached PTP interface type. +**/ +TPM2_PTP_INTERFACE_TYPE +GetCachedPtpInterface ( + VOID + ); + +/** + Return cached PTP CRB interface IdleByPass state. + + @return Cached PTP CRB interface IdleByPass state. +**/ +UINT8 +GetCachedIdleByPass ( + VOID + ); + +/** + The common function cache current active TpmInterfaceType when needed. + + @retval EFI_SUCCESS DTPM2.0 instance is registered, or system does not support register DTPM2.0 instance +**/ +EFI_STATUS +InternalTpm2DeviceLibDTpmCommonConstructor ( + VOID + ); + +#endif // _TPM2_DEVICE_LIB_DTPM_H_ diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf new file mode 100644 index 00000000..e10d842f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf @@ -0,0 +1,56 @@ +## @file +# Provides TPM 2.0 TIS/PTP functions for DTPM +# +# Spec Compliance Info: +# "TCG PC Client Platform TPM Profile(PTP) Specification Family 2.0 Level 00 Revision 00.43" +# "TCG PC Client Specific TPM Interface Specification(TIS) Version 1.3" +# +# This library implements TIS (TPM Interface Specification) and +# PTP (Platform TPM Profile) functions which is +# used for every TPM 2.0 command. Choosing this library means platform uses and +# only uses TPM 2.0 DTPM device. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm2DeviceLibDTpm + MODULE_UNI_FILE = Tpm2DeviceLibDTpm.uni + FILE_GUID = E54A3327-A345-4068-8842-70AC0D519855 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm2DeviceLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + CONSTRUCTOR = Tpm2DeviceLibConstructor +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm2Tis.c + Tpm2Ptp.c + Tpm2DeviceLibDTpm.c + Tpm2DeviceLibDTpmBase.c + Tpm2DeviceLibDTpm.h + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + IoLib + TimerLib + DebugLib + PcdLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdCRBIdleByPass ## PRODUCES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni new file mode 100644 index 00000000..a92e2be9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni @@ -0,0 +1,19 @@ +// /** @file
+// Provides TPM 2.0 TIS/PTP functions for DTPM
+//
+// This library implements TIS (TPM Interface Specification) and
+// PTP (Platform TPM Profile) functions which is
+// used for every TPM 2.0 command. Choosing this library means platform uses and
+// only uses TPM 2.0 DTPM device.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM 2.0 TIS/PTP functions for DTPM"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library implements TIS (TPM Interface Specification) and PTP (Platform TPM Profile) functions which is used for every TPM 2.0 command. Choosing this library means platform uses and only uses TPM 2.0 DTPM device."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpmBase.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpmBase.c new file mode 100644 index 00000000..43ac13ed --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpmBase.c @@ -0,0 +1,68 @@ +/** @file + This file abstract internal interfaces of which implementation differs per library instance. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/Tpm2DeviceLib.h> +#include <Library/PcdLib.h> + +#include "Tpm2DeviceLibDTpm.h" + +/** + Return cached PTP CRB interface IdleByPass state. + + @return Cached PTP CRB interface IdleByPass state. +**/ +UINT8 +GetCachedIdleByPass ( + VOID + ) +{ + return PcdGet8(PcdCRBIdleByPass); +} + +/** + Return cached PTP interface type. + + @return Cached PTP interface type. +**/ +TPM2_PTP_INTERFACE_TYPE +GetCachedPtpInterface ( + VOID + ) +{ + return PcdGet8(PcdActiveTpmInterfaceType); +} + +/** + The common function cache current active TpmInterfaceType when needed. + + @retval EFI_SUCCESS DTPM2.0 instance is registered, or system does not support register DTPM2.0 instance +**/ +EFI_STATUS +InternalTpm2DeviceLibDTpmCommonConstructor ( + VOID + ) +{ + TPM2_PTP_INTERFACE_TYPE PtpInterface; + UINT8 IdleByPass; + + // + // Cache current active TpmInterfaceType only when needed + // + if (PcdGet8(PcdActiveTpmInterfaceType) == 0xFF) { + PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + PcdSet8S(PcdActiveTpmInterfaceType, PtpInterface); + } + + if (PcdGet8(PcdActiveTpmInterfaceType) == Tpm2PtpInterfaceCrb && PcdGet8(PcdCRBIdleByPass) == 0xFF) { + IdleByPass = Tpm2GetIdleByPass((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + PcdSet8S(PcdCRBIdleByPass, IdleByPass); + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpmStandaloneMm.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpmStandaloneMm.c new file mode 100644 index 00000000..4f1079b7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpmStandaloneMm.c @@ -0,0 +1,66 @@ +/** @file + This file abstract internal interfaces of which implementation differs per library instance. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/Tpm2DeviceLib.h> + +#include "Tpm2DeviceLibDTpm.h" + +TPM2_PTP_INTERFACE_TYPE mActiveTpmInterfaceType; +UINT8 mCRBIdleByPass; + +/** + Return cached PTP CRB interface IdleByPass state. + + @return Cached PTP CRB interface IdleByPass state. +**/ +UINT8 +GetCachedIdleByPass ( + VOID + ) +{ + return mCRBIdleByPass; +} + +/** + Return cached PTP interface type. + + @return Cached PTP interface type. +**/ +TPM2_PTP_INTERFACE_TYPE +GetCachedPtpInterface ( + VOID + ) +{ + return mActiveTpmInterfaceType; +} + +/** + The common function cache current active TpmInterfaceType when needed. + + @retval EFI_SUCCESS DTPM2.0 instance is registered, or system does not support register DTPM2.0 instance +**/ +EFI_STATUS +InternalTpm2DeviceLibDTpmCommonConstructor ( + VOID + ) +{ + mActiveTpmInterfaceType = 0xFF; + mCRBIdleByPass = 0xFF; + + // + // Always cache current active TpmInterfaceType for StandaloneMm implementation + // + mActiveTpmInterfaceType = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + + if (mActiveTpmInterfaceType == Tpm2PtpInterfaceCrb) { + mCRBIdleByPass = Tpm2GetIdleByPass((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + } + + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpmStandaloneMm.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpmStandaloneMm.inf new file mode 100644 index 00000000..6f4ae035 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpmStandaloneMm.inf @@ -0,0 +1,54 @@ +## @file +# Provides TPM 2.0 TIS/PTP functions for DTPM +# +# Spec Compliance Info: +# "TCG PC Client Platform TPM Profile(PTP) Specification Family 2.0 Level 00 Revision 00.43" +# "TCG PC Client Specific TPM Interface Specification(TIS) Version 1.3" +# +# This library implements TIS (TPM Interface Specification) and +# PTP (Platform TPM Profile) functions which is +# used for every TPM 2.0 command. Choosing this library means platform uses and +# only uses TPM 2.0 DTPM device. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm2DeviceLibDTpmStandaloneMm + FILE_GUID = 9A5DB21A-FF0B-46D0-8672-B4F83FEF1F0E + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm2DeviceLib|MM_STANDALONE + CONSTRUCTOR = Tpm2DeviceLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm2Tis.c + Tpm2Ptp.c + Tpm2DeviceLibDTpm.c + Tpm2DeviceLibDTpmStandaloneMm.c + Tpm2DeviceLibDTpm.h + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + IoLib + TimerLib + DebugLib + PcdLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c new file mode 100644 index 00000000..028f823f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c @@ -0,0 +1,96 @@ +/** @file + This library is TPM2 DTPM instance. + It can be registered to Tpm2 Device router, to be active TPM2 engine, + based on platform setting. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/PcdLib.h> + +#include <Guid/TpmInstance.h> + +#include "Tpm2DeviceLibDTpm.h" + +/** + Dump PTP register information. + + @param[in] Register Pointer to PTP register. +**/ +VOID +DumpPtpInfo ( + IN VOID *Register + ); + +/** + This service enables the sending of commands to the TPM2. + + @param[in] InputParameterBlockSize Size of the TPM2 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM2 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +DTpm2SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ); + +/** + This service requests use TPM2. + + @retval EFI_SUCCESS Get the control of TPM2 chip. + @retval EFI_NOT_FOUND TPM2 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +DTpm2RequestUseTpm ( + VOID + ); + +TPM2_DEVICE_INTERFACE mDTpm2InternalTpm2Device = { + TPM_DEVICE_INTERFACE_TPM20_DTPM, + DTpm2SubmitCommand, + DTpm2RequestUseTpm, +}; + +/** + The function register DTPM2.0 instance and caches current active TPM interface type. + + @retval EFI_SUCCESS DTPM2.0 instance is registered, or system does not support register DTPM2.0 instance +**/ +EFI_STATUS +EFIAPI +Tpm2InstanceLibDTpmConstructor ( + VOID + ) +{ + EFI_STATUS Status; + + Status = Tpm2RegisterTpm2DeviceLib (&mDTpm2InternalTpm2Device); + if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) { + // + // Unsupported means platform policy does not need this instance enabled. + // + if (Status == EFI_SUCCESS) { + Status = InternalTpm2DeviceLibDTpmCommonConstructor (); + DumpPtpInfo ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + } + return EFI_SUCCESS; + } + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf new file mode 100644 index 00000000..a0dc5b35 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf @@ -0,0 +1,52 @@ +## @file +# Provides a DTPM instance for TPM 2.0 TIS/PTP. +# +# This library can be registered to Tpm 2.0 device router, to be active TPM 2.0 +# engine, based on platform setting. It supports both TIS (TPM Interface Specification) +# and PTP (Platform TPM Profile) functions. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm2InstanceLibDTpm + MODULE_UNI_FILE = Tpm2InstanceLibDTpm.uni + FILE_GUID = 286BF25A-C2C3-408c-B3B4-25E6758B7317 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL + CONSTRUCTOR = Tpm2InstanceLibDTpmConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm2Tis.c + Tpm2Ptp.c + Tpm2InstanceLibDTpm.c + Tpm2DeviceLibDTpmBase.c + Tpm2DeviceLibDTpm.h + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + IoLib + TimerLib + DebugLib + PcdLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdCRBIdleByPass ## PRODUCES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni new file mode 100644 index 00000000..795b4431 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni @@ -0,0 +1,18 @@ +// /** @file
+// Provides a DTPM instance for TPM 2.0 TIS/PTP
+//
+// This library can be registered to Tpm 2.0 device router, to be active TPM 2.0
+// engine, based on platform setting. It supports both TIS (TPM Interface Specification)
+// and PTP (Platform TPM Profile) functions.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides a DTPM instance for TPM 2.0 TIS/PTP"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to Tpm 2.0 device router, to be active TPM 2.0 engine, based on platform setting. It supports both TIS (TPM Interface Specification) and PTP (Platform TPM Profile) functions."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c new file mode 100644 index 00000000..8fbc9a87 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c @@ -0,0 +1,619 @@ +/** @file + PTP (Platform TPM Profile) CRB (Command Response Buffer) interface used by dTPM2.0 library. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> +Copyright (c), Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/Tpm20.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/DebugLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/PcdLib.h> + +#include <IndustryStandard/TpmPtp.h> +#include <IndustryStandard/TpmTis.h> + +#include "Tpm2DeviceLibDTpm.h" + +// +// Execution of the command may take from several seconds to minutes for certain +// commands, such as key generation. +// +#define PTP_TIMEOUT_MAX (90000 * 1000) // 90s + +// +// Max TPM command/response length +// +#define TPMCMDBUFLENGTH 0x500 + +/** + Check whether TPM PTP register exist. + + @param[in] Reg Pointer to PTP register. + + @retval TRUE TPM PTP exists. + @retval FALSE TPM PTP is not found. +**/ +BOOLEAN +Tpm2IsPtpPresence ( + IN VOID *Reg + ) +{ + UINT8 RegRead; + + RegRead = MmioRead8 ((UINTN)Reg); + if (RegRead == 0xFF) { + // + // No TPM chip + // + return FALSE; + } + return TRUE; +} + +/** + 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 +PtpCrbWaitRegisterBits ( + IN UINT32 *Register, + IN UINT32 BitSet, + IN UINT32 BitClear, + IN UINT32 TimeOut + ) +{ + UINT32 RegRead; + UINT32 WaitTime; + + for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){ + RegRead = MmioRead32 ((UINTN)Register); + if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0) { + return EFI_SUCCESS; + } + MicroSecondDelay (30); + } + return EFI_TIMEOUT; +} + +/** + Get the control of TPM chip. + + @param[in] CrbReg Pointer to CRB register. + + @retval EFI_SUCCESS Get the control of TPM chip. + @retval EFI_INVALID_PARAMETER CrbReg is NULL. + @retval EFI_NOT_FOUND TPM chip doesn't exit. + @retval EFI_TIMEOUT Can't get the TPM control in time. +**/ +EFI_STATUS +PtpCrbRequestUseTpm ( + IN PTP_CRB_REGISTERS_PTR CrbReg + ) +{ + EFI_STATUS Status; + + if (!Tpm2IsPtpPresence (CrbReg)) { + return EFI_NOT_FOUND; + } + + MmioWrite32((UINTN)&CrbReg->LocalityControl, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS); + Status = PtpCrbWaitRegisterBits ( + &CrbReg->LocalityStatus, + PTP_CRB_LOCALITY_STATUS_GRANTED, + 0, + PTP_TIMEOUT_A + ); + return Status; +} + +/** + Send a command to TPM for execution and return response data. + + @param[in] CrbReg 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_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + @retval EFI_UNSUPPORTED Unsupported TPM version + +**/ +EFI_STATUS +PtpCrbTpmCommand ( + IN PTP_CRB_REGISTERS_PTR CrbReg, + IN UINT8 *BufferIn, + IN UINT32 SizeIn, + IN OUT UINT8 *BufferOut, + IN OUT UINT32 *SizeOut + ) +{ + EFI_STATUS Status; + UINT32 Index; + UINT32 TpmOutSize; + UINT16 Data16; + UINT32 Data32; + + DEBUG_CODE ( + UINTN DebugSize; + + DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Send - ")); + if (SizeIn > 0x100) { + DebugSize = 0x40; + } else { + DebugSize = SizeIn; + } + for (Index = 0; Index < DebugSize; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index])); + } + if (DebugSize != SizeIn) { + DEBUG ((EFI_D_VERBOSE, "...... ")); + for (Index = SizeIn - 0x20; Index < SizeIn; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index])); + } + } + DEBUG ((EFI_D_VERBOSE, "\n")); + ); + TpmOutSize = 0; + + // + // STEP 0: + // if CapCRbIdelByPass == 0, enforce Idle state before sending command + // + if (GetCachedIdleByPass () == 0 && (MmioRead32((UINTN)&CrbReg->CrbControlStatus) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE) == 0){ + Status = PtpCrbWaitRegisterBits ( + &CrbReg->CrbControlStatus, + PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE, + 0, + PTP_TIMEOUT_C + ); + if (EFI_ERROR (Status)) { + // + // Try to goIdle to recover TPM + // + Status = EFI_DEVICE_ERROR; + goto GoIdle_Exit; + } + } + + // + // STEP 1: + // Ready is any time the TPM is ready to receive a command, following a write + // of 1 by software to Request.cmdReady, as indicated by the Status field + // being cleared to 0. + // + MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY); + Status = PtpCrbWaitRegisterBits ( + &CrbReg->CrbControlRequest, + 0, + PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY, + PTP_TIMEOUT_C + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto GoIdle_Exit; + } + Status = PtpCrbWaitRegisterBits ( + &CrbReg->CrbControlStatus, + 0, + PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE, + PTP_TIMEOUT_C + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto GoIdle_Exit; + } + + // + // STEP 2: + // Command Reception occurs following a Ready state between the write of the + // first byte of a command to the Command Buffer and the receipt of a write + // of 1 to Start. + // + for (Index = 0; Index < SizeIn; Index++) { + MmioWrite8 ((UINTN)&CrbReg->CrbDataBuffer[Index], BufferIn[Index]); + } + MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandAddressHigh, (UINT32)RShiftU64 ((UINTN)CrbReg->CrbDataBuffer, 32)); + MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandAddressLow, (UINT32)(UINTN)CrbReg->CrbDataBuffer); + MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandSize, sizeof(CrbReg->CrbDataBuffer)); + + MmioWrite64 ((UINTN)&CrbReg->CrbControlResponseAddrss, (UINT32)(UINTN)CrbReg->CrbDataBuffer); + MmioWrite32 ((UINTN)&CrbReg->CrbControlResponseSize, sizeof(CrbReg->CrbDataBuffer)); + + // + // STEP 3: + // Command Execution occurs after receipt of a 1 to Start and the TPM + // clearing Start to 0. + // + MmioWrite32((UINTN)&CrbReg->CrbControlStart, PTP_CRB_CONTROL_START); + Status = PtpCrbWaitRegisterBits ( + &CrbReg->CrbControlStart, + 0, + PTP_CRB_CONTROL_START, + PTP_TIMEOUT_MAX + ); + if (EFI_ERROR (Status)) { + // + // Command Completion check timeout. Cancel the currently executing command by writing TPM_CRB_CTRL_CANCEL, + // Expect TPM_RC_CANCELLED or successfully completed response. + // + MmioWrite32((UINTN)&CrbReg->CrbControlCancel, PTP_CRB_CONTROL_CANCEL); + Status = PtpCrbWaitRegisterBits ( + &CrbReg->CrbControlStart, + 0, + PTP_CRB_CONTROL_START, + PTP_TIMEOUT_B + ); + MmioWrite32((UINTN)&CrbReg->CrbControlCancel, 0); + + if (EFI_ERROR(Status)) { + // + // Still in Command Execution state. Try to goIdle, the behavior is agnostic. + // + Status = EFI_DEVICE_ERROR; + goto GoIdle_Exit; + } + } + + // + // STEP 4: + // Command Completion occurs after completion of a command (indicated by the + // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the + // software to Request.goIdle. + // + + // + // Get response data header + // + for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) { + BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]); + } + DEBUG_CODE ( + DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand ReceiveHeader - ")); + for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index])); + } + DEBUG ((EFI_D_VERBOSE, "\n")); + ); + // + // Check the response data header (tag, parasize and returncode) + // + CopyMem (&Data16, BufferOut, sizeof (UINT16)); + // TPM2 should not use this RSP_COMMAND + if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) { + DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND)); + Status = EFI_UNSUPPORTED; + goto GoIdle_Exit; + } + + CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32)); + TpmOutSize = SwapBytes32 (Data32); + if (*SizeOut < TpmOutSize) { + // + // Command completed, but buffer is not enough + // + Status = EFI_BUFFER_TOO_SMALL; + goto GoReady_Exit; + } + *SizeOut = TpmOutSize; + // + // Continue reading the remaining data + // + for (Index = sizeof (TPM2_RESPONSE_HEADER); Index < TpmOutSize; Index++) { + BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]); + } + + DEBUG_CODE ( + DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Receive - ")); + for (Index = 0; Index < TpmOutSize; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index])); + } + DEBUG ((EFI_D_VERBOSE, "\n")); + ); + +GoReady_Exit: + // + // Goto Ready State if command is completed successfully and TPM support IdleBypass + // If not supported. flow down to GoIdle + // + if (GetCachedIdleByPass () == 1) { + MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY); + return Status; + } + + // + // Do not wait for state transition for TIMEOUT_C + // This function will try to wait 2 TIMEOUT_C at the beginning in next call. + // +GoIdle_Exit: + + // + // Return to Idle state by setting TPM_CRB_CTRL_STS_x.Status.goIdle to 1. + // + MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE); + + // + // Only enforce Idle state transition if execution fails when CRBIdleBypass==1 + // Leave regular Idle delay at the beginning of next command execution + // + if (GetCachedIdleByPass () == 1){ + Status = PtpCrbWaitRegisterBits ( + &CrbReg->CrbControlStatus, + PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE, + 0, + PTP_TIMEOUT_C + ); + } + + return Status; +} + +/** + Send a command to TPM for execution and return response data. + + @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_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + @retval EFI_UNSUPPORTED Unsupported TPM version + +**/ +EFI_STATUS +Tpm2TisTpmCommand ( + IN TIS_PC_REGISTERS_PTR TisReg, + IN UINT8 *BufferIn, + IN UINT32 SizeIn, + IN OUT UINT8 *BufferOut, + IN OUT UINT32 *SizeOut + ); + +/** + Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE + to ACCESS Register in the time of default TIS_TIMEOUT_A. + + @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 +TisPcRequestUseTpm ( + IN TIS_PC_REGISTERS_PTR TisReg + ); + +/** + Return PTP interface type. + + @param[in] Register Pointer to PTP register. + + @return PTP interface type. +**/ +TPM2_PTP_INTERFACE_TYPE +Tpm2GetPtpInterface ( + IN VOID *Register + ) +{ + PTP_CRB_INTERFACE_IDENTIFIER InterfaceId; + PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability; + + if (!Tpm2IsPtpPresence (Register)) { + return Tpm2PtpInterfaceMax; + } + // + // Check interface id + // + InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId); + InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability); + + if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) && + (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) && + (InterfaceId.Bits.CapCRB != 0)) { + return Tpm2PtpInterfaceCrb; + } + if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) && + (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) && + (InterfaceId.Bits.CapFIFO != 0) && + (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) { + return Tpm2PtpInterfaceFifo; + } + return Tpm2PtpInterfaceTis; +} + +/** + Return PTP CRB interface IdleByPass state. + + @param[in] Register Pointer to PTP register. + + @return PTP CRB interface IdleByPass state. +**/ +UINT8 +Tpm2GetIdleByPass ( + IN VOID *Register + ) +{ + PTP_CRB_INTERFACE_IDENTIFIER InterfaceId; + + // + // Check interface id + // + InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId); + + return (UINT8)(InterfaceId.Bits.CapCRBIdleBypass); +} + +/** + Dump PTP register information. + + @param[in] Register Pointer to PTP register. +**/ +VOID +DumpPtpInfo ( + IN VOID *Register + ) +{ + PTP_CRB_INTERFACE_IDENTIFIER InterfaceId; + PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability; + UINT8 StatusEx; + UINT16 Vid; + UINT16 Did; + UINT8 Rid; + TPM2_PTP_INTERFACE_TYPE PtpInterface; + + if (!Tpm2IsPtpPresence (Register)) { + return ; + } + + InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId); + InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability); + StatusEx = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->StatusEx); + + // + // Dump InterfaceId Register for PTP + // + DEBUG ((EFI_D_INFO, "InterfaceId - 0x%08x\n", InterfaceId.Uint32)); + DEBUG ((EFI_D_INFO, " InterfaceType - 0x%02x\n", InterfaceId.Bits.InterfaceType)); + if (InterfaceId.Bits.InterfaceType != PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) { + DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%02x\n", InterfaceId.Bits.InterfaceVersion)); + DEBUG ((EFI_D_INFO, " CapFIFO - 0x%x\n", InterfaceId.Bits.CapFIFO)); + DEBUG ((EFI_D_INFO, " CapCRB - 0x%x\n", InterfaceId.Bits.CapCRB)); + } + + // + // Dump Capability Register for TIS and FIFO + // + DEBUG ((EFI_D_INFO, "InterfaceCapability - 0x%08x\n", InterfaceCapability.Uint32)); + if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) || + (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO)) { + DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%x\n", InterfaceCapability.Bits.InterfaceVersion)); + } + + // + // Dump StatusEx Register for PTP FIFO + // + DEBUG ((EFI_D_INFO, "StatusEx - 0x%02x\n", StatusEx)); + if (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP) { + DEBUG ((EFI_D_INFO, " TpmFamily - 0x%x\n", (StatusEx & PTP_FIFO_STS_EX_TPM_FAMILY) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET)); + } + + Vid = 0xFFFF; + Did = 0xFFFF; + Rid = 0xFF; + PtpInterface = GetCachedPtpInterface (); + DEBUG ((EFI_D_INFO, "PtpInterface - %x\n", PtpInterface)); + switch (PtpInterface) { + case Tpm2PtpInterfaceCrb: + Vid = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Vid); + Did = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Did); + Rid = (UINT8)InterfaceId.Bits.Rid; + break; + case Tpm2PtpInterfaceFifo: + case Tpm2PtpInterfaceTis: + Vid = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Vid); + Did = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Did); + Rid = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Rid); + break; + default: + break; + } + DEBUG ((EFI_D_INFO, "VID - 0x%04x\n", Vid)); + DEBUG ((EFI_D_INFO, "DID - 0x%04x\n", Did)); + DEBUG ((EFI_D_INFO, "RID - 0x%02x\n", Rid)); +} + +/** + This service enables the sending of commands to the TPM2. + + @param[in] InputParameterBlockSize Size of the TPM2 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM2 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +DTpm2SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + TPM2_PTP_INTERFACE_TYPE PtpInterface; + + PtpInterface = GetCachedPtpInterface (); + switch (PtpInterface) { + case Tpm2PtpInterfaceCrb: + return PtpCrbTpmCommand ( + (PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress), + InputParameterBlock, + InputParameterBlockSize, + OutputParameterBlock, + OutputParameterBlockSize + ); + case Tpm2PtpInterfaceFifo: + case Tpm2PtpInterfaceTis: + return Tpm2TisTpmCommand ( + (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress), + InputParameterBlock, + InputParameterBlockSize, + OutputParameterBlock, + OutputParameterBlockSize + ); + default: + return EFI_NOT_FOUND; + } +} + +/** + This service requests use TPM2. + + @retval EFI_SUCCESS Get the control of TPM2 chip. + @retval EFI_NOT_FOUND TPM2 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +DTpm2RequestUseTpm ( + VOID + ) +{ + TPM2_PTP_INTERFACE_TYPE PtpInterface; + + PtpInterface = GetCachedPtpInterface (); + switch (PtpInterface) { + case Tpm2PtpInterfaceCrb: + return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + case Tpm2PtpInterfaceFifo: + case Tpm2PtpInterfaceTis: + return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + default: + return EFI_NOT_FOUND; + } +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c new file mode 100644 index 00000000..bca50633 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c @@ -0,0 +1,434 @@ +/** @file + TIS (TPM Interface Specification) functions used by dTPM2.0 library. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <IndustryStandard/Tpm20.h> + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/DebugLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Library/PcdLib.h> + +#include <IndustryStandard/TpmTis.h> + +#define TIS_TIMEOUT_MAX (90000 * 1000) // 90s + +// +// Max TPM command/response length +// +#define TPMCMDBUFLENGTH 0x500 + +/** + 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 +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 register + 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 BurstCount. + + @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 +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 +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_A. + + @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 +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_A + ); + return Status; +} + +/** + Send a command to TPM for execution and return response data. + + @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_BUFFER_TOO_SMALL Response data buffer is too small. + @retval EFI_DEVICE_ERROR Unexpected device behavior. + @retval EFI_UNSUPPORTED Unsupported TPM version + +**/ +EFI_STATUS +Tpm2TisTpmCommand ( + 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; + + DEBUG_CODE ( + UINTN DebugSize; + + DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand Send - ")); + if (SizeIn > 0x100) { + DebugSize = 0x40; + } else { + DebugSize = SizeIn; + } + for (Index = 0; Index < DebugSize; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index])); + } + if (DebugSize != SizeIn) { + DEBUG ((EFI_D_VERBOSE, "...... ")); + for (Index = SizeIn - 0x20; Index < SizeIn; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index])); + } + } + DEBUG ((EFI_D_VERBOSE, "\n")); + ); + TpmOutSize = 0; + + Status = TisPcPrepareCommand (TisReg); + if (EFI_ERROR (Status)){ + DEBUG ((DEBUG_ERROR, "Tpm2 is not ready for command!\n")); + return EFI_DEVICE_ERROR; + } + // + // Send the command data to Tpm + // + Index = 0; + while (Index < SizeIn) { + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + 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, "Tpm2 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); + + // + // NOTE: That may take many seconds to minutes for certain commands, such as key generation. + // + Status = TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA), + 0, + TIS_TIMEOUT_MAX + ); + if (EFI_ERROR (Status)) { + // + // dataAvail check timeout. Cancel the currently executing command by writing commandCancel, + // Expect TPM_RC_CANCELLED or successfully completed response. + // + DEBUG ((DEBUG_ERROR, "Wait for Tpm2 response data time out. Trying to cancel the command!!\n")); + + MmioWrite32((UINTN)&TisReg->Status, TIS_PC_STS_CANCEL); + Status = TisPcWaitRegisterBits ( + &TisReg->Status, + (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA), + 0, + TIS_TIMEOUT_B + ); + // + // Do not clear CANCEL bit here because Writes of 0 to this bit are ignored + // + if (EFI_ERROR (Status)) { + // + // Cancel executing command fail to get any response + // Try to abort the command with write of a 1 to commandReady in Command Execution state + // + Status = EFI_DEVICE_ERROR; + goto Exit; + } + } + + // + // Get response data header + // + Index = 0; + BurstCount = 0; + while (Index < sizeof (TPM2_RESPONSE_HEADER)) { + Status = TisPcReadBurstCount (TisReg, &BurstCount); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto Exit; + } + for (; BurstCount > 0; BurstCount--) { + *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo); + Index++; + if (Index == sizeof (TPM2_RESPONSE_HEADER)) break; + } + } + DEBUG_CODE ( + DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand ReceiveHeader - ")); + for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index])); + } + DEBUG ((EFI_D_VERBOSE, "\n")); + ); + // + // Check the response data header (tag,parasize and returncode ) + // + CopyMem (&Data16, BufferOut, sizeof (UINT16)); + // TPM2 should not use this RSP_COMMAND + if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) { + DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND)); + Status = EFI_UNSUPPORTED; + 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_DEVICE_ERROR; + goto Exit; + } + } +Exit: + DEBUG_CODE ( + DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand Receive - ")); + for (Index = 0; Index < TpmOutSize; Index++) { + DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index])); + } + DEBUG ((EFI_D_VERBOSE, "\n")); + ); + MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY); + return Status; +} + +/** + This service enables the sending of commands to the TPM2. + + @param[in] InputParameterBlockSize Size of the TPM2 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM2 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +DTpm2TisSubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + return Tpm2TisTpmCommand ( + (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress), + InputParameterBlock, + InputParameterBlockSize, + OutputParameterBlock, + OutputParameterBlockSize + ); +} + +/** + This service requests use TPM2. + + @retval EFI_SUCCESS Get the control of TPM2 chip. + @retval EFI_NOT_FOUND TPM2 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +DTpm2TisRequestUseTpm ( + VOID + ) +{ + return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress)); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.c new file mode 100644 index 00000000..4af3a6bc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.c @@ -0,0 +1,92 @@ +/** @file + This library is TPM2 device router. Platform can register multi TPM2 instance to it + via PcdTpmInstanceGuid. Platform need make choice that which one will be final one. + At most one TPM2 instance can be finally registered, and other will return unsupported. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/Tpm2DeviceLib.h> + +TPM2_DEVICE_INTERFACE mInternalTpm2DeviceInterface; + +/** + This service enables the sending of commands to the TPM2. + + @param[in] InputParameterBlockSize Size of the TPM2 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM2 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +Tpm2SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + if (mInternalTpm2DeviceInterface.Tpm2SubmitCommand == NULL) { + return EFI_UNSUPPORTED; + } + return mInternalTpm2DeviceInterface.Tpm2SubmitCommand ( + InputParameterBlockSize, + InputParameterBlock, + OutputParameterBlockSize, + OutputParameterBlock + ); +} + +/** + This service requests use TPM2. + + @retval EFI_SUCCESS Get the control of TPM2 chip. + @retval EFI_NOT_FOUND TPM2 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2RequestUseTpm ( + VOID + ) +{ + if (mInternalTpm2DeviceInterface.Tpm2RequestUseTpm == NULL) { + return EFI_UNSUPPORTED; + } + return mInternalTpm2DeviceInterface.Tpm2RequestUseTpm (); +} + +/** + This service register TPM2 device. + + @param Tpm2Device TPM2 device + + @retval EFI_SUCCESS This TPM2 device is registered successfully. + @retval EFI_UNSUPPORTED System does not support register this TPM2 device. + @retval EFI_ALREADY_STARTED System already register this TPM2 device. +**/ +EFI_STATUS +EFIAPI +Tpm2RegisterTpm2DeviceLib ( + IN TPM2_DEVICE_INTERFACE *Tpm2Device + ) +{ + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &Tpm2Device->ProviderGuid)){ + DEBUG ((DEBUG_WARN, "WARNING: Tpm2RegisterTpm2DeviceLib - does not support %g registration\n", &Tpm2Device->ProviderGuid)); + return EFI_UNSUPPORTED; + } + + CopyMem (&mInternalTpm2DeviceInterface, Tpm2Device, sizeof(mInternalTpm2DeviceInterface)); + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf new file mode 100644 index 00000000..20cafa18 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf @@ -0,0 +1,42 @@ +## @file +# Provides TPM 2.0 TIS functions +# +# This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to +# it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one. +# At most one TPM 2.0 instance can be finally registered, and other will return unsupported. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm2DeviceLibRouterDxe + MODULE_UNI_FILE = Tpm2DeviceLibRouterDxe.uni + FILE_GUID = C3D69D87-5200-4aab-A6DB-2569BA1A92FC + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm2DeviceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm2DeviceLibRouterDxe.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + PcdLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.uni new file mode 100644 index 00000000..c1c287c7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.uni @@ -0,0 +1,18 @@ +// /** @file
+// Provides TPM 2.0 TIS functions
+//
+// This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to
+// it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one.
+// At most one TPM 2.0 instance can be finally registered, and other will return unsupported.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM 2.0 TIS functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one. At most one TPM 2.0 instance can be finally registered, and other will return unsupported."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c new file mode 100644 index 00000000..1ca9f8c1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c @@ -0,0 +1,137 @@ +/** @file + This library is TPM2 device router. Platform can register multi TPM2 instance to it + via PcdTpmInstanceGuid. Platform need make choice that which one will be final one. + At most one TPM2 instance can be finally registered, and other will return unsupported. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/HobLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/Tpm2DeviceLib.h> + +EFI_GUID mInternalTpm2DeviceInterfaceGuid = { + 0x349cf818, 0xc0ba, 0x4c43, { 0x92, 0x9a, 0xc8, 0xa1, 0xb1, 0xb3, 0xd2, 0x55 } +}; + +/** + This function get TPM2.0 interface. + + @retval TPM2.0 interface. +**/ +TPM2_DEVICE_INTERFACE * +InternalGetTpm2DeviceInterface ( + VOID + ) +{ + EFI_HOB_GUID_TYPE *Hob; + + Hob = GetFirstGuidHob (&mInternalTpm2DeviceInterfaceGuid); + if (Hob == NULL) { + return NULL; + } + return (TPM2_DEVICE_INTERFACE *)(Hob + 1); +} + +/** + This service enables the sending of commands to the TPM2. + + @param[in] InputParameterBlockSize Size of the TPM2 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM2 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +Tpm2SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + TPM2_DEVICE_INTERFACE *Tpm2DeviceInterface; + + Tpm2DeviceInterface = InternalGetTpm2DeviceInterface (); + if (Tpm2DeviceInterface == NULL) { + return EFI_UNSUPPORTED; + } + + return Tpm2DeviceInterface->Tpm2SubmitCommand ( + InputParameterBlockSize, + InputParameterBlock, + OutputParameterBlockSize, + OutputParameterBlock + ); +} + +/** + This service requests use TPM2. + + @retval EFI_SUCCESS Get the control of TPM2 chip. + @retval EFI_NOT_FOUND TPM2 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2RequestUseTpm ( + VOID + ) +{ + TPM2_DEVICE_INTERFACE *Tpm2DeviceInterface; + + Tpm2DeviceInterface = InternalGetTpm2DeviceInterface (); + if (Tpm2DeviceInterface == NULL) { + return EFI_UNSUPPORTED; + } + return Tpm2DeviceInterface->Tpm2RequestUseTpm (); +} + +/** + This service register TPM2 device. + + @param Tpm2Device TPM2 device + + @retval EFI_SUCCESS This TPM2 device is registered successfully. + @retval EFI_UNSUPPORTED System does not support register this TPM2 device. + @retval EFI_ALREADY_STARTED System already register this TPM2 device. +**/ +EFI_STATUS +EFIAPI +Tpm2RegisterTpm2DeviceLib ( + IN TPM2_DEVICE_INTERFACE *Tpm2Device + ) +{ + TPM2_DEVICE_INTERFACE *Tpm2DeviceInterface; + + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &Tpm2Device->ProviderGuid)){ + DEBUG ((DEBUG_WARN, "WARNING: Tpm2RegisterTpm2DeviceLib - does not support %g registration\n", &Tpm2Device->ProviderGuid)); + return EFI_UNSUPPORTED; + } + + Tpm2DeviceInterface = InternalGetTpm2DeviceInterface (); + if (Tpm2DeviceInterface != NULL) { + // + // In PEI phase, there will be shadow driver dispatched again. + // + DEBUG ((EFI_D_INFO, "Tpm2RegisterTpm2DeviceLib - Override\n")); + CopyMem (Tpm2DeviceInterface, Tpm2Device, sizeof(*Tpm2Device)); + return EFI_SUCCESS; + } else { + Tpm2Device = BuildGuidDataHob (&mInternalTpm2DeviceInterfaceGuid, Tpm2Device, sizeof(*Tpm2Device)); + if (Tpm2Device != NULL) { + return EFI_SUCCESS; + } else { + return EFI_OUT_OF_RESOURCES; + } + } +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf new file mode 100644 index 00000000..fdd66def --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf @@ -0,0 +1,44 @@ +## @file +# Provides TPM 2.0 TIS functions +# +# This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to +# it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one. +# At most one TPM 2.0 instance can be finally registered, and other will return unsupported. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm2DeviceLibRouterPei + MODULE_UNI_FILE = Tpm2DeviceLibRouterPei.uni + FILE_GUID = 97CDCF04-4C8E-42fe-8015-11CC8A6E9D81 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm2DeviceLib|PEIM + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm2DeviceLibRouterPei.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + HobLib + PcdLib + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.uni new file mode 100644 index 00000000..c1c287c7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.uni @@ -0,0 +1,18 @@ +// /** @file
+// Provides TPM 2.0 TIS functions
+//
+// This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to
+// it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one.
+// At most one TPM 2.0 instance can be finally registered, and other will return unsupported.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM 2.0 TIS functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one. At most one TPM 2.0 instance can be finally registered, and other will return unsupported."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c new file mode 100644 index 00000000..dc7ce816 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c @@ -0,0 +1,119 @@ +/** @file + This library is TPM2 TCG2 protocol lib. + +Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved. <BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/Tpm2DeviceLib.h> +#include <Protocol/Tcg2Protocol.h> +#include <IndustryStandard/Tpm20.h> + +EFI_TCG2_PROTOCOL *mTcg2Protocol = NULL; + +/** + This service enables the sending of commands to the TPM2. + + @param[in] InputParameterBlockSize Size of the TPM2 input parameter block. + @param[in] InputParameterBlock Pointer to the TPM2 input parameter block. + @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +Tpm2SubmitCommand ( + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN OUT UINT32 *OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + EFI_STATUS Status; + TPM2_RESPONSE_HEADER *Header; + + if (mTcg2Protocol == NULL) { + Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &mTcg2Protocol); + if (EFI_ERROR (Status)) { + // + // Tcg2 protocol is not installed. So, TPM2 is not present. + // + DEBUG ((EFI_D_ERROR, "Tpm2SubmitCommand - Tcg2 - %r\n", Status)); + return EFI_NOT_FOUND; + } + } + // + // Assume when Tcg2 Protocol is ready, RequestUseTpm already done. + // + Status = mTcg2Protocol->SubmitCommand ( + mTcg2Protocol, + InputParameterBlockSize, + InputParameterBlock, + *OutputParameterBlockSize, + OutputParameterBlock + ); + if (EFI_ERROR (Status)) { + return Status; + } + Header = (TPM2_RESPONSE_HEADER *)OutputParameterBlock; + *OutputParameterBlockSize = SwapBytes32 (Header->paramSize); + + return EFI_SUCCESS; +} + +/** + This service requests use TPM2. + + @retval EFI_SUCCESS Get the control of TPM2 chip. + @retval EFI_NOT_FOUND TPM2 not found. + @retval EFI_DEVICE_ERROR Unexpected device behavior. +**/ +EFI_STATUS +EFIAPI +Tpm2RequestUseTpm ( + VOID + ) +{ + EFI_STATUS Status; + + if (mTcg2Protocol == NULL) { + Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &mTcg2Protocol); + if (EFI_ERROR (Status)) { + // + // Tcg2 protocol is not installed. So, TPM2 is not present. + // + DEBUG ((EFI_D_ERROR, "Tpm2RequestUseTpm - Tcg2 - %r\n", Status)); + return EFI_NOT_FOUND; + } + } + // + // Assume when Tcg2 Protocol is ready, RequestUseTpm already done. + // + return EFI_SUCCESS; +} + +/** + This service register TPM2 device. + + @param Tpm2Device TPM2 device + + @retval EFI_SUCCESS This TPM2 device is registered successfully. + @retval EFI_UNSUPPORTED System does not support register this TPM2 device. + @retval EFI_ALREADY_STARTED System already register this TPM2 device. +**/ +EFI_STATUS +EFIAPI +Tpm2RegisterTpm2DeviceLib ( + IN TPM2_DEVICE_INTERFACE *Tpm2Device + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf new file mode 100644 index 00000000..43895b45 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf @@ -0,0 +1,41 @@ +## @file +# Provides function interfaces to communicate with TPM 2.0 device +# +# This library helps to use TPM 2.0 device in library function API +# based on TPM2 protocol. +# +# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm2DeviceLibTcg2 + MODULE_UNI_FILE = Tpm2DeviceLibTcg2.uni + FILE_GUID = A1B0B230-67DC-431E-A94A-A96AF1EBE637 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = Tpm2DeviceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + Tpm2DeviceLibTcg2.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + UefiBootServicesTableLib + +[Protocols] + gEfiTcg2ProtocolGuid ## CONSUMES diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.uni new file mode 100644 index 00000000..b6609f2f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.uni @@ -0,0 +1,17 @@ +// /** @file
+// Provides function interfaces to communicate with TPM 2.0 device
+//
+// This library helps to use TPM 2.0 device in library function API
+// based on TCG2 protocol.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides function interfaces to communicate with TPM 2.0 device"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library helps to use TPM 2.0 device in library function API based on TCG2 protocol."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/CommonHeader.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/CommonHeader.h new file mode 100644 index 00000000..8a84ed7a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/CommonHeader.h @@ -0,0 +1,23 @@ +/** @file + The internal header file for TpmCommLib. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _TPMCOMMLIB_COMMON_HEADER_H_ +#define _TPMCOMMLIB_COMMON_HEADER_H_ + +#include <PiPei.h> +#include <IndustryStandard/Tpm12.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/IoLib.h> +#include <Library/TimerLib.h> +#include <Library/TpmCommLib.h> +#include <Library/BaseCryptLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/DebugLib.h> + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TisPc.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TisPc.c new file mode 100644 index 00000000..5794bb54 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TisPc.c @@ -0,0 +1,177 @@ +/** @file + Basic TIS (TPM Interface Specification) functions. + +Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 register + 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 BurstCount. + + @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_A. + + @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); + // + // No locality set before, ACCESS_X.activeLocality MUST be valid within TIMEOUT_A + // + Status = TisPcWaitRegisterBits ( + &TisReg->Access, + (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID), + 0, + TIS_TIMEOUT_A + ); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TpmComm.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TpmComm.c new file mode 100644 index 00000000..2a077af7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TpmComm.c @@ -0,0 +1,44 @@ +/** @file + Basic TPM command functions. + +Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf new file mode 100644 index 00000000..a17b55c2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf @@ -0,0 +1,45 @@ +## @file +# Provides some common functions for the TCG feature +# +# This instance provides basic TPM Interface Specification (TIS) functions +# and TPM hashall function. +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TpmCommLib + MODULE_UNI_FILE = TpmCommLib.uni + 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 +# + +[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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TpmCommLib.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TpmCommLib.uni new file mode 100644 index 00000000..96194551 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/TpmCommLib/TpmCommLib.uni @@ -0,0 +1,17 @@ +// /** @file
+// Provides some common functions for the TCG feature
+//
+// This instance provides basic TPM Interface Specification (TIS) functions
+// and TPM hashall function.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides some common functions for the TCG feature"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This instance provides basic TPM Interface Specification (TIS) functions and TPM hashall function."
+
diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c new file mode 100644 index 00000000..a96b92a4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.c @@ -0,0 +1,67 @@ +/** @file + Null version of VariableKeyLib for build purpose. Don't use it in real product. + +Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#include <Library/DebugLib.h> +#include <Library/VariableKeyLib.h> + +/** + Retrieves the key for integrity and/or confidentiality of variables. + + @param[out] VariableKey A pointer to pointer for the variable key buffer. + @param[in,out] VariableKeySize The size in bytes of the variable key. + + @retval EFI_SUCCESS The variable key was returned. + @retval EFI_DEVICE_ERROR An error occurred while attempting to get the variable key. + @retval EFI_ACCESS_DENIED The function was invoked after locking the key interface. + @retval EFI_UNSUPPORTED The variable key is not supported in the current boot configuration. +**/ +EFI_STATUS +EFIAPI +GetVariableKey ( + OUT VOID **VariableKey, + IN OUT UINTN *VariableKeySize + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +/** + Regenerates the variable key. + + @retval EFI_SUCCESS The variable key was regenerated successfully. + @retval EFI_DEVICE_ERROR An error occurred while attempting to regenerate the key. + @retval EFI_ACCESS_DENIED The function was invoked after locking the key interface. + @retval EFI_UNSUPPORTED Key regeneration is not supported in the current boot configuration. +**/ +EFI_STATUS +EFIAPI +RegenerateVariableKey ( + VOID + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + +/** + Locks the regenerate key interface. + + @retval EFI_SUCCESS The key interface was locked successfully. + @retval EFI_UNSUPPORTED Locking the key interface is not supported in the current boot configuration. + @retval Others An error occurred while attempting to lock the key interface. +**/ +EFI_STATUS +EFIAPI +LockVariableKeyInterface ( + VOID + ) +{ + ASSERT (FALSE); + return EFI_UNSUPPORTED; +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.inf new file mode 100644 index 00000000..a7953576 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Library/VariableKeyLibNull/VariableKeyLibNull.inf @@ -0,0 +1,33 @@ +## @file +# Provides Null version of VariableKeyLib for build only. +# +# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010029 + BASE_NAME = VariableKeyLibNull + FILE_GUID = 2B640ED8-1E6A-4516-9F1D-25910E59BC4A + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = VariableKeyLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 Arm AArch64 +# + +[Sources] + VariableKeyLibNull.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + |