Merge pull request #253 from nsacyber/issue-252

[#252] eventcheck script
This commit is contained in:
iadgovuser26 2020-06-10 18:17:35 -04:00 committed by GitHub
commit 7597fc8717
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 584 additions and 523 deletions

View File

@ -64,6 +64,8 @@ public final class TCGEventLog {
private boolean bHexEvent = false;
/** Event Output Flag use. */
private boolean bEvent = false;
/** Event Output Flag use. */
private boolean bCryptoAgile = false;
/**
* Default blank object constructor.
*/
@ -102,7 +104,7 @@ public final class TCGEventLog {
final boolean bContentFlag, final boolean bHexEventFlag)
throws CertificateException, NoSuchAlgorithmException, IOException {
boolean bCryptoAgile = isLogCrytoAgile(rawlog);
bCryptoAgile = isLogCrytoAgile(rawlog);
if (bCryptoAgile) {
initValue = INIT_SHA256_LIST;
algorithm = "TPM_ALG_SHA256";
@ -236,7 +238,14 @@ public final class TCGEventLog {
}
return pcrs;
}
/**
* Returns a flag which is set if the event log follows the "Crypto Agile" Format Type.
* A false implies the type is SHA1 format.
* @return true if log follows the Crypto Agile format.
*/
public boolean isCryptoAgile() {
return bCryptoAgile;
}
/**
* Returns a list of event found in the Event Log.
* @return an arraylist of event.

View File

@ -63,8 +63,9 @@ public class EvEfiBootServicesApp {
System.arraycopy(bootServices, UefiConstants.OFFSET_16, linkTimeAddress, 0,
UefiConstants.SIZE_8);
System.arraycopy(bootServices, UefiConstants.SIZE_24, lengthBytes, 0, UefiConstants.SIZE_8);
if (imageLength != 0) {
// if (imageLength != 0) {
devicePathLength = HexUtils.leReverseInt(lengthBytes);
if (devicePathLength != 0) {
byte[] devPathBytes = new byte[devicePathLength];
System.arraycopy(bootServices, UefiConstants.SIZE_32, devPathBytes,
0, devicePathLength);
@ -126,7 +127,7 @@ public class EvEfiBootServicesApp {
if (devicePathValid) {
info += "\n" + devPath.toString();
} else {
info += "\n Error processing device path" + "\n";
info += "\n No uefi device paths were specified";
}
return info;
}

View File

@ -7,4 +7,5 @@ include 'TPM_Utils',
'HIRS_AttestationCA',
'HIRS_AttestationCAPortal',
'tpm_module',
'tools/tcg_rim_tool'
'tools/tcg_rim_tool',
'tools/tcg_eventlog_tool'

View File

@ -0,0 +1,79 @@
#!bin/bash
# outline:
# 1. Run the tcg_rim_tool to check the validity of the rim using cmd line
# 2. Run the event_log_tool diff cmdline
# 3. Output results
function eventcheck_help() {
echo "Event Check: Checks a TCG defined Event Log agianst a Integrity Reference Manifest for a Linux Device with a TPM 2.0"
echo "usage: eventcheck -r [file] - p [file] -s [file] -l [file]";
echo "Options"
echo "-r --rim <path> : Reference Integrity Manifest (RIM) <path> Reference Integrity Manifest (RIM) Base RIM file holding OEM product information.";
echo "-p --publicCertificate <path> : Public key certificate path used to validate the rim file.";
echo "-s --supportRim <path> : PC Client defined support RIM file holding the reference data provided by the OEM of the product.";
echo "-l --log <path> : Event Log of the device being tested. Will default to latest event log if parameter is not supplied.";
echo "-h --help : help listing";
}
while [[ "$#" -gt 0 ]]; do
case $1 in
-p|--publicCertificate) oem_cert="$2"; shift ;;
-r|--rim) oem_rim=$2; shift ;;
-s|--supportRim) support_rim=$2; shift ;;
-l|--log) event_log=$2; shift ;;
-h|--help) eventcheck_help; exit 0 ;;
*) echo "Unknown parameter passed: $1"; eventcheck_help; exit 1 ;;
esac
shift
done
# Check for required parameters
if ${oem_rim+"false"}; then
echo "Error: Base RIM file needs to be specified using the -r parameter";
echo "Exiting without processing.";
exit 1;
fi
if ${support_rim+"false"}; then
echo "Error: Support RIM file needs to be specified using the -s parameter";
echo "Exiting without processing.";
exit 1;
fi
if ${oem_cert+"false"}; then
echo "Error: OEM Public Key Certificate Chain file needs to be specified using the -p parameter";
echo "Exiting without processing.";
exit 1;
fi
# If event log not specified, then use the local devices log (if present)
if ${event_log+"false"}; then
ech0 "Event log not specified attempting to use local devices event log...";
event_log="/sys/kernel/security/tpm0/binary_bios_measurements";
if [ ! -f $event_log ]; then
kver=$(uname -r);
echo "Error opening default event log file, sudo may be required.";
echo " Note kernel version must be greater than 4.18 to produce an Event log. Current verion is $kver.";
echo "Exiting without processing.";
exit 1;
fi
fi
echo "OEM Certificate Chain = $oem_cert";
echo "Base RIM = $oem_rim";
echo "Support RIM = $support_rim";
echo "eventlog = $event_log";
echo "Checking the RIM signature and OEM Certificate Chain";
java -jar ../tcg_rim_tool/build/libs/tools/tcg_rim_tool-1.0.jar -v $oem_rim -p $oem_cert
if [ $? -ne 0 ]; then
exit 1;
fi
echo "Comparing RIM against the specified Event Log";
java -jar ../tcg_eventlog_tool/build/libs/tools/tcg_eventlog_tool-1.0.jar -d $support_rim $event_log
echo " ";
echo "Event Check against RIM complete"

View File

@ -0,0 +1,7 @@
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,55 @@
apply plugin: 'java'
apply plugin: 'findbugs'
apply plugin: 'checkstyle'
version = '1.0'
repositories {
mavenCentral()
}
dependencies {
compile project(':HIRS_Utils')
compile libs.jcommander
compileOnly libs.checkstyle
compileOnly libs.findbugs
testCompile libs.testng
}
ext.configDir = new File(projectDir, 'config')
ext.checkstyleConfigDir = "$configDir/checkstyle"
checkstyle {
toolVersion = '5.7'
configFile = checkstyleConfigFile
configProperties.put('basedir', checkstyleConfigDir)
ignoreFailures = false
showViolations = true
}
ext.findbugsConfigDir = "$configDir/findbugs"
findbugs {
toolVersion = '3.0.0'
ignoreFailures = false
effort = 'max'
}
jar {
manifest {
attributes("Main-Class": "hirs.tcg_eventlog.Main",
"Class-Path": configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
)
}
from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {}
exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'
}
uploadArchives {
repositories {
flatDir {
dirs "${buildDir}"
}
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<suppress files="Main.java" checks="HideUtilityClassConstructor" />
<suppress checks="MagicNumber" files=".*[/\\]src[/\\]test[/\\]+" />
<suppress checks="FinalParameters" files=".*[/\\]src[/\\]test[/\\]+" />
<suppress checks="JavadocPackage" files=".*[/\\]src[/\\]test[/\\]+" />
</suppressions>

Binary file not shown.

View File

@ -1,4 +1,4 @@
package hirs.tcg_eventlog_tool;
package hirs.tcg_eventlog;
import java.io.File;
import java.io.IOException;
@ -12,7 +12,6 @@ public class Commander {
private static final String COMMAND_PREFIX = "-";
private static final String FULL_COMMAND_PREFIX = "--";
private static final String ALL_STRING = "all";
private static final String CONTENT_STRING = "contenthex";
private static final String DIFF_STRING = "diff";
private static final String EVENTIDS_STRING = "event";
@ -27,7 +26,7 @@ public class Commander {
private static final String VERSION_NUMBER = "1.0";
private boolean hasArguments = false;
private boolean bAll = false;
private boolean bValidArgs = true;
private boolean bContentHex = false;
private boolean bDiff = false;
private boolean bEventIds = false;
@ -37,6 +36,7 @@ public class Commander {
private boolean bOutput = false;
private boolean bPCRs = false;
private boolean bVerify = false;
private boolean bHelp = false;
private String inFile = "";
private String inFile2 = "";
@ -47,9 +47,9 @@ public class Commander {
private int eventNumber = -1;
/**
* The main constructor for the Commander class
* The main constructor for the Commander class.
*
* @param args
* @param args inout parameters
*/
public Commander(final String[] args) {
hasArguments = args.length > 0;
@ -62,10 +62,10 @@ public class Commander {
}
/**
* This method is called if an empty Commander was created, and later gets
* args. Will be used by the main constructor.
* This method is called if an empty Commander was created, and later gets args.
* Will be used by the main constructor.
*
* @param args
* @param args input parameters
*/
public final void parseArguments(final String[] args) {
String tempValue;
@ -74,17 +74,13 @@ public class Commander {
tempValue = args[i];
switch (tempValue) {
case FULL_COMMAND_PREFIX + ALL_STRING:
case COMMAND_PREFIX + "a":
bAll = true;
break;
case FULL_COMMAND_PREFIX + CONTENT_STRING:
case FULL_COMMAND_PREFIX + EVENTIDS_STRING:
case COMMAND_PREFIX + "e":
if (i<args.length-1) { // Check for a filter following the -e on the command line
if (!args[i+1].startsWith("-")) {
eventFilter=args[i+++1];
eventNumber = new Integer(eventFilter).intValue();
if (i < args.length - 1) { // Check for a filter following the -e
if (!args[i + 1].startsWith("-")) {
eventFilter = args[i++ + 1];
eventNumber = Integer.parseInt(eventFilter);
}
}
bEventIds = true;
@ -98,17 +94,19 @@ public class Commander {
break;
case FULL_COMMAND_PREFIX + DIFF_STRING:
case COMMAND_PREFIX + "d":
if ((args.length < i+3)||(args[i+1].charAt(0)=='-')||(args[i+2].charAt(0)=='-')){
System.out.print("tcg_eventlog_tool command line error: 2 or 3 parameters needed for -diff.\n");
if ((args.length < i + 2 + 1) || (args[i + 1].charAt(0) == '-')
|| (args[i + 2].charAt(0) == '-')) {
System.out.print("tcg_eventlog_tool command line error:"
+ " 2 or 3 parameters needed for -diff.\n");
System.out.print("usage: elt -d logFile1 logFile2 pcr#");
System.exit(0);
bValidArgs = false;
} else {
inFile = args[i+++1];
inFile2 = args[i+++1];
if (args.length>i+1) {
if (!args[i+1].contains("-")) { // pcr filter provided
eventFilter = args[i+++1];
eventNumber = new Integer(eventFilter).intValue();
inFile = args[i++ + 1];
inFile2 = args[i++ + 1];
if (args.length > i + 1) {
if (!args[i + 1].contains("-")) { // pcr filter provided
eventFilter = args[i++ + 1];
eventNumber = Integer.parseInt(eventFilter);
}
}
bDiff = true;
@ -121,22 +119,22 @@ public class Commander {
break;
case FULL_COMMAND_PREFIX + OUTPUT_STRING:
case COMMAND_PREFIX + "o":
if (i<args.length-1) { // Check for a filter following the -p on the command line
if (!args[i+1].startsWith("-")) {
outFile=args[i+++1];
if (i < args.length - 1) { // Check for a filter following the -o
if (!args[i + 1].startsWith("-")) {
outFile = args[i++ + 1];
} else {
System.out.print("no output file specified with -o option");
System.exit (1);
bValidArgs = false;
}
}
bOutput = true;
break;
case FULL_COMMAND_PREFIX + PCR_STRING:
case COMMAND_PREFIX + "p":
if (i<args.length-1) { // Check for a filter following the -p on the command line
if (!args[i+1].startsWith("-")) {
pcrFilter=args[i+++1];
pcrNumber = new Integer(pcrFilter).intValue();
if (i < args.length - 1) { // Check for a filter following the -p
if (!args[i + 1].startsWith("-")) {
pcrFilter = args[i++ + 1 ];
pcrNumber = Integer.parseInt(pcrFilter);
}
}
bPCRs = true;
@ -144,7 +142,7 @@ public class Commander {
case FULL_COMMAND_PREFIX + VERSION_STRING:
case COMMAND_PREFIX + "v":
System.out.print("TCG Event Log Parser version " + VERSION_NUMBER);
System.exit (0);
bValidArgs = false;
break;
case FULL_COMMAND_PREFIX + VERIFY_STRING:
case COMMAND_PREFIX + "V":
@ -155,15 +153,18 @@ public class Commander {
bHex = true;
break;
case FULL_COMMAND_PREFIX + HELP_STRING:
bHelp = true;
break;
case COMMAND_PREFIX + "h":
default:
printHelp("");
bValidArgs = false;
}
}
}
/**
* Getter for the property that indicates if something was given at the commandline.
* Getter for the property that indicates if something was given at the command line.
*
* @return true if any arguments were passed in.
*/
@ -175,10 +176,16 @@ public class Commander {
* Getter for the input All flag.
* @return true if the All flag was set.
*/
public final boolean getAllFlag() {
return bAll;
public final boolean getValidityFlag() {
return bValidArgs;
}
/**
* Getter for the help flag.
* @return true if the Help flag was set.
*/
public final boolean getHelpFlag() {
return bHelp;
}
/**
* Getter for the input associated with the PCR flag.
* @return true if the PCR Flag was set.
@ -212,7 +219,7 @@ public class Commander {
/**
* Getter for the input associated with the EventIds flag.
* @return true of EventIds Falg was set.
* @return true of EventIds Flag was set.
*/
public final boolean getEventIdsFlag() {
return bEventIds;
@ -220,14 +227,14 @@ public class Commander {
/**
* Getter for the input associated with the File flag.
* @return true if File Flage was set.
* @return true if File Flag was set.
*/
public final boolean getFileFlag() {
return bFile;
}
/**
* Getter for the input associated with the diff flag.
* @return
* @return true if the diff flag was set
*/
public final boolean getDiffFlag() {
return bDiff;
@ -235,7 +242,7 @@ public class Commander {
/**
* Getter for the input associated with the Verify flag.
* @return
* @return true if the verify flag was set
*/
public final boolean getVerifyFile() {
return bVerify;
@ -297,17 +304,17 @@ public class Commander {
return pcrNumber;
}
/**
* This method is used to inform the user of the allowed functionality of
* the program.
* This method is used to inform the user of the allowed functionality of the program.
* @param message message caller specific message to print before listing the help.
*/
private void printHelp(String message) {
public final void printHelp(final String message) {
StringBuilder sb = new StringBuilder();
String os = System.getProperty("os.name").toLowerCase();
if (message != null && !message.isEmpty()) {
sb.append(String.format("ERROR: %s\n\n", message));
if ((message != null) && (!message.isEmpty())) {
sb.append("\n\n" + message);
}
sb.append("\nTCG Log Parser ");
if (os.compareToIgnoreCase("linux")==0) {
if (os.compareToIgnoreCase("linux") == 0) {
sb.append("Usage: sh elt.sh [OPTION]...-f [FILE]...\n");
} else {
sb.append("Usage: ./elt.ps1 [OPTION]...-f [FILE]...\n");
@ -317,10 +324,12 @@ public class Commander {
+ "\n\t\t\t Following parameter MUST be a path and file name."
+ "\n\t\t\t The local Event Log file will be used if this option is not present."
+ "\n\t\t\t Note: Access to the local Event Log may require admin privileges.\n"
+ " -e\t--event\t\t Display event descriptions (including event content) in human readable form. "
+ " -e\t--event\t\t Display event descriptions (including event content) in "
+ "human readable form."
+ "\n\t\t\t Following optional parameter is a single pcr id used to filter"
+ " the output."
+ "\n\t\t\t All events will be displayed if the optional parameter is not provided.\n"
+ "\n\t\t\t All events will be displayed if the optional parameter is not +"
+ "provided.\n"
+ " -ec\t--contenthex\t Displays event content"
+ " in eventhex format when -event is used.\n"
+ " -ex\t--eventhex\t Displays event in hex format when -event is used"
@ -334,53 +343,57 @@ public class Commander {
+ "\n\t\t\t Following parameter MAY be a PCR number used to specify a single pcr."
+ "\n\t\t\t No following parameters will display all PCRs.\n"
+ " -v\t--version\t Parser Version.\n"
// + " -V\t--Verify\t Attempts to verify the log file against values on the local device."
// + " -V\t--Verify\t Attempts to verify the log file against values."
+ " -x\t--hex\t\t Displays output in hex format."
+ "\n\t\t\t Use -e -ec and -ex options to filter output."
+ "\n\t\t\t All output will be human readble form if this parameter is not present.\n"
+ "\n");
if (os.compareToIgnoreCase("linux")==0) {
+ "\n\t\t\t All output will be human readble form if not present."
+ "\n\n");
if (os.compareToIgnoreCase("linux") == 0) {
sb.append("\nIf no FILE parameter is provided then the standard Linux TCGEventLog path "
+ "\n(/sys/kernel/security/tpm0/binary_bios_measurements) is used."
+"\n Note admin privileges may be required (e.g. use sudo when running the script).\n"
+"All OPTIONS must be seperated by a space delimiter, no concatenation"
+ "\n Note admin privileges may be required (e.g. use sudo when running the "
+ " script).\n"
+ "All OPTIONS must be seperated by a space delimiter, no concatenation"
+ " of OPTIONS is currently supported.\n"
+"\nExamples: (run from the script directory)\n"
+"1. Display all events from the binary_bios_measurements.bin test pattern:\n"
+" sh elt.sh -f ../test/testdata/binary_bios_measurements_Dell_Fedora30.bin -e\n"
+"2. Display only the event with an index of 0 (e.g event that extend PCR 0):\n"
+" sh scripts/elt.sh -f "
+ "\nExamples: (run from the script directory)\n"
+ "1. Display all events from the binary_bios_measurements.bin test pattern:\n"
+ " sh elt.sh -f ../test/testdata/binary_bios_measurements_Dell_Fedora30.bin "
+ " -e\n"
+ "2. Display only the event with an index of 0 (e.g event that extend PCR 0):\n"
+ " sh scripts/elt.sh -f "
+ "../test/testdata/binary_bios_measurements_Dell_Fedora30.bin -p 0\n"
);
} else { //windows
sb.append("\nIf no FILE parameter is provided then the "
+ "standard Windows TCGEventLog path (C:\\Windows\\Logs\\MeasuredBoot) is used"
+"\n Note admin privileges may be required (e.g. run as Administrator).\n"
+"All OPTIONS must be seperated by a space delimiter, "
+ "\n Note admin privileges may be required (e.g. run as Administrator).\n"
+ "All OPTIONS must be seperated by a space delimiter, "
+ "no concatenation of OPTIONS is currently supported.\n"
+"\nExamples:(run from the script directory)\n"
+"1. Display all events from the binary_bios_measurements.bin test pattern:\n"
+" ./elt.ps1 -f "
+ "\nExamples:(run from the script directory)\n"
+ "1. Display all events from the binary_bios_measurements.bin test pattern:\n"
+ " ./elt.ps1 -f "
+ "..\\test\\testdata\\binary_bios_measurements_Dell_Fedora30.bin -e\n"
+"2. Display only the event with an index of 0 (e.g event that extend PCR 0):\n"
+" ./elt.ps1 -f "
+ "2. Display only the event with an index of 0 (e.g event that extend PCR 0):\n"
+ " ./elt.ps1 -f "
+ "..\\test\\testdata\\binary_bios_measurements_Dell_Fedora30.bin -p 0\n"
);
}
System.out.println(sb.toString());
System.exit(1);
}
/**
* Checks that the file given to create a new swidtag is a valid path.
* @param filepath
* @return
* Checks that the file path is a valid.
* @param filepath file path of file to check
* @return true if path is valid
*/
public static boolean isValidPath(String filepath) {
public static boolean isValidPath(final String filepath) {
try {
System.out.println("Checking for a valid creation path...");
File file = new File(filepath);
file.createNewFile();
boolean test = file.createNewFile();
if (!test) {
return false;
}
} catch (IOException | InvalidPathException | NullPointerException ex) {
return false;
}

View File

@ -0,0 +1,313 @@
package hirs.tcg_eventlog;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import hirs.tpm.eventlog.TCGEventLog;
import hirs.tpm.eventlog.TpmPcrEvent;
import hirs.utils.HexUtils;
/**
* Command-line application for processing TCG Event Logs.
* Input arg: path to *.tcglp file
*/
final class Main {
private static Commander commander = null;
private static FileOutputStream outputStream = null;
private static byte[] eventLog = null;
private static boolean bContentFlag, bEventFlag, bHexEvent, bHexFlag, bPcrFlag = false;
/**
* Main Constructor.
* @param args command line parameters.
*/
public static void main(final String[] args) {
commander = new Commander(args);
if (!commander.getValidityFlag()) {
System.out.print("Program exiting wihtout processs due to issues with"
+ " parameters provided.");
System.exit(1);
}
if (commander.hasArguments()) {
if (commander.getHelpFlag()) {
commander.printHelp("");
System.exit(1);
}
if (commander.getOutputFlag()) {
try {
outputStream = new FileOutputStream(commander.getOutputFileName());
} catch (FileNotFoundException e) {
System.out.print("Error opening output file" + commander.getOutputFileName()
+ "\nError was " + e.getMessage());
System.exit(1);
}
}
if (commander.getFileFlag()) {
eventLog = openLog(commander.getInFileName());
}
if (commander.getContentFlag()) {
bContentFlag = true;
}
if (commander.getDiffFlag()) {
bEventFlag = true;
String results = compareLogs(commander.getInFileName(),
commander.getInFile2Name());
writeOut(results);
System.exit(0);
}
if (commander.getEventIdsFlag()) {
bEventFlag = true;
}
if (commander.getEventHexFlag()) {
bHexEvent = true;
}
if (commander.getPCRFlag()) {
bPcrFlag = true;
}
if (commander.getVerifyFile()) {
System.out.print("Verify option is not yet implemented");
System.exit(1);
}
if (commander.getHexFlag()) {
bHexFlag = true;
}
} else {
System.out.print("Nothing to do: No Parameters provided.");
System.exit(1);
} // End commander processing
try {
if (eventLog == null) {
eventLog = openLog("");
}
// Main Event processing
TCGEventLog evLog = new TCGEventLog(eventLog, bEventFlag, bContentFlag, bHexEvent);
if (bPcrFlag) {
String[] pcrs = evLog.getExpectedPCRValues();
int count = 0;
if (!commander.getHexFlag()) {
writeOut("Expected Platform Configuration Register (PCR) values"
+ " derived from the Event Log: \n\n");
}
for (String pcr: pcrs) {
if (count++ == commander.getPcrNumber() || (commander.getPcrNumber() == -1)) {
if (bHexFlag) {
writeOut(pcr.toString() + "\n");
} else {
writeOut(" pcr " + (count - 1) + " = " + pcr.toString() + "\n");
}
}
}
if (!bHexFlag) {
writeOut("\n----------------- End PCR Values ----------------- \n\n");
}
}
// General event log output
if (bEventFlag) {
if (!bHexFlag) {
if (evLog.isCryptoAgile()) {
writeOut("\nEvent Log follows the \"Crypto Agile\" format and has "
+ evLog.getEventList().size() + " events:\n\n");
} else {
writeOut("\nEvent Log follows the \"SHA1\" format and has "
+ evLog.getEventList().size() + " events:\n\n");
}
}
for (TpmPcrEvent event: evLog.getEventList()) {
if ((commander.getEventNumber() == event.getPcrIndex())
|| commander.getEventNumber() == -1) {
if (bHexFlag) {
if (bEventFlag || bHexEvent) {
writeOut(HexUtils.byteArrayToHexString(event.getEvent()) + "\n");
}
if (bContentFlag) {
writeOut(HexUtils.byteArrayToHexString(event.getEventContent())
+ "\n");
}
} else {
writeOut(event.toString(bEventFlag, bContentFlag, bHexEvent) + "\n");
}
}
}
}
} catch (IOException i) {
System.out.print("IO error processing Event Log " + commander.getInFileName()
+ "\nError was " + i.toString());
System.exit(1);
} catch (CertificateException c) {
System.out.print("Certificate error processing Event Log " + commander.getInFileName()
+ "\nError was " + c.toString());
System.exit(1);
} catch (NoSuchAlgorithmException a) {
System.out.print("Algorithm error processing Event Log " + commander.getInFileName()
+ "\nError was " + a.toString());
System.exit(1);
}
}
/**
* Opens a TCG Event log file.
* @param fileName Name of the log file. Will use a OS specific default.
* @return a byte array holding the entire log
*/
public static byte[] openLog(final String fileName) {
String os = System.getProperty("os.name").toLowerCase(), fName = fileName;
byte[] rawLog = null;
boolean bDefault = false;
try {
if (fileName.isEmpty()) {
if (os.compareToIgnoreCase("linux") == 0) { // need to find Windows path
fName = "/sys/kernel/security/tpm0/binary_bios_measurements";
bDefault = true;
writeOut("Local Event Log being used: " + fileName + "\n");
}
}
Path path = Paths.get(fName);
rawLog = Files.readAllBytes(path);
if (!commander.getHexFlag()) {
writeOut("tcg_eventlog_tool is opening file:" + path + "\n");
}
} catch (Exception e) {
String error = "Error reading event Log File: " + e.toString();
if (bDefault) {
error += "\nTry using the -f option to specify an Event Log File";
}
writeOut(error);
System.exit(1);
}
return rawLog;
}
/**
* Write data out to the system and/or a file.
* @param data
*/
private static void writeOut(final String data) {
try {
String dataNoNull = data.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
if (commander.getOutputFlag()) {
outputStream.write(dataNoNull.getBytes(Charset.forName("UTF-8")));
} else {
System.out.print(dataNoNull); // output to the console
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Compares 2 Event Logs and returns a string based upon the results.
* Uses the Events digest field for comparisons.
* @param logFileName1 Log file to use as a reference.
* @param logFileName2 Log file to compare to the reference.
* @return A sting containing human readable results.
*/
public static String compareLogs(final String logFileName1, final String logFileName2) {
TCGEventLog eventLog1 = null, eventLog2 = null;
byte[] evLog = openLog(logFileName1);
byte[] evLog2 = openLog(logFileName2);
StringBuilder sb = new StringBuilder();
try {
eventLog1 = new TCGEventLog(evLog);
} catch (Exception e) {
sb.append("\nError processing event log " + logFileName1 + " : " + e.getMessage());
return sb.toString();
}
try {
eventLog2 = new TCGEventLog(evLog2);
ArrayList<TpmPcrEvent> errors = diffEventLogs(eventLog1.getEventList(),
eventLog2.getEventList(), commander.getPcrNumber());
if (errors.isEmpty() && !bHexFlag) {
sb.append("\nEvent Log " + logFileName1 + " MATCHED EventLog " + logFileName2);
} else {
if (!errors.isEmpty() && !bHexFlag) {
sb.append("\nEvent Log " + logFileName1
+ " did NOT match EventLog " + logFileName2 + "\n");
sb.append("There were " + errors.size() + " event mismatches: \n\n");
}
for (TpmPcrEvent error : errors) {
if (bHexFlag) {
if (bEventFlag || bHexEvent) {
sb.append(HexUtils.byteArrayToHexString(error.getEvent()) + "\n");
}
if (bContentFlag) {
sb.append(HexUtils.byteArrayToHexString(error.getEventContent())
+ "\n");
}
} else {
sb.append(error.toString(bEventFlag, bContentFlag, bHexEvent) + "\n");
}
}
}
} catch (IOException i) {
System.out.print("IO error processing Event Log " + commander.getInFileName()
+ "\nError was " + i.toString());
System.exit(1);
} catch (CertificateException c) {
System.out.print("Certificate error processing Event Log " + commander.getInFileName()
+ "\nError was " + c.toString());
System.exit(1);
} catch (NoSuchAlgorithmException a) {
System.out.print("Algorithm error processing Event Log " + commander.getInFileName()
+ "\nError was " + a.toString());
System.exit(1);
}
return sb.toString();
}
/**
* Compare this event log against a second event log.
* Returns a String Array of event descriptions in which the digests from the first
* did no match the second. Return value is null if all events matched.
* @param eventList initial events.
* @param eventList2 events to compare against.
* @param pcr used as a filter. Use -1 to check all pcrs.
* @return array list of strings. Null of no events mismatched.
*/
public static ArrayList<TpmPcrEvent> diffEventLogs(final ArrayList<TpmPcrEvent> eventList,
final ArrayList<TpmPcrEvent> eventList2, final int pcr) {
ArrayList<TpmPcrEvent> results = new ArrayList<TpmPcrEvent>();
for (TpmPcrEvent event2 : eventList2) {
if (pcr >= 0) {
if (event2.getPcrIndex() == pcr) {
if (!digestMatch(eventList, event2)) {
results.add(event2);
}
}
} else {
if (!digestMatch(eventList, event2)) {
results.add(event2);
}
}
}
return results;
}
/**
* Checks a digest from a single event against all digests with the same index in an Event Log.
* @param eventLog The Reference Event log.
* @param event single event to match.
* @return
*/
private static boolean digestMatch(final ArrayList<TpmPcrEvent> eventLog,
final TpmPcrEvent event) {
boolean matchFound = false;
for (TpmPcrEvent event2 : eventLog) {
if ((event.getPcrIndex() == event2.getPcrIndex())
&& (Arrays.equals(event.getEventDigest(), event2.getEventDigest()))) {
matchFound = true;
}
}
return matchFound;
}
}

View File

@ -0,0 +1,5 @@
/**
* Base package that includes common exceptions, interfaces and base implementations for and related
* to the ACA.
*/
package hirs.tcg_eventlog;

View File

@ -1,157 +0,0 @@
task wrapper(type: Wrapper) {
gradleVersion = '2.10'
}
allprojects {
task addPlugins << {
delete './build/plugins'
mkdir './build/plugins'
if (project.hasProperty('pluginDir')) {
if (pluginDir?.trim()) {
copy {
from "$pluginDir"
into 'build/plugins'
include '*.jar'
include '**/*.jar'
}
}
}
}
task copyVersion() {
doLast {
if (project.hasProperty('displayVersion')) {
String resourceDir="${buildDir}/resources/main"
println "setting app version file contents of: ${displayVersion} to ${resourceDir}"
new File(resourceDir, "VERSION").write("$displayVersion")
}
}
}
group = 'hirs'
version = file("$rootDir/VERSION").text.trim() + "-SNAPSHOT"
}
subprojects {
apply plugin: 'java'
apply plugin: 'maven-publish'
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-Werror"
}
repositories {
mavenCentral()
}
test {
testLogging {
exceptionFormat = 'full'
}
}
tasks.withType(Test) {
useTestNG() {
includeGroups = project.ext.includeGroups.split()
excludeGroups = project.ext.excludeGroups.split()
}
afterSuite { desc, result ->
if (desc.parent == null) {
logger.lifecycle("${result.successfulTestCount}/${result.testCount} tests passed")
}
}
}
tasks.withType(FindBugs) {
reports {
xml.enabled = false
html.enabled = true
}
}
tasks.withType(Pmd) {
reports {
xml.enabled = false
html.enabled = true
}
}
publishing {
repositories {
if(findProperty("env") != null && findProperty("env") == "CI") {
maven {
url "$rootDir/librepo"
}
} else {
mavenLocal()
}
}
}
// Global checkstyle file
ext.checkstyleConfigFile = new File(rootDir, "/config/checkstyle/sun_checks.xml")
// Version definitions of all of the libraries we're using. They're defined
// here to ensure that all projects are using the same versions of common
// dependencies:
ext.libs = [
bouncy_castle: 'org.bouncycastle:bcmail-jdk15on:1.59',
checkstyle: 'com.puppycrawl.tools:checkstyle:8.10.1',
commons_cli: 'commons-cli:commons-cli:1.2',
commons_codec: 'commons-codec:commons-codec:1.9',
commons_csv: 'org.apache.commons:commons-csv:1.4',
commons_exec: 'org.apache.commons:commons-exec:1.3',
commons_http: 'commons-httpclient:commons-httpclient:3.1',
commons_io: 'commons-io:commons-io:2.4',
commons_lang: 'org.apache.commons:commons-lang3:3.3.2',
commons_upload:'commons-fileupload:commons-fileupload:1.3.1',
commons_valid: 'commons-validator:commons-validator:1.4.0',
findbugs: 'com.google.code.findbugs:findbugs:3.0.0',
gson: 'com.google.code.gson:gson:2.2.4',
guava: 'com.google.guava:guava:18.0',
hibernate: [ 'org.hibernate.common:hibernate-commons-annotations:4.0.4.Final',
'org.hibernate:hibernate-core:4.3.11.Final',
'org.hibernate:hibernate-hikaricp:4.3.11.Final'],
hikari: 'com.zaxxer:HikariCP:2.4.1',
hsqldb: 'org.hsqldb:hsqldb:2.3.2',
http: 'org.apache.httpcomponents:httpclient:4.5',
jackson: [ 'com.fasterxml.jackson.core:jackson-core:2.6.3',
'com.fasterxml.jackson.core:jackson-databind:2.6.3',
'com.fasterxml.jackson.core:jackson-annotations:2.6.3'],
jadira_usertype: 'org.jadira.usertype:usertype.core:4.0.0.GA',
jcommander: 'com.beust:jcommander:1.35',
joda_time: 'joda-time:joda-time:2.9.4',
jstl: [ 'org.apache.taglibs:taglibs-standard-impl:1.2.5',
'org.apache.taglibs:taglibs-standard-spec:1.2.5'],
log4j2: [ 'org.apache.logging.log4j:log4j-api:2.8.1',
'org.apache.logging.log4j:log4j-core:2.8.1',
'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1'],
log4j2_web: 'org.apache.logging.log4j:log4j-web:2.8.1',
log_bridge: 'org.apache.logging.log4j:log4j-jcl:2.8.1',
mockito: 'org.mockito:mockito-all:1.10.19',
mariadb: 'org.mariadb.jdbc:mariadb-java-client:2.2.1',
minimal_json: 'com.eclipsesource.minimal-json:minimal-json:0.9.5',
pci_ids: 'com.github.marandus:pci-ids:0.3',
pmd: 'net.sourceforge.pmd:pmd:5.1.1',
powermock: [ 'org.powermock:powermock-core:1.6.3',
'org.powermock:powermock-api-mockito:1.6.3',
'org.powermock:powermock-module-testng:1.6.3' ],
protobuf_java: 'com.google.protobuf:protobuf-java:3.4.0',
reflections: 'org.reflections:reflections:0.9.9-RC1',
servlet_api: 'javax.servlet:servlet-api:2.5',
slf4j: 'org.slf4j:slf4j-api:1.7.13',
spring_core: ['org.springframework:spring-aop:4.2.3.RELEASE',
'org.springframework:spring-beans:4.2.3.RELEASE',
'org.springframework:spring-context:4.2.3.RELEASE',
'org.springframework:spring-expression:4.2.3.RELEASE',
'org.springframework:spring-orm:4.2.3.RELEASE'],
spring_msg: 'org.springframework:spring-messaging:4.2.3.RELEASE',
spring_plugin: 'org.springframework.plugin:spring-plugin-core:1.2.0.RELEASE',
spring_retry: 'org.springframework.retry:spring-retry:1.2.0.RELEASE',
spring_test: 'org.springframework:spring-test:4.2.3.RELEASE',
spring_web: 'org.springframework:spring-web:4.2.3.RELEASE',
spring_webmvc: 'org.springframework:spring-webmvc:4.2.3.RELEASE',
testng: 'org.testng:testng:6.8.8',
xml_rpc_client: 'org.apache.xmlrpc:xmlrpc-client:3.1.3',
]
}

View File

@ -1,277 +0,0 @@
package hirs.tcg_eventlog_tool;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import hirs.tpm.eventlog.TCGEventLog;
import hirs.tpm.eventlog.TpmPcrEvent;
import hirs.utils.HexUtils;
/**
* Command-line application for processing TCG Event Logs.
* Input arg: path to *.tcglp file
*
*/
public class Main {
private static Commander commander = null;
static FileOutputStream outputStream = null;
static byte[] eventLog = null;
static boolean bContentFlag, bEventFlag, bHexEvent, bHexFlag, bPcrFlag, bOutFile = false;
public static void main(String[] args) {
commander = new Commander(args);
if (commander.hasArguments()) {
if (commander.getOutputFlag()) {
try {
outputStream = new FileOutputStream(commander.getOutputFileName());
} catch (FileNotFoundException e) {
System.out.print("Error opening output file" + commander.getOutputFileName()
+ "\nError was "+ e.getMessage());
System.exit(1);
}
}
if (commander.getFileFlag()) {
eventLog = openLog(commander.getInFileName());
}
if (commander.getAllFlag()) {
System.out.print("All option is not yet implemented");
System.exit(1);
}
if (commander.getContentFlag()) {
bContentFlag = true;
}
if (commander.getDiffFlag()) {
bEventFlag = true;
if(commander.getHexFlag()) {
bHexFlag=bHexEvent = bContentFlag = true;
}
String results = compareLogs (commander.getInFileName(),commander.getInFile2Name());
writeOut(results);
System.exit(0);
}
if (commander.getEventIdsFlag()) {
bEventFlag = true;
}
if (commander.getEventHexFlag()) {
bHexEvent = true;
}
if (commander.getPCRFlag()) {
bPcrFlag = true;
}
if (commander.getVerifyFile()) {
System.out.print("Verify option is not yet implemented");
System.exit(1);
}
if (commander.getHexFlag()) {
bHexFlag = true;
}
} else {
System.out.print("Nothing to do: No Parameters provided.");
System.exit(1);
} // End commander processing
try {
if (eventLog == null) {
eventLog = openLog("");
}
// Main Event processing
TCGEventLog evLog = new TCGEventLog(eventLog, bEventFlag, bContentFlag, bHexEvent);
// Check for pcr flag
if (bPcrFlag) {
String[] pcrs = evLog.getExpectedPCRValues();
int count = 0;
if(!commander.getHexFlag()) {
writeOut("Expected Platform Configuration Register (PCR) values"
+ " derived from the Event Log: \n\n");
}
for (String pcr: pcrs) {
if(count++ == commander.getPcrNumber() || (commander.getPcrNumber() == -1)) {
if(bHexFlag) {
writeOut(pcr.toString()+"\n");
} else {
writeOut(" pcr " + (count-1) + " = " + pcr.toString() + "\n");
}
}
}
if(!bHexFlag) {
writeOut("\n----------------- End PCR Values ----------------- \n\n");
}
}
// General event log output
if (bEventFlag) {
for (TpmPcrEvent event: evLog.getEventList()) {
if ((commander.getEventNumber() == event.getPcrIndex())|| commander.getEventNumber() == -1) {
if(bHexFlag) {
if(bEventFlag || bHexEvent) {
writeOut(HexUtils.byteArrayToHexString(event.getEvent())+ "\n");
}
if(bContentFlag) {
writeOut(HexUtils.byteArrayToHexString(event.getEventContent())+ "\n");
}
}
else {
writeOut(event.toString(bEventFlag, bContentFlag, bHexEvent) + "\n");
}
}
}
}
} catch (Exception e) {
System.out.print("Error processing Event Log " + commander.getInFileName()
+ "\nError was "+ e.toString());
System.exit(1);
}
}
/**
* Opens a TCG Event log file
* @param fileName Name of the log file. Will use a OS specific default file if none is supplied.
* @param os the name os of the current system
* @return a byte array holding the entire log
*/
public static byte[] openLog(String fileName) {
String os = System.getProperty("os.name").toLowerCase();
byte[] rawLog=null;
boolean bDefault = false;
try {
if (fileName == "") {
if (os.compareToIgnoreCase("linux")==0) { // need to find Windows path
fileName = "/sys/kernel/security/tpm0/binary_bios_measurements";
bDefault = true;
writeOut("Local Event Log being used: "+fileName +"\n");
}
}
Path path = Paths.get(fileName);
rawLog = Files.readAllBytes(path);
if(!commander.getHexFlag()) {
writeOut("TPM Event Log parser opening file:"+ path +"\n\n");
}
} catch (Exception e) {
String error = "Error reading event Log File: " + e.toString();
if (bDefault) {
error += "\nTry using the -f option to specify an Event Log File";
}
writeOut(error);
System.exit(1);
}
return rawLog;
}
/**
* Write data out to the system and/or a file.
* @param data
*/
private static void writeOut(String data) {
try {
data = data.replaceAll("[^\\P{C}\t\r\n]", ""); // remove any null characters that seem to upset text editors
if(commander.getOutputFlag()) {
outputStream.write(data.getBytes()); // Write to an output file
} else {
System.out.print(data); // output to the console
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Compares 2 Event Logs and returns a string based upon the results.
* Uses the Events digest field for comparisons.
* @param LogFileName1 Log file to use as a reference.
* @param LogFileName2 Log file to compare to the refernce.
* @return A sting containing human readable results.
*/
public static String compareLogs (String LogFileName1, String LogFileName2) {
TCGEventLog eventLog = null, eventLog2 = null;
byte[] evLog = openLog(LogFileName1);
byte[] evLog2 = openLog(LogFileName2);
StringBuilder sb = new StringBuilder();
try {
eventLog = new TCGEventLog(evLog);
} catch (Exception e) {
sb.append("Error processing event log " + LogFileName1 + " : " + e.getMessage());
return sb.toString();
} try {
eventLog2 = new TCGEventLog(evLog2);
ArrayList<TpmPcrEvent> errors = diffEventLogs(eventLog.getEventList(),
eventLog2.getEventList(), commander.getPcrNumber() );
if (errors.isEmpty() && !bHexFlag) {
sb.append("Event Log " + LogFileName1 + " MATCHED EventLog "+ LogFileName2);
} else {
if (!errors.isEmpty() && !bHexFlag) {
sb.append("Event Log " + LogFileName1
+ " did NOT match EventLog " + LogFileName2 + "\n");
sb.append("There were " + errors.size() + " event mismatches: \n\n");
}
for (TpmPcrEvent error : errors ) {
if(bHexFlag) {
if(bEventFlag || bHexEvent) {
writeOut(HexUtils.byteArrayToHexString(error.getEvent())+ "\n");
}
if(bContentFlag) {
writeOut(HexUtils.byteArrayToHexString(error.getEventContent())+ "\n");
}
}
else {
writeOut(error.toString(bEventFlag, bContentFlag, bHexEvent) + "\n");
}
}
}
} catch (Exception e) {
writeOut("Error processing event log " + LogFileName2 + " : " + e.getMessage());
}
return sb.toString();
}
/**
* Compare this event log against a second event log.
* Returns a String Array of event descriptions in which the digests from the first
* did no match the second. Return value is null if all events matched.
* @param eventList initial events
* @param eventList2 events to compare against
* @param pcr used as a filter. Use -1 to check all pcrs.
* @return array list of strings. Null of no events mismatched.
*/
public static ArrayList<TpmPcrEvent> diffEventLogs(ArrayList<TpmPcrEvent> eventList,
ArrayList<TpmPcrEvent> eventList2, int pcr) {
ArrayList<TpmPcrEvent> results= new ArrayList<TpmPcrEvent>();
for (TpmPcrEvent event2 : eventList2) {
if(pcr >= 0) {
if (event2.getPcrIndex() == pcr) {
if(!digestMatch(eventList,event2)) {
results.add(event2);
}
}
} else {
if(!digestMatch(eventList,event2)) {
results.add(event2);
}
}
}
return results;
}
/**
* Checks a digest from a single event against all digests with the same index in an Event Log.
* @param eventLog The Reference Event log.
* @param event single event to match.
* @return
*/
private static boolean digestMatch(final ArrayList<TpmPcrEvent> eventLog, final TpmPcrEvent event) {
boolean matchFound = false;
for (TpmPcrEvent event2 : eventLog) {
if((event.getPcrIndex() == event2.getPcrIndex())
&& (Arrays.equals(event.getEventDigest(), event2.getEventDigest()))) {
matchFound = true;
}
}
return matchFound;
}
}