diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/TpmPcrEvent.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/TpmPcrEvent.java index 0f2c9cc5..128e7853 100644 --- a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/TpmPcrEvent.java +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/TpmPcrEvent.java @@ -5,6 +5,7 @@ import hirs.utils.tpm.eventlog.events.EvCompactHash; import hirs.utils.tpm.eventlog.events.EvConstants; import hirs.utils.tpm.eventlog.events.EvEfiGptPartition; import hirs.utils.tpm.eventlog.events.EvEfiHandoffTable; +import hirs.utils.tpm.eventlog.events.EvEfiSpdmFirmwareBlob; import hirs.utils.tpm.eventlog.events.EvEfiSpecIdEvent; import hirs.utils.tpm.eventlog.events.EvEventTag; import hirs.utils.tpm.eventlog.events.EvIPL; @@ -374,6 +375,14 @@ public class TpmPcrEvent { break; case EvConstants.EV_EFI_HCRTM_EVENT: break; + case EvConstants.EV_EFI_SPDM_FIRMWARE_BLOB: + try { + sb.append(new EvEfiSpdmFirmwareBlob(eventContent).toString()); + } catch (UnsupportedEncodingException ueEx) { + log.error(ueEx); + sb.append(ueEx.toString()); + } + break; default: sb.append("Unknown Event found\n"); } @@ -532,6 +541,9 @@ public class TpmPcrEvent { case EvConstants.EV_EFI_VARIABLE_AUTHORITY: description += "Event Content:\n" + new UefiVariable(content).toString(); break; + case EvConstants.EV_EFI_SPDM_FIRMWARE_BLOB: + description += "Event Content:\n" + new EvEfiSpdmFirmwareBlob(content).toString(); + break; default: description += " Unknown Event found" + "\n"; } @@ -609,6 +621,8 @@ public class TpmPcrEvent { return "EV_EFI_HCRTM_EVENT"; } else if (event == EvConstants.EV_EFI_VARIABLE_AUTHORITY) { return "EV_EFI_VARIABLE_AUTHORITY"; + } else if (event == EvConstants.EV_EFI_SPDM_FIRMWARE_BLOB) { + return "EV_EFI_SPDM_FIRMWARE_BLOB"; } else { return "Unknown Event ID " + event + " encountered"; } diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEvent.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEvent.java new file mode 100644 index 00000000..0e97f8a1 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEvent.java @@ -0,0 +1,103 @@ +package hirs.utils.tpm.eventlog.events; + +import lombok.Getter; + + +/** + * Abstract base class to process the DEVICE_SECURITY_EVENT_DATA or ..DATA2 event. + * Parses event data per PFP v1.06 Rev52 Tables 20 and 26. + * The event data comes in 2 forms: + * 1) DEVICE_SECURITY_EVENT_DATA or + * 2) DEVICE_SECURITY_EVENT_DATA2 + * The first 2 fields of the respective headers are the same in both ..DATA and ..DATA2. + * Field 1: + * The first 16 bytes of the event data header MUST be a String based identifier (Signature), + * NUL-terminated, per PFP. The only currently defined Signature is "SPDM Device Sec", which + * implies the data is a DEVICE_SECURITY_EVENT_DATA or ..DATA2. + * Field 2: + * The Version field indicates whether the Device Security Event is ..DATA or ..DATA2. + * + * DEVICE SECURITY EVENT structures defined by PFP v1.06 Rev 52: + *

+ * typedef struct tdDEVICE_SECURITY_EVENT_DATA { + * DEVICE_SECURITY_EVENT_DATA_HEADER EventDataHeader; + * DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT DeviceContext; + * } DEVICE_SECURITY_EVENT_DATA; + *

+ * typedef struct tdDEVICE_SECURITY_EVENT_DATA2 { + * DEVICE_SECURITY_EVENT_DATA_HEADER2 EventDataHeader; + * DEVICE_SECURITY_EVENT_DATA_SUB_HEADER EventDataSubHeader; + * DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT DeviceContext; + * } DEVICE_SECURITY_EVENT_DATA2; + *

+ * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER or HEADER2 { + * UINT8 Signature[16]; + * UINT16 Version; + * ... ... + * } + *

+ * Notes: + * 1. Has an EventType of EV_EFI_SPDM_FIRMWARE_BLOB (0x800000E1) + * 2. Event content defined as DEVICE_SECURITY_EVENT_DATA Struct. + * 3. First 16 bytes of the structure header is an ASCII "SPDM Device Sec" + *

+ * Only a few of the Device Security Event Data events have been implemented as there are many, + * but only those that were reported using the test devices at hand. + * Without test patterns, the processing may lead to an un-handled exception. + * For now, the only test pattern uses ..DeviceContext with PCI only, without USB -> assume only 1 + * even though the spec says both are in the data structure. If it is only 1, though, there's no + * method to tell them apart. + */ +public abstract class DeviceSecurityEvent { + + /** + * Human readable description of the data within the + * DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT. DEVICE can be either PCI or USB. + */ + @Getter + String deviceContextInfo = ""; + + /** + * DeviceSecurityEventData Default Constructor. + * + */ + public DeviceSecurityEvent() { + + } + + /** + * Parse the Device Context structure, can be PCI or USB based on device type field. + * + * @param dSEDbytes byte array holding the DeviceSecurityEventData. + * @param startByte starting byte of the device structure (depends on length of header). + * @param deviceType device type either PCI or USB. + * + */ + public void parseDeviceContext(final byte[] dSEDbytes, int startByte, int deviceType) { + + int deviceContextLength = dSEDbytes.length - startByte; + + // get the device context bytes + byte[] deviceContextBytes = new byte[deviceContextLength]; + System.arraycopy(dSEDbytes, startByte, deviceContextBytes, 0, + deviceContextLength); + + if (deviceType == 0) { + deviceContextInfo = "No Device Context (indicated by device type value of 0"; + } + else if (deviceType == 1) { + DeviceSecurityEventDataPciContext dSEDpciContext + = new DeviceSecurityEventDataPciContext(deviceContextBytes); + deviceContextInfo = dSEDpciContext.toString(); + } + //else if (deviceType == 2) { + //DeviceSecurityEventDataUsbContext dSEDusbContext + // = new DeviceSecurityEventDataUsbContext(deviceContextBytes); + //deviceContextInfo = dSEDusbContext.toString(); + //deviceContextInfo = "Device type is USB - to be implemented in future"; + //} + else { + deviceContextInfo = " Unknown device type; cannot process device context"; + } + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventData.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventData.java new file mode 100644 index 00000000..4f996548 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventData.java @@ -0,0 +1,45 @@ +package hirs.utils.tpm.eventlog.events; + +import lombok.Getter; +import java.io.UnsupportedEncodingException; + +/** + * Class to process DEVICE_SECURITY_EVENT_DATA. + * Parses event data per PFP v1.06 Rev52 Table 20. + *

+ * typedef struct tdDEVICE_SECURITY_EVENT_DATA { + * DEVICE_SECURITY_EVENT_DATA_HEADER EventDataHeader; + * DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT DeviceContext; + * } DEVICE_SECURITY_EVENT_DATA; + *

+ */ +public class DeviceSecurityEventData extends DeviceSecurityEvent { + + /** + * DeviceSecurityEventDataHeader Object. + */ + @Getter + private DeviceSecurityEventDataHeader dsedHeader = null; + + /** + * DeviceSecurityEventData Constructor. + * + * @param dSEDbytes byte array holding the DeviceSecurityEventData. + */ + public DeviceSecurityEventData(final byte[] dSEDbytes) throws UnsupportedEncodingException { + dsedHeader = new DeviceSecurityEventDataHeader(dSEDbytes); + parseDeviceContext(dSEDbytes, dsedHeader.getDSEDheaderByteSize(), dsedHeader.getDeviceType()); + } + + /** + * Returns a human readable description of the data within this structure. + * + * @return a description of this structure. + */ + public String toString() { + String dsedInfo = ""; + dsedInfo += dsedHeader.toString(); + dsedInfo += getDeviceContextInfo(); + return dsedInfo; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventData2.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventData2.java new file mode 100644 index 00000000..014b6fe0 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventData2.java @@ -0,0 +1,46 @@ +package hirs.utils.tpm.eventlog.events; + +import lombok.Getter; + +// TODO Placeholder class to be implemented upon getting test pattern +/** + * Class to process DEVICE_SECURITY_EVENT_DATA2. + * Parses event data per PFP v1.06 Rev52 Table 26. + *

+ * typedef struct tdDEVICE_SECURITY_EVENT_DATA2 { + * DEVICE_SECURITY_EVENT_DATA_HEADER2 EventDataHeader; + * DEVICE_SECURITY_EVENT_DATA_SUB_HEADER EventDataSubHeader; + * DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT DeviceContext; + * } DEVICE_SECURITY_EVENT_DATA2; + *

+ */ +public class DeviceSecurityEventData2 extends DeviceSecurityEvent { + + /** + * DeviceSecurityEventDataHeader Object. + */ + @Getter + private DeviceSecurityEventDataHeader2 dsedHeader2 = null; + + /** + * DeviceSecurityEventData2 Constructor. + * + * @param dSEDbytes byte array holding the DeviceSecurityEventData2. + */ + public DeviceSecurityEventData2(final byte[] dSEDbytes) { + + dsedHeader2 = new DeviceSecurityEventDataHeader2(dSEDbytes); + // get subheader + parseDeviceContext(dSEDbytes, dsedHeader2.getDSEDheaderByteSize(), dsedHeader2.getDeviceType()); + } + + /** + * Returns a human readable description of the data within this structure. + * + * @return a description of this structure. + */ + public String toString() { + String dsedInfo = ""; + return dsedInfo; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataDeviceContext.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataDeviceContext.java new file mode 100644 index 00000000..a9863eb7 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataDeviceContext.java @@ -0,0 +1,62 @@ +package hirs.utils.tpm.eventlog.events; + +import hirs.utils.HexUtils; +import lombok.Getter; + +/** + * Class to process the DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT event per PFP. + * DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT is a common SPDM structure which includes the + * identification of the device, device vendor, subsystem, etc. Device can be either a PCI + * or USB connection. + *

+ * typedef union tdDEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT { + * DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT PciContext; + * DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT UsbContext; + * } DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT; + *

+ */ +public abstract class DeviceSecurityEventDataDeviceContext { + + /** + * PCI Version. + */ + @Getter + private int version = 0; + /** + * PCI Length. + */ + @Getter + private int length = 0; + + /** + * DeviceSecurityEventDataDeviceContext Constructor. + * + * @param dSEDdeviceContextBytes byte array holding the DeviceSecurityEventData. + */ + public DeviceSecurityEventDataDeviceContext(final byte[] dSEDdeviceContextBytes) { + + byte[] pciVersionBytes = new byte[2]; + System.arraycopy(dSEDdeviceContextBytes, 0, pciVersionBytes, 0, 2); + version = HexUtils.leReverseInt(pciVersionBytes); + + byte[] pciLengthBytes = new byte[2]; + System.arraycopy(dSEDdeviceContextBytes, 2, pciLengthBytes, 0, 2); + length = HexUtils.leReverseInt(pciLengthBytes); + } + + /** + * Returns a human readable description of the data common to device context structures. + * + * @return a description of this structure.. + */ + public String toString() { + String dSEDdeviceContextCommonInfo = ""; + + dSEDdeviceContextCommonInfo += "\n DeviceSecurityEventData Device Info:"; + dSEDdeviceContextCommonInfo += "\n Device Structure Version = " + version; + + return dSEDdeviceContextCommonInfo; + } + +} + diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataHeader.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataHeader.java new file mode 100644 index 00000000..3c9ac444 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataHeader.java @@ -0,0 +1,103 @@ +package hirs.utils.tpm.eventlog.events; + +import hirs.utils.HexUtils; +import hirs.utils.tpm.eventlog.spdm.SpdmHa; +import hirs.utils.tpm.eventlog.spdm.SpdmMeasurementBlock; +import hirs.utils.tpm.eventlog.uefi.UefiConstants; +import lombok.Getter; + +import java.io.UnsupportedEncodingException; + +/** + * Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER. + * DEVICE_SECURITY_EVENT_DATA_HEADER contains the measurement(s) and hash algorithm identifier + * returned by the SPDM "GET_MEASUREMENTS" function. + * + * HEADERS defined by PFP v1.06 Rev 52: + *

+ * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER { + * UINT8 Signature[16]; + * UINT16 Version; + * UINT16 Length; + * UINT32 SpdmHashAlg; + * UINT32 DeviceType; + * SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock; + * UINT64 DevicePathLength; + * UNIT8 DevicePath[DevicePathLength] + * } DEVICE_SECURITY_EVENT_DATA_HEADER; + *

+ * Assumption: there is only 1 SpdmMeasurementBlock per event. Need more test patterns to verify. + */ +public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader { + + /** + * Event data length. + */ + @Getter + private int length = 0; + /** + * SPDM hash algorithm. + */ + @Getter + private int spdmHashAlgo = -1; + + /** + * SPDM Measurement Block. + */ + private SpdmMeasurementBlock spdmMeasurementBlock = null; + + /** + * DeviceSecurityEventDataHeader Constructor. + * + * @param dSEDbytes byte array holding the DeviceSecurityEventData. + */ + public DeviceSecurityEventDataHeader(final byte[] dSEDbytes) throws UnsupportedEncodingException { + + super(dSEDbytes); + + byte[] lengthBytes = new byte[UefiConstants.SIZE_2]; + System.arraycopy(dSEDbytes, 18, lengthBytes, 0, + UefiConstants.SIZE_2); + length = HexUtils.leReverseInt(lengthBytes); + + byte[] spdmHashAlgoBytes = new byte[UefiConstants.SIZE_4]; + System.arraycopy(dSEDbytes, UefiConstants.OFFSET_20, spdmHashAlgoBytes, 0, + UefiConstants.SIZE_4); + spdmHashAlgo = HexUtils.leReverseInt(spdmHashAlgoBytes); + + extractDeviceType(dSEDbytes, 24); + + // get the size of the SPDM Measurement Block + byte[] sizeOfSpdmMeasBlockBytes = new byte[UefiConstants.SIZE_2]; + System.arraycopy(dSEDbytes, 30, sizeOfSpdmMeasBlockBytes, 0, + UefiConstants.SIZE_2); + int sizeOfSpdmMeas = HexUtils.leReverseInt(sizeOfSpdmMeasBlockBytes); + int sizeOfSpdmMeasBlock = sizeOfSpdmMeas + 4; // header is 4 bytes + + // extract the bytes from the SPDM Measurement Block + byte[] spdmMeasBlockBytes = new byte[sizeOfSpdmMeasBlock]; + System.arraycopy(dSEDbytes, 28, spdmMeasBlockBytes, 0, + sizeOfSpdmMeasBlock); + spdmMeasurementBlock = new SpdmMeasurementBlock(spdmMeasBlockBytes); + + int devPathLenStartByte = 28 + sizeOfSpdmMeasBlock; + extractDevicePathAndFinalSize(dSEDbytes, devPathLenStartByte); + } + + /** + * Returns a human readable description of the data within this structure. + * + * @return a description of this structure. + */ + public String toString() { + String dsedHeaderInfo = ""; + + dsedHeaderInfo += super.toString(); + String spdmHashAlgoStr = SpdmHa.tcgAlgIdToString(spdmHashAlgo); + dsedHeaderInfo += "\n SPDM Hash Algorithm = " + spdmHashAlgoStr; + dsedHeaderInfo += "\n SPDM Measurement Block:"; + dsedHeaderInfo += spdmMeasurementBlock.toString(); + + return dsedHeaderInfo; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataHeader2.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataHeader2.java new file mode 100644 index 00000000..8e7589a9 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataHeader2.java @@ -0,0 +1,22 @@ +package hirs.utils.tpm.eventlog.events; + +import hirs.utils.tpm.eventlog.spdm.SpdmHa; + +// Placeholder for Header2 data structure. +public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader { + + public DeviceSecurityEventDataHeader2(final byte[] dSEDbytes) { + + } + + /** + * Returns a human readable description of the data within this structure. + * + * @return a description of this structure. + */ + public String toString() { + String dsedHeader2Info = ""; + + return dsedHeader2Info; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataPciContext.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataPciContext.java new file mode 100644 index 00000000..ed8f4c89 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventDataPciContext.java @@ -0,0 +1,120 @@ +package hirs.utils.tpm.eventlog.events; + +import hirs.utils.HexUtils; +import lombok.Getter; + +/** + * Class to process the DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT event per PFP. + *

+ * typedef struct tdDEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT { + * UINT16 Version; + * UINT16 Length; + * UINT16 VendorId; + * UINT16 DeviceId; + * UINT16 RevisionId; + * UINT16 ClassCode[3]; + * UINT16 SubsystemVendorId; + * UINT16 SubsystemId; + *

+ * The following fields are defined by the PCI Express Base Specification rev4.0 v1.0. + * VendorId + * DeviceId + * RevisionId + * ClassCode + * SubsystemVendorId + * SubsystemId + * Vendor id and device id are registered to specific manufacturers. + * https://admin.pci-ids.ucw.cz/read/PC/ + * Ex. vendor id 8086 and device id 0b60: https://admin.pci-ids.ucw.cz/read/PC/8086/0b60 + * Class code can be looked up on the web. + * https://admin.pci-ids.ucw.cz/read/PD/ + * The revision ID is controlled by the vendor and cannot be looked up. + */ +public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDeviceContext { + + /** + * PCI Vendor ID. + */ + @Getter + private String vendorId = ""; + /** + * PCI Device ID. + */ + @Getter + private String deviceId = ""; + /** + * PCI Revision ID. + */ + @Getter + private String revisionId = ""; + /** + * PCI Class Code. + */ + @Getter + private String classCode = ""; + /** + * PCI Subsystem Vendor ID. + */ + @Getter + private String subsystemVendorId = ""; + /** + * PCI Subsystem ID. + */ + @Getter + private String subsystemId = ""; + + /** + * DeviceSecurityEventDataPciContext Constructor. + * + * @param dSEDpciContextBytes byte array holding the DeviceSecurityEventDataPciContext. + */ + public DeviceSecurityEventDataPciContext(final byte[] dSEDpciContextBytes) { + + super(dSEDpciContextBytes); + + byte[] pciVendorIdBytes = new byte[2]; + System.arraycopy(dSEDpciContextBytes, 4, pciVendorIdBytes, 0, 2); + vendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciVendorIdBytes)); + + byte[] pciDeviceIdBytes = new byte[2]; + System.arraycopy(dSEDpciContextBytes, 6, pciDeviceIdBytes, 0, 2); + deviceId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciDeviceIdBytes)); + + byte[] pciRevisionIdBytes = new byte[1]; + System.arraycopy(dSEDpciContextBytes, 8, pciRevisionIdBytes, 0, 1); + revisionId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciRevisionIdBytes)); + + byte[] pciClassCodeBytes = new byte[3]; + System.arraycopy(dSEDpciContextBytes, 9, pciClassCodeBytes, 0, 3); + classCode = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciClassCodeBytes)); + + byte[] pciSubsystemVendorIdBytes = new byte[2]; + System.arraycopy(dSEDpciContextBytes, 12, pciSubsystemVendorIdBytes, 0, 2); + subsystemVendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemVendorIdBytes)); + + byte[] pciSubsystemIdBytes = new byte[2]; + System.arraycopy(dSEDpciContextBytes, 14, pciSubsystemIdBytes, 0, 2); + subsystemId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemIdBytes)); + + } + + /** + * Returns a human readable description of the data within this structure. + * + * @return a description of this structure.. + */ + public String toString() { + String dSEDpciContextInfo = ""; + + dSEDpciContextInfo += super.toString(); + dSEDpciContextInfo += "\n Device Type = PCI"; + dSEDpciContextInfo += "\n VendorID = 0x" + vendorId; + dSEDpciContextInfo += "\n DeviceID = 0x" + deviceId; + dSEDpciContextInfo += "\n RevisionID = 0x" + revisionId; + dSEDpciContextInfo += "\n ClassCode = 0x" + classCode; + dSEDpciContextInfo += "\n SubsystemVendorID = 0x" + subsystemVendorId; + dSEDpciContextInfo += "\n SubsystemID = 0x" + subsystemId; + + return dSEDpciContextInfo; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventHeader.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventHeader.java new file mode 100644 index 00000000..b7192054 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/DeviceSecurityEventHeader.java @@ -0,0 +1,220 @@ +package hirs.utils.tpm.eventlog.events; + +import hirs.utils.HexUtils; +import hirs.utils.tpm.eventlog.uefi.UefiConstants; +import hirs.utils.tpm.eventlog.uefi.UefiDevicePath; +import lombok.Getter; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +/** + * Abstract class to process the DEVICE_SECURITY_EVENT_DATA_HEADER or ..HEADER2 per PFP. + * The first 16 bytes of the event data header MUST be a String based identifier (Signature), + * NUL-terminated, per PFP. The only currently defined Signature is "SPDM Device Sec", + * which implies the data is a DEVICE_SECURITY_EVENT_DATA or ..DATA2. + * + * HEADERS defined by PFP v1.06 Rev 52. + * Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures. + *

+ * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER { + * UINT8 Signature[16]; + * UINT16 Version; + * UINT16 Length; + * UINT32 SpdmHashAlg; + * UINT32 DeviceType; + * SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock; + * UINT64 DevicePathLength; + * UNIT8 DevicePath[DevicePathLength] + * } DEVICE_SECURITY_EVENT_DATA_HEADER; + *

+ * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER2 { - NOT IMPLEMENTED YET + * UINT8 Signature[16]; + * UINT16 Version; + * UINT8 AuthState; + * UINT8 Reserved; + * UINT32 Length; + * UINT32 DeviceType; + * UINT32 SubHeaderType; + * UINT32 SubHeaderLength; + * UINT32 SubHeaderUID; + * UINT64 DevicePathLength; + * UNIT8 DevicePath[DevicePathLength] + * } DEVICE_SECURITY_EVENT_DATA_HEADER2; + *

+ * Fields common to both ..HEADER and ..HEADER2: + * Signature + * Version + * DeviceType + * DevicePathLength + * DevicePath + *

+ */ +public abstract class DeviceSecurityEventHeader { + + /** + * Contains the size (in bytes) of the header. + */ + @Getter + private Integer dSEDheaderByteSize = 0; + /** + * Signature (text) data. + */ + @Getter + private String signature = ""; + /** + * Version determines data structure used (..DATA or ..DATA2), + * which determines whether ..HEADER or ..HEADER2 is used + */ + @Getter + private String version = ""; + /** + * Device type. + */ + @Getter + private int deviceType = -1; + /** + * UEFI Device Path Length. + */ + @Getter + private int devicePathLength = 0; + /** + * UEFI Device path. + */ + @Getter + private UefiDevicePath devicePath = null; + /** + * Is the Device Path Valid. + */ + private boolean devicePathValid = false; + + /** + * Device Security Event Data Device Type = no device type. + */ + public static final int DEVICE_TYPE_NONE = 0; + /** + * Device Security Event Data Device Type = DEVICE_TYPE_PCI. + */ + public static final int DEVICE_TYPE_PCI = 1; + /** + * Device Security Event Data Device Type = DEVICE_TYPE_USB. + */ + public static final int DEVICE_TYPE_USB = 2; + + + /** + * DeviceSecurityEventDataHeaderBase Default Constructor. + */ + public DeviceSecurityEventHeader() { + + } + + /** + * DeviceSecurityEventDataHeaderBase Constructor. + * + * @param dSEDbytes byte array holding the DeviceSecurityEventData. + */ + public DeviceSecurityEventHeader(final byte[] dSEDbytes) { + + byte[] signatureBytes = new byte[UefiConstants.SIZE_16]; + System.arraycopy(dSEDbytes, 0, signatureBytes, 0, UefiConstants.SIZE_16); + signature = new String(signatureBytes, StandardCharsets.UTF_8) + .substring(0, UefiConstants.SIZE_15); + + byte[] versionBytes = new byte[UefiConstants.SIZE_2]; + System.arraycopy(dSEDbytes, UefiConstants.OFFSET_16, versionBytes, 0, + UefiConstants.SIZE_2); + version = HexUtils.byteArrayToHexString(versionBytes); + + } + + /** + * Parse the device type from the Device Security Event Data Header/Header2. + * + * @param dSEDbytes byte array holding the DeviceSecurityEventData/Data2. + * @param startByte starting byte of device type (depends on header fields before it). + */ + public void extractDeviceType(final byte[] dSEDbytes, int startByte) { + + // get the device type ID + byte[] deviceTypeBytes = new byte[UefiConstants.SIZE_4]; + System.arraycopy(dSEDbytes, startByte, deviceTypeBytes, 0, + UefiConstants.SIZE_4); + deviceType = HexUtils.leReverseInt(deviceTypeBytes); + } + + /** + * Parse the device path from the Device Security Event Data Header/Header2. + * Also, determine final length of header (will be used to extract the next data structure). + * + * @param dSEDbytes byte array holding the DeviceSecurityEventData/Data2. + * @param startByte starting byte of device path (depends on header fields before it). + */ + public void extractDevicePathAndFinalSize(final byte[] dSEDbytes, int startByte) + throws UnsupportedEncodingException { + + // get the device path length + byte[] devicePathLengthBytes = new byte[UefiConstants.SIZE_8]; + System.arraycopy(dSEDbytes, startByte, devicePathLengthBytes, 0, + UefiConstants.SIZE_8); + int devicePathLength = HexUtils.leReverseInt(devicePathLengthBytes); + + // get the device path + if (devicePathLength != 0) { + startByte = startByte + UefiConstants.SIZE_8; + byte[] devPathBytes = new byte[devicePathLength]; + System.arraycopy(dSEDbytes, startByte, devPathBytes, + 0, devicePathLength); + devicePath = new UefiDevicePath(devPathBytes); + devicePathValid = true; + } + + // header total size + dSEDheaderByteSize = startByte + devicePathLength; + } + + /** + * Returns the device type via a lookup. + * Lookup based upon section 10.2.7.2, Table 19, in the PFP 1.06 v52 spec. + * + * @param deviceTypeInt int to convert to string + * @return name of the device type + */ + public String deviceTypeToString(final int deviceTypeInt) { + String deviceTypeStr; + switch (deviceTypeInt) { + case DEVICE_TYPE_NONE: + deviceTypeStr = "No device type"; + break; + case DEVICE_TYPE_PCI: + deviceTypeStr = "PCI"; + break; + case DEVICE_TYPE_USB: + deviceTypeStr = "USB"; + break; + default: + deviceTypeStr = "Unknown or invalid Device Type"; + } + return deviceTypeStr; + } + + /** + * Returns a human readable description of the data common to header structures. + * + * @return a description of this structure. + */ + public String toString() { + String dsedHeaderCommonInfo = ""; + + dsedHeaderCommonInfo += "\n SPDM Device Type = " + deviceTypeToString(deviceType); + if (devicePathValid) { + dsedHeaderCommonInfo += "\n SPDM Device Path =\n"; + dsedHeaderCommonInfo += devicePath; + } + else { + dsedHeaderCommonInfo += "\n SPDM Device Path = Unknown or invalid"; + } + + return dsedHeaderCommonInfo; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/EvConstants.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/EvConstants.java index 07d01ea2..aaf69776 100644 --- a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/EvConstants.java +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/EvConstants.java @@ -163,4 +163,8 @@ public final class EvConstants { * EFI Variable Authority Event ID. */ public static final int EV_EFI_VARIABLE_AUTHORITY = 0x800000E0; + /** + * EFI SPDM Firmware Blob Event ID. + */ + public static final int EV_EFI_SPDM_FIRMWARE_BLOB = 0x800000E1; } diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/EvEfiSpdmFirmwareBlob.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/EvEfiSpdmFirmwareBlob.java new file mode 100644 index 00000000..da83c51f --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/events/EvEfiSpdmFirmwareBlob.java @@ -0,0 +1,104 @@ +package hirs.utils.tpm.eventlog.events; + +import hirs.utils.HexUtils; +import hirs.utils.tpm.eventlog.uefi.UefiConstants; + +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +/** + * Class to process the EV_EFI_SPDM_FIRMWARE_BLOB event. The event field MUST be a + * 1) DEVICE_SECURITY_EVENT_DATA or + * 2) DEVICE_SECURITY_EVENT_DATA2 + * DEVICE_SECURITY_EVENT_DATA has 2 structures: + * 1) DEVICE_SECURITY_EVENT_DATA_HEADER + * 2) DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT, which has 2 structures + * a) DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT + * b) DEVICE_SECURITY_EVENT_DATA_USB_CONTEXT + * DEVICE_SECURITY_EVENT_DATA2 has 3 structures: + * 1) DEVICE_SECURITY_EVENT_DATA_HEADER2 + * 2) DEVICE_SECURITY_EVENT_DATA_SUB_HEADER + * 3) DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT, which has 2 structures (see above) + * The first 16 bytes of the event data header MUST be a String based identifier (Signature), + * NUL-terminated, per PFP. The only currently defined Signature is "SPDM Device Sec", + * which implies the data is a DEVICE_SECURITY_EVENT_DATA or ..DATA2. + * The EV_EFI_SPDM_FIRMWARE_BLOB event is used to record an extended digest for the firmware of + * an embedded component or an add-in device that supports SPDM “GET_MEASUREMENTS” functionality. + * This event records extended digests of SPDM GET_MEASUREMENT responses that correspond to + * firmware, such as immutable ROM, mutable firmware, firmware version, firmware secure version + * number, etc. + */ +public class EvEfiSpdmFirmwareBlob { + + /** + * Signature (text) data. + */ + private String signature = ""; + /** + * True if the event is a DEVICE_SECURITY_EVENT_DATA or ..DATA2. + */ + private boolean bSpdmDeviceSecurityEventData = false; + /** + * Human readable description of the data within this DEVICE_SECURITY_EVENT_DATA/..DATA2 event. + */ + String spdmInfo = ""; + + /** + * EvEfiSpdmFirmwareBlob constructor. + * + * @param eventData byte array holding the event to process. + * @throws java.io.UnsupportedEncodingException if input fails to parse. + */ + public EvEfiSpdmFirmwareBlob(final byte[] eventData) throws UnsupportedEncodingException { + + byte[] signatureBytes = new byte[UefiConstants.SIZE_15]; + System.arraycopy(eventData, 0, signatureBytes, 0, UefiConstants.SIZE_15); + signature = new String(signatureBytes, StandardCharsets.UTF_8); + signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters + + if (signature.contains("SPDM Device Sec")) { // implies Device Security event + bSpdmDeviceSecurityEventData = true; + + byte[] versionBytes = new byte[UefiConstants.SIZE_2]; + System.arraycopy(eventData, UefiConstants.OFFSET_16, versionBytes, 0, + UefiConstants.SIZE_2); + String version = HexUtils.byteArrayToHexString(versionBytes); + + if (version.equals("0100")) { + DeviceSecurityEventData dSED = new DeviceSecurityEventData(eventData); + spdmInfo = dSED.toString(); + } + else if (version.equals("0200")) { + DeviceSecurityEventData2 dSED2 = new DeviceSecurityEventData2(eventData); + spdmInfo = dSED2.toString(); + } + else { + spdmInfo = " Unknown version of DeviceSecurityEventData structure"; + } + } + } + + /** + * Determines if this event is a DeviceSecurityEventData. + * + * @return true of the event is a DeviceSecurityEventData. + */ + public boolean isSpdmDeviceSecurityEventData() { + return bSpdmDeviceSecurityEventData; + } + + /** + * Returns a description of this event. + * + * @return Human readable description of this event. + */ + public String toString() { + if (bSpdmDeviceSecurityEventData) { + spdmInfo = " Signature = SPDM Device Sec" + spdmInfo; + } else { + spdmInfo = "EV_EFI_SPDM_FIRMWARE_BLOB event named " + signature + + " encountered but support for processing it has not been added to this application.\n"; + } + return spdmInfo; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/spdm/SpdmHa.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/spdm/SpdmHa.java new file mode 100644 index 00000000..cf49aae4 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/spdm/SpdmHa.java @@ -0,0 +1,78 @@ +package hirs.utils.tpm.eventlog.spdm; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * Class for defining hash algorithms referenced in the DMTF SPDM specification. + * SPDM 1.3.0, Table 21, MeasurementHashAlgo. + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SpdmHa { + + /** + * Spdm Hash Alg = Raw bit stream + */ + public static final int TPM_ALG_RAW = 1; + /** + * Spdm Hash Alg = TPM_ALG_SHA_256. + */ + public static final int TPM_ALG_SHA_256 = 2; + /** + * Spdm Hash Alg = TPM_ALG_SHA_384. + */ + public static final int TPM_ALG_SHA_384 = 4; + /** + * Spdm Hash Alg = TPM_ALG_SHA_512. + */ + public static final int TPM_ALG_SHA_512 = 8; + /** + * Spdm Hash Alg = TPM_ALG_SHA3_256. + */ + public static final int TPM_ALG_SHA3_256 = 16; + /** + * Spdm Hash Alg = TPM_ALG_SHA3_384. + */ + public static final int TPM_ALG_SHA3_384 = 32; + /** + * Spdm Hash Alg = TPM_ALG_SHA3_512. + */ + public static final int TPM_ALG_SHA3_512 = 64; + + /** + * Returns the hash name via a lookup. + * Lookup based upon section 10.4 for the SPDM v1.03 document. + * + * @param algId int to convert to string + * @return name of the algorithm + */ + public static String tcgAlgIdToString(final int algId) { + String alg; + switch (algId) { + case TPM_ALG_RAW: + alg = "Raw Bit Stream"; + break; + case TPM_ALG_SHA_256: + alg = "TPM_ALG_SHA_256"; + break; + case TPM_ALG_SHA_384: + alg = "TPM_ALG_SHA_384"; + break; + case TPM_ALG_SHA_512: + alg = "TPM_ALG_SHA_512"; + break; + case TPM_ALG_SHA3_256: + alg = "TPM_ALG_SHA3_256"; + break; + case TPM_ALG_SHA3_384: + alg = "TPM_ALG_SHA3_384"; + break; + case TPM_ALG_SHA3_512: + alg = "TPM_ALG_SHA3_512"; + break; + default: + alg = "Unknown or invalid Hash"; + } + return alg; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/spdm/SpdmMeasurement.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/spdm/SpdmMeasurement.java new file mode 100644 index 00000000..0773be82 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/spdm/SpdmMeasurement.java @@ -0,0 +1,122 @@ +package hirs.utils.tpm.eventlog.spdm; + +import hirs.utils.HexUtils; +import lombok.AccessLevel; +import lombok.Getter; + +/** + * Class to process the SpdmMeasurement. + *

+ * Measurement, defined by SPDM v1.03, Sect 10.11.1, Table 54: + * DMTF measurement spec format { + * DMTFSpecMeasurementValueType 1 byte; + * DMTFSpecMeasurementValueSize 2 bytes; + * DMTFSpecMeasurementValue bytes; + * } + *

+ * DMTFSpecMeasurementValueType[7] + * Indicates how bits [0:6] are represented + * Bit = 0: Digest + * Bit = 1: Raw bit stream + * DMTFSpecMeasurementValueType[6:0] (see SPDM Spec, Table 55 "DMTFSpecMeasurementValueType[6:0]") + * Immutable ROM 0x0 + * Mutable firmware 0x1 + * Hardware configuration 0x2 + * Firmware configuration 0x3 + * etc. + *

+ */ +public class SpdmMeasurement { + + /** + * Measurement value type (such as mutable firmware, etc). + */ + @Getter + private int dmtfSpecMeasurementValueType = 0; + /** + * Measurement value (digest). + */ + private byte[] dmtfSpecMeasurementValue = null; + + /** + * SpdmMeasurement Constructor. + * + * @param spdmMeasBytes byte array holding the SPDM Measurement bytes. + */ + public SpdmMeasurement(final byte[] spdmMeasBytes) { + + byte[] dmtfSpecMeasurementValueTypeBytes = new byte[1]; + System.arraycopy(spdmMeasBytes, 0, dmtfSpecMeasurementValueTypeBytes, 0, + 1); + dmtfSpecMeasurementValueType = HexUtils.leReverseInt(dmtfSpecMeasurementValueTypeBytes); + + // in future, can crosscheck this value size + 3 with the spdm block MeasurementSize size + byte[] dmtfSpecMeasurementValueSizeBytes = new byte[2]; + System.arraycopy(spdmMeasBytes, 1, dmtfSpecMeasurementValueSizeBytes, 0, + 2); + int dmtfSpecMeasurementValueSize = HexUtils.leReverseInt(dmtfSpecMeasurementValueSizeBytes); + + dmtfSpecMeasurementValue = new byte[dmtfSpecMeasurementValueSize]; + System.arraycopy(spdmMeasBytes, 3, dmtfSpecMeasurementValue, 0, + dmtfSpecMeasurementValueSize); + } + + /** + * Returns a human readable description of the data within this structure. + * + * @return a description of this structure.. + */ + public String dmtfSpecMeasurementValueTypeToString(final int measValType) { + + String measValTypeStr; + switch (measValType) { + case 0: + measValTypeStr = "Immutable ROM"; + break; + case 1: + measValTypeStr = "Mutable firmware"; + break; + case 2: + measValTypeStr = "Hardware configuration"; + break; + case 3: + measValTypeStr = "Firmware configuration"; + break; + case 4: + measValTypeStr = "Freeform measurement manifest"; + break; + case 5: + measValTypeStr = "Structured representation of debug and device mode"; + break; + case 6: + measValTypeStr = "Mutable firmware's version number"; + break; + case 7: + measValTypeStr = "Mutable firmware's security verison number"; + break; + case 8: + measValTypeStr = "Hash-extended measurement"; + break; + case 9: + measValTypeStr = "Informational"; + break; + case 10: + measValTypeStr = "Structured measurement manifest"; + break; + default: + measValTypeStr = "Unknown or invalid DMTF Spec Measurement Value Type"; + } + return measValTypeStr; + } + + public String toString() { + String spdmMeasInfo = ""; + + spdmMeasInfo += "\n SPDM Measurement Value Type = " + + dmtfSpecMeasurementValueTypeToString(dmtfSpecMeasurementValueType); + spdmMeasInfo += "\n SPDM Measurement Value = " + + HexUtils.byteArrayToHexString(dmtfSpecMeasurementValue); + + return spdmMeasInfo; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/spdm/SpdmMeasurementBlock.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/spdm/SpdmMeasurementBlock.java new file mode 100644 index 00000000..4b1345eb --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/spdm/SpdmMeasurementBlock.java @@ -0,0 +1,86 @@ +package hirs.utils.tpm.eventlog.spdm; + +import hirs.utils.HexUtils; +import hirs.utils.tpm.eventlog.uefi.UefiConstants; +import lombok.Getter; + +/** + * Class to process the SpdmMeasurementBlock. + *

+ * Measurement block format, defined by SPDM v1.03, Sect 10.11.1, Table 53: + * Measurement block format { + * Index 1 byte; + * MeasurementSpec 1 byte; + * MeasurementSize 2 bytes; + * Measurement bytes; + * } + *

+ * Index: index of the measurement block, as there can be more than one + * MeasurementSpec: bit mask; the measurement specification that the requested Measurement follows + * See "MeasurementSpecificationSel" in Table 21. See Tables 29, 53, 54 + * Bit 0: DMTFmeasSpec, per Table 54 + * Bit 1-7: Reserved + * Measurement: the digest + */ +public class SpdmMeasurementBlock { + + /** + * Measurement block index, as an SPDM measurement exchange can contain several measurements. + */ + @Getter + private int index = 0; + /** + * Measurement Spec. + */ + @Getter + private int measurementSpec = 0; + /** + * SPDM Measurement. + */ + private SpdmMeasurement spdmMeasurement; + + /** + * SpdmMeasurementBlock Constructor. + * + * @param spdmMeasBlockBytes byte array holding the SPDM Measurement Block bytes. + */ + public SpdmMeasurementBlock(final byte[] spdmMeasBlockBytes) { + + byte[] indexBytes = new byte[1]; + System.arraycopy(spdmMeasBlockBytes, 0, indexBytes, 0, + 1); + index = HexUtils.leReverseInt(indexBytes); + + byte[] measurementSpecBytes = new byte[1]; + System.arraycopy(spdmMeasBlockBytes, 1, measurementSpecBytes, 0, + 1); + measurementSpec = HexUtils.leReverseInt(measurementSpecBytes); + + // in future, can crosscheck this measurement size with the MeasurementSpec hash alg size + byte[] measurementSizeBytes = new byte[2]; + System.arraycopy(spdmMeasBlockBytes, 2, measurementSizeBytes, 0, + 2); + int measurementSize = HexUtils.leReverseInt(measurementSizeBytes); + + byte[] measurementBytes = new byte[measurementSize]; + System.arraycopy(spdmMeasBlockBytes, 4, measurementBytes, 0, + measurementSize); + spdmMeasurement = new SpdmMeasurement(measurementBytes); + } + + /** + * Returns a human readable description of the data within this structure. + * + * @return a description of this structure.. + */ + public String toString() { + String spdmMeasBlockInfo = ""; + + spdmMeasBlockInfo += "\n Index = " + index; + spdmMeasBlockInfo += "\n MeasurementSpec = " + measurementSpec; + spdmMeasBlockInfo += spdmMeasurement.toString(); + + return spdmMeasBlockInfo; + } + +}