| /** @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 = LIBSPDM_DATA_LOCATION_CONNECTION; | |
| DataSize = sizeof (MeasurementHashAlgo); | |
| Status = SpdmGetData (SpdmContext, LIBSPDM_DATA_MEASUREMENT_HASH_ALGO, &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 = LIBSPDM_DATA_LOCATION_CONNECTION; | |
| DataSize = sizeof (CapabilityFlags); | |
| SpdmGetData (SpdmContext, LIBSPDM_DATA_CAPABILITY_FLAGS, &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; | |
| } |