/** @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 typedef struct { TCG_DEVICE_SECURITY_EVENT_DATA_HEADER EventData; SPDM_MEASUREMENT_BLOCK_COMMON_HEADER CommonHeader; SPDM_MEASUREMENT_BLOCK_DMTF_HEADER DmtfHeader; UINT8 Digest[SHA256_DIGEST_SIZE]; TCG_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT PciContext; } EDKII_DEVICE_SECURITY_PCI_EVENT_DATA; 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(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: case TPM_ALG_SHA512: 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 **/ UINT32 TcgAlgIdToSpdmHashAlgo ( IN UINT16 TcgAlgId ) { switch (TcgAlgId) { case TPM_ALG_SHA256: return SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256; case TPM_ALG_SHA384: case TPM_ALG_SHA512: 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; EFI_STATUS Status; PCI_TYPE00 PciData; Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof(PciData), &PciData); ASSERT_EFI_ERROR(Status); // // Use PCR 2 for Firmware Blob code. // PcrIndex = 2; EventType = EV_EFI_SPDM_FIRMWARE_BLOB; CopyMem (EventLog.EventData.Signature, TCG_DEVICE_SECURITY_EVENT_DATA_SIGNATURE, sizeof(EventLog.EventData.Signature)); EventLog.EventData.Version = TCG_DEVICE_SECURITY_EVENT_DATA_VERSION; EventLog.EventData.Length = sizeof(EDKII_DEVICE_SECURITY_PCI_EVENT_DATA); EventLog.EventData.SpdmHashAlgo = TcgAlgIdToSpdmHashAlgo (TcgAlgId); EventLog.EventData.DeviceType = TCG_DEVICE_SECURITY_EVENT_DATA_DEVICE_TYPE_PCI; EventLog.CommonHeader.Index = DigestSel; EventLog.CommonHeader.MeasurementSpecification = SPDM_MEASUREMENT_BLOCK_HEADER_SPECIFICATION_DMTF; EventLog.CommonHeader.MeasurementSize = sizeof(SPDM_MEASUREMENT_BLOCK_DMTF_HEADER) + SHA256_DIGEST_SIZE; EventLog.DmtfHeader.DMTFSpecMeasurementValueType = SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_MUTABLE_FIRMWARE; EventLog.DmtfHeader.DMTFSpecMeasurementValueSize = SHA256_DIGEST_SIZE; CopyMem (&EventLog.Digest, Digest, SHA256_DIGEST_SIZE); EventLog.PciContext.Version = TCG_DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT_VERSION; EventLog.PciContext.Length = sizeof(TCG_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; } Status = TpmMeasureAndLogData ( PcrIndex, EventType, &EventLog, EventLog.EventData.Length, Digest, SHA256_DIGEST_SIZE ); 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[SHA256_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, "DvSec Capability - 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.Revision = EDKII_DEVICE_SECURITY_STATE_REVISION; 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_REQUIRED) != 0) { DoDeviceMeasurement (PciIo, &DeviceSecurityPolicy, &DeviceSecurityState); DEBUG((DEBUG_ERROR, "MeasurementState - 0x%08x\n", DeviceSecurityState.MeasurementState)); } if ((DeviceSecurityPolicy.AuthenticationPolicy & EDKII_DEVICE_AUTHENTICATION_REQUIRED) != 0) { DoDeviceAuthentication (PciIo, &DeviceSecurityPolicy, &DeviceSecurityState); DEBUG((DEBUG_ERROR, "AuthenticationState - 0x%08x\n", DeviceSecurityState.AuthenticationState)); } } Status = mDeviceSecurityPolicy->NotifyDeviceState (mDeviceSecurityPolicy, DeviceId, &DeviceSecurityState); if (EFI_ERROR(Status)) { DEBUG((DEBUG_ERROR, "mDeviceSecurityPolicy->NotifyDeviceState - %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; }