mirror of
https://github.com/nsacyber/HIRS.git
synced 2025-04-07 19:34:27 +00:00
Merge pull request #762 from nsacyber/v3_issue_747-spdm
Process SPDM Event EV_EFI_SPDM_FIRMWARE_BLOB
This commit is contained in:
commit
a418d11293
@ -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";
|
||||
}
|
||||
|
@ -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:
|
||||
* <p>
|
||||
* typedef struct tdDEVICE_SECURITY_EVENT_DATA {
|
||||
* DEVICE_SECURITY_EVENT_DATA_HEADER EventDataHeader;
|
||||
* DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT DeviceContext;
|
||||
* } DEVICE_SECURITY_EVENT_DATA;
|
||||
* <p>
|
||||
* 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;
|
||||
* <p>
|
||||
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER or HEADER2 {
|
||||
* UINT8 Signature[16];
|
||||
* UINT16 Version;
|
||||
* ... ...
|
||||
* }
|
||||
* <p>
|
||||
* 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"
|
||||
* <p>
|
||||
* 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";
|
||||
}
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* typedef struct tdDEVICE_SECURITY_EVENT_DATA {
|
||||
* DEVICE_SECURITY_EVENT_DATA_HEADER EventDataHeader;
|
||||
* DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT DeviceContext;
|
||||
* } DEVICE_SECURITY_EVENT_DATA;
|
||||
* <p>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* 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;
|
||||
* <p>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* 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;
|
||||
* <p>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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:
|
||||
* <p>
|
||||
* 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;
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* 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;
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* 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;
|
||||
* <p>
|
||||
* 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;
|
||||
* <p>
|
||||
* Fields common to both ..HEADER and ..HEADER2:
|
||||
* Signature
|
||||
* Version
|
||||
* DeviceType
|
||||
* DevicePathLength
|
||||
* DevicePath
|
||||
* <p>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* Measurement, defined by SPDM v1.03, Sect 10.11.1, Table 54:
|
||||
* DMTF measurement spec format {
|
||||
* DMTFSpecMeasurementValueType 1 byte;
|
||||
* DMTFSpecMeasurementValueSize 2 bytes;
|
||||
* DMTFSpecMeasurementValue <DMTFSpecMeasurementValueSize> bytes;
|
||||
* }
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -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.
|
||||
* <p>
|
||||
* 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 <MeasurementSize> bytes;
|
||||
* }
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user