/*
* Copyright (C) 2012 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson.policy.rule;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.intel.mtwilson.model.Measurement;
import com.intel.mtwilson.model.Pcr;
import com.intel.mtwilson.model.PcrEventLog;
import com.intel.mtwilson.model.PcrIndex;
//import com.intel.mtwilson.model.Sha1Digest;
import com.intel.dcsg.cpg.crypto.Sha1Digest;
import com.intel.mtwilson.policy.BaseRule;
import com.intel.mtwilson.policy.BaseRule;
import com.intel.mtwilson.policy.HostReport;
import com.intel.mtwilson.policy.HostReport;
import com.intel.mtwilson.policy.RuleResult;
import com.intel.mtwilson.policy.RuleResult;
import com.intel.mtwilson.policy.fault.PcrEventLogMissing;
import com.intel.mtwilson.policy.fault.PcrManifestMissing;
import com.intel.mtwilson.policy.fault.PcrValueMismatch;
import com.intel.mtwilson.policy.fault.PcrValueMissing;
import java.util.List;
/**
* The PcrMatchesConstant policy enforces that a specific PCR contains a specific
* pre-determined constant value. This is typical for values that are known in
* advance such as BIOS or trusted module measurements.
*
* The PcrEventLogIncludes and PcrEventLogEquals policies enforce that the event log
* for a specific PCR contain certain measurements.
*
* This policy, PcrEventLogIntegrity, is a complement to the other PcrEventLog* policies
* because it checks that the PCR value is equal to the result of extending all the
* measurements in the event log. If this policy is applied to a host and it fails,
* then results from the other PcrEventLog* may not be trustworthy since the event log
* integrity cannot be verified -- that is it can contain any list of modules and we
* don't know if it's accurate (and must assume it isn't).
*
*
* @author jbuhacoff
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonIgnoreProperties(ignoreUnknown=true)
public class PcrEventLogIntegrity extends BaseRule {
private PcrIndex pcrIndex;
protected PcrEventLogIntegrity() { } // for desearializing jackson
public PcrEventLogIntegrity(PcrIndex pcrIndex) {
this.pcrIndex = pcrIndex;
}
public PcrIndex getPcrIndex() { return pcrIndex; }
@Override
public RuleResult apply(HostReport hostReport) {
RuleResult report = new RuleResult(this);
if( hostReport.pcrManifest == null ) {
report.fault(new PcrManifestMissing());
}
else {
Pcr actualValue = hostReport.pcrManifest.getPcr(pcrIndex);
if( actualValue == null ) {
report.fault(new PcrValueMissing(pcrIndex));
}
else {
PcrEventLog eventLog = hostReport.pcrManifest.getPcrEventLog(pcrIndex);
if( eventLog == null ) {
report.fault(new PcrEventLogMissing(pcrIndex));
}
else {
List<Measurement> measurements = eventLog.getEventLog();
if( measurements != null ) {
Sha1Digest expectedValue = computeHistory(measurements); // calculate expected' based on history
// make sure the expected pcr value matches the actual pcr value
if( !expectedValue.equals(actualValue.getValue()) ) {
report.fault(new PcrValueMismatch(pcrIndex, expectedValue, actualValue.getValue()) );
}
}
}
}
}
return report;
}
private Sha1Digest computeHistory(List<Measurement> list) {
// start with a default value of zero... that should be the initial value of every PCR .. if a pcr is reset after boot the tpm usually sets its starting value at -1 so the end result is different , which we could then catch here when the hashes don't match
Sha1Digest result = Sha1Digest.ZERO;
for(Measurement m : list) {
result = result.extend(m.getValue());
}
return result;
}
}