/** @file EDKII Device Security library for SPDM device. It follows the SPDM Specification. Copyright (c) 2024, Intel Corporation. All rights reserved.
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; }