This adds the additional classes

This commit is contained in:
Cyrus 2021-03-11 10:56:19 -05:00
parent 19aa3c27a1
commit accbc422e7
5 changed files with 497 additions and 0 deletions

View File

@ -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<ReferenceDigestValue> 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();
}
}
}

View File

@ -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;
}
}

View File

@ -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<ReferenceDigestRecord>
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 <T extends ReferenceDigestRecord> Set<T> get(
final ReferenceDigestSelector referenceDigestSelector) {
LOGGER.info("Getting the full set of Reference Digest Records.");
return new HashSet<>(
(List<T>) 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);
}
}

View File

@ -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<ReferenceDigestRecord> {
/**
* 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 <T> 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
*/
<T extends ReferenceDigestRecord> Set<T> 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);
}

View File

@ -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 <T> the type of Reference Integrity Manifest that will be retrieved.
*/
public abstract class ReferenceDigestSelector<T extends ReferenceDigestRecord> {
/**
* 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<T> referenceTypeClass;
private final Map<String, Object> 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<T> 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<T> 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<T> 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<T> 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<T> 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<T> 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<String, Object> 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<T> getReferenceDigestClass() {
return this.referenceTypeClass;
}
// construct and execute query
private Set<T> execute() {
Set<T> results = this.referenceDigestManager.get(this);
return results;
}
/**
* Configures the selector to query for archived and unarchived rims.
*
* @return the selector
*/
public ReferenceDigestSelector<T> includeArchived() {
this.excludeArchivedRims = false;
return this;
}
}