Updated code allows the tpm event table to be searched and information

updated when the swidtag is added.
This commit is contained in:
Cyrus 2022-01-31 14:11:36 -05:00
parent ea6bb48d06
commit 035efad9d2
5 changed files with 328 additions and 66 deletions

View File

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

View File

@ -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<ReferenceDigestValue> {
/**
* 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);
}
}

View File

@ -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<ReferenceDigestValue>
return dbRecord;
}
@Override
public final Set<ReferenceDigestValue> getEventList() throws DeviceManagerException {
LOGGER.debug("getting ReferenceDigestValue list");
try {
final List<ReferenceDigestValue> 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<ReferenceDigestValue>
return dbDigestValues;
}
/**
* Returns a list of all <code>Device</code>s 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<ReferenceDigestValue> 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<String, Boolean> 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 {

View File

@ -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<ReferenceDiges
* 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
*/
FilteredRecordsList<ReferenceDigestValue> getOrderedDigestValueList(
String columnToOrder, boolean ascending, int firstResult,
int maxResults, String search);
Set<ReferenceDigestValue> getEventList();
/**
* Updates an existing ReferenceDigestRecord.

View File

@ -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 <ReferenceDigestValue> the type of DB Object that will be retrieved.
*/
public abstract class ReferenceEventSelector<ReferenceDigestValue> {
private static final String RIM_TYPE_FIELD = "rimType";
private static final String DIGEST_VALUE_FIELD = "digestValue";
private final ReferenceEventManager referenceEventManager;
private final Map<String, Object> 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<hirs.data.persist.ReferenceDigestValue> 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<hirs.data.persist.ReferenceDigestValue> getDigestValues() {
return Collections.unmodifiableSet(new HashSet<hirs.data.persist.ReferenceDigestValue>(
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<String, Object> 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;
}
}