Merge pull request #244 from nsacyber/issue-242

[#242] Add UEFI Variable processing for TCG Event Logs
This commit is contained in:
iadgovuser26 2020-05-15 08:50:37 -04:00 committed by GitHub
commit 2743077c83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2153 additions and 0 deletions

View File

@ -0,0 +1,36 @@
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 += 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() {
StringBuilder orderList = new StringBuilder();
orderList.append("BootOrder = ");
for (int i = 0; i < bootOrder.length; i++) {
orderList.append(String.format("Boot %04d", (int) bootOrder[i]));
}
return orderList.toString();
}
}

View File

@ -0,0 +1,99 @@
package hirs.tpm.eventlog.uefi;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
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), StandardCharsets.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() {
StringBuilder bootInfo = new StringBuilder("Description = ");
String bootvar = description.replaceAll("[^a-zA-Z_0-0\\s]", ""); // remove all non ascii chars
bootInfo.append(bootvar + "\n" + efiDevPath.toString());
return bootInfo.toString();
}
/**
* 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[] nullTerminator = new byte[UefiConstants.SIZE_2];
byte[] char16 = new byte[UefiConstants.SIZE_2];
nullTerminator[0] = 0;
nullTerminator[1] = 0;
for (int i = 0; i < data.length; i += UefiConstants.SIZE_2) {
char16[0] = data[i];
char16[1] = data[i + 1];
count++;
if (Arrays.equals(nullTerminator, char16)) {
return count * UefiConstants.SIZE_2;
}
}
return count * UefiConstants.SIZE_2 + 1;
}
}

View File

@ -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;
}

View File

@ -0,0 +1,427 @@
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 {
StringBuilder pInfo = new StringBuilder();
String devicePathInfo = "";
int devLength = 0, pathOffset = 0;
while (true) {
Byte devPath = Byte.valueOf(path[pathOffset]);
if ((devPath.intValue() == UefiConstants.TERMINATOR)
|| (devPath.intValue() == UefiConstants.END_FLAG)) {
break;
}
devicePathInfo = processDev(path, pathOffset);
if (devicePathInfo.contains("Unknown Device Path")) {
break;
}
pInfo.append(devicePathInfo);
devLength = path[pathOffset + UefiConstants.OFFSET_3] * UefiConstants.SIZE_256
+ path[pathOffset + UefiConstants.OFFSET_2];
pathOffset = pathOffset + devLength;
if (pathOffset >= path.length) {
break;
}
}
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) {
subType = "";
switch (path[offset + UefiConstants.OFFSET_1]) {
case 0x01: subType = "(Short): ";
subType += acpiShortSubType(path, offset);
break;
case 0x02: subType = "Expanded ACPI Device Path"; break;
default: subType = "Invalid ACPI Device Path sub type";
}
return subType;
}
/**
* Processes the ACPI short subtype.
* @param path
* @param offset
* @return short acpi info.
*/
private String acpiShortSubType(final byte[] path, final int offset) {
subType = "";
byte[] hid = new byte[UefiConstants.SIZE_4];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, hid, 0, UefiConstants.SIZE_4);
subType += "_HID = " + HexUtils.byteArrayToHexString(hid);
System.arraycopy(path, 2 * UefiConstants.SIZE_4 + offset, hid, 0, UefiConstants.SIZE_4);
subType += "_UID = " + HexUtils.byteArrayToHexString(hid);
return subType;
}
/**
* Processes the PCI subType.
* @param path
* @param offset
* @return pci device info.
*/
private String pciSubType(final byte[] path, final int offset) {
subType = "PCI: PCI Function Number = ";
subType += String.format("0x%x", path[offset + UefiConstants.SIZE_4]);
subType += " PCI Device Number = ";
subType += String.format("0x%x", path[offset + UefiConstants.SIZE_5]);
return subType;
}
/**
* processes the SATA sub type.
* @param path
* @param offset
* @return SATA drive info.
*/
private String sataSubType(final byte[] path, final int offset) {
subType = "SATA: HBA Port Number = ";
byte[] data = new byte[UefiConstants.SIZE_2];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, data, 0, UefiConstants.SIZE_2);
subType += HexUtils.byteArrayToHexString(data);
System.arraycopy(path, UefiConstants.OFFSET_6 + offset, data, 0, UefiConstants.SIZE_2);
subType += " Port Multiplier = " + HexUtils.byteArrayToHexString(data);
System.arraycopy(path, UefiConstants.OFFSET_8 + offset, data, 0, UefiConstants.SIZE_2);
subType += " Logical Unit Number = " + HexUtils.byteArrayToHexString(data);
return subType;
}
/**
* Processes the hard drive sub type.
* @param path
* @param offset
* @return hard drive info.
*/
private String hardDriveSubType(final byte[] path, final int offset) {
subType = "Partition Number = ";
byte[] partnumber = new byte[UefiConstants.SIZE_4];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, partnumber, 0, UefiConstants.SIZE_4);
subType += HexUtils.byteArrayToHexString(partnumber);
byte[] data = new byte[UefiConstants.SIZE_8];
System.arraycopy(path, UefiConstants.OFFSET_8 + offset, data, 0, UefiConstants.SIZE_8);
subType += "Partition Start = " + HexUtils.byteArrayToHexString(data);
System.arraycopy(path, UefiConstants.OFFSET_16 + offset, data, 0, UefiConstants.SIZE_8);
subType += "Partition Size = " + HexUtils.byteArrayToHexString(data);
byte[] signature = new byte[UefiConstants.SIZE_16];
System.arraycopy(path, UefiConstants.OFFSET_24 + offset, signature, 0, UefiConstants.SIZE_16);
subType += "Partition Signature = ";
if (path[UefiConstants.OFFSET_41 + offset] == UefiConstants.DRIVE_SIG_NONE) {
subType += "None";
} else if (path[UefiConstants.OFFSET_41 + offset] == UefiConstants.DRIVE_SIG_32BIT) {
subType += HexUtils.byteArrayToHexString(signature);
} else if (path[UefiConstants.OFFSET_41 + offset] == UefiConstants.DRIVE_SIG_GUID) {
UefiGuid guid = new UefiGuid(signature);
subType += guid.toString();
} else {
subType += "invalid partition signature type";
}
subType += "Partition Format = ";
if (path[UefiConstants.OFFSET_40 + offset] == UefiConstants.DRIVE_TYPE_PC_AT) {
subType += "PC-AT compatible legacy MBR";
} else if (path[UefiConstants.OFFSET_40 + offset] == UefiConstants.DRIVE_TYPE_GPT) {
subType += "GUID Partition Table";
} else {
subType += "Invalid partition table type";
}
return subType;
}
/**
* 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 {
subType = "File Path = ";
byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(path, 2 + offset, lengthBytes, 0, UefiConstants.SIZE_2);
int subTypeLength = HexUtils.leReverseInt(lengthBytes);
byte[] filePath = new byte[subTypeLength];
System.arraycopy(path, UefiConstants.OFFSET_4 + offset, filePath, 0, subTypeLength);
byte[] fileName = convertChar16tobyteArray(filePath);
subType += new String(fileName, "UTF-8");
return subType;
}
/**
* 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) {
subType = "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);
subType += 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);
subType += " : Vendor Data = " + HexUtils.byteArrayToHexString(vendorData);
} else {
subType += " : No Vendor Data pesent";
}
return subType;
}
/**
* 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) {
subType = "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);
subType += HexUtils.byteArrayToHexString(nvmData);
return subType;
}
/**
* BIOS Device Type definition.
* From Appendix A of the BIOS Boot Specification.
* Only processes 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) {
subType = "Legacy BIOS : Type = ";
Byte pathType = Byte.valueOf(path[offset + 1]);
switch (pathType.intValue()) {
case UefiConstants.DEVPATH_BIOS_RESERVED: subType += "Reserved"; break;
case UefiConstants.DEVPATH_BIOS_FLOPPY: subType += "Floppy"; break;
case UefiConstants.DEVPATH_BIOS_HD: subType += "Hard Disk"; break;
case UefiConstants.DEVPATH_BIOS_CD: subType += "CD-ROM"; break;
case UefiConstants.DEVPATH_BIOS_PCM: subType += "PCMCIA"; break;
case UefiConstants.DEVPATH_BIOS_USB: subType += "USB"; break;
case UefiConstants.DEVPATH_BIOS_EN: subType += "Embedded network"; break;
case UefiConstants.DEVPATH_BIOS_BEV: subType +=
"Bootstrap Entry Vector (BEV) from an Option ROM";
break;
default: subType += "Unknown";
break;
}
return subType;
}
/**
* 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) {
subType = "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);
subType += guid.toString();
return subType;
}
/**
* 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) {
subType = "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);
subType += guid.toString();
return subType;
}
/**
* 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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,405 @@
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 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 reference = "";
switch (uuid.toString().toLowerCase()) {
// 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 "3f7e615b-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-d131d5f0458a":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-6f9a0a3a006e":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() {
return getVendorTableReference().equals("Unknown GUID reference");
}
/**
* 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;
}
}

View File

@ -0,0 +1,111 @@
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[] partitionGuidBytes = new byte[UefiConstants.SIZE_16];
System.arraycopy(table, 0, partitionGuidBytes, 0, UefiConstants.SIZE_16);
partitionTypeGUID = new UefiGuid(partitionGuidBytes);
byte[] uniquePartGuidBytes = new byte[UefiConstants.SIZE_16];
System.arraycopy(table, UefiConstants.SIZE_16, uniquePartGuidBytes, 0, UefiConstants.SIZE_16);
uniquePartitionGUID = new UefiGuid(uniquePartGuidBytes);
byte[] attributeBytes = new byte[UefiConstants.SIZE_8];
System.arraycopy(table, UefiConstants.ATTRIBUTE_LENGTH, attributeBytes,
0, UefiConstants.SIZE_8);
attributes = HexUtils.byteArrayToHexString(attributeBytes);
byte[] partitionNameBytes = new byte[UefiConstants.UEFI_PT_LENGTH];
System.arraycopy(table, UefiConstants.PART_NAME_LENGTH, partitionNameBytes,
0, UefiConstants.UEFI_PT_LENGTH);
byte[] pName = convertChar16tobyteArray(partitionNameBytes);
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 += 2) {
hexdata[j++] = data[i];
}
return hexdata;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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<UefiSignatureData> sigList = new ArrayList<UefiSignatureData>();
/** 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<UefiSignatureData> 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() {
StringBuilder sigInfo = new StringBuilder();
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();
}
}

View File

@ -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<UefiSignatureList> certSuperList = new ArrayList<UefiSignatureList>();
/** 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<UefiSignatureList> 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() {
StringBuilder efiVariable = new StringBuilder();
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);
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,6 @@
/**
* Non-persistant classes related to TGC Event Logs.
*/
package hirs.tpm.eventlog.uefi;

View File

@ -0,0 +1,151 @@
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;
/**
* 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 <code>SessionFactory</code>.
* 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 <code>SessionFactory</code> 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");
}
}

View File

@ -0,0 +1,5 @@
/**
* Test classes for the hirs.tpm package.
*/
package hirs.tpm.eventlog.uefi;

View File

@ -0,0 +1 @@
040714002ce2edb630defa45bb09ca202c1654b7040614001ae3e1159d9f844c82fb1a707fc0f63b7fff0400

View File

@ -0,0 +1 @@
0070206b0000000000000d0000000000

View File

@ -0,0 +1 @@
28732ac11ff8d211ba4b00a0c93ec93b3c62a78c1e04ab4f8c12f49a86b85d7300a80f0000000000ffc712000000000000000000000000804500460049002000730079007300740065006d00200070006100720074006900740069006f006e000000000000000000000000000000000000000000000000000000000000000000

View File

@ -0,0 +1 @@
61dfe48bca93d211aa0d00e098032b8c09000000000000000c0000000000000042006f006f0074004f007200640065007200040003000200000001000500

View File

@ -0,0 +1 @@
61dfe48bca93d211aa0d00e098032b8c030000000000000000000000000000004b0045004b00

View File

@ -0,0 +1 @@
61dfe48bca93d211aa0d00e098032b8c0a00000000000000010000000000000053006500630075007200650042006f006f00740000