diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiBootOrder.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiBootOrder.java new file mode 100644 index 00000000..06e2291b --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiBootOrder.java @@ -0,0 +1,37 @@ +package hirs.tpm.eventlog.uefi; + +/** + * Class to process a UEFI BootOrder variable. + * UEFI spec version 2.8 section 3.3 on page 83 defines the Boot Order as: + * an array of UINT16s that make up an ordered list of the Boot#### options. + */ +public class UefiBootOrder { + /** list of UINT16 Boot#### numbers.*/ + private char[] bootOrder = null; + + /** + * Process the BootOrder UEFI variable. + * @param order byte array holding the UEFI boot order variable. + */ + UefiBootOrder(final byte[] order) { + bootOrder = new char[order.length / UefiConstants.SIZE_2]; + for (int i = 0; i < order.length; i = i + UefiConstants.SIZE_2) { + bootOrder[i / UefiConstants.SIZE_2] = + (char) (order[i + 1] * UefiConstants.SIZE_256 + order[i]); + } + } + +/** + * Provides a human readable Boot Order list on single line. + * @return A human readable Boot Order + */ +public String toString() { + StringBuffer orderList = new StringBuffer(); + orderList.append("BootOrder = "); + for (int i = 0; i < bootOrder.length; i++) { + int order = bootOrder[i]; + orderList.append(" Boot" + String.format("%04d", order)); + } + return orderList.toString(); + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiBootVariable.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiBootVariable.java new file mode 100644 index 00000000..9f7b1092 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiBootVariable.java @@ -0,0 +1,99 @@ +package hirs.tpm.eventlog.uefi; + +import java.io.UnsupportedEncodingException; +import java.util.Arrays; + +import hirs.utils.HexUtils; +/** + * Class to process a UEFI Boot#### variable. + * Data is defined using the EFI_LOAD_OptionStructure: + * typedef struct _EFI_LOAD_OPTION { + * UINT32 Attributes; + * UINT16 FilePathListLength; + * // CHAR16 Description[]; + * // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; + * // UINT8 OptionalData[]; + * } EFI_LOAD_OPTION; + * + * No length field for the Description is given + * so we need to calculate it by search for a null termination on the Description field + * Data following the Description should be an EFI Device Path + */ +public class UefiBootVariable { + /** Human readable description of the variable. */ + private String description = ""; + /** Variable attributes. */ + private byte[] attributes = null; + /** Firmware memory blob.*/ + private byte[] blob = null; + /** UEFI Device Path.*/ + private UefiDevicePath efiDevPath = null; + + /** + * UefiBootVariable Constructor. + * @param bootVar byte array holding the boot variable. + * @throws UnsupportedEncodingException if the data fails to parse. + */ +public UefiBootVariable(final byte[] bootVar) throws UnsupportedEncodingException { + attributes = new byte[UefiConstants.SIZE_4]; + System.arraycopy(bootVar, 0, attributes, 0, UefiConstants.SIZE_4); + byte[] blobLen = new byte[UefiConstants.SIZE_2]; + System.arraycopy(bootVar, UefiConstants.OFFSET_4, blobLen, 0, UefiConstants.SIZE_2); + int blobLength = HexUtils.leReverseInt(blobLen); + if (blobLength % UefiConstants.SIZE_2 == 0) { + blob = new byte[blobLength]; + } else { + blob = new byte[blobLength + 1]; + } + System.arraycopy(bootVar, UefiConstants.OFFSET_6, blob, 0, blobLength); + int descLength = getChar16ArrayLength(blob); + byte[] desc = new byte[descLength * UefiConstants.SIZE_2]; + System.arraycopy(bootVar, UefiConstants.OFFSET_6, desc, 0, descLength * UefiConstants.SIZE_2); + description = new String(UefiDevicePath.convertChar16tobyteArray(desc), "UTF-8"); + // Data following the Description should be EFI Partition Data (EFI_DEVICE_PATH_PROTOCOL) + int devPathLength = blobLength; + int devPathOffset = UefiConstants.OFFSET_6 + descLength; //attributes+bloblength+desc+length+2 + byte[] devPath = new byte[devPathLength]; + System.arraycopy(bootVar, devPathOffset, devPath, 0, devPathLength); + efiDevPath = new UefiDevicePath(devPath); +} + +/** + * Returns a string that represents a UEFI boot variable. + * Some devices have not properly terminated the Description filed with null characters + * so garbage bytes are appended to the string that we must strip off. + * All non-alpha numeric is stripped from the string. + * @return string that represents a UEFI boot variable. + */ +public String toString() { + String bootInfo = ""; + String bootvar = description.replaceAll("[^a-zA-Z_0-0\\s]", ""); // remove all non ascii chars + bootInfo += "Description = " + bootvar + "\n"; + bootInfo += efiDevPath.toString(); + return bootInfo; +} + +/** + * Searches for the first char16 based null character (2 bytes of zeros). + * Searches in a given byte array and returns the length of data up to that point in bytes. + * @param data a byte array to search for the data. + * @return the length of the data in bytes at the beginning of the byte array. + * which was terminated by a null character. + */ +public int getChar16ArrayLength(final byte[] data) { + int count = 0; + byte[] nullTerminitor = new byte[UefiConstants.SIZE_2]; + byte[] char16 = new byte[UefiConstants.SIZE_2]; + nullTerminitor[0] = 0; + nullTerminitor[1] = 0; + for (int i = 0; i < data.length; i = i + UefiConstants.SIZE_2) { + char16[0] = data[i]; + char16[1] = data[i + 1]; + count++; + if (Arrays.equals(nullTerminitor, char16)) { + return count * UefiConstants.SIZE_2; + } + } + return count * UefiConstants.SIZE_2 + 1; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiConstants.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiConstants.java new file mode 100644 index 00000000..33906100 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiConstants.java @@ -0,0 +1,122 @@ +package hirs.tpm.eventlog.uefi; + +/** + * This class contains the String constants that are referenced by UEFI. + * It is expected that member properties of this class will expand as + * more functionality is added. + */ +public final class UefiConstants { +/** + * Constructor. + */ + private UefiConstants() { + } + /** 2 byte size. */ + public static final int SIZE_2 = 2; + /** 4 byte size. */ + public static final int SIZE_4 = 4; + /** 5 byte size. */ + public static final int SIZE_5 = 5; + /** 8 byte size. */ + public static final int SIZE_8 = 8; + /** 16 byte size. */ + public static final int SIZE_16 = 16; + /** 20 byte size. */ + public static final int SIZE_20 = 20; + /** 28 byte size. */ + public static final int SIZE_28 = 28; + /** 32 byte size. */ + public static final int SIZE_32 = 32; + /** 40 byte size. */ + public static final int SIZE_40 = 40; + /** 256 byte size. */ + public static final int SIZE_256 = 256; + /** 1 byte offset. */ + public static final int OFFSET_1 = 1; + /** 2 byte offset. */ + public static final int OFFSET_2 = 2; + /** 3 byte offset. */ + public static final int OFFSET_3 = 3; + /** 4 byte offset. */ + public static final int OFFSET_4 = 4; + /** 6 byte offset. */ + public static final int OFFSET_6 = 4; + /** 8 byte offset. */ + public static final int OFFSET_8 = 8; + /** 16 byte offset. */ + public static final int OFFSET_16 = 16; + /** 20 byte offset. */ + public static final int OFFSET_20 = 20; + /** 24 byte offset. */ + public static final int OFFSET_24 = 24; + /** 28 byte offset. */ + public static final int OFFSET_28 = 28; + /** 28 byte offset. */ + public static final int OFFSET_32 = 32; + /** 40 byte offset. */ + public static final int OFFSET_40 = 40; + /** 41 byte offset. */ + public static final int OFFSET_41 = 41; + /** Device path terminator. */ + public static final int TERMINATOR = 0x7f; + /** Device path end flag. */ + public static final int END_FLAG = 0xff; + /** Device Type Hardware. */ + public static final int DEV_HW = 0x01; + /** Device Type ACPI. */ + public static final int DEV_ACPI = 0x02; + /** Device Type Messaging. */ + public static final int DEV_MSG = 0x03; + /** Device Type Media. */ + public static final int DEV_MEDIA = 0x04; + /** Device Type Hardware. */ + public static final int DEV_BIOS = 0x05; + /** Device Sub-Type Sata. */ + public static final int DEV_SUB_SATA = 0x12; + /** Device Sub-Type nvm. */ + public static final int DEV_SUB_NVM = 0x17; + /** BIOS Device Path reserved. */ + public static final int DEVPATH_BIOS_RESERVED = 0x0; + /** BIOS Device Path for Floppy disks. */ + public static final int DEVPATH_BIOS_FLOPPY = 0x01; + /** BIOS Device Path Hard drives. */ + public static final int DEVPATH_BIOS_HD = 0x02; + /** BIOS Device Path for CD Drives. */ + public static final int DEVPATH_BIOS_CD = 0x03; + /** BIOS Device Path for PCM CIA drives. */ + public static final int DEVPATH_BIOS_PCM = 0x04; + /** BIOS Device Path for USB Drives. */ + public static final int DEVPATH_BIOS_USB = 0x05; + /** BIOS Device Path for embedded network. */ + public static final int DEVPATH_BIOS_EN = 0x06; + /** BIOS Device Path for a Bootstrap Entry Vector (BEV) from an option ROM. */ + public static final int DEVPATH_BIOS_BEV = 0x80; + /** Hardware Device Path. */ + public static final int DEVPATH_HARWARE = 0x1; + /** 2 byte size. */ + public static final int DEVPATH_VENDOR = 0x03; + /** 2 byte size. */ + public static final int DEVPATH_FILE = 0x04; + /** PIWG File device path type. */ + public static final int DEVPATH_PWIG_FILE = 0x06; + /** PIWG Volume device path type. */ + public static final int DEVPATH_PWIG_VOL = 0x07; + /** PC-AT compatible legacy MBR. */ + public static final int DRIVE_TYPE_PC_AT = 0x01; + /** GUID Partition Table type. */ + public static final int DRIVE_TYPE_GPT = 0x02; + /** Drive Signature type. */ + public static final int DRIVE_SIG_NONE = 0x00; + /** Drive Signature type. */ + public static final int DRIVE_SIG_32BIT = 0x01; + /** Drive Signature type. */ + public static final int DRIVE_SIG_GUID = 0x02; + /** standard byte length. */ + public static final int BYTE_LENGTH = 8; + /** standard byte length. */ + public static final int ATTRIBUTE_LENGTH = 48; + /** standard byte length. */ + public static final int PART_NAME_LENGTH = 56; + /** standard UEFI partition table lengh. */ + public static final int UEFI_PT_LENGTH = 72; +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiDevicePath.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiDevicePath.java new file mode 100644 index 00000000..069736ea --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiDevicePath.java @@ -0,0 +1,441 @@ +package hirs.tpm.eventlog.uefi; + +import java.io.UnsupportedEncodingException; + +import hirs.utils.HexUtils; + +/** + * Class to process EFI_DEVICE_PATH_PROTOCOL which is referred to as the UEFI_DEVICE_PATH + * + * #define EFI_DEVICE_PATH_PROTOCOL_GUID \09576e91-6d3f-11d2-8e39-00a0c969723b + * typedef struct _EFI_DEVICE_PATH_PROTOCOL { + * UINT8 Type; + * UINT8 SubType; + * UINT8 Length[2]; + * } EFI_DEVICE_PATH_PROTOCOL; + * + * Where Type is defined in the UEFI spec section 10: + * Type 0x01 Hardware Device Path + * Type 0x02 ACPI Device Path + * Type 0x03 Messaging Device Path + * 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 + * + * 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. + * Without test patterns, the processing may lead to an un-handled exception + */ +public class UefiDevicePath { + /** UEFI Device path type. */ + private String type = ""; + /** UEFI Device path sub-type. */ + private String subType = ""; + /** UEFI Device path human readable description. */ + private String devPathInfo = ""; + /** UEFI Device path length. */ + private int length = 0; + +/** + * UEFI Device path constructor. + * @param path byte array holding device path data + * @throws UnsupportedEncodingException if path byte array contains unexpected values + */ + public UefiDevicePath(final byte[] path) throws UnsupportedEncodingException { + devPathInfo = processDevPath(path); + byte[] lengthBytes = new byte[UefiConstants.SIZE_2]; + System.arraycopy(path, UefiConstants.OFFSET_2, lengthBytes, 0, UefiConstants.OFFSET_2); + length = HexUtils.leReverseInt(lengthBytes); + } + +/** + * Returns the UEFI device type. + * @return uefi type + */ + public String getType() { + return type; + } + +/** + * Returns the UEFI device sub-type. + * @return uefi sub-type + */ + public String getSubType() { + return subType.trim(); + } + + /** + * Returns the UEFI device structure length. + * @return uefi device structure length + */ + public int getLegth() { + return length; + } + +/** + * Processes the UEFI device path. + * UEFI device path is a collection of EFI_DEVICE_PATH_PROTOCOL structures of variable length. + * length must be calculated for each device path and used as an offset. + * devPath is terminated by 07f and 0xff per the UEFi spec. + * @param path byte array holding the Device path + * @return Human readable string containing the device path description. + * @throws UnsupportedEncodingException + */ + private String processDevPath(final byte[] path) throws UnsupportedEncodingException { + StringBuffer pInfo = new StringBuffer(); + String devicePathInfo = ""; + int devLength = 0, pathOffset = 0; + boolean moreDev = true; + while (moreDev) { + Byte devPath = Byte.valueOf(path[pathOffset]); + if ((devPath.intValue() == UefiConstants.TERMINATOR) + || (devPath.intValue() == UefiConstants.END_FLAG)) { + moreDev = false; + break; + } + devicePathInfo = processDev(path, pathOffset); + if (devicePathInfo.contains("Unknown Device Path")) { + moreDev = false; + } + pInfo.append(devicePathInfo); + devLength = path[pathOffset + UefiConstants.OFFSET_3] * UefiConstants.SIZE_256 + + path[pathOffset + UefiConstants.OFFSET_2]; + pathOffset = pathOffset + devLength; + if (pathOffset >= path.length) { + moreDev = false; + } + } + return pInfo.toString(); +} + +/** + * Processes a specific UEFI device path, only limited set of types and subtypes are supported. + * Current types processed include Hardware Device Path, ACPI Device Path, + * Messaging Device Path, and Media Device Path. + * @param path + * @param offset + * @return human readable string representing the UEFI device path + * @throws UnsupportedEncodingException + */ + private String processDev(final byte[] path, final int offset) + throws UnsupportedEncodingException { + String devInfo = " "; + int devPath = path[offset]; + switch (path[0 + offset]) { + case UefiConstants.DEV_HW: type = "Hardware Device Path"; + if (devPath == UefiConstants.DEVPATH_HARWARE) { + devInfo += type + ": " + pciSubType(path, offset); + } + break; + case UefiConstants.DEV_ACPI: type = "ACPI Device Path"; + devInfo += type + ": " + 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); + } + if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEV_SUB_NVM) { + devInfo += type + ": " + nvmSubType(path, offset); + } + break; + case UefiConstants.DEV_MEDIA: type = "Media Device Path"; + if (path[offset + UefiConstants.OFFSET_1] == 0x01) { + devInfo += type + ": " + hardDriveSubType(path, offset); + } else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEVPATH_VENDOR) { + devInfo += type + ": " + vendorSubType(path, offset); + } else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEVPATH_FILE) { + devInfo += type + ": " + filePathSubType(path, offset); + } else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEVPATH_PWIG_FILE) { + devInfo += type + ": " + piwgFirmVolFile(path, offset); + } else if (path[offset + UefiConstants.OFFSET_1] == UefiConstants.DEVPATH_PWIG_VOL) { + devInfo += type + ": " + piwgFirmVolPath(path, offset); + } + break; + case UefiConstants.DEV_BIOS: type = "BIOS Device Path"; + devInfo += type + ": " + biosDevicePath(path, offset); + break; + case UefiConstants.TERMINATOR: devInfo += "End of Hardware Device Path"; + break; + default: type = "Unknown Device Path"; + devInfo = type; + } + devInfo += "\n"; + return devInfo; +} + +/** + * processes the ACPI UEFI device subtype. + * @param path + * @param offset + * @return acpi device info + */ +private String acpiSubType(final byte[] path, final int offset) { + String tmpType = ""; + switch (path[offset + UefiConstants.OFFSET_1]) { + case 0x01: tmpType = "(Short): "; + tmpType += acpiShortSubType(path, offset); + break; + case 0x02: tmpType = "Expanded ACPI Device Path"; break; + default: tmpType = "Invalid ACPI Device Path sub type"; + } + subType = tmpType; + return tmpType; +} + +/** + * Processes the ACPI short subtype. + * @param path + * @param offset + * @return short acpi info. + */ +private String acpiShortSubType(final byte[] path, final int offset) { + String tmpType = ""; + byte[] hid = new byte[UefiConstants.SIZE_4]; + System.arraycopy(path, UefiConstants.OFFSET_4 + offset, hid, 0, UefiConstants.SIZE_4); + tmpType += "_HID = " + HexUtils.byteArrayToHexString(hid); + System.arraycopy(path, 2 * UefiConstants.SIZE_4 + offset, hid, 0, UefiConstants.SIZE_4); + tmpType += "_UID = " + HexUtils.byteArrayToHexString(hid); + subType = tmpType; + return tmpType; +} + +/** + * Processes the PCI subType. + * @param path + * @param offset + * @return pci device info. + */ +private String pciSubType(final byte[] path, final int offset) { + String tmpType = "PCI: PCI Function Number = "; + tmpType += String.format("0x%x", path[offset + UefiConstants.SIZE_4]); + tmpType += " PCI Device Number = "; + tmpType += String.format("0x%x", path[offset + UefiConstants.SIZE_5]); + subType = tmpType; + return tmpType; +} + +/** + * processes the SATA sub type. + * @param path + * @param offset + * @return SATA drive info. + */ +private String sataSubType(final byte[] path, final int offset) { + String tmpType = "SATA: HBA Port Number = "; + byte[] data = new byte[UefiConstants.SIZE_2]; + System.arraycopy(path, UefiConstants.OFFSET_4 + offset, data, 0, UefiConstants.SIZE_2); + tmpType += HexUtils.byteArrayToHexString(data); + System.arraycopy(path, UefiConstants.OFFSET_6 + offset, data, 0, UefiConstants.SIZE_2); + tmpType += " Port Multiplier = " + HexUtils.byteArrayToHexString(data); + System.arraycopy(path, UefiConstants.OFFSET_8 + offset, data, 0, UefiConstants.SIZE_2); + tmpType += " Logical Unit Number = " + HexUtils.byteArrayToHexString(data); + subType = tmpType; + return tmpType; + } + +/** + * Processes the hard drive sub type. + * @param path + * @param offset + * @return hard drive info. + */ +private String hardDriveSubType(final byte[] path, final int offset) { + String tmpType = "Partition Number = "; + byte[] partnumber = new byte[UefiConstants.SIZE_4]; + System.arraycopy(path, UefiConstants.OFFSET_4 + offset, partnumber, 0, UefiConstants.SIZE_4); + tmpType += HexUtils.byteArrayToHexString(partnumber); + byte[] data = new byte[UefiConstants.SIZE_8]; + System.arraycopy(path, UefiConstants.OFFSET_8 + offset, data, 0, UefiConstants.SIZE_8); + tmpType += "Partition Start = " + HexUtils.byteArrayToHexString(data); + System.arraycopy(path, UefiConstants.OFFSET_16 + offset, data, 0, UefiConstants.SIZE_8); + tmpType += "Partition Size = " + HexUtils.byteArrayToHexString(data); + byte[] signature = new byte[UefiConstants.SIZE_16]; + System.arraycopy(path, UefiConstants.OFFSET_24 + offset, signature, 0, UefiConstants.SIZE_16); + tmpType += "Partition Signature = "; + if (path[UefiConstants.OFFSET_41 + offset] == UefiConstants.DRIVE_SIG_NONE) { + tmpType += "None"; + } else if (path[UefiConstants.OFFSET_41 + offset] == UefiConstants.DRIVE_SIG_32BIT) { + tmpType += HexUtils.byteArrayToHexString(signature); + } else if (path[UefiConstants.OFFSET_41 + offset] == UefiConstants.DRIVE_SIG_GUID) { + UefiGuid guid = new UefiGuid(signature); + tmpType += guid.toString(); + } else { + tmpType += "invalid partition signature type"; + } + tmpType += "Partition Format = "; + if (path[UefiConstants.OFFSET_40 + offset] == UefiConstants.DRIVE_TYPE_PC_AT) { + tmpType += "PC-AT compatible legacy MBR"; + } else if (path[UefiConstants.OFFSET_40 + offset] == UefiConstants.DRIVE_TYPE_GPT) { + tmpType += "GUID Partition Table"; + } else { + tmpType += "Invalid partition table type"; + } + subType = tmpType; + return tmpType; + } + +/** + * Process the File path sub type. + * @param path + * @param offset + * @return file path info. + * @throws UnsupportedEncodingException + */ +private String filePathSubType(final byte[] path, final int offset) + throws UnsupportedEncodingException { + String tmpType = "File Path = "; + byte[] lengthBytes = new byte[UefiConstants.SIZE_2]; + System.arraycopy(path, 2 + offset, lengthBytes, 0, UefiConstants.SIZE_2); + int subTypeLength = HexUtils.leReverseInt(lengthBytes); + byte[] filePath = new byte[subTypeLength]; + System.arraycopy(path, UefiConstants.OFFSET_4 + offset, filePath, 0, subTypeLength); + byte[] fileName = convertChar16tobyteArray(filePath); + tmpType += new String(fileName, "UTF-8"); + subType = tmpType; + return tmpType; +} + +/** + * Process a vendor sub-type 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. + * @param path + * @param offset + * @return vendor device info. + */ +private String vendorSubType(final byte[] path, final int offset) { + String tmpType = "Vendor Subtype GUID = "; + byte[] lengthBytes = new byte[UefiConstants.SIZE_2]; + System.arraycopy(path, UefiConstants.OFFSET_2 + offset, lengthBytes, 0, UefiConstants.SIZE_2); + int subTypeLength = HexUtils.leReverseInt(lengthBytes); + byte[] guidData = new byte[UefiConstants.SIZE_16]; + System.arraycopy(path, UefiConstants.OFFSET_4 + offset, guidData, 0, UefiConstants.SIZE_16); + UefiGuid guid = new UefiGuid(guidData); + tmpType += guid.toString() + " "; + if (subTypeLength - UefiConstants.SIZE_16 > 0) { + byte[] vendorData = new byte[subTypeLength - UefiConstants.SIZE_16]; + System.arraycopy(path, UefiConstants.OFFSET_20 + + offset, vendorData, 0, subTypeLength - UefiConstants.SIZE_16); + tmpType += " : Vendor Data = " + HexUtils.byteArrayToHexString(vendorData); + } else { + tmpType += " : No Vendor Data pesent"; + } + subType = tmpType; + return tmpType; +} + +/** + * Returns nvm device info. + * UEFI Specification, Version 2.8. + * Name space Identifier (NSID) and IEEE Extended Unique Identifier (EUI-64): + * See Links to UEFI Related Documents + * (http://uefi.org/uefi under the headings NVM Express Specification. + * @param path + * @param offset + * @return NVM device info. + */ +private String nvmSubType(final byte[] path, final int offset) { + String tmpType = "NVM Express Namespace = "; + byte[] lengthBytes = new byte[UefiConstants.SIZE_2]; + System.arraycopy(path, UefiConstants.OFFSET_2 + offset, lengthBytes, 0, UefiConstants.SIZE_2); + int subTypeLength = HexUtils.leReverseInt(lengthBytes); + byte[] nvmData = new byte[subTypeLength]; + System.arraycopy(path, UefiConstants.OFFSET_4 + offset, nvmData, 0, subTypeLength); + tmpType += HexUtils.byteArrayToHexString(nvmData); + subType = tmpType; + return tmpType; +} + +/** + * BIOS Device Type definition. + * From Appendix A of the BIOS Boot Specification. + * Only process the Device type. + * Status bootHandler pointer, and description String pointer are ignored. + * @param path byte array holding the device path. + * @return String that represents the UEFI defined BIOS Device Type. + */ +private String biosDevicePath(final byte[] path, final int offset) { + String devPath = "Legacy BIOS : Type = "; + byte devPathType = path[offset + 1]; + Byte pathType = Byte.valueOf(devPathType); + switch (pathType.intValue()) { + case UefiConstants.DEVPATH_BIOS_RESERVED: devPath += "Reserved"; break; + case UefiConstants.DEVPATH_BIOS_FLOPPY: devPath += "Floppy"; break; + case UefiConstants.DEVPATH_BIOS_HD: devPath += "Hard Disk"; break; + case UefiConstants.DEVPATH_BIOS_CD: devPath += "CD-ROM"; break; + case UefiConstants.DEVPATH_BIOS_PCM: devPath += "PCMCIA"; break; + case UefiConstants.DEVPATH_BIOS_USB: devPath += "USB"; break; + case UefiConstants.DEVPATH_BIOS_EN: devPath += "Embedded network"; break; + case UefiConstants.DEVPATH_BIOS_BEV: devPath += + "Bootstrap Entry Vector (BEV) from an Option ROM"; + break; + default: devPath += "Reserved"; + break; + } + subType = devPath; + return devPath; +} + +/** + * Returns PIWG firmware volume info. + * UEFI Specification, Version 2.8. + * PIWG Firmware File Section 10.3.5.6: + * Contents are defined in the UEFI PI Specification. + * @param path + * @param offset + * @return String that represents the PIWG Firmware Volume Path + */ +private String piwgFirmVolFile(final byte[] path, final int offset) { + String fWPath = "PIWG Firmware File "; + byte[] guidData = new byte[UefiConstants.SIZE_16]; + System.arraycopy(path, UefiConstants.OFFSET_4 + offset, guidData, 0, UefiConstants.SIZE_16); + UefiGuid guid = new UefiGuid(guidData); + fWPath += guid.toString(); + subType = fWPath; + return fWPath; +} + +/** + * Returns PIWG firmware file info. + * UEFI Specification, Version 2.8. + * PIWG Firmware Volume Section 10.3.5.7: + * Contents are defined in the UEFI PI Specification. + * @param path + * @param offset + * @return String that represents the PIWG Firmware Volume Path + */ +private String piwgFirmVolPath(final byte[] path, final int offset) { + String fWPath = "PIWG Firmware Volume "; + byte[] guidData = new byte[UefiConstants.SIZE_16]; + System.arraycopy(path, UefiConstants.OFFSET_4 + offset, guidData, 0, UefiConstants.SIZE_16); + UefiGuid guid = new UefiGuid(guidData); + fWPath += guid.toString(); + subType = fWPath; + return fWPath; +} + +/** + * Returns a string that represents the UEFi Device path. + * @return UEFi Device path. + */ +public String toString() { + return (devPathInfo); +} + +/** + * Converts from a char array to byte array. + * Removes the upper byte (typically set to 0) of each char. + * @param data Character array. + * @return byte array. + */ +public static byte[] convertChar16tobyteArray(final byte[] data) { + byte[] hexdata = new byte[data.length]; + int j = 0; + for (int i = 0; i < data.length; i = i + UefiConstants.SIZE_2) { + hexdata[j++] = data[i]; + } + return hexdata; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiFirmware.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiFirmware.java new file mode 100644 index 00000000..23f4e335 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiFirmware.java @@ -0,0 +1,73 @@ +package hirs.tpm.eventlog.uefi; + +import java.math.BigInteger; +import hirs.utils.HexUtils; + +/** + * Class to process the PFP defined UEFI_PLATFORM_FIRMWARE_BLOB structure. + * + * typedef struct tdUEFI_PLATFORM_FIRMWARE_BLOB { + * UEFI_PHYSICAL_ADDRESS BlobBase; + * UINT64 BlobLength; + * } UEFI_PLATFORM_FIRMWARE_BLOB; + */ +public class UefiFirmware { + private boolean berror = false; + /** byte array holding the firmwares physical address. */ + private byte[] physicalAddress = null; + /** byte array holding the uefi address length. */ + private byte[] addressLength = null; + /** uefi physical address. */ + private int blobAddress = 0; + /** uefi address length. */ + private int blobLength = 0; + + /** + * UefiFirmware constructor. + * @param blob byte array holding a Firmware Blob. + */ + public UefiFirmware(final byte[] blob) { + if (blob.length != UefiConstants.SIZE_16) { + berror = true; + } else { + physicalAddress = new byte[UefiConstants.SIZE_8]; + addressLength = new byte[UefiConstants.SIZE_8]; + System.arraycopy(blob, 0, physicalAddress, 0, UefiConstants.SIZE_8); + System.arraycopy(blob, UefiConstants.SIZE_8, addressLength, 0, UefiConstants.SIZE_8); + byte[] lelength = HexUtils.leReverseByte(addressLength); + BigInteger bigIntLength = new BigInteger(lelength); + blobLength = bigIntLength.intValue(); + byte[]leAddress = HexUtils.leReverseByte(physicalAddress); + BigInteger bigIntAddress = new BigInteger(leAddress); + blobAddress = bigIntAddress.intValue(); + } +} +/** + * Returns the uefi firmware blobs physical address. + * @return uefi firmware address. + */ +public int getPhysicalAddress() { + return blobAddress; + } +/** + * Returns the length of the blobs physical address. + * @return length of the address. + */ +public int getBlobLength() { + return blobLength; +} +/** + * Returns a description of the firmware blobs location. + * @return a description of the the firmware blobs location. + */ +public String toString() { + String blobInfo = ""; + if (!berror) { + blobInfo += " Platform Firwmare Blob Address = " + blobAddress; + blobInfo += " length = " + blobLength; + } else { + blobInfo += " Invalid Firmware Blob event encountered"; + } + return blobInfo; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiGuid.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiGuid.java new file mode 100644 index 00000000..d683bbe2 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiGuid.java @@ -0,0 +1,415 @@ +package hirs.tpm.eventlog.uefi; + +import java.math.BigInteger; +import java.util.UUID; + +import hirs.utils.HexUtils; + +/** + * Class to process GUID per the UEFI specification + * GUIDs are essentially UUID as defined by RFC-1422, however Microsoft refers to GUIDS. + */ +public class UefiGuid { + /** number of 100ns intervals since UUID Epoch. */ + private static final long UUID_EPOCH_INTERVALS = 0x01b21dd213814000L; + /** used for conversion to uuid time. */ + private static final int UUID_EPOCH_DIVISOR = 10000; + /** guid byte array. */ + private byte[] guid = new byte[UefiConstants.SIZE_16 ]; + /** UUID object. */ + private UUID uuid; + + /** + * UefiGUID constructor. + * @param guidBytes byte array holding a valid guid. + */ + public UefiGuid(final byte[] guidBytes) { + System.arraycopy(guidBytes, 0, guid, 0, UefiConstants.SIZE_16); + uuid = processGuid(guidBytes); + } + + /** 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 + * Matched uuids found in /sys/firmware/efi/efivars on Centos 7. + */ +private static UUID processGuid(final byte[] guid) { + byte[] msb1 = new byte[UefiConstants.SIZE_4]; + System.arraycopy(guid, 0, msb1, 0, UefiConstants.SIZE_4); + byte[] msb1r = HexUtils.leReverseByte(msb1); + byte[] msb2 = new byte[UefiConstants.SIZE_4]; + System.arraycopy(guid, UefiConstants.OFFSET_4, msb2, 0, UefiConstants.SIZE_4); + byte[] msb2r = HexUtils.leReverseByte(msb2); + byte[] msb2rs = new byte[UefiConstants.SIZE_4]; + System.arraycopy(msb2r, 0, msb2rs, UefiConstants.OFFSET_2, UefiConstants.SIZE_2); + System.arraycopy(msb2r, UefiConstants.OFFSET_2, msb2rs, 0, UefiConstants.SIZE_2); + byte[] msbt = new byte[UefiConstants.SIZE_8]; + System.arraycopy(msb1r, 0, msbt, 0, UefiConstants.SIZE_4); + System.arraycopy(msb2rs, 0, msbt, UefiConstants.OFFSET_4, UefiConstants.SIZE_4); + long msbl = new BigInteger(msbt).longValue(); + byte[] lsb = new byte[UefiConstants.SIZE_8]; + System.arraycopy(guid, UefiConstants.OFFSET_8, lsb, 0, UefiConstants.SIZE_8); + long lsbl = new BigInteger(lsb).longValue(); + UUID tmpUuid = new UUID(msbl, lsbl); + return tmpUuid; + } +/** + * Returns the standard GUID length. + * @return guid length + */ +public static int getGuidLength() { + return UefiConstants.SIZE_16; +} +/** + * Returns a String that represents a specification name referenced by the EFI_CONFIGURATION_TABLE + * VendorGUID field. For structure of EFI_CONFIGURATION_TABLE type, the UEFI specification + * has set of GUIDs published that represent standards that one can find further information on + * the configuration table being referenced. + * Refer to section 4.6 of UEFI spec v 2.8, page 101. + * + * @return A String of major UUID parameters + */ +@SuppressWarnings("checkstyle:methodlength") +public String getVendorTableReference() { + + String vendorRef = uuid.toString().toLowerCase(); + String reference = ""; + + switch (vendorRef) { + // UUIDS listed in the UEFI Specification + case "eb9d2d30-2d88-11d3-9a16-0090273fc14d": reference = "ACPI_TABLE_GUID"; break; + case "eb9d2d32-2d88-11d3-9a16-0090273fc14d": reference = "SAL_SYSTEM_TABLE_GUID"; break; + case "eb9d2d31-2d88-11d3-9a16-0090273fc14d": reference = "SMBIOS_TABLE_GUID"; break; + case "f2fd1544-9794-4a2c-992e-e5bbcf20e394": reference = "SMBIOS3_TABLE_GUID"; break; + case "eb9d2d2f-2d88-11d3-9a16-0090273fc14d": reference = "MPS_TABLE_GUID"; break; + case "8868e871-e4f1-11d3-bc22-0080c73c8881": reference = "EFI_ACPI_TABLE_GUID"; break; + case "87367f87-1119-41ce-aaec-8be01101f558": + reference = "EFI_JSON_CONFIG_DATA_TABLE_GUID "; break; + case "35e7a725-8dd2-4cac-8011-33cda8109056": + reference = "EFI_JSON_CAPSULE_DATA_TABLE_GUID"; break; + case "dbc461c3-b3de-422a-b9b4-9886fd49a1e5": + reference = "EFI_JSON_CAPSULE_RESULT_TABLE_GUID"; break; + case "77ab535a-45fc-624b-5560-f7b281d1f96e": reference = "EFI_VIRTUAL_DISK_GUID"; break; + case "3d5abd30-4175-87Ce-6d64-d2ADe523C4bb": reference = "EFI_VIRTUAL_CD_GUID"; break; + case "5Cea02c9-4d07-69d3-269f-4496Fbe096f9": + reference = "EFI_PERSISTENT_VIRTUAL_DISK_GUID"; break; + case "08018188-42cd-bb48-100f-5387D53ded3d": reference = "EFI_PERSISTENT_VIRTUAL_CD_GUID"; break; + + // DXE GUIds from https://github.com/linuxboot/linuxboot/blob/master/boards/qemu/image-files.txt + case "fc510ee7-ffdc-11d4-bd41-0080c73c8881": reference = "DXE Apriori-FVRECOVERY"; break; + case "1b45cc0a-156a-428a-62af-49864da0e6e6": reference = "PEI Apriori file name"; break; + case "80cf7257-87ab-47f9-a3fe-d50b76d89541": reference = "PcdDxe"; break; + case "b601f8c4-43b7-4784-95b1-f4226cb40cee": reference = "RuntimeDxe"; break; + case "f80697e9-7fd6-4665-8646-88e33ef71dfc": reference = "SecurityStubDxe"; break; + case "1a1e4886-9517-440e-9fde-3be44cee2136": reference = "CpuDxe"; break; + case "11a6edf6-a9be-426d-a6cc-b22fe51d9224": reference = "PciHotPlugInitDxe"; break; + case "128fb770-5e79-4176-9e51-9bb268a17dd1": reference = "PciHostBridgeDxe"; break; + case "93b80004-9fb3-11d4-9a3a-0090273fc14d": reference = "PCI Bus Driver - PciBusDxe"; break; + case "9b680fce-ad6b-4f3a-b60b-f59899003443": reference = "DevicePathDxe"; break; + case "f9d88642-0737-49bc-81b5-6889cd57d9ea": reference = "SmbiosDxe"; break; + case "4110465d-5ff3-4f4b-b580-24ed0d06747a": reference = "SmbiosPlatformDxe"; break; + case "9622e42c-8e38-4a08-9e8f-54f784652f6b": reference = "AcpiTableDxe"; break; + case "49970331-e3fa-4637-9abc-3b7868676970": reference = "AcpiPlatform"; break; + case "7e374e25-8e01-4fee-87f2-390c23c606cd": reference = "ACPI data"; break; + case "bdce85bb-fbaa-4f4e-9264-501a2c249581": reference = "S3SaveStateDxe"; break; + case "d9dcc5df-4007-435e-9098-8970935504b2": reference = "PlatformDxe"; break; + case "8657015b-ea43-440d-949a-af3be365c0fc": reference = "IoMmuDxe"; break; + case "cbd2e4d5-7068-4ff5-b462-9822b4ad8d60": reference = "VariableRuntimeDxe"; break; + + //PIWG Dxe driver Files (FvFile) + // from https://bugs.launchpad.net/ubuntu/+source/edk2/+bug/1272444 + case "70d57d67-7f05-494d-a014-b75d7345b700": reference = "Storage Security Command Driver"; break; + case "3acc966d-8e33-45c6-b4fe-62724bcd15a9": reference = "AHCI Bus Driver"; break; + case "67bbc344-84bc-4e5c-b4df-f5e4a00e1f3a": reference = "Host Controller Driver"; break; + case "86edaae5-073c-4c89-b949-8984ac8a55f3": reference = "MMC/SD Media Device Driver"; break; + case "9e863906-a40f-4875-977F-5b93ff237fc6": reference = "Serial Terminal Driver"; break; + case "a6cc6bc8-2ada-46C3-bba4-e99672CC9530": reference = "PCI Serial Driver"; break; + case "69fd8e47-a161-4550-b01a-5594ceb2b2b2": reference = "PCI IDE/ATAPI Bus Driver"; break; + case "51ccf399-4fdf-4e55-a45b-e123f84d456a": + reference = "Platform Console Management Driver"; break; + case "6b38f7b4-ad98-40e9-9093-aca2b5a253c4": reference = "Generic Disk I/O Driver"; break; + case "2d2e62cf-9ecf-43b7-8219-94e7fC713dfe": reference = "Usb Keyboard Driver"; break; + case "9fb4b4a7-42C0-4bcd-8540-9bcc6711f83e": reference = "Usb Mass Storage Driver"; break; + case "e3752948-b9a1-4770-90c4-df41c38986be": reference = "QEMU Video Driver"; break; + case "240612B7-a063-11d4-9a3a-0090273fc14d": reference = "Usb Bus Driver"; break; + case "bdfe430e-8F2a-4db0-9991-6f856594777e": reference = "Usb Ehci Driver"; break; + case "2fb92efa-2ee0-4bae-9eB6-7464125E1EF7": reference = "Usb Ehci Driver"; break; + case "a92cdb4b-82f1-4e0b-a516-8a655d371524": reference = "Virtio Network Driver"; break; + case "4579b72d-7ec4-4dd4-8486-083c86b182a7": reference = "iSCSI Driver"; break; + case "3b1deaB5-c75d-442e-9238-8e2ffb62b0bb": reference = "UEFI PXE Base Code Driver"; break; + case "6b6963ab-906d-4a65-a7ca-bd40e5d6af2b": reference = "UDP Network Service Driver"; break; + case "6d6963ab-906d-4a65-a7ca-bd40e5d6af4d": reference = "Tcp Network Service Driver"; break; + case "dc3641b8-2fa8-4ed3-bc1f-f9962a03454b": reference = "MTFTP4 Network Service Driver"; break; + case "9fb1a1f3-3b71-4324-b39a-745cbb015fff": reference = "IP4 Network Service Driver"; break; + case "26841bde-920a-4e7a-9Fbe-637f477143a6": + reference = "IP4 CONFIG Network Service Driver"; break; + case "94734718-0bbc-47fb-96a5-ee7a5ae6a2ad": reference = "DHCP Protocol Driver"; break; + case "529d3f93-e8e9-4e73-b1e1-bdf6a9d50113": reference = "ARP Network Service Driver "; break; + case "e4f61863-fe2c-4b56-a8d4-08519bc439df": reference = "VLAN Configuration Driver"; break; + case "a2f436ea-a127-4ef8-957c-8048606ff670": reference = "Simple Network Protocol Driver"; break; + case "961578fe-b6b7-44c3-af35-6bc705cd2b1f": reference = "FAT File System Driver"; break; + case "0abd8284-6da3-4616-971a-83a5148067ba": reference = "ISA Floppy Driver"; break; + case "3dc82376-637b-40a6-a8fc-a565417f2c38": reference = "PS/2 Keyboard Driver"; break; + case "93b80003-9fb3-11d4-9a3a-0090273fc14d": reference = "ISA Serial Driver"; break; + case "240612b5-a063-11d4-9a3a-0090273fc14a": reference = "ISA Bus Driver"; break; + case "99549f44-49bb-4820-b9d2-901329412d67": reference = "IDE Controller Init Driver"; break; + case "0a66e322-3740-4cce-ad62-bd172cecca35": reference = "Scsi Disk Driver"; break; + case "1fa1f39e-feff-4aae-bd7b-38a070a3b609": reference = "Partition Driver"; break; + case "9e863906-a40f-4875-977f-5b93ff237fc6": reference = "Serial Terminal Driver"; break; + case "cccb0c28-4b24-11d5-9a5a-0090273fc14d": reference = "Graphics Console Driver"; break; + case "408edcec-cf6d-477c-a5a8-b4844e3de281": reference = "Console Splitter Driver"; break; + case "fab5d4f4-83c0-4aaf-8480-442d11df6cea": reference = "Virtio SCSI Host Driver"; break; + case "11d92dfb-3Ca9-4f93-ba2e-4780ed3e03b5": reference = "Virtio Block Driver"; break; + case "33cb97af-6c33-4c42-986b-07581fa366d4": reference = "Block MMIO to Block IO Driver"; break; + // PIWG Volumes (Fv) + case "a881d567-6cb0-4eee-8435-2e72d33e45B5": reference = "PIWG Default Volume"; break; + + // UEFI UUIDS for Certificates + case "3c5766e8-269c-4e34-aa14-ed776e85b3b6":reference = "EFI_CERT_RSA2048_GUID"; break; + case "e2b36190-879b-4a3d-ad8d-f2e7bba32784":reference = "EFI_CERT_RSA2048_SHA256_GUID"; break; + case "c1c41626-504c-4092-aca9-41f936934328":reference = "EFI_CERT_SHA256_GUID"; break; + case "826ca512-cf10-4ac9-b187-be01496631bd":reference = "EFI_CERT_SHA1_GUID"; break; + case "67f8444f-8743-48f1-a328-1eaab8736080":reference = "EFI_CERT_RSA2048_SHA1_GUID"; break; + case "a5c059a1-94e4-4aa7-87b5-ab155c2bf072":reference = "EFI_CERT_X509_GUID"; break; + case "0b6e5233-a65c-44c9-9407-d9ab83bfc8bd":reference = "EFI_CERT_SHA224_GUID"; break; + case "ff3e5307-9fd0-48c9-85f1-8ad56c701e01":reference = "EFI_CERT_SHA384_GUID"; break; + case "093e0fae-a6c4-4f50-9f1b-d41e2b89c19a":reference = "EFI_CERT_SHA512_GUID"; break; + case "3bd2a492-96c0-4079-b420-fcf98ef103ed":reference = "EFI_CERT_X509_SHA256_GUID"; break; + case "7076876e-80c2-4ee6-aad2-28b349a6865b":reference = "EFI_CERT_X509_SHA384_GUID"; break; + case "446dbf63-2502-4cda-bcfa-2465d2b0fe9d":reference = "EFI_CERT_X509_SHA512_GUID"; break; + case "a7717414-c616-4977-9420-844712a735bf": + reference = "EFI_CERT_TYPE_RSA2048_SHA256_GUID"; break; + // UEFI defined variables + case "452e8ced-dfff-4b8c-ae01-5118862e682c": + reference = "EFI_CERT_EXTERNAL_MANAGEMENT_GUID"; break; + case "d719b2cb-3d3a-4596-a3bc-dad00e67656f":reference = "EFI_IMAGE_SECURITY_DATABASE_GUID"; break; + case "4aafd29d-68df-49ee-8aa9-347d375665a7":reference = "EFI_CERT_TYPE_PKCS7_GUID"; break; + case "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" :reference = "EFI System Partition"; break; + case "024DEE41-33E7-11D3-9D69-0008C781F39F" : + reference = "Partition containing a legacy MBR"; break; + // RHBoot UEFI Application UUIDs + // From listed in RHBoot (RHShim) https://github.com/rhboot/efivar/blob/master/src/guids.txt + case "0abba7dc-e516-4167-bbf5-4d9d1c739416":reference = "fwupdate:"; break; + case "3b8c8162-188c-46a4-aec9-be43f1d65697":reference = "ux_capsule"; break; + case "605dab50-e046-4300-abb6-3dd810dd8b23":reference = "RH_Shim"; break; + case "8be4df61-93ca-11d2-aa0d-00e098032b8c":reference = "EFI_Global_Variable"; break; + case "91376aff-cba6-42be-949d-06fde81128e8":reference = "GRUB"; break; + + // Partition Table GUIDs + case "0fc63daf-8483-4772-8e79-3d69d8477de4":reference = "Linux filesystem data"; break; + case "e6d6d379-f507-44c2-a23c-238f2a3df928": + reference = "Logical Volume Manager (LVM) partition"; break; + case "4f68bce3-e8cd-4db1-96e7-fbcaf984b709":reference = "Root partition (x86-64)"; break; + case "a19d880f-05fc-4d3b-a006-743f0f84911e":reference = "RAID partition "; break; + case "933ac7e1-2eb4-4f13-b844-0e14e2aef915":reference = "/home partition[ (x86-64)"; break; + case "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7":reference = "GPT Basic data partition"; break; + + // RHBoot Lenovo specific UUIDS + case "3cc24e96-22c7-41d8-8863-8e39dcdcc2cf":reference = "lenovo"; break; + case "82988420-7467-4490-9059-feb448dd1963":reference = "lenovo_me_config"; break; + case "f7e615b-0d45-4f80-88dc-26b234958560":reference = "lenovo_diag"; break; + case "665d3f60-ad3e-4cad-8e26-db46eee9f1b5":reference = "lenovo_rescue"; break; + case "721c8b66-426c-4e86-8e99-3457c46ab0b9":reference = "lenovo_setup"; break; + case "f46ee6f4-4785-43a3-923d-7f786c3c8479":reference = "lenovo_startup_interrupt"; break; + case "126a762d-5758-4fca-8531-201a7f57f850":reference = "lenovo_boot_menu"; break; + case "a7d8d9a6-6ab0-4aeb-ad9d-163e59a7a380":reference = "lenovo_diag_splash"; break; + // Company UUIDs (From Internet searches) + case "77fa9abd-0359-4d32-bd60-28f4e78f784b":reference = "Microsoft Inc."; break; + case "f5a96b31-dba0-4faa-a42a-7a0c9832768e":reference = "HPE Inc."; break; + case "2879c886-57ee-45cc-b126-f92f24f906b9":reference = "SUSE Certificate"; break; + case "70564dce-9afc-4ee3-85fc-949649d7e45c":reference = "Dell Inc."; break; + + // Intel GUIDS + case "bfcc0833-2125-42d1-8c6d-13821e23c078":reference = "Intel(R) Desktop Boards"; break; + case "80b3ad5b-9880-4af9-a645-e56a68be89de":reference = "Intel(R) CISD FW Update"; break; + +// Microsoft GUIDS + case "e3c9e316-0b5c-4db8-817d-f92df00215ae": + reference = "Microsoft Reserved Partition (MSR)"; break; + case "5808c8aa-7e8f-42e0-85d2-e1e90434cfb3": + reference = "Logical Disk Manager (LDM) metadata partition "; break; + case "af9b60a0-1431-4f62-bc68-3311714a69ad": + reference = "Logical Disk Manager data partition"; break; + case "de94bba4-06d1-4d40-a16a-bfd50179d6ac":reference = "Windows Recovery Environment"; break; + case "9f25ee7a-e7b7-11db-94b5-f7e662935912":reference = "Windows Boot Loader"; break; + + // Linux specific GUIDS + case "0fc63daf-8483-4772-8e79-3d69d8477de":reference = "Linux filesystem data"; break; + case "44479540-f297-41b2-9af7-d131d5f0458a4":reference = "Root partition (x86)"; break; + case "69dad710-2ce4-4e3c-b16c-21a1d49abed3":reference = "Root partition (32-bit ARM)"; break; + case "b921b045-1df0-41c3-af44-4c6f280d3fae": + reference = "Root partition (64-bit ARM/AArch64)"; break; + case "0657fd6d-a4ab-43c4-84e5-0933c84b4f4f":reference = "Swap partition"; break; + case "3b8f8425-20e0-4f3b-907f-1a25a76f98e8":reference = "/srv (server data) partition"; break; + case "7ffec5c9-2d00-49b7-8941-3ea10a5586b7":reference = "Plain dm-crypt partitiont"; break; + case "ca7d7ccb-63ed-4c53-861c-1742536059cc":reference = "LUKS partition"; break; + + // Linux Boot GUIDS + // https://github.com/linuxboot/linuxboot/blob/master/boards/s2600wf/vendor-files.txt + case "9cfd802c-09a1-43d6-8217-aa49c1f90d2c": + reference = "Intel Management Engine BIOS Extension (Mebx)"; break; + case "b62efbbb-3923-4cb9-a6e8-db818e828a80": + reference = "Intel Management Engine BIOS Extension (Mebx) Setup Browser"; break; + case "9ce4325e-003e-11e3-b582-b8ac6f199a57": + reference = "Non-Volatile Dual In-line Memory Module (NVDIMM) Driver"; break; + case "ea9de6d5-7839-46f7-9e63-4de8b00e2e5d": + reference = "NVM DIMM Human Interface Infrastructure (HII)"; break; + case "56a1b86f-0d4a-485d-87de-ad0eba1c8c2a":reference = "IBM C Video Gop"; break; + case "a1f436ea-a127-4ef8-957c-8048606ff670":reference = "SnpDxe"; break; + case "a210f973-229d-4f4d-aa37-9895e6c9eaba":reference = "DpcDxe"; break; + case "025bbfc7-e6a9-4b8b-82ad-6815a1aeaf4a": + reference = "MNP Network Service Driver - MnpDxe"; break; + case "b44b2005-42bc-41c9-80af-abd7dc7d6923":reference = "RSTesSATAEFI"; break; + case "15e1e31a-9f9d-4c84-82fb-1a707fc0f63b":reference = "RSTeSATAEFI"; break; + case "2cc25173-bd9f-4c89-89cc-29256a3fd9c3":reference = "RSTesSATALegacy"; break; + case "bd5d4ca5-674f-4584-8cf9-ce4ea1f54dd1":reference = "RSTeSATALegacy"; break; + + // WinNt GUIDs, add if they are still found in use + //https://sourceforge.net/p/uefinotes/wiki/FV%20Sources/?version=3 + case "fc5c7020-1a48-4198-9be2-ead5abc8cf2f":reference = "BdsDxe"; break; + case "d0893f05-b06d-4161-b947-9be9b85ac3a1":reference = "SnpNt32Dxe"; break; + case "9b3ada4f-ae56-4c24-8Dea-f03b7558ae50":reference = "PcdPeim"; break; + case "34c8c28F-b61c-45a2-8f2e-89e46becc63b":reference = "PeiVariable"; break; + case "fe5cea76-4f72-49e8-986f-2cd899dffe5d":reference = "FaultTolerantWriteDxe"; break; + + // Linux Boot Image files + // UEFI Platform Initialization (PI) specifications + // Driver Execution Environment (DXE) Architectural protocols and platform modules + //https://github.com/linuxboot/linuxboot/blob/master/boards/winterfell/image-files.txt + case "5ae3f37e-4eae-41ae-8240-35465b5e81eb":reference = "CORE_DXE"; break; + case "cbc59c4a-383a-41eb-a8ee-4498aea567e4":reference = "DXE Runtime"; break; + case "3c1de39f-d207-408a-aacc-731cfb7f1dd7":reference = "DXE PciBus"; break; + case "80e66e0a-ccd1-43fa-a7b1-2d5ee0f13910":reference = "DXE PciRootBridge"; break; + case "9f3a0016-ae55-4288-829d-d22fd344c347":reference = "DXE AmiBoardInfo"; break; + case "13ac6dd0-73d0-11d4-b06b-00aa00bd6de7":reference = "DXE EBC"; break; + case "e03abadf-e536-4e88-b3a0-b77f78eb34fe":reference = "CPU DXE"; break; + case "b7d19491-e55a-470d-8508-85a5dfa41974":reference = "SBDXE"; break; + case "e23f86e1-056e-4888-b685-cfcd67c179d4":reference = "DXE SBRun"; break; + case "e4ecd0b2-e277-4f2b-becb-e4d75c9a812e":reference = "NBDXE"; break; + case "5ad34ba6-f024-2149-52e4-da0398e2bb9" :reference = "DXE Services Table"; break; + // ACPI configuration and tables + case "750890a6-7acf-4f4f-81bd-b400c2bea95a":reference = "AcpiModeEnable"; break; + case "d4c05cd1-5eae-431d-a095-13a9e5822045":reference = "MPST"; break; + case "db93cb2c-bf1c-431a-abc8-8737bc2afc1f":reference = "PRAD-ACPI-table"; break; + case "3bc5b795-a4e0-4d56-9321-316d18a7aefe":reference = "PRAD"; break; + case "16d0a23e-c09c-407d-a14a-ad058fdd0ca1":reference = "ACPI"; break; + case "26a2481e-4424-46a2-9943-cc4039ead8f8":reference = "S3Save"; break; + case "efd652cc-0e99-40f0-96c0-e08c089070fc":reference = "S3Restore"; break; + case "8c783970-f02a-4a4d-af09-8797a51eec8d":reference = "PowerManagement"; break; + case "299141bb-211a-48a5-92c0-6f9a0a3a006e0":reference = "PowerManagement-ACPI-table"; break; + case "2df10014-cf21-4280-8c3f-e539b8ee5150":reference = "PpmPolicyInitDxe"; break; + case "4b680e2d-0d63-4f62-b930-7ae995b9b3a3":reference = "SmBusDxe"; break; + // SMM handlers + case "4a37320b-3fb3-4365-9730-9e89c600395d":reference = "SmmDispatcher"; break; + case "753630c9-fae5-47a9-bbbf-88d621cd7282":reference = "SmmChildDispatcher"; break; + case "be216ba8-38c4-4535-a6ca-5dca5b43addf":reference = "SmiVariable"; break; + case "a56897a1-a77f-4600-84db-22b0a801fa9a":reference = "SmmRuntime"; break; + case "d2596f82-f0e1-49fa-95bc-62012c795728":reference = "SmmBase Data"; break; + case "69009842-63f2-43db-964b-efad1c39ec85":reference = "SmmBase Data"; break; + case "d0632c90-afd7-4492-b186-257c63143c61":reference = "SmmBase"; break; + case "7e2d983f-f703-4a29-9761-77b51f5354ed":reference = "SmmCommunicate"; break; + // CMOS and NVRAM handlers + case "6869c5b3-ac8d-4973-8b37-e354dbf34add":reference = "CmosManagerSmm"; break; + case "842a454a-75e5-408b-8b1c-36420e4e3f21":reference = "NvramSmi"; break; + case "5446c293-339b-47cd-b719-585de39408cc":reference = "PostReport"; break; + case "71ca9ca1-325d-4bfe-afa3-2ec5c94a8680":reference = "DmAcpi"; break; + case "cef68c66-06ab-4fb3-a3ed-5ffa885b5725":reference = "SMBiosBoard"; break; + case "b13edd38-684c-41ed-a305-d7b7e32497df":reference = "SMBios64"; break; + case "ded7956d-7e20-4f20-91a1-190439b04d5b":reference = "SmbiosGetFlashData64"; break; + case "daf4bf89-ce71-4917-b522-c89d32fbc59f":reference = "SmbiosStaticData"; break; + // Apple GUIDS + case "48465300-0000-11aa-aa11-00306543ecac": + reference = "Apple Hierarchical File System Plus (HFS+) partition "; break; + case "7c3457ef-0000-11aa-aa11-00306543ecac":reference = "Apple APFS container"; break; + case "55465300-0000-11aa-aa11-00306543ecac":reference = "Apple UFS container"; break; + case "52414944-0000-11aa-aa11-00306543ecac":reference = "Apple RAID partition"; break; + case "4c616265-6c00-11aa-aa11-00306543ecac":reference = "Apple Label"; break; + case "53746f72-6167-11aa-aa11-00306543ecac":reference = "Apple Core Storage Container"; break; + case "6a898cc3-1dd2-11b2-99a6-080020736631":reference = "ZFS Partition"; break; + + // Chrome OS GUIDS + case "2568845d-2332-4675-bc39-8fa5a4748d15":reference = "Chrome OS kernel "; break; + case "3cb8e202-3b7e-47dd-8a3c-7ff2a13cfcec":reference = "Chrome OS rootfs "; break; + case "2e0a753d-9e48-43b0-8337-b15192cb1b5e":reference = "Chrome OS future use "; break; + + // Android GUIDS + case "fe3a2a5d-4f32-41a7-b725-accc3285a309":reference = "Android Bootloader"; break; + case "114eaffe-1552-4022-b26e-9b053604cf84":reference = "Android Bootloader 2"; break; + case "49a4d17f-93a3-45c1-a0de-f50b2ebe2599":reference = "Android Boot"; break; + case "4177c722-9e92-4aab-8644-43502bfd5506":reference = "Android Recovery"; break; + case "38f428e6-d326-425d-9140-6e0ea133647c":reference = "Android System"; break; + case "bd59408b-4514-490d-bf12-9878d963f378":reference = "Android Config"; break; + case "8f68cc74-c5e5-48da-be91-a0c8c15e9c80":reference = "Android Factory"; break; + case "ac6d7924-eb71-4df8-b48d-e267b27148ff":reference = "Android OEM"; break; + + // MISC GUIDs + case "5023b95c-db26-429b-a648-bd47664c8012":reference = "Built-in EFI Shell"; break; + case "610a0202-d308-00c4-0000-000004300d06":reference = "Mystery UUID"; break; + case "00000000-0000-0000-0000-000000000000":reference = "Empty UUID"; break; + + default: reference = "Unknown GUID reference"; + } + return reference; + } + +/** + * Returns a string of the entity that the UUID represents. + * Contains a Vendor String lookup on the UUID. + * @return UUID description. + */ +public String toString() { + String guidinfo = ""; + guidinfo = uuid.toString() + " : " + getVendorTableReference(); + return guidinfo; + } + +/** + * Returns a string of the entity that the UUID represents. + * Does not contain a vendor lookup on the UUID. + * @return UUID description. + */ +public String toStringNoLookup() { + return uuid.toString(); +} +/** + * Returns a string of the entity that the UUID represents. + * Does not contain a vendor lookup on the UUID. + * @param guid byte array holding the guid data. + * @return true if the UUID has a valid structure. + */ +public static boolean isValidUUID(final byte[] guid) { + boolean valid = false; + UUID tmpUuid = processGuid(guid); + if (tmpUuid.toString().length() != 0) { + valid = true; + } + return (valid); + } + +/** + * Checks to see if the uuid is the test or Empty UUID ("00000000-0000-0000-0000-000000000000"). + * @return true if the uuid is the Empty UUID, false if not + */ +public boolean isEmptyUUID() { + return uuid.toString().equals("00000000-0000-0000-0000-000000000000"); + } + +/** + * Checks to see if the uuid is the Empty UUID or an unknown. + * @return true if the uuid is the Empty UUID, false if not + */ +public boolean isUnknownUUID() { + if (getVendorTableReference().equals("Unknown GUID reference")) { + return true; + } + return false; + } + +/** + * Retrieves the timestamp within a time based GUID. + * @param uuid uuid object + * @return long representing the time stamp from the GUID + */ +public long getTimeFromUUID(final UUID uuid) { + return (uuid.timestamp() - UUID_EPOCH_INTERVALS) / UUID_EPOCH_DIVISOR; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiPartition.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiPartition.java new file mode 100644 index 00000000..c903dfba --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiPartition.java @@ -0,0 +1,110 @@ +package hirs.tpm.eventlog.uefi; + +import java.io.UnsupportedEncodingException; + +import hirs.utils.HexUtils; +/** + * Class to process EFI Partitions for EFI Partition tables defined in UEFI section 5.3.3 + * typedef struct { + * EFI_GUID PartitionTypeGUID; + * EFI_GUID UniquePartitionGUID; + * EFI_LBA StartingLBA; // Same as UINT64. + * EFI_LBA EndingLBA; + * UINT64 Attributes; + * CHAR16 PartitionName[36]; // 36 CHAR16 = 72 Bytes + * } EFI_PARTITION_ENTRY; + * + * UEFI Table 23. Defined GPT Partition Entry - Partition Type GUIDs (implemented in EFIGui.java) + * Examples: + * Unused Entry 00000000-0000-0000-0000-000000000000 + * EFI System Partition C12A7328-F81F-11D2-BA4B-00A0C93EC93B + * Partition containing a legacy MBR 024DEE41-33E7-11D3-9D69-0008C781F39F + * Linux filesystem data 0FC63DAF-8483-4772-8E79-3D69D8477DE4 + * Logical Volume Manager (LVM) partition E6D6D379-F507-44C2-A23C-238F2A3DF928 + * Plain dm-crypt partition 7FFEC5C9-2D00-49B7-8941-3EA10A5586B7 + * Root partition (x86-64) 4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709 + * RAID partition A19D880F-05FC-4D3B-A006-743F0F84911E + * LUKS partition CA7D7CCB-63ED-4C53-861C-1742536059CC + * + * linux commands to check uuids: + * blkid list //unique parition guids + * ls /dev/disk/by-partuuid + */ +public class UefiPartition { + private UefiGuid partitionTypeGUID = null; + private UefiGuid uniquePartitionGUID = null; + private String partitionName = ""; + private String attributes = ""; + +/** + * Processes a UEFI defined partition entry. + * @param table byte array holding the partition table. + * @throws UnsupportedEncodingException if parsing of the data fails. + */ + public UefiPartition(final byte[] table) throws UnsupportedEncodingException { + byte[] partitionGUID = new byte[UefiGuid.getGuidLength()]; + System.arraycopy(table, 0, partitionGUID, 0, UefiGuid.getGuidLength()); + partitionTypeGUID = new UefiGuid(partitionGUID); + byte[] uniquePartGUID = new byte[UefiGuid.getGuidLength()]; + System.arraycopy(table, UefiGuid.getGuidLength(), uniquePartGUID, 0, UefiGuid.getGuidLength()); + uniquePartitionGUID = new UefiGuid(uniquePartGUID); + byte[] attribute = new byte[UefiConstants.SIZE_8]; + System.arraycopy(table, UefiConstants.ATTRIBUTE_LENGTH, attribute, 0, UefiConstants.SIZE_8); + attributes = HexUtils.byteArrayToHexString(attribute); + byte[] partitionname = new byte[UefiConstants.UEFI_PT_LENGTH]; + System.arraycopy(table, UefiConstants.PART_NAME_LENGTH, partitionname, + 0, UefiConstants.UEFI_PT_LENGTH); + byte[] pName = convertChar16tobyteArray(partitionname); + partitionName = new String(pName, "UTF-8").trim(); + } + +/** + * Returns the partition Type GIUD. + * @return the partition type GUID. + */ +public UefiGuid getPartitionTypeGUID() { + return partitionTypeGUID; +} +/** + * Returns the unique partition GUID. + * @return the unique partition GUID. + */ +public UefiGuid getUniquePartitionGUID() { + return uniquePartitionGUID; +} + +/** + * Returns the partition name. + * @return the partition name. + */ +public String getName() { + return partitionName; + } + +/** + * Returns a description of the partition. + * @return partition description. + */ +public String toString() { + String partitionInfo = ""; + partitionInfo += " Partition Name : " + partitionName + "\n"; + partitionInfo += " Partition Type GUID : " + partitionTypeGUID.toString() + "\n"; + partitionInfo += " Unique Partition GUID : " + uniquePartitionGUID.toStringNoLookup() + "\n"; + partitionInfo += " Attributes : " + attributes + "\n"; + return partitionInfo; + } + +/** + * Copies character array to a byte by removing upper byte of character array. + * @param data input char array + * @return byte array + */ +private byte[] convertChar16tobyteArray(final byte[] data) { + byte[] hexdata = new byte[data.length]; + int j = 0; + for (int i = 0; i < data.length; i = i + 2) { + hexdata[j++] = data[i]; + } + return hexdata; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiSecureBoot.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiSecureBoot.java new file mode 100644 index 00000000..017968e6 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiSecureBoot.java @@ -0,0 +1,55 @@ +package hirs.tpm.eventlog.uefi; + +import java.math.BigInteger; + +/** + * Class that processes the UEFI defined SecureBoot Variable. + * Currently this variable only specifies if SecureBoot is on/off. + */ +public class UefiSecureBoot { + /** Variable value. */ + private int secureBootVar = 0; + /** Error flag.*/ + private boolean berror = false; + /** Human readable description. */ + private String info = ""; + +/** + * Constructor to process the EFI Secure Boot Variable. + * @param data UEFI variable data. + */ +public UefiSecureBoot(final byte[] data) { + if (data.length == 0) { + berror = true; + info = "Unkown State: Empty Secure Boot variable\n"; + } else { + secureBootVar = new BigInteger(data).intValue(); + } + } + +/** + * Return the value of the Secure Boot Variable. + * Current defined values are 1 = On and 0=off. + * @return Integer value of the Secure Boot Variable. + */ +public int getSecurBootVariable() { + return secureBootVar; +} + +/** + * Provides a human readable value for the Secure Boot variable. + * @return Human readable description. + */ +public String toString() { + if (!berror) { + if (secureBootVar == 1) { + info += " Secure Boot is enabled \n"; + } else if (secureBootVar == 0) { + info += " Secure Boot is NOT enabled \n"; + } else { + info += " Unkown State: Secure Variable is undefined \n"; + } + } + return info; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiSignatureData.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiSignatureData.java new file mode 100644 index 00000000..4db7a1f5 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiSignatureData.java @@ -0,0 +1,186 @@ +package hirs.tpm.eventlog.uefi; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; + +import hirs.utils.HexUtils; + +/** + * 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 + * + * typedef struct _EFI_SIGNATURE_DATA { + * EFI_GUID SignatureOwner; + * UINT8 SignatureData[...]; + * } EFI_SIGNATURE_DATA; + * + * However page 1729 0f UEFI 2.8 implies that SignatureListType of EFI_CERT_SHA256_GUID + * will contain the "the SHA-256 hash of the binary". + * So the Signature Data depends upon the Signature Type from the EFI Signature List. + */ +public class UefiSignatureData { + /** UEFI Certificate GUID.*/ + private byte[] guid = new byte[UefiConstants.SIZE_16]; + /** UEFI Signature data.*/ + private byte[] sigData = null; + /** UEFI Certificate object .*/ + private UefiX509Cert cert = null; + /** UEFI Certificate GUID.*/ + private UefiGuid efiGuid = null; + /** UEFI Signature type.*/ + private UefiGuid signatureType = null; + /** UEFI Signature validity.*/ + private boolean valid = false; + /** UEFI Certificate SHA1 hash.*/ + private byte[] binaryHash = new byte[UefiConstants.SIZE_40]; + /** UEFI Signature data status.*/ + private String status = "Signature Data contians a valid Certificate"; + +/** + * UefiSignatureData constructor. + * @param inputStream The Signature data. + * @param sigType UEFI defined signature type. + * @throws IOException if there's an problem reading the input stream. + * @throws CertificateException If there a problem parsing the X509 certificate. + * @throws NoSuchAlgorithmException if there's a problem hashing the certificate. + */ +UefiSignatureData(final ByteArrayInputStream inputStream, final UefiGuid sigType) + throws IOException, CertificateException, NoSuchAlgorithmException { + signatureType = sigType; + // UEFI spec section 32.5.3.3 states that SignatureListType of EFI_CERT_SHA256_GUID + // only contains a hash, not a cert + if (sigType.getVendorTableReference().equals("EFI_CERT_SHA256_GUID")) { + inputStream.read(guid); + efiGuid = new UefiGuid(guid); + // Should be a SHA256 hash of the "binary" + inputStream.read(binaryHash); + } else if (sigType.getVendorTableReference().equals("EFI_CERT_X509_GUID")) { + inputStream.read(guid); + efiGuid = new UefiGuid(guid); + // Read in Type and Length separately so we calculate the rest of the cert size + byte[] certType = new byte[UefiConstants.SIZE_2]; + inputStream.read(certType); + byte[] certLength = new byte[UefiConstants.SIZE_2]; + inputStream.read(certLength); + int cLength = new BigInteger(certLength).intValue() + UefiConstants.SIZE_4; + byte[] certData = new byte[cLength]; + inputStream.read(certData); + // put the cert back together + byte[] certBlob = new byte[cLength + UefiConstants.SIZE_4]; + System.arraycopy(certType, 0, certBlob, 0, UefiConstants.SIZE_2); + System.arraycopy(certLength, 0, certBlob, UefiConstants.OFFSET_2, UefiConstants.SIZE_2); + System.arraycopy(certData, 0, certBlob, UefiConstants.OFFSET_4, cLength); + cert = new UefiX509Cert(certBlob); + } else if (sigType.isUnknownUUID()) { + //status = "Signature List Type has an unknown GUID: " + efiGuid.toString(); + status = "Signature List Type has an unknown GUID"; + return; + } else { // else process as a cert (RH SHIM does this) + processC509Cert(inputStream); + efiGuid = sigType; + } + valid = true; +} + +/** + * Default EFISignatureData Constructor. + * @param data byte array of the EFISignatureData to process + * @throws CertificateException If there a problem parsing the X509 certificate. + * @throws NoSuchAlgorithmException if there's a problem hashing the certificate. + */ +UefiSignatureData(final byte[] data) throws CertificateException, NoSuchAlgorithmException { + System.arraycopy(data, 0, guid, 0, UefiConstants.SIZE_16); + sigData = new byte[data.length - UefiConstants.SIZE_16]; + System.arraycopy(data, UefiConstants.OFFSET_16, sigData, 0, data.length - UefiConstants.SIZE_16); + cert = new UefiX509Cert(sigData); + efiGuid = new UefiGuid(guid); +} + +/** + * Processes an x509 Cert used by secure DB or DBx. + * @param inputStream x509 certificate data. + * @throws IOException is there's a problem reading the data. + * @throws CertificateException if there's a problem parsing the certificate. + * @throws NoSuchAlgorithmException if there's a problem creating a hash. + */ +private void processC509Cert(final ByteArrayInputStream inputStream) + throws IOException, CertificateException, NoSuchAlgorithmException { + byte[] certType = new byte[UefiConstants.SIZE_2]; + inputStream.read(certType); + byte[] certLength = new byte[UefiConstants.SIZE_2]; + inputStream.read(certLength); + int cLength = new BigInteger(certLength).intValue() + UefiConstants.SIZE_4; + byte[] certData = new byte[cLength]; + inputStream.read(certData); + // put the cert back together + byte[] certBlob = new byte[cLength + UefiConstants.SIZE_4]; + System.arraycopy(certType, 0, certBlob, 0, 2); + System.arraycopy(certLength, 0, certBlob, 2, 2); + System.arraycopy(certData, 0, certBlob, UefiConstants.OFFSET_4, cLength); + cert = new UefiX509Cert(certBlob); +} + +/** + * Efi GUID of the signature owner. + * @return EFIGuid object + */ +public UefiGuid getEfiVarGuid() { + return efiGuid; +} + +/** + * Returns the signature type. + * @return Guid: either EFI_CERT_SHA256_GUID or EFI_SHA256_GUID + */ +public UefiGuid getSignatureType() { + return signatureType; +} + +/** + * Returns a X509 Certificate object which is created from the sign data. + * @return X509Cert Object + */ +public UefiX509Cert getCert() { + return cert; +} + +/** + * Checks if EFI Signature/Certificate is valid. + * @return true if EFI Signature is valid + */ +public boolean isValid() { + return valid; +} + +/** + * Retrieves the last status of the object. + * @return String with the latest status on this object. + */ +public String getStatus() { + return status; +} + +/** + * Provides a description of the fields within the EFI Signature Data. + * @return X509Cert human readable description. + */ +public String toString() { + String sigInfo = ""; + if (!valid) { + sigInfo = status; + } else { + if (signatureType.getVendorTableReference().equals("EFI_CERT_SHA256_GUID")) { + sigInfo += "UEFI Signature Owner = " + efiGuid.toString() + "\n"; + sigInfo += "Binary Hash = " + HexUtils.byteArrayToHexString(binaryHash) + "\n"; + } else { + sigInfo += "UEFI Signature Owner = " + efiGuid.toString() + "\n"; + sigInfo += cert.toString(); + } + } + return sigInfo; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiSignatureList.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiSignatureList.java new file mode 100644 index 00000000..d2686461 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiSignatureList.java @@ -0,0 +1,204 @@ +package hirs.tpm.eventlog.uefi; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.ArrayList; + +import hirs.utils.HexUtils; + +/** + * 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. + * + * 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. + * + * typedef struct _EFI_SIGNATURE_LIST { + * EFI_GUID SignatureType; + * UINT32 SignatureListSize; + * UINT32 SignatureHeaderSize; + * UINT32 SignatureSize; + * // UINT8 SignatureHeader[SignatureHeaderSize]; + * // EFI_SIGNATURE_DATA Signatures[...][SignatureSize]; + * } EFI_SIGNATURE_LIST; + * + */ +public class UefiSignatureList { + /** Size of the signature list.*/ + private int listSize = 0; + /** Size of a signature. */ + private int signatureSize = 0; + /** Signature data. */ + private byte[]sigData = null; + /** Number of Items in the list. */ + private int numberOfItems = 0; + /** Signature validity. */ + private boolean valid = true; + /** Current status. */ + private String status = "Signature List is Valid"; + /** Array List of Signature found in the list. */ + private ArrayList sigList = new ArrayList(); + /** Input Stream for processing. */ + private ByteArrayInputStream efiSigDataIS = null; + /** Type of signature. */ + private UefiGuid signatureType = null; +/** + * UefiSignatureList constructor. + * @param list byte array holding the signature list. + * @throws CertificateException If there a problem parsing the X509 certificate. + * @throws NoSuchAlgorithmException if there's a problem hashing the certificate. + * @throws 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); + + 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. + * @param lists ByteArrayInputStream containing an EFI Signature list. + * @throws IOException If there's a problem in reading he input stream. + * @throws CertificateException If there's a problem parsing the X509 certificate. + * @throws NoSuchAlgorithmException if there's a problem hashing the certificate. + */ +UefiSignatureList(final ByteArrayInputStream lists) + throws IOException, CertificateException, NoSuchAlgorithmException { + byte[] guid = new byte[UefiConstants.SIZE_16]; + lists.read(guid); + signatureType = new UefiGuid(guid); + + if (!isValidSigListGUID(signatureType)) { + processSignatureData(lists); + } else { // valid SigData Processing + byte[] lSize = new byte[UefiConstants.SIZE_4]; + lists.read(lSize); + listSize = HexUtils.leReverseInt(lSize); + + byte[] hSize = new byte[UefiConstants.SIZE_4]; + lists.read(hSize); + + byte[] sSize = new byte[UefiConstants.SIZE_4]; + lists.read(sSize); + signatureSize = listSize - UefiConstants.SIZE_28; + sigData = new byte[signatureSize]; + lists.read(sigData); + processSignatureList(sigData); + } +} + +/** + * Method for processing a set of EFI SignatureList(s). + * @param sigData Byte array holding one or more SignatureLists + * @throws CertificateException If there's a problem parsing the X509 certificate. + * @throws NoSuchAlgorithmException if there's a problem hashing the certificate. + * @throws IOException If there's a problem parsing the signature data. + */ +private void processSignatureList(final byte[] efiSigData) + throws CertificateException, NoSuchAlgorithmException, IOException { + efiSigDataIS = new ByteArrayInputStream(efiSigData); + while (efiSigDataIS.available() > 0) { + UefiSignatureData tmpSigData = new UefiSignatureData(efiSigDataIS, signatureType); + if (!tmpSigData.isValid()) { + valid = false; + status = tmpSigData.getStatus(); + break; + } + sigList.add(tmpSigData); + numberOfItems++; + } +} + +/** + * Method for processing a set of EFI SignatureList(s). + * @param sigData Byte array holding one or more SignatureLists. + * @throws CertificateException If there's a problem parsing the X509 certificate. + * @throws NoSuchAlgorithmException if there's a problem hashing the certificate. + * @throws 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()) { + valid = false; + status = tmpigData.getStatus(); + break; + } + sigList.add(tmpigData); + numberOfItems++; + } + } + +/** + * Returns an ArrayList of EFISignatureData objects. + * @return ArrayList of EFISignatureData objects. + */ +public ArrayList getSigatureDataList() { + return sigList; +} + +/** + * Return the number of certificates found within a certificate list. + * @return int Number of certs. + */ +public int getNumberOfCerts() { + return numberOfItems; +} + +/** + * Checks to see if GUID is listed on page 1729 of UEFI spec version 2.8. + * @param guid GUID of the has algorithm. + * @return true if the GUID is a valid GUID for Signature List Type, false if not. + */ +public boolean isValidSigListGUID(final UefiGuid guid) { + switch (guid.getVendorTableReference()) { + case "EFI_CERT_SHA256_GUID": return true; + case "EFI_CERT_X509_SHA256": return true; + case "EFI_CERT_X509_SHA384": return true; + case "EFI_CERT_X509_SHA512": return true; + case "EFI_CERT_X509_GUID": return true; + default: return false; + } +} + +/** + * Provides a description of the fields within the EFI Signature Data field. + * Which is essentially a list of X509 certificates. + * @return human readable description. + */ +public String toString() { + StringBuffer sigInfo = new StringBuffer(); + sigInfo.append("UEFI Signature List Type = " + signatureType.toString() + "\n"); + sigInfo.append("Number if items = " + numberOfItems + "\n"); + sigList.iterator(); + for (int i = 0; i < sigList.size(); i++) { + UefiSignatureData certData = (UefiSignatureData) sigList.get(i); + sigInfo.append(certData.toString()); + } + if (!valid) { + sigInfo.append("*** Invalid UEFI Signature data encountered: " + status + "\n"); + } + return sigInfo.toString(); + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiVariable.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiVariable.java new file mode 100644 index 00000000..d7aec349 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiVariable.java @@ -0,0 +1,180 @@ +package hirs.tpm.eventlog.uefi; + +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; + +import hirs.utils.HexUtils; + +/** + * Class to process a UEFI variable within a TPM Event. + * typedef struct tdUEFI_VARIABLE_DATA{ + * UEFI_GUID VariableName; (16 bytes) + * UINT64 UnicodeNameLength; (8 bytes) + * UINT64 VariableDataLength; (8 bytes) + * CHAR16 UnicodeName[]; + * INT8 VariableData[]; + * } UEFI_VARIABLE_DATA + */ +public class UefiVariable { + + /** UEFI defined variable identifier GUID. */ + private UefiGuid uefiGuid = null; + /** List of Signature lists. */ + private ArrayList certSuperList = new ArrayList(); + /** Name of the UEFI variable. */ + private String varName = ""; + /** UEFI defined Boot Variable. */ + private UefiBootVariable bootv = null; + /** UEFI Defined boot order. */ + private UefiBootOrder booto = null; + /** UEFI defined secure boot. */ + private UefiSecureBoot sb = null; + /** UEFI variable data. */ + private byte[] uefiVaribelData = null; + +/** + * EFIVariable constructor. + * The UEFI_VARIABLE_DATA contains a "VariableName" field which is used to determine + * the class used to parse the data within the "VariableData". + * @param varibaleData byte array holding the UEFI Variable. + * @throws CertificateException If there a problem parsing the X509 certificate. + * @throws NoSuchAlgorithmException if there's a problem hashing the certificate. + * @throws IOException If there's a problem parsing the signature data. + */ +public UefiVariable(final byte[] varibaleData) + throws CertificateException, NoSuchAlgorithmException, IOException { + byte[] guid = new byte[UefiConstants.SIZE_16]; + byte[] nameLength = new byte[UefiConstants.SIZE_8]; + byte[] nameTemp = null; + byte[] dataLength = new byte[UefiConstants.SIZE_8]; + byte[] name = null; + int variableLength = 0; + + System.arraycopy(varibaleData, 0, guid, 0, UefiConstants.SIZE_16); + uefiGuid = new UefiGuid(guid); + System.arraycopy(varibaleData, UefiConstants.SIZE_16, nameLength, 0, UefiConstants.SIZE_8); + int nlength = HexUtils.leReverseInt(nameLength); + System.arraycopy(varibaleData, UefiConstants.OFFSET_24, dataLength, 0, UefiConstants.SIZE_8); + nameTemp = new byte[nlength * UefiConstants.SIZE_2]; + + System.arraycopy(varibaleData, UefiConstants.OFFSET_32, + nameTemp, 0, nlength * UefiConstants.SIZE_2); + byte[] name1 = UefiDevicePath.convertChar16tobyteArray(nameTemp); + name = new byte[nlength]; + System.arraycopy(name1, 0, name, 0, nlength); + variableLength = HexUtils.leReverseInt(dataLength); + uefiVaribelData = new byte[variableLength]; + System.arraycopy(varibaleData, UefiConstants.OFFSET_32 + + nlength * UefiConstants.SIZE_2, uefiVaribelData, 0, variableLength); + varName = new String(name, "UTF-8"); + String tmpName = varName; + if (varName.contains("Boot00")) { + tmpName = "Boot00"; + } + switch (tmpName) { + case "PK": processSigList(uefiVaribelData); break; + case "KEK": processSigList(uefiVaribelData); break; + case "db": processSigList(uefiVaribelData); break; + case "dbx": processSigList(uefiVaribelData); break; + case "Boot00": bootv = new UefiBootVariable(uefiVaribelData); break; + case "BootOrder": booto = new UefiBootOrder(uefiVaribelData); break; + case "SecureBoot": sb = new UefiSecureBoot(uefiVaribelData); break; + default: + } +} + +/** + * The GUID is a globally unique identifier assigned to this UEFI variable. + * UEFI variable specific GUIDs are specified in the UEFI specification. + * @return UEFI Variable GUID. + */ +public UefiGuid getEfiVarGuid() { + return uefiGuid; +} + +/** + * Returns a human readable Name for this UEFI Variable (e.g. SecureBoot). + * @return the UEFI Variable name assigned to this variable. + */ +public String getEfiVarName() { + return varName; +} + +/** + * Returns a arrayList of UefiSignatureList (Certificates or hashes) held in the Event Log. + * @return and array list of UEFI defined Signature Lists. + */ +public ArrayList getEFISignatureList() { + return certSuperList; +} + +/** + * Processes the data as a UEFI defined Signature List. + * @param data the bye array holding the Signature List. + * @throws CertificateException If there a problem parsing the X509 certificate. + * @throws NoSuchAlgorithmException if there's a problem hashing the certificate. + * @throws IOException If there's a problem parsing the signature data. + */ +private void processSigList(final byte[] data) + throws CertificateException, NoSuchAlgorithmException, IOException { + ByteArrayInputStream certData = new ByteArrayInputStream(data); + while (certData.available() > 0) { + UefiSignatureList list; + list = new UefiSignatureList(certData); + certSuperList.add(list); + } +} + +/** + * Print out all the interesting characteristics available on this UEFI Variable. + * @return human readable description of the UEFi variable. + */ +public String toString() { + StringBuffer efiVariable = new StringBuffer(); + efiVariable.append("UEFI Variable Name:" + varName + "\n"); + efiVariable.append("UEFI_GUID = " + getEfiVarGuid().toString() + "\n"); + efiVariable.append("UEFI Variable Contents => " + "\n"); + String tmpName = varName; + if (varName.contains("Boot00")) { + tmpName = "Boot00"; + } + switch (tmpName) { + case "Shim": efiVariable.append(printCert(uefiVaribelData, 0)); break; + case "MokList": efiVariable.append(printCert(uefiVaribelData, 0)); break; + case "Boot00": efiVariable.append(bootv.toString()); break; + case "BootOrder": efiVariable.append(booto.toString()); break; + case "SecureBoot": efiVariable.append(sb.toString()); break; + default: + } + for (int i = 0; i < certSuperList.size(); i++) { + efiVariable.append(certSuperList.get(i).toString()); + } + return efiVariable.toString(); +} + +/** + * 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. + */ +public String printCert(final byte[] data, final int offset) { + String certInfo = ""; + byte[] certLength = new byte[UefiConstants.SIZE_2]; + System.arraycopy(data, offset + UefiConstants.OFFSET_2, certLength, 0, UefiConstants.SIZE_2); + int cLength = new BigInteger(certLength).intValue() + UefiConstants.SIZE_4; + byte[] certData = new byte[cLength]; + System.arraycopy(data, offset, certData, 0, cLength); + try { + UefiX509Cert cert = new UefiX509Cert(certData); + certInfo = cert.toString(); + } catch (Exception e) { + certInfo = "Error Processing Certificate : " + e.getMessage() + "\n"; + } + return (certInfo); + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiX509Cert.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiX509Cert.java new file mode 100644 index 00000000..61e556fe --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/UefiX509Cert.java @@ -0,0 +1,87 @@ +package hirs.tpm.eventlog.uefi; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import javax.xml.bind.DatatypeConverter; + +/** + * Class for processing a Secure Boot certificate stored in the UEFI DB or DBX. + * X509 certs are used by Secure Boot for validating EFI files. + */ +public class UefiX509Cert { + /** Certificate object .*/ + private java.security.cert.Certificate cert = null; + +/** + * Constructor for the certificate. + * @param certData byte array holding the certificate. + * @throws CertificateException If the certificate cannot parse. + * @throws NoSuchAlgorithmException if a hash cannot be generated from the cert. + */ +public UefiX509Cert(final byte[] certData) throws CertificateException, NoSuchAlgorithmException { + CertificateFactory cf; + cf = CertificateFactory.getInstance("X.509"); + InputStream targetStream = new ByteArrayInputStream(certData); + cert = cf.generateCertificate(targetStream); + MessageDigest md = MessageDigest.getInstance("SHA1"); + md.update(certData); +} + +/** + * Finds the byte length of the certificate. + * @return the certificate length. + * @throws CertificateEncodingException if the certificate failed to parse. + */ +public int getLength() throws CertificateEncodingException { + int length = 0; + X509Certificate x509Cert = (X509Certificate) cert; + length = x509Cert.getEncoded().length; + return length; +} + +/** + * Calculates the fingerprint per Microsoft's specs using SHA1 and colon based notation. + * e.g. "44:d6:41:ca:ca:08:09:00:23:98:b4:87:7b:8e:98:2e:d2:6f:7b:76" + * @return a string representation of the certificate fingerprint + */ +public String getSHA1FingerPrint() { + byte[] der = null; + MessageDigest md = null; + try { + md = MessageDigest.getInstance("SHA-1"); + der = cert.getEncoded(); + } catch (Exception e) { + return ("Error creating Certificate Fingerprint: " + e.getMessage()); + } + md.update(der); + byte[] digest = md.digest(); + String digestHex = DatatypeConverter.printHexBinary(digest); + digestHex = digestHex.replaceAll("..(?!$)", "$0:"); // places : every 2 digits + return digestHex.toLowerCase(); +} + +/** + * Provides a Sting of select fields of the Certificate data. + * @return A string detailing select fields of the certificate. + */ +public String toString() { + X509Certificate x509Cert = (X509Certificate) cert; + String certData = ""; + certData += "Certificate Serial Number = " + + x509Cert.getSerialNumber().toString(UefiConstants.SIZE_16) + "\n"; + certData += "Subject DN = " + x509Cert.getSubjectDN() + "\n"; + certData += "Issuer DN = " + x509Cert.getIssuerDN() + "\n"; + certData += "Not Before Date = " + x509Cert.getNotBefore() + "\n"; + certData += "Not After Date = " + x509Cert.getNotAfter() + "\n"; + certData += "Signature Algorithm = " + x509Cert.getSigAlgName() + "\n"; + certData += "SHA1 Fingerprint = " + getSHA1FingerPrint() + "\n"; + return certData; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/package-info.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/package-info.java new file mode 100644 index 00000000..7b0ed551 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/uefi/package-info.java @@ -0,0 +1,6 @@ +/** + * Non-persistant classes related to TGC Event Logs. + */ + +package hirs.tpm.eventlog.uefi; + diff --git a/HIRS_Utils/src/test/java/hirs/tpm/eventlog/uefi/UefiProcessingTest.java b/HIRS_Utils/src/test/java/hirs/tpm/eventlog/uefi/UefiProcessingTest.java new file mode 100644 index 00000000..92e5b448 --- /dev/null +++ b/HIRS_Utils/src/test/java/hirs/tpm/eventlog/uefi/UefiProcessingTest.java @@ -0,0 +1,158 @@ +package hirs.tpm.eventlog.uefi; + +import java.io.IOException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import hirs.utils.HexUtils; + +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/* +import org.junit.Test; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +*/ + +/** + * Class for testing TCG Event Log processing of UEFI defined Data. + */ +public class UefiProcessingTest { + // Variable files collected using an Event Parsing tool + private static final String UEFI_VARIABLE_BOOT = "/tcgeventlog/uefi/EV_EFI_VARIABLE_BOOT.txt"; + private static final String UEFI_VARIABLE_BOOT_SECURE_BOOT + = "/tcgeventlog/uefi/EV_EFI_VAR_SECURE_BOOT.txt"; + private static final String UEFI_VARIABLE_BOOT_DRIVER_CONFIG_KEK + = "/tcgeventlog/uefi/EV_EFI_VARIABLE_DRIVER_CONFIG_KEK.txt"; + private static final String UEFI_GPT_EVENT = "/tcgeventlog/uefi/EV_EFI_GPT_EVENT.txt"; + private static final String UEFI_FW_BLOB = "/tcgeventlog/uefi/EFI_PLATFORM_FIRMWARE_BLOB.txt"; + private static final String UEFI_DEVICE_PATH = "/tcgeventlog/uefi/EFI_DEVICE_PATH.txt"; + + private static final Logger LOGGER + = LogManager.getLogger(UefiProcessingTest.class); + +/** + * Initializes a SessionFactory. + * The factory is used for an in-memory database that is used for testing. + */ +@BeforeClass +public static final void setup() { + LOGGER.debug("retrieving session factory"); +} + +/** + * Closes the SessionFactory from setup. + */ +@AfterClass +public static final void tearDown() { + LOGGER.debug("closing session factory"); +} + +/** + * Tests the processing of UEFI Variables. + * @throws IOException when processing the test fails. + * @throws NoSuchAlgorithmException if non TCG Algorithm is encountered. + * @throws CertificateException if parsing issue for X509 cert is encountered. + */ +@Test +public final void testUefiVariables() throws IOException, + CertificateException, NoSuchAlgorithmException { + LOGGER.debug("Testing the parsing of UEFI Variables"); + String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_VARIABLE_BOOT), + "UTF-8"); + byte[] uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt); + UefiVariable uefiVariable = new UefiVariable(uefiVariableBytes); + UefiGuid guid = uefiVariable.getEfiVarGuid(); + String varName = uefiVariable.getEfiVarName(); + Assert.assertEquals(guid.toString(), + "8be4df61-93ca-11d2-aa0d-00e098032b8c : EFI_Global_Variable"); + Assert.assertEquals(varName, "BootOrder"); + + uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_VARIABLE_BOOT_SECURE_BOOT), + "UTF-8"); + uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt); + uefiVariable = new UefiVariable(uefiVariableBytes); + guid = uefiVariable.getEfiVarGuid(); + varName = uefiVariable.getEfiVarName(); + Assert.assertEquals(guid.toString(), + "8be4df61-93ca-11d2-aa0d-00e098032b8c : EFI_Global_Variable"); + Assert.assertEquals(varName, "SecureBoot"); + + uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream( + UEFI_VARIABLE_BOOT_DRIVER_CONFIG_KEK), "UTF-8"); + uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt); + uefiVariable = new UefiVariable(uefiVariableBytes); + varName = uefiVariable.getEfiVarName(); + Assert.assertEquals(varName, "KEK"); +} + +/** + * Tests the processing of a UEFI defined GPT Partition event. + * @throws IOException when processing the test fails. + * @throws NoSuchAlgorithmException if non TCG Algorithm is encountered. + * @throws CertificateException if parsing issue for X509 cert is encountered. + */ +@Test +public final void testUefiPartiton() throws IOException, + CertificateException, NoSuchAlgorithmException { + LOGGER.debug("Testing the parsing of GPT Data"); + String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_GPT_EVENT), + "UTF-8"); + byte[] uefiPartitionBytes = HexUtils.hexStringToByteArray(uefiTxt); + UefiPartition gptPart = new UefiPartition(uefiPartitionBytes); + String gptPartName = gptPart.getName(); + UefiGuid gptTypeuid = gptPart.getPartitionTypeGUID(); + UefiGuid gptUniqueGuid = gptPart.getUniquePartitionGUID(); + Assert.assertEquals(gptTypeuid.toString(), + "c12a7328-f81f-11d2-ba4b-00a0c93ec93b : EFI System Partition"); + Assert.assertEquals(gptUniqueGuid.toString(), + "8ca7623c-041e-4fab-8c12-f49a86b85d73 : Unknown GUID reference"); + Assert.assertEquals(gptPartName, "EFI system partition"); + } + +/** + * Tests the processing of a UEFI defined GPT Partition event. + * @throws IOException when processing the test fails. + * @throws NoSuchAlgorithmException if non TCG Algorithm is encountered. + * @throws CertificateException if parsing issue for X509 cert is encountered. + */ +@Test +public final void testUefiFirmwareBlob() throws IOException, + CertificateException, NoSuchAlgorithmException { + LOGGER.debug("Testing the parsing of Uefi Firmware Blob"); + String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_FW_BLOB), "UTF-8"); + byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt); + UefiFirmware uefiFWBlob = new UefiFirmware(uefiFwBlobBytes); + int fwAddress = uefiFWBlob.getPhysicalAddress(); + int fwLength = uefiFWBlob.getBlobLength(); + Assert.assertEquals(fwAddress, 1797287936); + Assert.assertEquals(fwLength, 851968); +} + +/** + * Tests the processing of a UEFI defined Device Path. + * @throws IOException when processing the test fails. + */ +@Test +public final void testUefiDevicePath() throws IOException { + + LOGGER.debug("Testing the parsing of Uefi Device Path"); + String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_DEVICE_PATH), + "UTF-8"); + byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt); + UefiDevicePath uefiDevPath = new UefiDevicePath(uefiFwBlobBytes); + String devPathType = uefiDevPath.getType(); + String devPathSubType = uefiDevPath.getSubType(); + Assert.assertEquals(devPathType, "Media Device Path"); + Assert.assertEquals(devPathSubType, + "PIWG Firmware File 15e1e31a-9f9d-4c84-82fb-1a707fc0f63b : RSTeSATAEFI"); + + } +} + diff --git a/HIRS_Utils/src/test/java/hirs/tpm/eventlog/uefi/package-info.java b/HIRS_Utils/src/test/java/hirs/tpm/eventlog/uefi/package-info.java new file mode 100644 index 00000000..d353f28a --- /dev/null +++ b/HIRS_Utils/src/test/java/hirs/tpm/eventlog/uefi/package-info.java @@ -0,0 +1,5 @@ +/** + * Test classes for the hirs.tpm package. + */ + +package hirs.tpm.eventlog.uefi; diff --git a/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EFI_DEVICE_PATH.txt b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EFI_DEVICE_PATH.txt new file mode 100644 index 00000000..7802a6f4 --- /dev/null +++ b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EFI_DEVICE_PATH.txt @@ -0,0 +1 @@ +040714002ce2edb630defa45bb09ca202c1654b7040614001ae3e1159d9f844c82fb1a707fc0f63b7fff0400 \ No newline at end of file diff --git a/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EFI_PLATFORM_FIRMWARE_BLOB.txt b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EFI_PLATFORM_FIRMWARE_BLOB.txt new file mode 100644 index 00000000..ceab9816 --- /dev/null +++ b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EFI_PLATFORM_FIRMWARE_BLOB.txt @@ -0,0 +1 @@ +0070206b0000000000000d0000000000 \ No newline at end of file diff --git a/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_GPT_EVENT.txt b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_GPT_EVENT.txt new file mode 100644 index 00000000..f82c5911 --- /dev/null +++ b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_GPT_EVENT.txt @@ -0,0 +1 @@ +28732ac11ff8d211ba4b00a0c93ec93b3c62a78c1e04ab4f8c12f49a86b85d7300a80f0000000000ffc712000000000000000000000000804500460049002000730079007300740065006d00200070006100720074006900740069006f006e000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_VARIABLE_BOOT.txt b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_VARIABLE_BOOT.txt new file mode 100644 index 00000000..8b6b3d49 --- /dev/null +++ b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_VARIABLE_BOOT.txt @@ -0,0 +1 @@ +61dfe48bca93d211aa0d00e098032b8c09000000000000000c0000000000000042006f006f0074004f007200640065007200040003000200000001000500 \ No newline at end of file diff --git a/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_VARIABLE_DRIVER_CONFIG_KEK.txt b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_VARIABLE_DRIVER_CONFIG_KEK.txt new file mode 100644 index 00000000..b0b75029 --- /dev/null +++ b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_VARIABLE_DRIVER_CONFIG_KEK.txt @@ -0,0 +1 @@ +61dfe48bca93d211aa0d00e098032b8c030000000000000000000000000000004b0045004b00 \ No newline at end of file diff --git a/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_VAR_SECURE_BOOT.txt b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_VAR_SECURE_BOOT.txt new file mode 100644 index 00000000..bf6b6d07 --- /dev/null +++ b/HIRS_Utils/src/test/resources/tcgeventlog/uefi/EV_EFI_VAR_SECURE_BOOT.txt @@ -0,0 +1 @@ +61dfe48bca93d211aa0d00e098032b8c0a00000000000000010000000000000053006500630075007200650042006f006f00740000