Merge pull request #819 from nsacyber/v3_issue_804-spdm

Add processing for EV_EFI_NOACTION_NvIndexInstance and SPDM Cert Chain data structure
This commit is contained in:
iadgovuser26 2024-08-20 11:58:12 -04:00 committed by GitHub
commit fcd0c6f50e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 1130 additions and 561 deletions

View File

@ -43,17 +43,16 @@ dependencies {
implementation 'org.apache.logging.log4j:log4j-core:2.19.0'
implementation 'org.apache.logging.log4j:log4j-api:2.19.0'
implementation 'org.glassfish.jaxb:jaxb-runtime:4.0.1'
implementation 'org.slf4j:slf4j-simple:1.7.30'
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
testImplementation 'org.junit.platform:junit-platform-launcher:1.9.3'
testImplementation 'org.hamcrest:hamcrest:2.2'
testImplementation project(path: ':HIRS_AttestationCA')
testImplementation 'org.mockito:mockito-core:4.2.0'
testImplementation project(path: ':HIRS_AttestationCA')
compileOnly libs.lombok
annotationProcessor libs.lombok
}
checkstyle {

View File

@ -179,9 +179,9 @@ public final class PciIds {
String classCode = refClassCode;
if (classCode != null && classCode.trim().matches("^[0-9A-Fa-f]{6}$")) {
String deviceClass = classCode.substring(0,2).toLowerCase();
String deviceSubclass = classCode.substring(2,4).toLowerCase();
String programInterface = classCode.substring(4,6).toLowerCase();
String deviceClass = classCode.substring(0, 2).toLowerCase();
String deviceSubclass = classCode.substring(2, 4).toLowerCase();
String programInterface = classCode.substring(4, 6).toLowerCase();
translatedClassCode.add(deviceClass);
translatedClassCode.add(deviceSubclass);
translatedClassCode.add(programInterface);

View File

@ -169,9 +169,10 @@ public final class TCGEventLog {
// the if statement is executed
// [new event file status = eventList.get(eventNumber-1).getVendorTableFileStatus()]
// (ie. if the new file status is not-accessible or from-code, then want to update)
if((vendorTableFileStatus != FILESTATUS_NOT_ACCESSIBLE) &&
(eventList.get(eventNumber-1).getVendorTableFileStatus() != FILESTATUS_FROM_FILESYSTEM)) {
vendorTableFileStatus = eventList.get(eventNumber-1).getVendorTableFileStatus();
if ((vendorTableFileStatus != FILESTATUS_NOT_ACCESSIBLE)
&& (eventList.get(eventNumber - 1).getVendorTableFileStatus()
!= FILESTATUS_FROM_FILESYSTEM)) {
vendorTableFileStatus = eventList.get(eventNumber - 1).getVendorTableFileStatus();
}
}
calculatePcrValues();

View File

@ -6,7 +6,6 @@ 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.EvEfiSpdmDeviceSecurityEvent;
import hirs.utils.tpm.eventlog.events.EvEfiSpecIdEvent;
import hirs.utils.tpm.eventlog.events.EvEventTag;
import hirs.utils.tpm.eventlog.events.EvIPL;
import hirs.utils.tpm.eventlog.events.EvNoAction;
@ -113,7 +112,6 @@ public class TpmPcrEvent {
* Event hash for Crypto Agile events.
*/
private byte[] eventDataSha256hash;
private EvPostCode evPostCode;
@Setter @Getter
private int eventNumber;
@Setter @Getter
@ -232,7 +230,7 @@ public class TpmPcrEvent {
*/
protected void setEventContent(final byte[] eventData) {
eventContent = new byte[eventData.length];
evPostCode = new EvPostCode(eventContent);
//EvPostCode evPostCode = new EvPostCode(eventContent);
System.arraycopy(eventData, 0, eventContent, 0, eventData.length);
}
@ -268,12 +266,8 @@ public class TpmPcrEvent {
noAction = new EvNoAction(eventContent);
sb.append(noAction.toString());
if (noAction.isSpecIDEvent()) {
// this should be in the constructor
EvEfiSpecIdEvent specID = noAction.getSpecIDEvent();
specVersion = String.format("%s.%s",
specID.getVersionMajor(),
specID.getVersionMinor());
specErrataVersion = specID.getErrata();
specVersion = noAction.getSpecVersion();
specErrataVersion = noAction.getSpecErrataVersion();
}
} catch (UnsupportedEncodingException ueEx) {
log.error(ueEx);
@ -324,23 +318,6 @@ public class TpmPcrEvent {
case EvConstants.EV_EFI_EVENT_BASE:
break;
case EvConstants.EV_EFI_VARIABLE_DRIVER_CONFIG:
UefiVariable efiVar = null;
try {
efiVar = new UefiVariable(eventContent);
String efiVarDescription = efiVar.toString().replace("\n", "\n ");
sb.append(efiVarDescription.substring(0,
efiVarDescription.length() - INDENT_3));
} catch (CertificateException cEx) {
log.error(cEx);
sb.append(cEx.toString());
} catch (NoSuchAlgorithmException noSaEx) {
log.error(noSaEx);
sb.append(noSaEx.toString());
} catch (IOException ioEx) {
log.error(ioEx);
sb.append(ioEx.toString());
}
break;
case EvConstants.EV_EFI_VARIABLE_BOOT:
case EvConstants.EV_EFI_VARIABLE_AUTHORITY:
case EvConstants.EV_EFI_SPDM_DEVICE_POLICY:
@ -458,9 +435,8 @@ public class TpmPcrEvent {
EvNoAction noAction = new EvNoAction(content);
description += "Event Content:\n" + noAction.toString();
if (noAction.isSpecIDEvent()) {
EvEfiSpecIdEvent specID = noAction.getSpecIDEvent();
specVersion = specID.getVersionMajor() + "." + specID.getVersionMinor();
specErrataVersion = specID.getErrata();
specVersion = noAction.getSpecVersion();
specErrataVersion = noAction.getSpecErrataVersion();
}
break;
case EvConstants.EV_SEPARATOR:
@ -514,28 +490,19 @@ public class TpmPcrEvent {
case EvConstants.EV_EFI_EVENT_BASE:
break;
case EvConstants.EV_EFI_VARIABLE_DRIVER_CONFIG:
UefiVariable efiVar = new UefiVariable(content);
String efiVarDescription = efiVar.toString().replace("\n", "\n ");
description += "Event Content:\n " + efiVarDescription.substring(0,
efiVarDescription.length() - INDENT_3);
vendorTableFileStatus = efiVar.getVendorTableFileStatus();
break;
case EvConstants.EV_EFI_VARIABLE_BOOT:
case EvConstants.EV_EFI_VARIABLE_AUTHORITY:
case EvConstants.EV_EFI_SPDM_DEVICE_POLICY:
case EvConstants.EV_EFI_SPDM_DEVICE_AUTHORITY:
UefiVariable efiVar2 = new UefiVariable(content);
description += "Event Content:\n" + efiVar2.toString();
vendorTableFileStatus = efiVar2.getVendorTableFileStatus();
UefiVariable efiVar = new UefiVariable(content);
description += "Event Content:\n" + efiVar.toString();
vendorTableFileStatus = efiVar.getVendorTableFileStatus();
break;
case EvConstants.EV_EFI_BOOT_SERVICES_APPLICATION:
case EvConstants.EV_EFI_BOOT_SERVICES_DRIVER:
EvEfiBootServicesApp bootServices = new EvEfiBootServicesApp(content);
description += "Event Content:\n" + bootServices.toString();
break;
case EvConstants.EV_EFI_BOOT_SERVICES_DRIVER: // same as EV_EFI_BOOT_SERVICES_APP
EvEfiBootServicesApp bootDriver = new EvEfiBootServicesApp(content);
description += "Event Content:\n" + bootDriver.toString();
break;
case EvConstants.EV_EFI_RUNTIME_SERVICES_DRIVER:
break;
case EvConstants.EV_EFI_GPT_EVENT:
@ -555,10 +522,6 @@ public class TpmPcrEvent {
case EvConstants.EV_EFI_HCRTM_EVENT:
break;
case EvConstants.EV_EFI_SPDM_FIRMWARE_BLOB:
EvEfiSpdmDeviceSecurityEvent tempp = new EvEfiSpdmDeviceSecurityEvent(content);
description += "Event Content:\n" + tempp.toString();
// description += "Event Content:\n" + new EvEfiSpdmDeviceSecurityEvent(content).toString();
break;
case EvConstants.EV_EFI_SPDM_FIRMWARE_CONFIG:
description += "Event Content:\n" + new EvEfiSpdmDeviceSecurityEvent(content).toString();
break;

View File

@ -3,11 +3,6 @@ package hirs.utils.tpm.eventlog.events;
import lombok.Getter;
import lombok.Setter;
import static hirs.utils.tpm.eventlog.events.DeviceSecurityEventHeader.DEVICE_TYPE_NONE;
import static hirs.utils.tpm.eventlog.events.DeviceSecurityEventHeader.DEVICE_TYPE_PCI;
import static hirs.utils.tpm.eventlog.events.DeviceSecurityEventHeader.DEVICE_TYPE_USB;
/**
* 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.
@ -17,10 +12,10 @@ import static hirs.utils.tpm.eventlog.events.DeviceSecurityEventHeader.DEVICE_TY
* 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.
* per PFP. The only currently defined Signatures are "SPDM Device Sec" and "SPDM Device Sec2",
* which implies the data is a DEVICE_SECURITY_EVENT_DATA or ..DATA2, respectively.
* Field 2:
* The Version field indicates whether the Device Security Event is ..DATA or ..DATA2.
* The Version field also indicates whether the Device Security Event is ..DATA or ..DATA2.
*
* DEVICE SECURITY EVENT structures defined by PFP v1.06 Rev 52:
* <p>
@ -39,19 +34,9 @@ import static hirs.utils.tpm.eventlog.events.DeviceSecurityEventHeader.DEVICE_TY
* UINT8 Signature[16];
* UINT16 Version;
* ... ...
* (The rest of the components are different for HEADER vs HEADER2)
* }
* <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 {
@ -73,7 +58,7 @@ public abstract class DeviceSecurityEvent {
* DEVICE_SECURITY_EVENT_DATA_DEVICE_CONTEXT. DEVICE can be either PCI or USB.
*/
@Getter
String deviceContextInfo = "";
private String deviceContextInfo = "";
/**
* DeviceSecurityEventData Default Constructor.
@ -91,22 +76,19 @@ public abstract class DeviceSecurityEvent {
*/
public void instantiateDeviceContext(final byte[] dsedDeviceContextBytes) {
if (deviceType == DEVICE_TYPE_NONE) {
deviceContextInfo = "\n No Device Context (indicated by device type value of 0";
}
else if (deviceType == DEVICE_TYPE_PCI) {
dsedDevContext
= new DeviceSecurityEventDataPciContext(dsedDeviceContextBytes);
deviceContextInfo = dsedDevContext.toString();
}
else if (deviceType == DEVICE_TYPE_USB) {
// dsedDevContext
// = new DeviceSecurityEventDataUsbContext(dsedDeviceContextBytes);
// deviceContextInfo = dsedDevContext.toString();
deviceContextInfo = " Device Type: USB - To be implemented";
}
else {
deviceContextInfo = " Unknown device type; cannot process device context";
if (dsedDeviceContextBytes.length == 0) {
deviceContextInfo = "\n DeviceSecurityEventDataDeviceContext object is empty";
} else {
if (deviceType == DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE) {
deviceContextInfo = "\n No Device Context (indicated by device type value of 0)";
} else if (deviceType == DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI) {
dsedDevContext = new DeviceSecurityEventDataPciContext(dsedDeviceContextBytes);
deviceContextInfo = dsedDevContext.toString();
} else if (deviceType == DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB) {
deviceContextInfo = " Device Type: USB - To be implemented";
} else {
deviceContextInfo = " Unknown device type; cannot process device context";
}
}
}
}

View File

@ -2,9 +2,6 @@ package hirs.utils.tpm.eventlog.events;
import lombok.Getter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* Class to process DEVICE_SECURITY_EVENT_DATA.
* Parses event data per PFP v1.06 Rev52 Table 20.
@ -23,22 +20,36 @@ public class DeviceSecurityEventData extends DeviceSecurityEvent {
@Getter
private DeviceSecurityEventDataHeader dsedHeader = null;
/**
* Human-readable description of the data within the
* DEVICE_SECURITY_EVENT_DATA_HEADER.
*/
@Getter
private String headerInfo = "";
/**
* DeviceSecurityEventData Constructor.
*
* @param dsedBytes byte array holding the DeviceSecurityEventData.
*/
public DeviceSecurityEventData(final byte[] dsedBytes) {
dsedHeader = new DeviceSecurityEventDataHeader(dsedBytes);
setDeviceType(dsedHeader.getDeviceType());
int dsedHeaderLength = dsedHeader.getDsedHeaderLength();
int dsedDevContextLength = dsedBytes.length - dsedHeaderLength;
byte[] dsedDevContextBytes = new byte[dsedDevContextLength];
System.arraycopy(dsedBytes, dsedHeaderLength, dsedDevContextBytes, 0,
dsedDevContextLength);
if (dsedBytes.length == 0) {
headerInfo = " DeviceSecurityEventData object is empty";
} else {
dsedHeader = new DeviceSecurityEventDataHeader(dsedBytes);
headerInfo = dsedHeader.toString();
instantiateDeviceContext(dsedDevContextBytes);
setDeviceType(dsedHeader.getDeviceType());
int dsedHeaderLength = dsedHeader.getDsedHeaderLength();
int dsedDevContextLength = dsedBytes.length - dsedHeaderLength;
byte[] dsedDevContextBytes = new byte[dsedDevContextLength];
System.arraycopy(dsedBytes, dsedHeaderLength, dsedDevContextBytes, 0,
dsedDevContextLength);
instantiateDeviceContext(dsedDevContextBytes);
}
}
/**
@ -47,8 +58,7 @@ public class DeviceSecurityEventData extends DeviceSecurityEvent {
* @return a description of this structure.
*/
public String toString() {
String dsedInfo = "";
dsedInfo += dsedHeader.toString();
String dsedInfo = headerInfo;
dsedInfo += getDeviceContextInfo();
return dsedInfo;
}

View File

@ -2,12 +2,6 @@ package hirs.utils.tpm.eventlog.events;
import lombok.Getter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import static hirs.utils.tpm.eventlog.events.DeviceSecurityEventDataHeader2.SUBHEADERTYPE_CERT_CHAIN;
import static hirs.utils.tpm.eventlog.events.DeviceSecurityEventDataHeader2.SUBHEADERTYPE_MEAS_BLOCK;
/**
* Class to process DEVICE_SECURITY_EVENT_DATA2.
* Parses event data per PFP v1.06 Rev52 Table 26.
@ -34,13 +28,20 @@ public class DeviceSecurityEventData2 extends DeviceSecurityEvent {
private DeviceSecurityEventDataSubHeader dsedSubHeader = null;
/**
* Human readable description of the data within the
* Human-readable description of the data within the
* DEVICE_SECURITY_EVENT_DATA_HEADER2.
*/
@Getter
private String headerInfo = "";
/**
* Human-readable description of the data within the
* DEVICE_SECURITY_EVENT_DATA_SUB_HEADER. SUB_HEADER can be either
* DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK or
* DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN
*/
@Getter
String subHeaderInfo = "";
private String subHeaderInfo = "";
/**
* DeviceSecurityEventData2 Constructor.
@ -49,36 +50,41 @@ public class DeviceSecurityEventData2 extends DeviceSecurityEvent {
*/
public DeviceSecurityEventData2(final byte[] dsedBytes) {
dsedHeader2 = new DeviceSecurityEventDataHeader2(dsedBytes);
setDeviceType(dsedHeader2.getDeviceType());
int dsedHeaderLength = dsedHeader2.getDsedHeaderLength();
int subHeaderType = dsedHeader2.getSubHeaderType();
int subHeaderLength = dsedHeader2.getSubHeaderLength();
if (dsedBytes.length == 0) {
headerInfo = " DeviceSecurityEventData2 object is empty";
} else {
dsedHeader2 = new DeviceSecurityEventDataHeader2(dsedBytes);
headerInfo = dsedHeader2.toString();
subHeaderInfo = "\nSub header type: " + subHeaderType;
setDeviceType(dsedHeader2.getDeviceType());
int dsedHeaderLength = dsedHeader2.getDsedHeaderLength();
int subHeaderType = dsedHeader2.getSubHeaderType();
int subHeaderLength = dsedHeader2.getSubHeaderLength();
byte[] dsedSubHeaderBytes = new byte[subHeaderLength];
System.arraycopy(dsedBytes, dsedHeaderLength, dsedSubHeaderBytes, 0, subHeaderLength);
subHeaderInfo = " Sub header type: "
+ DeviceSecurityEventDataSubHeader.subheaderTypeToString(subHeaderType) + "\n";
if (subHeaderType == SUBHEADERTYPE_MEAS_BLOCK) {
dsedSubHeader = new DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock(dsedSubHeaderBytes);
subHeaderInfo += dsedSubHeader.toString();
byte[] dsedSubHeaderBytes = new byte[subHeaderLength];
System.arraycopy(dsedBytes, dsedHeaderLength, dsedSubHeaderBytes, 0, subHeaderLength);
if (subHeaderType == DeviceSecurityEventDataSubHeader.SUBHEADERTYPE_MEAS_BLOCK) {
dsedSubHeader = new DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock(dsedSubHeaderBytes);
subHeaderInfo += dsedSubHeader.toString();
} else if (subHeaderType == DeviceSecurityEventDataSubHeader.SUBHEADERTYPE_CERT_CHAIN) {
dsedSubHeader = new DeviceSecurityEventDataSubHeaderCertChain(dsedSubHeaderBytes);
subHeaderInfo += dsedSubHeader.toString();
} else {
subHeaderInfo += " Sub header type unknown\n";
}
int dsedDevContextStartByte = dsedHeaderLength + subHeaderLength;
int dsedDevContextLength = dsedBytes.length - dsedDevContextStartByte;
byte[] dsedDevContextBytes = new byte[dsedDevContextLength];
System.arraycopy(dsedBytes, dsedDevContextStartByte, dsedDevContextBytes, 0,
dsedDevContextLength);
instantiateDeviceContext(dsedDevContextBytes);
}
else if (subHeaderType == SUBHEADERTYPE_CERT_CHAIN) {
// dsedSubHeader = new DeviceSecurityEventDataSubHeaderCertChain();
subHeaderInfo += " Cert chain to be implemented ";
}
else {
subHeaderInfo += "Sub header type unknown";
}
int dsedDevContextStartByte = dsedHeaderLength + subHeaderLength;
int dsedDevContextLength = dsedBytes.length - dsedDevContextStartByte;
byte[] dsedDevContextBytes = new byte[dsedDevContextLength];
System.arraycopy(dsedBytes, dsedDevContextStartByte, dsedDevContextBytes, 0,
dsedDevContextLength);
instantiateDeviceContext(dsedDevContextBytes);
}
/**
@ -87,9 +93,8 @@ public class DeviceSecurityEventData2 extends DeviceSecurityEvent {
* @return a description of this structure.
*/
public String toString() {
String dsedInfo = "";
dsedInfo += dsedHeader2.toString();
dsedInfo += dsedSubHeader.toString();
String dsedInfo = headerInfo;
dsedInfo += subHeaderInfo;
dsedInfo += getDeviceContextInfo();
return dsedInfo;
}

View File

@ -28,6 +28,19 @@ public abstract class DeviceSecurityEventDataDeviceContext {
@Getter
private int length = 0;
/**
* 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;
/**
* DeviceSecurityEventDataDeviceContext Constructor.
*
@ -45,17 +58,16 @@ public abstract class DeviceSecurityEventDataDeviceContext {
}
/**
* Returns a human readable description of the data common to device context structures.
* Returns a human-readable description of the data common to device context structures.
*
* @return a description of this structure..
* @return a description of this structure.
*/
public String toString() {
String dSEDdeviceContextCommonInfo = "";
dSEDdeviceContextCommonInfo += "\n DeviceSecurityEventData Device Context:";
dSEDdeviceContextCommonInfo += " DeviceSecurityEventData Device Context:\n";
return dSEDdeviceContextCommonInfo;
}
}

View File

@ -8,7 +8,6 @@ import lombok.Getter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER.
@ -48,6 +47,12 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
*/
private SpdmMeasurementBlock spdmMeasurementBlock = null;
/**
* Human-readable description of the data within the
* SpdmMeasurementBlock.
*/
private String spdmMeasurementBlockInfo = "";
/**
* DeviceSecurityEventDataHeader Constructor.
*
@ -83,7 +88,13 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
ByteArrayInputStream spdmMeasurementBlockData =
new ByteArrayInputStream(spdmMeasBlockBytes);
spdmMeasurementBlock = new SpdmMeasurementBlock(spdmMeasurementBlockData);
try {
spdmMeasurementBlock = new SpdmMeasurementBlock(spdmMeasurementBlockData);
spdmMeasurementBlockInfo = spdmMeasurementBlock.toString();
} catch (IOException e) {
spdmMeasurementBlockInfo = " Error reading SPDM Measurement Block";
}
int devPathLenStartByte = 28 + sizeOfSpdmMeasBlock;
extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte);
@ -95,13 +106,11 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
* @return a description of this structure.
*/
public String toString() {
String dsedHeaderInfo = "";
dsedHeaderInfo += super.toString();
String dsedHeaderInfo = super.toString();
String spdmHashAlgoStr = SpdmHa.tcgAlgIdToString(spdmHashAlgo);
dsedHeaderInfo += "\n SPDM Hash Algorithm = " + spdmHashAlgoStr;
dsedHeaderInfo += "\n SPDM Measurement Block:";
dsedHeaderInfo += spdmMeasurementBlock.toString();
dsedHeaderInfo += " SPDM Hash Algorithm = " + spdmHashAlgoStr + "\n";
dsedHeaderInfo += " SPDM Measurement Block:\n";
dsedHeaderInfo += spdmMeasurementBlockInfo;
return dsedHeaderInfo;
}

View File

@ -3,8 +3,6 @@ package hirs.utils.tpm.eventlog.events;
import hirs.utils.HexUtils;
import lombok.Getter;
import java.io.UnsupportedEncodingException;
/**
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER2.
* DEVICE_SECURITY_EVENT_DATA_HEADER2 contains the measurement(s) and hash algorithm identifier
@ -30,7 +28,7 @@ import java.io.UnsupportedEncodingException;
public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
/**
* Event auth state
* Event auth state.
*/
@Getter
private int authState = 0;
@ -40,10 +38,12 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
@Getter
private int length = 0;
/**
* Event sub headerType
* Event sub headerType.
* SUBHEADERTYPE_MEAS_BLOCK = 0
* SUBHEADERTYPE_CERT_CHAIN = 1
*/
@Getter
private int subHeaderType = 0;
private int subHeaderType = -1;
/**
* Event sub header length.
*/
@ -56,12 +56,12 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
private String subHeaderUid = "";
/**
* Auth state - success
* Auth state - success.
*/
public static final int AUTH_SUCCESS = 0;
/**
* Auth state - digital signature of the data is valid, but the public key certificate chain is not
* validated with the entry in in the UEFI device signature variable
* validated with the entry in the UEFI device signature variable.
*/
public static final int AUTH_NO_AUTHORITY = 1;
/**
@ -70,27 +70,23 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
*/
public static final int AUTH_NO_BINDING = 2;
/**
* Auth state - data has no digital signature
* Auth state - data has no digital signature.
*/
public static final int AUTH_FAIL_NO_SIG = 3;
/**
* Auth state - data is invalid
* Auth state - data is invalid.
*/
public static final int AUTH_FAIL_INVALID = 4;
/**
* Auth state - device is not an SPDM-capable device
* Auth state - device is not an SPDM-capable device.
*/
public static final int AUTH_NO_SPDM = 0xFF;
/**
* Sub header type - SPDM measurement block
*/
public static final int SUBHEADERTYPE_MEAS_BLOCK = 0;
/**
* Sub header type - SPDM cert chain
*/
public static final int SUBHEADERTYPE_CERT_CHAIN = 1;
/**
* DeviceSecurityEventDataHeader2 Constructor.
*
* @param dsedBytes byte array holding the DeviceSecurityEventData2.
*/
public DeviceSecurityEventDataHeader2(final byte[] dsedBytes) {
super(dsedBytes);
@ -130,15 +126,18 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
* @return a description of this structure.
*/
public String toString() {
String dsedHeader2Info = "";
dsedHeader2Info += super.toString();
dsedHeader2Info += "\n AuthState: " + getAuthStateString();
dsedHeader2Info += "\n Sub header UID: " + subHeaderUid;
String dsedHeader2Info = super.toString();
dsedHeader2Info += " AuthState: " + getAuthStateString() + "\n";
dsedHeader2Info += " Sub header UID: " + subHeaderUid + "\n";
return dsedHeader2Info;
}
/**
* Returns a human-readable description of auth state based on numeric representation lookup.
*
* @return a description of the auth state.
*/
public String getAuthStateString() {
switch (authState) {

View File

@ -3,7 +3,6 @@ package hirs.utils.tpm.eventlog.events;
import hirs.utils.HexUtils;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
import static hirs.utils.PciIds.translateDevice;
@ -102,7 +101,6 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
byte[] pciSubsystemIdBytes = new byte[2];
System.arraycopy(dSEDpciContextBytes, 14, pciSubsystemIdBytes, 0, 2);
subsystemId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemIdBytes));
}
/**
@ -114,22 +112,22 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
String dSEDpciContextInfo = "";
dSEDpciContextInfo += super.toString();
dSEDpciContextInfo += "\n Device Type = PCI";
dSEDpciContextInfo += "\n Vendor = " + translateVendor(vendorId);
dSEDpciContextInfo += "\n Device = " + translateDevice(vendorId, deviceId);
dSEDpciContextInfo += "\n RevisionID = " + revisionId;
dSEDpciContextInfo += " Device Type = PCI\n";
dSEDpciContextInfo += " Vendor = " + translateVendor(vendorId) + "\n";
dSEDpciContextInfo += " Device = " + translateDevice(vendorId, deviceId) + "\n";
dSEDpciContextInfo += " RevisionID = " + revisionId + "\n";
List<String> classCodeList = translateDeviceClass(classCode);
dSEDpciContextInfo += "\n Device Class: ";
if(classCodeList.size() == 3) {
dSEDpciContextInfo += "\n Class = " + classCodeList.get(0);
dSEDpciContextInfo += "\n Subclass = " + classCodeList.get(1);
dSEDpciContextInfo += "\n Programming Interface = " + classCodeList.get(2);
dSEDpciContextInfo += " Device Class: \n";
if (classCodeList.size() == 3) {
dSEDpciContextInfo += " Class = " + classCodeList.get(0) + "\n";
dSEDpciContextInfo += " Subclass = " + classCodeList.get(1) + "\n";
dSEDpciContextInfo += " Programming Interface = " + classCodeList.get(2) + "\n";
} else {
dSEDpciContextInfo += " ** Class code could not be determined **";
}
dSEDpciContextInfo += "\n SubsystemVendor = " + translateVendor(subsystemVendorId);
dSEDpciContextInfo += "\n Subsystem = " + translateDevice(subsystemVendorId, subsystemId);
dSEDpciContextInfo += " SubsystemVendor = " + translateVendor(subsystemVendorId) + "\n";
dSEDpciContextInfo += " Subsystem = " + translateDevice(subsystemVendorId, subsystemId) + "\n";
return dSEDpciContextInfo;
}

View File

@ -1,6 +1,5 @@
package hirs.utils.tpm.eventlog.events;
/**
* Class to process the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER event per PFP.
*
@ -14,7 +13,37 @@ package hirs.utils.tpm.eventlog.events;
*/
public abstract class DeviceSecurityEventDataSubHeader {
/**
* Sub header type - SPDM measurement block.
*/
public static final int SUBHEADERTYPE_MEAS_BLOCK = 0;
/**
* Sub header type - SPDM cert chain.
*/
public static final int SUBHEADERTYPE_CERT_CHAIN = 1;
/**
* DeviceSecurityEventDataSubHeader Default Constructor.
*
*/
public DeviceSecurityEventDataSubHeader() {
}
/**
* 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 subheaderTypeInt int to convert to string
* @return name of the device type
*/
public static String subheaderTypeToString(final int subheaderTypeInt) {
switch (subheaderTypeInt) {
case SUBHEADERTYPE_MEAS_BLOCK:
return "SPDM Measurement Block";
case SUBHEADERTYPE_CERT_CHAIN:
return "SPDM Cert Chain";
default:
return "Unknown or invalid Subheader Type of value " + subheaderTypeInt;
}
}
}

View File

@ -0,0 +1,113 @@
package hirs.utils.tpm.eventlog.events;
import hirs.utils.HexUtils;
import hirs.utils.tpm.eventlog.spdm.SpdmCertificateChain;
import hirs.utils.tpm.eventlog.spdm.SpdmHa;
/**
* Class to process the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN event per PFP.
*
* <p>
* typedef union tdDEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN {
* UINT16 SpdmVersion;
* UINT8 SpdmSlotId;
* UINT8 Reserved;
* UINT32 SpdmBaseHashAlgo;
* SPDM_CERT_CHAIN SpdmCertChain;
* } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN;
* <p>
* SpdmVersion: SpdmBaseHashAlgo
* SpdmSlotId: SlotId associated with this SPDM Certificate Chain
* SpdmBaseHashAlgo: SPDM Base Hash Algorithm for the root certificate in the SPDM Certificate chain
* SpdmCertChain: SPDM Certificate Chain
*/
public class DeviceSecurityEventDataSubHeaderCertChain extends DeviceSecurityEventDataSubHeader {
/**
* SPDM version.
*/
private int spdmVersion = 0;
/**
* SPDM slot ID.
*/
private int spdmSlotId = 0;
/**
* SPDM base hash algorithm.
*/
private int spdmBaseHashAlgo = -1;
/**
* SPDM cert chain.
*/
private SpdmCertificateChain spdmCertChain = null;
/**
* Human-readable description of any error associated with SPDM base hash alg.
*/
private String spdmCertChainError = "";
/**
* DeviceSecurityEventDataSubHeaderCertChain Constructor.
*
* @param dsedSubHBytes byte array holding the DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock.
*/
public DeviceSecurityEventDataSubHeaderCertChain(final byte[] dsedSubHBytes) {
byte[] spdmVersionBytes = new byte[2];
System.arraycopy(dsedSubHBytes, 0, spdmVersionBytes, 0, 2);
spdmVersion = HexUtils.leReverseInt(spdmVersionBytes);
byte[] spdmLotIdBytes = new byte[1];
System.arraycopy(dsedSubHBytes, 2, spdmLotIdBytes, 0, 1);
spdmSlotId = HexUtils.leReverseInt(spdmLotIdBytes);
// byte[] reserved[Bytes]: 1 byte
byte[] spdmBaseHashAlgoBytes = new byte[4];
System.arraycopy(dsedSubHBytes, 4, spdmBaseHashAlgoBytes, 0, 4);
spdmBaseHashAlgo = HexUtils.leReverseInt(spdmBaseHashAlgoBytes);
// get the size of the SPDM Cert Chain
int spdmCertChainSize = dsedSubHBytes.length - 8;
// extract the bytes that comprise the SPDM Cert Chain
byte[] spdmCertChainBytes = new byte[spdmCertChainSize];
System.arraycopy(dsedSubHBytes, 8, spdmCertChainBytes, 0,
spdmCertChainSize);
int spdmBaseHashAlgoSize = SpdmHa.tcgAlgIdToByteSize(spdmBaseHashAlgo);
if (spdmCertChainSize <= 0) {
spdmCertChainError += "SPDM cert chain length is not >0, "
+ "stopping cert chain processing";
} else if (spdmBaseHashAlgoSize <= 0) {
spdmCertChainError += "SPDM base hash algorithm size is not >0 "
+ "stopping cert chain processing";
}
if (spdmCertChainError.isEmpty()) {
spdmCertChain = new SpdmCertificateChain(spdmCertChainBytes, spdmBaseHashAlgoSize);
}
}
/**
* Returns a human-readable description of the data within this structure.
*
* @return a description of this structure.
*/
public String toString() {
String dsedSubHeaderInfo = "";
dsedSubHeaderInfo += " SPDM Version = " + spdmVersion + "\n";
dsedSubHeaderInfo += " SPDM Slot ID = " + spdmSlotId + "\n";
String spdmBaseHashAlgoStr = SpdmHa.tcgAlgIdToString(spdmBaseHashAlgo);
dsedSubHeaderInfo += " SPDM Base Hash Algorithm = " + spdmBaseHashAlgoStr + "\n";
// SPDM Certificate Chain output
if (!spdmCertChainError.isEmpty()) {
dsedSubHeaderInfo += " SPDM cert chain error: " + spdmCertChainError + "\n";
} else if (spdmCertChain == null) {
dsedSubHeaderInfo += " SPDM cert chain error: Could not parse cert chain\n";
} else {
dsedSubHeaderInfo += spdmCertChain.toString();
}
return dsedSubHeaderInfo;
}
}

View File

@ -22,6 +22,14 @@ import java.util.List;
* SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock[SpdmMeasurementBlockCount];
* } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK;
* <p>
*
* SpdmMeasurementBlock is an array of SPDM_MEASUREMENT_BLOCKs
* The size of each block is the same and can be found by either:
* 1) 4 + SpdmMeasurementBlock MeasurementSize
* OR
* 2) 4 + hash length of the hash algorithm found in
* DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK SpdmMeasurementHashAlgo
* where 4 is the size of the SpdmMeasurementBlock header
*/
public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends DeviceSecurityEventDataSubHeader {
@ -45,9 +53,13 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
* List of SPDM Measurement Blocks.
*/
private List<SpdmMeasurementBlock> spdmMeasurementBlockList;
/**
* Error reading SPDM Measurement Block.
*/
private boolean spdmMeasurementBlockReadError = false;
/**
* DeviceSecurityEventDataHeader Constructor.
* DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock Constructor.
*
* @param dsedSubHBytes byte array holding the DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock.
*/
@ -69,7 +81,7 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
System.arraycopy(dsedSubHBytes, 4, spdmMeasurementHashAlgoBytes, 0, 4);
spdmMeasurementHashAlgo = HexUtils.leReverseInt(spdmMeasurementHashAlgoBytes);
// get the size of the SPDM Measurement Block List
// get the total size of the SPDM Measurement Block List
int spdmMeasurementBlockListSize = dsedSubHBytes.length - 8;
// extract the bytes that comprise the SPDM Measurement Block List
@ -80,9 +92,14 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
ByteArrayInputStream spdmMeasurementBlockListData =
new ByteArrayInputStream(spdmMeasurementBlockListBytes);
while (spdmMeasurementBlockListData.available() > 0) {
SpdmMeasurementBlock spdmMeasurementBlock;
spdmMeasurementBlock = new SpdmMeasurementBlock(spdmMeasurementBlockListData);
spdmMeasurementBlockList.add(spdmMeasurementBlock);
try {
SpdmMeasurementBlock spdmMeasurementBlock =
new SpdmMeasurementBlock(spdmMeasurementBlockListData);
spdmMeasurementBlockList.add(spdmMeasurementBlock);
} catch (IOException e) {
spdmMeasurementBlockReadError = true;
break;
}
}
}
@ -93,18 +110,23 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
*/
public String toString() {
String dsedSubHeaderInfo = "";
dsedSubHeaderInfo += "\n SPDM Version: " + spdmVersion;
dsedSubHeaderInfo += " SPDM Version = " + spdmVersion + "\n";
String spdmHashAlgoStr = SpdmHa.tcgAlgIdToString(spdmMeasurementHashAlgo);
dsedSubHeaderInfo += "\n SPDM Hash Algorithm = " + spdmHashAlgoStr;
dsedSubHeaderInfo += " SPDM Hash Algorithm = " + spdmHashAlgoStr + "\n";
// SPDM Measurement Block List output
dsedSubHeaderInfo += "\n Number of SPDM Measurement Blocks = " + spdmMeasurementBlockList.size();
dsedSubHeaderInfo += " Number of SPDM Measurement Blocks = "
+ spdmMeasurementBlockList.size() + "\n";
int spdmMeasBlockCnt = 1;
for (SpdmMeasurementBlock spdmMeasBlock : spdmMeasurementBlockList) {
dsedSubHeaderInfo += "\n SPDM Measurement Block # " + spdmMeasBlockCnt++ + " of " +
spdmMeasurementBlockList.size();
dsedSubHeaderInfo += " SPDM Measurement Block # " + spdmMeasBlockCnt++ + " of "
+ spdmMeasurementBlockList.size() + "\n";
dsedSubHeaderInfo += spdmMeasBlock.toString();
}
if (spdmMeasurementBlockReadError) {
dsedSubHeaderInfo += " Error reading SPDM Measurement Block #"
+ spdmMeasBlockCnt + ", halting processing\n";
}
return dsedSubHeaderInfo;
}

View File

@ -5,7 +5,6 @@ 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;
/**
@ -64,8 +63,8 @@ public abstract class DeviceSecurityEventHeader {
@Getter
private String signature = "";
/**
* Version determines data structure used (..DATA or ..DATA2),
* which determines whether ..HEADER or ..HEADER2 is used
* Version determines data structure used (..DATA or ..DATA2).
* This determines whether ..HEADER or ..HEADER2 is used.
*/
@Getter
private String version = "";
@ -84,34 +83,9 @@ public abstract class DeviceSecurityEventHeader {
*/
@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.
* DeviceSecurityEventDataHeader Constructor.
*
* @param dSEDbytes byte array holding the DeviceSecurityEventData.
*/
@ -126,7 +100,6 @@ public abstract class DeviceSecurityEventHeader {
System.arraycopy(dSEDbytes, UefiConstants.OFFSET_16, versionBytes, 0,
UefiConstants.SIZE_2);
version = HexUtils.byteArrayToHexString(versionBytes);
}
/**
@ -135,7 +108,7 @@ public abstract class DeviceSecurityEventHeader {
* @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) {
public void extractDeviceType(final byte[] dsedBytes, final int startByte) {
// get the device type ID
byte[] deviceTypeBytes = new byte[UefiConstants.SIZE_4];
@ -151,31 +124,26 @@ public abstract class DeviceSecurityEventHeader {
* @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) {
public void extractDevicePathAndFinalSize(final byte[] dsedBytes, final int startByte) {
int startByteUpdated = startByte;
// get the device path length
byte[] devicePathLengthBytes = new byte[UefiConstants.SIZE_8];
System.arraycopy(dsedBytes, startByte, devicePathLengthBytes, 0,
UefiConstants.SIZE_8);
byte[] devicePathLengthBytes = new byte[8];
System.arraycopy(dsedBytes, startByteUpdated, devicePathLengthBytes, 0, 8);
int devicePathLength = HexUtils.leReverseInt(devicePathLengthBytes);
// get the device path
if (devicePathLength != 0) {
startByte = startByte + UefiConstants.SIZE_8;
if (devicePathLength > 0) {
startByteUpdated = startByteUpdated + 8;
byte[] devPathBytes = new byte[devicePathLength];
System.arraycopy(dsedBytes, startByte, devPathBytes,
System.arraycopy(dsedBytes, startByteUpdated, devPathBytes,
0, devicePathLength);
try {
devicePath = new UefiDevicePath(devPathBytes);
devicePathValid = true;
}
catch (UnsupportedEncodingException e) {
devicePathValid = false;
}
devicePath = new UefiDevicePath(devPathBytes);
}
// header total size
dsedHeaderLength = startByte + devicePathLength;
dsedHeaderLength = startByteUpdated + devicePathLength;
}
/**
@ -187,11 +155,11 @@ public abstract class DeviceSecurityEventHeader {
*/
public String deviceTypeToString(final int deviceTypeInt) {
switch (deviceTypeInt) {
case DEVICE_TYPE_NONE:
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE:
return "No device type";
case DEVICE_TYPE_PCI:
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI:
return "PCI";
case DEVICE_TYPE_USB:
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB:
return "USB";
default:
return "Unknown or invalid Device Type";
@ -206,13 +174,12 @@ public abstract class DeviceSecurityEventHeader {
public String toString() {
String dsedHeaderCommonInfo = "";
dsedHeaderCommonInfo += "\n SPDM Device Type = " + deviceTypeToString(deviceType);
if (devicePathValid) {
dsedHeaderCommonInfo += "\n SPDM Device Path:\n";
dsedHeaderCommonInfo += " SPDM Device Type = " + deviceTypeToString(deviceType) + "\n";
if (devicePath != null) {
dsedHeaderCommonInfo += " SPDM Device Path:\n";
dsedHeaderCommonInfo += devicePath;
}
else {
dsedHeaderCommonInfo += "\n SPDM Device Path = Unknown or invalid";
} else {
dsedHeaderCommonInfo += " SPDM Device Path = Unknown or invalid\n";
}
return dsedHeaderCommonInfo;

View File

@ -117,15 +117,15 @@ public class EvEfiBootServicesApp {
* @return a human readable string.
*/
public String toString() {
String info = "Image info: ";
info += " Image physical address: " + HexUtils.byteArrayToHexString(physicalAddress);
info += " Image length = " + imageLength;
info += " Image link time address: " + HexUtils.byteArrayToHexString(physicalAddress);
info += " Device path length = " + devicePathLength;
String info = " Image info:\n";
info += " Image physical address = " + HexUtils.byteArrayToHexString(physicalAddress) + "\n";
info += " Image length = " + imageLength + "\n";
info += " Image link time address = " + HexUtils.byteArrayToHexString(physicalAddress) + "\n";
info += " Device path length = " + devicePathLength + "\n";
if (devicePathValid) {
info += "\n" + devicePath.toString();
info += devicePath.toString() + "\n";
} else {
info += "\n No uefi device paths were specified";
info += " No uefi device paths were specified\n";
}
return info;
}

View File

@ -128,14 +128,15 @@ public class EvEfiHandoffTable {
*/
public String toString() {
StringBuilder tableInfo = new StringBuilder();
tableInfo.append("Number of UEFI_CONFIGURATION_TABLEs = " + numberOfTables + "\n");
tableInfo.append(" Number of UEFI_CONFIGURATION_TABLEs = " + numberOfTables + "\n");
for (int i = 0; i < numberOfTables; i++) {
UefiGuid currentGuid = vendorGuids.get(i);
tableInfo.append(" Table " + i + ": " + currentGuid.toString());
tableInfo.append(" UEFI industry standard table type = "
tableInfo.append(" Table " + i + ":\n");
tableInfo.append(" GUID = " + currentGuid.toString() + "\n");
tableInfo.append(" UEFI industry standard table type = "
+ currentGuid.getVendorTableReference() + "\n");
tableInfo.append(" VendorTable " + i + " address: "
+ HexUtils.byteArrayToHexString(vendorTables.get(i)));
tableInfo.append(" VendorTable " + i + " address: "
+ HexUtils.byteArrayToHexString(vendorTables.get(i)) + "\n");
}
return tableInfo.toString();
}

View File

@ -2,10 +2,7 @@ package hirs.utils.tpm.eventlog.events;
import hirs.utils.HexUtils;
import hirs.utils.tpm.eventlog.uefi.UefiConstants;
import lombok.Getter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
/**
@ -41,60 +38,55 @@ public class EvEfiSpdmDeviceSecurityEvent {
/**
* Signature (text) data.
*/
private String signature = "";
private String dsedSignature = "";
/**
* Human readable description of the data within this DEVICE_SECURITY_EVENT_DATA/..DATA2 event.
* Human-readable description of the data within this DEVICE_SECURITY_EVENT_DATA/..DATA2 event.
*/
String spdmInfo = "";
private String spdmInfo = "";
/**
* EvEfiSpdmFirmwareBlob constructor.
*
* @param eventData byte array holding the event to process.
* @throws java.io.UnsupportedEncodingException if input fails to parse.
*/
public EvEfiSpdmDeviceSecurityEvent(final byte[] eventData) {
byte[] signatureBytes = new byte[UefiConstants.SIZE_16];
System.arraycopy(eventData, 0, signatureBytes, 0, UefiConstants.SIZE_16);
signature = new String(signatureBytes, StandardCharsets.UTF_8);
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
byte[] dsedSignatureBytes = new byte[UefiConstants.SIZE_16];
System.arraycopy(eventData, 0, dsedSignatureBytes, 0, UefiConstants.SIZE_16);
dsedSignature = new String(dsedSignatureBytes, StandardCharsets.UTF_8);
dsedSignature = dsedSignature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
byte[] versionBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(eventData, UefiConstants.OFFSET_16, versionBytes, 0,
byte[] dsedVersionBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(eventData, UefiConstants.OFFSET_16, dsedVersionBytes, 0,
UefiConstants.SIZE_2);
String version = HexUtils.byteArrayToHexString(versionBytes);
if (version == "") {
version = "version not readable";
String dsedVersion = HexUtils.byteArrayToHexString(dsedVersionBytes);
if (dsedVersion == "") {
dsedVersion = "version not readable";
}
if (signature.contains("SPDM Device Sec2")) {
if (dsedSignature.contains("SPDM Device Sec2")) {
spdmInfo = " Signature = SPDM Device Sec2";
spdmInfo = " Signature = SPDM Device Sec2\n";
if (version.equals("0200")) {
if (dsedVersion.equals("0200")) {
dsed = new DeviceSecurityEventData2(eventData);
spdmInfo += dsed.toString();
} else {
spdmInfo += " Incompatible version for DeviceSecurityEventData2: " + dsedVersion + "\n";
}
else {
spdmInfo += " Incompatible version for DeviceSecurityEventData2: " + version;
}
}
else if (signature.contains("SPDM Device Sec")) { // implies Device Security event
} else if (dsedSignature.contains("SPDM Device Sec")) { // implies Device Security event
spdmInfo = " Signature = SPDM Device Sec";
spdmInfo = " Signature = SPDM Device Sec\n";
if (version.equals("0100")) {
if (dsedVersion.equals("0100")) {
dsed = new DeviceSecurityEventData(eventData);
spdmInfo += dsed.toString();
} else {
spdmInfo += " Incompatible version for DeviceSecurityEventData: " + dsedVersion + "\n";
}
else {
spdmInfo += " Incompatible version for DeviceSecurityEventData: " + version;
}
}
else {
spdmInfo = " Signature = Undetermined value: " + signature;
} else {
spdmInfo = " Signature = Undetermined value: " + dsedSignature + "\n";
}
}

View File

@ -98,7 +98,6 @@ public class EvEfiSpecIdEvent {
algList = new ArrayList<>();
byte[] signatureBytes = new byte[UefiConstants.SIZE_16];
System.arraycopy(efiSpecId, 0, signatureBytes, 0, UefiConstants.SIZE_16);
signature = HexUtils.byteArrayToHexString(signatureBytes);
signature = new String(signatureBytes, StandardCharsets.UTF_8)
.substring(0, UefiConstants.SIZE_15);

View File

@ -1,5 +1,6 @@
package hirs.utils.tpm.eventlog.events;
import hirs.utils.HexUtils;
import hirs.utils.tpm.eventlog.uefi.UefiConstants;
import lombok.Getter;
@ -7,12 +8,15 @@ import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
/**
* Class to process the EV_NO_ACTION event using a structure of TCG_EfiSpecIDEvent.
* Class to process the EV_NO_ACTION event.
* The first 16 bytes of the event data MUST be a String based identifier (Signature).
* The only currently defined Signature is "Spec ID Event03"
* which implies the data is a TCG_EfiSpecIDEvent.
* TCG_EfiSpecIDEvent is the first event in a TPM Event Log and is used to determine
* if the format of the Log (SHA1 vs Crypto Agile).
* The only currently defined Signatures are
* 1) "Spec ID Event03"
* - implies the data is a TCG_EfiSpecIDEvent
* - TCG_EfiSpecIDEvent is the first event in a TPM Event Log and is used to determine
* if the format of the Log (SHA1 vs Crypto Agile).
* 2) "NvIndexInstance"
* - implies the data is a NV_INDEX_INSTANCE_EVENT_LOG_DATA
* <p>
* Notes:
* 1. First 16 bytes of the structure is an ASCII with a fixed Length of 16
@ -29,10 +33,21 @@ public class EvNoAction {
*/
private boolean bSpecIDEvent = false;
/**
* EvEfiSpecIdEvent Object.
* TCG Event Log spec version.
*/
@Getter
private EvEfiSpecIdEvent specIDEvent = null;
private String specVersion = "Unknown";
/**
* TCG Event Log errata version.
*/
@Getter
private String specErrataVersion = "Unknown";
/**
* Human-readable description of the data within this DEVICE_SECURITY_EVENT_DATA/..DATA2 event.
*/
@Getter
private String noActionInfo = "";
/**
* EvNoAction constructor.
@ -46,8 +61,23 @@ public class EvNoAction {
signature = new String(signatureBytes, StandardCharsets.UTF_8);
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
if (signature.contains("Spec ID Event03")) { // implies CryptAgileFormat
specIDEvent = new EvEfiSpecIdEvent(eventData);
EvEfiSpecIdEvent specIDEvent = new EvEfiSpecIdEvent(eventData);
noActionInfo += specIDEventToString(specIDEvent).toString();
bSpecIDEvent = true;
specVersion = String.format("%s.%s",
specIDEvent.getVersionMajor(),
specIDEvent.getVersionMinor());
specErrataVersion = specIDEvent.getErrata();
} else if (signature.contains("StartupLocality")) {
noActionInfo += " Signature = StartupLocality";
noActionInfo += "\n StartupLocality = " + getLocality(eventData);
} else if (signature.contains("NvIndexInstance")) {
NvIndexInstanceEventLogData nvIndexInstanceEvent = new NvIndexInstanceEventLogData(eventData);
noActionInfo += nvIndexInstanceEvent.toString();
} else {
noActionInfo = "EV_NO_ACTION event named " + signature
+ " encountered but support for processing it has not been"
+ " added to this application.\n";
}
}
@ -60,27 +90,62 @@ public class EvNoAction {
return bSpecIDEvent;
}
/**
* Returns a human-readable description of a SpecId event.
*
* @param specIDEvent byte array holding the event.
* @return a description of the event.
*/
public String specIDEventToString(final EvEfiSpecIdEvent specIDEvent) {
String specIdInfo = "";
specIdInfo += " Signature = Spec ID Event03 : ";
if (specIDEvent.isCryptoAgile()) {
specIdInfo += "Log format is Crypto Agile\n";
} else {
specIdInfo += "Log format is SHA 1 (NOT Crypto Agile)\n";
}
specIdInfo += " Platform Profile Specification version = "
+ specIDEvent.getVersionMajor() + "." + specIDEvent.getVersionMinor()
+ " using errata version " + specIDEvent.getErrata();
return specIdInfo;
}
/**
* Returns a human-readable description of locality based on numeric representation lookup.
*
* @param eventData byte array holding the event from which to grab locality
* @return a description of the locality.
*/
private String getLocality(final byte[] eventData) {
String localityInfo = "";
byte[] localityBytes = new byte[1];
System.arraycopy(eventData, 16, localityBytes, 0, 1);
int locality = HexUtils.leReverseInt(localityBytes);
switch (locality) {
case 0:
localityInfo += "Locality 0 without an H-CRTM sequence";
break;
case 3:
localityInfo += "Locality 3 without an H-CRTM sequence";
break;
case 4:
localityInfo += "Locality 4 with an H-CRTM sequence initialized";
break;
default:
localityInfo += "Unknown";
}
return localityInfo;
}
/**
* Returns a description of this event.
*
* @return Human readable description of this event.
* @return Human-readable description of this event.
*/
public String toString() {
String specInfo = "";
if (bSpecIDEvent) {
specInfo += " Signature = Spec ID Event03 : ";
if (specIDEvent.isCryptoAgile()) {
specInfo += "Log format is Crypto Agile\n";
} else {
specInfo += "Log format is SHA 1 (NOT Crypto Agile)\n";
}
specInfo += " Platform Profile Specification version = "
+ specIDEvent.getVersionMajor() + "." + specIDEvent.getVersionMinor()
+ " using errata version " + specIDEvent.getErrata();
} else {
specInfo = "EV_NO_ACTION event named " + signature
+ " encountered but support for processing it has not been added to this application.\n";
}
return specInfo;
return noActionInfo;
}
}

View File

@ -39,14 +39,14 @@ public class EvSCrtmVersion {
if (UefiGuid.isValidUUID(data)) {
guid = new UefiGuid(data);
String guidInfo = guid.toStringNoLookup();
description = " SCRM Version = " + guidInfo;
description = " SCRM Version = " + guidInfo;
}
} else if (data.length < UefiConstants.SIZE_4) {
description = HexUtils.byteArrayToHexString(data);
} else if (EvPostCode.isAscii(data)) {
description = new String(data, StandardCharsets.UTF_8);
} else {
description = "Unknown Version format";
description = " Unknown Version format";
}
}
return (description);

View File

@ -0,0 +1,105 @@
package hirs.utils.tpm.eventlog.events;
import hirs.utils.HexUtils;
import java.nio.charset.StandardCharsets;
/**
* Class to process the NV_INDEX_INSTANCE_EVENT_LOG_DATA per PFP.
* Per PFP, the first 16 bytes of the structure are a String based identifier (Signature),
* which are a NULL-terminated ASCII string "NvIndexInstance".
*
* 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 tdNV_INDEX_INSTANCE_EVENT_LOG_DATA {
* BYTE Signature[16];
* UINT16 Version;
* UINT8[6] Reserved;
* DEVICE_SECURITY_EVENT_DATA2 Data;
* } NV_INDEX_INSTANCE_EVENT_LOG_DATA;
* <p>
*/
public class NvIndexInstanceEventLogData {
/**
* DeviceSecurityEventData2 Object.
*/
// private DeviceSecurityEventData2 dsed = null;
private DeviceSecurityEvent dsed = null;
/**
* Signature (text) data.
*/
private String signature = "";
/**
* Human-readable description of the data within this DEVICE_SECURITY_EVENT_DATA/..DATA2 event.
*/
private String nvIndexInstanceInfo = "";
/**
* NvIndexInstanceEventLogData constructor.
*
* @param eventData byte array holding the event to process.
*/
public NvIndexInstanceEventLogData(final byte[] eventData) {
byte[] signatureBytes = new byte[16];
System.arraycopy(eventData, 0, signatureBytes, 0, 16);
signature = new String(signatureBytes, StandardCharsets.UTF_8);
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
byte[] versionBytes = new byte[2];
System.arraycopy(eventData, 16, versionBytes, 0, 2);
String nvIndexVersion = HexUtils.byteArrayToHexString(versionBytes);
if (nvIndexVersion == "") {
nvIndexVersion = "version not readable";
}
nvIndexInstanceInfo = " Nv Index Instance Signature = " + signature + "\n";
nvIndexInstanceInfo += " Nv Index Instance Version = " + nvIndexVersion + "\n";
// 6 bytes of Reserved data
byte[] dsedSignatureBytes = new byte[16];
System.arraycopy(eventData, 24, dsedSignatureBytes, 0, 16);
String dsedSignature = new String(dsedSignatureBytes, StandardCharsets.UTF_8);
dsedSignature = dsedSignature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
byte[] dsedVersionBytes = new byte[2];
System.arraycopy(eventData, 40, dsedVersionBytes, 0, 2);
String dsedVersion = HexUtils.byteArrayToHexString(dsedVersionBytes);
if (dsedVersion == "") {
dsedVersion = "version not readable";
}
if (dsedSignature.contains("SPDM Device Sec2")) {
int dsedEventDataSize = eventData.length - 24;
byte[] dsedEventData = new byte[dsedEventDataSize];
System.arraycopy(eventData, 24, dsedEventData, 0, dsedEventDataSize);
nvIndexInstanceInfo += " Signature = SPDM Device Sec2\n";
if (dsedVersion.equals("0200")) {
dsed = new DeviceSecurityEventData2(dsedEventData);
nvIndexInstanceInfo += dsed.toString();
} else {
nvIndexInstanceInfo += " Incompatible version for DeviceSecurityEventData2: "
+ dsedVersion + "\n";
}
} else {
nvIndexInstanceInfo = " Signature error: should be \'SPDM Device Sec2\' but is "
+ signature + "\n";
}
}
/**
* Returns a description of this event.
*
* @return Human-readable description of this event.
*/
public String toString() {
return nvIndexInstanceInfo;
}
}

View File

@ -0,0 +1,172 @@
package hirs.utils.tpm.eventlog.spdm;
import hirs.utils.HexUtils;
import hirs.utils.tpm.eventlog.uefi.UefiX509Cert;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
/**
* Class to process the SpdmCertificateChain.
* <p>
* Certificate chain format, defined by SPDM v1.03, Sect 10.6.1, Table 33:
* Certificate chain format {
* Length 2 bytes;
* Reserved 2 bytes;
* RootHash <H> bytes;
* Certificates <Length> - (4 + <H>) bytes;
* }
* <p>
* Length: total length of cert chain including all fields in this block
* H: the output size of the hash algorithm selected by the most recent ALGORITHMS response
* this field shall be in hash byte order
* hash algorithm is included in the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN
* structure as the member "SpdmBaseHashAlg"
* RootHash: the digest of the Root Certificate.
* size is determined by hash algorithm selected by the most recent SPDM ALGORITHMS response;
* the hash algorithm is the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN SpdmBaseHashAlgo
* Certificates: Complete cert chain consisting of 1 or more ASN.1 DER-encoded X.509 v3 certs
* this field shall be in Encoded ASN.1 byte order
*/
public class SpdmCertificateChain {
///**
// * Length of the certificate chain to include all fields in this structure.
// */
//private int length = 0;
/**
* Root hash.
*/
private byte[] rootHash = null;
/**
* Number of certs in the SPDM cert chain.
*/
private int numberOfCerts = 0;
/**
* Array List of certs found in the chain.
*/
private ArrayList<UefiX509Cert> certList = new ArrayList<UefiX509Cert>();
/**
* Human-readable description of any error associated with SPDM base hash alg.
*/
private String spdmBaseHashAlgoError = "";
/**
* Human-readable description of any error associated with parsing the X509 certs.
*/
private String certProcessingError = "";
/**
* SpdmCertificateChain Constructor.
*
* @param spdmCertChainBytes byte array holding the SPDM Cert Chain bytes.
* @param rootHashLength length of RootHash.
*/
public SpdmCertificateChain(final byte[] spdmCertChainBytes, final int rootHashLength) {
if (rootHashLength <= 0) {
spdmBaseHashAlgoError = "SPDM base hash algorithm size is not >0";
} else {
byte[] lengthBytes = new byte[2];
System.arraycopy(spdmCertChainBytes, 0, lengthBytes, 0, 2);
//length = HexUtils.leReverseInt(lengthBytes);
// Reserved: 2 bytes
rootHash = new byte[rootHashLength];
System.arraycopy(spdmCertChainBytes, 4, rootHash, 0, rootHashLength);
int certChainStartPos = 4 + rootHashLength;
int certChainLength = spdmCertChainBytes.length - certChainStartPos;
byte[] certChainBytes = new byte[certChainLength];
System.arraycopy(spdmCertChainBytes, certChainStartPos, certChainBytes, 0, certChainLength);
processCertChain(certChainBytes);
}
}
/**
* Method for processing the data in an EFI SignatureList (ex. can be one or more X509 certs)
*
* @param certChainData Byte array holding the cert chain data
*/
private void processCertChain(final byte[] certChainData) {
UefiX509Cert cert = null;
ByteArrayInputStream certChainDataIS = new ByteArrayInputStream(certChainData);
while (certChainDataIS.available() > 0) {
// java.io.IOException If there's a problem parsing the cert chain data.
// java.security.cert.CertificateException if there's a problem parsing the X509 certificate.
// java.security.NoSuchAlgorithmException if there's a problem hashing the certificate.
try {
byte[] certType = new byte[2];
certChainDataIS.read(certType);
byte[] certLength = new byte[2];
certChainDataIS.read(certLength);
//int cLength = new BigInteger(certLength).intValue() + UefiConstants.SIZE_4;
int cLength = new BigInteger(certLength).intValue();
byte[] certData = new byte[cLength];
certChainDataIS.read(certData);
// put the cert back together
byte[] certBlob = new byte[cLength + 4];
System.arraycopy(certType, 0, certBlob, 0, 2);
System.arraycopy(certLength, 0, certBlob, 2, 2);
System.arraycopy(certData, 0, certBlob, 4, cLength);
cert = new UefiX509Cert(certBlob);
//cert = new X509Certificate(certBlob);
certList.add(cert);
numberOfCerts++;
} catch (IOException e) {
certProcessingError += "Error with Cert # " + (numberOfCerts + 1)
+ ": IOException (error reading cert data)";
break;
} catch (CertificateException e) {
certProcessingError += "Error with Cert # " + (numberOfCerts + 1)
+ ": CertificateException";
break;
} catch (NoSuchAlgorithmException e) {
certProcessingError += "Error with Cert # " + (numberOfCerts + 1)
+ ": CNoSuchAlgorithmException";
break;
}
}
}
/**
* Returns a human-readable description of the data within this structure.
*
* @return a description of this structure.
*/
public String toString() {
String spdmCertChainInfo = "";
if (!spdmBaseHashAlgoError.isEmpty()) {
spdmCertChainInfo += " *** ERROR with SPDM base hash algorithm size ***\n";
spdmCertChainInfo += " " + spdmBaseHashAlgoError + "\n";
spdmCertChainInfo += " Stopping processing of this cert chain\n";
} else {
spdmCertChainInfo += " Root hash = " + HexUtils.byteArrayToHexString(rootHash) + "\n";
spdmCertChainInfo += " Number of certs in chain = " + numberOfCerts + "\n";
int certCnt = 1;
for (UefiX509Cert cert : certList) {
spdmCertChainInfo += " Cert # " + certCnt++ + " of "
+ numberOfCerts + ": ------------------\n";
spdmCertChainInfo += cert.toString();
}
if (!certProcessingError.isEmpty()) {
spdmCertChainInfo += " *** ERROR processing cert ***\n";
spdmCertChainInfo += " " + certProcessingError + "\n";
spdmCertChainInfo += " Stopping processing of this cert chain\n";
}
}
return spdmCertChainInfo;
}
}

View File

@ -11,7 +11,7 @@ import lombok.NoArgsConstructor;
public class SpdmHa {
/**
* Spdm Hash Alg = Raw bit stream
* Spdm Hash Alg = Raw bit stream.
*/
public static final int TPM_ALG_RAW = 1;
/**
@ -41,7 +41,7 @@ public class SpdmHa {
/**
* Returns the hash name via a lookup.
* Lookup based upon section 10.4 for the SPDM v1.03 document.
* Lookup based upon SPDM Spec v1.03 section 10.4.
*
* @param algId int to convert to string
* @return name of the algorithm
@ -75,4 +75,41 @@ public class SpdmHa {
}
return alg;
}
/**
* Returns the hash value size based on the hash algorithm.
* Lookup based upon SPDM Spec v1.03 section 10.4.
*
* @param algId int to convert to string
* @return size of the algorithm output
*/
public static int tcgAlgIdToByteSize(final int algId) {
int byteSize;
switch (algId) {
//case TPM_ALG_RAW: // add this when have more test data
// byteSize = ;
// break;
case TPM_ALG_SHA_256:
byteSize = 32;
break;
case TPM_ALG_SHA_384:
byteSize = 48;
break;
case TPM_ALG_SHA_512:
byteSize = 64;
break;
case TPM_ALG_SHA3_256:
byteSize = 32;
break;
case TPM_ALG_SHA3_384:
byteSize = 48;
break;
case TPM_ALG_SHA3_512:
byteSize = 64;
break;
default:
byteSize = -1;
}
return byteSize;
}
}

View File

@ -1,7 +1,6 @@
package hirs.utils.tpm.eventlog.spdm;
import hirs.utils.HexUtils;
import lombok.AccessLevel;
import lombok.Getter;
/**
@ -36,7 +35,7 @@ public class SpdmMeasurement {
/**
* Measurement value (digest).
*/
private byte[] dmtfSpecMeasurementValue = null;
private byte[] dmtfSpecMeasurementValue;
/**
* SpdmMeasurement Constructor.
@ -62,7 +61,7 @@ public class SpdmMeasurement {
}
/**
* Lookup for SPDM measurement value type
* Lookup for SPDM measurement value type.
*
* @param measValType the numerical representation of the measurement value type.
*
@ -119,10 +118,11 @@ public class SpdmMeasurement {
public String toString() {
String spdmMeasInfo = "";
spdmMeasInfo += "\n SPDM Measurement Value Type = " +
dmtfSpecMeasurementValueTypeToString(dmtfSpecMeasurementValueType);
spdmMeasInfo += "\n SPDM Measurement Value = " +
HexUtils.byteArrayToHexString(dmtfSpecMeasurementValue);
spdmMeasInfo += " SPDM Measurement Value Type = "
+ dmtfSpecMeasurementValueTypeToString(dmtfSpecMeasurementValueType);
spdmMeasInfo += "\n SPDM Measurement Value = "
+ HexUtils.byteArrayToHexString(dmtfSpecMeasurementValue);
spdmMeasInfo += "\n";
return spdmMeasInfo;
}

View File

@ -1,16 +1,10 @@
package hirs.utils.tpm.eventlog.spdm;
import hirs.utils.HexUtils;
import hirs.utils.tpm.eventlog.uefi.UefiConstants;
import lombok.Getter;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Class to process the SpdmMeasurementBlock.
@ -46,57 +40,44 @@ public class SpdmMeasurementBlock {
* SPDM Measurement.
*/
private SpdmMeasurement spdmMeasurement;
/**
* Error reading SPDM Measurement Block.
*/
private boolean spdmMeasurementBlockReadError = false;
/**
* SpdmMeasurementBlock Constructor.
*
* @param spdmMeasBlocks byte array holding the SPDM Measurement Block bytes.
*/
public SpdmMeasurementBlock(final ByteArrayInputStream spdmMeasBlocks) {
public SpdmMeasurementBlock(final ByteArrayInputStream spdmMeasBlocks) throws IOException {
try {
byte[] indexBytes = new byte[1];
spdmMeasBlocks.read(indexBytes);
index = HexUtils.leReverseInt(indexBytes);
byte[] indexBytes = new byte[1];
spdmMeasBlocks.read(indexBytes);
index = HexUtils.leReverseInt(indexBytes);
byte[] measurementSpecBytes = new byte[1];
spdmMeasBlocks.read(measurementSpecBytes);
measurementSpec = HexUtils.leReverseInt(measurementSpecBytes);
byte[] measurementSpecBytes = new byte[1];
spdmMeasBlocks.read(measurementSpecBytes);
measurementSpec = HexUtils.leReverseInt(measurementSpecBytes);
// in future, can crosscheck this measurement size with the MeasurementSpec hash alg size
byte[] measurementSizeBytes = new byte[2];
spdmMeasBlocks.read(measurementSizeBytes);
int measurementSize = HexUtils.leReverseInt(measurementSizeBytes);
// in future, can crosscheck this measurement size with the MeasurementSpec hash alg size
byte[] measurementSizeBytes = new byte[2];
spdmMeasBlocks.read(measurementSizeBytes);
int measurementSize = HexUtils.leReverseInt(measurementSizeBytes);
byte[] measurementBytes = new byte[measurementSize];
spdmMeasBlocks.read(measurementBytes);
spdmMeasurement = new SpdmMeasurement(measurementBytes);
} catch (IOException ioEx) {
spdmMeasurementBlockReadError = true;
}
byte[] measurementBytes = new byte[measurementSize];
spdmMeasBlocks.read(measurementBytes);
spdmMeasurement = new SpdmMeasurement(measurementBytes);
}
/**
* Returns a human-readable description of the data within this structure.
*
* @return a description of this structure..
* @return a description of this structure.
*/
public String toString() {
String spdmMeasBlockInfo = "";
if(spdmMeasurementBlockReadError) {
spdmMeasBlockInfo += "\n Error reading SPDM Measurement Block";
}
else {
spdmMeasBlockInfo += "\n Index = " + index;
spdmMeasBlockInfo += "\n MeasurementSpec = " + measurementSpec;
spdmMeasBlockInfo += spdmMeasurement.toString();
}
spdmMeasBlockInfo += " Index = " + index + "\n";
spdmMeasBlockInfo += " MeasurementSpec = " + measurementSpec + "\n";
spdmMeasBlockInfo += spdmMeasurement.toString();
return spdmMeasBlockInfo;
}

View File

@ -25,15 +25,15 @@ public class UefiBootOrder {
}
/**
* Provides a human readable Boot Order list on single line.
* Provides a human-readable Boot Order list on single line.
*
* @return A human readable Boot Order
* @return A human-readable Boot Order
*/
public String toString() {
StringBuilder orderList = new StringBuilder();
orderList.append("BootOrder = ");
orderList.append(" BootOrder = ");
for (int i = 0; i < bootOrder.length; i++) {
orderList.append(String.format("Boot %04d", (int) bootOrder[i]));
orderList.append(String.format("Boot%04d ", (int) bootOrder[i]));
}
//orderList.append("\n");
return orderList.toString();

View File

@ -23,7 +23,7 @@ import java.util.Arrays;
*/
public class UefiBootVariable {
/**
* Human readable description of the variable.
* Human-readable description of the variable.
*/
private String description = "";
/**
@ -81,7 +81,7 @@ public class UefiBootVariable {
* @return string that represents a UEFI boot variable.
*/
public String toString() {
StringBuilder bootInfo = new StringBuilder("Description = ");
StringBuilder bootInfo = new StringBuilder(" EFI Load Option = ");
// remove all non ascii chars
String bootVar = description.replaceAll("[^a-zA-Z_0-0\\s]", "");
bootInfo.append(bootVar + "\n" + efiDevPath.toString());

View File

@ -3,12 +3,23 @@ package hirs.utils.tpm.eventlog.uefi;
import hirs.utils.HexUtils;
import lombok.Getter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
/**
* Class to process EFI_DEVICE_PATH_PROTOCOL which is referred to as the UEFI_DEVICE_PATH
* Class to process a Device Path. A Device Path is a variable-length binary
* structure that is made up of variable-length generic Device Path nodes.
* The first Device Path node starts at byte offset zero of the Device Path.
* The next Device Path node starts at the end of the previous Device Path node.
* There is no limit to the number, type, or sequence of nodes in a Device Path.
* <p>
* Generic Device Path Node Structure:
* Name Byte Offset Byte Length Description
* Type 0 1 Device path type (such as 0x01 - Hardware Device Path)
* Sub-Type 1 1 Sub-Type
* Length 2 2 Length of this structure in bytes. Length is 4+n bytes
* Data 4 n Specific Device Path data
* <p>
* EFI_DEVICE_PATH_PROTOCOL:
* #define EFI_DEVICE_PATH_PROTOCOL_GUID \09576e91-6d3f-11d2-8e39-00a0c969723b
* typedef struct _EFI_DEVICE_PATH_PROTOCOL {
* UINT8 Type;
@ -23,7 +34,7 @@ import java.nio.charset.StandardCharsets;
* Type 0x04 Media Device Path
* Type 0x05 BIOS Boot Specification Device Path
* Type 0x7F End of Hardware Device Path
* Each Type has a sub-type that may or may no be defined in the section
* Each Type has a Subtype that may or may not be defined in the section
* <p>
* Only a few of the SubTypes have been implemented as there are many,
* but only those that were reported using the test devices at hand.
@ -36,11 +47,11 @@ public class UefiDevicePath {
@Getter
private String type = "";
/**
* UEFI Device path sub-type.
* UEFI Device path subtype.
*/
private String subType = "";
/**
* UEFI Device path human readable description.
* UEFI Device path human-readable description.
*/
private String devPathInfo = "";
/**
@ -53,9 +64,8 @@ public class UefiDevicePath {
* UEFI Device path constructor.
*
* @param path byte array holding device path data
* @throws java.io.UnsupportedEncodingException if path byte array contains unexpected values
*/
public UefiDevicePath(final byte[] path) throws UnsupportedEncodingException {
public UefiDevicePath(final byte[] path) {
devPathInfo = processDevPath(path);
byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(path, UefiConstants.OFFSET_2, lengthBytes, 0, UefiConstants.OFFSET_2);
@ -63,9 +73,9 @@ public class UefiDevicePath {
}
/**
* Returns the UEFI device sub-type.
* Returns the UEFI device subtype.
*
* @return uefi sub-type
* @return uefi subtype
*/
public String getSubType() {
return subType.trim();
@ -81,18 +91,17 @@ public class UefiDevicePath {
* @return Human readable string containing the device path description.
* @throws java.io.UnsupportedEncodingException
*/
private String processDevPath(final byte[] path) throws UnsupportedEncodingException {
private String processDevPath(final byte[] path) {
StringBuilder pInfo = new StringBuilder();
int devLength = 0, pathOffset = 0, devCount = 0;
int devLength = 0;
int pathOffset = 0;
int devCount = 0;
while (true) {
Byte devPath = Byte.valueOf(path[pathOffset]);
if ((devPath.intValue() == UefiConstants.TERMINATOR)
|| (devPath.intValue() == UefiConstants.END_FLAG)) {
break;
}
if (devCount++ > 0) {
pInfo.append("\n");
}
pInfo.append(processDev(path, pathOffset));
devLength = path[pathOffset + UefiConstants.OFFSET_3] * UefiConstants.SIZE_256
+ path[pathOffset + UefiConstants.OFFSET_2];
@ -111,11 +120,10 @@ public class UefiDevicePath {
*
* @param path
* @param offset
* @return human readable string representing the UEFI device path
* @return human-readable string representing the UEFI device path
* @throws java.io.UnsupportedEncodingException
*/
private String processDev(final byte[] path, final int offset)
throws UnsupportedEncodingException {
private String processDev(final byte[] path, final int offset) {
String devInfo = " ";
int devPath = path[offset];
byte unknownSubType = path[offset + UefiConstants.OFFSET_1];
@ -123,50 +131,50 @@ public class UefiDevicePath {
case UefiConstants.DEV_HW:
type = "Hardware Device Path";
if (devPath == UefiConstants.DEVPATH_HARWARE) {
devInfo += type + ": " + pciSubType(path, offset);
devInfo += type + ":\n" + pciSubType(path, offset);
}
break;
case UefiConstants.DEV_ACPI:
type = "ACPI Device Path";
devInfo += type + ": " + acpiSubType(path, offset);
devInfo += type + ":\n" + acpiSubType(path, offset);
break;
case UefiConstants.DEV_MSG:
type = "Messaging Device Path";
if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEV_SUB_SATA) {
devInfo += type + ": " + sataSubType(path, offset);
devInfo += type + ":\n" + sataSubType(path, offset);
} else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEV_SUB_NVM) {
devInfo += type + ": " + nvmSubType(path, offset);
devInfo += type + ":\n" + nvmSubType(path, offset);
} else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEV_SUB_USB) {
devInfo += type + ": " + usbSubType(path, offset);
devInfo += type + ":\n" + usbSubType(path, offset);
} else {
devInfo += "UEFI Messaging Device Path Type " + Integer.valueOf(unknownSubType);
devInfo += "UEFI Messaging Device Path Type " + Integer.valueOf(unknownSubType) + "\n";
}
break;
case UefiConstants.DEV_MEDIA:
type = "Media Device Path";
if (path[offset + UefiConstants.OFFSET_1] == 0x01) {
devInfo += type + ": " + hardDriveSubType(path, offset);
devInfo += type + ":\n" + hardDriveSubType(path, offset);
} else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEVPATH_VENDOR) {
devInfo += type + ": " + vendorSubType(path, offset);
devInfo += type + ":\n" + vendorSubType(path, offset);
} else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEVPATH_FILE) {
devInfo += type + ": " + filePathSubType(path, offset);
devInfo += type + ":\n" + filePathSubType(path, offset);
} else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEVPATH_PWIG_FILE) {
devInfo += type + ": " + piwgFirmVolFile(path, offset);
devInfo += type + ":\n" + piwgFirmVolFile(path, offset);
} else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEVPATH_PWIG_VOL) {
devInfo += type + ": " + piwgFirmVolPath(path, offset);
devInfo += type + ":\n" + piwgFirmVolPath(path, offset);
} else {
devInfo += "UEFI Media Device Path Type " + Integer.valueOf(unknownSubType);
devInfo += "UEFI Media Device Path Type " + Integer.valueOf(unknownSubType) + "\n";
}
break;
case UefiConstants.DEV_BIOS:
type = "BIOS Device Path";
devInfo += type + ": " + biosDevicePath(path, offset);
devInfo += type + ":\n" + biosDevicePath(path, offset);
break;
case UefiConstants.TERMINATOR:
devInfo += "End of Hardware Device Path";
devInfo += "End of Hardware Device Path\n";
break;
default:
devInfo += "UEFI Device Path Type " + Integer.valueOf(unknownSubType);
devInfo += "UEFI Device Path Type " + Integer.valueOf(unknownSubType) + "\n";
}
return devInfo;
}
@ -179,17 +187,17 @@ public class UefiDevicePath {
* @return acpi device info
*/
private String acpiSubType(final byte[] path, final int offset) {
subType = "";
subType = " Sub Type = ACPI\n";
switch (path[offset + UefiConstants.OFFSET_1]) {
case 0x01:
subType = "(Short): ";
case 0x01: // standard version
subType += acpiShortSubType(path, offset);
break;
case 0x02:
subType = "Expanded ACPI Device Path";
subType = "(expanded version):\n";
// tbd
break;
default:
subType = "Invalid ACPI Device Path sub type";
subType = "Invalid ACPI Device Path sub type\n";
}
return subType;
}
@ -205,9 +213,13 @@ public class UefiDevicePath {
subType = "";
byte[] hid = new byte[UefiConstants.SIZE_4];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, hid, 0, UefiConstants.SIZE_4);
subType += "_HID = " + HexUtils.byteArrayToHexString(hid);
subType += " _HID = " + HexUtils.byteArrayToHexString(hid) + "\n";
System.arraycopy(path, 2 * UefiConstants.SIZE_4 + offset, hid, 0, UefiConstants.SIZE_4);
subType += "_UID = " + HexUtils.byteArrayToHexString(hid);
String uid = HexUtils.byteArrayToHexString(hid);
if (uid.contains("00000000")) {
uid = "No _UID exists for this device";
}
subType += " _UID = " + uid + "\n";
return subType;
}
@ -219,22 +231,25 @@ public class UefiDevicePath {
* @return pci device info.
*/
private String pciSubType(final byte[] path, final int offset) {
subType = "PCI: PCI Function Number = ";
subType = " Sub Type = PCI\n";
subType += " PCI Function Number = ";
subType += String.format("0x%x", path[offset + UefiConstants.SIZE_4]);
subType += " PCI Device Number = ";
subType += "\n PCI Device Number = ";
subType += String.format("0x%x", path[offset + UefiConstants.SIZE_5]);
subType += "\n";
return subType;
}
/**
* processes the SATA sub type.
* processes the SATA subtype.
*
* @param path
* @param offset
* @return SATA drive info.
*/
private String sataSubType(final byte[] path, final int offset) {
subType = "SATA: HBA Port Number = ";
subType = " Sub Type = SATA\n";
subType += " SATA: HBA Port Number = ";
byte[] data = new byte[UefiConstants.SIZE_2];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, data, 0, UefiConstants.SIZE_2);
subType += HexUtils.byteArrayToHexString(data);
@ -242,18 +257,20 @@ public class UefiDevicePath {
subType += " Port Multiplier = " + HexUtils.byteArrayToHexString(data);
System.arraycopy(path, UefiConstants.OFFSET_8 + offset, data, 0, UefiConstants.SIZE_2);
subType += " Logical Unit Number = " + HexUtils.byteArrayToHexString(data);
subType += "\n";
return subType;
}
/**
* Processes the hard drive sub type.
* Processes the hard drive subtype.
*
* @param path
* @param offset
* @return hard drive info.
*/
private String hardDriveSubType(final byte[] path, final int offset) {
subType = "Partition Number = ";
subType = " Sub Type = Hard Drive\n";
subType += " Partition Number = ";
byte[] partnumber = new byte[UefiConstants.SIZE_4];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, partnumber,
0, UefiConstants.SIZE_4);
@ -261,14 +278,14 @@ public class UefiDevicePath {
byte[] data = new byte[UefiConstants.SIZE_8];
System.arraycopy(path, UefiConstants.OFFSET_8 + offset, data, 0,
UefiConstants.SIZE_8);
subType += " Partition Start = " + HexUtils.byteArrayToHexString(data);
subType += "\n Partition Start = " + HexUtils.byteArrayToHexString(data);
System.arraycopy(path, UefiConstants.OFFSET_16 + offset, data, 0,
UefiConstants.SIZE_8);
subType += " Partition Size = " + HexUtils.byteArrayToHexString(data);
subType += "\n Partition Size = " + HexUtils.byteArrayToHexString(data);
byte[] signature = new byte[UefiConstants.SIZE_16];
System.arraycopy(path, UefiConstants.OFFSET_24 + offset, signature, 0,
UefiConstants.SIZE_16);
subType += "\n Partition Signature = ";
subType += "\n Partition Signature = ";
if (path[UefiConstants.OFFSET_41 + offset] == UefiConstants.DRIVE_SIG_NONE) {
subType += "None";
} else if (path[UefiConstants.OFFSET_41 + offset] == UefiConstants.DRIVE_SIG_32BIT) {
@ -279,26 +296,28 @@ public class UefiDevicePath {
} else {
subType += "invalid partition signature type";
}
subType += " Partition Format = ";
subType += "\n Partition Format = ";
if (path[UefiConstants.OFFSET_40 + offset] == UefiConstants.DRIVE_TYPE_PC_AT) {
subType += " PC-AT compatible legacy MBR";
subType += "PC-AT compatible legacy MBR";
} else if (path[UefiConstants.OFFSET_40 + offset] == UefiConstants.DRIVE_TYPE_GPT) {
subType += " GUID Partition Table";
subType += "GUID Partition Table";
} else {
subType += " Invalid partition table type";
subType += "Invalid partition table type";
}
subType += "\n";
return subType;
}
/**
* Process the File path sub type.
* Process the File path subtype.
*
* @param path
* @param offset
* @return file path info.
*/
private String filePathSubType(final byte[] path, final int offset) {
subType = "File Path = ";
subType = " Sub Type = File Path\n";
subType += " File Path = ";
byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(path, 2 + offset, lengthBytes, 0, UefiConstants.SIZE_2);
int subTypeLength = HexUtils.leReverseInt(lengthBytes);
@ -307,11 +326,12 @@ public class UefiDevicePath {
0, subTypeLength);
byte[] fileName = convertChar16tobyteArray(filePath);
subType += new String(fileName, StandardCharsets.UTF_8);
subType += "\n";
return subType;
}
/**
* Process a vendor sub-type on a Media Type.
* Process a vendor subtype on a Media Type.
* Length of this structure in bytes. Length is 20 + n bytes
* Vendor-assigned GUID that defines the data that follows.
* Vendor-defined variable size data.
@ -321,7 +341,8 @@ public class UefiDevicePath {
* @return vendor device info.
*/
private String vendorSubType(final byte[] path, final int offset) {
subType = "Vendor Subtype GUID = ";
subType = " Sub Type = Vendor\n";
subType += " Vendor Subtype GUID = ";
byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(path, UefiConstants.OFFSET_2 + offset, lengthBytes,
0, UefiConstants.SIZE_2);
@ -337,8 +358,9 @@ public class UefiDevicePath {
+ offset, vendorData, 0, subTypeLength - UefiConstants.SIZE_16);
subType += " : Vendor Data = " + HexUtils.byteArrayToHexString(vendorData);
} else {
subType += " : No Vendor Data pesent";
subType += " : No Vendor Data present";
}
subType += "\n";
return subType;
}
@ -351,8 +373,8 @@ public class UefiDevicePath {
* @return USB device info.
*/
private String usbSubType(final byte[] path, final int offset) {
subType = " USB ";
subType += " port = " + Integer.valueOf(path[offset + UefiConstants.OFFSET_4]);
subType = " Sub Type = USB\n";
subType += " port = " + Integer.valueOf(path[offset + UefiConstants.OFFSET_4]);
subType += " interface = " + Integer.valueOf(path[offset + UefiConstants.OFFSET_5]);
byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(path, UefiConstants.OFFSET_2 + offset, lengthBytes,
@ -361,6 +383,7 @@ public class UefiDevicePath {
byte[] usbData = new byte[subTypeLength];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, usbData,
0, subTypeLength);
subType += "\n";
// Todo add further USB processing ...
return subType;
}
@ -377,7 +400,8 @@ public class UefiDevicePath {
* @return NVM device info.
*/
private String nvmSubType(final byte[] path, final int offset) {
subType = "NVM Express Namespace = ";
subType = " Sub Type = NVM\n";
subType += " NVM Express Namespace = ";
byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(path, UefiConstants.OFFSET_2 + offset, lengthBytes,
0, UefiConstants.SIZE_2);
@ -386,6 +410,7 @@ public class UefiDevicePath {
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, nvmData,
0, subTypeLength);
subType += HexUtils.byteArrayToHexString(nvmData);
subType += "\n";
return subType;
}
@ -400,7 +425,8 @@ public class UefiDevicePath {
* @return String that represents the UEFI defined BIOS Device Type.
*/
private String biosDevicePath(final byte[] path, final int offset) {
subType = "Legacy BIOS : Type = ";
subType = " Sub Type = Bios Device Path\n";
subType += " Legacy BIOS : Type = ";
Byte pathType = Byte.valueOf(path[offset + 1]);
switch (pathType.intValue()) {
case UefiConstants.DEVPATH_BIOS_RESERVED:
@ -432,6 +458,7 @@ public class UefiDevicePath {
subType += "Unknown";
break;
}
subType += "\n";
return subType;
}
@ -446,12 +473,13 @@ public class UefiDevicePath {
* @return String that represents the PIWG Firmware Volume Path
*/
private String piwgFirmVolFile(final byte[] path, final int offset) {
subType = "PIWG Firmware File ";
subType = " Sub Type = PIWG Firmware Volume File\n";
byte[] guidData = new byte[UefiConstants.SIZE_16];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, guidData,
0, UefiConstants.SIZE_16);
UefiGuid guid = new UefiGuid(guidData);
subType += guid.toString();
subType += "\n";
return subType;
}
@ -466,12 +494,13 @@ public class UefiDevicePath {
* @return String that represents the PIWG Firmware Volume Path
*/
private String piwgFirmVolPath(final byte[] path, final int offset) {
subType = "PIWG Firmware Volume ";
subType = " Sub Type = PIWG Firmware Volume Path\n";
byte[] guidData = new byte[UefiConstants.SIZE_16];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, guidData,
0, UefiConstants.SIZE_16);
UefiGuid guid = new UefiGuid(guidData);
subType += guid.toString();
subType += "\n";
return subType;
}

View File

@ -28,20 +28,20 @@ public class UefiGuid {
*/
private static final int UUID_EPOCH_DIVISOR = 10000;
/**
* Filesystem path of vendor-table.json
* Filesystem path of vendor-table.json.
*/
private static final Path JSON_PATH = FileSystems.getDefault().getPath("/etc",
"hirs", "aca", "default-properties", "vendor-table.json");
/**
* Name of vendor-table file in code
* Name of vendor-table file in code.
*/
private static final String JSON_FILENAME = "vendor-table.json";
/**
* Reference to the vendor-table json object
* Reference to the vendor-table json object.
*/
private JsonObject uefiVendorRef;
/**
* Track status of vendor-table.json
* Track status of vendor-table.json.
*/
@Getter
private String vendorTableFileStatus = FILESTATUS_NOT_ACCESSIBLE;
@ -77,13 +77,12 @@ public class UefiGuid {
uefiVendorRef = JsonUtils.getSpecificJsonObject(vendorPathString,
"VendorTable");
if(!isVendorTableReferenceHandleEmpty()) {
if (!isVendorTableReferenceHandleEmpty()) {
vendorTableFileStatus = FILESTATUS_FROM_FILESYSTEM;
}
else {
} else {
// could not access vendor-table.json from filesystem, so attempt to access from code
uefiVendorRef = JsonUtils.getSpecificJsonObject(JSON_FILENAME, "VendorTable");
if(!isVendorTableReferenceHandleEmpty()) {
if (!isVendorTableReferenceHandleEmpty()) {
vendorTableFileStatus = FILESTATUS_FROM_CODE;
}
}

View File

@ -38,18 +38,18 @@ public class UefiSecureBoot {
}
/**
* Provides a human readable value for the Secure Boot variable.
* Provides a human-readable value for the Secure Boot variable.
*
* @return Human readable description.
*/
public String toString() {
if (!berror) {
if (secureBootVariable == 1) {
info += " Secure Boot is enabled ";
info += " Secure Boot is enabled ";
} else if (secureBootVariable == 0) {
info += " Secure Boot is NOT enabled ";
info += " Secure Boot is NOT enabled ";
} else {
info += " Unkown State: Secure Variable is undefined ";
info += " Unknown State: Secure Variable is undefined ";
}
}
return info;

View File

@ -10,9 +10,15 @@ import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
/**
* Class for processing the contents of a Secure Boot PK, KEK, DB or DBX contents.
* used for EFIVariables associated with Secure Boot
* as defined by Section 32.4.1 Signature Database from the UEFI 2.8 specification
* Class for processing either
* 1) the contents of a Secure Boot PK, KEK, DB or DBX contents,
* used for EFIVariables associated with Secure Boot,
* as defined by Section 32.4.1 Signature Database from the UEFI 2.8 specification
* 2) the contents of an SPDM devdb,
* used for SPDM Device Policy or Device Authority, whose data is an EFIVariable
* EFIVariable data for SPDM Device Policy: UefiSignatureList
* EFIVariable data for SPDM Device: UefiSignatureData only
* as defined by PFP v1.06 Rev52, Section 10.4
* <p>
* typedef struct _EFI_SIGNATURE_DATA {
* EFI_GUID SignatureOwner;
@ -67,8 +73,8 @@ public class UefiSignatureData {
*
* @param inputStream The Signature data.
* @param sigType UEFI defined signature type.
* @throws java.io.IOException if there's an problem reading the input stream.
* @throws java.security.cert.CertificateException If there a problem parsing the X509 certificate.
* @throws java.io.IOException if there's a problem reading the input stream.
* @throws java.security.cert.CertificateException If there's a problem parsing the X509 certificate.
* @throws java.security.NoSuchAlgorithmException if there's a problem hashing the certificate.
*/
UefiSignatureData(final ByteArrayInputStream inputStream, final UefiGuid sigType)

View File

@ -12,12 +12,18 @@ import java.util.ArrayList;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_NOT_ACCESSIBLE;
/**
* Class for processing the contents of a Secure Boot DB or DBX contents.
* used for EFIVariables associated with Secure Boot
* as defined by Section 32.4.1 Signature Database from the UEFI 2.8 specification.
* Class for processing either
* 1) the contents of a Secure Boot PK, KEK, DB or DBX contents,
* used for EFIVariables associated with Secure Boot,
* as defined by Section 32.4.1 Signature Database from the UEFI 2.8 specification
* 2) the contents of an SPDM devdb,
* used for SPDM Device Policy, whose data is an EFIVariable
* as defined by PFP v1.06 Rev52, Section 10.4
* <p>
* An EFI Signature List is actual a list of Certificates used to verify a Signature.
* This is mainly found in PCR[7] UEFI variables for the Secure Boot PK, KEK, Db and DBx variables.
* An EFI Signature List is actually a list of Certificates used to verify a Signature.
* This is mainly found in PCR[7] UEFI variables for either the
* Secure Boot PK, KEK, Db and DBx variables
* or the SPDM devdb variable (under EV_EFI_SPDM_DEVICE_POLICY).
* <p>
* typedef struct _EFI_SIGNATURE_LIST {
* EFI_GUID SignatureType;
@ -27,6 +33,35 @@ import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_NOT_ACCESSIB
* // UINT8 SignatureHeader[SignatureHeaderSize];
* // EFI_SIGNATURE_DATA Signatures[...][SignatureSize];
* } EFI_SIGNATURE_LIST;
*
* SignatureListHeader (contents common to any Signature Type)
* - SignatureType
* - SignatureListSize
* - SignatureHeaderSize
* - SignatureSize
* SignatureHeader (contents depend on the SignatureType)
* - The format of this header is specified by the SignatureType (SHA256, X509).
* Signatures[][] is an array of signatures.
* - Each signature is SignatureSize bytes in length.
* - The format of the signature is defined by SignatureType (SHA256, X509).
*
* / |-------------------------| ------- SignatureType
* / | Signature List Header | SignatureListSize
* |---------------------| / |-------------------------|\ SignatureHeaderSize
* | Signature List #0 | / | Signature Header | \ _____ SignatureSize
* | | / |-------------------------|
* |---------------------| / | Signature #0 |
* | Signature List #1 | / |-------------------------|
* |---------------------|/ | Signature #1 | --> each Signature is
* | Signature List #2 | |-------------------------| 1 UefiSignatureData
* | | | Signature #2 | (1 cert or hash)
* | | |-------------------------|
* |---------------------| | ... |
* \ | |
* \ |-------------------------|
* \ | Signature #n |
* \ |-------------------------|
*
*/
public class UefiSignatureList {
/**
@ -58,7 +93,7 @@ public class UefiSignatureList {
/**
* Current status of Signature List data.
*/
private String dataStatus = "Signature List data validity is undetermined yet";
private String dataInvalidStatus = "Signature List data validity is undetermined yet";
/**
* Array List of Signature found in the list.
*/
@ -72,42 +107,42 @@ public class UefiSignatureList {
*/
private UefiGuid signatureType = null;
/**
* Track status of vendor-table.json
* Track status of vendor-table.json.
*/
@Getter
private String vendorTableFileStatus = FILESTATUS_NOT_ACCESSIBLE;
/**
* UefiSignatureList constructor.
*
* @param list byte array holding the signature list.
* @throws java.security.cert.CertificateException If there a problem parsing the X509 certificate.
* @throws java.security.NoSuchAlgorithmException if there's a problem hashing the certificate.
* @throws java.io.IOException If there's a problem parsing the signature data.
*/
UefiSignatureList(final byte[] list)
throws CertificateException, NoSuchAlgorithmException, IOException {
byte[] guid = new byte[UefiConstants.SIZE_16];
System.arraycopy(list, 0, guid, 0, UefiConstants.SIZE_16);
signatureType = new UefiGuid(guid);
vendorTableFileStatus = signatureType.getVendorTableFileStatus();
byte[] lSize = new byte[UefiConstants.SIZE_4];
System.arraycopy(list, UefiConstants.OFFSET_16, lSize, 0, UefiConstants.SIZE_4);
listSize = HexUtils.leReverseInt(lSize);
byte[] hSize = new byte[UefiConstants.SIZE_4];
System.arraycopy(list, UefiConstants.OFFSET_20, hSize, 0, UefiConstants.SIZE_4);
byte[] sSize = new byte[UefiConstants.SIZE_4];
System.arraycopy(list, UefiConstants.OFFSET_24, sSize, 0, UefiConstants.SIZE_4);
signatureSize = HexUtils.leReverseInt(sSize);
sigData = new byte[signatureSize];
System.arraycopy(list, UefiConstants.OFFSET_28, sigData, 0, signatureSize);
processSignatureList(sigData);
}
// /**
// * UefiSignatureList constructor.
// *
// * @param list byte array holding the signature list.
// * @throws java.security.cert.CertificateException If there a problem parsing the X509 certificate.
// * @throws java.security.NoSuchAlgorithmException if there's a problem hashing the certificate.
// * @throws java.io.IOException If there's a problem parsing the signature data.
// */
// UefiSignatureList(final byte[] list)
// throws CertificateException, NoSuchAlgorithmException, IOException {
//
// byte[] guid = new byte[UefiConstants.SIZE_16];
// System.arraycopy(list, 0, guid, 0, UefiConstants.SIZE_16);
// signatureType = new UefiGuid(guid);
// vendorTableFileStatus = signatureType.getVendorTableFileStatus();
//
// byte[] lSize = new byte[UefiConstants.SIZE_4];
// System.arraycopy(list, UefiConstants.OFFSET_16, lSize, 0, UefiConstants.SIZE_4);
// listSize = HexUtils.leReverseInt(lSize);
//
// byte[] hSize = new byte[UefiConstants.SIZE_4];
// System.arraycopy(list, UefiConstants.OFFSET_20, hSize, 0, UefiConstants.SIZE_4);
//
// byte[] sSize = new byte[UefiConstants.SIZE_4];
// System.arraycopy(list, UefiConstants.OFFSET_24, sSize, 0, UefiConstants.SIZE_4);
// signatureSize = HexUtils.leReverseInt(sSize);
//
// sigData = new byte[signatureSize];
// System.arraycopy(list, UefiConstants.OFFSET_28, sigData, 0, signatureSize);
// processSignatureList(sigData);
// }
/**
* EFI Signature list constructor.
@ -125,10 +160,9 @@ public class UefiSignatureList {
vendorTableFileStatus = signatureType.getVendorTableFileStatus();
// if signatureType is invalid, don't even process any of the data
// however, if signatureTYpe is valid, but some of the data later on is invalid, that will
// however, if signatureType is valid, but some of the data later on is invalid, that will
// be caught when UefiSignatureData is processed
if (!isValidSigListGUID(signatureType)) {
//processSignatureData(lists);
signatureTypeValid = false;
} else { // valid SigData Processing
signatureTypeValid = true;
@ -164,7 +198,7 @@ public class UefiSignatureList {
UefiSignatureData tmpSigData = new UefiSignatureData(efiSigDataIS, signatureType);
if (!tmpSigData.isValid()) {
dataValid = false;
dataStatus = tmpSigData.getStatus();
dataInvalidStatus = tmpSigData.getStatus();
break;
}
sigList.add(tmpSigData);
@ -172,28 +206,6 @@ public class UefiSignatureList {
}
}
/**
* Method for processing a set of EFI SignatureList(s).
*
* @param sigDataIS Byte array holding one or more SignatureLists.
* @throws java.security.cert.CertificateException If there's a problem parsing the X509 certificate.
* @throws java.security.NoSuchAlgorithmException if there's a problem hashing the certificate.
* @throws java.io.IOException If there's a problem parsing the signature data.
*/
private void processSignatureData(final ByteArrayInputStream sigDataIS)
throws CertificateException, NoSuchAlgorithmException, IOException {
while (sigDataIS.available() > 0) {
UefiSignatureData tmpigData = new UefiSignatureData(sigDataIS, signatureType);
if (!tmpigData.isValid()) {
dataValid = false;
dataStatus = tmpigData.getStatus();
break;
}
sigList.add(tmpigData);
numberOfCerts++;
}
}
/**
* Checks to see if GUID is listed on page 1729 of UEFI spec version 2.8.
*
@ -223,19 +235,21 @@ public class UefiSignatureList {
StringBuilder sigInfo = new StringBuilder();
if (!signatureTypeValid) {
sigInfo.append(" *** Unknown UEFI Signature Type encountered:\n" +
" " + signatureType.toString() + "\n");
}
else {
sigInfo.append(" *** Unknown UEFI Signature Type encountered:\n"
+ " " + signatureType.toString() + "\n");
} else {
sigInfo.append(" UEFI Signature List Type = " + signatureType.toString() + "\n");
sigInfo.append(" Number of Certs or Hashes in UEFI Signature List = " + numberOfCerts + "\n");
int certOrHashCnt = 1;
for (int i = 0; i < sigList.size(); i++) {
sigInfo.append(" Cert or Hash # " + certOrHashCnt++ + " of "
+ numberOfCerts + ": ------------------\n");
UefiSignatureData certData = sigList.get(i);
sigInfo.append(certData.toString());
}
if (!dataValid) {
sigInfo.append(" *** Invalid UEFI Signature data encountered: " + dataStatus + "\n");
sigInfo.append(" *** Invalid UEFI Signature data encountered: " + dataInvalidStatus + "\n");
}
}
return sigInfo.toString();

View File

@ -42,11 +42,11 @@ public class UefiVariable {
@Getter
private String efiVarName = "";
/**
* Encountered invalid UEFI Signature List
* Encountered invalid UEFI Signature List.
*/
private boolean invalidSignatureListEncountered = false;
/**
* Invalid UEFI Signature List
* Invalid UEFI Signature List.
*/
private String invalidSignatureListStatus = "";
/**
@ -75,6 +75,11 @@ public class UefiVariable {
@Getter
private String vendorTableFileStatus = FILESTATUS_FROM_FILESYSTEM;
/**
* Human-readable description of the data within the SPDM devdc (to be updated with more test data).
*/
private String spdmDevdcInfo = "";
/**
* EFIVariable constructor.
* The UEFI_VARIABLE_DATA contains a "VariableName" field which is used to determine
@ -128,10 +133,16 @@ public class UefiVariable {
case "dbx":
processSigList(uefiVariableData);
break;
case "devdb": // Update when test patterns exist
break; // PFP v1.06 Rev 52, Sec 3.3.4.8
case "devdb":
processSigList(uefiVariableData);
break; // Update when test patterns exist
// PFP v1.06 Rev 52, Sec 3.3.4.8
// EV_EFI_SPDM_DEVICE_POLICY: EFI_SIGNATURE_LIST
// EV_EFI_SPDM_DEVICE_AUTHORITY: EFI_SIGNATURE_DATA
// for now, differentiate them by using devdc for ..DEVICE_AUTHORITY
case "devdc":
processSigDataX509(uefiVariableData);
break;
case "Boot00":
bootv = new UefiBootVariable(uefiVariableData);
break;
@ -173,13 +184,13 @@ public class UefiVariable {
// the if statement is executed
// [new event file status = list.getVendorTableFileStatus()]
// (ie. if the new file status is not-accessible or from-code, then want to update)
if((vendorTableFileStatus != FILESTATUS_NOT_ACCESSIBLE) &&
(list.getVendorTableFileStatus() != FILESTATUS_FROM_FILESYSTEM)) {
if ((vendorTableFileStatus != FILESTATUS_NOT_ACCESSIBLE)
&& (list.getVendorTableFileStatus() != FILESTATUS_FROM_FILESYSTEM)) {
vendorTableFileStatus = list.getVendorTableFileStatus();
}
// efiVariableSigListContents += list.toString();
if(!list.isSignatureTypeValid()) {
if (!list.isSignatureTypeValid()) {
invalidSignatureListEncountered = true;
invalidSignatureListStatus = list.toString();
break;
@ -188,18 +199,64 @@ public class UefiVariable {
}
}
/**
* Method for processing the data in an EFI Signature Data, where the data is known to be an X509 cert.
*
* @param efiSigData Byte array holding the SignatureData data
* @throws java.security.cert.CertificateException If there's a problem parsing the X509 certificate.
* @throws java.security.NoSuchAlgorithmException if there's a problem hashing the certificate.
* @throws java.io.IOException If there's a problem parsing the signature data.
*/
private void processSigDataX509(final byte[] efiSigData)
throws CertificateException, NoSuchAlgorithmException, IOException {
ByteArrayInputStream efiSigDataIS = new ByteArrayInputStream(efiSigData);
ArrayList<UefiSignatureData> sigList = new ArrayList<UefiSignatureData>();
spdmDevdcInfo += "";
// for now, hard-code the signature type for X509
// in future with more test data, update this (potentially need to look at previous SPDM event)
byte[] guid = HexUtils.hexStringToByteArray("A159C0A5E494A74A87B5AB155C2BF072");
UefiGuid signatureType = new UefiGuid(guid);
int numberOfCerts = 0;
boolean dataValid = true;
String dataInvalidStatus = "Signature data validity is undetermined yet";
while (efiSigDataIS.available() > 0) {
UefiSignatureData tmpSigData = new UefiSignatureData(efiSigDataIS, signatureType);
if (!tmpSigData.isValid()) {
dataValid = false;
dataInvalidStatus = tmpSigData.getStatus();
break;
}
sigList.add(tmpSigData);
numberOfCerts++;
}
spdmDevdcInfo += " Number of X509 Certs in UEFI Signature Data = " + numberOfCerts + "\n";
int certCnt = 0;
for (int i = 0; i < sigList.size(); i++) {
certCnt++;
spdmDevdcInfo += " Cert # " + certCnt + " of " + numberOfCerts + ": ------------------\n";
UefiSignatureData certData = sigList.get(i);
spdmDevdcInfo += certData.toString();
}
if (!dataValid) {
spdmDevdcInfo += " *** Invalid UEFI Signature data encountered: " + dataInvalidStatus + "\n";
}
}
/**
* Print out all the interesting characteristics available on this UEFI Variable.
*
* @return human readable description of the UEFi variable.
* @return human-readable description of the UEFi variable.
*/
public String toString() {
StringBuilder efiVariable = new StringBuilder();
efiVariable.append("UEFI Variable Name: " + efiVarName + "\n");
efiVariable.append("UEFI Variable GUID: " + uefiVarGuid.toString() + "\n");
efiVariable.append(" UEFI Variable Name: " + efiVarName + "\n");
efiVariable.append(" UEFI Variable GUID: " + uefiVarGuid.toString() + "\n");
if (efiVarName != "") {
efiVariable.append("UEFI Variable Contents => " + "\n");
efiVariable.append(" UEFI Variable Contents => " + "\n");
}
String tmpName = "";
if (efiVarName.contains("Boot00")) {
@ -216,11 +273,9 @@ public class UefiVariable {
case "KEK":
case "db":
case "dbx":
break;
case "devdb": // SPDM_DEVICE_POLICY and SPDM_DEVICE_AUTHORITY
// (update when test patterns exist)
efiVariable.append(" EV_EFI_SPDM_DEVICE_POLICY and EV_EFI_SPDM_DEVICE_AUTHORITY: " +
"To be processed once more test patterns exist");
case "devdc": // for now use devdb and devdc respectively
// (update when more test patterns exist)
break;
case "Boot00":
efiVariable.append(bootv.toString());
@ -233,38 +288,43 @@ public class UefiVariable {
break;
default:
if (!tmpName.isEmpty()) {
efiVariable.append(String.format("Data not provided for "
efiVariable.append(String.format(" Data not provided for "
+ "UEFI variable named %s ", tmpName));
} else {
efiVariable.append("Data not provided ");
efiVariable.append(" Data not provided ");
}
}
// Signature List output (if there are any Signature Lists)
if (certSuperList.size() > 0){
if (certSuperList.size() > 0) {
efiVariable.append("Number of UEFI Signature Lists = " + certSuperList.size() + "\n");
int certSuperListCnt = 1;
for (UefiSignatureList uefiSigList : certSuperList) {
efiVariable.append("UEFI Signature List # " + certSuperListCnt++ + " of "
+ certSuperList.size() + ": ------------------\n");
efiVariable.append(uefiSigList.toString());
}
}
int certSuperListCnt = 1;
for (UefiSignatureList uefiSigList : certSuperList) {
efiVariable.append("UEFI Signature List # " + certSuperListCnt++ + " of " +
certSuperList.size() + ":\n");
efiVariable.append(uefiSigList.toString());
}
if(invalidSignatureListEncountered) {
if (invalidSignatureListEncountered) {
efiVariable.append(invalidSignatureListStatus);
efiVariable.append("*** Encountered invalid Signature Type - " +
"Stopped processing of this event data\n");
efiVariable.append("*** Encountered invalid Signature Type - "
+ "Stopped processing of this event data\n");
}
// Signature Data output (if there is a Signature Data)
if (!spdmDevdcInfo.isEmpty()) {
efiVariable.append(spdmDevdcInfo);
}
return efiVariable.toString();
}
/**
* Retrieves human readable description from a Certificate.
* Retrieves human-readable description from a Certificate.
*
* @param data byte[] holding the certificate.
* @param offset offset to start of the certificate within the byte array.
* @return human readable description of a certificate.
* @return human-readable description of a certificate.
*/
public String printCert(final byte[] data, final int offset) {
String certInfo = "";

View File

@ -1,5 +1,9 @@
package hirs.tcg_eventlog;
import hirs.utils.HexUtils;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
@ -12,10 +16,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
import hirs.utils.HexUtils;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_FROM_CODE;
import static hirs.utils.tpm.eventlog.uefi.UefiConstants.FILESTATUS_NOT_ACCESSIBLE;