From 21db7258150c52d6085ee15274b387a29d8bca52 Mon Sep 17 00:00:00 2001 From: Cyrus <24922493+cyrus-dev@users.noreply.github.com> Date: Fri, 6 Mar 2020 07:06:09 -0500 Subject: [PATCH] [#230] Update RIM details page to display PCRs (#233) * This is an update to the display of the Reference Integrity Manifest code base that'll allow a user to upload a swidtag. This code includes some additions from #217, slightly modified. * This code update include changes to import, archive and delete a swidtag into the RIM object. * Updated the code with additional checks on the uploaded file locations. Added the number associated with the PCR value to the detail page. * This change fixes the bug that caused the rim detail page to go blank if the associated event log file associated with the resource file doesn't exist. Co-authored-by: lareine --- ...eferenceManifestDetailsPageController.java | 49 ++++- .../ReferenceManifestPageController.java | 88 ++++++--- .../main/webapp/WEB-INF/jsp/rim-details.jsp | 112 +++++++----- .../java/hirs/data/persist/SwidResource.java | 52 ++++++ .../tpm/eventlog/CryptoAgileEventLog.java | 135 +------------- .../java/hirs/tpm/eventlog/SHA1EventLog.java | 131 +------------ .../java/hirs/tpm/eventlog/TCGEventLog.java | 173 +++++++++++++++++- .../tpm/eventlog/TCGEventLogProcessor.java | 28 +-- .../java/hirs/tpm/eventlog/TpmPcrEvent.java | 10 - .../java/hirs/tpm/eventlog/TpmPcrEvent1.java | 2 +- .../java/hirs/tpm/eventlog/TpmPcrEvent2.java | 2 +- 11 files changed, 415 insertions(+), 367 deletions(-) diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java index 8cd21439..25f6245c 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java @@ -1,14 +1,22 @@ - package hirs.attestationca.portal.page.controllers; import hirs.data.persist.ReferenceManifest; +import hirs.data.persist.SwidResource; import hirs.persist.ReferenceManifestManager; +import hirs.tpm.eventlog.TCGEventLogProcessor; import hirs.attestationca.portal.page.Page; import hirs.attestationca.portal.page.PageController; import hirs.attestationca.portal.page.PageMessages; import hirs.attestationca.portal.page.params.ReferenceManifestDetailsPageParams; +import java.io.IOException; +import java.nio.file.NoSuchFileException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.UUID; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -24,14 +32,15 @@ import org.springframework.web.servlet.ModelAndView; @Controller @RequestMapping("/rim-details") public class ReferenceManifestDetailsPageController -extends PageController { + extends PageController { private final ReferenceManifestManager referenceManifestManager; - private static final Logger LOGGER = - LogManager.getLogger(ReferenceManifestDetailsPageController.class); + private static final Logger LOGGER + = LogManager.getLogger(ReferenceManifestDetailsPageController.class); /** * Constructor providing the Page's display and routing specification. + * * @param referenceManifestManager the reference manifest manager */ @Autowired @@ -92,12 +101,14 @@ extends PageController { /** * This method takes the place of an entire class for a string builder. * Gathers all information and returns it for displays. + * * @param uuid database reference for the requested RIM. * @param referenceManifestManager the reference manifest manager. * @return mapping of the RIM information from the database. + * @throws java.io.IOException error for reading file bytes. */ public static HashMap getRimDetailInfo(final UUID uuid, - final ReferenceManifestManager referenceManifestManager) { + final ReferenceManifestManager referenceManifestManager) throws IOException { HashMap data = new HashMap<>(); ReferenceManifest rim = ReferenceManifest @@ -140,7 +151,33 @@ extends PageController { // checkout later data.put("rimType", rim.getRimType()); - data.put("swidFiles", rim.parseResource()); + List resources = rim.parseResource(); + String resourceFilename = null; + TCGEventLogProcessor logProcessor = new TCGEventLogProcessor(); + + try { + for (SwidResource swidRes : resources) { + resourceFilename = swidRes.getName(); + Path logPath = Paths.get(String.format("%s/%s", + SwidResource.RESOURCE_UPLOAD_FOLDER, + resourceFilename)); + if (Files.exists(logPath)) { + logProcessor = new TCGEventLogProcessor( + Files.readAllBytes(logPath)); + swidRes.setPcrValues(Arrays.asList( + logProcessor.getExpectedPCRValues())); + } else { + swidRes.setPcrValues(Arrays.asList( + logProcessor.getExpectedPCRValues())); + } + } + } catch (NoSuchFileException nsfEx) { + LOGGER.error(String.format("File Not found!: %s", + resourceFilename)); + LOGGER.error(nsfEx); + } + + data.put("swidFiles", resources); } else { LOGGER.error(String.format("Unable to find Reference Integrity " + "Manifest with ID: %s", uuid)); diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestPageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestPageController.java index f8c6e8e8..75ec1fc8 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestPageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestPageController.java @@ -14,6 +14,7 @@ import hirs.persist.DBManagerException; import hirs.persist.ReferenceManifestManager; import hirs.persist.CriteriaModifier; import hirs.data.persist.ReferenceManifest; +import hirs.data.persist.SwidResource; import hirs.data.persist.certificate.Certificate; import java.io.IOException; import java.net.URISyntaxException; @@ -21,9 +22,14 @@ import java.net.URISyntaxException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.List; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import javax.servlet.http.HttpServletResponse; import org.apache.logging.log4j.LogManager; @@ -44,36 +50,36 @@ import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.support.RedirectAttributes; import org.springframework.web.servlet.view.RedirectView; - /** * Controller for the Reference Manifest page. */ @Controller @RequestMapping("/reference-manifests") public class ReferenceManifestPageController -extends PageController { + extends PageController { private static final String BIOS_RELEASE_DATE_FORMAT = "yyyy-MM-dd"; private final BiosDateValidator biosValidator; private final ReferenceManifestManager referenceManifestManager; - private static final Logger LOGGER = - LogManager.getLogger(ReferenceManifestPageController.class); + private static final Logger LOGGER + = LogManager.getLogger(ReferenceManifestPageController.class); /** - * This class was created for the purposes of avoiding findbugs message: - * As the JavaDoc states, DateFormats are inherently unsafe for - * multi-threaded use. The detector has found a call to an instance - * of DateFormat that has been obtained via a static field. - * This looks suspicious. + * This class was created for the purposes of avoiding findbugs message: As + * the JavaDoc states, DateFormats are inherently unsafe for multi-threaded + * use. The detector has found a call to an instance of DateFormat that has + * been obtained via a static field. This looks suspicious. * * This class can have uses elsewhere but for now it will remain here. */ private static final class BiosDateValidator { + private final String dateFormat; /** * Default constructor that sets the format to parse against. + * * @param dateFormat */ public BiosDateValidator(final String dateFormat) { @@ -82,6 +88,7 @@ extends PageController { /** * Validates a date by attempting to parse based on format provided. + * * @param date string of the given date * @return true if the format matches */ @@ -102,6 +109,7 @@ extends PageController { /** * Constructor providing the Page's display and routing specification. + * * @param referenceManifestManager the reference manifest manager */ @Autowired @@ -113,11 +121,12 @@ extends PageController { } /** - * Returns the path for the view and the data model for the page. + * Returns the filePath for the view and the data model for the page. * * @param params The object to map url parameters into. - * @param model The data model for the request. Can contain data from redirect. - * @return the path for the view and data model for the page. + * @param model The data model for the request. Can contain data from + * redirect. + * @return the filePath for the view and data model for the page. */ @Override public ModelAndView initPage(final NoPageParams params, @@ -126,11 +135,12 @@ extends PageController { } /** - * Returns the list of RIMs using the data table input for paging, - * ordering, and filtering. + * Returns the list of RIMs using the data table input for paging, ordering, + * and filtering. + * * @param input the data tables input - * @return the data tables response, including the result set - * and paging information + * @return the data tables response, including the result set and paging + * information */ @ResponseBody @RequestMapping(value = "/list", @@ -157,7 +167,6 @@ extends PageController { referenceManifestManager, input, orderColumnName, criteriaModifier); - LOGGER.debug("Returning list of size: " + records.size()); return new DataTableResponse<>(records, input); } @@ -177,17 +186,44 @@ extends PageController { final RedirectAttributes attr) throws URISyntaxException, Exception { Map model = new HashMap<>(); PageMessages messages = new PageMessages(); + List rims = new ArrayList<>(); + String fileName; + Path filePath; // loop through the files for (MultipartFile file : files) { + fileName = file.getOriginalFilename(); + if (fileName.toLowerCase().endsWith("swidtag")) { + rims.add(file); + } else { + filePath = Paths.get(String.format("%s/%s", + SwidResource.RESOURCE_UPLOAD_FOLDER, + file.getOriginalFilename())); + if (Files.notExists(Paths.get(SwidResource.RESOURCE_UPLOAD_FOLDER))) { + Files.createDirectory(Paths.get(SwidResource.RESOURCE_UPLOAD_FOLDER)); + } + if (Files.notExists(filePath)) { + Files.createFile(filePath); + } + + Files.write(filePath, file.getBytes()); + + String uploadCompletedMessage = String.format( + "%s successfully uploaded", file.getOriginalFilename()); + messages.addSuccess(uploadCompletedMessage); + LOGGER.info(uploadCompletedMessage); + } + } + + for (MultipartFile file : rims) { //Parse reference manifests - ReferenceManifest rims = parseRIMs(file, messages); + ReferenceManifest rim = parseRIM(file, messages); //Store only if it was parsed - if (rims != null) { + if (rim != null) { storeManifest(file.getOriginalFilename(), messages, - rims, + rim, referenceManifestManager); } } @@ -300,22 +336,23 @@ extends PageController { * @throws IllegalArgumentException */ private ReferenceManifest getRimFromDb(final String id) throws IllegalArgumentException { - UUID uuid = UUID.fromString(id); + UUID uuid = UUID.fromString(id); - return ReferenceManifest - .select(referenceManifestManager) - .byEntityId(uuid).getRIM(); + return ReferenceManifest + .select(referenceManifestManager) + .byEntityId(uuid).getRIM(); } /** * Takes the rim files provided and returns a {@link ReferenceManifest} * object. + * * @param file the provide user file via browser. * @param messages the object that handles displaying information to the * user. * @return a single or collection of reference manifest files. */ - private ReferenceManifest parseRIMs( + private ReferenceManifest parseRIM( final MultipartFile file, final PageMessages messages) { @@ -348,6 +385,7 @@ extends PageController { /** * Stores the {@link ReferenceManifest} objects. + * * @param fileName name of the file given * @param messages message object for user display of statuses * @param referenceManifest the object to store diff --git a/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/rim-details.jsp b/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/rim-details.jsp index 325f55ef..642fbf60 100644 --- a/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/rim-details.jsp +++ b/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/rim-details.jsp @@ -107,51 +107,73 @@
- - -
- -
- -
-
-
- ${resource.getName()} - -
-
- File Size: - ${resource.getSize()}
- Hash: - ${resource.getHashValue()}
- - RIM Format: - ${resource.getRimFormat()}
-
- - RIM Type: - ${resource.getRimType()}
-
- - URI Global: - ${resource.getRimUriGlobal()}
-
-
-
-
-
-
-
-
- + + +
+ +
+ +
+
+
+ ${resource.getName()} + +
+
+ File Size: + ${resource.getSize()}
+ Hash: + ${resource.getHashValue()}
+ + RIM Format: + ${resource.getRimFormat()}
+
+ + RIM Type: + ${resource.getRimType()}
+
+ + URI Global: + ${resource.getRimUriGlobal()}
+
+ +
+ +
+
+ +
+
+ ${pcrValue.key} + ${pcrValue.value} +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -160,4 +182,4 @@ - \ No newline at end of file + diff --git a/HIRS_Utils/src/main/java/hirs/data/persist/SwidResource.java b/HIRS_Utils/src/main/java/hirs/data/persist/SwidResource.java index 531622cd..9bad68c8 100644 --- a/HIRS_Utils/src/main/java/hirs/data/persist/SwidResource.java +++ b/HIRS_Utils/src/main/java/hirs/data/persist/SwidResource.java @@ -3,7 +3,11 @@ package hirs.data.persist; import com.google.common.base.Preconditions; import hirs.utils.xjc.File; import java.util.Map; +import java.util.List; +import java.util.LinkedHashMap; +import java.util.Collections; import java.math.BigInteger; +import java.text.DecimalFormat; import javax.xml.namespace.QName; /** @@ -12,9 +16,20 @@ import javax.xml.namespace.QName; */ public class SwidResource { + private static final String CATALINA_HOME = System.getProperty("catalina.base"); + private static final String TOMCAT_UPLOAD_DIRECTORY + = "/webapps/HIRS_AttestationCAPortal/upload/"; + + /** + * String holder for location for storing binaries. + */ + public static final String RESOURCE_UPLOAD_FOLDER + = CATALINA_HOME + TOMCAT_UPLOAD_DIRECTORY; + private String name, size; private String rimFormat, rimType, rimUriGlobal, hashValue; + private List pcrValues; /** * Default constructor. @@ -26,6 +41,7 @@ public class SwidResource { rimType = null; rimUriGlobal = null; hashValue = null; + pcrValues = null; } /** @@ -112,4 +128,40 @@ public class SwidResource { public String getHashValue() { return hashValue; } + + /** + * Getter for the list of PCR Values. + * @return an unmodifiable list + */ + public List getPcrValues() { + return Collections.unmodifiableList(pcrValues); + } + + /** + * Setter for the list of associated PCR Values. + * @param pcrValues a collection of PCRs + */ + public void setPcrValues(final List pcrValues) { + this.pcrValues = pcrValues; + } + + /** + * Getter for a generated map of the PCR values. + * @return mapping of PCR# to the actual value. + */ + public LinkedHashMap getPcrMap() { + LinkedHashMap innerMap = new LinkedHashMap<>(); + DecimalFormat df = new DecimalFormat("00"); + + if (!this.pcrValues.isEmpty()) { + long iterate = 0; + String pcrNum; + for (String string : this.pcrValues) { + pcrNum = df.format(iterate++); + innerMap.put(String.format("PCR%s:", pcrNum), string); + } + } + + return innerMap; + } } diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/CryptoAgileEventLog.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/CryptoAgileEventLog.java index 2f5200d5..360603f6 100644 --- a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/CryptoAgileEventLog.java +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/CryptoAgileEventLog.java @@ -1,138 +1,11 @@ package hirs.tpm.eventlog; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; - -import hirs.utils.HexUtils; - /** - * Class to handle the "Crypto Agile" Format for TCG Event Logs as defined in the - * TCG Platform Firmware Profile (PFP). - * The Format can provide multiple digests with different algorithm, - * however currently on SHA256 is supported. + * Class to handle the "Crypto Agile" Format for TCG Event Logs as defined in + * the TCG Platform Firmware Profile (PFP). The Format can provide multiple + * digests with different algorithm, however currently on SHA256 is supported. * All other are currently ignored. */ -public class CryptoAgileEventLog implements TCGEventLog { - /** - * SHA256 length = 24 bytes. - */ - private static final int PCR_LENGTH = TpmPcrEvent.SHA256_LENGTH; - /** - * Each PCR bank holds 24 registers. - */ - private static final int PCR_COUNT = 24; - /** - * PFP defined EV_NO_ACTION identifier. - */ - private static final int NO_ACTION_EVENT = 0x00000003; - /** - * 2 dimensional array holding the PCR values. - */ - private byte[][] pcrList = new byte[PCR_COUNT][PCR_LENGTH]; - /** - * List of parsed events within the log. - */ - private ArrayList eventList = new ArrayList<>(); +public class CryptoAgileEventLog { - /** - * Constructor. - * - * @param rawlog the entire tcg log - * @throws IOException if the input stream cannot access the log data - */ - public CryptoAgileEventLog(final byte[] rawlog) throws IOException { - ByteArrayInputStream is = new ByteArrayInputStream(rawlog); - // process the EfiSpecId Event in SHA1 format per the PFP - TpmPcrEvent1 idEvent = new TpmPcrEvent1(is); - eventList.add(idEvent); - // put all events into an event list for further processing - while (is.available() > 0) { // All other events should be Crypto agile - eventList.add(new TpmPcrEvent2(is)); - } - calculatePCRValues(); - } - - /** - * Returns a single PCR value given an index (PCR Number). - */ - @Override - public String[] getExpectedPCRValues() { - String[] pcrs = new String[PCR_COUNT]; - for (int i = 0; i < PCR_COUNT; i++) { - pcrs[i] = HexUtils.byteArrayToHexString(pcrList[i]); - } - return pcrs; - } - - /** - * Returns all 24 PCR values for display purposes. - * - * @param index pcr index - * @return Returns an array of strings for all 24 PCRs - */ - @Override - public String getExpectedPCRValue(final int index) { - return HexUtils.byteArrayToHexString(pcrList[index]); - } - - /** - * Calculates the "Expected Values for TPM PCRs based upon Event digests in the Event Log. - * Uses the algorithm and eventList passed into the constructor. - * - * @return a 2 dimensional bye array holding the hashes of the PCRs. - */ - private void calculatePCRValues() { - byte[] extendedPCR = null; - for (int i = 0; i < PCR_COUNT; i++) { // Initialize the PCRlist array - System.arraycopy(HexUtils.hexStringToByteArray( - "0000000000000000000000000000000000000000000000000000000000000000"), - 0, pcrList[i], 0, PCR_LENGTH); - } - for (TpmPcrEvent currentEvent : eventList) { - if (currentEvent.getPcrIndex() >= 0) { // Ignore NO_EVENTS which can have a PCR=-1 - try { - if (currentEvent.getEventType() != NO_ACTION_EVENT) { - // Don't include EV_NO_ACTION - extendedPCR = extendPCRsha256(pcrList[currentEvent.getPcrIndex()], - currentEvent.getEventDigest()); - System.arraycopy(extendedPCR, 0, pcrList[currentEvent.getPcrIndex()], - 0, PCR_LENGTH); - } - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - } - } - } - - /** - * Extends a sha256 hash with a hash of new data. - * - * @param currentValue byte array holding the current hash value - * @param newEvent byte array holding the value to extend - * @return new hash value - * @throws NoSuchAlgorithmException if hash algorithm is not supported. - */ - private byte[] extendPCRsha256(final byte[] currentValue, final byte[] newEvent) - throws NoSuchAlgorithmException { - return sha256hash( - HexUtils.hexStringToByteArray(HexUtils.byteArrayToHexString(currentValue) - + HexUtils.byteArrayToHexString(newEvent))); - } - - /** - * Creates a sha356 hash of a given byte array. - * - * @param blob byte array hold the value to hash. - * @return byte array holding the hash of the input array. - * @throws NoSuchAlgorithmException if hash algorithm is not supported. - */ - private byte[] sha256hash(final byte[] blob) throws NoSuchAlgorithmException { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(blob); - return md.digest(); - } } diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/SHA1EventLog.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/SHA1EventLog.java index ced29ee4..84d246d5 100644 --- a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/SHA1EventLog.java +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/SHA1EventLog.java @@ -1,134 +1,11 @@ package hirs.tpm.eventlog; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; - -import hirs.utils.HexUtils; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - /** - * Class to handle the "SHA1" Format for TCG Event Logs. - * "SHA1" Format is defined in the TCG Platform Firmware Profile (PFP). - * This is to support older versions of UEFI Firmware or OS that create logs with SHA1. + * Class to handle the "SHA1" Format for TCG Event Logs. "SHA1" Format is + * defined in the TCG Platform Firmware Profile (PFP). This is to support older + * versions of UEFI Firmware or OS that create logs with SHA1. */ -public class SHA1EventLog implements TCGEventLog { - private static final Logger LOGGER - = LogManager.getLogger(TCGEventLog.class); - /** - * SHA256 length = 24 bytes. - */ - private static final int PCR_LENGTH = TpmPcrEvent.SHA1_LENGTH; - /** - * Each PCR bank holds 24 registers. - */ - private static final int PCR_COUNT = 24; - /** - * PFP defined EV_NO_ACTION identifier. - */ - private static final int NO_ACTION_EVENT = 0x00000003; - /** - * List of parsed events within the log. - */ - private final ArrayList eventList = new ArrayList(); - /** - * 2 dimensional array holding the PCR values. - */ - private final byte[][] pcrList1 = new byte[PCR_COUNT][PCR_LENGTH]; +public class SHA1EventLog { - /** - * Constructor. - * - * @param rawlog the entire tcg log - * @throws IOException if the inspur stream cannot access the log data - */ - public SHA1EventLog(final byte[] rawlog) throws IOException { - ByteArrayInputStream is = new ByteArrayInputStream(rawlog); - // put all events into an event list for further processing - while (is.available() > 0) { - eventList.add(new TpmPcrEvent1(is)); - } - calculatePcrValues(); - } - /** - * Returns all 24 PCR values for display purposes. - * - * @return Returns an array of strings representing the expected hash values for all 24 PCRs - */ - public String[] getExpectedPCRValues() { - String[] pcrs = new String[PCR_COUNT]; - for (int i = 0; i < PCR_COUNT; i++) { - pcrs[i] = HexUtils.byteArrayToHexString(pcrList1[i]); - } - return pcrs; - } - - /** - * Returns a single PCR value given an index (PCR Number). - * - * @param index pcr index - * @return String representing the PCR contents - */ - public String getExpectedPCRValue(final int index) { - return HexUtils.byteArrayToHexString(pcrList1[index]); - } - - /** - * Calculates the "Expected Values for TPM PCRs based upon Event digests in the Event Log. - * Uses the algorithm and eventList passed into the constructor, - */ - private void calculatePcrValues() { - byte[] extendedPCR = null; - for (int i = 0; i < PCR_COUNT; i++) { // Initialize the PCRlist1 array - System.arraycopy(HexUtils.hexStringToByteArray( - "0000000000000000000000000000000000000000"), - 0, pcrList1[i], 0, PCR_LENGTH); - } - for (TpmPcrEvent currentEvent : eventList) { - if (currentEvent.getPcrIndex() >= 0) { // Ignore NO_EVENTS which can have a PCR=-1 - try { - if (currentEvent.getEventType() != NO_ACTION_EVENT) { - // Don't include EV_NO_ACTION event - extendedPCR = extendPCRsha1(pcrList1[currentEvent.getPcrIndex()], - currentEvent.getEventDigest()); - System.arraycopy(extendedPCR, 0, pcrList1[currentEvent.getPcrIndex()], - 0, currentEvent.getDigestLength()); - } - } catch (NoSuchAlgorithmException e) { - LOGGER.error(e); - } - } - } - } - - /** - * Extends a sha1 hash with a hash of new data. - * - * @param currentValue value to extend - * @param newEvent value to extend with - * @return new hash resultant hash - * @throws NoSuchAlgorithmException if hash algorithm not supported - */ - private byte[] extendPCRsha1(final byte[] currentValue, final byte[] newEvent) - throws NoSuchAlgorithmException { - return sha1hash(HexUtils.hexStringToByteArray(HexUtils.byteArrayToHexString(currentValue) - + HexUtils.byteArrayToHexString(newEvent))); - } - - /** - * Creates a sha1 hash of a given byte array. - * - * @param blob byte array of data to hash - * @return byte array holding the hash of the input array - * @throws NoSuchAlgorithmException id hash algorithm not supported - */ - private byte[] sha1hash(final byte[] blob) throws NoSuchAlgorithmException { - MessageDigest md = MessageDigest.getInstance("SHA1"); - md.update(blob); - return md.digest(); - } } diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TCGEventLog.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TCGEventLog.java index 87d740ac..264c5837 100644 --- a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TCGEventLog.java +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TCGEventLog.java @@ -1,16 +1,173 @@ package hirs.tpm.eventlog; +import hirs.utils.HexUtils; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + /** * Interface for handling different formats of TCG Event logs. */ -public interface TCGEventLog { - /** Retrieves a all expected PCR values. - * @return String array holding all PCR Values +public class TCGEventLog { + + private static final Logger LOGGER + = LogManager.getLogger(TCGEventLog.class); + + /** + * Init value for SHA 256 values. */ - String[] getExpectedPCRValues(); - /** Retrieves a single expected PCR values. - * @param index the PCR reference - * @return a String holding an expected PCR value + public static final String INIT_SHA256_LIST = "00000000000000000000000000" + + "00000000000000000000000000000000000000"; + /** + * Init value for SHA 1 values. */ - String getExpectedPCRValue(int index); + public static final String INIT_SHA1_LIST = "0000000000000000000000000000000000000000"; + + /** + * PFP defined EV_NO_ACTION identifier. + */ + public static final int NO_ACTION_EVENT = 0x00000003; + /** + * String value of SHA1 hash. + */ + public static final String HASH_STRING = "SHA1"; + /** + * String value of SHA256 hash. + */ + public static final String HASH256_STRING = "SHA-256"; + /** + * Each PCR bank holds 24 registers. + */ + public static final int PCR_COUNT = 24; + /** + * 2 dimensional array holding the PCR values. + */ + private final byte[][] pcrList; + /** + * List of parsed events within the log. + */ + private final ArrayList eventList = new ArrayList<>(); + + private int pcrLength; + private String hashType; + private String initValue; + + /** + * Default blank object constructor. + */ + public TCGEventLog() { + this.pcrList = new byte[PCR_COUNT][TpmPcrEvent.SHA1_LENGTH]; + initValue = INIT_SHA1_LIST; + pcrLength = TpmPcrEvent.SHA1_LENGTH; + initPcrList(); + } + + /** + * Default constructor for just the rawlog that'll set up SHA1 Log. + * @param rawlog data for the event log file + * @throws IOException IO Stream for the event log + */ + public TCGEventLog(final byte[] rawlog) throws IOException { + this(rawlog, TpmPcrEvent.SHA1_LENGTH, HASH_STRING, INIT_SHA1_LIST); + } + + /** + * Default constructor for specific log. + * @param rawlog data for the event log file + * @param pcrLength determined by SHA1 or 256 + * @param hashType the type of algorithm + * @param initValue the default blank value + * @throws IOException IO Stream for the event log + */ + public TCGEventLog(final byte[] rawlog, final int pcrLength, + final String hashType, final String initValue) throws IOException { + this.pcrLength = pcrLength; + this.pcrList = new byte[PCR_COUNT][pcrLength]; + this.hashType = hashType; + this.initValue = initValue; + ByteArrayInputStream is = new ByteArrayInputStream(rawlog); + // put all events into an event list for further processing + while (is.available() > 0) { + eventList.add(new TpmPcrEvent1(is)); + } + calculatePcrValues(); + } + + /** + * This method puts blank values in the pcrList. + */ + private void initPcrList() { + for (int i = 0; i < PCR_COUNT; i++) { // Initialize the PCRlist1 array + System.arraycopy(HexUtils.hexStringToByteArray( + initValue), + 0, pcrList[i], 0, pcrLength); + } + } + + /** + * Calculates the "Expected Values for TPM PCRs based upon Event digests in the Event Log. + * Uses the algorithm and eventList passed into the constructor, + */ + private void calculatePcrValues() { + byte[] extendedPCR; + initPcrList(); + for (TpmPcrEvent currentEvent : eventList) { + if (currentEvent.getPcrIndex() >= 0) { // Ignore NO_EVENTS which can have a PCR=-1 + try { + if (currentEvent.getEventType() != NO_ACTION_EVENT) { + // Don't include EV_NO_ACTION event + extendedPCR = extendPCR(pcrList[currentEvent.getPcrIndex()], + currentEvent.getEventDigest()); + System.arraycopy(extendedPCR, 0, pcrList[currentEvent.getPcrIndex()], + 0, currentEvent.getDigestLength()); + } + } catch (NoSuchAlgorithmException e) { + LOGGER.error(e); + } + } + } + } + + /** + * Extends a hash with a hash of new data. + * + * @param currentValue value to extend + * @param newEvent value to extend with + * @return new hash resultant hash + * @throws NoSuchAlgorithmException if hash algorithm not supported + */ + private byte[] extendPCR(final byte[] currentValue, final byte[] newEvent) + throws NoSuchAlgorithmException { + MessageDigest md = MessageDigest.getInstance(hashType); + md.update(HexUtils.hexStringToByteArray(HexUtils.byteArrayToHexString(currentValue) + + HexUtils.byteArrayToHexString(newEvent))); + return md.digest(); + } + + /** + * Returns all 24 PCR values for display purposes. + * + * @return Returns an array of strings representing the expected hash values for all 24 PCRs + */ + public String[] getExpectedPCRValues() { + String[] pcrs = new String[PCR_COUNT]; + for (int i = 0; i < PCR_COUNT; i++) { + pcrs[i] = HexUtils.byteArrayToHexString(pcrList[i]); + } + return pcrs; + } + + /** + * Returns a single PCR value given an index (PCR Number). + * + * @param index pcr index + * @return String representing the PCR contents + */ + public String getExpectedPCRValue(final int index) { + return HexUtils.byteArrayToHexString(pcrList[index]); + } } diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TCGEventLogProcessor.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TCGEventLogProcessor.java index a38e26b3..037ea560 100644 --- a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TCGEventLogProcessor.java +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TCGEventLogProcessor.java @@ -20,10 +20,6 @@ public class TCGEventLogProcessor { * Name of the hash algorithm used to process the Event Log, default is SHA256. */ private String algorithm = "SHA256"; - /** - * PFP defined EV_NO_ACTION identifier. - */ - private static final int NO_ACTION_EVENT = 0x00000003; /** * Parsed event log array. */ @@ -37,6 +33,13 @@ public class TCGEventLogProcessor { */ private static final int SIG_SIZE = 16; + /** + * Default Constructor. + */ + public TCGEventLogProcessor() { + tcgLog = new TCGEventLog(); + } + /** * Constructor. * @@ -45,9 +48,10 @@ public class TCGEventLogProcessor { */ public TCGEventLogProcessor(final byte[] rawLog) throws IOException { if (isLogCrytoAgile(rawLog)) { - tcgLog = new CryptoAgileEventLog(rawLog); + tcgLog = new TCGEventLog(rawLog, TpmPcrEvent.SHA256_LENGTH, + TCGEventLog.HASH256_STRING, TCGEventLog.INIT_SHA256_LIST); } else { - tcgLog = new SHA1EventLog(rawLog); + tcgLog = new TCGEventLog(rawLog); algorithm = "SHA"; } } @@ -80,8 +84,8 @@ public class TCGEventLogProcessor { */ public TpmWhiteListBaseline createTPMBaseline(final String name) { TpmWhiteListBaseline baseline = new TpmWhiteListBaseline(name); - TPMMeasurementRecord record = null; - String pcrValue = ""; + TPMMeasurementRecord record; + String pcrValue; for (int i = 0; i < TpmPcrEvent.PCR_COUNT; i++) { if (algorithm.compareToIgnoreCase("SHA1") == 0) { // Log Was SHA1 Format pcrValue = tcgLog.getExpectedPCRValue(i); @@ -112,15 +116,13 @@ public class TCGEventLogProcessor { System.arraycopy(log, TpmPcrEvent.INT_LENGTH, eType, 0, TpmPcrEvent.INT_LENGTH); byte[] eventType = HexUtils.leReverseByte(eType); int eventID = new BigInteger(eventType).intValue(); - if (eventID != NO_ACTION_EVENT) { + if (eventID != TCGEventLog.NO_ACTION_EVENT) { return false; } // Event Type should be EV_NO_ACTION byte[] signature = new byte[SIG_SIZE]; System.arraycopy(log, SIG_OFFSET, signature, 0, SIG_SIZE); // should be "Spec ID Event03" String sig = new String(signature, "UTF-8").substring(0, SIG_SIZE - 1); // remove null char - if (sig.equals("Spec ID Event03")) { - return true; - } - return (false); + + return sig.equals("Spec ID Event03"); } } diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent.java index 93724934..40f7cd30 100644 --- a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent.java +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent.java @@ -167,16 +167,6 @@ public class TpmPcrEvent { return errata; } - /** - * Sets the event digest value after processing. - * - * @param digestData SHA1 or SHA256 digest to set - */ - protected void setDigest(final byte[] digestData) { - digest = new byte[digestLength]; - System.arraycopy(digestData, 0, digest, 0, digestLength); - } - /** * Sets the event content after processing. * diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent1.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent1.java index 11868ba7..489e2ccc 100644 --- a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent1.java +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent1.java @@ -41,7 +41,7 @@ public class TpmPcrEvent1 extends TpmPcrEvent { setEventType(unit32Data); byte[] eventDigest = new byte[SHA1_LENGTH]; is.read(eventDigest); - setDigest(eventDigest); + setEventDigest(eventDigest); is.read(unit32Data); int eventSize = HexUtils.leReverseInt(unit32Data); byte[] eventContent = new byte[eventSize]; diff --git a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent2.java b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent2.java index ad8c1f20..809195cb 100644 --- a/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent2.java +++ b/HIRS_Utils/src/main/java/hirs/tpm/eventlog/TpmPcrEvent2.java @@ -84,7 +84,7 @@ public class TpmPcrEvent2 extends TpmPcrEvent { hashAlg = new TcgTpmtHa(is); hashlist.add(hashAlg); if (hashAlg.getHashName().compareToIgnoreCase("TPM_ALG_SHA256") == 0) { - setDigest(hashAlg.getDigest()); + setEventDigest(hashAlg.getDigest()); } } is.read(rawInt);