summaryrefslogtreecommitdiff
path: root/SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmMeasurement.c
diff options
context:
space:
mode:
authorWenxing Hou <wenxing.hou@intel.com>2024-04-18 17:28:15 +0800
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>2024-04-30 02:21:13 +0000
commit750d763623fd1ff4a69d2e350310333dcbc19d4f (patch)
tree3ce5671d442e72592c2bb920a6a6cba13f88d7f9 /SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmMeasurement.c
parentc3f615a1bd7d64f42e7962f5a4d53f1f1a4423e6 (diff)
downloadedk2-750d763623fd1ff4a69d2e350310333dcbc19d4f.zip
edk2-750d763623fd1ff4a69d2e350310333dcbc19d4f.tar.gz
edk2-750d763623fd1ff4a69d2e350310333dcbc19d4f.tar.bz2
SecurityPkg: add DeviceSecurity support
This patch implement the SpdmSecurityLib, which is the core of DeviceSecurity. And the SpdmSecurityLib include Device Authentication and Measurement. The other library is to support SpdmSecurityLib. Cc: Jiewen Yao <jiewen.yao@intel.com> Signed-off-by: Wenxing Hou <wenxing.hou@intel.com> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
Diffstat (limited to 'SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmMeasurement.c')
-rw-r--r--SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmMeasurement.c714
1 files changed, 714 insertions, 0 deletions
diff --git a/SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmMeasurement.c b/SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmMeasurement.c
new file mode 100644
index 0000000..f94ec1e
--- /dev/null
+++ b/SecurityPkg/DeviceSecurity/SpdmSecurityLib/SpdmMeasurement.c
@@ -0,0 +1,714 @@
+/** @file
+ EDKII Device Security library for SPDM device.
+ It follows the SPDM Specification.
+
+Copyright (c) 2024, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "SpdmSecurityLibInternal.h"
+
+/**
+ This function returns the SPDM device type for TCG SPDM event.
+
+ @param[in] SpdmDeviceContext The SPDM context for the device.
+
+ @return TCG SPDM device type
+**/
+UINT32
+EFIAPI
+GetSpdmDeviceType (
+ IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext
+ )
+{
+ if (CompareGuid (&SpdmDeviceContext->DeviceId.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid)) {
+ return TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_PCI;
+ }
+
+ if (CompareGuid (&SpdmDeviceContext->DeviceId.DeviceType, &gEdkiiDeviceIdentifierTypeUsbGuid)) {
+ return TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_USB;
+ }
+
+ return TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_NULL;
+}
+
+/**
+ This function returns the SPDM device measurement context size for TCG SPDM event.
+
+ @param[in] SpdmDeviceContext The SPDM context for the device.
+
+ @return TCG SPDM device measurement context size
+**/
+UINTN
+EFIAPI
+GetDeviceMeasurementContextSize (
+ IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext
+ )
+{
+ if (CompareGuid (&SpdmDeviceContext->DeviceId.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid)) {
+ return sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT);
+ }
+
+ if (CompareGuid (&SpdmDeviceContext->DeviceId.DeviceType, &gEdkiiDeviceIdentifierTypeUsbGuid)) {
+ // TBD - usb context
+ return 0;
+ }
+
+ return 0;
+}
+
+/**
+ This function creates the SPDM PCI device measurement context for TCG SPDM event.
+
+ @param[in] SpdmDeviceContext The SPDM context for the device.
+ @param[in, out] DeviceContext The TCG SPDM PCI device measurement context.
+ @param[in] DeviceContextSize The size of TCG SPDM PCI device measurement context.
+
+ @retval EFI_SUCCESS The TCG SPDM PCI device measurement context is returned.
+**/
+EFI_STATUS
+CreatePciDeviceMeasurementContext (
+ IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext,
+ IN OUT VOID *DeviceContext,
+ IN UINTN DeviceContextSize
+ )
+{
+ TCG_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT *PciContext;
+ PCI_TYPE00 PciData;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ if (DeviceContextSize != sizeof (*PciContext)) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ PciIo = SpdmDeviceContext->DeviceIo;
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (PciData), &PciData);
+ ASSERT_EFI_ERROR (Status);
+
+ PciContext = DeviceContext;
+ PciContext->Version = TCG_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT_VERSION;
+ PciContext->Length = sizeof (*PciContext);
+ PciContext->VendorId = PciData.Hdr.VendorId;
+ PciContext->DeviceId = PciData.Hdr.DeviceId;
+ PciContext->RevisionID = PciData.Hdr.RevisionID;
+ PciContext->ClassCode[0] = PciData.Hdr.ClassCode[0];
+ PciContext->ClassCode[1] = PciData.Hdr.ClassCode[1];
+ PciContext->ClassCode[2] = PciData.Hdr.ClassCode[2];
+ if ((PciData.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
+ PciContext->SubsystemVendorID = PciData.Device.SubsystemVendorID;
+ PciContext->SubsystemID = PciData.Device.SubsystemID;
+ } else {
+ PciContext->SubsystemVendorID = 0;
+ PciContext->SubsystemID = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function creates the SPDM device measurement context for TCG SPDM event.
+
+ @param[in] SpdmDeviceContext The SPDM context for the device.
+ @param[in, out] DeviceContext The TCG SPDM device measurement context.
+ @param[in] DeviceContextSize The size of TCG SPDM device measurement context.
+
+ @retval EFI_SUCCESS The TCG SPDM device measurement context is returned.
+ @retval EFI_UNSUPPORTED The TCG SPDM device measurement context is unsupported.
+**/
+EFI_STATUS
+EFIAPI
+CreateDeviceMeasurementContext (
+ IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext,
+ IN OUT VOID *DeviceContext,
+ IN UINTN DeviceContextSize
+ )
+{
+ if (CompareGuid (&SpdmDeviceContext->DeviceId.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid)) {
+ return CreatePciDeviceMeasurementContext (SpdmDeviceContext, DeviceContext, DeviceContextSize);
+ }
+
+ if (CompareGuid (&SpdmDeviceContext->DeviceId.DeviceType, &gEdkiiDeviceIdentifierTypeUsbGuid)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function dumps data.
+
+ @param[in] Data A pointer to Data.
+ @param[in] Size The size of Data.
+
+**/
+VOID
+EFIAPI
+InternalDumpData (
+ CONST UINT8 *Data,
+ UINTN Size
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Size; Index++) {
+ DEBUG ((DEBUG_INFO, "%02x ", (UINTN)Data[Index]));
+ }
+}
+
+/**
+ This function extend the PCI digest from the DvSec register.
+
+ @param[in] SpdmDeviceContext The SPDM context for the device.
+ @param[in] AuthState The auth state of the device.
+ @param[in] MeasurementRecordLength The length of the SPDM measurement record
+ @param[in] MeasurementRecord The SPDM measurement record
+ @param[in] RequesterNonce A buffer to hold the requester nonce (32 bytes), if not NULL.
+ @param[in] ResponderNonce A buffer to hold the responder nonce (32 bytes), if not NULL.
+ @param[out] SecurityState The Device Security state associated with the device.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+ExtendMeasurement (
+ IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext,
+ IN UINT8 AuthState,
+ IN UINT32 MeasurementRecordLength,
+ IN UINT8 *MeasurementRecord,
+ IN UINT8 *RequesterNonce,
+ IN UINT8 *ResponderNonce,
+ OUT EDKII_DEVICE_SECURITY_STATE *SecurityState
+ )
+{
+ UINT32 PcrIndex;
+ UINT32 EventType;
+ VOID *EventLog;
+ UINT32 EventLogSize;
+ UINT8 *EventLogPtr;
+
+ TCG_DEVICE_SECURITY_EVENT_DATA_HEADER2 *EventData2;
+ TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK *TcgSpdmMeasurementBlock;
+ VOID *DeviceContext;
+ UINTN DeviceContextSize;
+ EFI_STATUS Status;
+ SPDM_MEASUREMENT_BLOCK_COMMON_HEADER *SpdmMeasurementBlockCommonHeader;
+ SPDM_MEASUREMENT_BLOCK_DMTF_HEADER *SpdmMeasurementBlockDmtfHeader;
+ VOID *Digest;
+ UINTN DigestSize;
+ UINTN DevicePathSize;
+ UINT32 MeasurementHashAlgo;
+ UINTN DataSize;
+ VOID *SpdmContext;
+ SPDM_DATA_PARAMETER Parameter;
+
+ SpdmContext = SpdmDeviceContext->SpdmContext;
+
+ EventLog = NULL;
+ ZeroMem (&Parameter, sizeof (Parameter));
+ Parameter.location = SpdmDataLocationConnection;
+ DataSize = sizeof (MeasurementHashAlgo);
+ Status = SpdmGetData (SpdmContext, SpdmDataMeasurementHashAlgo, &Parameter, &MeasurementHashAlgo, &DataSize);
+ ASSERT_EFI_ERROR (Status);
+
+ if (MeasurementRecord != NULL) {
+ SpdmMeasurementBlockCommonHeader = (VOID *)MeasurementRecord;
+ SpdmMeasurementBlockDmtfHeader = (VOID *)(SpdmMeasurementBlockCommonHeader + 1);
+ Digest = (SpdmMeasurementBlockDmtfHeader + 1);
+ DigestSize = MeasurementRecordLength - sizeof (SPDM_MEASUREMENT_BLOCK_DMTF);
+
+ DEBUG ((DEBUG_INFO, "SpdmMeasurementBlockCommonHeader\n"));
+ DEBUG ((DEBUG_INFO, " Index - 0x%02x\n", SpdmMeasurementBlockCommonHeader->Index));
+ DEBUG ((DEBUG_INFO, " MeasurementSpecification - 0x%02x\n", SpdmMeasurementBlockCommonHeader->MeasurementSpecification));
+ DEBUG ((DEBUG_INFO, " MeasurementSize - 0x%04x\n", SpdmMeasurementBlockCommonHeader->MeasurementSize));
+ DEBUG ((DEBUG_INFO, "SpdmMeasurementBlockDmtfHeader\n"));
+ DEBUG ((DEBUG_INFO, " DMTFSpecMeasurementValueType - 0x%02x\n", SpdmMeasurementBlockDmtfHeader->DMTFSpecMeasurementValueType));
+ DEBUG ((DEBUG_INFO, " DMTFSpecMeasurementValueSize - 0x%04x\n", SpdmMeasurementBlockDmtfHeader->DMTFSpecMeasurementValueSize));
+ DEBUG ((DEBUG_INFO, "Measurement - "));
+ InternalDumpData (Digest, DigestSize);
+ DEBUG ((DEBUG_INFO, "\n"));
+ if (MeasurementRecordLength <= sizeof (SPDM_MEASUREMENT_BLOCK_COMMON_HEADER) + sizeof (SPDM_MEASUREMENT_BLOCK_DMTF_HEADER)) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_MEASUREMENT_AUTH_FAILURE;
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if ((SpdmMeasurementBlockCommonHeader->MeasurementSpecification & SPDM_MEASUREMENT_SPECIFICATION_DMTF) == 0) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_MEASUREMENT_AUTH_FAILURE;
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (SpdmMeasurementBlockCommonHeader->MeasurementSize != MeasurementRecordLength - sizeof (SPDM_MEASUREMENT_BLOCK_COMMON_HEADER)) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_MEASUREMENT_AUTH_FAILURE;
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (SpdmMeasurementBlockDmtfHeader->DMTFSpecMeasurementValueSize != SpdmMeasurementBlockCommonHeader->MeasurementSize - sizeof (SPDM_MEASUREMENT_BLOCK_DMTF_HEADER)) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_MEASUREMENT_AUTH_FAILURE;
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Use PCR 2 for Firmware Blob code.
+ //
+ switch (SpdmMeasurementBlockDmtfHeader->DMTFSpecMeasurementValueType & 0x7F) {
+ case SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_IMMUTABLE_ROM:
+ case SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_MUTABLE_FIRMWARE:
+ case SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_VERSION:
+ case SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_SECURE_VERSION_NUMBER:
+ if (SpdmDeviceContext->IsEmbeddedDevice) {
+ PcrIndex = 0;
+ } else {
+ PcrIndex = 2;
+ }
+
+ EventType = EV_EFI_SPDM_FIRMWARE_BLOB;
+ break;
+ case SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_HARDWARE_CONFIGURATION:
+ case SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_FIRMWARE_CONFIGURATION:
+ case SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_DEVICE_MODE:
+ if (SpdmDeviceContext->IsEmbeddedDevice) {
+ PcrIndex = 1;
+ } else {
+ PcrIndex = 3;
+ }
+
+ EventType = EV_EFI_SPDM_FIRMWARE_CONFIG;
+ break;
+ case SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_MEASUREMENT_MANIFEST:
+ // skip manifest, because manifest doesn't belong to the EV_EFI_SPDM_FIRMWARE_BLOB and EV_EFI_SPDM_FIRMWARE_CONFIG
+ default:
+ return EFI_SUCCESS;
+ }
+ } else {
+ if (SpdmDeviceContext->IsEmbeddedDevice) {
+ PcrIndex = 0;
+ } else {
+ PcrIndex = 2;
+ }
+
+ EventType = EV_EFI_SPDM_FIRMWARE_BLOB;
+ }
+
+ DeviceContextSize = GetDeviceMeasurementContextSize (SpdmDeviceContext);
+ DevicePathSize = GetDevicePathSize (SpdmDeviceContext->DevicePath);
+
+ switch (AuthState) {
+ case TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_SUCCESS:
+ EventLogSize = (UINT32)(sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_HEADER2) +
+ sizeof (UINT64) + DevicePathSize +
+ sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK) +
+ MeasurementRecordLength +
+ DeviceContextSize);
+ EventLog = AllocatePool (EventLogSize);
+ if (EventLog == NULL) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_OUT_OF_RESOURCE;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EventLogPtr = EventLog;
+
+ EventData2 = (VOID *)EventLogPtr;
+ CopyMem (EventData2->Signature, TCG_DEVICE_SECURITY_EVENT_DATA_SIGNATURE_2, sizeof (EventData2->Signature));
+ EventData2->Version = TCG_DEVICE_SECURITY_EVENT_DATA_VERSION_2;
+ EventData2->AuthState = AuthState;
+ EventData2->Reserved = 0;
+ EventData2->Length = (UINT32)EventLogSize;
+ EventData2->DeviceType = GetSpdmDeviceType (SpdmDeviceContext);
+
+ EventData2->SubHeaderType = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_SUB_HEADER_TYPE_SPDM_MEASUREMENT_BLOCK;
+ EventData2->SubHeaderLength = sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK) + MeasurementRecordLength;
+ EventData2->SubHeaderUID = SpdmDeviceContext->DeviceUID;
+
+ EventLogPtr = (VOID *)(EventData2 + 1);
+
+ *(UINT64 *)EventLogPtr = (UINT64)DevicePathSize;
+ EventLogPtr += sizeof (UINT64);
+ CopyMem (EventLogPtr, SpdmDeviceContext->DevicePath, DevicePathSize);
+ EventLogPtr += DevicePathSize;
+
+ TcgSpdmMeasurementBlock = (VOID *)EventLogPtr;
+ TcgSpdmMeasurementBlock->SpdmVersion = SpdmDeviceContext->SpdmVersion;
+ TcgSpdmMeasurementBlock->SpdmMeasurementBlockCount = 1;
+ TcgSpdmMeasurementBlock->Reserved = 0;
+ TcgSpdmMeasurementBlock->SpdmMeasurementHashAlgo = MeasurementHashAlgo;
+ EventLogPtr += sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK);
+
+ if ((MeasurementRecord != NULL) && (MeasurementRecordLength != 0)) {
+ CopyMem (EventLogPtr, MeasurementRecord, MeasurementRecordLength);
+ EventLogPtr += MeasurementRecordLength;
+ }
+
+ if (DeviceContextSize != 0) {
+ DeviceContext = (VOID *)EventLogPtr;
+ Status = CreateDeviceMeasurementContext (SpdmDeviceContext, DeviceContext, DeviceContextSize);
+ if (Status != EFI_SUCCESS) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR;
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+
+ Status = TpmMeasureAndLogData (
+ PcrIndex,
+ EventType,
+ EventLog,
+ EventLogSize,
+ EventLog,
+ EventLogSize
+ );
+ if (EFI_ERROR (Status)) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR;
+ }
+
+ DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData (Measurement) - %r\n", Status));
+ break;
+ case TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_INVALID:
+ EventLogSize = (UINT32)(sizeof (TCG_DEVICE_SECURITY_EVENT_DATA_HEADER2) +
+ sizeof (UINT64) + DevicePathSize +
+ DeviceContextSize);
+ EventLog = AllocatePool (EventLogSize);
+ if (EventLog == NULL) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_OUT_OF_RESOURCE;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EventLogPtr = EventLog;
+
+ EventData2 = (VOID *)EventLogPtr;
+ CopyMem (EventData2->Signature, TCG_DEVICE_SECURITY_EVENT_DATA_SIGNATURE_2, sizeof (EventData2->Signature));
+ EventData2->Version = TCG_DEVICE_SECURITY_EVENT_DATA_VERSION_2;
+ EventData2->AuthState = AuthState;
+ EventData2->Reserved = 0;
+ EventData2->Length = (UINT32)EventLogSize;
+ EventData2->DeviceType = GetSpdmDeviceType (SpdmDeviceContext);
+
+ EventData2->SubHeaderType = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_SUB_HEADER_TYPE_SPDM_MEASUREMENT_BLOCK;
+ EventData2->SubHeaderLength = 0;
+ EventData2->SubHeaderUID = SpdmDeviceContext->DeviceUID;
+
+ EventLogPtr = (VOID *)(EventData2 + 1);
+
+ *(UINT64 *)EventLogPtr = (UINT64)DevicePathSize;
+ EventLogPtr += sizeof (UINT64);
+ CopyMem (EventLogPtr, SpdmDeviceContext->DevicePath, DevicePathSize);
+ EventLogPtr += DevicePathSize;
+
+ if (DeviceContextSize != 0) {
+ DeviceContext = (VOID *)EventLogPtr;
+ Status = CreateDeviceMeasurementContext (SpdmDeviceContext, DeviceContext, DeviceContextSize);
+ if (Status != EFI_SUCCESS) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR;
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+
+ Status = TpmMeasureAndLogData (
+ PcrIndex,
+ EventType,
+ EventLog,
+ EventLogSize,
+ EventLog,
+ EventLogSize
+ );
+ if (EFI_ERROR (Status)) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR;
+ }
+
+ DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData (Measurement) - %r\n", Status));
+ goto Exit;
+ default:
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_UNSUPPORTED;
+ return EFI_UNSUPPORTED;
+ }
+
+ if (RequesterNonce != NULL) {
+ TCG_NV_INDEX_DYNAMIC_EVENT_LOG_STRUCT_SPDM_GET_MEASUREMENTS DynamicEventLogSpdmGetMeasurementsEvent;
+
+ CopyMem (DynamicEventLogSpdmGetMeasurementsEvent.Header.Signature, TCG_NV_EXTEND_INDEX_FOR_DYNAMIC_SIGNATURE, sizeof (TCG_NV_EXTEND_INDEX_FOR_DYNAMIC_SIGNATURE));
+ DynamicEventLogSpdmGetMeasurementsEvent.Header.Version = TCG_NV_INDEX_DYNAMIC_EVENT_LOG_STRUCT_VERSION;
+ ZeroMem (DynamicEventLogSpdmGetMeasurementsEvent.Header.Reserved, sizeof (DynamicEventLogSpdmGetMeasurementsEvent.Header.Reserved));
+ DynamicEventLogSpdmGetMeasurementsEvent.Header.Uid = SpdmDeviceContext->DeviceUID;
+ DynamicEventLogSpdmGetMeasurementsEvent.DescriptionSize = sizeof (TCG_SPDM_GET_MEASUREMENTS_DESCRIPTION);
+ CopyMem (DynamicEventLogSpdmGetMeasurementsEvent.Description, TCG_SPDM_GET_MEASUREMENTS_DESCRIPTION, sizeof (TCG_SPDM_GET_MEASUREMENTS_DESCRIPTION));
+ DynamicEventLogSpdmGetMeasurementsEvent.DataSize = SPDM_NONCE_SIZE;
+ CopyMem (DynamicEventLogSpdmGetMeasurementsEvent.Data, RequesterNonce, SPDM_NONCE_SIZE);
+
+ Status = TpmMeasureAndLogData (
+ TCG_NV_EXTEND_INDEX_FOR_DYNAMIC,
+ EV_NO_ACTION,
+ &DynamicEventLogSpdmGetMeasurementsEvent,
+ sizeof (DynamicEventLogSpdmGetMeasurementsEvent),
+ &DynamicEventLogSpdmGetMeasurementsEvent,
+ sizeof (DynamicEventLogSpdmGetMeasurementsEvent)
+ );
+ if (EFI_ERROR (Status)) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR;
+ }
+
+ DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData (Dynamic) - %r\n", Status));
+ }
+
+ if (ResponderNonce != NULL) {
+ TCG_NV_INDEX_DYNAMIC_EVENT_LOG_STRUCT_SPDM_MEASUREMENTS DynamicEventLogSpdmMeasurementsEvent;
+
+ CopyMem (DynamicEventLogSpdmMeasurementsEvent.Header.Signature, TCG_NV_EXTEND_INDEX_FOR_DYNAMIC_SIGNATURE, sizeof (TCG_NV_EXTEND_INDEX_FOR_DYNAMIC_SIGNATURE));
+ DynamicEventLogSpdmMeasurementsEvent.Header.Version = TCG_NV_INDEX_DYNAMIC_EVENT_LOG_STRUCT_VERSION;
+ ZeroMem (DynamicEventLogSpdmMeasurementsEvent.Header.Reserved, sizeof (DynamicEventLogSpdmMeasurementsEvent.Header.Reserved));
+ DynamicEventLogSpdmMeasurementsEvent.Header.Uid = SpdmDeviceContext->DeviceUID;
+ DynamicEventLogSpdmMeasurementsEvent.DescriptionSize = sizeof (TCG_SPDM_MEASUREMENTS_DESCRIPTION);
+ CopyMem (DynamicEventLogSpdmMeasurementsEvent.Description, TCG_SPDM_MEASUREMENTS_DESCRIPTION, sizeof (TCG_SPDM_MEASUREMENTS_DESCRIPTION));
+ DynamicEventLogSpdmMeasurementsEvent.DataSize = SPDM_NONCE_SIZE;
+ CopyMem (DynamicEventLogSpdmMeasurementsEvent.Data, ResponderNonce, SPDM_NONCE_SIZE);
+
+ Status = TpmMeasureAndLogData (
+ TCG_NV_EXTEND_INDEX_FOR_DYNAMIC,
+ EV_NO_ACTION,
+ &DynamicEventLogSpdmMeasurementsEvent,
+ sizeof (DynamicEventLogSpdmMeasurementsEvent),
+ &DynamicEventLogSpdmMeasurementsEvent,
+ sizeof (DynamicEventLogSpdmMeasurementsEvent)
+ );
+ if (EFI_ERROR (Status)) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR;
+ }
+
+ DEBUG ((DEBUG_INFO, "TpmMeasureAndLogData (Dynamic) - %r\n", Status));
+ }
+
+Exit:
+ if (EventLog != NULL) {
+ FreePool (EventLog);
+ }
+
+ return Status;
+}
+
+/**
+ This function gets SPDM measurement and extend to TPM.
+
+ @param[in] SpdmDeviceContext The SPDM context for the device.
+ @param[in] SlotId The number of slot id of the certificate.
+ @param[out] SecurityState A poniter to security state of the requester.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+DoDeviceMeasurement (
+ IN SPDM_DEVICE_CONTEXT *SpdmDeviceContext,
+ IN UINT8 SlotId,
+ OUT EDKII_DEVICE_SECURITY_STATE *SecurityState
+ )
+{
+ EFI_STATUS Status;
+ SPDM_RETURN SpdmReturn;
+ VOID *SpdmContext;
+ UINT32 CapabilityFlags;
+ UINTN DataSize;
+ SPDM_DATA_PARAMETER Parameter;
+ UINT8 NumberOfBlocks;
+ UINT32 MeasurementRecordLength;
+ UINT8 MeasurementRecord[LIBSPDM_MAX_MEASUREMENT_RECORD_SIZE];
+ UINT8 Index;
+ UINT8 RequesterNonce[SPDM_NONCE_SIZE];
+ UINT8 ResponderNonce[SPDM_NONCE_SIZE];
+ UINT8 RequestAttribute;
+ UINT32 MeasurementsBlockSize;
+ SPDM_MEASUREMENT_BLOCK_DMTF *MeasurementBlock;
+ UINT8 NumberOfBlock;
+ UINT8 ReceivedNumberOfBlock;
+ UINT8 AuthState;
+ UINT8 ContentChanged;
+ UINT8 ContentChangedCount;
+
+ SpdmContext = SpdmDeviceContext->SpdmContext;
+
+ ZeroMem (&Parameter, sizeof (Parameter));
+ Parameter.location = SpdmDataLocationConnection;
+ DataSize = sizeof (CapabilityFlags);
+ SpdmGetData (SpdmContext, SpdmDataCapabilityFlags, &Parameter, &CapabilityFlags, &DataSize);
+
+ if ((CapabilityFlags & SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG) == 0) {
+ AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_NO_SIG;
+ Status = ExtendCertificate (SpdmDeviceContext, AuthState, 0, NULL, NULL, 0, 0, SecurityState);
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_NO_CAPABILITIES;
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ RequestAttribute = 0;
+ RequestAttribute |= SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE;
+
+ MeasurementRecordLength = sizeof (MeasurementRecord);
+ ZeroMem (RequesterNonce, sizeof (RequesterNonce));
+ ZeroMem (ResponderNonce, sizeof (ResponderNonce));
+
+ //
+ // get all measurement once, with signature.
+ //
+ SpdmReturn = SpdmGetMeasurementEx (
+ SpdmContext,
+ NULL,
+ RequestAttribute,
+ SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS,
+ SlotId,
+ NULL,
+ &NumberOfBlocks,
+ &MeasurementRecordLength,
+ MeasurementRecord,
+ NULL,
+ RequesterNonce,
+ ResponderNonce,
+ NULL,
+ 0
+ );
+ if (LIBSPDM_STATUS_IS_SUCCESS (SpdmReturn)) {
+ DEBUG ((DEBUG_INFO, "NumberOfBlocks %d\n", NumberOfBlocks));
+
+ MeasurementBlock = (VOID *)MeasurementRecord;
+ for (Index = 0; Index < NumberOfBlocks; Index++) {
+ MeasurementsBlockSize =
+ sizeof (SPDM_MEASUREMENT_BLOCK_DMTF) +
+ MeasurementBlock
+ ->MeasurementBlockDmtfHeader
+ .DMTFSpecMeasurementValueSize;
+
+ AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_SUCCESS;
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_SUCCESS;
+ if (Index == NumberOfBlocks - 1) {
+ Status = ExtendMeasurement (SpdmDeviceContext, AuthState, MeasurementsBlockSize, (UINT8 *)MeasurementBlock, RequesterNonce, ResponderNonce, SecurityState);
+ } else {
+ Status = ExtendMeasurement (SpdmDeviceContext, AuthState, MeasurementsBlockSize, (UINT8 *)MeasurementBlock, NULL, NULL, SecurityState);
+ }
+
+ MeasurementBlock = (VOID *)((size_t)MeasurementBlock + MeasurementsBlockSize);
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+ }
+ } else if (SpdmReturn == LIBSPDM_STATUS_VERIF_FAIL) {
+ AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_INVALID;
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_MEASUREMENT_AUTH_FAILURE;
+ Status = ExtendMeasurement (SpdmDeviceContext, AuthState, 0, NULL, NULL, NULL, SecurityState);
+ return Status;
+ } else {
+ ContentChangedCount = 0;
+ContentChangedFlag:
+ RequestAttribute = 0;
+ ContentChanged = SPDM_MEASUREMENTS_RESPONSE_CONTENT_NO_CHANGE_DETECTED;
+ ReceivedNumberOfBlock = 0;
+
+ //
+ // 1. Query the total number of measurements available.
+ //
+ SpdmReturn = SpdmGetMeasurement (
+ SpdmContext,
+ NULL,
+ RequestAttribute,
+ SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS,
+ SlotId,
+ NULL,
+ &NumberOfBlocks,
+ NULL,
+ NULL
+ );
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR;
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((DEBUG_INFO, "NumberOfBlocks - 0x%x\n", NumberOfBlocks));
+
+ ReceivedNumberOfBlock = 0;
+ for (Index = 1; Index <= 0xFE; Index++) {
+ if (ReceivedNumberOfBlock == NumberOfBlocks) {
+ break;
+ }
+
+ DEBUG ((DEBUG_INFO, "Index - 0x%x\n", Index));
+ //
+ // 2. query measurement one by one
+ // get signature in last message only.
+ //
+ if (ReceivedNumberOfBlock == NumberOfBlocks - 1) {
+ RequestAttribute |= SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE;
+ }
+
+ MeasurementRecordLength = sizeof (MeasurementRecord);
+ ZeroMem (RequesterNonce, sizeof (RequesterNonce));
+ ZeroMem (ResponderNonce, sizeof (ResponderNonce));
+ SpdmReturn = SpdmGetMeasurementEx (
+ SpdmContext,
+ NULL,
+ RequestAttribute,
+ Index,
+ SlotId,
+ &ContentChanged,
+ &NumberOfBlock,
+ &MeasurementRecordLength,
+ MeasurementRecord,
+ NULL,
+ RequesterNonce,
+ ResponderNonce,
+ NULL,
+ 0
+ );
+ if (LIBSPDM_STATUS_IS_ERROR (SpdmReturn)) {
+ if (SpdmReturn == LIBSPDM_STATUS_VERIF_FAIL) {
+ AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_INVALID;
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR;
+ Status = ExtendMeasurement (SpdmDeviceContext, AuthState, 0, NULL, NULL, NULL, SecurityState);
+ return Status;
+ } else {
+ continue;
+ }
+ }
+
+ if ((ReceivedNumberOfBlock == NumberOfBlocks - 1) &&
+ (ContentChanged == SPDM_MEASUREMENTS_RESPONSE_CONTENT_CHANGE_DETECTED))
+ {
+ if (ContentChangedCount == 0) {
+ ContentChangedCount++;
+ goto ContentChangedFlag;
+ } else {
+ AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_FAIL_INVALID;
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_DEVICE_ERROR;
+ Status = ExtendMeasurement (SpdmDeviceContext, AuthState, 0, NULL, NULL, NULL, SecurityState);
+ return Status;
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "ExtendMeasurement...\n"));
+ AuthState = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_AUTH_STATE_SUCCESS;
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_SUCCESS;
+ if (ReceivedNumberOfBlock == NumberOfBlocks - 1) {
+ Status = ExtendMeasurement (SpdmDeviceContext, AuthState, MeasurementRecordLength, MeasurementRecord, RequesterNonce, ResponderNonce, SecurityState);
+ } else {
+ Status = ExtendMeasurement (SpdmDeviceContext, AuthState, MeasurementRecordLength, MeasurementRecord, NULL, ResponderNonce, SecurityState);
+ }
+
+ if (Status != EFI_SUCCESS) {
+ return Status;
+ }
+
+ ReceivedNumberOfBlock += 1;
+ }
+
+ if (ReceivedNumberOfBlock != NumberOfBlocks) {
+ SecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_MEASUREMENT_AUTH_FAILURE;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}