Finished issue. Ready for PR

This commit is contained in:
TheSilentCoder 2024-10-15 15:14:59 -04:00
parent 337a626335
commit 0a5de5316e
17 changed files with 445 additions and 375 deletions

View File

@ -19,7 +19,7 @@ import java.util.Map;
public class SwidResource { public class SwidResource {
@Getter @Getter
private final boolean validFileSize = false; private static final boolean VALID_FILE_SIZE = false;
@Getter @Getter
@Setter @Setter

View File

@ -8,7 +8,7 @@ import javax.xml.namespace.QName;
* class. It is expected that member properties of this class will expand as * class. It is expected that member properties of this class will expand as
* more functionality is added to SwidTagGateway. * more functionality is added to SwidTagGateway.
*/ */
public class SwidTagConstants { public final class SwidTagConstants {
public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks"; //"/opt/hirs/rimtool/keystore.jks"; public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks"; //"/opt/hirs/rimtool/keystore.jks";
public static final String DEFAULT_KEYSTORE_PASSWORD = "password"; public static final String DEFAULT_KEYSTORE_PASSWORD = "password";

View File

@ -13,18 +13,18 @@ import java.io.IOException;
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER. * Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER.
* DEVICE_SECURITY_EVENT_DATA_HEADER contains the measurement(s) and hash algorithm identifier * DEVICE_SECURITY_EVENT_DATA_HEADER contains the measurement(s) and hash algorithm identifier
* returned by the SPDM "GET_MEASUREMENTS" function. * returned by the SPDM "GET_MEASUREMENTS" function.
* * <p>
* HEADERS defined by PFP v1.06 Rev 52: * HEADERS defined by PFP v1.06 Rev 52:
* <p> * <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER { * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER {
* UINT8 Signature[16]; * UINT8 Signature[16];
* UINT16 Version; * UINT16 Version;
* UINT16 Length; * UINT16 Length;
* UINT32 SpdmHashAlg; * UINT32 SpdmHashAlg;
* UINT32 DeviceType; * UINT32 DeviceType;
* SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock; * SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock;
* UINT64 DevicePathLength; * UINT64 DevicePathLength;
* UNIT8 DevicePath[DevicePathLength] * UNIT8 DevicePath[DevicePathLength]
* } DEVICE_SECURITY_EVENT_DATA_HEADER; * } DEVICE_SECURITY_EVENT_DATA_HEADER;
* <p> * <p>
* Assumption: there is only 1 SpdmMeasurementBlock per event. Need more test patterns to verify. * Assumption: there is only 1 SpdmMeasurementBlock per event. Need more test patterns to verify.
@ -62,8 +62,9 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
super(dsedBytes); super(dsedBytes);
final int dsedBytesSrcIndex1 = 18;
byte[] lengthBytes = new byte[UefiConstants.SIZE_2]; byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(dsedBytes, 18, lengthBytes, 0, System.arraycopy(dsedBytes, dsedBytesSrcIndex1, lengthBytes, 0,
UefiConstants.SIZE_2); UefiConstants.SIZE_2);
length = HexUtils.leReverseInt(lengthBytes); length = HexUtils.leReverseInt(lengthBytes);
@ -72,18 +73,22 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
UefiConstants.SIZE_4); UefiConstants.SIZE_4);
spdmHashAlgo = HexUtils.leReverseInt(spdmHashAlgoBytes); spdmHashAlgo = HexUtils.leReverseInt(spdmHashAlgoBytes);
extractDeviceType(dsedBytes, 24); final int dsedBytesStartByte = 24;
extractDeviceType(dsedBytes, dsedBytesStartByte);
// get the size of the SPDM Measurement Block // get the size of the SPDM Measurement Block
final int dsedBytesSrcIndex2 = 30;
byte[] sizeOfSpdmMeasBlockBytes = new byte[UefiConstants.SIZE_2]; byte[] sizeOfSpdmMeasBlockBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(dsedBytes, 30, sizeOfSpdmMeasBlockBytes, 0, System.arraycopy(dsedBytes, dsedBytesSrcIndex2, sizeOfSpdmMeasBlockBytes, 0,
UefiConstants.SIZE_2); UefiConstants.SIZE_2);
int sizeOfSpdmMeas = HexUtils.leReverseInt(sizeOfSpdmMeasBlockBytes); final int sizeOfSpdmMeas = HexUtils.leReverseInt(sizeOfSpdmMeasBlockBytes);
int sizeOfSpdmMeasBlock = sizeOfSpdmMeas + 4; // header is 4 bytes final int offSetBytesForSpdm = 4;
final int sizeOfSpdmMeasBlock = sizeOfSpdmMeas + offSetBytesForSpdm; // header is 4 bytes
// extract the bytes that comprise the SPDM Measurement Block // extract the bytes that comprise the SPDM Measurement Block
final int dsedBytesSrcIndex3 = 28;
byte[] spdmMeasBlockBytes = new byte[sizeOfSpdmMeasBlock]; byte[] spdmMeasBlockBytes = new byte[sizeOfSpdmMeasBlock];
System.arraycopy(dsedBytes, 28, spdmMeasBlockBytes, 0, System.arraycopy(dsedBytes, dsedBytesSrcIndex3, spdmMeasBlockBytes, 0,
sizeOfSpdmMeasBlock); sizeOfSpdmMeasBlock);
ByteArrayInputStream spdmMeasurementBlockData = ByteArrayInputStream spdmMeasurementBlockData =
@ -96,7 +101,8 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
spdmMeasurementBlockInfo = " Error reading SPDM Measurement Block"; spdmMeasurementBlockInfo = " Error reading SPDM Measurement Block";
} }
int devPathLenStartByte = 28 + sizeOfSpdmMeasBlock; final int offSetBytesForDevPath = 28;
final int devPathLenStartByte = offSetBytesForDevPath + sizeOfSpdmMeasBlock;
extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte); extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte);
} }

View File

@ -7,26 +7,52 @@ import lombok.Getter;
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER2. * Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER2.
* DEVICE_SECURITY_EVENT_DATA_HEADER2 contains the measurement(s) and hash algorithm identifier * DEVICE_SECURITY_EVENT_DATA_HEADER2 contains the measurement(s) and hash algorithm identifier
* returned by the SPDM "GET_MEASUREMENTS" function. * returned by the SPDM "GET_MEASUREMENTS" function.
* * <p>
* HEADERS defined by PFP v1.06 Rev 52: * HEADERS defined by PFP v1.06 Rev 52:
* <p> * <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER2 { * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER2 {
* UINT8 Signature[16]; * UINT8 Signature[16];
* UINT16 Version; * UINT16 Version;
* UINT8 AuthState; * UINT8 AuthState;
* UINT8 Reserved * UINT8 Reserved
* UINT32 Length; * UINT32 Length;
* UINT32 DeviceType; * UINT32 DeviceType;
* UINT32 SubHeaderType; * UINT32 SubHeaderType;
* UINT32 SubHeaderLength; * UINT32 SubHeaderLength;
* UINT64 SubHeaderUID; * UINT64 SubHeaderUID;
* UINT64 DevicePathLength; * UINT64 DevicePathLength;
* UNIT8 DevicePath[DevicePathLength] * UNIT8 DevicePath[DevicePathLength]
* } DEVICE_SECURITY_EVENT_DATA_HEADER2; * } DEVICE_SECURITY_EVENT_DATA_HEADER2;
* <p> * <p>
*/ */
public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader { public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
/**
* 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 the UEFI device signature variable.
*/
public static final int AUTH_NO_AUTHORITY = 1;
/**
* Auth state - digital signature of the measurement data is valid, but the reported device capabilities,
* negotiated parameters or certificate chains were not validated by a transcript.
*/
public static final int AUTH_NO_BINDING = 2;
/**
* Auth state - data has no digital signature.
*/
public static final int AUTH_FAIL_NO_SIG = 3;
/**
* Auth state - data is invalid.
*/
public static final int AUTH_FAIL_INVALID = 4;
/**
* Auth state - device is not an SPDM-capable device.
*/
public static final int AUTH_NO_SPDM = 0xFF;
/** /**
* Event auth state. * Event auth state.
*/ */
@ -55,33 +81,6 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
@Getter @Getter
private String subHeaderUid = ""; private String subHeaderUid = "";
/**
* 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 the UEFI device signature variable.
*/
public static final int AUTH_NO_AUTHORITY = 1;
/**
* Auth state - digital signature of the measurement data is valid, but the reported device capabilities,
* negotiated parameters or certificate chains were not validated by a transcript.
*/
public static final int AUTH_NO_BINDING = 2;
/**
* Auth state - data has no digital signature.
*/
public static final int AUTH_FAIL_NO_SIG = 3;
/**
* Auth state - data is invalid.
*/
public static final int AUTH_FAIL_INVALID = 4;
/**
* Auth state - device is not an SPDM-capable device.
*/
public static final int AUTH_NO_SPDM = 0xFF;
/** /**
* DeviceSecurityEventDataHeader2 Constructor. * DeviceSecurityEventDataHeader2 Constructor.
* *
@ -91,33 +90,43 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
super(dsedBytes); super(dsedBytes);
final int dsedBytesSrcIndex = 18;
byte[] authStateBytes = new byte[1]; byte[] authStateBytes = new byte[1];
System.arraycopy(dsedBytes, 18, authStateBytes, 0, 1); System.arraycopy(dsedBytes, dsedBytesSrcIndex, authStateBytes, 0, 1);
authState = HexUtils.leReverseInt(authStateBytes); authState = HexUtils.leReverseInt(authStateBytes);
// byte[] reserved[Bytes]: 1 byte // byte[] reserved[Bytes]: 1 byte
byte[] lengthBytes = new byte[4]; final int dsedBytesSrcIndex2 = 20;
System.arraycopy(dsedBytes, 20, lengthBytes, 0, 4); final int lengthBytesSize = 4;
byte[] lengthBytes = new byte[lengthBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex2, lengthBytes, 0, lengthBytesSize);
length = HexUtils.leReverseInt(lengthBytes); length = HexUtils.leReverseInt(lengthBytes);
extractDeviceType(dsedBytes, 24); final int dsedBytesStartByte1 = 24;
extractDeviceType(dsedBytes, dsedBytesStartByte1);
byte[] subHeaderTypeBytes = new byte[4]; final int dsedBytesSrcIndex3 = 28;
System.arraycopy(dsedBytes, 28, subHeaderTypeBytes, 0, 4); final int subHeaderTypeBytesSize = 4;
byte[] subHeaderTypeBytes = new byte[subHeaderTypeBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex3, subHeaderTypeBytes, 0, subHeaderTypeBytesSize);
subHeaderType = HexUtils.leReverseInt(subHeaderTypeBytes); subHeaderType = HexUtils.leReverseInt(subHeaderTypeBytes);
byte[] subHeaderLengthBytes = new byte[4]; final int dsedBytesSrcIndex4 = 32;
System.arraycopy(dsedBytes, 32, subHeaderLengthBytes, 0, 4); final int subHeaderLengthBytesSize = 4;
byte[] subHeaderLengthBytes = new byte[subHeaderLengthBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex4, subHeaderLengthBytes, 0, subHeaderLengthBytesSize);
subHeaderLength = HexUtils.leReverseInt(subHeaderLengthBytes); subHeaderLength = HexUtils.leReverseInt(subHeaderLengthBytes);
byte[] subHeaderUidBytes = new byte[8]; final int dsedBytesSrcIndex5 = 36;
System.arraycopy(dsedBytes, 36, subHeaderUidBytes, 0, 8); final int subHeaderUidBytesSize = 8;
byte[] subHeaderUidBytes = new byte[subHeaderUidBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex5, subHeaderUidBytes, 0, subHeaderUidBytesSize);
subHeaderUidBytes = HexUtils.leReverseByte(subHeaderUidBytes); subHeaderUidBytes = HexUtils.leReverseByte(subHeaderUidBytes);
subHeaderUid = HexUtils.byteArrayToHexString(subHeaderUidBytes); subHeaderUid = HexUtils.byteArrayToHexString(subHeaderUidBytes);
int devPathLenStartByte = 44; final int dsedBytesStartByte2 = 44;
extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte); extractDevicePathAndFinalSize(dsedBytes, dsedBytesStartByte2);
} }
/** /**
@ -139,22 +148,14 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
* @return a description of the auth state. * @return a description of the auth state.
*/ */
public String getAuthStateString() { public String getAuthStateString() {
return switch (authState) {
switch (authState) { case AUTH_SUCCESS -> ("AUTH_SUCCESS");
case AUTH_SUCCESS: case AUTH_NO_AUTHORITY -> ("AUTH_NO_AUTHORITY");
return ("AUTH_SUCCESS"); case AUTH_NO_BINDING -> ("AUTH_NO_BINDING");
case AUTH_NO_AUTHORITY: case AUTH_FAIL_NO_SIG -> ("AUTH_FAIL_NO_SIG");
return ("AUTH_NO_AUTHORITY"); case AUTH_FAIL_INVALID -> ("AUTH_FAIL_INVALID");
case AUTH_NO_BINDING: case AUTH_NO_SPDM -> ("AUTH_NO_SPDM");
return ("AUTH_NO_BINDING"); default -> ("Auth State unknown");
case AUTH_FAIL_NO_SIG: };
return ("AUTH_FAIL_NO_SIG");
case AUTH_FAIL_INVALID:
return ("AUTH_FAIL_INVALID");
case AUTH_NO_SPDM:
return ("AUTH_NO_SPDM");
default:
return ("Auth State unknown");
}
} }
} }

View File

@ -13,27 +13,27 @@ import static hirs.utils.PciIds.translateVendor;
* Class to process the DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT event per PFP. * Class to process the DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT event per PFP.
* <p> * <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT { * typedef struct tdDEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT {
* UINT16 Version; * UINT16 Version;
* UINT16 Length; * UINT16 Length;
* UINT16 VendorId; * UINT16 VendorId;
* UINT16 DeviceId; * UINT16 DeviceId;
* UINT16 RevisionId; * UINT16 RevisionId;
* UINT16 ClassCode[3]; * UINT16 ClassCode[3];
* UINT16 SubsystemVendorId; * UINT16 SubsystemVendorId;
* UINT16 SubsystemId; * UINT16 SubsystemId;
* <p> * <p>
* The following fields are defined by the PCI Express Base Specification rev4.0 v1.0. * The following fields are defined by the PCI Express Base Specification rev4.0 v1.0.
* VendorId * VendorId
* DeviceId * DeviceId
* RevisionId * RevisionId
* ClassCode * ClassCode
* SubsystemVendorId * SubsystemVendorId
* SubsystemId * SubsystemId
* Vendor id and device id are registered to specific manufacturers. * Vendor id and device id are registered to specific manufacturers.
* https://admin.pci-ids.ucw.cz/read/PC/ * https://admin.pci-ids.ucw.cz/read/PC/
* Ex. vendor id 8086 and device id 0b60: https://admin.pci-ids.ucw.cz/read/PC/8086/0b60 * Ex. vendor id 8086 and device id 0b60: https://admin.pci-ids.ucw.cz/read/PC/8086/0b60
* Class code can be looked up on the web. * Class code can be looked up on the web.
* https://admin.pci-ids.ucw.cz/read/PD/ * https://admin.pci-ids.ucw.cz/read/PD/
* The revision ID is controlled by the vendor and cannot be looked up. * The revision ID is controlled by the vendor and cannot be looked up.
*/ */
public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDeviceContext { public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDeviceContext {
@ -78,28 +78,36 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
super(dSEDpciContextBytes); super(dSEDpciContextBytes);
final int dSEDpciContextBytesSrcIndex1 = 4;
byte[] pciVendorIdBytes = new byte[2]; byte[] pciVendorIdBytes = new byte[2];
System.arraycopy(dSEDpciContextBytes, 4, pciVendorIdBytes, 0, 2); System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex1, pciVendorIdBytes, 0, 2);
vendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciVendorIdBytes)); vendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciVendorIdBytes));
final int dSEDpciContextBytesSrcIndex2 = 6;
byte[] pciDeviceIdBytes = new byte[2]; byte[] pciDeviceIdBytes = new byte[2];
System.arraycopy(dSEDpciContextBytes, 6, pciDeviceIdBytes, 0, 2); System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex2, pciDeviceIdBytes, 0, 2);
deviceId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciDeviceIdBytes)); deviceId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciDeviceIdBytes));
final int dSEDpciContextBytesSrcIndex3 = 8;
byte[] pciRevisionIdBytes = new byte[1]; byte[] pciRevisionIdBytes = new byte[1];
System.arraycopy(dSEDpciContextBytes, 8, pciRevisionIdBytes, 0, 1); System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex3, pciRevisionIdBytes, 0, 1);
revisionId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciRevisionIdBytes)); revisionId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciRevisionIdBytes));
byte[] pciClassCodeBytes = new byte[3]; final int dSEDpciContextBytesSrcIndex4 = 9;
System.arraycopy(dSEDpciContextBytes, 9, pciClassCodeBytes, 0, 3); final int pciClassCodeBytesSize = 3;
byte[] pciClassCodeBytes = new byte[pciClassCodeBytesSize];
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex4, pciClassCodeBytes, 0,
pciClassCodeBytesSize);
classCode = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciClassCodeBytes)); classCode = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciClassCodeBytes));
final int dSEDpciContextBytesSrcIndex5 = 12;
byte[] pciSubsystemVendorIdBytes = new byte[2]; byte[] pciSubsystemVendorIdBytes = new byte[2];
System.arraycopy(dSEDpciContextBytes, 12, pciSubsystemVendorIdBytes, 0, 2); System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex5, pciSubsystemVendorIdBytes, 0, 2);
subsystemVendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemVendorIdBytes)); subsystemVendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemVendorIdBytes));
final int dSEDpciContextBytesSrcIndex6 = 14;
byte[] pciSubsystemIdBytes = new byte[2]; byte[] pciSubsystemIdBytes = new byte[2];
System.arraycopy(dSEDpciContextBytes, 14, pciSubsystemIdBytes, 0, 2); System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex6, pciSubsystemIdBytes, 0, 2);
subsystemId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemIdBytes)); subsystemId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemIdBytes));
} }
@ -118,8 +126,9 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
dSEDpciContextInfo += " RevisionID = " + revisionId + "\n"; dSEDpciContextInfo += " RevisionID = " + revisionId + "\n";
List<String> classCodeList = translateDeviceClass(classCode); List<String> classCodeList = translateDeviceClass(classCode);
final int validClassCodeListSize = 3;
dSEDpciContextInfo += " Device Class: \n"; dSEDpciContextInfo += " Device Class: \n";
if (classCodeList.size() == 3) { if (classCodeList.size() == validClassCodeListSize) {
dSEDpciContextInfo += " Class = " + classCodeList.get(0) + "\n"; dSEDpciContextInfo += " Class = " + classCodeList.get(0) + "\n";
dSEDpciContextInfo += " Subclass = " + classCodeList.get(1) + "\n"; dSEDpciContextInfo += " Subclass = " + classCodeList.get(1) + "\n";
dSEDpciContextInfo += " Programming Interface = " + classCodeList.get(2) + "\n"; dSEDpciContextInfo += " Programming Interface = " + classCodeList.get(2) + "\n";

View File

@ -9,11 +9,11 @@ import hirs.utils.tpm.eventlog.spdm.SpdmHa;
* *
* <p> * <p>
* typedef union tdDEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN { * typedef union tdDEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN {
* UINT16 SpdmVersion; * UINT16 SpdmVersion;
* UINT8 SpdmSlotId; * UINT8 SpdmSlotId;
* UINT8 Reserved; * UINT8 Reserved;
* UINT32 SpdmBaseHashAlgo; * UINT32 SpdmBaseHashAlgo;
* SPDM_CERT_CHAIN SpdmCertChain; * SPDM_CERT_CHAIN SpdmCertChain;
* } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN; * } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN;
* <p> * <p>
* SpdmVersion: SpdmBaseHashAlgo * SpdmVersion: SpdmBaseHashAlgo
@ -61,16 +61,21 @@ public class DeviceSecurityEventDataSubHeaderCertChain extends DeviceSecurityEve
// byte[] reserved[Bytes]: 1 byte // byte[] reserved[Bytes]: 1 byte
byte[] spdmBaseHashAlgoBytes = new byte[4]; final int dsedSybHBytesSrcIndex1 = 4;
System.arraycopy(dsedSubHBytes, 4, spdmBaseHashAlgoBytes, 0, 4); final int spdmBaseHashAlgoBytesSize = 4;
byte[] spdmBaseHashAlgoBytes = new byte[spdmBaseHashAlgoBytesSize];
System.arraycopy(dsedSubHBytes, dsedSybHBytesSrcIndex1, spdmBaseHashAlgoBytes, 0,
spdmBaseHashAlgoBytesSize);
spdmBaseHashAlgo = HexUtils.leReverseInt(spdmBaseHashAlgoBytes); spdmBaseHashAlgo = HexUtils.leReverseInt(spdmBaseHashAlgoBytes);
// get the size of the SPDM Cert Chain // get the size of the SPDM Cert Chain
int spdmCertChainSize = dsedSubHBytes.length - 8; final int offsetForSpdmCertChain = 8;
int spdmCertChainSize = dsedSubHBytes.length - offsetForSpdmCertChain;
// extract the bytes that comprise the SPDM Cert Chain // extract the bytes that comprise the SPDM Cert Chain
final int dsedSybHBytesSrcIndex2 = 8;
byte[] spdmCertChainBytes = new byte[spdmCertChainSize]; byte[] spdmCertChainBytes = new byte[spdmCertChainSize];
System.arraycopy(dsedSubHBytes, 8, spdmCertChainBytes, 0, System.arraycopy(dsedSubHBytes, dsedSybHBytesSrcIndex2, spdmCertChainBytes, 0,
spdmCertChainSize); spdmCertChainSize);
int spdmBaseHashAlgoSize = SpdmHa.tcgAlgIdToByteSize(spdmBaseHashAlgo); int spdmBaseHashAlgoSize = SpdmHa.tcgAlgIdToByteSize(spdmBaseHashAlgo);

View File

@ -15,24 +15,28 @@ import java.util.List;
* *
* <p> * <p>
* typedef union tdDEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK { * typedef union tdDEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK {
* UINT16 SpdmVersion; * UINT16 SpdmVersion;
* UINT8 SpdmMeasurementBlockCount; * UINT8 SpdmMeasurementBlockCount;
* UINT8 Reserved; * UINT8 Reserved;
* UINT32 SpdmMeasurementHashAlgo; * UINT32 SpdmMeasurementHashAlgo;
* SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock[SpdmMeasurementBlockCount]; * SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock[SpdmMeasurementBlockCount];
* } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK; * } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK;
* <p> * <p>
* * <p>
* SpdmMeasurementBlock is an array of SPDM_MEASUREMENT_BLOCKs * SpdmMeasurementBlock is an array of SPDM_MEASUREMENT_BLOCKs
* The size of each block is the same and can be found by either: * The size of each block is the same and can be found by either:
* 1) 4 + SpdmMeasurementBlock MeasurementSize * 1) 4 + SpdmMeasurementBlock MeasurementSize
* OR * OR
* 2) 4 + hash length of the hash algorithm found in * 2) 4 + hash length of the hash algorithm found in
* DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK SpdmMeasurementHashAlgo * DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK SpdmMeasurementHashAlgo
* where 4 is the size of the SpdmMeasurementBlock header * where 4 is the size of the SpdmMeasurementBlock header
*/ */
public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends DeviceSecurityEventDataSubHeader { public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends DeviceSecurityEventDataSubHeader {
/**
* List of SPDM Measurement Blocks.
*/
private final List<SpdmMeasurementBlock> spdmMeasurementBlockList;
/** /**
* SPDM version. * SPDM version.
*/ */
@ -48,11 +52,6 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
*/ */
@Getter @Getter
private int spdmMeasurementHashAlgo = -1; private int spdmMeasurementHashAlgo = -1;
/**
* List of SPDM Measurement Blocks.
*/
private List<SpdmMeasurementBlock> spdmMeasurementBlockList;
/** /**
* Error reading SPDM Measurement Block. * Error reading SPDM Measurement Block.
*/ */
@ -77,16 +76,21 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
// byte[] reserved[Bytes]: 1 byte // byte[] reserved[Bytes]: 1 byte
byte[] spdmMeasurementHashAlgoBytes = new byte[4]; final int spdmMeasurementHashAlgoBytesSize = 4;
System.arraycopy(dsedSubHBytes, 4, spdmMeasurementHashAlgoBytes, 0, 4); final int dsedSubHBytesSrcIndex1 = 4;
byte[] spdmMeasurementHashAlgoBytes = new byte[spdmMeasurementHashAlgoBytesSize];
System.arraycopy(dsedSubHBytes, dsedSubHBytesSrcIndex1, spdmMeasurementHashAlgoBytes, 0,
spdmMeasurementHashAlgoBytesSize);
spdmMeasurementHashAlgo = HexUtils.leReverseInt(spdmMeasurementHashAlgoBytes); spdmMeasurementHashAlgo = HexUtils.leReverseInt(spdmMeasurementHashAlgoBytes);
// get the total size of the SPDM Measurement Block List // get the total size of the SPDM Measurement Block List
int spdmMeasurementBlockListSize = dsedSubHBytes.length - 8; final int offsetForspdmMeasurementBlockList = 8;
final int spdmMeasurementBlockListSize = dsedSubHBytes.length - offsetForspdmMeasurementBlockList;
// extract the bytes that comprise the SPDM Measurement Block List // extract the bytes that comprise the SPDM Measurement Block List
final int dsedSubHBytesSrcIndex2 = 8;
byte[] spdmMeasurementBlockListBytes = new byte[spdmMeasurementBlockListSize]; byte[] spdmMeasurementBlockListBytes = new byte[spdmMeasurementBlockListSize];
System.arraycopy(dsedSubHBytes, 8, spdmMeasurementBlockListBytes, 0, System.arraycopy(dsedSubHBytes, dsedSubHBytesSrcIndex2, spdmMeasurementBlockListBytes, 0,
spdmMeasurementBlockListSize); spdmMeasurementBlockListSize);
ByteArrayInputStream spdmMeasurementBlockListData = ByteArrayInputStream spdmMeasurementBlockListData =

View File

@ -55,7 +55,7 @@ public abstract class DeviceSecurityEventHeader {
* UEFI Device Path Length. * UEFI Device Path Length.
*/ */
@Getter @Getter
private final int devicePathLength = 0; private static final int DEVICE_PATH_LENGTH = 0;
/** /**
* Contains the size (in bytes) of the header. * Contains the size (in bytes) of the header.
*/ */
@ -128,13 +128,15 @@ public abstract class DeviceSecurityEventHeader {
int startByteUpdated = startByte; int startByteUpdated = startByte;
// get the device path length // get the device path length
byte[] devicePathLengthBytes = new byte[8]; final int devicePathLengthBytesSize = 8;
System.arraycopy(dsedBytes, startByteUpdated, devicePathLengthBytes, 0, 8); byte[] devicePathLengthBytes = new byte[devicePathLengthBytesSize];
System.arraycopy(dsedBytes, startByteUpdated, devicePathLengthBytes, 0, devicePathLengthBytesSize);
int retrievedDevicePathLength = HexUtils.leReverseInt(devicePathLengthBytes); int retrievedDevicePathLength = HexUtils.leReverseInt(devicePathLengthBytes);
// get the device path // get the device path
if (retrievedDevicePathLength > 0) { if (retrievedDevicePathLength > 0) {
startByteUpdated = startByteUpdated + 8; final int startByteUpdatedOffset = 8;
startByteUpdated = startByteUpdated + startByteUpdatedOffset;
byte[] devPathBytes = new byte[retrievedDevicePathLength]; byte[] devPathBytes = new byte[retrievedDevicePathLength];
System.arraycopy(dsedBytes, startByteUpdated, devPathBytes, System.arraycopy(dsedBytes, startByteUpdated, devPathBytes,
0, retrievedDevicePathLength); 0, retrievedDevicePathLength);
@ -153,16 +155,12 @@ public abstract class DeviceSecurityEventHeader {
* @return name of the device type * @return name of the device type
*/ */
public String deviceTypeToString(final int deviceTypeInt) { public String deviceTypeToString(final int deviceTypeInt) {
switch (deviceTypeInt) { return switch (deviceTypeInt) {
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE: case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE -> "No device type";
return "No device type"; case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI -> "PCI";
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI: case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB -> "USB";
return "PCI"; default -> "Unknown or invalid Device Type";
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB: };
return "USB";
default:
return "Unknown or invalid Device Type";
}
} }
/** /**

View File

@ -6,11 +6,6 @@ package hirs.utils.tpm.eventlog.events;
*/ */
public final class EvConstants { public final class EvConstants {
/**
* Default private constructor so checkstyles doesn't complain
*/
private EvConstants() { }
/** /**
* Type length = 4 bytes. * Type length = 4 bytes.
*/ */
@ -39,11 +34,11 @@ public final class EvConstants {
* Each PCR bank holds 24 registers. * Each PCR bank holds 24 registers.
*/ */
public static final int PCR_COUNT = 24; public static final int PCR_COUNT = 24;
// Event IDs
/** /**
* Pre boot cert Event ID. * Pre boot cert Event ID.
*/ */
public static final int EV_PREBOOT_CERT = 0x00000000; public static final int EV_PREBOOT_CERT = 0x00000000;
// Event IDs
/** /**
* POST Code Event ID. * POST Code Event ID.
*/ */
@ -180,4 +175,9 @@ public final class EvConstants {
* EFI SPDM Device Authority Event ID. * EFI SPDM Device Authority Event ID.
*/ */
public static final int EV_EFI_SPDM_DEVICE_AUTHORITY = 0x800000E4; public static final int EV_EFI_SPDM_DEVICE_AUTHORITY = 0x800000E4;
/**
* Default private constructor so checkstyles doesn't complain.
*/
private EvConstants() {
}
} }

View File

@ -11,16 +11,16 @@ import java.nio.charset.StandardCharsets;
* Class to process the EV_NO_ACTION event. * Class to process the EV_NO_ACTION event.
* The first 16 bytes of the event data MUST be a String based identifier (Signature). * The first 16 bytes of the event data MUST be a String based identifier (Signature).
* Currently defined Signatures are * Currently defined Signatures are
* "Spec ID Event03" * "Spec ID Event03"
* - implies the data is a TCG_EfiSpecIDEvent * - implies the data is a TCG_EfiSpecIDEvent
* - TCG_EfiSpecIDEvent is the first event in a TPM Event Log and is used to determine * - 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). * if the format of the Log (SHA1 vs Crypto Agile).
* "StartupLocality" * "StartupLocality"
* - implies the data represents locality info (use lookup to interpret) * - implies the data represents locality info (use lookup to interpret)
* "NvIndexInstance" * "NvIndexInstance"
* - implies the data is a NV_INDEX_INSTANCE_EVENT_LOG_DATA * - implies the data is a NV_INDEX_INSTANCE_EVENT_LOG_DATA
* "NvIndexDynamic" * "NvIndexDynamic"
* - implies the data is a NV_INDEX_DYNAMIC_EVENT_LOG_DATA * - implies the data is a NV_INDEX_DYNAMIC_EVENT_LOG_DATA
* <p> * <p>
* Notes: * Notes:
* 1. First 16 bytes of the structure is an ASCII with a fixed Length of 16 * 1. First 16 bytes of the structure is an ASCII with a fixed Length of 16
@ -66,7 +66,7 @@ public class EvNoAction {
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
if (signature.contains("Spec ID Event03")) { // implies CryptAgileFormat if (signature.contains("Spec ID Event03")) { // implies CryptAgileFormat
EvEfiSpecIdEvent specIDEvent = new EvEfiSpecIdEvent(eventData); EvEfiSpecIdEvent specIDEvent = new EvEfiSpecIdEvent(eventData);
noActionInfo += specIDEventToString(specIDEvent).toString(); noActionInfo += specIDEventToString(specIDEvent);
bSpecIDEvent = true; bSpecIDEvent = true;
specVersion = String.format("%s.%s", specVersion = String.format("%s.%s",
specIDEvent.getVersionMajor(), specIDEvent.getVersionMajor(),
@ -126,25 +126,21 @@ public class EvNoAction {
* @return a description of the locality. * @return a description of the locality.
*/ */
private String getLocality(final byte[] eventData) { private String getLocality(final byte[] eventData) {
String localityInfo = ""; final int eventDataSrcIndex = 16;
byte[] localityBytes = new byte[1]; byte[] localityBytes = new byte[1];
System.arraycopy(eventData, 16, localityBytes, 0, 1); System.arraycopy(eventData, eventDataSrcIndex, localityBytes, 0, 1);
int locality = HexUtils.leReverseInt(localityBytes); final int locality = HexUtils.leReverseInt(localityBytes);
switch (locality) { final int locality0 = 0;
case 0: final int locality3 = 3;
localityInfo += "Locality 0 without an H-CRTM sequence"; final int locality4 = 4;
break;
case 3: return switch (locality) {
localityInfo += "Locality 3 without an H-CRTM sequence"; case locality0 -> "Locality 0 without an H-CRTM sequence";
break; case locality3 -> "Locality 3 without an H-CRTM sequence";
case 4: case locality4 -> "Locality 4 with an H-CRTM sequence initialized";
localityInfo += "Locality 4 with an H-CRTM sequence initialized"; default -> "Unknown";
break; };
default:
localityInfo += "Unknown";
}
return localityInfo;
} }
/** /**

View File

@ -8,19 +8,19 @@ import java.nio.charset.StandardCharsets;
* Class to process the NV_INDEX_DYNAMIC_EVENT_LOG_DATA per PFP. * Class to process the NV_INDEX_DYNAMIC_EVENT_LOG_DATA per PFP.
* Per PFP, the first 16 bytes of the structure are a String based identifier (Signature), * Per PFP, the first 16 bytes of the structure are a String based identifier (Signature),
* which are a NULL-terminated ASCII string "NvIndexDynamic". * which are a NULL-terminated ASCII string "NvIndexDynamic".
* * <p>
* HEADERS defined by PFP v1.06 Rev 52. * HEADERS defined by PFP v1.06 Rev 52.
* Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures. * Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures.
* <p> * <p>
* typedef struct tdNV_INDEX_DYNAMIC_EVENT_LOG_DATA { * typedef struct tdNV_INDEX_DYNAMIC_EVENT_LOG_DATA {
* BYTE Signature[16]; * BYTE Signature[16];
* UINT16 Version; * UINT16 Version;
* UINT8[6] Reserved; * UINT8[6] Reserved;
* UINT64 UID; * UINT64 UID;
* UINT16 DescriptionSize; * UINT16 DescriptionSize;
* UINT8 Description[DescriptionSize]; * UINT8 Description[DescriptionSize];
* UINT16 DataSize; * UINT16 DataSize;
* DEVICE_SECURITY_EVENT_DATA2 Data[DataSize]; * DEVICE_SECURITY_EVENT_DATA2 Data[DataSize];
* } NV_INDEX_DYNAMIC_EVENT_LOG_DATA; * } NV_INDEX_DYNAMIC_EVENT_LOG_DATA;
* <p> * <p>
*/ */
@ -43,13 +43,16 @@ public class NvIndexDynamicEventLogData {
*/ */
public NvIndexDynamicEventLogData(final byte[] eventData) { public NvIndexDynamicEventLogData(final byte[] eventData) {
byte[] signatureBytes = new byte[16]; final int signatureBytesSize = 16;
System.arraycopy(eventData, 0, signatureBytes, 0, 16); byte[] signatureBytes = new byte[signatureBytesSize];
System.arraycopy(eventData, 0, signatureBytes, 0, signatureBytesSize);
signature = new String(signatureBytes, StandardCharsets.UTF_8); signature = new String(signatureBytes, StandardCharsets.UTF_8);
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
byte[] versionBytes = new byte[2]; final int versionBytesSize = 2;
System.arraycopy(eventData, 16, versionBytes, 0, 2); final int eventDataSrcIndex1 = 16;
byte[] versionBytes = new byte[versionBytesSize];
System.arraycopy(eventData, eventDataSrcIndex1, versionBytes, 0, versionBytesSize);
String nvIndexVersion = HexUtils.byteArrayToHexString(versionBytes); String nvIndexVersion = HexUtils.byteArrayToHexString(versionBytes);
if (nvIndexVersion.isEmpty()) { if (nvIndexVersion.isEmpty()) {
nvIndexVersion = "version not readable"; nvIndexVersion = "version not readable";
@ -58,23 +61,28 @@ public class NvIndexDynamicEventLogData {
nvIndexDynamicInfo += " Nv Index Dynamic Version = " + nvIndexVersion + "\n"; nvIndexDynamicInfo += " Nv Index Dynamic Version = " + nvIndexVersion + "\n";
// 6 bytes of Reserved data // 6 bytes of Reserved data
final int uidBytesSize = 8;
byte[] uidBytes = new byte[8]; final int eventDataSrcIndex2 = 24;
System.arraycopy(eventData, 24, uidBytes, 0, 8); byte[] uidBytes = new byte[uidBytesSize];
System.arraycopy(eventData, eventDataSrcIndex2, uidBytes, 0, uidBytesSize);
String uid = HexUtils.byteArrayToHexString(uidBytes); String uid = HexUtils.byteArrayToHexString(uidBytes);
nvIndexDynamicInfo += " UID = " + uid + "\n"; nvIndexDynamicInfo += " UID = " + uid + "\n";
byte[] descriptionSizeBytes = new byte[2]; final int descriptionSizeBytesLength = 2;
System.arraycopy(eventData, 32, descriptionSizeBytes, 0, 2); final int eventDataSrcIndex3 = 32;
byte[] descriptionSizeBytes = new byte[descriptionSizeBytesLength];
System.arraycopy(eventData, eventDataSrcIndex3, descriptionSizeBytes, 0, descriptionSizeBytesLength);
int descriptionSize = HexUtils.leReverseInt(descriptionSizeBytes); int descriptionSize = HexUtils.leReverseInt(descriptionSizeBytes);
final int eventDataSrcIndex4 = 34;
byte[] descriptionBytes = new byte[descriptionSize]; byte[] descriptionBytes = new byte[descriptionSize];
System.arraycopy(eventData, 34, descriptionBytes, 0, descriptionSize); System.arraycopy(eventData, eventDataSrcIndex4, descriptionBytes, 0, descriptionSize);
String description = new String(descriptionBytes, StandardCharsets.UTF_8); String description = new String(descriptionBytes, StandardCharsets.UTF_8);
description = description.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters description = description.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
nvIndexDynamicInfo += " Description = " + description + "\n"; nvIndexDynamicInfo += " Description = " + description + "\n";
int dataSizeStartByte = 34 + descriptionSize; final int dataSizeOffset = 34;
int dataSizeStartByte = dataSizeOffset + descriptionSize;
byte[] dataSizeBytes = new byte[2]; byte[] dataSizeBytes = new byte[2];
System.arraycopy(eventData, dataSizeStartByte, dataSizeBytes, 0, 2); System.arraycopy(eventData, dataSizeStartByte, dataSizeBytes, 0, 2);
int dataSize = HexUtils.leReverseInt(dataSizeBytes); int dataSize = HexUtils.leReverseInt(dataSizeBytes);

View File

@ -8,15 +8,15 @@ import java.nio.charset.StandardCharsets;
* Class to process the NV_INDEX_INSTANCE_EVENT_LOG_DATA per PFP. * 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), * Per PFP, the first 16 bytes of the structure are a String based identifier (Signature),
* which are a NULL-terminated ASCII string "NvIndexInstance". * which are a NULL-terminated ASCII string "NvIndexInstance".
* * <p>
* HEADERS defined by PFP v1.06 Rev 52. * HEADERS defined by PFP v1.06 Rev 52.
* Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures. * Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures.
* <p> * <p>
* typedef struct tdNV_INDEX_INSTANCE_EVENT_LOG_DATA { * typedef struct tdNV_INDEX_INSTANCE_EVENT_LOG_DATA {
* BYTE Signature[16]; * BYTE Signature[16];
* UINT16 Version; * UINT16 Version;
* UINT8[6] Reserved; * UINT8[6] Reserved;
* DEVICE_SECURITY_EVENT_DATA2 Data; * DEVICE_SECURITY_EVENT_DATA2 Data;
* } NV_INDEX_INSTANCE_EVENT_LOG_DATA; * } NV_INDEX_INSTANCE_EVENT_LOG_DATA;
* <p> * <p>
*/ */
@ -45,13 +45,15 @@ public class NvIndexInstanceEventLogData {
*/ */
public NvIndexInstanceEventLogData(final byte[] eventData) { public NvIndexInstanceEventLogData(final byte[] eventData) {
byte[] signatureBytes = new byte[16]; final int signatureBytesSize = 16;
System.arraycopy(eventData, 0, signatureBytes, 0, 16); byte[] signatureBytes = new byte[signatureBytesSize];
System.arraycopy(eventData, 0, signatureBytes, 0, signatureBytesSize);
signature = new String(signatureBytes, StandardCharsets.UTF_8); signature = new String(signatureBytes, StandardCharsets.UTF_8);
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
final int eventDataSrcIndex1 = 16;
byte[] versionBytes = new byte[2]; byte[] versionBytes = new byte[2];
System.arraycopy(eventData, 16, versionBytes, 0, 2); System.arraycopy(eventData, eventDataSrcIndex1, versionBytes, 0, 2);
String nvIndexVersion = HexUtils.byteArrayToHexString(versionBytes); String nvIndexVersion = HexUtils.byteArrayToHexString(versionBytes);
if (nvIndexVersion == "") { if (nvIndexVersion == "") {
nvIndexVersion = "version not readable"; nvIndexVersion = "version not readable";
@ -60,14 +62,16 @@ public class NvIndexInstanceEventLogData {
nvIndexInstanceInfo += " Nv Index Instance Version = " + nvIndexVersion + "\n"; nvIndexInstanceInfo += " Nv Index Instance Version = " + nvIndexVersion + "\n";
// 6 bytes of Reserved data // 6 bytes of Reserved data
final int eventDataSrcIndex2 = 24;
byte[] dsedSignatureBytes = new byte[16]; final int dsedSignatureBytesSize = 16;
System.arraycopy(eventData, 24, dsedSignatureBytes, 0, 16); byte[] dsedSignatureBytes = new byte[dsedSignatureBytesSize];
System.arraycopy(eventData, eventDataSrcIndex2, dsedSignatureBytes, 0, dsedSignatureBytesSize);
String dsedSignature = new String(dsedSignatureBytes, StandardCharsets.UTF_8); String dsedSignature = new String(dsedSignatureBytes, StandardCharsets.UTF_8);
dsedSignature = dsedSignature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters dsedSignature = dsedSignature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
final int eventDataSrcIndex3 = 40;
byte[] dsedVersionBytes = new byte[2]; byte[] dsedVersionBytes = new byte[2];
System.arraycopy(eventData, 40, dsedVersionBytes, 0, 2); System.arraycopy(eventData, eventDataSrcIndex3, dsedVersionBytes, 0, 2);
String dsedVersion = HexUtils.byteArrayToHexString(dsedVersionBytes); String dsedVersion = HexUtils.byteArrayToHexString(dsedVersionBytes);
if (dsedVersion == "") { if (dsedVersion == "") {
dsedVersion = "version not readable"; dsedVersion = "version not readable";
@ -75,9 +79,10 @@ public class NvIndexInstanceEventLogData {
if (dsedSignature.contains("SPDM Device Sec2")) { if (dsedSignature.contains("SPDM Device Sec2")) {
int dsedEventDataSize = eventData.length - 24; final int eventDataSrcIndex4 = 24;
final int dsedEventDataSize = eventData.length - eventDataSrcIndex4;
byte[] dsedEventData = new byte[dsedEventDataSize]; byte[] dsedEventData = new byte[dsedEventDataSize];
System.arraycopy(eventData, 24, dsedEventData, 0, dsedEventDataSize); System.arraycopy(eventData, eventDataSrcIndex4, dsedEventData, 0, dsedEventDataSize);
nvIndexInstanceInfo += " Signature = SPDM Device Sec2\n"; nvIndexInstanceInfo += " Signature = SPDM Device Sec2\n";
@ -89,7 +94,7 @@ public class NvIndexInstanceEventLogData {
+ dsedVersion + "\n"; + dsedVersion + "\n";
} }
} else { } else {
nvIndexInstanceInfo = " Signature error: should be \'SPDM Device Sec2\' but is " nvIndexInstanceInfo = " Signature error: should be 'SPDM Device Sec2' but is "
+ signature + "\n"; + signature + "\n";
} }
} }

View File

@ -15,22 +15,22 @@ import java.util.ArrayList;
* <p> * <p>
* Certificate chain format, defined by SPDM v1.03, Sect 10.6.1, Table 33: * Certificate chain format, defined by SPDM v1.03, Sect 10.6.1, Table 33:
* Certificate chain format { * Certificate chain format {
* Length 2 bytes; * Length 2 bytes;
* Reserved 2 bytes; * Reserved 2 bytes;
* RootHash <H> bytes; * RootHash <H> bytes;
* Certificates <Length> - (4 + <H>) bytes; * Certificates <Length> - (4 + <H>) bytes;
* } * }
* <p> * <p>
* Length: total length of cert chain including all fields in this block * 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 * H: the output size of the hash algorithm selected by the most recent ALGORITHMS response
* this field shall be in hash byte order * this field shall be in hash byte order
* hash algorithm is included in the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN * hash algorithm is included in the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN
* structure as the member "SpdmBaseHashAlg" * structure as the member "SpdmBaseHashAlg"
* RootHash: the digest of the Root Certificate. * RootHash: the digest of the Root Certificate.
* size is determined by hash algorithm selected by the most recent SPDM ALGORITHMS response; * 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 * 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 * 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 * this field shall be in Encoded ASN.1 byte order
*/ */
public class SpdmCertificateChain { public class SpdmCertificateChain {
@ -38,6 +38,10 @@ public class SpdmCertificateChain {
// * Length of the certificate chain to include all fields in this structure. // * Length of the certificate chain to include all fields in this structure.
// */ // */
//private int length = 0; //private int length = 0;
/**
* Array List of certs found in the chain.
*/
private final ArrayList<UefiX509Cert> certList = new ArrayList<UefiX509Cert>();
/** /**
* Root hash. * Root hash.
*/ */
@ -46,10 +50,6 @@ public class SpdmCertificateChain {
* Number of certs in the SPDM cert chain. * Number of certs in the SPDM cert chain.
*/ */
private int numberOfCerts = 0; 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. * Human-readable description of any error associated with SPDM base hash alg.
*/ */
@ -63,7 +63,7 @@ public class SpdmCertificateChain {
* SpdmCertificateChain Constructor. * SpdmCertificateChain Constructor.
* *
* @param spdmCertChainBytes byte array holding the SPDM Cert Chain bytes. * @param spdmCertChainBytes byte array holding the SPDM Cert Chain bytes.
* @param rootHashLength length of RootHash. * @param rootHashLength length of RootHash.
*/ */
public SpdmCertificateChain(final byte[] spdmCertChainBytes, final int rootHashLength) { public SpdmCertificateChain(final byte[] spdmCertChainBytes, final int rootHashLength) {
@ -76,11 +76,13 @@ public class SpdmCertificateChain {
// Reserved: 2 bytes // Reserved: 2 bytes
final int spdmCertChainBytesSrcIndex = 4;
rootHash = new byte[rootHashLength]; rootHash = new byte[rootHashLength];
System.arraycopy(spdmCertChainBytes, 4, rootHash, 0, rootHashLength); System.arraycopy(spdmCertChainBytes, spdmCertChainBytesSrcIndex, rootHash, 0, rootHashLength);
int certChainStartPos = 4 + rootHashLength; final int offsetForCertChain = 4;
int certChainLength = spdmCertChainBytes.length - certChainStartPos; final int certChainStartPos = offsetForCertChain + rootHashLength;
final int certChainLength = spdmCertChainBytes.length - certChainStartPos;
byte[] certChainBytes = new byte[certChainLength]; byte[] certChainBytes = new byte[certChainLength];
System.arraycopy(spdmCertChainBytes, certChainStartPos, certChainBytes, 0, certChainLength); System.arraycopy(spdmCertChainBytes, certChainStartPos, certChainBytes, 0, certChainLength);
@ -93,7 +95,7 @@ public class SpdmCertificateChain {
* *
* @param certChainData Byte array holding the cert chain data * @param certChainData Byte array holding the cert chain data
*/ */
private void processCertChain(final byte[] certChainData) { private void processCertChain(final byte[] certChainData) {
UefiX509Cert cert = null; UefiX509Cert cert = null;
@ -113,10 +115,11 @@ public class SpdmCertificateChain {
byte[] certData = new byte[cLength]; byte[] certData = new byte[cLength];
certChainDataIS.read(certData); certChainDataIS.read(certData);
// put the cert back together // put the cert back together
byte[] certBlob = new byte[cLength + 4]; final int certBlobStartIndex = 4;
byte[] certBlob = new byte[cLength + certBlobStartIndex];
System.arraycopy(certType, 0, certBlob, 0, 2); System.arraycopy(certType, 0, certBlob, 0, 2);
System.arraycopy(certLength, 0, certBlob, 2, 2); System.arraycopy(certLength, 0, certBlob, 2, 2);
System.arraycopy(certData, 0, certBlob, 4, cLength); System.arraycopy(certData, 0, certBlob, certBlobStartIndex, cLength);
cert = new UefiX509Cert(certBlob); cert = new UefiX509Cert(certBlob);
//cert = new X509Certificate(certBlob); //cert = new X509Certificate(certBlob);
certList.add(cert); certList.add(cert);

View File

@ -4,7 +4,7 @@ package hirs.utils.tpm.eventlog.spdm;
* Class for defining hash algorithms referenced in the DMTF SPDM specification. * Class for defining hash algorithms referenced in the DMTF SPDM specification.
* SPDM 1.3.0, Table 21, MeasurementHashAlgo. * SPDM 1.3.0, Table 21, MeasurementHashAlgo.
*/ */
public class SpdmHa { public final class SpdmHa {
/** /**
* Spdm Hash Alg = Raw bit stream. * Spdm Hash Alg = Raw bit stream.
@ -49,32 +49,16 @@ public class SpdmHa {
* @return name of the algorithm * @return name of the algorithm
*/ */
public static String tcgAlgIdToString(final int algId) { public static String tcgAlgIdToString(final int algId) {
String alg; String alg = switch (algId) {
switch (algId) { case TPM_ALG_RAW -> "Raw Bit Stream";
case TPM_ALG_RAW: case TPM_ALG_SHA_256 -> "TPM_ALG_SHA_256";
alg = "Raw Bit Stream"; case TPM_ALG_SHA_384 -> "TPM_ALG_SHA_384";
break; case TPM_ALG_SHA_512 -> "TPM_ALG_SHA_512";
case TPM_ALG_SHA_256: case TPM_ALG_SHA3_256 -> "TPM_ALG_SHA3_256";
alg = "TPM_ALG_SHA_256"; case TPM_ALG_SHA3_384 -> "TPM_ALG_SHA3_384";
break; case TPM_ALG_SHA3_512 -> "TPM_ALG_SHA3_512";
case TPM_ALG_SHA_384: default -> "Unknown or invalid Hash";
alg = "TPM_ALG_SHA_384"; };
break;
case TPM_ALG_SHA_512:
alg = "TPM_ALG_SHA_512";
break;
case TPM_ALG_SHA3_256:
alg = "TPM_ALG_SHA3_256";
break;
case TPM_ALG_SHA3_384:
alg = "TPM_ALG_SHA3_384";
break;
case TPM_ALG_SHA3_512:
alg = "TPM_ALG_SHA3_512";
break;
default:
alg = "Unknown or invalid Hash";
}
return alg; return alg;
} }
@ -86,26 +70,17 @@ public class SpdmHa {
* @return size of the algorithm output * @return size of the algorithm output
*/ */
public static int tcgAlgIdToByteSize(final int algId) { public static int tcgAlgIdToByteSize(final int algId) {
int byteSize; final int byteSize256 = 32;
switch (algId) { final int byteSize384 = 48;
//case TPM_ALG_RAW: // add this when have more test data final int byteSize512 = 64;
// byteSize = ;
// break; return switch (algId) {
case TPM_ALG_SHA_256: // case TPM_ALG_RAW: // add this when have more test data
byteSize = 32; // return ;
break; case TPM_ALG_SHA_256, TPM_ALG_SHA3_256 -> byteSize256;
case TPM_ALG_SHA_384, TPM_ALG_SHA3_384: case TPM_ALG_SHA_384, TPM_ALG_SHA3_384 -> byteSize384;
byteSize = 48; case TPM_ALG_SHA_512, TPM_ALG_SHA3_512 -> byteSize512;
break; default -> -1;
case TPM_ALG_SHA_512, TPM_ALG_SHA3_512: };
byteSize = 64;
break;
case TPM_ALG_SHA3_256:
byteSize = 32;
break;
default:
byteSize = -1;
}
return byteSize;
} }
} }

View File

@ -27,6 +27,61 @@ import lombok.Getter;
*/ */
public class SpdmMeasurement { public class SpdmMeasurement {
/**
* MEASUREMENT_VALUE_0 = Immutable ROM.
*/
private static final int MEASUREMENT_VALUE_0 = 0;
/**
* MEASUREMENT_VALUE_1 = Mutable firmware.
*/
private static final int MEASUREMENT_VALUE_1 = 1;
/**
* MEASUREMENT_VALUE_2 = Hardware configuration.
*/
private static final int MEASUREMENT_VALUE_2 = 2;
/**
* MEASUREMENT_VALUE_3 = Firmware configuration.
*/
private static final int MEASUREMENT_VALUE_3 = 3;
/**
* MEASUREMENT_VALUE_4 = Freeform measurement manifest.
*/
private static final int MEASUREMENT_VALUE_4 = 4;
/**
* MEASUREMENT_VALUE_5 = Structured representation of debug and device mode.
*/
private static final int MEASUREMENT_VALUE_5 = 5;
/**
* MEASUREMENT_VALUE_6 = Mutable firmware's version number.
*/
private static final int MEASUREMENT_VALUE_6 = 6;
/**
* MEASUREMENT_VALUE_7 = Mutable firmware's security version number.
*/
private static final int MEASUREMENT_VALUE_7 = 7;
/**
* MEASUREMENT_VALUE_8 = Hash-extended measurement.
*/
private static final int MEASUREMENT_VALUE_8 = 8;
/**
* MEASUREMENT_VALUE_9 = Informational.
*/
private static final int MEASUREMENT_VALUE_9 = 9;
/**
* MEASUREMENT_VALUE_10 = Structured measurement manifest.
*/
private static final int MEASUREMENT_VALUE_10 = 10;
/** /**
* Measurement value (digest). * Measurement value (digest).
*/ */
@ -69,22 +124,20 @@ public class SpdmMeasurement {
* @return a description of the measurement value type. * @return a description of the measurement value type.
*/ */
public String dmtfSpecMeasurementValueTypeToString(final int measValType) { public String dmtfSpecMeasurementValueTypeToString(final int measValType) {
return switch (measValType) {
String measValTypeStr = switch (measValType) { case MEASUREMENT_VALUE_0 -> "Immutable ROM";
case 0 -> "Immutable ROM"; case MEASUREMENT_VALUE_1 -> "Mutable firmware";
case 1 -> "Mutable firmware"; case MEASUREMENT_VALUE_2 -> "Hardware configuration";
case 2 -> "Hardware configuration"; case MEASUREMENT_VALUE_3 -> "Firmware configuration";
case 3 -> "Firmware configuration"; case MEASUREMENT_VALUE_4 -> "Freeform measurement manifest";
case 4 -> "Freeform measurement manifest"; case MEASUREMENT_VALUE_5 -> "Structured representation of debug and device mode";
case 5 -> "Structured representation of debug and device mode"; case MEASUREMENT_VALUE_6 -> "Mutable firmware's version number";
case 6 -> "Mutable firmware's version number"; case MEASUREMENT_VALUE_7 -> "Mutable firmware's security version number";
case 7 -> "Mutable firmware's security version number"; case MEASUREMENT_VALUE_8 -> "Hash-extended measurement";
case 8 -> "Hash-extended measurement"; case MEASUREMENT_VALUE_9 -> "Informational";
case 9 -> "Informational"; case MEASUREMENT_VALUE_10 -> "Structured measurement manifest";
case 10 -> "Structured measurement manifest";
default -> "Unknown or invalid DMTF Spec Measurement Value Type"; default -> "Unknown or invalid DMTF Spec Measurement Value Type";
}; };
return measValTypeStr;
} }
/** /**

View File

@ -58,40 +58,45 @@ public class TCGEventLogTest {
NoSuchAlgorithmException { NoSuchAlgorithmException {
LOGGER.debug("Testing the parsing of a Crypto Agile formatted TCG Event Log"); LOGGER.debug("Testing the parsing of a Crypto Agile formatted TCG Event Log");
// setup
final InputStream log = this.getClass().getResourceAsStream(DEFAULT_EVENT_LOG);
final InputStream pcrs = this.getClass().getResourceAsStream(DEFAULT_EXPECTED_PCRS);
final byte[] rawLogBytes = IOUtils.toByteArray(log);
final TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
final String[] pcrFromLog = evlog.getExpectedPCRValues();
final Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
final String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
boolean testPass = true; try {
// setup
final InputStream log = this.getClass().getResourceAsStream(DEFAULT_EVENT_LOG);
final InputStream pcrs = this.getClass().getResourceAsStream(DEFAULT_EXPECTED_PCRS);
final byte[] rawLogBytes = IOUtils.toByteArray(log);
final TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
final String[] pcrFromLog = evlog.getExpectedPCRValues();
final Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
final String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
// Test 1 get all PCRs boolean testPass = true;
for (int i = 0; i < PCR_COUNT; i++) {
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) { // Test 1 get all PCRs
testPass = false; for (int i = 0; i < PCR_COUNT; i++) {
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i); if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
testPass = false;
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i);
}
} }
assertTrue(testPass);
// Test 2 get an individual PCR
final int pcrIndex = 3;
String pcr3 = evlog.getExpectedPCRValue(pcrIndex);
assertThat(pcrFromLog[pcrIndex], equalTo(pcr3));
// Test 3 check the Algorithm String Identifier used in the log
String algStr = evlog.getEventLogHashAlgorithm();
assertThat("TPM_ALG_SHA256", equalTo(algStr));
// Test 4 check the Algorithm # Identifier used in the log
int id = evlog.getEventLogHashAlgorithmID();
assertThat(TcgTpmtHa.TPM_ALG_SHA256, equalTo(id));
LOGGER.debug("OK. Parsing of a Crypto Agile Format Success");
} catch (Throwable throwable) {
throw throwable;
} }
assertTrue(testPass);
// Test 2 get an individual PCR
final int pcrIndex = 3;
String pcr3 = evlog.getExpectedPCRValue(pcrIndex);
assertThat(pcrFromLog[pcrIndex], equalTo(pcr3));
// Test 3 check the Algorithm String Identifier used in the log
String algStr = evlog.getEventLogHashAlgorithm();
assertThat("TPM_ALG_SHA256", equalTo(algStr));
// Test 4 check the Algorithm # Identifier used in the log
int id = evlog.getEventLogHashAlgorithmID();
assertThat(TcgTpmtHa.TPM_ALG_SHA256, equalTo(id));
LOGGER.debug("OK. Parsing of a Crypto Agile Format Success");
} }
/** /**
@ -106,38 +111,42 @@ public class TCGEventLogTest {
NoSuchAlgorithmException { NoSuchAlgorithmException {
LOGGER.debug("Testing the parsing of a SHA1 formated TCG Event Log"); LOGGER.debug("Testing the parsing of a SHA1 formated TCG Event Log");
// setup try {
final InputStream log = this.getClass().getResourceAsStream(SHA1_EVENT_LOG); // setup
final InputStream pcrs = this.getClass().getResourceAsStream(SHA1_EXPECTED_PCRS); final InputStream log = this.getClass().getResourceAsStream(SHA1_EVENT_LOG);
final byte[] rawLogBytes = IOUtils.toByteArray(log); final InputStream pcrs = this.getClass().getResourceAsStream(SHA1_EXPECTED_PCRS);
final TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false); final byte[] rawLogBytes = IOUtils.toByteArray(log);
final String[] pcrFromLog = evlog.getExpectedPCRValues(); final TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
final Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray(); final String[] pcrFromLog = evlog.getExpectedPCRValues();
final String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class); final Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
final String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
boolean testPass = true; boolean testPass = true;
// Test 1 get all PCRs // Test 1 get all PCRs
for (int i = 0; i < PCR_COUNT; i++) { for (int i = 0; i < PCR_COUNT; i++) {
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) { if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
testPass = false; testPass = false;
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i); LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i);
}
} }
assertTrue(testPass);
// Test 2 get an individual PCR
String pcr0 = evlog.getExpectedPCRValue(0);
assertThat(pcrFromLog[0], equalTo(pcr0));
// Test 3 check the Algorithm String Identifier used in the log
String algStr = evlog.getEventLogHashAlgorithm();
assertThat("TPM_ALG_SHA1", equalTo(algStr));
// Test 4 check the Algorithm # Identifier used in the log
int id = evlog.getEventLogHashAlgorithmID();
assertThat(TcgTpmtHa.TPM_ALG_SHA1, equalTo(id));
LOGGER.debug("OK. Parsing of a SHA1 formatted TCG Event Log Success");
} catch (Throwable throwable) {
throw throwable;
} }
assertTrue(testPass);
// Test 2 get an individual PCR
String pcr0 = evlog.getExpectedPCRValue(0);
assertThat(pcrFromLog[0], equalTo(pcr0));
// Test 3 check the Algorithm String Identifier used in the log
String algStr = evlog.getEventLogHashAlgorithm();
assertThat("TPM_ALG_SHA1", equalTo(algStr));
// Test 4 check the Algorithm # Identifier used in the log
int id = evlog.getEventLogHashAlgorithmID();
assertThat(TcgTpmtHa.TPM_ALG_SHA1, equalTo(id));
LOGGER.debug("OK. Parsing of a SHA1 formatted TCG Event Log Success");
} }
} }

View File

@ -1,5 +1,4 @@
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import org.gradle.api.tasks.Copy
plugins { plugins {
// Apply the application plugin to add support for building a CLI application in Java. // Apply the application plugin to add support for building a CLI application in Java.
@ -8,7 +7,7 @@ plugins {
} }
// Global checkstyle file // Global checkstyle file
ext.checkstyleConfigFile = new File(rootDir, "/config/checkstyle/sun_checks.xml") ext.checkstyleConfigFile = new File(rootDir, "/config/checkstyle/sun_checks.xml")
subprojects { subprojects {
apply plugin: "com.github.spotbugs" apply plugin: "com.github.spotbugs"
@ -19,13 +18,12 @@ subprojects {
tasks.withType(com.github.spotbugs.snom.SpotBugsTask) { tasks.withType(com.github.spotbugs.snom.SpotBugsTask) {
reports { reports {
html { html.required = true
enabled = true
}
} }
} }
} }
dependencies { dependencies {
repositories { repositories {
// Use Maven Central for resolving dependencies. // Use Maven Central for resolving dependencies.
@ -36,10 +34,10 @@ dependencies {
def projectVersion = rootProject.file('VERSION').text.trim() def projectVersion = rootProject.file('VERSION').text.trim()
def buildTime = { -> def buildTime = { ->
Date latestdate = new Date(); Date latestdate = new Date()
def time = latestdate.getTime(); def time = latestdate.getTime()
long seconds = TimeUnit.MILLISECONDS.toSeconds(time); long seconds = TimeUnit.MILLISECONDS.toSeconds(time)
return seconds; return seconds
} }
def gitHash = { -> def gitHash = { ->