From accbc422e794c93d1673c3b8e28536b186dacb1e Mon Sep 17 00:00:00 2001 From: Cyrus <24922493+cyrus-dev@users.noreply.github.com> Date: Thu, 11 Mar 2021 10:56:19 -0500 Subject: [PATCH] This adds the additional classes --- .../data/persist/ReferenceDigestRecord.java | 101 +++++++++ .../data/persist/ReferenceDigestValue.java | 79 +++++++ .../persist/DBReferenceDigestManager.java | 64 ++++++ .../hirs/persist/ReferenceDigestManager.java | 44 ++++ .../hirs/persist/ReferenceDigestSelector.java | 209 ++++++++++++++++++ 5 files changed, 497 insertions(+) create mode 100644 HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestRecord.java create mode 100644 HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestValue.java create mode 100644 HIRS_Utils/src/main/java/hirs/persist/DBReferenceDigestManager.java create mode 100644 HIRS_Utils/src/main/java/hirs/persist/ReferenceDigestManager.java create mode 100644 HIRS_Utils/src/main/java/hirs/persist/ReferenceDigestSelector.java diff --git a/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestRecord.java b/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestRecord.java new file mode 100644 index 00000000..3a2e4b1c --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestRecord.java @@ -0,0 +1,101 @@ +package hirs.data.persist; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import java.util.ArrayList; +import java.util.List; + +/** + * This class will represent an entry a table that'll be associated + * with the manufacturer and model with all digest values, + * Event Type, index, RIM Tagid. + */ +@Entity +@Table(name = "ReferenceDigestRecord") +public class ReferenceDigestRecord extends ArchivableEntity { + + @Column(nullable = false) + private String manufacturer; + @Column(nullable = false) + private String model; + @Column(columnDefinition = "blob", nullable = false) + private byte[] valueBlob; + + // NOTE: when this works, and do a show tables to give to Lawrence + private List associatedDigests = new ArrayList<>(); + + /** + * Default Constructor. + */ + protected ReferenceDigestRecord() { + super(); + this.manufacturer = null; + this.model = null; + this.valueBlob = null; + } + + /** + * Default constructor with parameters. + * @param manufacturer device manufacturer + * @param model device model + * @param valueBlob the data values of the event. + */ + public ReferenceDigestRecord(final String manufacturer, + final String model, + final byte[] valueBlob) { + this.manufacturer = manufacturer; + this.model = model; + this.valueBlob = valueBlob.clone(); + } + + /** + * Getter for the manufacturer associated. + * @return the string of the manufacturer + */ + public String getManufacturer() { + return manufacturer; + } + + /** + * Setter for the manufacturer associated. + * @param manufacturer the string of the manufacturer + */ + public void setManufacturer(final String manufacturer) { + this.manufacturer = manufacturer; + } + + /** + * Getter for the model associated. + * @return the string of the model + */ + public String getModel() { + return model; + } + + /** + * Setter for the model associated. + * @param model the string of the model + */ + public void setModel(final String model) { + this.model = model; + } + + /** + * Getter for the byte array of event values. + * @return a clone of the byte array + */ + public byte[] getValueBlob() { + return valueBlob.clone(); + } + + /** + * Setter for the byte array of values. + * @param valueBlob non-null array. + */ + public void setValueBlob(final byte[] valueBlob) { + if (valueBlob != null) { + this.valueBlob = valueBlob.clone(); + } + } +} diff --git a/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestValue.java b/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestValue.java new file mode 100644 index 00000000..aa095815 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/data/persist/ReferenceDigestValue.java @@ -0,0 +1,79 @@ +package hirs.data.persist; + +import java.util.Arrays; +import java.util.Objects; + +/** + * This class represents that actual entry in the Support RIM. + * Digest Value, Event Type, index, RIM Tagid + */ +public class ReferenceDigestValue { + + private int eventNumber; + private String digestValue; + private String eventType; + private String tagId; + private boolean matchFail; + private byte[] chunk; + + /** + * Default Constructor. + */ + public ReferenceDigestValue() { + + } + + /** + * Default Constructor with a parameter for the data. + * @param data event data + */ + public ReferenceDigestValue(final byte[] data) { + this.chunk = data.clone(); + int i = 0; + this.eventNumber = data[i]; + this.digestValue = String.valueOf(data[++i]); + this.eventType = String.valueOf(data[++i]); + this.tagId = String.valueOf(data[++i]); + this.matchFail = false; + } + + /** + * Default Constructor with parameters for all associated data. + * @param eventNumber the event number + * @param digestValue the key digest value + * @param eventType the event type + * @param tagId the tag id + * @param matchFail the status of the baseline check + */ + public ReferenceDigestValue(final int eventNumber, final String digestValue, + final String eventType, final String tagId, final boolean matchFail) { + this.eventNumber = eventNumber; + this.digestValue = digestValue; + this.eventType = eventType; + this.tagId = tagId; + this.matchFail = matchFail; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + ReferenceDigestValue that = (ReferenceDigestValue) obj; + return eventNumber == that.eventNumber && matchFail == that.matchFail + && Objects.equals(digestValue, that.digestValue) + && Objects.equals(eventType, that.eventType) + && Objects.equals(tagId, that.tagId) && Arrays.equals(chunk, that.chunk); + } + + @Override + @SuppressWarnings("MagicNumber") + public int hashCode() { + int result = Objects.hash(eventNumber, digestValue, eventType, tagId, matchFail); + result = 31 * result + Arrays.hashCode(chunk); + return result; + } +} diff --git a/HIRS_Utils/src/main/java/hirs/persist/DBReferenceDigestManager.java b/HIRS_Utils/src/main/java/hirs/persist/DBReferenceDigestManager.java new file mode 100644 index 00000000..057db95f --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/persist/DBReferenceDigestManager.java @@ -0,0 +1,64 @@ +package hirs.persist; + +import hirs.data.persist.ReferenceDigestRecord; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.hibernate.SessionFactory; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * This class is used to persist and retrieve {@link hirs.data.persist.ReferenceDigestRecord}s into + * and from the database. + */ +public class DBReferenceDigestManager extends DBManager + implements ReferenceDigestManager { + + private static final Logger LOGGER = LogManager.getLogger(DBReferenceDigestManager.class); + + /** + * Default Constructor. + * + * @param sessionFactory session factory used to access database connections + */ + public DBReferenceDigestManager(final SessionFactory sessionFactory) { + super(ReferenceDigestRecord.class, sessionFactory); + } + + /** + * This method does not need to be used directly as it is used by + * {@link ReferenceManifestSelector}'s get* methods. Regardless, it may be + * used to retrieve ReferenceManifest by other code in this package, given a + * configured ReferenceManifestSelector. + * + * @param referenceDigestSelector a configured + * {@link ReferenceDigestSelector} to use for querying + * @return the resulting set of ReferenceManifest, possibly empty + */ + @Override + @SuppressWarnings("unchecked") + public Set get( + final ReferenceDigestSelector referenceDigestSelector) { + LOGGER.info("Getting the full set of Reference Digest Records."); + return new HashSet<>( + (List) getWithCriteria( + referenceDigestSelector.getReferenceDigestClass(), + Collections.singleton(referenceDigestSelector.getCriterion()) + ) + ); + } + + /** + * Remove a ReferenceDigestRecord from the database. + * + * @param referenceDigestRecord the referenceDigestRecord to delete + * @return true if deletion was successful, false otherwise + */ + public boolean deleteReferenceManifest(final ReferenceDigestRecord referenceDigestRecord) { + LOGGER.info(String.format("Deleting reference to %s/%s", + referenceDigestRecord.getManufacturer(), referenceDigestRecord.getModel())); + return delete(referenceDigestRecord); + } +} diff --git a/HIRS_Utils/src/main/java/hirs/persist/ReferenceDigestManager.java b/HIRS_Utils/src/main/java/hirs/persist/ReferenceDigestManager.java new file mode 100644 index 00000000..cbd0d03b --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/persist/ReferenceDigestManager.java @@ -0,0 +1,44 @@ + +package hirs.persist; + +import hirs.data.persist.ReferenceDigestRecord; + +import java.util.Set; + +/** + * This class facilitates the persistence of {@link hirs.data.persist.ReferenceDigestRecord}s + * including storage, retrieval, and deletion. + */ +public interface ReferenceDigestManager extends OrderedListQuerier { + + /** + * Persists a new Reference Digest. + * + * @param referenceDigestRecord the ReferenceDigestRecord + * @return the persisted ReferenceDigestRecord + */ + ReferenceDigestRecord save(ReferenceDigestRecord referenceDigestRecord); + + /** + * Updates an existing ReferenceDigestRecord. + * @param referenceDigestRecord the Reference Digest update + */ + void update(ReferenceDigestRecord referenceDigestRecord); + + /** + * Retrieve Reference Digest according to the given {@link ReferenceDigestSelector}. + * + * @param the type of reference digest that will be retrieved + * @param referenceDigestSelector a {@link ReferenceDigestSelector} to use for querying + * @return a Set of matching RIMs, which may be empty + */ + Set get(ReferenceDigestSelector referenceDigestSelector); + + /** + * Delete the given RIM. + * + * @param referenceDigestRecord the RIM to delete + * @return true if the deletion succeeded, false otherwise. + */ + boolean delete(ReferenceDigestRecord referenceDigestRecord); +} diff --git a/HIRS_Utils/src/main/java/hirs/persist/ReferenceDigestSelector.java b/HIRS_Utils/src/main/java/hirs/persist/ReferenceDigestSelector.java new file mode 100644 index 00000000..99e09891 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/persist/ReferenceDigestSelector.java @@ -0,0 +1,209 @@ +package hirs.persist; + +import com.google.common.base.Preconditions; +import hirs.data.persist.ReferenceDigestRecord; +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 RIMs in conjunction + * with a {@link ReferenceDigestManager}. To make use of this object, + * use (some ReferenceManifest).select(ReferenceManifestManager). + * + * @param the type of Reference Integrity Manifest that will be retrieved. + */ +public abstract class ReferenceDigestSelector { + /** + * String representing the database field for the manufacturer. + */ + public static final String PLATFORM_MANUFACTURER = "manufacturer"; + /** + * String representing the database field for the manufacturer id. + */ + public static final String PLATFORM_MODEL = "model"; + + private final ReferenceDigestManager referenceDigestManager; + private final Class referenceTypeClass; + + private final Map fieldValueSelections; + private boolean excludeArchivedRims; + + /** + * Default Constructor. + * + * @param referenceDigestManager the RIM manager to be used to retrieve RIMs + * @param referenceTypeClass the type of Reference Manifest to process. + */ + public ReferenceDigestSelector(final ReferenceDigestManager referenceDigestManager, + final Class referenceTypeClass) { + this(referenceDigestManager, referenceTypeClass, true); + } + + /** + * Standard Constructor for the Selector. + * + * @param referenceDigestManager the RIM manager to be used to retrieve RIMs + * @param referenceTypeClass the type of Reference Manifest to process. + * @param excludeArchivedRims true if excluding archived RIMs + */ + public ReferenceDigestSelector(final ReferenceDigestManager referenceDigestManager, + final Class referenceTypeClass, + final boolean excludeArchivedRims) { + Preconditions.checkArgument( + referenceDigestManager != null, + "reference manifest manager cannot be null" + ); + + Preconditions.checkArgument( + referenceTypeClass != null, + "type cannot be null" + ); + + this.referenceDigestManager = referenceDigestManager; + this.referenceTypeClass = referenceTypeClass; + this.excludeArchivedRims = excludeArchivedRims; + this.fieldValueSelections = new HashMap<>(); + } + + /** + * Specify the entity id that rims must have to be considered as matching. + * + * @param manufacturer the UUID to query + * @return this instance (for chaining further calls) + */ + public ReferenceDigestSelector byManufacturer(final String manufacturer) { + setFieldValue(PLATFORM_MANUFACTURER, manufacturer); + return this; + } + + /** + * Specify the hash code of the bytes that rim must match. + * + * @param model the hash code of the bytes to query for + * @return this instance (for chaining further calls) + */ + public ReferenceDigestSelector byModel(final String model) { + setFieldValue(PLATFORM_MODEL, model); + return this; + } + + /** + * 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.ReferenceDigestRecord}. 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 digest record or null if none is found + */ + public T getDigestRecord() { + Set rims = execute(); + if (rims.isEmpty()) { + return null; + } + return rims.iterator().next(); + } + + /** + * Retrieve the result set as a set of + * {@link hirs.data.persist.ReferenceDigestRecord}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 RIMs, possibly empty + */ + public Set getDigestRecords() { + return Collections.unmodifiableSet(new HashSet<>(execute())); + } + + /** + * Construct the criterion that can be used to query for rims matching the + * configuration of this {@link hirs.persist.ReferenceDigestSelector}. + * + * @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.excludeArchivedRims) { + conj.add(Restrictions.isNull(Certificate.ARCHIVE_FIELD)); + } + + return conj; + } + + /** + * @return the rim class that this instance will query + */ + public Class getReferenceDigestClass() { + return this.referenceTypeClass; + } + + // construct and execute query + private Set execute() { + Set results = this.referenceDigestManager.get(this); + return results; + } + + /** + * Configures the selector to query for archived and unarchived rims. + * + * @return the selector + */ + public ReferenceDigestSelector includeArchived() { + this.excludeArchivedRims = false; + return this; + } +}