package com.intel.mtwilson.model; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.intel.dcsg.cpg.crypto.Sha1Digest; import com.intel.dcsg.cpg.validation.ObjectModel; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.builder.HashCodeBuilder; //import org.codehaus.jackson.annotate.JsonValue; /** * Represents an ordered list of modules (hash,description), options, or other data that * are extended into a specific PCR. * * One PcrModuleManifest is equal to another PcrModuleManifest if they specify exactly * the same set of module values, in any order. Subsets and supersets * are not considered equal. * * For the purpose of determining if a given host complies with a policy * (matches the whitelist), you need to have an expected (whitelisted) * PcrModuleManifest and an actual (from the HostReport) PcrModuleManifest, and * compare the expected to the actual. * * @since 1.2 * @author jbuhacoff */ public class PcrEventLog extends ObjectModel { private final PcrIndex pcrIndex; private final List<Measurement> eventLog = new ArrayList<>(); public PcrEventLog(PcrIndex pcrIndex) { this.pcrIndex = pcrIndex; } @JsonCreator public PcrEventLog(@JsonProperty("pcr_index") PcrIndex pcrIndex, @JsonProperty("event_log") List<Measurement> moduleManifest) { this.pcrIndex = pcrIndex; if( moduleManifest != null ) { this.eventLog.addAll(moduleManifest); } } public PcrIndex getPcrIndex() { return pcrIndex; } public List<Measurement> getEventLog() { return eventLog; } /** * Checks to see if the PcrModuleManifest contains the given Measurement (value & description) * @param measurement * @return true if the PcrModuleManifest contains the given Measurement value */ public boolean contains(Measurement m) { if( m == null ) { return false; } return eventLog.contains(m); } /** * Checks to see if the PcrModuleManifest contains a Measurement with the given SHA1 digest value * @param value * @return true if the PcrModuleManifest contains an entry with the specified value, false otherwise */ public boolean contains(Sha1Digest value) { if( value == null ) { return false; } for(Measurement m : eventLog) { if( m.getValue().equals(value) ) { return true; } } return false; } /** * Returns a string representing the PCR manifest, one PCR index-value pair * per line. Only non-null PCRs are represented in the output. * * @see java.lang.Object#toString() */ // @JsonValue @Override public String toString() { String result = String.format("PCR %d module manifest:", pcrIndex.toInteger()); for(Measurement m : eventLog) { result = result.concat(m.getValue().toString()+" "+m.getLabel()+"\n"); } return result; } @Override public int hashCode() { HashCodeBuilder builder = new HashCodeBuilder(17,57); builder.append(pcrIndex); for(Measurement m : eventLog) { builder.append(m); } return builder.toHashCode(); } /** * A PCR Manifest is equal to another if it contains exactly the same * digest values in the same registers. In addition, because a PCR Manifest * can have ignored (null) digests for some registers, both manifests must * have null digests for the same registers. * @param other * @return */ @Override public boolean equals(Object other) { if( other == null ) { return false; } if( other == this ) { return true; } if( other.getClass() != this.getClass() ) { return false; } PcrEventLog rhs = (PcrEventLog)other; // EqualsBuilder builder = new EqualsBuilder(); // org.apache.commons.lang3.builder.EqualsBuilder if( !pcrIndex.equals(rhs.pcrIndex)) { return false; } if( !eventLog.equals(rhs.eventLog)) { return false; } return true; } @Override public void validate() { if( eventLog == null ) { fault("Measurement set is null"); } else if( eventLog.isEmpty() ) { fault("Measurement set is empty"); } else { for(Measurement m : eventLog) { if( !m.isValid() ) { fault(m, "Invalid measurement %s in module manifest", m.getLabel()); } } } } }