From c1d932429ef9700a2da64452546be14e92468b07 Mon Sep 17 00:00:00 2001 From: jyao1 Date: Wed, 18 Sep 2013 05:31:18 +0000 Subject: Add TPM2 implementation. signed off by: jiewen.yao@intel.com reviewed by: guo.dong@intel.com git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14687 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Library/Tpm2CommandLib/Tpm2Capability.c | 741 ++++++++++++++++ .../Library/Tpm2CommandLib/Tpm2CommandLib.inf | 48 ++ .../Library/Tpm2CommandLib/Tpm2DictionaryAttack.c | 203 +++++ SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c | 166 ++++ SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c | 635 ++++++++++++++ SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c | 525 ++++++++++++ .../Library/Tpm2CommandLib/Tpm2Miscellaneous.c | 114 +++ SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c | 938 +++++++++++++++++++++ SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c | 508 +++++++++++ SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c | 102 +++ SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c | 66 ++ 11 files changed, 4046 insertions(+) create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c create mode 100644 SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c (limited to 'SecurityPkg/Library/Tpm2CommandLib') diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c new file mode 100644 index 0000000000..0fe2c367d2 --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c @@ -0,0 +1,741 @@ +/** @file + Implement TPM2 Capability related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#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() + +/** + 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 feilds 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; + } + + // + // Return the response + // + *MoreData = RecvBuffer.MoreData; + // + // Does not unpack all possiable 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 = SwapBytes32 (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); + 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); + 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; + CopyMem (Pcrs->pcrSelections[Index].pcrSelect, TpmCap.data.assignedPCR.pcrSelections[Index].pcrSelect, Pcrs->pcrSelections[Index].sizeofSelect); + } + + return EFI_SUCCESS; +} + +/** + 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 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/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf b/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf new file mode 100644 index 0000000000..804f063429 --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf @@ -0,0 +1,48 @@ +## @file +# This library is used by other modules to send TPM2 command. +# +# Copyright (c) 2013, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tpm2CommandLib + 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 IPF +# + +[Sources] + Tpm2Capability.c + Tpm2Sequences.c + Tpm2Integrity.c + Tpm2Hierarchy.c + Tpm2NVStorage.c + Tpm2Startup.c + Tpm2Test.c + Tpm2DictionaryAttack.c + Tpm2Miscellaneous.c + Tpm2Help.c + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + Tpm2DeviceLib diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c new file mode 100644 index 0000000000..2f6488fb97 --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c @@ -0,0 +1,203 @@ +/** @file + Implement TPM2 DictionaryAttack related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackLockReset - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackLockReset - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + 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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackParameters - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackParameters - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c new file mode 100644 index 0000000000..4f5fcb5a7b --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c @@ -0,0 +1,166 @@ +/** @file + Implement TPM2 help. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +typedef struct { + TPMI_ALG_HASH HashAlgo; + UINT16 HashSize; +} INTERNAL_HASH_INFO; + +STATIC INTERNAL_HASH_INFO mHashInfo[] = { + {TPM_ALG_SHA1, SHA1_DIGEST_SIZE}, + {TPM_ALG_SHA256, SHA256_DIGEST_SIZE}, + {TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE}, + {TPM_ALG_SHA384, SHA384_DIGEST_SIZE}, + {TPM_ALG_SHA512, SHA512_DIGEST_SIZE}, +}; + +/** + 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; +} + +/** + 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 += sizeof(UINT8); + + // 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 += sizeof(UINT8); + + // hmac = nullAuth + WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0)); + Buffer += sizeof(UINT16); + } + + return (UINT32)(UINTN)(Buffer - (UINT8 *)AuthSessionOut); +} + +/** + Copy AuthSessionIn from TPM2 response buffer. + + @param [in] AuthSessionIn Input AuthSession data in TPM2 response buffer + @param [out] AuthSessionOut Output AuthSession data + + @return 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); + + CopyMem (AuthSessionOut->nonce.buffer, Buffer, AuthSessionOut->nonce.size); + Buffer += AuthSessionOut->nonce.size; + + // sessionAttributes + *(UINT8 *)&AuthSessionOut->sessionAttributes = *(UINT8 *)Buffer; + Buffer += sizeof(UINT8); + + // hmac + AuthSessionOut->hmac.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + Buffer += sizeof(UINT16); + + CopyMem (AuthSessionOut->hmac.buffer, Buffer, AuthSessionOut->hmac.size); + Buffer += AuthSessionOut->hmac.size; + + return (UINT32)(UINTN)(Buffer - (UINT8 *)AuthSessionIn); +} diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c new file mode 100644 index 0000000000..c6935d9a82 --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c @@ -0,0 +1,635 @@ +/** @file + Implement TPM2 Hierarchy related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#pragma pack(1) + +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 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)) { + return Status; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Clear: 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, "Clear: 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, "Clear: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Unmarshal the response + // + + // None + + return EFI_SUCCESS; +} + +/** + 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 += sizeof(UINT8); + + 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)) { + return Status; + } + + if (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "ClearControl: 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, "ClearControl: 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, "ClearControl: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Unmarshal the response + // + + // None + + return EFI_SUCCESS; +} + +/** + 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 Authorizeation + 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 (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "HierarchyChangeAuth: 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, "HierarchyChangeAuth: 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,"HierarchyChangeAuth: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + 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 (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "ChangeEPS: 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, "ChangeEPS: 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,"ChangeEPS: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + 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 (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "ChangePPS: 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, "ChangePPS: 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,"ChangePPS: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + 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 += sizeof(UINT8); + + 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 (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "HierarchyControl: 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, "HierarchyControl: 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,"HierarchyControl: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c new file mode 100644 index 0000000000..88dcc0afe2 --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c @@ -0,0 +1,525 @@ +/** @file + Implement TPM2 Integrity related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#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)); + 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 (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; + 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); + Digests = PcrValuesOut->digests; + for (Index = 0; Index < PcrValues->count; Index++) { + PcrValues->digests[Index].size = SwapBytes16(Digests->size); + 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 += sizeof(UINT8); + 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 (ResultBufSize > sizeof(Res)) { + DEBUG ((EFI_D_ERROR, "Tpm2PcrAllocate: 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, "Tpm2PcrAllocate: 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,"Tpm2PcrAllocate: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + // + // Return the response + // + *AllocationSuccess = Res.AllocationSuccess; + *MaxPCR = SwapBytes32(Res.MaxPCR); + *SizeNeeded = SwapBytes32(Res.SizeNeeded); + *SizeAvailable = SwapBytes32(Res.SizeAvailable); + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c new file mode 100644 index 0000000000..914ad7f70b --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c @@ -0,0 +1,114 @@ +/** @file + Implement TPM2 Miscellanenous related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2SetAlgorithmSet - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Tpm2SetAlgorithmSet - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode))); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c new file mode 100644 index 0000000000..c4714d3e19 --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c @@ -0,0 +1,938 @@ +/** @file + Implement TPM2 NVStorage related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#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); + NvNameSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)((UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize))); + + if (RecvBufferSize != sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize + sizeof(UINT16) + NvNameSize) { + DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - NvPublicSize %x, NvNameSize %x\n", RecvBufferSize, NvNameSize)); + 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 *)&NvPublic->nvPublic.authPolicy; + Buffer += sizeof(UINT16) + NvPublic->nvPublic.authPolicy.size; + NvPublic->nvPublic.dataSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer)); + + CopyMem (NvName, (UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize, 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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvDefineSpace - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + + 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: + return EFI_BAD_BUFFER_SIZE; + case TPM_RC_ATTRIBUTES: + case TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo: + return EFI_UNSUPPORTED; + case TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_authHandle: + return EFI_INVALID_PARAMETER; + case TPM_RC_NV_DEFINED: + return EFI_ALREADY_STARTED; + case TPM_RC_VALUE + RC_NV_DefineSpace_publicInfo: + case TPM_RC_VALUE + RC_NV_DefineSpace_authHandle: + return EFI_INVALID_PARAMETER; + case TPM_RC_NV_SPACE: + return EFI_OUT_OF_RESOURCES; + default: + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + 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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvUndefineSpace - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + + 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: + return EFI_UNSUPPORTED; + case TPM_RC_NV_AUTHORIZATION: + return EFI_SECURITY_VIOLATION; + case TPM_RC_HANDLE + RC_NV_UndefineSpace_nvIndex: // TPM_RC_NV_DEFINED: + return EFI_NOT_FOUND; + case TPM_RC_HANDLE + RC_NV_UndefineSpace_authHandle: // TPM_RC_NV_DEFINED: + return EFI_INVALID_PARAMETER; + case TPM_RC_VALUE + RC_NV_UndefineSpace_authHandle: + case TPM_RC_VALUE + RC_NV_UndefineSpace_nvIndex: + return EFI_INVALID_PARAMETER; + default: + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + 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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvRead - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + 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: + return EFI_SECURITY_VIOLATION; + case TPM_RC_NV_LOCKED: + return EFI_ACCESS_DENIED; + case TPM_RC_NV_RANGE: + return EFI_BAD_BUFFER_SIZE; + case TPM_RC_NV_UNINITIALIZED: + return EFI_NOT_READY; + case TPM_RC_HANDLE + RC_NV_Read_nvIndex: // TPM_RC_NV_DEFINED: + return EFI_NOT_FOUND; + case TPM_RC_HANDLE + RC_NV_Read_authHandle: // TPM_RC_NV_DEFINED: + return EFI_INVALID_PARAMETER; + case TPM_RC_VALUE + RC_NV_Read_nvIndex: + case TPM_RC_VALUE + RC_NV_Read_authHandle: + return EFI_INVALID_PARAMETER; + case TPM_RC_BAD_AUTH + RC_NV_Read_authHandle + TPM_RC_S: + return EFI_INVALID_PARAMETER; + case TPM_RC_AUTH_UNAVAILABLE: + return EFI_INVALID_PARAMETER; + case TPM_RC_AUTH_FAIL + RC_NV_Read_authHandle + TPM_RC_S: + return EFI_INVALID_PARAMETER; + default: + return EFI_DEVICE_ERROR; + case TPM_RC_ATTRIBUTES + RC_NV_Read_authHandle + TPM_RC_S: + return EFI_UNSUPPORTED; + } + + // + // Return the response + // + OutData->size = SwapBytes16 (RecvBuffer.Data.size); + CopyMem (OutData->buffer, &RecvBuffer.Data.buffer, OutData->size); + + return EFI_SUCCESS; +} + +/** + 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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvWrite - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + 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 EFI_SUCCESS; + case TPM_RC_ATTRIBUTES: + return EFI_UNSUPPORTED; + case TPM_RC_NV_AUTHORIZATION: + return EFI_SECURITY_VIOLATION; + case TPM_RC_NV_LOCKED: + return EFI_ACCESS_DENIED; + case TPM_RC_NV_RANGE: + return EFI_BAD_BUFFER_SIZE; + case TPM_RC_HANDLE + RC_NV_Write_nvIndex: // TPM_RC_NV_DEFINED: + return EFI_NOT_FOUND; + case TPM_RC_HANDLE + RC_NV_Write_authHandle: // TPM_RC_NV_DEFINED: + return EFI_INVALID_PARAMETER; + case TPM_RC_VALUE + RC_NV_Write_nvIndex: + case TPM_RC_VALUE + RC_NV_Write_authHandle: + return EFI_INVALID_PARAMETER; + case TPM_RC_BAD_AUTH + RC_NV_Write_authHandle + TPM_RC_S: + return EFI_INVALID_PARAMETER; + case TPM_RC_AUTH_UNAVAILABLE: + return EFI_INVALID_PARAMETER; + case TPM_RC_AUTH_FAIL + RC_NV_Write_authHandle + TPM_RC_S: + return EFI_INVALID_PARAMETER; + default: + return EFI_DEVICE_ERROR; + case TPM_RC_ATTRIBUTES + RC_NV_Write_authHandle + TPM_RC_S: + return EFI_UNSUPPORTED; + } +} + +/** + 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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvReadLock - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + + 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: + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + 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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvWriteLock - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + + 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: + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + 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)) { + return Status; + } + + if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) { + DEBUG ((EFI_D_ERROR, "Tpm2NvGlobalWriteLock - RecvBufferSize Error - %x\n", RecvBufferSize)); + return EFI_DEVICE_ERROR; + } + + 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: + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c new file mode 100644 index 0000000000..305b6f2078 --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c @@ -0,0 +1,508 @@ +/** @file + Implement TPM2 Sequences related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#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)); + 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)); + BufferPtr += sizeof(UINT16); + + CopyMem( + Result->buffer, + BufferPtr, + Result->size + ); + + return EFI_SUCCESS; +} diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c new file mode 100644 index 0000000000..e8af4033ce --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c @@ -0,0 +1,102 @@ +/** @file + Implement TPM2 Startup related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#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; + + 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); + + return Status; +} + +/** + 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); + + return Status; +} diff --git a/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c new file mode 100644 index 0000000000..453351bfb3 --- /dev/null +++ b/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c @@ -0,0 +1,66 @@ +/** @file + Implement TPM2 Test related command. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +#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; +} -- cgit v1.2.3