add support for EvCompactHash EvEfiSpecIdEvent and EvNoAction events

This commit is contained in:
lareine 2020-03-27 15:58:05 -04:00
parent faa77be822
commit 94cf172ce8
5 changed files with 330 additions and 0 deletions

View File

@ -0,0 +1,52 @@
package hirs.tpm.eventlog.events;
import java.io.UnsupportedEncodingException;
import hirs.tpm.eventlog.uefi.UefiConstants;
import hirs.utils.HexUtils;
/**
* Class to process the EV_COMPACT_HASH event.
* The Old 2005 PFP description of EV_COMPACT_HASH which provides 4 byte ESI field (a pointer).
* The 2019 PFP description allow the vendor to create event data that is "specified by the caller"
* however the for PCR 6 there is a constraint that it contain
* "The Event Data field SHALL be a unique string".
*/
public class EvCompactHash {
private String eventInfo = "";
/**
* Constructor that takes in the event data (hex string) and passes to function below.
* @param event byte array of the Event Compact Hash.
* @throws UnsupportedEncodingException if compact hash has non utf-8 characters.
*/
public EvCompactHash(final byte[] event) throws UnsupportedEncodingException {
hashEvent(event);
}
/**
* Takes the event data (hex string) converts to readable output.
* This may be somewhat limited due to the unpublished nature of vendor specific data.
* @param event data to process.
* @return a human readable description.
* @throws UnsupportedEncodingException if compact hash has non utf-8 characters.
*/
public String hashEvent(final byte[] event) throws UnsupportedEncodingException {
// determine if old format is used
if (event.length == UefiConstants.SIZE_4) { // older PFP defines as 4 byte ESI pointer.
eventInfo = " ESI = " + HexUtils.byteArrayToHexString(event);
} else { // otherwise assume the event content is a string
eventInfo = " " + new String(event, "UTF-8");
}
return eventInfo;
}
/**
* Readable description of the Event Content, however limiting that may be.
* @return Event description.
*/
public String toString() {
return eventInfo;
}
}

View File

@ -0,0 +1,179 @@
package hirs.tpm.eventlog.events;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import hirs.tpm.eventlog.TcgTpmtHa;
import hirs.tpm.eventlog.uefi.UefiConstants;
import hirs.utils.HexUtils;
/**
* Class to process the TCG_EfiSpecIDEvent.
* The first 16 bytes of a Event Data MUST be String based identifier (Signature).
* The only currently defined Signature is "Spec ID Event03" which implies the data is
* a TCG_EfiSpecIDEvent. TCG_EfiSpecIDEvent is the first event in a TPM Event Log
* and is used to determine the format of the Log (SHA1 vs Crypt Agile).
*
* typedef struct tdTCG_EfiSpecIdEvent {
* BYTE Signature[16];
* UINT32 platformClass;
* UINT8 specVersionMinor;
* UINT8 specVersionMajor;
* UINT8 specErrata;
* UINT8 uintnSize;
* UINT32 numberOfAlgorithms;
* TCG_EfiSpecIdEventAlgorithmSize digestSizes[numberOfAlgorithms];
* UINT8 vendorInfoSize;
* BYTE vendorInfo[VendorInfoSize];
* } TCG_EfiSpecIDEvent;
*
* typedef struct tdTCG_EfiSpecIdEventAlgorithmSize {
* UINT16 algorithmId;
* UINT16 digestSize;
* } TCG_EfiSpecIdEventAlgorithmSize;
*
* define TPM_ALG_SHA1 (TPM_ALG_ID)(0x0004)
* define TPM_ALG_SHA256 (TPM_ALG_ID)(0x000B)
* define TPM_ALG_SHA384 (TPM_ALG_ID)(0x000C)
* define TPM_ALG_SHA512 (TPM_ALG_ID)(0x000D)
*
* Notes: Parses event data for an EfiSpecID per Table 5 TCG_EfiSpecIdEvent Example.
* 1. Should be the first Structure in the log
* 2. Has an EventType of EV_NO_ACTION (0x00000003)
* 3. Digest of 20 bytes of all 0's
* 4. Event content defined as TCG_EfiSpecIDEvent Struct.
* 5. First 16 bytes of the structure is an ASCII "Spec ID Event03"
* 6. The version of the log is used to determine which format the Log
* is to use (sha1 or Crypto Agile)
*/
public class EvEfiSpecIdEvent {
/** Minor Version. */
private String vMin = "";
/** Major Version. */
private String vMaj = "";
/** Specification errata version. */
private String errata = "";
/** Signature (text) data. */
private String signature = "";
/** Platform class. */
private String platformClass = "";
/** Algorithm count. */
private int numberOfAlg = 0;
/** True if event log uses Crypto Agile format. */
private boolean cryptoAgile = false;
/** Algorithm list. */
private ArrayList<String> algList = new ArrayList<String>();
/**
* EvEfiSpecIdEvent Constructor.
* @param efiSpecId byte array holding the spec ID Event.
* @throws UnsupportedEncodingException if input fails to parse.
*/
public EvEfiSpecIdEvent(final byte[] efiSpecId) throws UnsupportedEncodingException {
byte[] signatureBytes = new byte[UefiConstants.SIZE_16];
System.arraycopy(efiSpecId, 0, signatureBytes, 0, UefiConstants.SIZE_16);
signature = HexUtils.byteArrayToHexString(signatureBytes);
signature = new String(signatureBytes, "UTF-8").substring(0, UefiConstants.SIZE_15);
byte[] platformClassBytes = new byte[UefiConstants.SIZE_4];
System.arraycopy(efiSpecId, UefiConstants.OFFSET_16, platformClassBytes, 0,
UefiConstants.SIZE_4);
platformClass = HexUtils.byteArrayToHexString(platformClassBytes);
byte[] specVersionMinorBytes = new byte[1];
System.arraycopy(efiSpecId, UefiConstants.OFFSET_20, specVersionMinorBytes, 0, 1);
vMin = HexUtils.byteArrayToHexString(specVersionMinorBytes);
byte[] specVersionMajorBytes = new byte[1];
System.arraycopy(efiSpecId, UefiConstants.OFFSET_21, specVersionMajorBytes, 0, 1);
vMaj = HexUtils.byteArrayToHexString(specVersionMajorBytes);
byte[] specErrataBytes = new byte[1];
System.arraycopy(efiSpecId, UefiConstants.OFFSET_22, specErrataBytes, 0, 1);
errata = HexUtils.byteArrayToHexString(specErrataBytes);
byte[] numberOfAlgBytes = new byte[UefiConstants.SIZE_4];
System.arraycopy(efiSpecId, UefiConstants.OFFSET_24, numberOfAlgBytes, 0,
UefiConstants.SIZE_4);
numberOfAlg = HexUtils.leReverseInt(numberOfAlgBytes);
byte[] algorithmIDBytes = new byte[UefiConstants.SIZE_2];
int algLocation = UefiConstants.SIZE_28;
for (int i = 0; i < numberOfAlg; i++) {
System.arraycopy(efiSpecId, algLocation + UefiConstants.OFFSET_4 * i, algorithmIDBytes,
0, UefiConstants.SIZE_2);
String alg = TcgTpmtHa.tcgAlgIdtoString(HexUtils.leReverseInt(algorithmIDBytes));
algList.add(alg);
}
if ((algList.size() == 1) && (algList.get(0).compareTo("SHA1") == 0)) {
cryptoAgile = false;
} else {
cryptoAgile = true;
}
}
/**
* Returns the specification major revision.
* @return major revision.
*/
public String getVersionMajor() {
return vMaj;
}
/**
* Returns the specification minor revision.
* @return minor revision.
*/
public String getVersionMinor() {
return vMin;
}
/**
* Returns the specification eratta version.
* @return major revision.
*/
public String getErrata() {
return errata;
}
/**
* Returns the contents of the events signature field.
* @return signature data.
*/
public String getSignature() {
return signature;
}
/**
* Returns the class of the platform.
* @return platform class.
*/
public String getPlatformClass() {
return platformClass;
}
/**
* Returns a list of hash algorithms used in the event log.
* @return ArrayList of TCG defined algorithm identifiers.
*/
public ArrayList<String> getAlgList() {
return algList;
}
/**
* Used to determine if the log uses the Crypto Agile format.
* @return boolean true if the algorithm is Crpyto Agile.
*/
public boolean isCryptoAgile() {
return cryptoAgile;
}
/**
* Returns a human readable description of the data within this event.
* @return a description of this event..
*/
public String toString() {
String specInfo = "";
if (signature == "Spec ID Event#") {
specInfo += "Platform Profile Specification version = " + vMaj + "." + vMin
+ " using errata version" + errata + "\n";
} else {
specInfo = "EV_NO_ACTION event named " + signature
+ " ecncountered but support for processing it has not been added to this application";
}
return specInfo;
}
}

View File

@ -0,0 +1,81 @@
package hirs.tpm.eventlog.events;
import java.io.UnsupportedEncodingException;
import hirs.tpm.eventlog.uefi.UefiConstants;
/**
* Class to process the EV_NO_ACTION event using a structure of TCG_EfiSpecIDEvent.
* The first 16 bytes of the event data MUST be a String based identifier (Signature).
* The only currently defined Signature is "Spec ID Event03"
* which implies the data is a TCG_EfiSpecIDEvent.
* TCG_EfiSpecIDEvent is the first event in a TPM Event Log and is used to determine
* if the format of the Log (SHA1 vs Crypto Agile).
*
* Notes:
* 1. First 16 bytes of the structure is an ASCII with a fixed Length of 16
* 2. Add processing of other NoEvent types when new ones get defined
*/
public class EvNoAction {
/** Signature (text) data. */
private String signature = "";
/** True of the event is a SpecIDEvent. */
private boolean bSpecIDEvent = false;
/** EvEfiSpecIdEvent Object. */
private EvEfiSpecIdEvent specIDEvent = null;
/**
* EvNoAction constructor.
* @param eventData byte array holding the event to process.
* @throws UnsupportedEncodingException if input fails to parse.
*/
public EvNoAction(final byte[] eventData) throws UnsupportedEncodingException {
byte[] signatureBytes = new byte[UefiConstants.SIZE_16];
System.arraycopy(eventData, 0, signatureBytes, 0, UefiConstants.SIZE_16);
signature = new String(signatureBytes, "UFT-8");
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
if (signature.contains("Spec ID Event03")) { // implies CryptAgileFormat
specIDEvent = new EvEfiSpecIdEvent(eventData);
bSpecIDEvent = true;
}
}
/**
* Returns the EfiSpecIDEvent object (currently only NoAction event defined)
* or null if its not.
* @return EfiSpecIDEvent object or null.
*/
public EvEfiSpecIdEvent getEvEfiSpecIdEvent() {
return specIDEvent;
}
/**
* Determines if this event is a SpecIDEvent.
* @return true of the event is a SpecIDEvent.
*/
public boolean isSpecIDEvent() {
return bSpecIDEvent;
}
/**
* Returns a description of this event.
* @return Human readable description of this event.
*/
public String toString() {
String specInfo = "";
if (bSpecIDEvent) {
specInfo += " Signature = Spec ID Event03 : ";
if (specIDEvent.isCryptoAgile()) {
specInfo += "Log format is Crypto Agile \n";
} else {
specInfo += "Log format is SHA 1 (NOT Crypto Agile) \n";
specInfo += " Platform Profile Specification version = "
+ specIDEvent.getVersionMajor() + "." + specIDEvent.getVersionMinor()
+ " using errata version " + specIDEvent.getErrata() + "\n";
}
} else {
specInfo = "EV_NO_ACTION event named " + signature
+ " encountered but support for processing it has not been added to this application.\n";
}
return specInfo;
}
}

View File

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

View File

@ -19,10 +19,18 @@ public final class UefiConstants {
public static final int SIZE_5 = 5;
/** 8 byte size. */
public static final int SIZE_8 = 8;
/** 15 byte size. */
public static final int SIZE_15 = 15;
/** 16 byte size. */
public static final int SIZE_16 = 16;
/** 20 byte size. */
public static final int SIZE_20 = 20;
/** 21 byte size. */
public static final int SIZE_21 = 20;
/** 22 byte size. */
public static final int SIZE_22 = 20;
/** 23 byte size. */
public static final int SIZE_23 = 20;
/** 28 byte size. */
public static final int SIZE_28 = 28;
/** 32 byte size. */
@ -47,6 +55,10 @@ public final class UefiConstants {
public static final int OFFSET_16 = 16;
/** 20 byte offset. */
public static final int OFFSET_20 = 20;
/** 21 byte offset. */
public static final int OFFSET_21 = 21;
/** 22 byte offset. */
public static final int OFFSET_22 = 22;
/** 24 byte offset. */
public static final int OFFSET_24 = 24;
/** 28 byte offset. */