[PATCH V2 4/6] IntelSiliconPkg/IntelPciDeviceSecurityDxe: Add PciSecurity.


Yao, Jiewen
 

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2303

This driver is to do the PCI device authentication
based upon Intel PCIe Security Specification.

Cc: Ray Ni <ray.ni@...>
Cc: Rangasai V Chaganty <rangasai.v.chaganty@...>
Cc: Yun Lou <yun.lou@...>
Signed-off-by: Jiewen Yao <jiewen.yao@...>
Signed-off-by: Yun Lou <yun.lou@...>
---
Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.c | 701 ++++++++++++++++++++
Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.inf | 45 ++
Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/TcgDeviceEvent.h | 193 ++++++
3 files changed, 939 insertions(+)

diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.c b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.c
new file mode 100644
index 0000000000..f1859c2715
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.c
@@ -0,0 +1,701 @@
+/** @file
+ EDKII Device Security library for PCI device.
+ It follows the Intel PCIe Security Specification.
+
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <IndustryStandard/Spdm.h>
+#include <IndustryStandard/IntelPciSecurity.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/Tpm20.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/TpmMeasurementLib.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DeviceSecurity.h>
+#include <Protocol/PlatformDeviceSecurityPolicy.h>
+#include "TcgDeviceEvent.h"
+
+typedef struct {
+ UINT8 Measurement[SHA512_DIGEST_SIZE];
+} EDKII_DEVICE_SECURITY_EVENT_MEASUREMENT_CONTENT_MAX_HASH;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+} PCI_DEVICE_INSTANCE;
+
+#define PCI_DEVICE_INSTANCE_SIGNATURE SIGNATURE_32 ('P', 'D', 'I', 'S')
+#define PCI_DEVICE_INSTANCE_FROM_LINK(a) CR (a, PCI_DEVICE_INSTANCE, Link, PCI_DEVICE_INSTANCE_SIGNATURE)
+
+LIST_ENTRY mSecurityEventMeasurementDeviceList = INITIALIZE_LIST_HEAD_VARIABLE(mSecurityEventMeasurementDeviceList);;
+EDKII_DEVICE_SECURITY_POLICY_PROTOCOL *mDeviceSecurityPolicy;
+
+/**
+ Record a PCI device into device list.
+
+ @param PciIo PciIo instance of the device
+ @param PciDeviceList The list to record the the device
+**/
+VOID
+RecordPciDeviceInList(
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN LIST_ENTRY *PciDeviceList
+ )
+{
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ EFI_STATUS Status;
+ PCI_DEVICE_INSTANCE *NewPciDevice;
+
+ Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBus, &PciDevice, &PciFunction);
+ ASSERT_EFI_ERROR(Status);
+
+ NewPciDevice = AllocateZeroPool(sizeof(*NewPciDevice));
+ ASSERT_EFI_ERROR(NewPciDevice != NULL);
+
+ NewPciDevice->Signature = PCI_DEVICE_INSTANCE_SIGNATURE;
+ NewPciDevice->PciSegment = PciSegment;
+ NewPciDevice->PciBus = PciBus;
+ NewPciDevice->PciDevice = PciDevice;
+ NewPciDevice->PciFunction = PciFunction;
+
+ InsertTailList(PciDeviceList, &NewPciDevice->Link);
+}
+
+/**
+ Check if a PCI device is recorded in device list.
+
+ @param PciIo PciIo instance of the device
+ @param PciDeviceList The list to record the the device
+
+ @retval TRUE The PCI device is in the list.
+ @retval FALSE The PCI device is NOT in the list.
+**/
+BOOLEAN
+IsPciDeviceInList(
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN LIST_ENTRY *PciDeviceList
+ )
+{
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ PCI_DEVICE_INSTANCE *CurrentPciDevice;
+
+ Status = PciIo->GetLocation (PciIo, &PciSegment, &PciBus, &PciDevice, &PciFunction);
+ ASSERT_EFI_ERROR(Status);
+
+ Link = GetFirstNode(PciDeviceList);
+ while (!IsNull(PciDeviceList, Link)) {
+ CurrentPciDevice = PCI_DEVICE_INSTANCE_FROM_LINK(Link);
+
+ if (CurrentPciDevice->PciSegment == PciSegment && CurrentPciDevice->PciBus == PciBus &&
+ CurrentPciDevice->PciDevice == PciDevice && CurrentPciDevice->PciFunction == PciFunction) {
+ DEBUG((DEBUG_INFO, "PCI device duplicated (Loc - %04x:%02x:%02x:%02x)\n", PciSegment, PciBus, PciDevice, PciFunction));
+ return TRUE;
+ }
+
+ Link = GetNextNode(PciDeviceList, Link);
+ }
+
+ return FALSE;
+}
+
+/*
+ return Offset of the PCI Cap ID.
+
+ @param PciIo PciIo instance of the device
+ @param CapId The Capability ID of the Pci device
+
+ @return The PCI Capability ID Offset
+*/
+UINT32
+GetPciCapId (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 CapId
+ )
+{
+ EFI_PCI_CAPABILITY_HDR PciCapIdHdr;
+ UINT32 PciCapIdOffset;
+ EFI_STATUS Status;
+
+ PciCapIdHdr.CapabilityID = ~CapId;
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_CAPBILITY_POINTER_OFFSET, 1, &PciCapIdHdr.NextItemPtr);
+ ASSERT_EFI_ERROR(Status);
+ if (PciCapIdHdr.NextItemPtr == 0 || PciCapIdHdr.NextItemPtr == 0xFF) {
+ return 0;
+ }
+ PciCapIdOffset = 0;
+ do {
+ if (PciCapIdHdr.CapabilityID == CapId) {
+ break;
+ }
+ PciCapIdOffset = PciCapIdHdr.NextItemPtr;
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PciCapIdOffset, 1, &PciCapIdHdr);
+ ASSERT_EFI_ERROR(Status);
+ } while (PciCapIdHdr.NextItemPtr != 0 && PciCapIdHdr.NextItemPtr != 0xFF);
+
+ if (PciCapIdHdr.CapabilityID == CapId) {
+ return PciCapIdOffset;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ return Offset of the PCIe Ext Cap ID.
+
+ @param PciIo PciIo instance of the device
+ @param CapId The Ext Capability ID of the Pci device
+
+ @return The PCIe Ext Capability ID Offset
+*/
+UINT32
+GetPciExpressExtCapId (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 CapId
+ )
+{
+ UINT32 PcieCapIdOffset;
+ PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER PciExpressExtCapIdHdr;
+ EFI_STATUS Status;
+
+ PcieCapIdOffset = GetPciCapId (PciIo, EFI_PCI_CAPABILITY_ID_PCIEXP);
+ if (PcieCapIdOffset == 0) {
+ return 0;
+ }
+
+ PciExpressExtCapIdHdr.CapabilityId = ~CapId;
+ PciExpressExtCapIdHdr.CapabilityVersion = 0xF;
+ PciExpressExtCapIdHdr.NextCapabilityOffset = 0x100;
+ PcieCapIdOffset = 0;
+ do {
+ if (PciExpressExtCapIdHdr.CapabilityId == CapId) {
+ break;
+ }
+ PcieCapIdOffset = PciExpressExtCapIdHdr.NextCapabilityOffset;
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, PcieCapIdOffset, 1, &PciExpressExtCapIdHdr);
+ ASSERT_EFI_ERROR(Status);
+ } while (PciExpressExtCapIdHdr.NextCapabilityOffset != 0 && PciExpressExtCapIdHdr.NextCapabilityOffset != 0xFFF);
+
+ if (PciExpressExtCapIdHdr.CapabilityId == CapId) {
+ return PcieCapIdOffset;
+ } else {
+ return 0;
+ }
+}
+
+/**
+ Read byte of the PCI device configuration space.
+
+ @param PciIo PciIo instance of the device
+ @param Offset The offset of the Pci device configuration space
+
+ @return Byte value of the PCI device configuration space.
+**/
+UINT8
+DvSecPciRead8 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, Offset, 1, &Data);
+ ASSERT_EFI_ERROR(Status);
+
+ return Data;
+}
+
+/**
+ Write byte of the PCI device configuration space.
+
+ @param PciIo PciIo instance of the device
+ @param Offset The offset of the Pci device configuration space
+ @param Data Byte value of the PCI device configuration space.
+**/
+VOID
+DvSecPciWrite8 (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 Offset,
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, Offset, 1, &Data);
+ ASSERT_EFI_ERROR(Status);
+}
+
+/**
+ Get the Digest size from the TCG hash Algorithm ID.
+
+ @param TcgAlgId TCG hash Algorithm ID
+
+ @return Digest size of the TCG hash Algorithm ID
+**/
+UINTN
+DigestSizeFromTcgAlgId (
+ IN UINT16 TcgAlgId
+ )
+{
+ switch (TcgAlgId) {
+ case TPM_ALG_SHA256:
+ return SHA256_DIGEST_SIZE;
+ case TPM_ALG_SHA384:
+ return SHA384_DIGEST_SIZE;
+ case TPM_ALG_SHA512:
+ return SHA512_DIGEST_SIZE;
+ case TPM_ALG_SM3_256:
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ Convert the SPDM hash algo ID from the TCG hash Algorithm ID.
+
+ @param TcgAlgId TCG hash Algorithm ID
+
+ @return SPDM hash algo ID
+**/
+UINT8
+TcgAlgIdToSpdmHashAlgo (
+ IN UINT16 TcgAlgId
+ )
+{
+ switch (TcgAlgId) {
+ case TPM_ALG_SHA256:
+ return SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA2_256;
+ case TPM_ALG_SHA384:
+ return SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA2_384;
+ case TPM_ALG_SHA512:
+ return SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA2_512;
+ case TPM_ALG_SM3_256:
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ This function extend the PCI digest from the DvSec register.
+
+ @param[in] PciIo The PciIo of the device.
+ @param[in] DeviceSecurityPolicy The Device Security Policy associated with the device.
+ @param[in] TcgAlgId TCG hash Algorithm ID
+ @param[in] DigestSel The digest selector
+ @param[in] Digest The digest buffer
+ @param[out] DeviceSecurityState The Device Security state associated with the device.
+**/
+VOID
+ExtendDigestRegister (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EDKII_DEVICE_SECURITY_POLICY *DeviceSecurityPolicy,
+ IN UINT16 TcgAlgId,
+ IN UINT8 DigestSel,
+ IN UINT8 *Digest,
+ OUT EDKII_DEVICE_SECURITY_STATE *DeviceSecurityState
+ )
+{
+ UINT32 PcrIndex;
+ UINT32 EventType;
+ EDKII_DEVICE_SECURITY_PCI_EVENT_DATA EventLog;
+ EDKII_DEVICE_SECURITY_EVENT_MEASUREMENT_CONTENT_MAX_HASH HashData;
+ UINT64 HashDataLen;
+ UINTN DigestSize;
+ EFI_STATUS Status;
+ PCI_TYPE00 PciData;
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof(PciData), &PciData);
+ ASSERT_EFI_ERROR(Status);
+
+ PcrIndex = EDKII_DEVICE_MEASUREMENT_COMPONENT_PCR_INDEX;
+ EventType = EDKII_DEVICE_MEASUREMENT_COMPONENT_EVENT_TYPE;
+
+ CopyMem (EventLog.EventData.Signature, EDKII_DEVICE_SECURITY_EVENT_DATA_SIGNATURE, sizeof(EventLog.EventData.Signature));
+ EventLog.EventData.Version = EDKII_DEVICE_SECURITY_EVENT_DATA_VERSION;
+ EventLog.EventData.Length = sizeof(EDKII_DEVICE_SECURITY_PCI_EVENT_DATA);
+ EventLog.EventData.SpdmMeasurementBlock.Index = DigestSel;
+ EventLog.EventData.SpdmMeasurementBlock.MeasurementType = SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_MUTABLE_FIRMWARE;
+ EventLog.EventData.SpdmMeasurementBlock.MeasurementSpecification = 0xFF;
+ EventLog.EventData.SpdmMeasurementBlock.Reserved = 0;
+ EventLog.EventData.SpdmHashAlgo = TcgAlgIdToSpdmHashAlgo (TcgAlgId);
+ EventLog.EventData.DeviceType = EDKII_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_PCI;
+ ZeroMem (EventLog.EventData.Reserved, sizeof(EventLog.EventData.Reserved));
+ EventLog.PciContext.Version = EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT_VERSION;
+ EventLog.PciContext.Length = sizeof(EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT);
+ EventLog.PciContext.VendorId = PciData.Hdr.VendorId;
+ EventLog.PciContext.DeviceId = PciData.Hdr.DeviceId;
+ EventLog.PciContext.RevisionID = PciData.Hdr.RevisionID;
+ EventLog.PciContext.ClassCode[0] = PciData.Hdr.ClassCode[0];
+ EventLog.PciContext.ClassCode[1] = PciData.Hdr.ClassCode[1];
+ EventLog.PciContext.ClassCode[2] = PciData.Hdr.ClassCode[2];
+ if ((PciData.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
+ EventLog.PciContext.SubsystemVendorID = PciData.Device.SubsystemVendorID;
+ EventLog.PciContext.SubsystemID = PciData.Device.SubsystemID;
+ } else {
+ EventLog.PciContext.SubsystemVendorID = 0;
+ EventLog.PciContext.SubsystemID = 0;
+ }
+
+ DigestSize = DigestSizeFromTcgAlgId (TcgAlgId);
+ CopyMem (&HashData.Measurement, Digest, DigestSize);
+
+ HashDataLen = DigestSize;
+ Status = TpmMeasureAndLogData (
+ PcrIndex,
+ EventType,
+ &EventLog,
+ EventLog.EventData.Length,
+ &HashData,
+ HashDataLen
+ );
+ DEBUG((DEBUG_INFO, "TpmMeasureAndLogData - %r\n", Status));
+ if (EFI_ERROR(Status)) {
+ DeviceSecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_TCG_EXTEND_TPM_PCR;
+ } else {
+ RecordPciDeviceInList (PciIo, &mSecurityEventMeasurementDeviceList);
+ }
+}
+
+/**
+ This function reads the PCI digest from the DvSec register and extend to TPM.
+
+ @param[in] PciIo The PciIo of the device.
+ @param[in] DvSecOffset The DvSec register offset of the device.
+ @param[in] DeviceSecurityPolicy The Device Security Policy associated with the device.
+ @param[out] DeviceSecurityState The Device Security state associated with the device.
+**/
+VOID
+DoMeasurementsFromDigestRegister (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT32 DvSecOffset,
+ IN EDKII_DEVICE_SECURITY_POLICY *DeviceSecurityPolicy,
+ OUT EDKII_DEVICE_SECURITY_STATE *DeviceSecurityState
+ )
+{
+ UINT8 Modified;
+ UINT8 Valid;
+ UINT16 TcgAlgId;
+ UINT8 NumDigest;
+ UINT8 DigestSel;
+ UINT8 Digest[SHA512_DIGEST_SIZE];
+ UINTN DigestSize;
+ EFI_STATUS Status;
+
+ TcgAlgId = DvSecPciRead8 (
+ PciIo,
+ DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, TcgAlgId)
+ );
+ DEBUG((DEBUG_INFO, " TcgAlgId - 0x%04x\n", TcgAlgId));
+ DigestSize = DigestSizeFromTcgAlgId (TcgAlgId);
+ if (DigestSize == 0) {
+ DEBUG((DEBUG_INFO, "Unsupported Algorithm - 0x%04x\n", TcgAlgId));
+ DeviceSecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_PCI_NO_CAPABILITIES;
+ return ;
+ }
+ DEBUG((DEBUG_INFO, " (DigestSize: 0x%x)\n", DigestSize));
+
+ DeviceSecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_SUCCESS;
+
+ NumDigest = DvSecPciRead8 (
+ PciIo,
+ DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, FirmwareID)
+ );
+ DEBUG((DEBUG_INFO, " NumDigest - 0x%02x\n", NumDigest));
+
+ Valid = DvSecPciRead8 (
+ PciIo,
+ DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, Valid)
+ );
+ DEBUG((DEBUG_INFO, " Valid - 0x%02x\n", Valid));
+
+ //
+ // Only 2 are supported as maximum.
+ // But hardware may report 3.
+ //
+ if (NumDigest > 2) {
+ NumDigest = 2;
+ }
+
+ for (DigestSel = 0; DigestSel < NumDigest; DigestSel++) {
+ DEBUG((DEBUG_INFO, " DigestSel - 0x%02x\n", DigestSel));
+ if ((DigestSel == 0) && ((Valid & INTEL_PCI_DIGEST_0_VALID) == 0)) {
+ continue;
+ }
+ if ((DigestSel == 1) && ((Valid & INTEL_PCI_DIGEST_1_VALID) == 0)) {
+ continue;
+ }
+ while (TRUE) {
+ //
+ // Host MUST clear DIGEST_MODIFIED before read DIGEST.
+ //
+ DvSecPciWrite8 (
+ PciIo,
+ DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, Modified),
+ INTEL_PCI_DIGEST_MODIFIED
+ );
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ (UINT32)(DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + sizeof(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE) + DigestSize * DigestSel),
+ DigestSize,
+ Digest
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // After read DIGEST, Host MUST consult DIGEST_MODIFIED.
+ //
+ Modified = DvSecPciRead8 (
+ PciIo,
+ DvSecOffset + sizeof(INTEL_PCI_DIGEST_CAPABILITY_HEADER) + OFFSET_OF(INTEL_PCI_DIGEST_CAPABILITY_STRUCTURE, Modified)
+ );
+ if ((Modified & INTEL_PCI_DIGEST_MODIFIED) == 0) {
+ break;
+ }
+ }
+
+ //
+ // Dump Digest
+ //
+ {
+ UINTN Index;
+ DEBUG((DEBUG_INFO, " Digest - "));
+ for (Index = 0; Index < DigestSize; Index++) {
+ DEBUG((DEBUG_INFO, "%02x", *(Digest + Index)));
+ }
+ DEBUG((DEBUG_INFO, "\n"));
+ }
+
+ DEBUG((DEBUG_INFO, "ExtendDigestRegister...\n", ExtendDigestRegister));
+ ExtendDigestRegister (PciIo, DeviceSecurityPolicy, TcgAlgId, DigestSel, Digest, DeviceSecurityState);
+ }
+}
+
+/**
+ The device driver uses this service to measure a PCI device.
+
+ @param[in] PciIo The PciIo of the device.
+ @param[in] DeviceSecurityPolicy The Device Security Policy associated with the device.
+ @param[out] DeviceSecurityState The Device Security state associated with the device.
+**/
+VOID
+DoDeviceMeasurement (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EDKII_DEVICE_SECURITY_POLICY *DeviceSecurityPolicy,
+ OUT EDKII_DEVICE_SECURITY_STATE *DeviceSecurityState
+ )
+{
+ UINT32 DvSecOffset;
+ INTEL_PCI_DIGEST_CAPABILITY_HEADER DvSecHdr;
+ EFI_STATUS Status;
+
+ if (IsPciDeviceInList (PciIo, &mSecurityEventMeasurementDeviceList)) {
+ DeviceSecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_SUCCESS;
+ return ;
+ }
+
+ DvSecOffset = GetPciExpressExtCapId (PciIo, INTEL_PCI_CAPID_DVSEC);
+ DEBUG((DEBUG_INFO, "DvSecOffset - 0x%x\n", DvSecOffset));
+ if (DvSecOffset == 0) {
+ DeviceSecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_PCI_NO_CAPABILITIES;
+ return ;
+ }
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, DvSecOffset, sizeof(DvSecHdr)/sizeof(UINT16), &DvSecHdr);
+ ASSERT_EFI_ERROR(Status);
+ DEBUG((DEBUG_INFO, " CapId - 0x%04x\n", DvSecHdr.CapId));
+ DEBUG((DEBUG_INFO, " CapVersion - 0x%01x\n", DvSecHdr.CapVersion));
+ DEBUG((DEBUG_INFO, " NextOffset - 0x%03x\n", DvSecHdr.NextOffset));
+ DEBUG((DEBUG_INFO, " DvSecVendorId - 0x%04x\n", DvSecHdr.DvSecVendorId));
+ DEBUG((DEBUG_INFO, " DvSecRevision - 0x%01x\n", DvSecHdr.DvSecRevision));
+ DEBUG((DEBUG_INFO, " DvSecLength - 0x%03x\n", DvSecHdr.DvSecLength));
+ DEBUG((DEBUG_INFO, " DvSecId - 0x%04x\n", DvSecHdr.DvSecId));
+ if ((DvSecHdr.DvSecVendorId != INTEL_PCI_DVSEC_VENDORID_INTEL) &&
+ (DvSecHdr.DvSecId != INTEL_PCI_DVSEC_DVSECID_MEASUREMENT)) {
+ DeviceSecurityState->MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_PCI_NO_CAPABILITIES;
+ return ;
+ }
+
+ DoMeasurementsFromDigestRegister (PciIo, DvSecOffset, DeviceSecurityPolicy, DeviceSecurityState);
+}
+
+/**
+ The device driver uses this service to verify a PCI device.
+
+ @param[in] PciIo The PciIo of the device.
+ @param[in] DeviceSecurityPolicy The Device Security Policy associated with the device.
+ @param[out] DeviceSecurityState The Device Security state associated with the device.
+**/
+VOID
+DoDeviceAuthentication (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EDKII_DEVICE_SECURITY_POLICY *DeviceSecurityPolicy,
+ OUT EDKII_DEVICE_SECURITY_STATE *DeviceSecurityState
+ )
+{
+ DeviceSecurityState->AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_UNSUPPORTED;
+}
+
+/**
+ The device driver uses this service to measure and/or verify a device.
+
+ The flow in device driver is:
+ 1) Device driver discovers a new device.
+ 2) Device driver creates an EFI_DEVICE_PATH_PROTOCOL.
+ 3) Device driver creates a device access protocol. e.g.
+ EFI_PCI_IO_PROTOCOL for PCI device.
+ EFI_USB_IO_PROTOCOL for USB device.
+ EFI_EXT_SCSI_PASS_THRU_PROTOCOL for SCSI device.
+ EFI_ATA_PASS_THRU_PROTOCOL for ATA device.
+ EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL for NVMe device.
+ EFI_SD_MMC_PASS_THRU_PROTOCOL for SD/MMC device.
+ 4) Device driver installs the EFI_DEVICE_PATH_PROTOCOL with EFI_DEVICE_PATH_PROTOCOL_GUID,
+ and the device access protocol with EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID.
+ Once it is done, a DeviceHandle is returned.
+ 5) Device driver creates EDKII_DEVICE_IDENTIFIER with EDKII_DEVICE_IDENTIFIER_TYPE_xxx_GUID
+ and the DeviceHandle.
+ 6) Device driver calls DeviceAuthenticate().
+ 7) If DeviceAuthenticate() returns EFI_SECURITY_VIOLATION, the device driver uninstalls
+ all protocols on this handle.
+ 8) If DeviceAuthenticate() returns EFI_SUCCESS, the device driver installs the device access
+ protocol with a real protocol GUID. e.g.
+ EFI_PCI_IO_PROTOCOL with EFI_PCI_IO_PROTOCOL_GUID.
+ EFI_USB_IO_PROTOCOL with EFI_USB_IO_PROTOCOL_GUID.
+
+ @param[in] This The protocol instance pointer.
+ @param[in] DeviceId The Identifier for the device.
+
+ @retval EFI_SUCCESS The device specified by the DeviceId passed the measurement
+ and/or authentication based upon the platform policy.
+ If TCG measurement is required, the measurement is extended to TPM PCR.
+ @retval EFI_SECURITY_VIOLATION The device fails to return the measurement data.
+ @retval EFI_SECURITY_VIOLATION The device fails to response the authentication request.
+ @retval EFI_SECURITY_VIOLATION The system fails to verify the device based upon the authentication response.
+ @retval EFI_SECURITY_VIOLATION The system fails to extend the measurement to TPM PCR.
+**/
+EFI_STATUS
+EFIAPI
+DeviceAuthentication (
+ IN EDKII_DEVICE_SECURITY_PROTOCOL *This,
+ IN EDKII_DEVICE_IDENTIFIER *DeviceId
+ )
+{
+ EDKII_DEVICE_SECURITY_POLICY *DeviceSecurityPolicy;
+ EDKII_DEVICE_SECURITY_STATE DeviceSecurityState;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+
+ if (mDeviceSecurityPolicy == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if (!CompareGuid (&DeviceId->DeviceType, &gEdkiiDeviceIdentifierTypePciGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->HandleProtocol (
+ DeviceId->DeviceHandle,
+ &gEdkiiDeviceIdentifierTypePciGuid,
+ (VOID **)&PciIo
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Locate - DeviceIdentifierTypePci - %r\n", Status));
+ return EFI_SUCCESS;
+ }
+
+ DeviceSecurityState.Version = 0x1;
+ DeviceSecurityState.MeasurementState = 0x0;
+ DeviceSecurityState.AuthenticationState = 0x0;
+
+ Status = mDeviceSecurityPolicy->GetDevicePolicy (mDeviceSecurityPolicy, DeviceId, &DeviceSecurityPolicy);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "mDeviceSecurityPolicy->GetDevicePolicy - %r\n", Status));
+ DeviceSecurityState.MeasurementState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_GET_POLICY_PROTOCOL;
+ DeviceSecurityState.AuthenticationState = EDKII_DEVICE_SECURITY_STATE_ERROR_UEFI_GET_POLICY_PROTOCOL;
+ } else {
+ if ((DeviceSecurityPolicy->MeasurementPolicy & EDKII_DEVICE_MEASUREMENT_POLICY_REQUIRED) != 0) {
+ DoDeviceMeasurement (PciIo, DeviceSecurityPolicy, &DeviceSecurityState);
+ DEBUG((DEBUG_ERROR, "MeasurementState - 0x%08x\n", DeviceSecurityState.MeasurementState));
+ }
+ if ((DeviceSecurityPolicy->AuthenticationPolicy & EDKII_DEVICE_AUTHENTICATION_POLICY_REQUIRED) != 0) {
+ DoDeviceAuthentication (PciIo, DeviceSecurityPolicy, &DeviceSecurityState);
+ DEBUG((DEBUG_ERROR, "AuthenticationState - 0x%08x\n", DeviceSecurityState.AuthenticationState));
+ }
+ }
+
+ Status = mDeviceSecurityPolicy->SetDeviceState (mDeviceSecurityPolicy, DeviceId, &DeviceSecurityState);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "mDeviceSecurityPolicy->SetDeviceState - %r\n", Status));
+ }
+
+ if ((DeviceSecurityState.MeasurementState == 0) &&
+ (DeviceSecurityState.AuthenticationState == 0)) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_SECURITY_VIOLATION;
+ }
+}
+
+EDKII_DEVICE_SECURITY_PROTOCOL mDeviceSecurity = {
+ EDKII_DEVICE_SECURITY_PROTOCOL_REVISION,
+ DeviceAuthentication
+};
+
+/**
+ Entrypoint of the device security driver.
+
+ @param[in] ImageHandle ImageHandle of the loaded driver
+ @param[in] SystemTable Pointer to the System Table
+
+ @retval EFI_SUCCESS The Protocol is installed.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources available to initialize driver.
+ @retval EFI_DEVICE_ERROR A device error occurred attempting to initialize the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+MainEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEdkiiDeviceSecurityPolicyProtocolGuid, NULL, (VOID **)&mDeviceSecurityPolicy);
+ ASSERT_EFI_ERROR(Status);
+
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEdkiiDeviceSecurityProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ (VOID **)&mDeviceSecurity
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ return Status;
+}
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.inf b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.inf
new file mode 100644
index 0000000000..89a4c8fadd
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/IntelPciDeviceSecurityDxe.inf
@@ -0,0 +1,45 @@
+## @file
+# EDKII Device Security library for PCI device
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IntelPciDeviceSecurityDxe
+ FILE_GUID = D9569195-ED94-47D2-9523-38BF2D201371
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MainEntryPoint
+
+[Sources]
+ IntelPciDeviceSecurityDxe.c
+ TcgDeviceEvent.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelSiliconPkg/IntelSiliconPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ DevicePathLib
+ BaseMemoryLib
+ PrintLib
+ DebugLib
+ UefiLib
+ PcdLib
+ TpmMeasurementLib
+
+[Protocols]
+ gEdkiiDeviceSecurityPolicyProtocolGuid ## CONSUMES
+ gEdkiiDeviceSecurityProtocolGuid ## PRODUCES
+ gEdkiiDeviceIdentifierTypePciGuid ## COMSUMES
+
+[Depex]
+ gEdkiiDeviceSecurityPolicyProtocolGuid
diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/TcgDeviceEvent.h b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/TcgDeviceEvent.h
new file mode 100644
index 0000000000..8b1227dace
--- /dev/null
+++ b/Silicon/Intel/IntelSiliconPkg/Feature/PcieSecurity/IntelPciDeviceSecurityDxe/TcgDeviceEvent.h
@@ -0,0 +1,193 @@
+/** @file
+ TCG Device Event data structure
+Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+
+#ifndef __TCG_EVENT_DATA_H__
+#define __TCG_EVENT_DATA_H__
+
+#include <IndustryStandard/Spdm.h>
+
+#pragma pack(1)
+
+// -------------------------------------------
+// TCG Measurement for SPDM Device Measurement
+// -------------------------------------------
+
+//
+// Device Firmware Component (including immutable ROM or mutable firmware)
+//
+#define EDKII_DEVICE_MEASUREMENT_COMPONENT_PCR_INDEX 2
+#define EDKII_DEVICE_MEASUREMENT_COMPONENT_EVENT_TYPE 0x800000E1
+//
+// Device Firmware Configuration (including hardware configuration or firmware configuration)
+//
+#define EDKII_DEVICE_MEASUREMENT_CONFIGURATION_PCR_INDEX 4
+#define EDKII_DEVICE_MEASUREMENT_CONFIGURATION_EVENT_TYPE 0x800000E2
+
+//
+// Device Firmware Measurement Measurement Data
+// The measurement data is the device firmware measurement.
+//
+// TBD: Open:
+// In order to support crypto agile, the firmware will hash the DeviceMeasurement again.
+// As such the device measurement algo might be different with host firmware measurement algo.
+//
+
+//
+// Device Firmware Measurement Event Data
+//
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_SIGNATURE "SPDM Device Sec\0"
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_VERSION 0
+
+//
+// Device Type
+// 0x03 ~ 0xDF reserved by TCG.
+// 0xE0 ~ 0xFF reserved by OEM.
+//
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_NULL 0
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_PCI 1
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_USB 2
+
+//
+// Device Firmware Measurement Event Data Common Part
+// The device specific part should follow this data structure.
+//
+typedef struct {
+ //
+ // It must be EDKII_DEVICE_SECURITY_EVENT_DATA_SIGNATURE.
+ //
+ UINT8 Signature[16];
+ //
+ // It must be EDKII_DEVICE_SECURITY_EVENT_DATA_VERSION.
+ //
+ UINT16 Version;
+ //
+ // The length of whole data structure, including Device Context.
+ //
+ UINT16 Length;
+ //
+ // The SPDM measurement block header.
+ //
+ SPDM_MEASUREMENT_BLOCK_HEADER SpdmMeasurementBlock;
+ //
+ // The SpdmHashAlgo
+ //
+ UINT8 SpdmHashAlgo;
+ //
+ // The type of device. This field is to determine the Device Context followed by.
+ //
+ UINT8 DeviceType;
+ //
+ // reserved. Make UINT64 aligned.
+ //
+ UINT8 Reserved[6];
+} EDKII_DEVICE_SECURITY_EVENT_DATA_HEADER;
+
+//
+// PCI device specific context
+//
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT_VERSION 0
+typedef struct {
+ UINT16 Version;
+ UINT16 Length;
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT8 RevisionID;
+ UINT8 ClassCode[3];
+ UINT16 SubsystemVendorID;
+ UINT16 SubsystemID;
+} EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT;
+
+typedef struct {
+ EDKII_DEVICE_SECURITY_EVENT_DATA_HEADER EventData;
+ EDKII_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT PciContext;
+} EDKII_DEVICE_SECURITY_PCI_EVENT_DATA;
+
+//
+// USB device specific context
+//
+#define EDKII_DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT_VERSION 0
+typedef struct {
+ UINT16 Version;
+ UINT16 Length;
+//UINT8 DeviceDescriptor[DescLen];
+//UINT8 BodDescriptor[DescLen];
+//UINT8 ConfigurationDescriptor[DescLen][NumOfConfiguration];
+} EDKII_DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT;
+
+typedef struct {
+ EDKII_DEVICE_SECURITY_EVENT_DATA_HEADER EventData;
+ EDKII_DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT PciContext;
+} EDKII_DEVICE_SECURITY_USB_EVENT_DATA;
+
+// ----------------------------------------------
+// TCG Measurement for SPDM Device Authentication
+// ----------------------------------------------
+
+//
+// Device Root cert is stored into a UEFI authenticated variable.
+// It is non-volatile, boot service, runtime service, and time based authenticated variable.
+// The "devdb" includes a list of allowed device root cert.
+// The "devdbx" includes a list of forbidden device root cert.
+// The usage of "devdb" and "devdbx" is same as "db" and "dbx" in UEFI secure boot.
+//
+// NOTE: We choose not to mix "db"/"dbx" for better management purpose.
+//
+
+#define EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME L"devdb"
+#define EDKII_DEVICE_ROOT_CERT_VARAIBLE2_NAME L"devdbx"
+
+#define EDKII_DEVICE_SIGNATURE_DATABASE_GUID \
+ {0xb9c2b4f4, 0xbf5f, 0x462d, 0x8a, 0xdf, 0xc5, 0xc7, 0xa, 0xc3, 0x5d, 0xad}
+
+//
+// Platform Firmware adhering to the policy MUST therefore measure the following values into PCR[7]:
+// 1. The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME variable.
+// 2. The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/EDKII_DEVICE_ROOT_CERT_VARAIBLE2_NAME variable.
+// 3. Entries in the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME variable to
+// authenticate the device.
+//
+// For all UEFI variable value events, the eventType SHALL be EV_EFI_VARIABLE_DRIVER_CONFIG and the Event
+// value SHALL be the value of the UEFI_VARIABLE_DATA structure (this structure SHALL be considered byte-aligned).
+// The measurement digest MUST be tagged Hash for each supported PCR bank of the event data which is the
+// UEFI_VARIABLE_DATA structure. The UEFI_VARIABLE_DATA.UnicodeNameLength value is the number of CHAR16
+// characters (not the number of bytes). The UEFI_VARIABLE_DATA.UnicodeName contents MUST NOT include a NUL.
+// If reading a UEFI variable returns UEFI_NOT_FOUND, the UEFI_VARIABLE_DATA.VariableDataLength field MUST
+// be set to zero and UEFI_VARIABLE_DATA.VariableData field will have a size of zero.
+//
+
+//
+// Entities that MUST be measured if the TPM is enabled:
+// 1. Before executing any code not cryptographically authenticated as being provided by the Platform Manufacturer,
+// the Platform Manufacturer firmware MUST measure the following values, in the order listed using the
+// EV_EFI_VARIABLE_DRIVER_CONFIG event type to PCR[7]:
+// a) The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME variable.
+// b) The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ EDKII_DEVICE_ROOT_CERT_VARAIBLE2_NAME variable.
+// 2. If the platform supports changing any of the following UEFI policy variables after they are initially measured
+// in PCR[7] and before ExitBootServices() has completed, the platform MAY be restarted OR the variables MUST be
+// remeasured into PCR[7]. Additionally the normal update process for setting any of the UEFI variables below SHOULD
+// occur before the initial measurement in PCR[7] or after the call to ExitBootServices() has completed.
+// a) The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME variable.
+// b) The content of the EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ EDKII_DEVICE_ROOT_CERT_VARAIBLE2_NAME variable.
+// 3. The system SHALL measure the EV_SEPARATOR event in PCR[7]. (This occurs at the same time the separator is
+// measured to PCR[0-7].)
+// Before setting up a device, the UEFI firmware SHALL determine if the entry in the
+// EDKII_DEVICE_SIGNATURE_DATABASE_GUID/ EDKII_DEVICE_ROOT_CERT_VARAIBLE_NAME variable that was used to validate
+// the device has previously been measured in PCR[7]. If it has not been, it MUST be measured into PCR[7] as follows.
+// If it has been measured previously, it MUST NOT be measured again. The measurement SHALL occur in conjunction
+// with device setup.
+// a) The eventType SHALL be EV_EFI_VARIABLE_AUTHORITY.
+// b) The event value SHALL be the value of the UEFI_VARIABLE_DATA structure.
+// i. The UEFI_VARIABLE_DATA.VariableData value SHALL be the UEFI_SIGNATURE_DATA value from the
+// UEFI_SIGNATURE_LIST that contained the authority that was used to validate the image.
+// ii. The UEFI_VARIABLE_DATA.VariableName SHALL be set to UEFI_IMAGE_SECURITY_DATABASE_GUID.
+// iii. The UEFI_VARIABLE_DATA.UnicodeName SHALL be set to the value of UEFI_IMAGE_SECURITY_DATABASE.
+// The value MUST NOT include the terminating NUL.
+//
+
+#pragma pack()
+
+#endif
--
2.19.2.windows.1

Join devel@edk2.groups.io to automatically receive all group messages.