From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga02.intel.com (mga02.intel.com []) by mx.groups.io with SMTP id smtpd.web11.5236.1572525094034209064 for ; Thu, 31 Oct 2019 05:31:39 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: intel.com, ip: , mailfrom: jiewen.yao@intel.com) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 31 Oct 2019 05:31:39 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.68,250,1569308400"; d="scan'208";a="283875731" Received: from jyao1-mobl2.ccr.corp.intel.com ([10.254.211.198]) by orsmga001.jf.intel.com with ESMTP; 31 Oct 2019 05:31:37 -0700 From: "Yao, Jiewen" To: devel@edk2.groups.io Cc: Ray Ni , Rangasai V Chaganty , Yun Lou Subject: [PATCH V2 4/6] IntelSiliconPkg/IntelPciDeviceSecurityDxe: Add PciSecurity. Date: Thu, 31 Oct 2019 20:31:25 +0800 Message-Id: <20191031123127.10900-5-jiewen.yao@intel.com> X-Mailer: git-send-email 2.19.2.windows.1 In-Reply-To: <20191031123127.10900-1-jiewen.yao@intel.com> References: <20191031123127.10900-1-jiewen.yao@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 Cc: Rangasai V Chaganty Cc: Yun Lou Signed-off-by: Jiewen Yao Signed-off-by: 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.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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.
+# 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.
+SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + + +#ifndef __TCG_EVENT_DATA_H__ +#define __TCG_EVENT_DATA_H__ + +#include + +#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