Updated the UefiGuid to have the vendor json file get passed in. This updates the unit test and fixes the issue.

This commit is contained in:
Cyrus 2021-08-20 09:19:01 -04:00
parent 9fbbf81ada
commit 61497809f5
4 changed files with 234 additions and 167 deletions

View File

@ -1,43 +1,53 @@
package hirs.tpm.eventlog.events; package hirs.tpm.eventlog.events;
import java.util.ArrayList;
import hirs.tpm.eventlog.uefi.UefiConstants; import hirs.tpm.eventlog.uefi.UefiConstants;
import hirs.tpm.eventlog.uefi.UefiGuid; import hirs.tpm.eventlog.uefi.UefiGuid;
import hirs.utils.HexUtils; import hirs.utils.HexUtils;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.file.Path;
import java.util.ArrayList;
/** Class to process the PC Client Firmware profile defined EV_EFI_HANDOFF_TABLES event. /**
* Class to process the PC Client Firmware profile defined EV_EFI_HANDOFF_TABLES event.
* The Event data holds a structure called UEFI_HANDOFF_TABLE_POINTERS: * The Event data holds a structure called UEFI_HANDOFF_TABLE_POINTERS:
* * <p>
* tdUEFI_HANDOFF_TABLE_POINTERS { * tdUEFI_HANDOFF_TABLE_POINTERS {
* UINT64 NumberOfTables; * UINT64 NumberOfTables;
* UEFI_CONFIGURATION_TABLE TableEntry[NumberOfTables]; * UEFI_CONFIGURATION_TABLE TableEntry[NumberOfTables];
* }UEFI_HANDOFF_TABLE_POINTERS; * }UEFI_HANDOFF_TABLE_POINTERS;
* * <p>
* The UEFI_CONFIGURATION_TABLE id defined in the UEFI spec as: * The UEFI_CONFIGURATION_TABLE id defined in the UEFI spec as:
* * <p>
* typedef struct{ * typedef struct{
* EFI_GUID VendorGuid; * EFI_GUID VendorGuid;
* VOID *VendorTable; * VOID *VendorTable;
* } EFI_CONFIGURATION_TABLE; * } EFI_CONFIGURATION_TABLE;
* Where the defines * Where the defines
* VendorGuid: The 128-bit GUID value that uniquely identifies the system configuration table. * VendorGuid: The 128-bit GUID value that uniquely identifies the system configuration table.
* VendorTable: A pointer to the table associated with VendorGuid. * VendorTable: A pointer to the table associated with VendorGuid.
* Section 4.6 of the UEFI spec has a listing of some of the industry defined * Section 4.6 of the UEFI spec has a listing of some of the industry defined
* standard that define the particular table. * standard that define the particular table.
*/ */
public class EvEfiHandoffTable { public class EvEfiHandoffTable {
/** Number of Tables. */ /**
* Number of Tables.
*/
private int tableCount = 0; private int tableCount = 0;
/** List of Vendor GUIDs. */ /**
* List of Vendor GUIDs.
*/
private ArrayList<UefiGuid> vendorGuids = new ArrayList<UefiGuid>(); private ArrayList<UefiGuid> vendorGuids = new ArrayList<UefiGuid>();
/** List of Vendors. */ /**
* List of Vendors.
*/
private ArrayList<byte[]> vendorTables = new ArrayList<byte[]>(); private ArrayList<byte[]> vendorTables = new ArrayList<byte[]>();
private Path vendorPathString;
/** /**
* EvEFIHandoffTable constructor. * EvEFIHandoffTable constructor.
*
* @param tpmEventData byte array holding the Handoff table data. * @param tpmEventData byte array holding the Handoff table data.
*/ */
public EvEfiHandoffTable(final byte[] tpmEventData) { public EvEfiHandoffTable(final byte[] tpmEventData) {
@ -53,56 +63,87 @@ public class EvEfiHandoffTable {
vendorGuids.add(getNextGUID(tpmEventData, offset)); vendorGuids.add(getNextGUID(tpmEventData, offset));
vendorTables.add(getNextTable(tpmEventData, offset + UefiConstants.OFFSET_16)); vendorTables.add(getNextTable(tpmEventData, offset + UefiConstants.OFFSET_16));
offset += UefiConstants.OFFSET_24; offset += UefiConstants.OFFSET_24;
} }
} }
/** /**
* Return the number of EFI configuration tables covered in this event. * EvEFIHandoffTable constructor.
* @return number of EFI configuration tables. *
* @param tpmEventData byte array holding the Handoff table data.
* @param vendorPathString the string for the vendor file
*/
public EvEfiHandoffTable(final byte[] tpmEventData, final Path vendorPathString) {
// Get NumberOfTables from the EventData
byte[] count = new byte[UefiConstants.SIZE_8];
System.arraycopy(tpmEventData, 0, count, 0, UefiConstants.SIZE_8);
byte[] bigEndCount = HexUtils.leReverseByte(count);
BigInteger countInt = new BigInteger(bigEndCount);
tableCount = countInt.intValue();
this.vendorPathString = vendorPathString;
// process each UEFI_CONFIGURATION_TABLE table
int offset = UefiConstants.OFFSET_8;
for (int tables = 0; tables < tableCount; tables++) {
vendorGuids.add(getNextGUID(tpmEventData, offset));
vendorTables.add(getNextTable(tpmEventData, offset + UefiConstants.OFFSET_16));
offset += UefiConstants.OFFSET_24;
}
}
/**
* Return the number of EFI configuration tables covered in this event.
*
* @return number of EFI configuration tables.
*/ */
public int getNumberOfTables() { public int getNumberOfTables() {
return tableCount; return tableCount;
} }
/** /**
* Returns the next GUI in the table. * Returns the next GUI in the table.
*
* @param eventData byte array holding the guids. * @param eventData byte array holding the guids.
* @param offset offset to the guid. * @param offset offset to the guid.
* @return Vendor Guid * @return Vendor Guid
*/ */
private UefiGuid getNextGUID(final byte[] eventData, final int offset) { private UefiGuid getNextGUID(final byte[] eventData, final int offset) {
byte[] guid = new byte[UefiConstants.SIZE_16]; byte[] guid = new byte[UefiConstants.SIZE_16];
System.arraycopy(eventData, offset, guid, 0, UefiConstants.SIZE_16); System.arraycopy(eventData, offset, guid, 0, UefiConstants.SIZE_16);
return new UefiGuid(guid); if (vendorPathString == null || vendorPathString.toString().isEmpty()) {
return new UefiGuid(guid);
} else {
return new UefiGuid(guid, vendorPathString);
} }
}
/** /**
* Copies the next table to a new array. * Copies the next table to a new array.
*
* @param eventData byte array holding the next table. * @param eventData byte array holding the next table.
* @param offset offset within the table to fond the data. * @param offset offset within the table to fond the data.
* @return a byte array holding the new table. * @return a byte array holding the new table.
*/ */
private byte[] getNextTable(final byte[] eventData, final int offset) { private byte[] getNextTable(final byte[] eventData, final int offset) {
byte[] table = new byte[UefiConstants.SIZE_8]; byte[] table = new byte[UefiConstants.SIZE_8];
System.arraycopy(eventData, offset, table, 0, UefiConstants.SIZE_8); System.arraycopy(eventData, offset, table, 0, UefiConstants.SIZE_8);
return table; return table;
} }
/** /**
* Returns a human readable description of the hand off tables. * Returns a human readable description of the hand off tables.
* @return a human readable description. *
*/ * @return a human readable description.
public String toString() { */
StringBuilder tableInfo = new StringBuilder(); public String toString() {
tableInfo.append("Number of UEFI_CONFIGURATION_TABLEs = " + tableCount + "\n"); StringBuilder tableInfo = new StringBuilder();
for (int i = 0; i < tableCount; i++) { tableInfo.append("Number of UEFI_CONFIGURATION_TABLEs = " + tableCount + "\n");
UefiGuid currentGuid = vendorGuids.get(i); for (int i = 0; i < tableCount; i++) {
tableInfo.append(" Table " + i + ": " + currentGuid.toString()); UefiGuid currentGuid = vendorGuids.get(i);
tableInfo.append(" UEFI industry standard table type = " tableInfo.append(" Table " + i + ": " + currentGuid.toString());
+ currentGuid.getVendorTableReference() + "\n"); tableInfo.append(" UEFI industry standard table type = "
tableInfo.append(" VendorTable " + i + " address: " + currentGuid.getVendorTableReference() + "\n");
+ HexUtils.byteArrayToHexString(vendorTables.get(i))); tableInfo.append(" VendorTable " + i + " address: "
} + HexUtils.byteArrayToHexString(vendorTables.get(i)));
return tableInfo.toString(); }
return tableInfo.toString();
} }
} }

View File

@ -1,14 +1,14 @@
package hirs.tpm.eventlog.uefi; package hirs.tpm.eventlog.uefi;
import com.eclipsesource.json.JsonObject;
import hirs.utils.HexUtils;
import hirs.utils.JsonUtils;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.file.FileSystems; import java.nio.file.FileSystems;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.UUID; import java.util.UUID;
import com.eclipsesource.json.JsonObject;
import hirs.utils.HexUtils;
import hirs.utils.JsonUtils;
/** /**
* Class to process GUID per the UEFI specification * Class to process GUID per the UEFI specification
* GUIDs are essentially UUID as defined by RFC-1422, however Microsoft refers to GUIDS. * GUIDs are essentially UUID as defined by RFC-1422, however Microsoft refers to GUIDS.
@ -47,6 +47,20 @@ public class UefiGuid {
uefiVendorRef = JsonUtils.getSpecificJsonObject(JSON_PATH, "VendorTable"); uefiVendorRef = JsonUtils.getSpecificJsonObject(JSON_PATH, "VendorTable");
} }
/**
* UefiGUID constructor.
*
* @param guidBytes byte array holding a valid guid.
* @param vendorPathString string path for vendor
*/
public UefiGuid(final byte[] guidBytes, final Path vendorPathString) {
guid = new byte[UefiConstants.SIZE_16];
System.arraycopy(guidBytes, 0, guid, 0, UefiConstants.SIZE_16);
uuid = processGuid(guidBytes);
uefiVendorRef = JsonUtils.getSpecificJsonObject(vendorPathString,
"VendorTable");
}
/** /**
* Converts a GUID with a byte array to a RFC-1422 UUID object. * Converts a GUID with a byte array to a RFC-1422 UUID object.
* Assumes a MS format and converts to Big Endian format used by most others , including Linux * Assumes a MS format and converts to Big Endian format used by most others , including Linux

View File

@ -20,8 +20,9 @@ public class ComponentClassTest {
@Test @Test
public void testGetComponentNoneUNK() throws URISyntaxException { public void testGetComponentNoneUNK() throws URISyntaxException {
String componentIdentifier = "00000001"; String componentIdentifier = "00000001";
ComponentClass instance = new ComponentClass("TCG", Paths.get(this.getClass() ComponentClass instance = new ComponentClass("TCG",
.getResource(JSON_FILE).toURI()), componentIdentifier); Paths.get(this.getClass().getResource(JSON_FILE).toURI()),
componentIdentifier);
String resultCategory = instance.getCategory(); String resultCategory = instance.getCategory();
String resultComponent = instance.getComponent(); String resultComponent = instance.getComponent();
Assert.assertEquals(resultComponent, "Unknown"); Assert.assertEquals(resultComponent, "Unknown");

View File

@ -1,10 +1,9 @@
package hirs.tpm.eventlog.events; package hirs.tpm.eventlog.events;
import java.io.IOException; import hirs.tpm.eventlog.TCGEventLogTest;
import java.security.NoSuchAlgorithmException; import hirs.tpm.eventlog.uefi.UefiGuid;
import java.security.cert.CertificateException; import hirs.tpm.eventlog.uefi.UefiPartition;
import java.util.ArrayList; import hirs.utils.HexUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -13,25 +12,28 @@ import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import hirs.tpm.eventlog.TCGEventLogTest; import java.io.IOException;
import hirs.utils.HexUtils; import java.net.URISyntaxException;
import hirs.tpm.eventlog.uefi.UefiGuid; import java.nio.file.Paths;
import hirs.tpm.eventlog.uefi.UefiPartition; import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
/** /**
* Class for testing TCG Event Log Event processing. * Class for testing TCG Event Log Event processing.
*/ */
public class TCGEventLogEventsTest { public class TCGEventLogEventsTest {
// Variable files collected using an Event Parsing tool // Variable files collected using an Event Parsing tool
private static final String EVENT_SPECID = "/tcgeventlog/events/EvEfiSpecId.txt"; private static final String EVENT_SPECID = "/tcgeventlog/events/EvEfiSpecId.txt";
private static final String EVENT_BOOTSERVICES private static final String EVENT_BOOTSERVICES
= "/tcgeventlog/events/EvBootServicesApplication.txt"; = "/tcgeventlog/events/EvBootServicesApplication.txt";
private static final String EVENT_GPT_PARTITION private static final String EVENT_GPT_PARTITION
= "/tcgeventlog/events/EvEfiGptPartition.txt"; = "/tcgeventlog/events/EvEfiGptPartition.txt";
private static final String EVENT_HANDOFF_TABLES = "/tcgeventlog/events/EvHandoffTables.txt"; private static final String EVENT_HANDOFF_TABLES = "/tcgeventlog/events/EvHandoffTables.txt";
private static final String UEFI_POST_CODE = "/tcgeventlog/events/EvPostCode.txt"; private static final String UEFI_POST_CODE = "/tcgeventlog/events/EvPostCode.txt";
private static final Logger LOGGER private static final Logger LOGGER
= LogManager.getLogger(TCGEventLogTest.class); = LogManager.getLogger(TCGEventLogTest.class);
private static final String JSON_FILE = "/tcgeventlog/uefi/vendor-table.json";
/** /**
* Initializes a <code>SessionFactory</code>. * Initializes a <code>SessionFactory</code>.
@ -50,111 +52,120 @@ public class TCGEventLogEventsTest {
LOGGER.debug("closing session factory"); LOGGER.debug("closing session factory");
} }
/** /**
* Tests the processing of a SpecIDEvent event. * Tests the processing of a SpecIDEvent event.
* @throws IOException when processing the test fails *
*/ * @throws IOException when processing the test fails
@Test */
public final void testSpecIDEvent() throws IOException { @Test
LOGGER.debug("Testing the SpecID Event Processing"); public final void testSpecIDEvent() throws IOException {
String event = IOUtils.toString(this.getClass().getResourceAsStream(EVENT_SPECID), "UTF-8"); LOGGER.debug("Testing the SpecID Event Processing");
byte[] eventBytes = HexUtils.hexStringToByteArray(event); String event = IOUtils.toString(this.getClass().getResourceAsStream(EVENT_SPECID), "UTF-8");
EvEfiSpecIdEvent specEvent = new EvEfiSpecIdEvent(eventBytes); byte[] eventBytes = HexUtils.hexStringToByteArray(event);
Assert.assertTrue(specEvent.isCryptoAgile()); EvEfiSpecIdEvent specEvent = new EvEfiSpecIdEvent(eventBytes);
Assert.assertEquals(specEvent.getSignature(), "Spec ID Event03"); Assert.assertTrue(specEvent.isCryptoAgile());
} Assert.assertEquals(specEvent.getSignature(), "Spec ID Event03");
}
/** /**
* Tests the processing of a Boot Services App event. * Tests the processing of a Boot Services App event.
* @throws IOException when processing the test fails *
* @throws NoSuchAlgorithmException if an unknown algorithm is encountered. * @throws IOException when processing the test fails
* @throws CertificateException if a certificate fails to parse. * @throws NoSuchAlgorithmException if an unknown algorithm is encountered.
*/ * @throws CertificateException if a certificate fails to parse.
@Test */
public final void testEvBootServicesApp() throws IOException { @Test
LOGGER.debug("Testing the parsing of Boot Services Application Event"); public final void testEvBootServicesApp() throws IOException {
String event = IOUtils.toString(this.getClass().getResourceAsStream(EVENT_BOOTSERVICES), LOGGER.debug("Testing the parsing of Boot Services Application Event");
"UTF-8"); String event = IOUtils.toString(this.getClass().getResourceAsStream(EVENT_BOOTSERVICES),
byte[] eventBytes = HexUtils.hexStringToByteArray(event); "UTF-8");
EvEfiBootServicesApp bootService = new EvEfiBootServicesApp(eventBytes); byte[] eventBytes = HexUtils.hexStringToByteArray(event);
String address = HexUtils.byteArrayToHexString(bootService.getImagePhysicalAddress()); EvEfiBootServicesApp bootService = new EvEfiBootServicesApp(eventBytes);
Assert.assertEquals(address, "1820d45800000000"); String address = HexUtils.byteArrayToHexString(bootService.getImagePhysicalAddress());
String path = bootService.getDevicePath().toString(); Assert.assertEquals(address, "1820d45800000000");
Assert.assertTrue(path.contains("PIWG Firmware Volume b6ede22c-de30-45fa-bb09-ca202c1654b7")); String path = bootService.getDevicePath().toString();
} Assert.assertTrue(path.contains("PIWG Firmware Volume "
+ "b6ede22c-de30-45fa-bb09-ca202c1654b7"));
}
/** /**
* Tests the processing of a Boot Services App event. * Tests the processing of a Boot Services App event.
* @throws IOException when processing the test fails *
* @throws NoSuchAlgorithmException if an unknown algorithm is encountered. * @throws IOException when processing the test fails
* @throws CertificateException if a certificate fails to parse. * @throws NoSuchAlgorithmException if an unknown algorithm is encountered.
*/ * @throws CertificateException if a certificate fails to parse.
@Test */
public final void testEvGptPartiton() throws IOException { @Test
LOGGER.debug("Testing the parsing of Boot Services Application Event"); public final void testEvGptPartiton() throws IOException {
String event = IOUtils.toString(this.getClass().getResourceAsStream(EVENT_GPT_PARTITION), LOGGER.debug("Testing the parsing of Boot Services Application Event");
"UTF-8"); String event = IOUtils.toString(this.getClass().getResourceAsStream(EVENT_GPT_PARTITION),
byte[] eventBytes = HexUtils.hexStringToByteArray(event); "UTF-8");
EvEfiGptPartition partition = new EvEfiGptPartition(eventBytes); byte[] eventBytes = HexUtils.hexStringToByteArray(event);
ArrayList<UefiPartition> partitonList = partition.getPartitionList(); EvEfiGptPartition partition = new EvEfiGptPartition(eventBytes);
int partNumber = 1; ArrayList<UefiPartition> partitonList = partition.getPartitionList();
for (UefiPartition parition:partitonList) { int partNumber = 1;
UefiGuid guidPart = parition.getPartitionTypeGUID(); for (UefiPartition parition : partitonList) {
UefiGuid guidUnique = parition.getUniquePartitionGUID(); UefiGuid guidPart = parition.getPartitionTypeGUID();
String name = parition.getName(); UefiGuid guidUnique = parition.getUniquePartitionGUID();
if (partNumber == 1) { String name = parition.getName();
Assert.assertTrue(guidPart.toString(). if (partNumber == 1) {
contains("de94bba4-06d1-4d40-a16a-bfd50179d6a")); Assert.assertTrue(guidPart.toString().
Assert.assertTrue(guidUnique.toString(). contains("de94bba4-06d1-4d40-a16a-bfd50179d6a"));
contains("42cc8787-db23-4e45-9981-701adc801dc7")); Assert.assertTrue(guidUnique.toString().
Assert.assertEquals(name, "Basic data partition"); contains("42cc8787-db23-4e45-9981-701adc801dc7"));
} Assert.assertEquals(name, "Basic data partition");
if (partNumber == 2) { }
Assert.assertTrue(guidPart.toString(). if (partNumber == 2) {
contains("c12a7328-f81f-11d2-ba4b-00a0c93ec93b")); Assert.assertTrue(guidPart.toString().
Assert.assertTrue(guidUnique.toString(). contains("c12a7328-f81f-11d2-ba4b-00a0c93ec93b"));
contains("8ca7623c-041e-4fab-8c12-f49a86b85d73")); Assert.assertTrue(guidUnique.toString().
Assert.assertEquals(name, "EFI system partition"); contains("8ca7623c-041e-4fab-8c12-f49a86b85d73"));
} Assert.assertEquals(name, "EFI system partition");
if (partNumber++ == 3) { }
Assert.assertTrue(guidPart.toString(). if (partNumber++ == 3) {
contains("e3c9e316-0b5c-4db8-817d-f92df00215ae")); Assert.assertTrue(guidPart.toString().
Assert.assertTrue(guidUnique.toString(). contains("e3c9e316-0b5c-4db8-817d-f92df00215ae"));
contains("d890cfff-320c-4f45-b6cf-a4d8bee6d9cb")); Assert.assertTrue(guidUnique.toString().
Assert.assertEquals(name, "Microsoft reserved partition"); contains("d890cfff-320c-4f45-b6cf-a4d8bee6d9cb"));
Assert.assertEquals(name, "Microsoft reserved partition");
}
} }
} }
}
/** /**
* Tests the processing of a Hand off Table event. * Tests the processing of a Hand off Table event.
* @throws IOException when processing the test fails *
*/ * @throws IOException when processing the test fails
@Test */
public final void testHandOffTables() throws IOException { @Test
LOGGER.debug("Testing the Hand Off Tables Event Processing"); public final void testHandOffTables() throws IOException, URISyntaxException {
String event = IOUtils.toString(this.getClass(). LOGGER.debug("Testing the Hand Off Tables Event Processing");
getResourceAsStream(EVENT_HANDOFF_TABLES), "UTF-8"); String event = IOUtils.toString(this.getClass().
byte[] eventBytes = HexUtils.hexStringToByteArray(event); getResourceAsStream(EVENT_HANDOFF_TABLES), "UTF-8");
EvEfiHandoffTable hTable = new EvEfiHandoffTable(eventBytes); byte[] eventBytes = HexUtils.hexStringToByteArray(event);
Assert.assertEquals(hTable.getNumberOfTables(), 1); EvEfiHandoffTable hTable = new EvEfiHandoffTable(eventBytes,
String tableInfo = hTable.toString(); Paths.get(this.getClass().getResource(JSON_FILE).toURI()));
Assert.assertTrue(tableInfo.toString(). Assert.assertEquals(hTable.getNumberOfTables(), 1);
contains("UEFI industry standard table type = SMBIOS3_TABLE_GUID")); String tableInfo = hTable.toString();
} LOGGER.error(tableInfo);
Assert.assertTrue(tableInfo.
contains("UEFI industry standard table type = SMBIOS3_TABLE_GUID"));
}
/** /**
* Tests the processing of a Post Code event. * Tests the processing of a Post Code event.
* @throws IOException when processing the test fails *
*/ * @throws IOException when processing the test fails
@Test */
public final void testPostCode() throws IOException { @Test
LOGGER.debug("Testing the Post Code Event Processing"); public final void testPostCode() throws IOException {
String event = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_POST_CODE), "UTF-8"); LOGGER.debug("Testing the Post Code Event Processing");
byte[] eventBytes = HexUtils.hexStringToByteArray(event); String event = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_POST_CODE),
EvPostCode pCode = new EvPostCode(eventBytes); "UTF-8");
Assert.assertTrue(pCode.isString()); byte[] eventBytes = HexUtils.hexStringToByteArray(event);
String postCode = pCode.toString(); EvPostCode pCode = new EvPostCode(eventBytes);
Assert.assertEquals(postCode, "ACPI DATA"); Assert.assertTrue(pCode.isString());
} String postCode = pCode.toString();
Assert.assertEquals(postCode, "ACPI DATA");
}
} }