mirror of
https://github.com/nsacyber/HIRS.git
synced 2025-03-24 21:16:01 +00:00
Continued changes to update to Hibernate 5, removed a lot of the
baseline files
This commit is contained in:
parent
dabd88719f
commit
116ed5b4aa
@ -7,11 +7,6 @@ import hirs.persist.AppraiserManager;
|
||||
import hirs.persist.DeviceGroupManager;
|
||||
import hirs.persist.PolicyManager;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import static hirs.attestationca.AbstractAttestationCertificateAuthority.LOG;
|
||||
|
||||
/**
|
||||
@ -71,19 +66,4 @@ public final class AcaDbInit {
|
||||
|
||||
LOG.info("ACA database initialization complete.");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
File file = new File("/home/tdmatth/Downloads/HP_CND12774J0_pxe.1.swidtag");
|
||||
FileInputStream fis = new FileInputStream(file);
|
||||
|
||||
BufferedInputStream bis = new BufferedInputStream(fis);
|
||||
byte[] buffer = new byte[1024];
|
||||
int length = 0;
|
||||
String output = "";
|
||||
while ((length = bis.read(buffer)) != -1) {
|
||||
output += new String(buffer, 0, length);
|
||||
}
|
||||
|
||||
System.out.println(output);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package hirs;
|
||||
|
||||
import static org.apache.logging.log4j.LogManager.getLogger;
|
||||
import hirs.data.persist.IMAReport;
|
||||
|
||||
import hirs.data.persist.Report;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
@ -1,9 +1,9 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.data.persist.baseline.Baseline;
|
||||
import hirs.data.persist.enums.AlertSeverity;
|
||||
import hirs.data.persist.enums.AlertSource;
|
||||
import hirs.data.persist.enums.AlertType;
|
||||
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.CollectionTable;
|
||||
@ -241,7 +241,7 @@ public class Alert extends ArchivableEntity {
|
||||
* Returns the source of this <code>Alert</code>.
|
||||
*
|
||||
* @return source of this <code>Alert</code>
|
||||
* @see Source
|
||||
*
|
||||
*/
|
||||
@XmlAttribute(name = "source")
|
||||
public final AlertSource getSource() {
|
||||
@ -316,39 +316,6 @@ public class Alert extends ArchivableEntity {
|
||||
this.received = truncate(received, DEFAULT_MAX_STRING_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id of baselines associated with the alert as well as the severity of the
|
||||
* <code>Baseline</code> that was in use, if any, when the <code>Alert</code> was generated.
|
||||
* Should only be used when initially generating an <code>Alert</code>.
|
||||
*
|
||||
* @param baselines - a collection of <code>Baseline</code>s related to this alert
|
||||
*/
|
||||
public final void setBaselineIdsAndSeverity(final Set<Baseline> baselines) {
|
||||
if (baselines != null) {
|
||||
for (Baseline baseline : baselines) {
|
||||
if (baseline != null) {
|
||||
this.baselineIds.add(baseline.getId());
|
||||
|
||||
/**
|
||||
* This is a temporary solution to resolve any failures in
|
||||
* live code or unit tests. BaselineId is used to count the number
|
||||
* of alerts associated with a baseline. The <code>AlertManager</code>
|
||||
* class uses baselineId for this count.
|
||||
*
|
||||
*/
|
||||
this.baselineId = baseline.getId();
|
||||
|
||||
// only overwrite severity if the new one is non-null
|
||||
if (baseline.getSeverity() != null) {
|
||||
// Assign the most critical severity level of the collection of baselines to
|
||||
// the alert
|
||||
this.severity = getPrioritizedSeverityLevel(baseline.getSeverity());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the severity of the alert regardless of baseline.
|
||||
* @param severity Alert.Severity.
|
||||
@ -378,7 +345,7 @@ public class Alert extends ArchivableEntity {
|
||||
* Returns the <code>Severity</code> of this <code>Alert</code>.
|
||||
*
|
||||
* @return severity of this <code>Alert</code>
|
||||
* @see Severity
|
||||
*
|
||||
*/
|
||||
@XmlAttribute(name = "severity")
|
||||
public final AlertSeverity getSeverity() {
|
||||
|
@ -1,12 +1,12 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.data.persist.info.FirmwareInfo;
|
||||
import hirs.data.persist.info.HardwareInfo;
|
||||
import hirs.data.persist.info.NetworkInfo;
|
||||
import hirs.data.persist.info.OSInfo;
|
||||
import hirs.data.persist.info.HardwareInfo;
|
||||
import hirs.data.persist.info.TPMInfo;
|
||||
import hirs.data.persist.info.FirmwareInfo;
|
||||
import hirs.data.persist.baseline.TpmWhiteListBaseline;
|
||||
import static org.apache.logging.log4j.LogManager.getLogger;
|
||||
import hirs.utils.VersionHelper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
@ -17,12 +17,10 @@ import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
import hirs.utils.VersionHelper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import static org.apache.logging.log4j.LogManager.getLogger;
|
||||
|
||||
/**
|
||||
* A <code>DeficeInfoReport</code> is a <code>Report</code> used to transfer the
|
||||
* information about the device. This <code>Report</code> includes the network,
|
||||
@ -249,7 +247,7 @@ public class DeviceInfoReport extends Report implements Serializable {
|
||||
* @return True, if one of the TPM baselines in the set has the same kernel-specific
|
||||
* info as this DeviceinfoReport.
|
||||
*/
|
||||
public final boolean matchesKernelInfo(final Iterable<TpmWhiteListBaseline> tpmBaselines) {
|
||||
public final boolean matchesKernelInfo(final Iterable<Digest> tpmBaselines) {
|
||||
boolean match = false;
|
||||
|
||||
if (tpmBaselines != null) {
|
||||
@ -257,8 +255,8 @@ public class DeviceInfoReport extends Report implements Serializable {
|
||||
final OSInfo kernelOSInfo = getOSInfo();
|
||||
|
||||
// perform the search
|
||||
for (final TpmWhiteListBaseline baseline : tpmBaselines) {
|
||||
final OSInfo baselineOSInfo = baseline.getOSInfo();
|
||||
for (final Digest baseline : tpmBaselines) {
|
||||
final OSInfo baselineOSInfo = new OSInfo();//baseline.getOSInfo();
|
||||
if(baselineOSInfo.getOSName().equalsIgnoreCase(kernelOSInfo.getOSName())
|
||||
&& baselineOSInfo.getOSVersion().equalsIgnoreCase(kernelOSInfo.getOSVersion())) {
|
||||
match = true;
|
||||
|
@ -1,280 +0,0 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.data.persist.enums.AlertSource;
|
||||
import org.hibernate.criterion.Criterion;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
/**
|
||||
* An <code>IMADeviceState</code> manages the IMA state for appraisal. This
|
||||
* information is useful so that the IMA appraiser does not have to request or
|
||||
* appraise the full report for each appraisal. The appraiser can fetch the
|
||||
* information from the last appraisal and begin appraising from the saved
|
||||
* state.
|
||||
* <p>
|
||||
* For instance consider a client that first appraises at t0. At t0 the client
|
||||
* send the full report and IMA appraiser appraises the X entries in the report.
|
||||
* Then at time t1 the client has another appraisal. If the machine has not been
|
||||
* rebooted then the appraiser can validate the integrity of the full report
|
||||
* using the saved PCR value from t0. The server can also validate only the IMA
|
||||
* entries after t0.
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Access(AccessType.FIELD)
|
||||
public class IMADeviceState extends DeviceState {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@OneToOne(fetch = FetchType.EAGER, optional = false)
|
||||
@JoinColumn(name = "device", nullable = false, unique = true)
|
||||
private final Device device;
|
||||
|
||||
@Column(name = "bootcycleId")
|
||||
private String bootcycleId;
|
||||
|
||||
@Column(name = "appraiseIndex")
|
||||
private int index;
|
||||
|
||||
@Column(nullable = true, name = "pcrState",
|
||||
length = Digest.SHA512_DIGEST_LENGTH)
|
||||
private byte[] pcrState;
|
||||
|
||||
@Column(name = "mostRecentFullReportDate")
|
||||
private Date mostRecentFullReportDate;
|
||||
|
||||
/**
|
||||
* Creates a new <code>IMADeviceState</code> to manage the state for the
|
||||
* <code>Device</code>. The boot-cycle ID will be null to indicate that this
|
||||
* has not saved state for previous report. The index will be 0 to indicate
|
||||
* that no entries have been appraised, and the PCR state will be null as
|
||||
* well.
|
||||
*
|
||||
* @param device
|
||||
* device
|
||||
*/
|
||||
public IMADeviceState(final Device device) {
|
||||
if (device == null) {
|
||||
throw new NullPointerException("device");
|
||||
}
|
||||
this.device = device;
|
||||
resetState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor that has no state saved.
|
||||
*/
|
||||
protected IMADeviceState() {
|
||||
this.device = null;
|
||||
resetState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the database ID associated with this entity. After this object is
|
||||
* stored in a database then this ID will be set. This is necessary only for
|
||||
* Hibernate.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public final Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state. This sets boot-cycle ID to null, index to 0, and PCR
|
||||
* state to null.
|
||||
*/
|
||||
public final void resetState() {
|
||||
this.bootcycleId = null;
|
||||
this.index = 0;
|
||||
this.pcrState = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Device</code> associated with this state.
|
||||
*
|
||||
* @return the device
|
||||
*/
|
||||
public final Device getDevice() {
|
||||
return device;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the boot-cycle ID associated with the last appraisal. This may be
|
||||
* null to indicate a reset in state. If the <code>IMAAppraiser</code> sees
|
||||
* this value as null then it will know to request a full report and
|
||||
* appraise the full report.
|
||||
*
|
||||
* @return the bootcycleId (may be null if no appraisals yet or state is
|
||||
* reset)
|
||||
*/
|
||||
public final String getBootcycleId() {
|
||||
return bootcycleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the boot-cycle ID associated with the last appraisal.
|
||||
*
|
||||
* @param bootcycleId
|
||||
* bootcycleId
|
||||
*/
|
||||
public final void setBootcycleId(final String bootcycleId) {
|
||||
this.bootcycleId = bootcycleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the next IMA record to be appraised. The first
|
||||
* record has index 0. If zero is returned then this indicates the first
|
||||
* entry in the report is to be appraised.
|
||||
*
|
||||
* @return index of last successfully appraised IMA record
|
||||
*/
|
||||
public final int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index of the next IMA record to be appraised.
|
||||
*
|
||||
* @param index
|
||||
* index of last IMA record that was successfully appraised
|
||||
* @throws IllegalArgumentException
|
||||
* if index < 0
|
||||
*/
|
||||
public final void setIndex(final int index)
|
||||
throws IllegalArgumentException {
|
||||
if (index < 0) {
|
||||
throw new IllegalArgumentException("index < 0");
|
||||
}
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the date of the most recent full report. This is useful for determining the start time
|
||||
* of the most recent delta report series, as the first delta report is indistinguishable from
|
||||
* a full report.
|
||||
*
|
||||
* @return date of most recent full report or null if there have not been any reports yet
|
||||
*/
|
||||
public final Date getMostRecentFullReportDate() {
|
||||
if (mostRecentFullReportDate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return (Date) mostRecentFullReportDate.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the date of the most recent full report. This is useful for determining the start time
|
||||
* of the most recent delta report series, as the first delta report is indistinguishable from
|
||||
* a full report.
|
||||
*
|
||||
* @param date date of the most recent full report or null to unset the date
|
||||
*/
|
||||
public final void setMostRecentFullReportDate(final Date date) {
|
||||
if (date == null) {
|
||||
this.mostRecentFullReportDate = null;
|
||||
} else {
|
||||
this.mostRecentFullReportDate = (Date) date.clone();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Criterion getDeviceTrustAlertCriterion() {
|
||||
Criterion createTimeRestriction = Restrictions.ge("createTime", mostRecentFullReportDate);
|
||||
Criterion sourceRestriction = Restrictions.eq("source", AlertSource.IMA_APPRAISER);
|
||||
return Restrictions.and(createTimeRestriction, sourceRestriction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PCR hash that verified the last IMA report. An IMA report can
|
||||
* be verified by recalculating the PCR hash in the TPM. This value
|
||||
* indicates the last verified PCR value for a valid report in the
|
||||
* boot-cycle ID.
|
||||
* <p>
|
||||
* This may return null if the state has been reset, no entries have been
|
||||
* appraised, or the <code>Device</code> does not have a TPM.
|
||||
*
|
||||
* @return PCR state
|
||||
*/
|
||||
public final byte[] getPcrState() {
|
||||
if (pcrState == null) {
|
||||
return null;
|
||||
} else {
|
||||
return Arrays.copyOf(pcrState, pcrState.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the PCR state. See {@link #getPcrState()} for more details.
|
||||
*
|
||||
* @param pcrState PCR state
|
||||
*/
|
||||
public final void setPcrState(final byte[] pcrState) {
|
||||
if (pcrState == null) {
|
||||
this.pcrState = null;
|
||||
} else {
|
||||
this.pcrState = Arrays.copyOf(pcrState, pcrState.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code representing this object. The hash code is derived
|
||||
* from the <code>Device</code> this state represents.
|
||||
*
|
||||
* @return hash code
|
||||
*/
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + device.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this object for equality with <code>obj</code>.
|
||||
* <code>IMADeviceState</code> objects are considered equal if they have
|
||||
* equal <code>Device</code>s.
|
||||
*
|
||||
* @param obj
|
||||
* other object
|
||||
* @return true if both are instances of <code>IMADeviceState</code> and
|
||||
* both have the same <code>Device</code>
|
||||
*/
|
||||
@Override
|
||||
public final boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof IMADeviceState)) {
|
||||
return false;
|
||||
}
|
||||
final IMADeviceState other = (IMADeviceState) obj;
|
||||
return device.equals(other.device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return String.format("(%s %s %d)", device, bootcycleId, index);
|
||||
}
|
||||
}
|
@ -1,194 +0,0 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
/**
|
||||
* This class represents an IMA measurement record. A measurement record
|
||||
* contains a file path and a hash. The file path represents the file name and
|
||||
* the hash is the hash of the file.
|
||||
* <p>
|
||||
* In IMA the file path is not guaranteed to be unique. For instance initrd has
|
||||
* files measured at /. The root file space that is mounted later is also
|
||||
* mounted at /.
|
||||
*/
|
||||
@XmlSeeAlso(Digest.class)
|
||||
@Entity
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public class IMAMeasurementRecord extends ExaminableRecord {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(IMAMeasurementRecord.class);
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@XmlElement
|
||||
@Column(nullable = false)
|
||||
private final String path;
|
||||
|
||||
@XmlElement
|
||||
@Embedded
|
||||
private final Digest hash;
|
||||
|
||||
@XmlTransient
|
||||
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "ima_report_id")
|
||||
@JsonIgnore
|
||||
private IMAReport report;
|
||||
|
||||
/**
|
||||
* Creates a new <code>IMAMeasurementRecord</code>. The record contains the
|
||||
* file path and its hash.
|
||||
*
|
||||
* @param path
|
||||
* the file path that identifies the file location
|
||||
* @param hash
|
||||
* SHA-1 hash of the file
|
||||
* @throws IllegalArgumentException
|
||||
* if digest algorithm is not SHA-1
|
||||
*/
|
||||
public IMAMeasurementRecord(final String path, final Digest hash)
|
||||
throws IllegalArgumentException {
|
||||
super();
|
||||
checkNullArg(path, "path");
|
||||
checkNullArg(hash, "hash");
|
||||
if (hash.getAlgorithm() != DigestAlgorithm.SHA1) {
|
||||
throw new IllegalArgumentException("digest algorithm is not SHA-1");
|
||||
}
|
||||
this.path = path;
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor necessary for Hibernate.
|
||||
*/
|
||||
protected IMAMeasurementRecord() {
|
||||
super();
|
||||
this.path = null;
|
||||
this.hash = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the IMAMeasurementRecord.
|
||||
*
|
||||
* @return id of IMAMeasurementRecord
|
||||
*/
|
||||
public final Long getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* Returns the path (including file name) of the IMA baseline record.
|
||||
*
|
||||
* @return file path of baseline record
|
||||
*/
|
||||
public final String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SHA1 hash of the file associated with IMA baseline record.
|
||||
*
|
||||
* @return hash of file associated with baseline record
|
||||
*/
|
||||
public final Digest getHash() {
|
||||
return this.hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* This gets the report.
|
||||
*
|
||||
* @return Report
|
||||
*/
|
||||
public final IMAReport getReport() {
|
||||
return report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given report.
|
||||
*
|
||||
* @param report report that matches the given record
|
||||
*/
|
||||
public final void setReport(final IMAReport report) {
|
||||
this.report = report;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides hashCode() method in order to generate a new hashCode based on
|
||||
* hashCode of path and hash. This is required because of override of
|
||||
* equals() method.
|
||||
*
|
||||
* @return generated hash code
|
||||
*/
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
if (id == null) {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean if other is equal to this.
|
||||
* <code>IMAMeasurementRecord</code>s are identified by their name and hash,
|
||||
* so this returns true if <code>other</code> is an instance of
|
||||
* <code>IMAMeasurementRecord</code> and its name and hash are the same as
|
||||
* this <code>IMAMeasurementRecord</code>. Otherwise this returns false.
|
||||
*
|
||||
* @param obj
|
||||
* other object to test for equals
|
||||
* @return true if other is <code>IMAMeasurementRecord</code> and has same
|
||||
* name and same hash
|
||||
*/
|
||||
@Override
|
||||
public final boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof IMAMeasurementRecord)) {
|
||||
return false;
|
||||
}
|
||||
IMAMeasurementRecord other = (IMAMeasurementRecord) obj;
|
||||
|
||||
if (other.id == null || id == null) {
|
||||
return super.equals(other);
|
||||
}
|
||||
return other.id.equals(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return String.format("(%s, %s)", path, hash);
|
||||
}
|
||||
|
||||
private void checkNullArg(final Object arg, final String argName) {
|
||||
if (arg == null) {
|
||||
final String msg = String.format("null argument: %s", argName);
|
||||
LOGGER.error(msg);
|
||||
throw new NullPointerException(msg);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,195 +0,0 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Access;
|
||||
import javax.persistence.AccessType;
|
||||
import javax.persistence.CascadeType;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import static org.apache.logging.log4j.LogManager.getLogger;
|
||||
|
||||
/**
|
||||
* IMAReport is a listing of <code>IMAMeasurementRecord</code>s. The list of
|
||||
* <code>IMAMeasurementRecord</code>s is an ordered list. The list is ordered
|
||||
* based upon the order in which the files were measured. The ordering is
|
||||
* important because the TPM hash value can only be verified if the order is
|
||||
* correct.
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
@XmlRootElement
|
||||
@XmlSeeAlso(IMAMeasurementRecord.class)
|
||||
@Entity
|
||||
public class IMAReport extends Report {
|
||||
|
||||
private static final Logger LOGGER = getLogger(IMAReport.class);
|
||||
private static final int MAX_BOOTCYCLE_LENGTH = 128;
|
||||
|
||||
@Column(nullable = true, length = MAX_BOOTCYCLE_LENGTH)
|
||||
@XmlElement(name = "bootcycleID", required = false)
|
||||
private String bootcycleId;
|
||||
|
||||
@XmlElement(name = "startIndex", required = true)
|
||||
@Column(nullable = false, name = "startingIndex")
|
||||
private int index;
|
||||
|
||||
@XmlElement
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,
|
||||
mappedBy = "report")
|
||||
@Access(AccessType.FIELD)
|
||||
@JsonIgnore
|
||||
private final Set<IMAMeasurementRecord> imaRecords;
|
||||
|
||||
/**
|
||||
* Constructor used to initialize an IMA report. This creates an empty set
|
||||
* of IMA records and sets the default index to zero.
|
||||
*/
|
||||
public IMAReport() {
|
||||
imaRecords = new LinkedHashSet<>();
|
||||
index = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getReportType() {
|
||||
return this.getClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the boot cycle ID. A boot cycle ID is a unique identifier that
|
||||
* indicates a machine reboot. If the machine is rebooted then it will have
|
||||
* a different boot cycle ID.
|
||||
* <p>
|
||||
* The boot cycle ID is useful for IMA delta measurements. With this ID the
|
||||
* appraiser can know if a machine has rebooted. If it has not rebooted then
|
||||
* efficiencies can be applied, such as not re-appraising a part of a report
|
||||
* that has previously been appraised.
|
||||
* <p>
|
||||
* This is an optional component of an IMA report. The return value may be
|
||||
* null.
|
||||
*
|
||||
* @return boot cycle ID
|
||||
*/
|
||||
public final String getBootcycleId() {
|
||||
return this.bootcycleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the boot cycle ID for this report. See {@link #getBootcycleId()} for
|
||||
* more details.
|
||||
*
|
||||
* @param bootcycleId boot cycle ID (may be null to omit from report)
|
||||
*/
|
||||
public final void setBootcycleId(final String bootcycleId) {
|
||||
this.bootcycleId = bootcycleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the first record. An IMA report contains an array of
|
||||
* measurement records. This value indicates the index of the first record
|
||||
* in this report.
|
||||
* <p>
|
||||
* This can be non-zero if this report represents a delta report. A report
|
||||
* can be sent at time t0. This report contains y records. At time t1, if
|
||||
* the machine has not rebooted, then the full IMA report will have x+y
|
||||
* records where y≥0. A delta report can be sent with just the records in
|
||||
* the set {y-x}. In that case the index would be x.
|
||||
* <p>
|
||||
* The first entry in the IMA report has index 0.
|
||||
*
|
||||
* @return index of the first measurement record in this report
|
||||
*/
|
||||
public final int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index of the first measurement record.
|
||||
*
|
||||
* @param index
|
||||
* index of first measurement record
|
||||
* @throws IllegalArgumentException
|
||||
* if index<0
|
||||
*/
|
||||
public final void setIndex(final int index) {
|
||||
if (index < 0) {
|
||||
final String msg = "index cannot be less than zero";
|
||||
LOGGER.warn(msg);
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of IMA records. The <code>IMAMeasurementRecords</code> are
|
||||
* lazily loaded and this method will have to be called within a transaction
|
||||
* in order to properly load and return all of the records related to the
|
||||
* report.
|
||||
*
|
||||
* @return list of IMA measurement records
|
||||
*/
|
||||
@JsonIgnore
|
||||
public Set<IMAMeasurementRecord> getRecords() {
|
||||
return Collections.unmodifiableSet(imaRecords);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a record to the list of IMA measurement records by appending it to
|
||||
* the ordered list.
|
||||
*
|
||||
* @param record
|
||||
* IMA record to be added
|
||||
*/
|
||||
public final void addRecord(final IMAMeasurementRecord record) {
|
||||
if (record == null) {
|
||||
LOGGER.error("null record");
|
||||
throw new NullPointerException("record");
|
||||
}
|
||||
|
||||
imaRecords.add(record);
|
||||
LOGGER.debug("record added: {}", record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a record from the list.
|
||||
*
|
||||
* @param record
|
||||
* record to be removed
|
||||
* @return a boolean indicating if the removal was successful
|
||||
*/
|
||||
public final boolean removeRecord(final IMAMeasurementRecord record) {
|
||||
return imaRecords.remove(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating if this report is a full report. The first measurement in the
|
||||
* IMA log has an index of 0. If delta reports are enabled, the first delta report should be a
|
||||
* full report (index starts at 0), and subsequent delta reports will have index values greater
|
||||
* than 0.
|
||||
*
|
||||
* @return true if a full report or first delta report, false if not the first delta report
|
||||
*/
|
||||
public final boolean isFullReport() {
|
||||
return index == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method returns the number of records in the IMA report.
|
||||
* @return the number of records found in the IMA Report
|
||||
*/
|
||||
public int getRecordCount() {
|
||||
return imaRecords.size();
|
||||
}
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.data.persist.baseline.ImaBlacklistBaseline;
|
||||
import hirs.data.persist.baseline.AbstractImaBaselineRecord;
|
||||
import hirs.data.persist.enums.AlertType;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
/**
|
||||
* This class holds information about blacklisted paths and hashes that, if found in a machine's
|
||||
* IMA log, would be adverse indicators of the integrity of that machine. This class is intended
|
||||
* to be flexible, and as such, any instance may include only a path, only a hash, or both.
|
||||
* For blacklist records that contain only one of these two pieces of information, a measurement
|
||||
* record will be considered as matching if its respective path or hash matches that record.
|
||||
* For blacklist records that contain both pieces of information, only measurement records
|
||||
* that contain both a matching path and hash will be considered as matching.
|
||||
*/
|
||||
@Entity
|
||||
public class ImaBlacklistRecord extends AbstractImaBaselineRecord {
|
||||
/**
|
||||
* Referenced in DbImaBlacklistBaselineRecordManager.iterateOverBaselineRecords().
|
||||
*/
|
||||
public static final int FILENAME_HASH_BUCKET_COUNT = 4;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "ima_baseline_id")
|
||||
private ImaBlacklistBaseline baseline;
|
||||
|
||||
/**
|
||||
* Construct a new ImaBlacklistRecord that blacklists any file at the given path.
|
||||
*
|
||||
* @param path the path to blacklist
|
||||
*/
|
||||
public ImaBlacklistRecord(final String path) {
|
||||
this(path, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new ImaBlacklistRecord that blacklists any file at the given path.
|
||||
*
|
||||
* @param path the path to blacklist
|
||||
* @param description a description of the given path, may be null
|
||||
*/
|
||||
public ImaBlacklistRecord(final String path, final String description) {
|
||||
this(path, null, description, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new ImaBlacklistRecord that blacklists any file with the given hash.
|
||||
*
|
||||
* @param hash the hash to blacklist
|
||||
*/
|
||||
public ImaBlacklistRecord(final Digest hash) {
|
||||
this(null, hash, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new ImaBlacklistRecord that blacklists any file with the given hash.
|
||||
*
|
||||
* @param hash the hash to blacklist
|
||||
* @param description a description of the given hash. may be null
|
||||
*/
|
||||
public ImaBlacklistRecord(final Digest hash, final String description) {
|
||||
this(null, hash, description, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new ImaBlacklistRecord that blacklists a file at the given path with the given
|
||||
* hash.
|
||||
*
|
||||
* @param path the path to blacklist
|
||||
* @param hash the hash to blacklist
|
||||
*/
|
||||
public ImaBlacklistRecord(final String path, final Digest hash) {
|
||||
this(path, hash, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new ImaBlacklistRecord with the given parameters. Either a path or hash,
|
||||
* or both, may be provided, as well as a description.
|
||||
*
|
||||
* If:
|
||||
* - a non-null path and a null hash is provided, any file matching the path should be
|
||||
* considered as blacklisted
|
||||
* - a null path and a non-null hash is provided, any file whose hash matches the given hash
|
||||
* should be considered as blacklisted
|
||||
* - a non-null path and a non-null hash is provided, a file that has both a matching path
|
||||
* and hash should be considered as blacklisted
|
||||
*
|
||||
* This class cannot be instantiated with both a null path and hash.
|
||||
*
|
||||
* @param path a blacklisted path, as described above
|
||||
* @param hash a blacklisted hash, as described above
|
||||
* @param description a description of the nature of the blacklist record, may be null
|
||||
*/
|
||||
public ImaBlacklistRecord(
|
||||
final String path,
|
||||
final Digest hash,
|
||||
final String description) {
|
||||
this(path, hash, description, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new ImaBlacklistRecord with the given parameters. Either a path or hash,
|
||||
* or both, may be provided, as well as a description.
|
||||
*
|
||||
* If:
|
||||
* - a non-null path and a null hash is provided, any file matching the path should be
|
||||
* considered as blacklisted
|
||||
* - a null path and a non-null hash is provided, any file whose hash matches the given hash
|
||||
* should be considered as blacklisted
|
||||
* - a non-null path and a non-null hash is provided, a file that has both a matching path
|
||||
* and hash should be considered as blacklisted
|
||||
*
|
||||
* This class cannot be instantiated with both a null path and hash.
|
||||
*
|
||||
* @param path a blacklisted path, as described above
|
||||
* @param hash a blacklisted hash, as described above
|
||||
* @param description a description of the nature of the blacklist record, may be null
|
||||
* @param baseline the baseline that this record belongs to, may be null
|
||||
*/
|
||||
public ImaBlacklistRecord(
|
||||
final String path,
|
||||
final Digest hash,
|
||||
final String description,
|
||||
final ImaBlacklistBaseline baseline) {
|
||||
super(path, hash, description);
|
||||
if (path == null && hash == null) {
|
||||
throw new IllegalArgumentException("Cannot instantiate with both a null path and hash");
|
||||
}
|
||||
|
||||
if (path != null && StringUtils.isEmpty(path)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot instantiate with an empty (and non-null) path"
|
||||
);
|
||||
}
|
||||
this.baseline = baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero-arg constructor necessary for Hibernate.
|
||||
*/
|
||||
protected ImaBlacklistRecord() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the IMA blacklist baseline that this record belongs to.
|
||||
*
|
||||
* @return this record's owning blacklist baseline
|
||||
*/
|
||||
public ImaBlacklistBaseline getBaseline() {
|
||||
return baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this record's associated blacklist baseline.
|
||||
*
|
||||
* @param baseline the blacklist baseline to associate this record with
|
||||
*/
|
||||
public void setBaseline(final ImaBlacklistBaseline baseline) {
|
||||
this.baseline = baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the alert match type that should be raised for a measurement record that matches this
|
||||
* baseline record.
|
||||
*
|
||||
* @return the alert match type
|
||||
*/
|
||||
public AlertType getAlertMatchType() {
|
||||
if (getPath() == null) {
|
||||
return AlertType.IMA_BLACKLIST_HASH_MATCH;
|
||||
} else if (getHash() == null) {
|
||||
return AlertType.IMA_BLACKLIST_PATH_MATCH;
|
||||
} else {
|
||||
return AlertType.IMA_BLACKLIST_PATH_AND_HASH_MATCH;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.data.persist.baseline.ImaIgnoreSetBaseline;
|
||||
import hirs.data.persist.baseline.AbstractImaBaselineRecord;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
/**
|
||||
* An <code>IMAIgnoreSetRecord</code> contains a filepath and description of
|
||||
* files that should be ignored in IMA reports. The description is to provide
|
||||
* insight into why a file or group of files (in the case of dynamic matching) was ignored.
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
public class ImaIgnoreSetRecord extends AbstractImaBaselineRecord {
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "ima_ignore_set_id")
|
||||
private ImaIgnoreSetBaseline baseline;
|
||||
|
||||
@Transient
|
||||
private static final Pattern RECORD_PATTERN = Pattern.compile("\\((.*),.*\\)");
|
||||
|
||||
/**
|
||||
* Creates a new <code>ImaIgnoreSetRecord</code>.
|
||||
*
|
||||
* @param path file path, not null
|
||||
*/
|
||||
public ImaIgnoreSetRecord(final String path) {
|
||||
this(path, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>ImaIgnoreSetRecord</code>.
|
||||
*
|
||||
* @param path file path, not null
|
||||
* @param description description of why the file path was added to the ignore set, may be null
|
||||
*/
|
||||
public ImaIgnoreSetRecord(final String path, final String description) {
|
||||
this(path, description, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>ImaIgnoreSetRecord</code>.
|
||||
*
|
||||
* @param path file path
|
||||
* @param baseline the IMA ignore set baseline this record belongs to, may be null
|
||||
*/
|
||||
public ImaIgnoreSetRecord(final String path, final ImaIgnoreSetBaseline baseline) {
|
||||
this(path, null, baseline);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>ImaIgnoreSetRecord</code>.
|
||||
*
|
||||
* @param path file path, not null
|
||||
* @param description description of why the file path was added to the ignore set, may be null
|
||||
* @param baseline the IMA ignore set baseline this record belongs to, may be null
|
||||
*/
|
||||
public ImaIgnoreSetRecord(
|
||||
final String path,
|
||||
final String description,
|
||||
final ImaIgnoreSetBaseline baseline) {
|
||||
super(path, null, description);
|
||||
Preconditions.checkNotNull(path, "Path cannot be null");
|
||||
this.baseline = baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor necessary for Hibernate.
|
||||
*/
|
||||
protected ImaIgnoreSetRecord() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* This gets the baseline associated with the ignore set record.
|
||||
*
|
||||
* @return ImaIgnoreSetBaseline
|
||||
*/
|
||||
public final ImaIgnoreSetBaseline getBaseline() {
|
||||
return baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given baseline.
|
||||
*
|
||||
* @param recordBaseline baseline that matches the given baseline
|
||||
*/
|
||||
public final void setBaseline(final ImaIgnoreSetBaseline recordBaseline) {
|
||||
setOnlyBaseline(recordBaseline);
|
||||
if (recordBaseline != null) {
|
||||
recordBaseline.addOnlyToBaseline(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the baseline for this record.
|
||||
*
|
||||
* @param baseline
|
||||
* baseline or null
|
||||
*/
|
||||
public final void setOnlyBaseline(final ImaIgnoreSetBaseline baseline) {
|
||||
if (this.baseline != null && baseline != null) {
|
||||
this.baseline.removeOnlyBaseline(this);
|
||||
}
|
||||
|
||||
this.baseline = baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Designed to translate the 'received' String field in an <code>Alert</code> into an <code>
|
||||
* ImaIgnoreSetRecord</code>. Throws an IllegalArgumentException if an invalid String is passed
|
||||
* in
|
||||
*
|
||||
* @param record String formatted like the 'received' field of an <code>Alert</code>
|
||||
* @param description Description to be provided for the IMA ignore set baseline record
|
||||
* @return ImaIgnoreSetRecord built ImaIgnoreSetRecord based on report record String
|
||||
*/
|
||||
public static ImaIgnoreSetRecord fromString(final String record, final String description) {
|
||||
Matcher m = RECORD_PATTERN.matcher(record);
|
||||
m.matches();
|
||||
|
||||
//Verifies that one and only one group was captured based on the Regex pattern.
|
||||
if (m.groupCount() != 1) {
|
||||
String msg = String.format("Unexpected number of groups found with pattern \"%s\" "
|
||||
+ "on string \"%s\"", RECORD_PATTERN.toString(), record);
|
||||
|
||||
throw new IllegalArgumentException(msg);
|
||||
|
||||
}
|
||||
|
||||
return new ImaIgnoreSetRecord(m.group(1), description);
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import hirs.data.persist.baseline.TpmWhiteListBaseline;
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.utils.xjc.File;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -21,7 +20,6 @@ public class SwidResource {
|
||||
|
||||
private String name, size;
|
||||
private String rimFormat, rimType, rimUriGlobal, hashValue;
|
||||
private TpmWhiteListBaseline tpmWhiteList;
|
||||
private DigestAlgorithm digest = DigestAlgorithm.SHA1;
|
||||
private boolean validFileSize = false;
|
||||
|
||||
@ -76,7 +74,6 @@ public class SwidResource {
|
||||
}
|
||||
|
||||
this.digest = digest;
|
||||
tpmWhiteList = new TpmWhiteListBaseline(this.name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,18 +1,10 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.data.persist.baseline.TpmBlackListBaseline;
|
||||
import hirs.data.persist.baseline.TpmWhiteListBaseline;
|
||||
import hirs.data.persist.baseline.HasBaselines;
|
||||
import hirs.data.persist.baseline.Baseline;
|
||||
import hirs.data.persist.enums.AlertSeverity;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
@ -21,13 +13,12 @@ import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.OrderColumn;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class represents TPM policy. TPM Policy identifies the TPMBaseline instance that the TPM
|
||||
@ -38,7 +29,7 @@ import org.apache.logging.log4j.Logger;
|
||||
* maintains a set of the PCRs that should be appraised on a device-specific basis.
|
||||
*/
|
||||
@Entity
|
||||
public final class TPMPolicy extends Policy implements HasBaselines {
|
||||
public final class TPMPolicy extends Policy {
|
||||
|
||||
/**
|
||||
* Identifies all valid TPM PCRs bits (i.e. PCR 0-23) in any TPM PCR mask.
|
||||
@ -80,18 +71,6 @@ public final class TPMPolicy extends Policy implements HasBaselines {
|
||||
@Enumerated(EnumType.STRING)
|
||||
private AlertSeverity kernelUpdateAlertSeverity = AlertSeverity.UNSPECIFIED;
|
||||
|
||||
@ManyToMany(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "TPMWhiteListBaselines",
|
||||
joinColumns = { @JoinColumn(name = "PolicyID", nullable = false) })
|
||||
@OrderColumn(name = "TPMWhiteListBaselineIndex")
|
||||
private final List<TpmWhiteListBaseline> tpmWhiteListBaselines = new LinkedList<>();
|
||||
|
||||
@ManyToMany(fetch = FetchType.EAGER)
|
||||
@JoinTable(name = "TPMBlackListBaselines",
|
||||
joinColumns = { @JoinColumn(name = "PolicyID", nullable = false) })
|
||||
@OrderColumn(name = "TPMBlackListBaselineIndex")
|
||||
private final List<TpmBlackListBaseline> tpmBlackListBaselines = new LinkedList<>();
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "TPMPolicyDeviceSpecificPCRs",
|
||||
joinColumns = { @JoinColumn(name = "PolicyID", nullable = false) })
|
||||
@ -126,98 +105,6 @@ public final class TPMPolicy extends Policy implements HasBaselines {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the policy such that it contains only the given TPM WhiteList
|
||||
* baseline, which identifies
|
||||
* trusted PCR values for appraising a device. The trusted values are the expected or
|
||||
* acceptable values for PCRs. The report's PCR values will be compared against these values
|
||||
* to determine if the device is in a trusted state.
|
||||
*
|
||||
* @param baseline
|
||||
* The TPM white list baseline to be used by this policy.
|
||||
*/
|
||||
public void setTpmWhiteListBaseline(final TpmWhiteListBaseline baseline) {
|
||||
LOGGER.debug("setting TpmWhiteListBaseline {} for the {} policy", baseline, getName());
|
||||
if (baseline == null) {
|
||||
throw new PolicyException("Cannot set TPM baseline to null");
|
||||
}
|
||||
this.tpmWhiteListBaselines.clear();
|
||||
this.tpmWhiteListBaselines.add(baseline);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the policy such that it contains only the given TPM BlackList baseline,
|
||||
* which identifies PCR values that are not permitted.
|
||||
* Reports containing values that are not permitted result in the generation of an alert.
|
||||
*
|
||||
* @param baseline
|
||||
* The TPM black list baseline to be used by this policy.
|
||||
*/
|
||||
public void setTpmBlackListBaseline(final TpmBlackListBaseline baseline) {
|
||||
LOGGER.debug("setting TpmBlackListBaseline {} for the {} policy", baseline, getName());
|
||||
if (baseline == null) {
|
||||
throw new PolicyException("Cannot set TPM baseline to null");
|
||||
}
|
||||
this.tpmBlackListBaselines.clear();
|
||||
this.tpmBlackListBaselines.add(baseline);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the policy such that it contains the given TPM white list baselines,
|
||||
* which together identify trusted PCR values for appraising a device. These trusted
|
||||
* values are the expected or acceptable values for PCRs. The report's PCR
|
||||
* values will be compared against these values to determine if the device
|
||||
* is in a trusted state.
|
||||
*
|
||||
* @param baselines
|
||||
* The TPM white list baselines to be used by this policy.
|
||||
*/
|
||||
public void setTpmWhiteListBaselines(final Collection<TpmWhiteListBaseline> baselines) {
|
||||
LOGGER.debug("setting TpmWhiteListBaseline {} for the {} policy", baselines, getName());
|
||||
if (baselines == null) {
|
||||
throw new PolicyException("Cannot set TPM baselines to null");
|
||||
}
|
||||
this.tpmWhiteListBaselines.clear();
|
||||
this.tpmWhiteListBaselines.addAll(baselines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the policy such that it contains multiple TPM BlackList baselines,
|
||||
* which identifies PCR values that are not permitted.
|
||||
* Reports containing values that are not permitted result in the generation of an alert.
|
||||
*
|
||||
* @param blackListBaselines
|
||||
* The TPM black list baselines to be used by this policy.
|
||||
*/
|
||||
public void setTpmBlackListBaselines(
|
||||
final Collection<TpmBlackListBaseline> blackListBaselines) {
|
||||
LOGGER.debug("setting TpmBlackListBaseline {} for the {} policy",
|
||||
blackListBaselines, getName());
|
||||
if (blackListBaselines == null) {
|
||||
throw new PolicyException("Cannot set TPM baselines to null");
|
||||
}
|
||||
this.tpmBlackListBaselines.clear();
|
||||
this.tpmBlackListBaselines.addAll(blackListBaselines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TPM whitelist baselines associated with this policy.
|
||||
*
|
||||
* @return the TPM whitelist baselines for this policy
|
||||
*/
|
||||
public Collection<TpmWhiteListBaseline> getTpmWhiteListBaselines() {
|
||||
return Collections.unmodifiableCollection(this.tpmWhiteListBaselines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the TPM blacklist baselines associated with this policy.
|
||||
*
|
||||
* @return the TPM blacklist baselines for this policy
|
||||
*/
|
||||
public List<TpmBlackListBaseline> getTpmBlackListBaselines() {
|
||||
return Collections.unmodifiableList(tpmBlackListBaselines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of the device-specific PCRs. These are PCR IDs used by the appraiser to know
|
||||
* that the hash for that PCR should be compared against values for those PCRs from a previous
|
||||
@ -567,13 +454,6 @@ public final class TPMPolicy extends Policy implements HasBaselines {
|
||||
kernelUpdateAlertSeverity = severity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Baseline> getBaselines() {
|
||||
List<Baseline> baselines = new ArrayList<>();
|
||||
baselines.addAll(tpmWhiteListBaselines);
|
||||
return Collections.unmodifiableList(baselines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the list of kernel pcrs into a String for display purposes.
|
||||
* @return String
|
||||
|
@ -1,14 +1,10 @@
|
||||
package hirs.persist;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import hirs.FilteredRecordsList;
|
||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||
import hirs.data.persist.ArchivableEntity;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
@ -25,28 +21,16 @@ import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static org.hibernate.criterion.Restrictions.ilike;
|
||||
import static org.hibernate.criterion.Restrictions.sqlRestriction;
|
||||
@ -56,25 +40,25 @@ import static org.hibernate.criterion.Restrictions.sqlRestriction;
|
||||
* This class exists primarily to reduce code in {@link DBManager} which retries these methods
|
||||
* using a RetryTemplate.
|
||||
*
|
||||
* @param <AbstractEntity> type of objects to manage by this manager
|
||||
* @param <T> type of objects to manage by this manager
|
||||
*/
|
||||
public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<AbstractEntity> {
|
||||
public abstract class AbstractDbManager<T> implements CrudManager<ArchivableEntity> {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger(AbstractDbManager.class);
|
||||
private static final int MAX_CLASS_CACHE_ENTRIES = 500;
|
||||
|
||||
private final AbstractEntity entity;
|
||||
private final ArchivableEntity entity;
|
||||
|
||||
private SessionFactory factory;
|
||||
|
||||
/**
|
||||
* Creates a new <code>AbstractDbManager</code>.
|
||||
*
|
||||
* @param clazz Class to search for when doing Hibernate queries,
|
||||
* @param entity Class to search for when doing Hibernate queries,
|
||||
* unfortunately class type of T cannot be determined using only T
|
||||
* @param sessionFactory the session factory to use to interact with the database
|
||||
*/
|
||||
public AbstractDbManager(final AbstractEntity entity, final SessionFactory sessionFactory) {
|
||||
public AbstractDbManager(final ArchivableEntity entity, final SessionFactory sessionFactory) {
|
||||
if (entity == null) {
|
||||
LOGGER.error("AbstractDbManager cannot be instantiated with a null class");
|
||||
throw new IllegalArgumentException(
|
||||
@ -91,74 +75,6 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
this.factory = sessionFactory;
|
||||
}
|
||||
|
||||
private static final LoadingCache<AbstractEntity, Set<Field>> PERSISTED_FIELDS =
|
||||
CacheBuilder.newBuilder()
|
||||
.maximumSize(MAX_CLASS_CACHE_ENTRIES)
|
||||
.build(new CacheLoader<AbstractEntity, Set<Field>>() {
|
||||
@Override
|
||||
public Set<Field> load(final AbstractEntity entity) throws Exception {
|
||||
return getPersistedFields(entity);
|
||||
}
|
||||
});
|
||||
|
||||
private static Set<Field> getPersistedFields(final AbstractEntity entity) {
|
||||
Set<Field> fields = new HashSet<>();
|
||||
|
||||
for (Field f : entity.getDeclaredFields()) {
|
||||
if (f.isAnnotationPresent(OneToMany.class)
|
||||
|| f.isAnnotationPresent(ManyToMany.class)
|
||||
|| f.isAnnotationPresent(ManyToOne.class)
|
||||
|| f.isAnnotationPresent(OneToOne.class)
|
||||
|| f.isAnnotationPresent(Column.class)) {
|
||||
fields.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.getSuperclass() != Object.class) {
|
||||
fields.addAll(getPersistedFields(entity.getSuperclass()));
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
private static final LoadingCache<Class, Set<Field>> LAZY_LOADED_FIELDS =
|
||||
CacheBuilder.newBuilder()
|
||||
.maximumSize(MAX_CLASS_CACHE_ENTRIES)
|
||||
.build(
|
||||
new CacheLoader<Class, Set<Field>>() {
|
||||
@Override
|
||||
public Set<Field> load(final Class clazz) throws Exception {
|
||||
return getLazyFields(clazz);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
private static Set<Field> getLazyFields(final Class clazz) {
|
||||
Set<Field> fields = new HashSet<>();
|
||||
|
||||
for (Field f : clazz.getDeclaredFields()) {
|
||||
if (f.isAnnotationPresent(OneToMany.class)) {
|
||||
if (f.getAnnotation(OneToMany.class).fetch().equals(FetchType.LAZY)) {
|
||||
fields.add(f);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (f.isAnnotationPresent(ManyToMany.class)) {
|
||||
if (f.getAnnotation(ManyToMany.class).fetch().equals(FetchType.LAZY)) {
|
||||
fields.add(f);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (clazz.getSuperclass() != Object.class) {
|
||||
fields.addAll(getLazyFields(clazz.getSuperclass()));
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently configured database implementation.
|
||||
*
|
||||
@ -204,8 +120,8 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
LOGGER.debug("retrieving object from db");
|
||||
tx = session.beginTransaction();
|
||||
Object obj = session.get(entity, id);
|
||||
if (obj instanceof AbstractEntity) {
|
||||
AbstractEntity objectOfTypeT = (AbstractEntity) obj;
|
||||
if (obj instanceof hirs.data.persist.ArchivableEntity) {
|
||||
hirs.data.persist.ArchivableEntity objectOfTypeT = (hirs.data.persist.ArchivableEntity) obj;
|
||||
LOGGER.debug("found object, deleting it");
|
||||
session.delete(objectOfTypeT);
|
||||
deleted = true;
|
||||
@ -248,16 +164,16 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
Transaction tx = null;
|
||||
Session session = factory.getCurrentSession();
|
||||
CriteriaBuilder builder = session.getCriteriaBuilder();
|
||||
CriteriaQuery<AbstractEntity> criteria = builder.createQuery(entity);
|
||||
CriteriaQuery<hirs.data.persist.ArchivableEntity> criteria = builder.createQuery(entity);
|
||||
try {
|
||||
LOGGER.debug("retrieving object from db");
|
||||
tx = session.beginTransaction();
|
||||
Root<AbstractEntity> myObjectRoot = criteria.from(clazz);
|
||||
Join<AbstractEntity, JoinObject> joinObject = myObjectRoot.join("joinObject");
|
||||
Root<hirs.data.persist.ArchivableEntity> myObjectRoot = criteria.from(clazz);
|
||||
Join<hirs.data.persist.ArchivableEntity, JoinObject> joinObject = myObjectRoot.join("joinObject");
|
||||
Object object = session.getSessionFactory().getCurrentSession().createCriteria(clazz)
|
||||
.add(Restrictions.eq("name", name)).uniqueResult();
|
||||
if (object instanceof AbstractEntity) {
|
||||
AbstractEntity objectOfTypeT = (AbstractEntity) object;
|
||||
if (object instanceof hirs.data.persist.ArchivableEntity) {
|
||||
hirs.data.persist.ArchivableEntity objectOfTypeT = (hirs.data.persist.ArchivableEntity) object;
|
||||
LOGGER.debug("found object, deleting it");
|
||||
session.delete(objectOfTypeT);
|
||||
deleted = true;
|
||||
@ -287,7 +203,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* @throws DBManagerException if unable to find the baseline or delete it
|
||||
* from the database
|
||||
*/
|
||||
protected boolean doDelete(final AbstractEntity object) throws DBManagerException {
|
||||
protected boolean doDelete(final ArchivableEntity object) throws DBManagerException {
|
||||
LOGGER.debug("deleting object: {}", object);
|
||||
if (object == null) {
|
||||
LOGGER.debug("null object argument");
|
||||
@ -327,14 +243,14 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
LOGGER.debug("Deleting instances of class: {}", clazz);
|
||||
tx = session.beginTransaction();
|
||||
CriteriaBuilder builder = session.getCriteriaBuilder();
|
||||
CriteriaQuery<AbstractEntity> criteriaQuery = builder.createQuery(clazz);
|
||||
Root<AbstractEntity> root = criteriaQuery.from(clazz);
|
||||
CriteriaQuery<ArchivableEntity> criteriaQuery = builder.createQuery(clazz);
|
||||
Root<hirs.data.persist.ArchivableEntity> root = criteriaQuery.from(clazz);
|
||||
Predicate recordPredicate = builder.and(
|
||||
);
|
||||
criteriaQuery.select(root).where(recordPredicate);
|
||||
Query<AbstractEntity> query = session.createQuery(criteriaQuery);
|
||||
List<AbstractEntity> results = query.getResultList();
|
||||
AbstractEntity ret = null;
|
||||
Query<ArchivableEntity> query = session.createQuery(criteriaQuery);
|
||||
List<ArchivableEntity> results = query.getResultList();
|
||||
ArchivableEntity ret = null;
|
||||
if (results != null && !results.isEmpty()) {
|
||||
ret = results.get(0);
|
||||
}
|
||||
@ -342,8 +258,8 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
List instances = session.createCriteria(clazz)
|
||||
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
|
||||
for (Object instance : instances) {
|
||||
if (instance instanceof AbstractEntity) {
|
||||
session.delete((AbstractEntity) instance);
|
||||
if (instance instanceof ArchivableEntity) {
|
||||
session.delete((ArchivableEntity) instance);
|
||||
numEntitiesDeleted++;
|
||||
}
|
||||
}
|
||||
@ -370,7 +286,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* @throws DBManagerException if an error is encountered while performing the query or creating
|
||||
* the result objects
|
||||
*/
|
||||
protected List<AbstractEntity> doGetWithCriteria(final Collection<Criterion> criteriaCollection)
|
||||
protected List<ArchivableEntity> doGetWithCriteria(final Collection<Criterion> criteriaCollection)
|
||||
throws DBManagerException {
|
||||
return doGetWithCriteria(entity, criteriaCollection);
|
||||
}
|
||||
@ -379,7 +295,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* Runs a Criteria query using the given collection of Criterion over the
|
||||
* associated class.
|
||||
*
|
||||
* @param <AbstractEntity> the specific type of class to retrieve
|
||||
* @param <ArchivableEntity> the specific type of class to retrieve
|
||||
* (should extend this class' <T> parameter)
|
||||
* @param clazzToGet the class of object to retrieve
|
||||
* @param criteriaCollection the collection of Criterion to apply
|
||||
@ -388,8 +304,8 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* @throws DBManagerException if an error is encountered while performing the query or creating
|
||||
* the result objects
|
||||
*/
|
||||
protected final List<AbstractEntity> doGetWithCriteria(
|
||||
final Class<AbstractEntity> clazzToGet,
|
||||
protected final List<ArchivableEntity> doGetWithCriteria(
|
||||
final Class<ArchivableEntity> clazzToGet,
|
||||
final Collection<Criterion> criteriaCollection
|
||||
) throws DBManagerException {
|
||||
LOGGER.debug("running criteria query over: {}", clazzToGet);
|
||||
@ -397,7 +313,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
LOGGER.debug("null object argument");
|
||||
throw new NullPointerException("criteria or restrictions");
|
||||
}
|
||||
List<AbstractEntity> ret = new ArrayList<>();
|
||||
List<ArchivableEntity> ret = new ArrayList<>();
|
||||
Transaction tx = null;
|
||||
Session session = factory.getCurrentSession();
|
||||
try {
|
||||
@ -437,7 +353,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* @throws DBManagerException if object has previously been saved or an
|
||||
* error occurs while trying to save it to the database
|
||||
*/
|
||||
protected AbstractEntity doSave(final AbstractEntity object) throws DBManagerException {
|
||||
protected ArchivableEntity doSave(final ArchivableEntity object) throws DBManagerException {
|
||||
LOGGER.debug("saving object: {}", object);
|
||||
if (object == null) {
|
||||
LOGGER.debug("null object argument");
|
||||
@ -452,7 +368,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
final Serializable id = session.save(object);
|
||||
Object o = session.get(object.getClass(), id);
|
||||
session.getTransaction().commit();
|
||||
return (AbstractEntity) o;
|
||||
return (ArchivableEntity) o;
|
||||
} catch (Exception e) {
|
||||
final String msg = "unable to save object";
|
||||
LOGGER.error(msg, e);
|
||||
@ -471,7 +387,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* @param object object to update
|
||||
* @throws DBManagerException if unable to update the record
|
||||
*/
|
||||
protected void doUpdate(final AbstractEntity object) throws DBManagerException {
|
||||
protected void doUpdate(final ArchivableEntity object) throws DBManagerException {
|
||||
LOGGER.debug("updating object");
|
||||
if (object == null) {
|
||||
LOGGER.debug("null object argument");
|
||||
@ -506,7 +422,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
protected AbstractEntity doGet(final String name) throws DBManagerException {
|
||||
protected ArchivableEntity doGet(final String name) throws DBManagerException {
|
||||
LOGGER.debug("getting object: {}", name);
|
||||
if (name == null) {
|
||||
LOGGER.debug("null name argument");
|
||||
@ -519,14 +435,14 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
LOGGER.debug("retrieving " + entity.toString() + " from db");
|
||||
tx = session.beginTransaction();
|
||||
CriteriaBuilder builder = session.getCriteriaBuilder();
|
||||
CriteriaQuery<AbstractEntity> criteriaQuery = builder.createQuery(entity);
|
||||
Root<AbstractEntity> root = criteriaQuery.from(entity);
|
||||
CriteriaQuery<ArchivableEntity> criteriaQuery = builder.createQuery(entity);
|
||||
Root<ArchivableEntity> root = criteriaQuery.from(entity);
|
||||
Predicate recordPredicate = builder.and(
|
||||
builder.equal(root.get("name"), name));
|
||||
criteriaQuery.select(root).where(recordPredicate);
|
||||
Query<AbstractEntity> query = session.createQuery(criteriaQuery);
|
||||
List<AbstractEntity> results = query.getResultList();
|
||||
AbstractEntity ret = null;
|
||||
Query<ArchivableEntity> query = session.createQuery(criteriaQuery);
|
||||
List<ArchivableEntity> results = query.getResultList();
|
||||
ArchivableEntity ret = null;
|
||||
if (results != null && !results.isEmpty()) {
|
||||
ret = results.get(0);
|
||||
}
|
||||
@ -555,7 +471,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
protected AbstractEntity doGet(final Serializable id) throws DBManagerException {
|
||||
protected ArchivableEntity doGet(final Serializable id) throws DBManagerException {
|
||||
LOGGER.debug("getting object: {}", id);
|
||||
if (id == null) {
|
||||
LOGGER.debug("null id argument");
|
||||
@ -566,155 +482,7 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
try {
|
||||
LOGGER.debug("retrieving object from db");
|
||||
tx = session.beginTransaction();
|
||||
AbstractEntity ret = (AbstractEntity) session.get(entity, id);
|
||||
tx.commit();
|
||||
return ret;
|
||||
} catch (Exception e) {
|
||||
final String msg = "unable to retrieve object";
|
||||
LOGGER.error(msg, e);
|
||||
if (tx != null) {
|
||||
LOGGER.debug("rolling back transaction");
|
||||
tx.rollback();
|
||||
}
|
||||
throw new DBManagerException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void doLoadLazyFields(final Object obj, final boolean recurse)
|
||||
throws ExecutionException, IllegalAccessException, NoSuchMethodException,
|
||||
InvocationTargetException {
|
||||
doLoadLazyFields(obj, recurse, new HashSet<>());
|
||||
}
|
||||
|
||||
private void doLoadLazyFields(final Object obj, final boolean recurse,
|
||||
final Set<Object> doNotLoad)
|
||||
throws ExecutionException, IllegalAccessException, NoSuchMethodException,
|
||||
InvocationTargetException {
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obj.getClass().isAnnotationPresent(Entity.class)) {
|
||||
return;
|
||||
}
|
||||
|
||||
doNotLoad.add(obj);
|
||||
|
||||
for (Field field : LAZY_LOADED_FIELDS.get(obj.getClass())) {
|
||||
field.setAccessible(true);
|
||||
Object fieldObj = FieldUtils.readField(obj, field.getName(), true);
|
||||
Hibernate.initialize(fieldObj);
|
||||
field.setAccessible(false);
|
||||
if (fieldObj instanceof Collection) {
|
||||
Collection.class.getMethod("size").invoke(fieldObj);
|
||||
}
|
||||
}
|
||||
|
||||
if (recurse) {
|
||||
for (Field field : PERSISTED_FIELDS.get(obj.getClass())) {
|
||||
field.setAccessible(true);
|
||||
Object fieldObj = FieldUtils.readField(obj, field.getName(), true);
|
||||
field.setAccessible(false);
|
||||
if (!doNotLoad.contains(fieldObj)) {
|
||||
if (fieldObj instanceof Collection) {
|
||||
for (Object o : (Collection) fieldObj) {
|
||||
doLoadLazyFields(o, true, doNotLoad);
|
||||
}
|
||||
} else {
|
||||
doLoadLazyFields(fieldObj, true, doNotLoad);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Object</code> from the database. This searches the
|
||||
* database for an entry whose name matches <code>name</code>. It then
|
||||
* reconstructs the <code>Object</code> from the database entry. It will also
|
||||
* load all the lazy fields in the given class. If the parameter <code>recurse</code>
|
||||
* is set to true, this method will recursively descend into each of the object's fields
|
||||
* to load all the lazily-loaded entities. If false, only the fields belonging to the object
|
||||
* itself will be loaded.
|
||||
*
|
||||
* @param name name of the object
|
||||
* @param recurse whether to recursively load lazy data throughout the object's structures
|
||||
* @return object if found, otherwise null.
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
protected AbstractEntity doGetAndLoadLazyFields(final String name, final boolean recurse)
|
||||
throws DBManagerException {
|
||||
LOGGER.debug("getting object: {}", name);
|
||||
if (name == null) {
|
||||
LOGGER.debug("null id argument");
|
||||
return null;
|
||||
}
|
||||
|
||||
Transaction tx = null;
|
||||
Session session = factory.getCurrentSession();
|
||||
try {
|
||||
LOGGER.debug("retrieving " + entity.toString() + " from db");
|
||||
tx = session.beginTransaction();
|
||||
CriteriaBuilder builder = session.getCriteriaBuilder();
|
||||
CriteriaQuery<AbstractEntity> criteriaQuery = builder.createQuery(entity);
|
||||
Root<AbstractEntity> root = criteriaQuery.from(entity);
|
||||
Predicate recordPredicate = builder.and(
|
||||
builder.equal(root.get("name"), name));
|
||||
criteriaQuery.select(root).where(recordPredicate);
|
||||
Query<AbstractEntity> query = session.createQuery(criteriaQuery);
|
||||
List<AbstractEntity> results = query.getResultList();
|
||||
AbstractEntity ret = null;
|
||||
if (results != null && !results.isEmpty()) {
|
||||
ret = results.get(0);
|
||||
}
|
||||
|
||||
// T ret = clazz.cast(session.createCriteria(clazz)
|
||||
// .add(Restrictions.eq("name", name)).uniqueResult());
|
||||
doLoadLazyFields(ret, recurse);
|
||||
tx.commit();
|
||||
return ret;
|
||||
} catch (Exception e) {
|
||||
final String msg = "unable to retrieve object";
|
||||
LOGGER.error(msg, e);
|
||||
if (tx != null) {
|
||||
LOGGER.debug("rolling back transaction");
|
||||
tx.rollback();
|
||||
}
|
||||
throw new DBManagerException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Object</code> from the database. This searches the
|
||||
* database for an entry whose id matches <code>id</code>. It then
|
||||
* reconstructs the <code>Object</code> from the database entry. It will also
|
||||
* load all the lazy fields in the given class. If the parameter <code>recurse</code>
|
||||
* is set to true, this method will recursively descend into each of the object's fields
|
||||
* to load all the lazily-loaded entities. If false, only the fields belonging to the object
|
||||
* itself will be loaded.
|
||||
*
|
||||
* @param id id of the object
|
||||
* @param recurse whether to recursively load lazy data throughout the object's structures
|
||||
* @return object if found, otherwise null.
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
protected AbstractEntity doGetAndLoadLazyFields(final Serializable id, final boolean recurse)
|
||||
throws DBManagerException {
|
||||
LOGGER.debug("getting object: {}", id);
|
||||
if (id == null) {
|
||||
LOGGER.debug("null id argument");
|
||||
return null;
|
||||
}
|
||||
|
||||
Transaction tx = null;
|
||||
Session session = factory.getCurrentSession();
|
||||
try {
|
||||
LOGGER.debug("retrieving object from db");
|
||||
tx = session.beginTransaction();
|
||||
AbstractEntity ret = (AbstractEntity) session.get(entity, id);
|
||||
doLoadLazyFields(ret, recurse);
|
||||
ArchivableEntity ret = (ArchivableEntity) session.get(entity, id);
|
||||
tx.commit();
|
||||
return ret;
|
||||
} catch (Exception e) {
|
||||
@ -742,17 +510,17 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* @return list of <code>T</code> names
|
||||
* @throws DBManagerException if unable to search the database
|
||||
*/
|
||||
protected List<AbstractEntity> doGetList(final AbstractEntity entity,
|
||||
protected List<ArchivableEntity> doGetList(final ArchivableEntity entity,
|
||||
final Criterion additionalRestriction)
|
||||
throws DBManagerException {
|
||||
LOGGER.debug("Getting object list");
|
||||
AbstractEntity searchClass = entity;
|
||||
ArchivableEntity searchClass = entity;
|
||||
if (entity == null) {
|
||||
LOGGER.debug("entity is null");
|
||||
searchClass = this.entity;
|
||||
}
|
||||
|
||||
List<AbstractEntity> objects = new ArrayList<>();
|
||||
List<ArchivableEntity> objects = new ArrayList<>();
|
||||
Transaction tx = null;
|
||||
Session session = factory.getCurrentSession();
|
||||
try {
|
||||
@ -774,8 +542,8 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
}
|
||||
// List list = criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
|
||||
for (Object o : results) {
|
||||
if (o instanceof AbstractEntity) {
|
||||
objects.add((AbstractEntity) o);
|
||||
if (o instanceof ArchivableEntity) {
|
||||
objects.add((ArchivableEntity) o);
|
||||
}
|
||||
}
|
||||
tx.commit();
|
||||
@ -812,12 +580,12 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
* @throws DBManagerException if unable to create the list
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:parameternumber")
|
||||
protected FilteredRecordsList<AbstractEntity> doGetOrderedList(final AbstractEntity clazz,
|
||||
protected FilteredRecordsList<ArchivableEntity> doGetOrderedList(final ArchivableEntity clazz,
|
||||
final String columnToOrder, final boolean ascending, final int firstResult,
|
||||
final int maxResults, final String search, final Map<String, Boolean> searchableColumns,
|
||||
final CriteriaModifier criteriaModifier) throws DBManagerException {
|
||||
LOGGER.debug("Getting object list");
|
||||
AbstractEntity searchClass = clazz;
|
||||
ArchivableEntity searchClass = clazz;
|
||||
if (clazz == null) {
|
||||
LOGGER.debug("clazz is null");
|
||||
searchClass = this.clazz;
|
||||
@ -830,9 +598,9 @@ public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<A
|
||||
}
|
||||
|
||||
//Object that will store query values
|
||||
FilteredRecordsList<AbstractEntity> aqr = new FilteredRecordsList<>();
|
||||
FilteredRecordsList<ArchivableEntity> aqr = new FilteredRecordsList<>();
|
||||
|
||||
List<AbstractEntity> objects = new ArrayList<>();
|
||||
List<ArchivableEntity> objects = new ArrayList<>();
|
||||
Transaction tx = null;
|
||||
Session session = factory.getCurrentSession();
|
||||
try {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package hirs.persist;
|
||||
|
||||
import hirs.data.persist.AbstractEntity;
|
||||
import org.hibernate.criterion.Criterion;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -9,7 +10,7 @@ import java.util.List;
|
||||
* Interface defining database CRUD operations (Create, Read, Update, Delete).
|
||||
* @param <T> the object type, T.
|
||||
*/
|
||||
public interface CrudManager<AbstractEntity> extends OrderedListQuerier<AbstractEntity> {
|
||||
public interface CrudManager<T> extends OrderedListQuerier<AbstractEntity> {
|
||||
|
||||
/**
|
||||
* Deletes all instances of the associated class.
|
||||
@ -80,39 +81,39 @@ public interface CrudManager<AbstractEntity> extends OrderedListQuerier<Abstract
|
||||
*/
|
||||
AbstractEntity get(Serializable id) throws DBManagerException;
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Object</code> from the database. This searches the
|
||||
* database for an entry whose id matches <code>id</code>. It then
|
||||
* reconstructs the <code>Object</code> from the database entry. It will also
|
||||
* load all the lazy fields in the given class. If the parameter <code>recurse</code>
|
||||
* is set to true, this method will recursively descend into each of the object's fields
|
||||
* to load all the lazily-loaded entities. If false, only the fields belonging to the object
|
||||
* itself will be loaded.
|
||||
*
|
||||
* @param id id of the object
|
||||
* @param recurse whether to recursively load lazy data throughout the object's structures
|
||||
* @return object if found, otherwise null.
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
AbstractEntity getAndLoadLazyFields(Serializable id, boolean recurse)
|
||||
throws DBManagerException;
|
||||
|
||||
/**
|
||||
* Returns a list of all <code>T</code>s of type <code>clazz</code> in the database, with no
|
||||
* additional restrictions.
|
||||
* <p>
|
||||
* This would be useful if <code>T</code> has several subclasses being
|
||||
* managed. This class argument allows the caller to limit which types of
|
||||
* <code>T</code> should be returned.
|
||||
*
|
||||
* @param clazz class type of <code>T</code>s to search for (may be null to
|
||||
* use Class<T>)
|
||||
* @return list of <code>T</code> names
|
||||
* @throws DBManagerException if unable to search the database
|
||||
*/
|
||||
List<AbstractEntity> getList(AbstractEntity entity)
|
||||
throws DBManagerException;
|
||||
// /**
|
||||
// * Retrieves the <code>Object</code> from the database. This searches the
|
||||
// * database for an entry whose id matches <code>id</code>. It then
|
||||
// * reconstructs the <code>Object</code> from the database entry. It will also
|
||||
// * load all the lazy fields in the given class. If the parameter <code>recurse</code>
|
||||
// * is set to true, this method will recursively descend into each of the object's fields
|
||||
// * to load all the lazily-loaded entities. If false, only the fields belonging to the object
|
||||
// * itself will be loaded.
|
||||
// *
|
||||
// * @param id id of the object
|
||||
// * @param recurse whether to recursively load lazy data throughout the object's structures
|
||||
// * @return object if found, otherwise null.
|
||||
// * @throws DBManagerException if unable to search the database or recreate
|
||||
// * the <code>Object</code>
|
||||
// */
|
||||
// AbstractEntity getAndLoadLazyFields(Serializable id, boolean recurse)
|
||||
// throws DBManagerException;
|
||||
//
|
||||
// /**
|
||||
// * Returns a list of all <code>T</code>s of type <code>clazz</code> in the database, with no
|
||||
// * additional restrictions.
|
||||
// * <p>
|
||||
// * This would be useful if <code>T</code> has several subclasses being
|
||||
// * managed. This class argument allows the caller to limit which types of
|
||||
// * <code>T</code> should be returned.
|
||||
// *
|
||||
// * @param AbstractEntity class type of <code>T</code>s to search for (may be null to
|
||||
// * use Class<T>)
|
||||
// * @return list of <code>T</code> names
|
||||
// * @throws DBManagerException if unable to search the database
|
||||
// */
|
||||
// List<AbstractEntity> getList(AbstractEntity entity)
|
||||
// throws DBManagerException;
|
||||
|
||||
/**
|
||||
* Returns a list of all <code>T</code>s of type <code>clazz</code> in the database, with an
|
||||
@ -122,7 +123,7 @@ public interface CrudManager<AbstractEntity> extends OrderedListQuerier<Abstract
|
||||
* managed. This class argument allows the caller to limit which types of
|
||||
* <code>T</code> should be returned.
|
||||
*
|
||||
* @param clazz class type of <code>T</code>s to search for (may be null to
|
||||
* @param AbstractEntity class type of <code>T</code>s to search for (may be null to
|
||||
* use Class<T>)
|
||||
* @param additionalRestriction - an added Criterion to use in the query, null for none
|
||||
* @return list of <code>T</code> names
|
||||
|
@ -1,6 +1,7 @@
|
||||
package hirs.persist;
|
||||
|
||||
import hirs.FilteredRecordsList;
|
||||
import hirs.data.persist.AbstractEntity;
|
||||
import hirs.data.persist.ArchivableEntity;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -27,7 +28,7 @@ import java.util.Map;
|
||||
* archive, and delete operations for managing objects in a database.
|
||||
*
|
||||
*/
|
||||
public class DBManager<AbstractEntity> extends AbstractDbManager<AbstractEntity> {
|
||||
public class DBManager<T> extends AbstractDbManager<AbstractEntity> {
|
||||
private static final Logger LOGGER = LogManager.getLogger(DBManager.class);
|
||||
|
||||
/**
|
||||
@ -114,7 +115,7 @@ public class DBManager<AbstractEntity> extends AbstractDbManager<AbstractEntity>
|
||||
* @throws DBManagerException if an error is encountered while performing the query or creating
|
||||
* the result objects
|
||||
*/
|
||||
public final List<AbstractEntity> getWithCriteria(final Collection<Criterion> criteriaCollection)
|
||||
public final List<hirs.data.persist.ArchivableEntity> getWithCriteria(final Collection<Criterion> criteriaCollection)
|
||||
throws DBManagerException {
|
||||
return retryTemplate.execute(
|
||||
new RetryCallback<List<AbstractEntity>, DBManagerException>() {
|
||||
@ -137,13 +138,13 @@ public class DBManager<AbstractEntity> extends AbstractDbManager<AbstractEntity>
|
||||
* @throws DBManagerException if an error is encountered while performing the query or creating
|
||||
* the result objects
|
||||
*/
|
||||
protected final List<AbstractEntity> getWithCriteria(
|
||||
final Class<AbstractEntity> clazzToGet,
|
||||
protected final List<hirs.data.persist.ArchivableEntity> getWithCriteria(
|
||||
final Class<hirs.data.persist.ArchivableEntity> clazzToGet,
|
||||
final Collection<Criterion> criteriaCollection) throws DBManagerException {
|
||||
return retryTemplate.execute(
|
||||
new RetryCallback<List<AbstractEntity>, DBManagerException>() {
|
||||
@Override
|
||||
public List<AbstractEntity> doWithRetry(final RetryContext context)
|
||||
public List<hirs.data.persist.ArchivableEntity> doWithRetry(final RetryContext context)
|
||||
throws DBManagerException {
|
||||
return doGetWithCriteria(clazzToGet, criteriaCollection);
|
||||
}
|
||||
@ -213,10 +214,10 @@ public class DBManager<AbstractEntity> extends AbstractDbManager<AbstractEntity>
|
||||
* @throws DBManagerException if unable to search the database or recreate
|
||||
* the <code>Object</code>
|
||||
*/
|
||||
public final AbstractEntity get(final String name) throws DBManagerException {
|
||||
return retryTemplate.execute(new RetryCallback<AbstractEntity, DBManagerException>() {
|
||||
public final ArchivableEntity get(final String name) throws DBManagerException {
|
||||
return retryTemplate.execute(new RetryCallback<ArchivableEntity, DBManagerException>() {
|
||||
@Override
|
||||
public AbstractEntity doWithRetry(final RetryContext context) throws DBManagerException {
|
||||
public ArchivableEntity doWithRetry(final RetryContext context) throws DBManagerException {
|
||||
return doGet(name);
|
||||
}
|
||||
});
|
||||
@ -488,7 +489,7 @@ public class DBManager<AbstractEntity> extends AbstractDbManager<AbstractEntity>
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractEntity target = get(name);
|
||||
ArchivableEntity target = get(name);
|
||||
if (target == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -5,14 +5,11 @@ import hirs.appraiser.Appraiser;
|
||||
import hirs.data.persist.Device;
|
||||
import hirs.data.persist.DeviceGroup;
|
||||
import hirs.data.persist.Policy;
|
||||
import hirs.data.persist.baseline.Baseline;
|
||||
import hirs.data.persist.baseline.HasBaselines;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
@ -20,7 +17,6 @@ import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -97,36 +93,7 @@ public class DBPolicyManager extends DBManager<Policy> implements PolicyManager
|
||||
public final List<Policy> getPolicyList(final Class<? extends Policy> clazz)
|
||||
throws PolicyManagerException {
|
||||
LOGGER.debug("getting policy list");
|
||||
try {
|
||||
return super.getList(clazz, Restrictions.isNull("archivedTime"));
|
||||
} catch (DBManagerException e) {
|
||||
throw new PolicyManagerException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all the policies that contain the given baseline.
|
||||
*
|
||||
* @param clazz the class of Policy to search
|
||||
* @param baseline the baseline that should be a member of returned Policies
|
||||
* @return the list of matching Policies
|
||||
*/
|
||||
@Override
|
||||
public List<Policy> getPoliciesContainingBaseline(
|
||||
final Class<? extends Policy> clazz,
|
||||
final Baseline baseline
|
||||
) {
|
||||
List<Policy> matchingPolicies = new ArrayList<>();
|
||||
List<Policy> policies = getPolicyList(clazz);
|
||||
for (Policy policy : policies) {
|
||||
if (policy instanceof HasBaselines) {
|
||||
HasBaselines policyWithBaselines = (HasBaselines) policy;
|
||||
if (policyWithBaselines.getBaselines().contains(baseline)) {
|
||||
matchingPolicies.add(policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchingPolicies;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,29 +1,16 @@
|
||||
package hirs.persist;
|
||||
|
||||
import hirs.FilteredRecordsList;
|
||||
import hirs.data.bean.SimpleImaRecordBean;
|
||||
import hirs.data.persist.IMAMeasurementRecord;
|
||||
import hirs.data.persist.IMAReport;
|
||||
import hirs.data.persist.IntegrityReport;
|
||||
import hirs.data.persist.Report;
|
||||
import hirs.data.persist.ReportSummary;
|
||||
import hirs.persist.imarecord.DbImaRecordQueryForDevice;
|
||||
import hirs.persist.imarecord.DbImaRecordQueryForDeviceSinceLastFullReport;
|
||||
import hirs.persist.imarecord.DbImaRecordQueryForNone;
|
||||
import hirs.persist.imarecord.DbImaRecordQueryForReport;
|
||||
import hirs.persist.imarecord.DbImaRecordQueryParameters;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.criterion.Conjunction;
|
||||
import org.hibernate.criterion.Disjunction;
|
||||
import org.hibernate.criterion.MatchMode;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -90,165 +77,12 @@ public class DBReportManager extends DBManager<Report> implements ReportManager
|
||||
throws ReportManagerException {
|
||||
LOGGER.debug("getting report list");
|
||||
try {
|
||||
return super.getList(clazz);
|
||||
return super.getList(Report);
|
||||
} catch (DBManagerException e) {
|
||||
throw new ReportManagerException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all Report Records that are ordered by a column
|
||||
* and direction (ASC, DESC) that is provided by the user. This
|
||||
* method contains database interactions designed to extract specific
|
||||
* fields from the database to avoid retrieving full records in order
|
||||
* to improve query performance and reduce the size of teh data set
|
||||
* returned to the caller. This method helps support the server-side
|
||||
* processing in the JQuery DataTables.
|
||||
*
|
||||
* @param scope the scope of the search: NONE, ALL, REPORT, or DEVICE
|
||||
* @param id the id or name of the REPORT or DEVICE to search
|
||||
* @param sinceLastFullReport limits the records to those since the last full report for the
|
||||
* device
|
||||
* @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
|
||||
* @param searchableColumns map containing columns that search string can
|
||||
* be applied to
|
||||
* @return FilteredRecordsList object with fields for DataTables
|
||||
* @throws ReportManagerException if unable to create the list
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("checkstyle:parameternumber")
|
||||
public final FilteredRecordsList<SimpleImaRecordBean>
|
||||
getOrderedRecordListWithoutRecords(
|
||||
final IMARecordScope scope,
|
||||
final String id,
|
||||
final boolean sinceLastFullReport,
|
||||
final IMARecordField columnToOrder,
|
||||
final boolean ascending,
|
||||
final int firstResult,
|
||||
final int maxResults,
|
||||
final String search,
|
||||
final Map<String, Boolean> searchableColumns)
|
||||
throws ReportManagerException {
|
||||
|
||||
// check columnToOrder
|
||||
if (columnToOrder == null) {
|
||||
final String msg = "columnToOrder cannot be null";
|
||||
LOGGER.error(msg);
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
// check scope
|
||||
if (scope == null) {
|
||||
throw new IllegalArgumentException("IMARecordScope cannot be null");
|
||||
}
|
||||
|
||||
switch (scope) {
|
||||
case NONE:
|
||||
// Returns an empty FilteredRecordsList to make DataTables
|
||||
// display "No Data".
|
||||
return new FilteredRecordsList<>();
|
||||
case REPORT:
|
||||
// return getImaRecordsForReport(id, columnToOrder, ascending,
|
||||
// firstResult,
|
||||
// maxResults, search, searchableColumns);
|
||||
case DEVICE:
|
||||
// return getImaRecordsForDevice(id, sinceLastFullReport,
|
||||
// columnToOrder, ascending, firstResult,
|
||||
// maxResults, search, searchableColumns);
|
||||
default:
|
||||
throw new UnsupportedOperationException(
|
||||
"IMARecordScope " + scope + " is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all Report Records 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 scope the scope of the search: NONE, ALL, REPORT, or DEVICE
|
||||
* @param id the id or name of the REPORT or DEVICE to search
|
||||
* @param sinceLastFullReport limits the records to those since the last full report for the
|
||||
* device
|
||||
* @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
|
||||
* @throws ReportManagerException if unable to create the list
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("checkstyle:parameternumber")
|
||||
public final FilteredRecordsList<IMAMeasurementRecord> getOrderedRecordList(
|
||||
final IMARecordScope scope,
|
||||
final String id,
|
||||
final boolean sinceLastFullReport,
|
||||
final IMARecordField columnToOrder,
|
||||
final boolean ascending,
|
||||
final int firstResult,
|
||||
final int maxResults,
|
||||
final String search)
|
||||
throws ReportManagerException {
|
||||
|
||||
// check columnToOrder
|
||||
if (columnToOrder == null) {
|
||||
final String msg = "columnToOrder cannot be null";
|
||||
LOGGER.error(msg);
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
// check scope
|
||||
if (scope == null) {
|
||||
throw new IllegalArgumentException("IMARecordScope cannot be null");
|
||||
}
|
||||
|
||||
Transaction tx = null;
|
||||
Session session = getFactory().getCurrentSession();
|
||||
try {
|
||||
tx = session.beginTransaction();
|
||||
|
||||
final DbImaRecordQueryParameters params
|
||||
= new DbImaRecordQueryParameters(id, columnToOrder, ascending,
|
||||
firstResult, maxResults, search);
|
||||
|
||||
switch (scope) {
|
||||
case NONE:
|
||||
return new DbImaRecordQueryForNone().query();
|
||||
case REPORT:
|
||||
return new DbImaRecordQueryForReport(session, params).query();
|
||||
case DEVICE:
|
||||
if (sinceLastFullReport) {
|
||||
DbImaRecordQueryForDeviceSinceLastFullReport q
|
||||
= new DbImaRecordQueryForDeviceSinceLastFullReport(session, params);
|
||||
return q.query();
|
||||
} else {
|
||||
return new DbImaRecordQueryForDevice(session, params).query();
|
||||
}
|
||||
default:
|
||||
throw new UnsupportedOperationException(
|
||||
"IMARecordScope " + scope + " is not supported");
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
String msg = "Error executing IMA Record query for " + scope + " scope.";
|
||||
if (scope == IMARecordScope.DEVICE) {
|
||||
msg += "Since last full report = " + sinceLastFullReport;
|
||||
}
|
||||
LOGGER.error(msg, ex);
|
||||
throw ex;
|
||||
} finally {
|
||||
if (tx != null) {
|
||||
tx.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Report</code> from the database. This searches the
|
||||
* database for an entry whose id matches <code>id</code>. It then
|
||||
@ -330,52 +164,6 @@ public class DBReportManager extends DBManager<Report> implements ReportManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method retrieves all ima report ids associated with the latest full ima
|
||||
* report (as determined by a starting index of 0 and the most recent
|
||||
* report create time) of provided device id.
|
||||
* @param id of device
|
||||
* @return list of IMA report ids
|
||||
*/
|
||||
private List<UUID> getImaIdsOfRecentBootCycle(final String id) {
|
||||
|
||||
ReportSummaryManager reportSummaryManager =
|
||||
new DBReportSummaryManager(getFactory());
|
||||
List<ReportSummary> reportSummary = reportSummaryManager
|
||||
.getReportSummaryListByHostname(id);
|
||||
|
||||
List<IMAReport> imaReports = new ArrayList<>();
|
||||
for (ReportSummary summary : reportSummary) {
|
||||
IntegrityReport integrityReport = (IntegrityReport) summary
|
||||
.getReport();
|
||||
imaReports.add(integrityReport.extractReport(IMAReport.class));
|
||||
}
|
||||
|
||||
String bootCycleId = "";
|
||||
Date createTime = null;
|
||||
List<UUID> imaReportIds = new ArrayList<>();
|
||||
|
||||
// Retrieve most recent IMAReport where index is 0.
|
||||
for (IMAReport report : imaReports) {
|
||||
if (createTime == null) {
|
||||
createTime = report.getCreateTime();
|
||||
bootCycleId = report.getBootcycleId();
|
||||
} else if (createTime.before(report.getCreateTime())
|
||||
&& report.getIndex() == 0) {
|
||||
createTime = report.getCreateTime();
|
||||
bootCycleId = report.getBootcycleId();
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve all IMAReports corresponding to bootCycleID.
|
||||
for (IMAReport report : imaReports) {
|
||||
if (report.getBootcycleId().equals(bootCycleId)) {
|
||||
imaReportIds.add(report.getId());
|
||||
}
|
||||
}
|
||||
return imaReportIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method retrieves all ima report ids corresponding to provided
|
||||
* device id.
|
||||
@ -391,12 +179,7 @@ public class DBReportManager extends DBManager<Report> implements ReportManager
|
||||
.getReportSummaryListByHostname(id);
|
||||
|
||||
List<UUID> imaReportIds = new ArrayList<>();
|
||||
for (ReportSummary summary : reportSummary) {
|
||||
IntegrityReport integrityReport = (IntegrityReport) summary
|
||||
.getReport();
|
||||
imaReportIds.add(integrityReport.extractReport(IMAReport.class)
|
||||
.getId());
|
||||
}
|
||||
|
||||
return imaReportIds;
|
||||
}
|
||||
|
||||
|
@ -1,211 +0,0 @@
|
||||
package hirs.persist;
|
||||
|
||||
import hirs.data.persist.baseline.Baseline;
|
||||
import hirs.data.persist.DeviceInfoReport;
|
||||
import hirs.data.persist.IMAReport;
|
||||
import hirs.data.persist.IntegrityReport;
|
||||
import hirs.data.persist.TPMReport;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.OptionGroup;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
|
||||
import hirs.ima.SimpleImaBaselineGenerator;
|
||||
import hirs.ima.IMABaselineGeneratorException;
|
||||
import hirs.tpm.TPMBaselineGenerator;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
/**
|
||||
* This class is a command-line interface (CLI) for importing baselines into a
|
||||
* database. This takes a file and stores it in a <code>BaselineManager</code>.
|
||||
*/
|
||||
public final class ImportCLI {
|
||||
private static final Logger LOGGER = LogManager.getLogger(ImportCLI.class);
|
||||
private static final String HELP = "help";
|
||||
private static final String TPM = "tpm";
|
||||
private static final String IMA = "ima";
|
||||
private static final String CSV = "csv";
|
||||
private static final String XML = "xml";
|
||||
|
||||
private static BaselineManager baselineManager;
|
||||
|
||||
/**
|
||||
* Default constructor that is private to prevent this class from being
|
||||
* initialized.
|
||||
*/
|
||||
private ImportCLI() {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a new baseline.
|
||||
*
|
||||
* @param args command-line arguments
|
||||
*/
|
||||
public static void main(final String[] args) {
|
||||
LOGGER.debug("import cli started");
|
||||
loadBeansFromSpringContext();
|
||||
|
||||
final int fileIndex = 0;
|
||||
final int nameIndex = 1;
|
||||
final Options options = getOptions();
|
||||
final CommandLineParser parser = new DefaultParser();
|
||||
InputStream istream = null;
|
||||
try {
|
||||
final CommandLine line = parser.parse(options, args);
|
||||
if (line.hasOption("help")) {
|
||||
printHelp(options);
|
||||
return;
|
||||
}
|
||||
|
||||
final String[] extraArgs = line.getArgs();
|
||||
if (extraArgs.length != 2) {
|
||||
LOGGER.error("file and baseline name not given");
|
||||
printHelp(options);
|
||||
return;
|
||||
}
|
||||
LOGGER.debug("importing file: {}", extraArgs[fileIndex]);
|
||||
istream = new FileInputStream(new File(extraArgs[fileIndex]));
|
||||
final String name = extraArgs[nameIndex];
|
||||
|
||||
Baseline baseline = null;
|
||||
if (line.hasOption("tpm")) {
|
||||
LOGGER.debug("specified TPM import");
|
||||
final TPMBaselineGenerator generator = new TPMBaselineGenerator();
|
||||
if (line.hasOption("csv")) {
|
||||
LOGGER.debug("importing csv file");
|
||||
baseline = generator.generateWhiteListBaselineFromCSVFile(name, istream);
|
||||
} else {
|
||||
LOGGER.debug("importing TPM baseline from intgerity report xml file");
|
||||
IntegrityReport report;
|
||||
report = getIntegrityReportFromXmlFile(istream);
|
||||
if (report != null) {
|
||||
baseline = generator.generateBaselineFromIntegrityReport(name, report);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (line.hasOption("ima")) {
|
||||
LOGGER.debug("specified IMA import");
|
||||
final SimpleImaBaselineGenerator generator = new SimpleImaBaselineGenerator();
|
||||
if (line.hasOption("csv")) {
|
||||
LOGGER.debug("importing csv file");
|
||||
baseline = generator.generateBaselineFromCSVFile(name, istream);
|
||||
} else {
|
||||
LOGGER.debug("importing IMA baseline from intgerity report xml file");
|
||||
IntegrityReport report;
|
||||
report = getIntegrityReportFromXmlFile(istream);
|
||||
try {
|
||||
if (report != null) {
|
||||
generator.generateBaselineFromIntegrityReport(name, report);
|
||||
} else {
|
||||
LOGGER.error("could not create integrity report from xml file");
|
||||
return;
|
||||
}
|
||||
} catch (IMABaselineGeneratorException | NullPointerException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
saveBaseline(baseline);
|
||||
|
||||
} catch (ParseException e) {
|
||||
if (options.hasOption(HELP)) {
|
||||
printHelp(options);
|
||||
} else {
|
||||
LOGGER.error("error parsing options");
|
||||
LOGGER.error(e.getMessage());
|
||||
printHelp(options);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("unable to generate baseline", e);
|
||||
} finally {
|
||||
try {
|
||||
if (istream != null) {
|
||||
istream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("unexpected error closing istream", e);
|
||||
}
|
||||
LOGGER.debug("shutdown session factory");
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadBeansFromSpringContext() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(PersistenceConfiguration.class);
|
||||
context.refresh();
|
||||
|
||||
// register a shutdown hook such that components are properly shutdown when JVM is closing
|
||||
context.registerShutdownHook();
|
||||
|
||||
baselineManager = context.getBean(BaselineManager.class);
|
||||
}
|
||||
|
||||
private static void printHelp(final Options options) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("import-cli {--tpm | --ima} {--csv | --xml} file name", options);
|
||||
}
|
||||
|
||||
private static Options getOptions() {
|
||||
final Option help = new Option("h", HELP, false, "print this help menu");
|
||||
|
||||
final OptionGroup typeGroup = new OptionGroup();
|
||||
typeGroup.setRequired(true);
|
||||
final Option tpm = new Option("t", TPM, false, "add TPM baseline");
|
||||
final Option ima = new Option("i", IMA, false, "add IMA baseline");
|
||||
typeGroup.addOption(tpm);
|
||||
typeGroup.addOption(ima);
|
||||
|
||||
final OptionGroup formatGroup = new OptionGroup();
|
||||
formatGroup.setRequired(true);
|
||||
final Option csv = new Option("c", CSV, false, "CSV file format");
|
||||
final Option xml = new Option("x", XML, false, "XML report file format");
|
||||
formatGroup.addOption(csv);
|
||||
formatGroup.addOption(xml);
|
||||
|
||||
final Options options = new Options();
|
||||
options.addOption(help);
|
||||
options.addOptionGroup(typeGroup);
|
||||
options.addOptionGroup(formatGroup);
|
||||
return options;
|
||||
}
|
||||
|
||||
private static void saveBaseline(final Baseline baseline)
|
||||
throws BaselineManagerException {
|
||||
if (baseline == null) {
|
||||
LOGGER.info("baseline is null");
|
||||
return;
|
||||
}
|
||||
LOGGER.debug("saving baseline");
|
||||
baselineManager.saveBaseline(baseline);
|
||||
}
|
||||
|
||||
private static IntegrityReport getIntegrityReportFromXmlFile(final InputStream istream) {
|
||||
try {
|
||||
JAXBContext context = JAXBContext.newInstance(IntegrityReport.class,
|
||||
DeviceInfoReport.class, TPMReport.class,
|
||||
IMAReport.class);
|
||||
Unmarshaller unmarshaller = context.createUnmarshaller();
|
||||
return (IntegrityReport) unmarshaller.unmarshal(istream);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("error occurred while unmarshalling Integrity report", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,8 @@
|
||||
package hirs.persist;
|
||||
|
||||
import hirs.FilteredRecordsList;
|
||||
import hirs.data.bean.SimpleImaRecordBean;
|
||||
import hirs.data.persist.IMAMeasurementRecord;
|
||||
import hirs.data.persist.Report;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@ -45,71 +41,6 @@ public interface ReportManager {
|
||||
List<Report> getReportList(Class<? extends Report> clazz)
|
||||
throws ReportManagerException;
|
||||
|
||||
/**
|
||||
* Returns a list of all Report Records that are ordered by a column
|
||||
* and direction (ASC, DESC) that is provided by the user. This
|
||||
* method contains database interactions designed to extract specific
|
||||
* fields from the database to avoid retrieving full records in order
|
||||
* to improve query performance and reduce the size of teh data set
|
||||
* returned to the caller. This method helps support the server-side
|
||||
* processing in the JQuery DataTables.
|
||||
*
|
||||
* @param scope the scope of the search: NONE, ALL, REPORT, or DEVICE
|
||||
* @param id the id or name of the REPORT or DEVICE to search
|
||||
* @param sinceLastFullReport
|
||||
* limits the records to those since the last full report for the device
|
||||
* @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
|
||||
* @param searchableColumns map containing columns that search string can
|
||||
* be applied to
|
||||
* @return FilteredRecordsList object with fields for DataTables
|
||||
* @throws ReportManagerException if unable to create the list
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:parameternumber")
|
||||
FilteredRecordsList<SimpleImaRecordBean> getOrderedRecordListWithoutRecords(
|
||||
IMARecordScope scope,
|
||||
String id,
|
||||
boolean sinceLastFullReport,
|
||||
IMARecordField columnToOrder,
|
||||
boolean ascending,
|
||||
int firstResult,
|
||||
int maxResults,
|
||||
String search,
|
||||
Map<String, Boolean> searchableColumns)
|
||||
throws ReportManagerException;
|
||||
|
||||
/**
|
||||
* Returns a list of all Report Records 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 scope the scope of the search: NONE, ALL, REPORT, or DEVICE
|
||||
* @param id the id or name of the REPORT or DEVICE to search
|
||||
* @param sinceLastFullReport
|
||||
* limits the records to those since the last full report for the device
|
||||
* @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
|
||||
* @throws ReportManagerException if unable to create the list
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:parameternumber")
|
||||
FilteredRecordsList<IMAMeasurementRecord> getOrderedRecordList(
|
||||
IMARecordScope scope,
|
||||
String id,
|
||||
boolean sinceLastFullReport,
|
||||
IMARecordField columnToOrder,
|
||||
boolean ascending,
|
||||
int firstResult,
|
||||
int maxResults,
|
||||
String search)
|
||||
throws ReportManagerException;
|
||||
|
||||
/**
|
||||
* Retrieves the <code>Report</code> identified by <code>id</code>.
|
||||
*
|
||||
|
@ -1,12 +1,18 @@
|
||||
package hirs.repository;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.data.persist.baseline.IMABaselineRecord;
|
||||
import hirs.repository.measurement.PackageMeasurer;
|
||||
import hirs.repository.measurement.RPMMeasurer;
|
||||
import hirs.utils.exec.ExecBuilder;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileSystems;
|
||||
@ -17,17 +23,6 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
/**
|
||||
* Abstract base class representing a repository that deals with RPM packages.
|
||||
*
|
||||
@ -124,12 +119,10 @@ public abstract class RPMRepository<T extends RPMRepoPackage> extends Repository
|
||||
throws RepositoryException {
|
||||
try {
|
||||
Multimap<Path, Digest> measurements = rpmMeasurer.measure(rpmPath);
|
||||
Set<IMABaselineRecord> packageRecords = new HashSet<>();
|
||||
Set<Object> packageRecords = new HashSet<>();
|
||||
for (Map.Entry<Path, Collection<Digest>> e : measurements.asMap().entrySet()) {
|
||||
for (Digest digest : e.getValue()) {
|
||||
packageRecords.add(new IMABaselineRecord(
|
||||
e.getKey().toAbsolutePath().toString(), digest
|
||||
));
|
||||
packageRecords.add(digest);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,8 @@ package hirs.repository.measurement;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.data.persist.baseline.IMABaselineRecord;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -20,12 +17,8 @@ import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This abstract class implements the basic functionality for measuring a software package. It
|
||||
@ -216,22 +209,4 @@ public abstract class PackageMeasurer {
|
||||
|
||||
return new Digest(digestAlgorithm, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures the files at the specified file path.
|
||||
* @param filePath the file path root to measure files
|
||||
* @return set of IMA Baseline Records
|
||||
* @throws IOException if an IO error occurrs processing files at the file path
|
||||
*/
|
||||
public Set<IMABaselineRecord> measureAndGetRecords(final Path filePath) throws IOException {
|
||||
Set<IMABaselineRecord> records = new HashSet<>();
|
||||
Multimap<Path, Digest> map = measure(filePath);
|
||||
|
||||
for (Map.Entry<Path, Collection<Digest>> e : map.asMap().entrySet()) {
|
||||
for (Digest digest : e.getValue()) {
|
||||
records.add(new IMABaselineRecord(e.getKey().toString(), digest));
|
||||
}
|
||||
}
|
||||
return records;
|
||||
}
|
||||
}
|
||||
|
@ -1,671 +0,0 @@
|
||||
package hirs.tpm;
|
||||
|
||||
import hirs.data.persist.DeviceInfoReport;
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.data.persist.info.FirmwareInfo;
|
||||
import hirs.data.persist.info.HardwareInfo;
|
||||
import hirs.data.persist.IntegrityReport;
|
||||
import hirs.data.persist.info.OSInfo;
|
||||
import hirs.data.persist.Report;
|
||||
import hirs.data.persist.baseline.TPMBaseline;
|
||||
import hirs.data.persist.info.TPMInfo;
|
||||
import hirs.data.persist.TPMMeasurementRecord;
|
||||
import hirs.data.persist.TPMReport;
|
||||
import hirs.data.persist.baseline.TpmBlackListBaseline;
|
||||
import hirs.data.persist.baseline.TpmWhiteListBaseline;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Class used to process comma separated value files containing TPM PCR
|
||||
* measurements or HIRS integrity reports to generate a TPM measurement
|
||||
* baseline. Generating a TPM measurement baseline from a HIRS integrity report
|
||||
* is considered experimental and provided as a tool to assist with creating,
|
||||
* analyzing, and refining measurement baselines.
|
||||
*/
|
||||
public class TPMBaselineGenerator {
|
||||
|
||||
private static final Logger LOGGER
|
||||
= LogManager.getLogger(TPMBaselineGenerator.class);
|
||||
|
||||
private static final String KERNEL_UPDATE_BASELINE_NAME = "Kernel Update %s %s";
|
||||
private static final String VALID_REGEX = "[0-9a-zA-Z./()_,\" -]+";
|
||||
|
||||
|
||||
/**
|
||||
* Enumerates the device info fields looked for within a TPMBaseline CSV file.
|
||||
*/
|
||||
public enum TPMBaselineFields {
|
||||
/**
|
||||
* FirmwareInfo's BIOS Vendor.
|
||||
*/
|
||||
BIOS_VENDOR,
|
||||
|
||||
/**
|
||||
* FirmwareInfo's BIOS Version.
|
||||
*/
|
||||
BIOS_VERSION,
|
||||
|
||||
/**
|
||||
* FirmwareInfo's BIOS Release Date.
|
||||
*/
|
||||
BIOS_RELEASE_DATE,
|
||||
|
||||
/**
|
||||
* HardwareInfo's Manufacturer.
|
||||
*/
|
||||
MANUFACTURER,
|
||||
|
||||
/**
|
||||
* HardwareInfo's Product Name.
|
||||
*/
|
||||
PRODUCT_NAME,
|
||||
|
||||
/**
|
||||
* HardwareInfo's Version.
|
||||
*/
|
||||
VERSION,
|
||||
|
||||
/**
|
||||
* HardwareInfo's Serial number.
|
||||
*/
|
||||
SYSTEM_SERIAL_NUMBER,
|
||||
|
||||
/**
|
||||
* HardwareInfo's Chassis serial number.
|
||||
*/
|
||||
CHASSIS_SERIAL_NUMBER,
|
||||
|
||||
/**
|
||||
* HardwareInfo's baseboard serial number.
|
||||
*/
|
||||
BASEBOARD_SERIAL_NUMBER,
|
||||
|
||||
/**
|
||||
* OSInfo's OS Name.
|
||||
*/
|
||||
OS_NAME,
|
||||
|
||||
/**
|
||||
* OSInfo's OS Version.
|
||||
*/
|
||||
OS_VERSION,
|
||||
|
||||
/**
|
||||
* OSInfo's OS Arch.
|
||||
*/
|
||||
OS_ARCH,
|
||||
|
||||
/**
|
||||
* OSInfo's Distribution.
|
||||
*/
|
||||
DISTRIBUTION,
|
||||
|
||||
/**
|
||||
* OSInfo's Distribution Release.
|
||||
*/
|
||||
DISTRIBUTION_RELEASE,
|
||||
|
||||
/**
|
||||
* TPMInfo's TPM Make.
|
||||
*/
|
||||
TPM_MAKE,
|
||||
|
||||
/**
|
||||
* TPMInfo's TPM Version Major.
|
||||
*/
|
||||
TPM_VERSION_MAJOR,
|
||||
|
||||
/**
|
||||
* TPMInfo's TPM Version Minor.
|
||||
*/
|
||||
TPM_VERSION_MINOR,
|
||||
|
||||
/**
|
||||
* TPMInfo's TPM Version Rev Major.
|
||||
*/
|
||||
TPM_VERSION_REV_MAJOR,
|
||||
|
||||
/**
|
||||
* TPMInfo's TPM Version Rev Minor.
|
||||
*/
|
||||
TPM_VERSION_REV_MINOR;
|
||||
|
||||
/**
|
||||
* Generates a CSV String from a map of TPMBaselineFields to values.
|
||||
* @param map Map<TPMBaselineFields, String>
|
||||
* @return CSV-escaped String corresponding to the map of values
|
||||
*/
|
||||
public static String toCSV(final Map<TPMBaselineFields, String> map) {
|
||||
if (map == null) {
|
||||
throw new IllegalArgumentException("TPMBaselineFields.toCSV:"
|
||||
+ " This method should not have been called with a null parameter.");
|
||||
}
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (final Entry<TPMBaselineFields, String> field : map.entrySet()) {
|
||||
builder.append(field.getKey().name())
|
||||
.append(",")
|
||||
.append(StringEscapeUtils.escapeCsv(field.getValue()))
|
||||
.append(System.lineSeparator());
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FirmwareInfo object from the supplied data field changes. Any
|
||||
* fields not supplied will retain their existing values from the given default
|
||||
* FirmwareInfo object.
|
||||
* @param map Map<TPMBaselineFields, String> correlating field keys to values.
|
||||
* @param defaultInfo the FirmwareInfo object to reference for default values.
|
||||
* @return new FirmwareInfo object with updated fields.
|
||||
*/
|
||||
private static FirmwareInfo toFirmwareInfo(final Map<TPMBaselineFields, String> map,
|
||||
final FirmwareInfo defaultInfo) {
|
||||
if (map == null || defaultInfo == null) {
|
||||
throw new IllegalArgumentException("TPMBaselineFields.toFirmwareInfo:"
|
||||
+ " This method should not have been called with a null parameter.");
|
||||
}
|
||||
|
||||
final String biosVendor =
|
||||
StringUtils.defaultIfBlank(
|
||||
map.get(TPMBaselineFields.BIOS_VENDOR), defaultInfo.getBiosVendor());
|
||||
|
||||
final String biosVersion =
|
||||
StringUtils.defaultIfBlank(
|
||||
map.get(TPMBaselineFields.BIOS_VERSION), defaultInfo.getBiosVersion());
|
||||
|
||||
final String biosReleaseDate =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.BIOS_RELEASE_DATE),
|
||||
defaultInfo.getBiosReleaseDate());
|
||||
|
||||
return new FirmwareInfo(biosVendor, biosVersion, biosReleaseDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new HardwareInfo object from the supplied data field changes. Any
|
||||
* fields not supplied will retain their existing values from the given default
|
||||
* HardwareInfo object.
|
||||
* @param map Map<TPMBaselineFields, String> correlating field keys to values.
|
||||
* @param defaultInfo the HardwareInfo object to reference for default values.
|
||||
* @return new HardwareInfo object with updated fields.
|
||||
*/
|
||||
private static HardwareInfo toHardwareInfo(final Map<TPMBaselineFields, String> map,
|
||||
final HardwareInfo defaultInfo) {
|
||||
if (map == null || defaultInfo == null) {
|
||||
throw new IllegalArgumentException("TPMBaselineFields.toHardwareInfo:"
|
||||
+ " This method should not have been called with a null parameter.");
|
||||
}
|
||||
|
||||
final String manufacturer =
|
||||
StringUtils.defaultIfBlank(
|
||||
map.get(TPMBaselineFields.MANUFACTURER), defaultInfo.getManufacturer());
|
||||
|
||||
final String productName =
|
||||
StringUtils.defaultIfBlank(
|
||||
map.get(TPMBaselineFields.PRODUCT_NAME), defaultInfo.getProductName());
|
||||
|
||||
final String version =
|
||||
StringUtils.defaultIfBlank(
|
||||
map.get(TPMBaselineFields.VERSION), defaultInfo.getVersion());
|
||||
|
||||
final String serialNumber =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.SYSTEM_SERIAL_NUMBER),
|
||||
defaultInfo.getSystemSerialNumber());
|
||||
|
||||
final String chassisSerialNumber =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.CHASSIS_SERIAL_NUMBER),
|
||||
defaultInfo.getChassisSerialNumber());
|
||||
|
||||
final String baseboardSerialNumber =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.BASEBOARD_SERIAL_NUMBER),
|
||||
defaultInfo.getBaseboardSerialNumber());
|
||||
|
||||
return new HardwareInfo(
|
||||
manufacturer,
|
||||
productName,
|
||||
version,
|
||||
serialNumber,
|
||||
chassisSerialNumber,
|
||||
baseboardSerialNumber
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new OSInfo object from the supplied data field changes. Any
|
||||
* fields not supplied will retain their existing values from the given default
|
||||
* OSInfo object.
|
||||
* @param map Map<TPMBaselineFields, String> correlating field keys to values.
|
||||
* @param defaultInfo the HardwareInfo object to reference for default values.
|
||||
* @return new OSInfo object with updated fields.
|
||||
*/
|
||||
private static OSInfo toOSInfo(final Map<TPMBaselineFields, String> map,
|
||||
final OSInfo defaultInfo) {
|
||||
if (map == null || defaultInfo == null) {
|
||||
throw new IllegalArgumentException("TPMBaselineFields.toOSInfo:"
|
||||
+ " This method should not have been called with a null parameter.");
|
||||
}
|
||||
|
||||
final String osName =
|
||||
StringUtils.defaultIfBlank(
|
||||
map.get(TPMBaselineFields.OS_NAME), defaultInfo.getOSName());
|
||||
|
||||
final String osVersion =
|
||||
StringUtils.defaultIfBlank(
|
||||
map.get(TPMBaselineFields.OS_VERSION), defaultInfo.getOSVersion());
|
||||
|
||||
final String osArch =
|
||||
StringUtils.defaultIfBlank(
|
||||
map.get(TPMBaselineFields.OS_ARCH), defaultInfo.getOSArch());
|
||||
|
||||
final String distribution =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.DISTRIBUTION),
|
||||
defaultInfo.getDistribution());
|
||||
|
||||
final String distributionRelease =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.DISTRIBUTION_RELEASE),
|
||||
defaultInfo.getDistributionRelease());
|
||||
|
||||
return new OSInfo(osName, osVersion, osArch, distribution, distributionRelease);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TPMInfo object from the supplied data field changes. Any
|
||||
* fields not supplied will retain their existing values from the given default
|
||||
* TPMInfo object.
|
||||
* @param map Map<TPMBaselineFields, String> correlating field keys to values.
|
||||
* @param defaultInfo the HardwareInfo object to reference for default values.
|
||||
* @return new TPMInfo object with updated fields.
|
||||
*/
|
||||
private static TPMInfo toTPMInfo(final Map<TPMBaselineFields, String> map,
|
||||
final TPMInfo defaultInfo) {
|
||||
if (map == null || defaultInfo == null) {
|
||||
throw new IllegalArgumentException("TPMBaselineFields.toTPMInfo:"
|
||||
+ " This method should not have been called with a null parameter.");
|
||||
}
|
||||
|
||||
final String tpmMake =
|
||||
StringUtils.defaultIfBlank(
|
||||
map.get(TPMBaselineFields.TPM_MAKE), defaultInfo.getTPMMake());
|
||||
|
||||
final String tpmVersionMajor =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.TPM_VERSION_MAJOR),
|
||||
"" + defaultInfo.getTPMVersionMajor());
|
||||
|
||||
final String tpmVersionMinor =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.TPM_VERSION_MINOR),
|
||||
"" + defaultInfo.getTPMVersionMinor());
|
||||
|
||||
final String tpmVersionRevMajor =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.TPM_VERSION_REV_MAJOR),
|
||||
"" + defaultInfo.getTPMVersionRevMajor());
|
||||
|
||||
final String tpmVersionRevMinor =
|
||||
StringUtils.defaultIfBlank(map.get(TPMBaselineFields.TPM_VERSION_REV_MINOR),
|
||||
"" + defaultInfo.getTPMVersionMinor());
|
||||
|
||||
return new TPMInfo(tpmMake, Short.valueOf(tpmVersionMajor),
|
||||
Short.valueOf(tpmVersionMinor), Short.valueOf(tpmVersionRevMajor),
|
||||
Short.valueOf(tpmVersionRevMinor));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method generates a TPM measurement white list baseline from a .csv file containing
|
||||
* PCR measurement entries. An off-line PCR measurement baseline process is
|
||||
* used to generate the .csv file. TPM measurement records are expected to
|
||||
* adhere to the following record structure with a comma separating them:
|
||||
* <ul>
|
||||
* <li>PCR index</li>
|
||||
* <li>SHA-1 hash</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param baselineName
|
||||
* of baseline to generate
|
||||
* @param in
|
||||
* is input stream containing PCR measurement entries
|
||||
* @return tpm baseline
|
||||
* @throws IOException
|
||||
* if error encountered reading data from input stream
|
||||
* @throws ParseException
|
||||
* if error encountered parsing data
|
||||
* @throws TPMBaselineGeneratorException
|
||||
* if error encountered when retrieving measurement entries from
|
||||
* input stream
|
||||
*/
|
||||
public final TpmWhiteListBaseline generateWhiteListBaselineFromCSVFile(
|
||||
final String baselineName, final InputStream in)
|
||||
throws IOException, ParseException, TPMBaselineGeneratorException {
|
||||
checkBaselineCreationArgs(baselineName, in);
|
||||
|
||||
TpmWhiteListBaseline tpmBaseline = parseWhiteListCsvFile(baselineName, in);
|
||||
LOGGER.debug("measurement baseline initialized: {}", tpmBaseline);
|
||||
return tpmBaseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method generates a TPM measurement black list baseline from a .csv file containing
|
||||
* PCR measurement entries. An off-line PCR measurement baseline process is
|
||||
* used to generate the .csv file. TPM measurement records are expected to
|
||||
* adhere to the following record structure with a comma separating them:
|
||||
* <ul>
|
||||
* <li>PCR index</li>
|
||||
* <li>SHA-1 hash</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param baselineName
|
||||
* of baseline to generate
|
||||
* @param in
|
||||
* is input stream containing PCR measurement entries
|
||||
* @return tpm baseline
|
||||
* @throws IOException
|
||||
* if error encountered reading data from input stream
|
||||
* @throws ParseException
|
||||
* if error encountered parsing data
|
||||
* @throws TPMBaselineGeneratorException
|
||||
* if error encountered when retrieving measurement entries from
|
||||
* input stream
|
||||
*/
|
||||
public TpmBlackListBaseline generateBlackListBaselineFromCSVFile(final String baselineName,
|
||||
final InputStream in) throws ParseException, TPMBaselineGeneratorException, IOException {
|
||||
checkBaselineCreationArgs(baselineName, in);
|
||||
|
||||
TpmBlackListBaseline tpmBaseline = parseBlackListCsvFile(baselineName, in);
|
||||
LOGGER.debug("measurement baseline initialized: {}", tpmBaseline);
|
||||
return tpmBaseline;
|
||||
}
|
||||
|
||||
private void checkBaselineCreationArgs(final String baselineName, final InputStream in) {
|
||||
if (baselineName == null) {
|
||||
LOGGER.error("null argument: baselineName");
|
||||
throw new NullPointerException("baselineName");
|
||||
}
|
||||
if (in == null) {
|
||||
LOGGER.error("null argument: in");
|
||||
throw new NullPointerException("in");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a TPM baseline from a <code>IntegrityReport</code>. This
|
||||
* extracts the PCR composite object from the report and verifies that valid
|
||||
* number of TPM PCRs are provided. The method creates a new
|
||||
* <code>TPMBaseline</code> object and then uses each PCR value obtained
|
||||
* from the PCR composite object to add it to the <code>TPMBaseline</code>
|
||||
* object.
|
||||
*
|
||||
* @param baselineName
|
||||
* name of baseline to be created
|
||||
* @param report
|
||||
* integrity report that containing PCR values for baseline
|
||||
* @return baseline that contains the PCR values from the report
|
||||
* @throws NullPointerException
|
||||
* if either baselineName or report parameters are null.
|
||||
*/
|
||||
public final TpmWhiteListBaseline generateBaselineFromIntegrityReport(
|
||||
final String baselineName, final IntegrityReport report)
|
||||
throws NullPointerException {
|
||||
|
||||
if (baselineName == null) {
|
||||
LOGGER.error("null argument: baselineName");
|
||||
throw new NullPointerException("baselineName");
|
||||
}
|
||||
if (report == null) {
|
||||
LOGGER.error("null argument: report");
|
||||
throw new NullPointerException("report");
|
||||
}
|
||||
|
||||
final TpmWhiteListBaseline baseline = new TpmWhiteListBaseline(baselineName);
|
||||
|
||||
LOGGER.debug("generating TPM baseline from report");
|
||||
|
||||
if (report.contains(TPMReport.class)) {
|
||||
final TPMReport tpmReport = report.extractReport(TPMReport.class);
|
||||
final List<TPMMeasurementRecord> pcrs = tpmReport.getTPMMeasurementRecords();
|
||||
for (TPMMeasurementRecord p : pcrs) {
|
||||
int id = p.getPcrId();
|
||||
final Digest sha1 = p.getHash();
|
||||
baseline.addToBaseline(new TPMMeasurementRecord(id, sha1));
|
||||
}
|
||||
} else {
|
||||
LOGGER.debug(String.format(
|
||||
"In generateBaselineFromIntegrityReport of %s, "
|
||||
+ "the IntegrityReport did not include a TPMReport",
|
||||
getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
LOGGER.debug("retrieving Device Info data from report");
|
||||
|
||||
if (report.contains(DeviceInfoReport.class)) {
|
||||
Report reportBuffer = report.extractReport(DeviceInfoReport.class);
|
||||
final DeviceInfoReport diReport = (DeviceInfoReport) reportBuffer;
|
||||
baseline.setFirmwareInfo(diReport.getFirmwareInfo());
|
||||
baseline.setHardwareInfo(diReport.getHardwareInfo());
|
||||
baseline.setOSInfo(diReport.getOSInfo());
|
||||
baseline.setTPMInfo(diReport.getTPMInfo());
|
||||
} else {
|
||||
LOGGER.debug(String.format(
|
||||
"In generateBaselineFromIntegrityReport of %s, "
|
||||
+ "the IntegrityReport did not include a DeviceInfoReport",
|
||||
getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
return baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a TPM whitelist baseline from a <code>IntegrityReport</code>. This
|
||||
* extracts the PCR composite object from the report and verifies that valid
|
||||
* number of TPM PCRs are provided. The method creates a new
|
||||
* <code>TPMBaseline</code> object and then uses each PCR value obtained
|
||||
* from the PCR composite object to add it to the <code>TPMBaseline</code>
|
||||
* object.
|
||||
* @param baselineName name of baseline to be created
|
||||
* @param report integrity report that containing PCR values for baseline
|
||||
* @param kernelPcrMask the kernel PCR mask from a TPM Policy
|
||||
* @return baseline that contains the PCR values from the report and the device info
|
||||
* @throws NullPointerException if either baselineName or report parameters are null.
|
||||
*/
|
||||
public final TpmWhiteListBaseline generateWhiteListBaselineOnKernelUpdate(
|
||||
final String baselineName, final IntegrityReport report, final int kernelPcrMask)
|
||||
throws NullPointerException {
|
||||
if (baselineName == null) {
|
||||
LOGGER.error("null argument: baselineName");
|
||||
throw new NullPointerException("baselineName");
|
||||
}
|
||||
|
||||
LOGGER.debug("generating TPM baseline on kernel update from report");
|
||||
|
||||
// Generate a temporary reference baseline from the given report. The name can be blank.
|
||||
final TpmWhiteListBaseline referenceBaseline =
|
||||
generateBaselineFromIntegrityReport("", report);
|
||||
final Set<TPMMeasurementRecord> records = referenceBaseline.getPcrRecords();
|
||||
|
||||
final TpmWhiteListBaseline newBaseline = new TpmWhiteListBaseline(baselineName);
|
||||
|
||||
// Copy each of the kernel PCR values from the reference baseline to the new one
|
||||
for (final TPMMeasurementRecord record : records) {
|
||||
final int shifted = 1 << record.getPcrId();
|
||||
if ((shifted & kernelPcrMask) == shifted) {
|
||||
newBaseline.addToBaseline(record);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.debug("retrieving Device Info data from referenced baseline");
|
||||
|
||||
// Copy the criteria from the device info report corroborated the kernel update.
|
||||
final OSInfo referenceOSInfo = referenceBaseline.getOSInfo();
|
||||
final HashMap<TPMBaselineFields, String> map = new HashMap<>();
|
||||
map.put(TPMBaselineFields.OS_NAME, referenceOSInfo.getOSName());
|
||||
map.put(TPMBaselineFields.OS_VERSION, referenceOSInfo.getOSVersion());
|
||||
final OSInfo osInfo = TPMBaselineFields.toOSInfo(map, new OSInfo());
|
||||
newBaseline.setOSInfo(osInfo);
|
||||
|
||||
return newBaseline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a standard name for baselines that are automatically created during a kernel
|
||||
* update event.
|
||||
* @param report IntegrityReport from which a kernel update was detected.
|
||||
* @return String of the name that can be used for a corresponding TPM baseline.
|
||||
* @throws NullPointerException If the parameter is null.
|
||||
* @throws TPMBaselineGeneratorException If the report doesn't contain a device info report.
|
||||
*/
|
||||
public final String generateNameForKernelUpdateBaseline(final IntegrityReport report)
|
||||
throws NullPointerException, TPMBaselineGeneratorException {
|
||||
LOGGER.debug("retrieving Device Info data to create kernel update baseline name");
|
||||
if (report == null) {
|
||||
LOGGER.error("null argument: report");
|
||||
throw new NullPointerException("report");
|
||||
}
|
||||
|
||||
if (report.contains(DeviceInfoReport.class)) {
|
||||
final DeviceInfoReport diReport = report.extractReport(DeviceInfoReport.class);
|
||||
|
||||
final OSInfo osInfo = diReport.getOSInfo();
|
||||
return String.format(KERNEL_UPDATE_BASELINE_NAME,
|
||||
osInfo.getOSName(), osInfo.getOSVersion());
|
||||
}
|
||||
|
||||
final String msg = "The integrity report did not contain a device info report."
|
||||
+ " Investigate how the appraiser got this far.";
|
||||
throw new TPMBaselineGeneratorException(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method parses a .csv file containing TPM measurement entries and
|
||||
* initializes and returns a new TPM baseline object.
|
||||
*
|
||||
* @param baselineName the name of the baseline.
|
||||
* @param inStream
|
||||
* containing file contents to be read. inStream is closed by
|
||||
* this method.
|
||||
* @return a TPM baseline initialized with measurement entries imported from
|
||||
* .csv TPM baseline file
|
||||
* @exception NullPointerException
|
||||
* if baselineName is a null value
|
||||
* @exception NullPointerException
|
||||
* if inStream is a null value
|
||||
* @throws IOException
|
||||
* if error encountered reading data from input stream
|
||||
* @throws ParseException
|
||||
* if error encountered parsing data
|
||||
* @throws TPMBaselineGeneratorException
|
||||
* if error encountered when retrieving measurement entries from
|
||||
* input stream
|
||||
*/
|
||||
private TpmWhiteListBaseline parseWhiteListCsvFile(final String baselineName,
|
||||
final InputStream inStream) throws IOException, ParseException,
|
||||
TPMBaselineGeneratorException {
|
||||
TpmWhiteListBaseline baseline = new TpmWhiteListBaseline(baselineName);
|
||||
|
||||
parseBaseline(baselineName, inStream, baseline);
|
||||
return baseline;
|
||||
}
|
||||
|
||||
private TpmBlackListBaseline parseBlackListCsvFile(final String baselineName,
|
||||
final InputStream inStream) throws IOException, ParseException,
|
||||
TPMBaselineGeneratorException {
|
||||
TpmBlackListBaseline baseline = new TpmBlackListBaseline(baselineName);
|
||||
|
||||
parseBaseline(baselineName, inStream, baseline);
|
||||
return baseline;
|
||||
}
|
||||
|
||||
private void parseBaseline(final String baselineName, final InputStream inStream,
|
||||
final TPMBaseline baseline)
|
||||
throws IOException, TPMBaselineGeneratorException {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
inStream, "UTF8"));
|
||||
String dataRow = reader.readLine();
|
||||
HashMap<TPMBaselineFields, String> fieldMap = new HashMap<>();
|
||||
|
||||
try {
|
||||
while (dataRow != null && dataRow.matches(VALID_REGEX)) {
|
||||
String[] dataArray = dataRow.split(",", 2); // looking for two values per row
|
||||
if (dataArray.length != 2) { // could be 1, if there were no commas
|
||||
final String msg = String.format(
|
||||
"invalid number of fields: %d", dataArray.length);
|
||||
LOGGER.error(msg);
|
||||
throw new TPMBaselineGeneratorException(msg);
|
||||
} else if (!dataArray[1].matches(VALID_REGEX)) {
|
||||
final String msg = String.format("One record contained invalid data"
|
||||
+ "while parsing a CSV file for TPM Baseline '%s'.", baselineName);
|
||||
LOGGER.error(msg);
|
||||
throw new TPMBaselineGeneratorException(msg);
|
||||
}
|
||||
|
||||
// Measurements will start with a number,
|
||||
// Device info records will start with the field name of the device info to set
|
||||
try {
|
||||
TPMBaselineFields field =
|
||||
TPMBaselineFields.valueOf(dataArray[0].toUpperCase());
|
||||
fieldMap.put(field, StringEscapeUtils.unescapeCsv(dataArray[1]));
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Wasn't in the list of fields, treat it as a measurement record
|
||||
int id = Integer.parseInt(dataArray[0]);
|
||||
final byte[] sha1Bytes
|
||||
= Hex.decodeHex(dataArray[1].toCharArray());
|
||||
final Digest sha1 = new Digest(DigestAlgorithm.SHA1, sha1Bytes);
|
||||
baseline.addToBaseline(new TPMMeasurementRecord(id, sha1));
|
||||
}
|
||||
|
||||
dataRow = reader.readLine();
|
||||
}
|
||||
|
||||
// Use the map to overwrite new device info data
|
||||
baseline.setFirmwareInfo(
|
||||
TPMBaselineFields.toFirmwareInfo(fieldMap, baseline.getFirmwareInfo()));
|
||||
baseline.setHardwareInfo(
|
||||
TPMBaselineFields.toHardwareInfo(fieldMap, baseline.getHardwareInfo()));
|
||||
baseline.setOSInfo(
|
||||
TPMBaselineFields.toOSInfo(fieldMap, baseline.getOSInfo()));
|
||||
baseline.setTPMInfo(
|
||||
TPMBaselineFields.toTPMInfo(fieldMap, baseline.getTPMInfo()));
|
||||
|
||||
if (baseline.isEmpty()) {
|
||||
throw new TPMBaselineGeneratorException("TPM baseline is empty!");
|
||||
}
|
||||
//Checks that PCR values are actual
|
||||
} catch (NumberFormatException nfe) {
|
||||
String recordInfo = "";
|
||||
if (dataRow != null) {
|
||||
recordInfo = " record: \"" + dataRow + "\"";
|
||||
}
|
||||
String msg = "TPMBaselineGenerator.parseWhiteListCsvFile: Error when attempting to "
|
||||
+ "parse a number in CSV file" + recordInfo + ".";
|
||||
LOGGER.error(msg + "\n" + nfe.getMessage());
|
||||
throw new TPMBaselineGeneratorException(msg);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
//Removes the Exception header to hide it from the user explanation
|
||||
LOGGER.error(iae.getMessage());
|
||||
String message = iae.getMessage().substring(
|
||||
iae.getMessage().indexOf(":") + 1);
|
||||
String error = "Baseline import failed due to "
|
||||
+ message.replaceAll("(.*):(.*)", "$1");
|
||||
throw new TPMBaselineGeneratorException(error);
|
||||
} catch (Exception ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
throw new TPMBaselineGeneratorException("Error when attempting to "
|
||||
+ "parse CSV file. Is file formatted correctly for a TPM"
|
||||
+ " Baseline?");
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package hirs.tpm;
|
||||
|
||||
/**
|
||||
* This class represents an <code>Exception</code> generated by
|
||||
* <code>CreateTPMBaseline</code>.
|
||||
*/
|
||||
public class TPMBaselineGeneratorException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 8850867303391694668L;
|
||||
|
||||
/**
|
||||
* Creates a new <code>CreateTPMBaselineException</code> that has the
|
||||
* message <code>msg</code>.
|
||||
*
|
||||
* @param msg
|
||||
* exception message
|
||||
*/
|
||||
TPMBaselineGeneratorException(final String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>CreateTPMBaselineException</code> that wraps the
|
||||
* given <code>Throwable</code>.
|
||||
*
|
||||
* @param t
|
||||
* root cause
|
||||
*/
|
||||
TPMBaselineGeneratorException(final Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>CreateTPMBaselineException</code> that has the
|
||||
* message <code>msg</code> and wraps the root cause.
|
||||
*
|
||||
* @param msg
|
||||
* exception message
|
||||
* @param t
|
||||
* root cause
|
||||
*/
|
||||
TPMBaselineGeneratorException(final String msg, final Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,17 @@
|
||||
package hirs.tpm.eventlog;
|
||||
|
||||
import hirs.data.persist.AbstractDigest;
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.TPMMeasurementRecord;
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.tpm.eventlog.events.EvConstants;
|
||||
import hirs.tpm.eventlog.uefi.UefiConstants;
|
||||
import hirs.utils.HexUtils;
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
@ -10,20 +22,6 @@ import java.security.cert.CertificateException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
import hirs.data.persist.AbstractDigest;
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.TPMMeasurementRecord;
|
||||
import hirs.data.persist.baseline.TpmWhiteListBaseline;
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.tpm.eventlog.events.EvConstants;
|
||||
import hirs.tpm.eventlog.uefi.UefiConstants;
|
||||
import hirs.utils.HexUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Class for handling different formats of TCG Event logs.
|
||||
*/
|
||||
@ -178,8 +176,8 @@ public final class TCGEventLog {
|
||||
* @param name name to call the TPM Baseline
|
||||
* @return whitelist baseline
|
||||
*/
|
||||
public TpmWhiteListBaseline createTPMBaseline(final String name) {
|
||||
TpmWhiteListBaseline baseline = new TpmWhiteListBaseline(name);
|
||||
public void createTPMBaseline(final String name) {
|
||||
// TpmWhiteListBaseline baseline = new TpmWhiteListBaseline(name);
|
||||
TPMMeasurementRecord record;
|
||||
String pcrValue;
|
||||
for (int i = 0; i < PCR_COUNT; i++) {
|
||||
@ -194,9 +192,9 @@ public final class TCGEventLog {
|
||||
final Digest hash = new Digest(DigestAlgorithm.SHA256, hexValue);
|
||||
record = new TPMMeasurementRecord(i, hash);
|
||||
}
|
||||
baseline.addToBaseline(record);
|
||||
// baseline.addToBaseline(record);
|
||||
}
|
||||
return baseline;
|
||||
// return baseline;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,5 @@
|
||||
package hirs;
|
||||
|
||||
import hirs.data.persist.IMAReport;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -3,8 +3,6 @@ package hirs.appraiser;
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.data.persist.baseline.IMABaselineRecord;
|
||||
import hirs.data.persist.IMAMeasurementRecord;
|
||||
import hirs.data.persist.IMAReport;
|
||||
import hirs.data.persist.baseline.ImaIgnoreSetBaseline;
|
||||
import hirs.data.persist.baseline.SimpleImaBaseline;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
@ -13,7 +13,6 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.HashSet;
|
||||
|
||||
import hirs.tpm.TPMBaselineGenerator;
|
||||
import org.hibernate.Session;
|
||||
import org.testng.Assert;
|
||||
|
||||
|
@ -2,7 +2,6 @@ package hirs.ima;
|
||||
|
||||
import hirs.data.persist.DeviceInfoReport;
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.ImaBlacklistRecord;
|
||||
import hirs.data.persist.ImaBlacklistRecordTest;
|
||||
import hirs.data.persist.TPMMeasurementRecord;
|
||||
import hirs.data.persist.baseline.IMABaselineRecord;
|
||||
@ -14,8 +13,6 @@ import hirs.data.persist.info.FirmwareInfo;
|
||||
import hirs.data.persist.info.HardwareInfo;
|
||||
import hirs.data.persist.info.OSInfo;
|
||||
import hirs.data.persist.info.TPMInfo;
|
||||
import hirs.tpm.TPMBaselineGenerator;
|
||||
import hirs.tpm.TPMBaselineGeneratorException;
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -6,7 +6,6 @@ import org.testng.annotations.Test;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import hirs.data.persist.baseline.ImaBlacklistBaseline;
|
||||
import hirs.data.persist.ImaBlacklistRecord;
|
||||
|
||||
/**
|
||||
* Tests that the {@link ImaBlacklistBaselineGenerator} works as expected.
|
||||
|
@ -1,6 +1,5 @@
|
||||
package hirs.ima;
|
||||
|
||||
import hirs.data.persist.IMAReport;
|
||||
import hirs.data.persist.baseline.SimpleImaBaseline;
|
||||
import hirs.data.persist.DeviceInfoReport;
|
||||
import hirs.data.persist.Digest;
|
||||
|
@ -2,7 +2,6 @@ package hirs.ima.matching;
|
||||
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.baseline.IMABaselineRecord;
|
||||
import hirs.data.persist.IMAMeasurementRecord;
|
||||
import hirs.data.persist.enums.ReportMatchStatus;
|
||||
import hirs.data.persist.baseline.SimpleImaBaseline;
|
||||
import hirs.data.persist.SimpleImaBaselineTest;
|
||||
|
@ -3,7 +3,6 @@ package hirs.ima.matching;
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.DigestTest;
|
||||
import hirs.data.persist.baseline.IMABaselineRecord;
|
||||
import hirs.data.persist.IMAMeasurementRecord;
|
||||
import hirs.data.persist.baseline.ImaAcceptableRecordBaseline;
|
||||
import hirs.data.persist.enums.ReportMatchStatus;
|
||||
import hirs.data.persist.baseline.SimpleImaBaseline;
|
||||
|
@ -3,7 +3,6 @@ package hirs.persist;
|
||||
import hirs.data.persist.Device;
|
||||
import hirs.data.persist.DeviceGroup;
|
||||
import hirs.data.persist.DeviceState;
|
||||
import hirs.data.persist.IMADeviceState;
|
||||
import hirs.data.persist.SpringPersistenceTest;
|
||||
import hirs.data.persist.TPMDeviceState;
|
||||
import hirs.data.persist.TPMReport;
|
||||
|
@ -2,7 +2,6 @@ package hirs.persist;
|
||||
|
||||
import hirs.data.persist.Device;
|
||||
import hirs.data.persist.DeviceGroup;
|
||||
import hirs.data.persist.IMADeviceState;
|
||||
|
||||
import hirs.data.persist.SpringPersistenceTest;
|
||||
import org.testng.Assert;
|
||||
|
@ -8,8 +8,6 @@ import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.data.persist.enums.ExamineState;
|
||||
import hirs.data.persist.info.FirmwareInfo;
|
||||
import hirs.data.persist.info.HardwareInfo;
|
||||
import hirs.data.persist.IMAMeasurementRecord;
|
||||
import hirs.data.persist.IMAReport;
|
||||
import hirs.data.persist.IntegrityReport;
|
||||
import hirs.data.persist.info.NetworkInfo;
|
||||
import hirs.data.persist.info.OSInfo;
|
||||
|
@ -3,7 +3,6 @@ package hirs.persist;
|
||||
import hirs.data.persist.baseline.Baseline;
|
||||
import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.data.persist.ImaBlacklistRecord;
|
||||
import hirs.data.persist.baseline.ImaBlacklistBaseline;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
@ -20,7 +20,6 @@ import hirs.data.persist.Digest;
|
||||
import hirs.data.persist.enums.DigestAlgorithm;
|
||||
import hirs.data.persist.info.FirmwareInfo;
|
||||
import hirs.data.persist.info.HardwareInfo;
|
||||
import hirs.data.persist.IMAReport;
|
||||
import hirs.data.persist.IntegrityReport;
|
||||
import hirs.data.persist.info.OSInfo;
|
||||
import hirs.data.persist.TPMReport;
|
||||
|
Loading…
x
Reference in New Issue
Block a user