From 035efad9d2dfca9e7c2a00780a8dc4fd98d83134 Mon Sep 17 00:00:00 2001 From: Cyrus <24922493+cyrus-dev@users.noreply.github.com> Date: Mon, 31 Jan 2022 14:11:36 -0500 Subject: [PATCH] Updated code allows the tpm event table to be searched and information updated when the swidtag is added. --- .../ReferenceManifestPageController.java | 80 ++++++++- .../data/persist/ReferenceDigestValue.java | 80 ++++++++- .../hirs/persist/DBReferenceEventManager.java | 65 ++------ .../hirs/persist/ReferenceEventManager.java | 12 +- .../hirs/persist/ReferenceEventSelector.java | 157 ++++++++++++++++++ 5 files changed, 328 insertions(+), 66 deletions(-) create mode 100644 HIRS_Utils/src/main/java/hirs/persist/ReferenceEventSelector.java 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 ccb9d9b2..af42810d 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 @@ -10,13 +10,17 @@ import hirs.attestationca.portal.page.PageController; import hirs.attestationca.portal.page.PageMessages; import hirs.attestationca.portal.page.params.NoPageParams; import hirs.data.persist.BaseReferenceManifest; +import hirs.data.persist.ReferenceDigestValue; import hirs.data.persist.ReferenceManifest; import hirs.data.persist.SupportReferenceManifest; import hirs.data.persist.SwidResource; import hirs.data.persist.certificate.Certificate; import hirs.persist.CriteriaModifier; import hirs.persist.DBManagerException; +import hirs.persist.ReferenceEventManager; import hirs.persist.ReferenceManifestManager; +import hirs.tpm.eventlog.TCGEventLog; +import hirs.tpm.eventlog.TpmPcrEvent; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; import org.apache.logging.log4j.LogManager; @@ -42,6 +46,7 @@ import java.io.IOException; import java.net.URISyntaxException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -69,6 +74,7 @@ public class ReferenceManifestPageController private final BiosDateValidator biosValidator; private final ReferenceManifestManager referenceManifestManager; + private final ReferenceEventManager referenceEventManager; private static final Logger LOGGER = LogManager.getLogger(ReferenceManifestPageController.class); @@ -118,12 +124,15 @@ public class ReferenceManifestPageController * Constructor providing the Page's display and routing specification. * * @param referenceManifestManager the reference manifest manager + * @param referenceEventManager this is the reference event manager */ @Autowired public ReferenceManifestPageController( - final ReferenceManifestManager referenceManifestManager) { + final ReferenceManifestManager referenceManifestManager, + final ReferenceEventManager referenceEventManager) { super(Page.REFERENCE_MANIFESTS); this.referenceManifestManager = referenceManifestManager; + this.referenceEventManager = referenceEventManager; this.biosValidator = new BiosDateValidator(BIOS_RELEASE_DATE_FORMAT); } @@ -173,6 +182,29 @@ public class ReferenceManifestPageController referenceManifestManager, input, orderColumnName, criteriaModifier); + SupportReferenceManifest support; + Set events; + for (ReferenceManifest rim : records) { + if (rim instanceof SupportReferenceManifest) { + support = (SupportReferenceManifest) rim; + events = ReferenceDigestValue + .select(referenceEventManager) + .bySupportRim(support.getId()).getDigestValues(); + for (ReferenceDigestValue rdv : events) { + if (support.getPlatformManufacturer() != null) { + rdv.setManufacturer(support.getPlatformManufacturer()); + } + if (support.getPlatformModel() != null) { + rdv.setModel(support.getPlatformModel()); + } + if (support.getAssociatedRim() != null) { + rdv.setBaseRimId(support.getAssociatedRim()); + } + referenceEventManager.updateRecord(rdv); + } + } + } + LOGGER.debug("Returning list of size: " + records.size()); return new DataTableResponse<>(records, input); } @@ -247,6 +279,8 @@ public class ReferenceManifestPageController support.setPlatformModel(base.getPlatformModel()); support.setTagId(base.getTagId()); support.setUpdated(true); + + // add in update code for the events based on support id try { referenceManifestManager.update(support); } catch (DBManagerException dbmEx) { @@ -535,7 +569,7 @@ public class ReferenceManifestPageController try { // save the new certificate if no match is found if (existingManifest == null) { - referenceManifestManager.save(referenceManifest); + saveTpmEvents(referenceManifestManager.save(referenceManifest)); final String successMsg = String.format("RIM successfully uploaded (%s): ", fileName); @@ -557,6 +591,7 @@ public class ReferenceManifestPageController existingManifest.restore(); existingManifest.resetCreateTime(); referenceManifestManager.update(existingManifest); + saveTpmEvents(existingManifest); final String successMsg = String.format("Pre-existing RIM found and unarchived (%s): ", fileName); @@ -570,4 +605,45 @@ public class ReferenceManifestPageController LOGGER.error(failMessage, dbmEx); } } + + private void saveTpmEvents(final ReferenceManifest referenceManifest) { + SupportReferenceManifest dbSupport; + String manufacturer; + String model; + if (referenceManifest instanceof SupportReferenceManifest) { + dbSupport = (SupportReferenceManifest) referenceManifest; + } else { + return; + } + TCGEventLog logProcessor = null; + if (dbSupport.getPlatformManufacturer() == null) { + manufacturer = ""; + } else { + manufacturer = dbSupport.getPlatformManufacturer(); + } + + if (dbSupport.getPlatformModel() == null) { + model = ""; + } else { + model = dbSupport.getPlatformModel(); + } + try { + logProcessor = new TCGEventLog(dbSupport.getRimBytes()); + ReferenceDigestValue rdv; + for (TpmPcrEvent tpe : logProcessor.getEventList()) { + rdv = new ReferenceDigestValue(dbSupport.getAssociatedRim(), + dbSupport.getId(), manufacturer, + model, tpe.getPcrIndex(), + tpe.getEventDigestStr(), tpe.getEventTypeStr(), + false, false, tpe.getEventContent()); + this.referenceEventManager.saveValue(rdv); + } + } catch (CertificateException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestValue.java b/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestValue.java index fefacba3..85f07591 100644 --- a/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestValue.java +++ b/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestValue.java @@ -1,5 +1,7 @@ package hirs.data.persist; +import hirs.persist.ReferenceEventManager; +import hirs.persist.ReferenceEventSelector; import org.bouncycastle.util.Arrays; import org.hibernate.annotations.Type; @@ -48,6 +50,67 @@ public class ReferenceDigestValue extends ArchivableEntity { @Column(nullable = false) private boolean patched = false; + /** + * This class enables the retrieval of ReferenceDigestValue by their attributes. + */ + public static class Selector extends ReferenceEventSelector { + /** + * Construct a new ReferenceEventSelector that will + * use the given (@link ReferenceEventManager} + * to retrieve one or may ReferenceDigestValue. + * + * @param referenceEventManager the reference event manager to be used to retrieve + * reference event. + */ + public Selector(final ReferenceEventManager referenceEventManager) { + super(referenceEventManager); + } + + /** + * Specify the base rim id that rims must have to be considered + * as matching. + * @param baseRimId identifier for the support rim + * @return this instance + */ + public Selector byBaseRim(final UUID baseRimId) { + setFieldValue("baseRimId", baseRimId); + return this; + } + + /** + * Specify the support rim id that rims must have to be considered + * as matching. + * @param supportRimId identifier for the support rim + * @return this instance + */ + public Selector bySupportRim(final UUID supportRimId) { + setFieldValue("supportRimId", supportRimId); + return this; + } + + /** + * Specify the platform manufacturer that rims must have to be considered + * as matching. + * @param manufacturer string for the manufacturer + * @return this instance + */ + public Selector byManufacturer(final String manufacturer) { + setFieldValue("manufacturer", manufacturer); + return this; + } + + /** + * Specify the platform model that rims must have to be considered + * as matching. + * @param model string for the model + * @return this instance + */ + public Selector byModel(final String model) { + setFieldValue("model", model); + return this; + } + } + /** * Default constructor necessary for Hibernate. */ @@ -95,6 +158,17 @@ public class ReferenceDigestValue extends ArchivableEntity { this.contentBlob = Arrays.clone(contentBlob); } + /** + * Get a Selector for use in retrieving ReferenceDigestValue. + * + * @param eventManager the ReferenceEventManager to be used to retrieve + * persisted tpm events + * @return a Selector instance to use for retrieving tpm events + */ + public static Selector select(final ReferenceEventManager eventManager) { + return new Selector(eventManager); + } + /** * Getter for the digest record UUID. * @return the string of the UUID @@ -275,7 +349,7 @@ public class ReferenceDigestValue extends ArchivableEntity { @Override public int hashCode() { - int result = Objects.hash(pcrIndex, digestValue, baseRimId, supportRimId, + int result = Objects.hash(pcrIndex, digestValue, manufacturer, model, eventType, matchFail, patched); return result; } @@ -285,7 +359,7 @@ public class ReferenceDigestValue extends ArchivableEntity { * @return a string */ public String toString() { - return String.format("ReferenceDigestValue: {%d, %s, %s, %b}", - pcrIndex, digestValue, eventType, matchFail); + return String.format("ReferenceDigestValue: {%s, %d, %s, %s, %b}", + model, pcrIndex, digestValue, eventType, matchFail); } } diff --git a/HIRS_Utils/src/main/java/hirs/persist/DBReferenceEventManager.java b/HIRS_Utils/src/main/java/hirs/persist/DBReferenceEventManager.java index e3609fcf..5dd220a3 100644 --- a/HIRS_Utils/src/main/java/hirs/persist/DBReferenceEventManager.java +++ b/HIRS_Utils/src/main/java/hirs/persist/DBReferenceEventManager.java @@ -1,6 +1,5 @@ package hirs.persist; -import hirs.FilteredRecordsList; import hirs.data.persist.BaseReferenceManifest; import hirs.data.persist.ReferenceDigestRecord; import hirs.data.persist.ReferenceDigestValue; @@ -8,16 +7,15 @@ import hirs.data.persist.ReferenceManifest; import hirs.data.persist.SupportReferenceManifest; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.criterion.Restrictions; import java.util.ArrayList; -import java.util.HashMap; +import java.util.HashSet; import java.util.List; -import java.util.Map; +import java.util.Set; import java.util.UUID; /** @@ -90,6 +88,18 @@ public class DBReferenceEventManager extends DBManager return dbRecord; } + @Override + public final Set getEventList() throws DeviceManagerException { + LOGGER.debug("getting ReferenceDigestValue list"); + + try { + final List events = super.getList(ReferenceDigestValue.class); + return new HashSet<>(events); + } catch (DBManagerException e) { + throw new DeviceManagerException(e); + } + } + @Override public ReferenceDigestValue getValueById(final ReferenceDigestValue referenceDigestValue) { LOGGER.debug("Getting record for {}", referenceDigestValue); @@ -258,53 +268,6 @@ public class DBReferenceEventManager extends DBManager return dbDigestValues; } - /** - * Returns a list of all Devices that are ordered by a column - * and direction (ASC, DESC) that is provided by the user. This method - * helps support the server-side processing in the JQuery DataTables. - * - * @param columnToOrder Column to be ordered - * @param ascending direction of sort - * @param firstResult starting point of first result in set - * @param maxResults total number we want returned for display in table - * @param search string of criteria to be matched to visible columns - * - * @return FilteredRecordsList object with fields for DataTables - */ - @Override - public final FilteredRecordsList getOrderedDigestValueList( - final String columnToOrder, - final boolean ascending, final int firstResult, - final int maxResults, final String search) { - if (columnToOrder == null) { - LOGGER.debug("null object argument"); - throw new NullPointerException("object"); - } - - //Maps object types and their ability to be searched by Hibernate - //without modification - Map searchableColumns = new HashMap<>(); - searchableColumns.put("name", true); - searchableColumns.put("group.name", true); - searchableColumns.put("last_report_timestamp", false); - - CriteriaModifier modifier = new CriteriaModifier() { - @Override - public void modify(final Criteria criteria) { - criteria.createAlias("valueGroup", "group"); - } - }; - - try { - LOGGER.debug("Getting baseline list"); - return super.getOrderedList(ReferenceDigestValue.class, columnToOrder, ascending, - firstResult, - maxResults, search, searchableColumns, modifier); - } catch (DBManagerException e) { - throw new AlertManagerException(e); - } - } - @Override public void updateRecord(final ReferenceDigestValue referenceDigestValue) { try { diff --git a/HIRS_Utils/src/main/java/hirs/persist/ReferenceEventManager.java b/HIRS_Utils/src/main/java/hirs/persist/ReferenceEventManager.java index 7d3dd6bb..93c8534e 100644 --- a/HIRS_Utils/src/main/java/hirs/persist/ReferenceEventManager.java +++ b/HIRS_Utils/src/main/java/hirs/persist/ReferenceEventManager.java @@ -1,11 +1,11 @@ package hirs.persist; -import hirs.FilteredRecordsList; import hirs.data.persist.ReferenceDigestRecord; import hirs.data.persist.ReferenceDigestValue; import hirs.data.persist.ReferenceManifest; import java.util.List; +import java.util.Set; /** * This class facilitates the persistence of {@link hirs.data.persist.ReferenceDigestValue}s @@ -90,17 +90,9 @@ public interface ReferenceEventManager extends OrderedListQuerier getOrderedDigestValueList( - String columnToOrder, boolean ascending, int firstResult, - int maxResults, String search); + Set getEventList(); /** * Updates an existing ReferenceDigestRecord. diff --git a/HIRS_Utils/src/main/java/hirs/persist/ReferenceEventSelector.java b/HIRS_Utils/src/main/java/hirs/persist/ReferenceEventSelector.java new file mode 100644 index 00000000..0756474d --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/persist/ReferenceEventSelector.java @@ -0,0 +1,157 @@ +package hirs.persist; + +import com.google.common.base.Preconditions; +import hirs.data.persist.certificate.Certificate; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.hibernate.criterion.Conjunction; +import org.hibernate.criterion.Criterion; +import org.hibernate.criterion.Restrictions; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * This class is used to select one or many TPM Events in conjunction + * with a {@link hirs.persist.ReferenceEventManager}. To make use of this object, + * use (some ReferenceDigestValue).select(ReferenceEventManager). + * + * @param the type of DB Object that will be retrieved. + */ +public abstract class ReferenceEventSelector { + private static final String RIM_TYPE_FIELD = "rimType"; + private static final String DIGEST_VALUE_FIELD = "digestValue"; + + private final ReferenceEventManager referenceEventManager; + + private final Map fieldValueSelections; + private boolean excludeArchivedValues; + + + /** + * Standard Constructor for the Selector. + * + * @param referenceEventManager the RIM manager to be used to retrieve RIMs + */ + public ReferenceEventSelector(final ReferenceEventManager referenceEventManager) { + this(referenceEventManager, true); + } + + /** + * Standard Constructor for the Selector. + * + * @param referenceEventManager the RIM manager to be used to retrieve RIMs + * @param excludeArchivedValues true if excluding archived RIMs + */ + public ReferenceEventSelector(final ReferenceEventManager referenceEventManager, + final boolean excludeArchivedValues) { + Preconditions.checkArgument( + referenceEventManager != null, + "reference event manager cannot be null" + ); + + this.referenceEventManager = referenceEventManager; + this.excludeArchivedValues = excludeArchivedValues; + this.fieldValueSelections = new HashMap<>(); + } + + /** + * Set a field name and value to match. + * + * @param name the field name to query + * @param value the value to query + */ + protected void setFieldValue(final String name, final Object value) { + Object valueToAssign = value; + + Preconditions.checkArgument( + value != null, + String.format("field value (%s) cannot be null.", name) + ); + + if (value instanceof String) { + Preconditions.checkArgument( + StringUtils.isNotEmpty((String) value), + "field value cannot be empty." + ); + } + + if (value instanceof byte[]) { + byte[] valueBytes = (byte[]) value; + + Preconditions.checkArgument( + ArrayUtils.isNotEmpty(valueBytes), + String.format("field value (%s) cannot be empty.", name) + ); + + valueToAssign = Arrays.copyOf(valueBytes, valueBytes.length); + } + + fieldValueSelections.put(name, valueToAssign); + } + + /** + * Retrieve the result set as a single + * {@link hirs.data.persist.ReferenceDigestValue}. This method is best used + * when selecting on a unique attribute. If the result set contains more + * than one RIM, one is chosen arbitrarily and returned. If no matching RIMs + * are found, this method returns null. + * + * @return a matching ReferenceDigestValue or null if none is found + */ + public hirs.data.persist.ReferenceDigestValue getDigestValue() { + Set events = getDigestValues(); + if (events.isEmpty()) { + return null; + } + return events.iterator().next(); + } + + /** + * Retrieve the result set as a set of + * {@link hirs.data.persist.ReferenceDigestValue}s. This method is best used + * when selecting on non-unique attributes. ReferenceManifests are populated + * into the set in no specific order. If no matching certificates are found, + * the returned Set will be empty. + * + * @return a Set of matching ReferenceDigestValues, possibly empty + */ + public Set getDigestValues() { + return Collections.unmodifiableSet(new HashSet( + this.referenceEventManager.getEventList())); + } + /** + * Construct the criterion that can be used to query for rims matching the + * configuration of this {@link ReferenceEventSelector}. + * + * @return a Criterion that can be used to query for rims matching the + * configuration of this instance + */ + Criterion getCriterion() { + Conjunction conj = new Conjunction(); + + for (Map.Entry fieldValueEntry : fieldValueSelections.entrySet()) { + conj.add(Restrictions.eq(fieldValueEntry.getKey(), fieldValueEntry.getValue())); + } + + if (this.excludeArchivedValues) { + conj.add(Restrictions.isNull(Certificate.ARCHIVE_FIELD)); + } + + return conj; + } + + /** + * Configures the selector to query for archived and unarchived rims. + * + * @return the selector + */ + public ReferenceEventSelector includeArchived() { + this.excludeArchivedValues = false; + return this; + } +}