/*
* Copyright (C) 2013 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson.policy.impl;
import com.intel.mountwilson.as.common.ASException;
import com.intel.mtwilson.as.controller.TblHostSpecificManifestJpaController;
import com.intel.mtwilson.as.controller.TblLocationPcrJpaController;
import com.intel.mtwilson.as.controller.TblMleJpaController;
import com.intel.mtwilson.as.controller.TblPcrManifestJpaController;
import com.intel.mtwilson.as.controller.TblModuleManifestJpaController;
import com.intel.mtwilson.as.data.MwAssetTagCertificate;
import com.intel.mtwilson.as.data.TblHostSpecificManifest;
import com.intel.mtwilson.as.data.TblHosts;
import com.intel.mtwilson.as.data.TblMle;
import com.intel.mtwilson.as.data.TblModuleManifest;
import com.intel.mtwilson.as.data.TblPcrManifest;
import com.intel.mtwilson.i18n.ErrorCode;
import com.intel.mtwilson.model.Bios;
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.dcsg.cpg.crypto.Sha1Digest;
import com.intel.dcsg.cpg.x509.X509Util;
import com.intel.mtwilson.My;
import com.intel.mtwilson.model.Vmm;
import com.intel.mtwilson.policy.Rule;
import com.intel.mtwilson.policy.rule.PcrEventLogEqualsExcluding;
import com.intel.mtwilson.policy.rule.PcrEventLogIncludes;
import com.intel.mtwilson.policy.rule.PcrEventLogIntegrity;
import com.intel.mtwilson.policy.rule.PcrMatchesConstant;
import com.intel.mtwilson.policy.rule.TagCertificateTrusted;
import java.io.FileInputStream;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManagerFactory;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class should be used to instantiate Policy and Rule objects out of our existing
* database schema.
*
* This class provides utility methods for the vendor-specific rule loading
* classes. For example, creating a PcrMatchesConstant rule out of a mw_pcr_manifest record
* is the same code regardless of which vendor is using it for what purpose.
*
* @author jbuhacoff
*/
public class JpaPolicyReader {
private Logger log = LoggerFactory.getLogger(getClass());
private EntityManagerFactory entityManagerFactory;
private TblMleJpaController mleJpaController;
private TblPcrManifestJpaController pcrManifestJpaController;
private TblHostSpecificManifestJpaController pcrHostSpecificManifestJpaController;
private TblModuleManifestJpaController moduleManifestJpaController;
private TblLocationPcrJpaController locationPcrJpaController;
public JpaPolicyReader(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
mleJpaController = new TblMleJpaController(entityManagerFactory);
pcrManifestJpaController = new TblPcrManifestJpaController(entityManagerFactory);
moduleManifestJpaController = new TblModuleManifestJpaController(entityManagerFactory);
locationPcrJpaController = new TblLocationPcrJpaController(entityManagerFactory);
pcrHostSpecificManifestJpaController = new TblHostSpecificManifestJpaController(entityManagerFactory);
}
public List<PcrIndex> loadBiosPcrIndexList(TblHosts tblHosts) {
ArrayList<PcrIndex> pcrs = new ArrayList<PcrIndex>();
TblMle biosMle = mleJpaController.findMleById(tblHosts.getBiosMleId().getId());
String biosPcrList = biosMle.getRequiredManifestList();
if (biosPcrList.isEmpty()) {
throw new ASException(
ErrorCode.AS_MISSING_MLE_REQD_MANIFEST_LIST,
tblHosts.getBiosMleId().getName(), tblHosts.getBiosMleId().getVersion());
}
String[] biosPcrs = biosPcrList.split(",");
for(String str : biosPcrs) {
pcrs.add(new PcrIndex(Integer.valueOf(str)));
}
return pcrs;
}
public List<PcrIndex> loadVmmPcrIndexList(TblHosts tblHosts) {
ArrayList<PcrIndex> pcrs = new ArrayList<PcrIndex>();
// Get the Vmm MLE without accessing cache
TblMle vmmMle = mleJpaController.findMleById(tblHosts.getVmmMleId().getId());
String vmmPcrList = vmmMle.getRequiredManifestList();
if (vmmPcrList == null || vmmPcrList.isEmpty()) {
throw new ASException(
ErrorCode.AS_MISSING_MLE_REQD_MANIFEST_LIST,
tblHosts.getVmmMleId().getName(), tblHosts.getVmmMleId().getVersion());
}
String[] vmmPcrs = vmmPcrList.split(",");
for(String str : vmmPcrs) {
pcrs.add(new PcrIndex(Integer.valueOf(str)));
}
return pcrs;
}
public Rule createPcrMatchesConstantRuleFromTblPcrManifest(TblPcrManifest pcrInfo, String... markers) {
try {
PcrIndex pcrIndex = new PcrIndex(Integer.valueOf(pcrInfo.getName()));
Sha1Digest pcrValue = new Sha1Digest(pcrInfo.getValue());
log.debug("Creating PcrMatchesConstantRule from PCR {} value {}", pcrIndex.toString(), pcrValue.toString());
PcrMatchesConstant rule = new PcrMatchesConstant(new Pcr(pcrIndex, pcrValue));
rule.setMarkers(markers);
return rule;
}
catch(IllegalArgumentException e) {
log.error("Invalid PCR {} value {}, skipped", pcrInfo.getName(), pcrInfo.getValue());
return null;
}
}
public Set<Rule> createPcrMatchesConstantRulesFromTblPcrManifest(Collection<TblPcrManifest> pcrInfoList, String... markers) {
HashSet<Rule> list = new HashSet<Rule>();
for(TblPcrManifest pcrInfo : pcrInfoList) {
Rule rule = createPcrMatchesConstantRuleFromTblPcrManifest(pcrInfo, markers); // returns null if the rule cannot be created, such as the digest value is blank
if( rule != null ) {
list.add(rule);
}
}
return list;
}
/*
public Set<Rule> loadPcrMatchesConstantRules(TblHosts tblHosts, TblMle mle) {
Collection<TblPcrManifest> pcrInfoList = mle.getTblPcrManifestCollection();
return createPcrMatchesConstantRulesFromTblPcrManifest(pcrInfoList, TrustMarker.BIOS.name());
}*/
public Set<Rule> loadPcrMatchesConstantRulesForBios(Bios bios, TblHosts tblHosts) {
TblMle biosMle = mleJpaController.findBiosMle(bios.getName(), bios.getVersion(), bios.getOem());
log.debug("WhitelistUtil found BIOS MLE: {}", biosMle.getName());
Collection<TblPcrManifest> pcrInfoList = biosMle.getTblPcrManifestCollection();
return createPcrMatchesConstantRulesFromTblPcrManifest(pcrInfoList, TrustMarker.BIOS.name());
}
public Set<Rule> loadPcrMatchesConstantRulesForVmm(Vmm vmm, TblHosts tblHosts) {
TblMle vmmMle = mleJpaController.findVmmMle(vmm.getName(), vmm.getVersion(), vmm.getOsName(), vmm.getOsVersion());
log.debug("WhitelistUtil found VMM MLE: {}", vmmMle.getName());
Collection<TblPcrManifest> pcrInfoList = vmmMle.getTblPcrManifestCollection();
return createPcrMatchesConstantRulesFromTblPcrManifest(pcrInfoList, TrustMarker.VMM.name());
}
public Set<Rule> loadPcrMatchesConstantRulesForLocation(String location, TblHosts tblHosts) {
// HashSet<Rule> rules = new HashSet<Rule>();
// TblLocationPcr locationPcr = locationPcrJpaController.findTblLocationPcrByLocationName(location)
// log.debug("WhitelistUtil found Location PCR: {}", locationPcr.getName());
// Sha1Digest pcrValue = new Sha1Digest(locationPcr.getValue());
// log.debug("Creating PcrMatchesConstantRule from PCR 22 value {}", pcrValue.toString());
// PcrMatchesConstant rule = new PcrMatchesConstant(new Pcr(PcrIndex.PCR22, pcrValue));
// rule.setMarkers(markers);
// rules.add(rule);
// return rules;
throw new UnsupportedOperationException("add support for checking pcr 22");
}
public Set<Rule> loadPcrMatchesConstantRulesForAssetTag(MwAssetTagCertificate atagCert, TblHosts tblHosts) {
HashSet<Rule> rules = new HashSet<Rule>();
// load the tag cacerts and create the tag trust rule
try(FileInputStream in = new FileInputStream(My.configuration().getAssetTagCaCertificateFile())) {
String text = IOUtils.toString(in);
List<X509Certificate> tagAuthorities = X509Util.decodePemCertificates(text);
TagCertificateTrusted tagTrustedRule = new TagCertificateTrusted(tagAuthorities.toArray(new X509Certificate[0]));
tagTrustedRule.setMarkers(TrustMarker.ASSET_TAG.name());
rules.add(tagTrustedRule);
}
catch(Exception e) {
throw new RuntimeException("Cannot load tag certificate authorities file: "+ e.getMessage());
}
log.debug("Adding the asset tag rule for host {} with asset tag ID {}", tblHosts.getName(), atagCert.getId());
log.debug("Creating PcrMatchesConstantRule from PCR 22 value {}", Sha1Digest.valueOf(atagCert.getPCREvent()).toString());
// Since we are storing the actual expected value in PCREvent field, we do not need to do a SHA1 of it again.
// Sha1Digest pcrValue = new Sha1Digest(atagCert.getPCREvent());
//PcrMatchesConstant rule = new PcrMatchesConstant(new Pcr(PcrIndex.PCR22, Sha1Digest.valueOf(atagCert.getPCREvent())));
PcrMatchesConstant tagPcrRule = new PcrMatchesConstant(new Pcr(PcrIndex.PCR22.toInteger(), Sha1Digest.valueOf(atagCert.getPCREvent()).toString()));
tagPcrRule.setMarkers(TrustMarker.ASSET_TAG.name());
rules.add(tagPcrRule);
return rules;
}
public Measurement createMeasurementFromTblModuleManifest(TblModuleManifest moduleInfo, TblHosts host) {
HashMap<String,String> info = new HashMap<String,String>();
// info.put("EventType", manifest.getEventType());
info.put("EventName", moduleInfo.getEventID().getName());
info.put("ComponentName", moduleInfo.getComponentName());
info.put("HostSpecificModule", moduleInfo.getUseHostSpecificDigestValue().toString());
// Since we can call this function even without registering the host, the hostID will not be present. So, we need to skip adding this host specific module
if( moduleInfo.getUseHostSpecificDigestValue() != null && moduleInfo.getUseHostSpecificDigestValue().booleanValue()) {
if (host.getId() != null && host.getId() != 0) {
TblHostSpecificManifest hostSpecificModule = pcrHostSpecificManifestJpaController.findByModuleAndHostID(host.getId(), moduleInfo.getId()); // returns null if not found;
if( hostSpecificModule == null ) {
log.error(String.format("Missing host-specific module %s for host %s", moduleInfo.getComponentName(), host.getName()));
Measurement m = new Measurement(Sha1Digest.ZERO, "Missing host-specific module: "+moduleInfo.getComponentName(), info);
return m;
}
else {
Measurement m = new Measurement(new Sha1Digest(hostSpecificModule.getDigestValue()), moduleInfo.getComponentName(), info);
return m;
}
} else
return null;
}
else {
info.put("PackageName", moduleInfo.getPackageName());
info.put("PackageVersion", moduleInfo.getPackageVersion());
info.put("PackageVendor", moduleInfo.getPackageVendor());
Measurement m = new Measurement(new Sha1Digest(moduleInfo.getDigestValue()), moduleInfo.getComponentName(), info);
return m;
}
}
// creates a rule for checking that ONE module is included in a pcr event log
public Rule createPcrEventLogIncludesRuleFromTblModuleManifest(TblModuleManifest moduleInfo, TblHosts host, String... markers) {
PcrIndex pcrIndex = new PcrIndex(Integer.valueOf(moduleInfo.getExtendedToPCR()));
log.debug("... MODULE for PCR {}", pcrIndex.toString());
Measurement m = createMeasurementFromTblModuleManifest(moduleInfo, host);
PcrEventLogIncludes rule = null;
if (m != null)
rule = new PcrEventLogIncludes(pcrIndex, m);
if (rule != null)
rule.setMarkers(markers);
return rule;
}
// creates a rule for checking that ONE OR MORE modules are included in a pcr event log
public Set<Rule> createPcrEventLogIncludesRuleFromTblModuleManifest(Collection<TblModuleManifest> pcrModuleInfoList, TblHosts host, String... markers) {
HashSet<Rule> list = new HashSet<Rule>();
HashMap<PcrIndex,Set<Measurement>> measurements = new HashMap<PcrIndex,Set<Measurement>>();
for(TblModuleManifest moduleInfo : pcrModuleInfoList) {
PcrIndex pcrIndex = PcrIndex.valueOf(Integer.valueOf(moduleInfo.getExtendedToPCR()));
if( !measurements.containsKey(pcrIndex) ) {
measurements.put(pcrIndex, new HashSet<Measurement>());
}
Measurement m = createMeasurementFromTblModuleManifest(moduleInfo, host);
if (m != null)
measurements.get(pcrIndex).add(m);
}
// for every pcr that has events, we add a "pcr event log includes..." rule for those events, and also an integrity rule.
for(PcrIndex pcrIndex : measurements.keySet()) {
if( pcrIndex.toInteger() == 19 ) {
// event log rule
log.debug("Adding PcrEventLogIncludes rule for PCR {} with {} events", pcrIndex.toString(), measurements.get(pcrIndex).size());
PcrEventLogIncludes eventLogIncludesRule = new PcrEventLogIncludes(pcrIndex, measurements.get(pcrIndex));
eventLogIncludesRule.setMarkers(markers);
list.add(eventLogIncludesRule);
// integrity rule
log.debug("Adding PcrEventLogIntegrity rule for PCR {}", pcrIndex.toString());
PcrEventLogIntegrity integrityRule = new PcrEventLogIntegrity(pcrIndex);
integrityRule.setMarkers(markers);
list.add(integrityRule); // if we're going to look for things in the host's event log, it needs to have integrity
}
}
return list;
}
public Set<Rule> loadPcrEventLogIncludesRuleForBios(Bios bios, TblHosts tblHosts) {
TblMle biosMle = mleJpaController.findBiosMle(bios.getName(), bios.getVersion(), bios.getOem());
Collection<TblModuleManifest> pcrModuleInfoList = biosMle.getTblModuleManifestCollection();
return createPcrEventLogIncludesRuleFromTblModuleManifest(pcrModuleInfoList, tblHosts, TrustMarker.BIOS.name());
}
public Set<Rule> loadPcrEventLogIncludesRuleForVmm(Vmm vmm, TblHosts tblHosts) {
TblMle vmmMle = mleJpaController.findVmmMle(vmm.getName(), vmm.getVersion(), vmm.getOsName(), vmm.getOsVersion());
Collection<TblModuleManifest> pcrModuleInfoList = vmmMle.getTblModuleManifestCollection();
return createPcrEventLogIncludesRuleFromTblModuleManifest(pcrModuleInfoList, tblHosts, TrustMarker.VMM.name());
}
public Set<Rule> loadPcrEventLogEqualExcludingVmm(Vmm vmm, TblHosts tblHosts, boolean verifyMLE) {
TblMle vmmMle = mleJpaController.findVmmMle(vmm.getName(), vmm.getVersion(), vmm.getOsName(), vmm.getOsVersion());
Collection<TblModuleManifest> pcrModuleInfoList = vmmMle.getTblModuleManifestCollection();
return createPcrEventLogEqualExcludingRuleFromTblModuleManifest(pcrModuleInfoList, tblHosts, verifyMLE, TrustMarker.VMM.name());
}
// creates a rule for checking that ONE OR MORE modules are included in a pcr event log
public Set<Rule> createPcrEventLogEqualExcludingRuleFromTblModuleManifest(Collection<TblModuleManifest> pcrModuleInfoList, TblHosts host, boolean verifyMLE, String... markers) {
HashSet<Rule> list = new HashSet<Rule>();
HashMap<PcrIndex,ArrayList<Measurement>> measurements = new HashMap<PcrIndex,ArrayList<Measurement>>();
for(TblModuleManifest moduleInfo : pcrModuleInfoList) {
PcrIndex pcrIndex = PcrIndex.valueOf(Integer.valueOf(moduleInfo.getExtendedToPCR()));
if( !measurements.containsKey(pcrIndex) ) {
measurements.put(pcrIndex, new ArrayList<Measurement>());
}
Measurement m = createMeasurementFromTblModuleManifest(moduleInfo, host);
if (m != null)
measurements.get(pcrIndex).add(m);
}
// for every pcr that has events, we add a "pcr event log includes..." rule for those events, and also an integrity rule.
for(PcrIndex pcrIndex : measurements.keySet()) {
if( pcrIndex.toInteger() == 19 ) {
// event log rule
log.debug("Adding PcrEventLogEqualsExcluding rule for PCR {} with {} events", pcrIndex.toString(), measurements.get(pcrIndex).size());
PcrEventLogEqualsExcluding eventLogEqualsExcludingRule = new PcrEventLogEqualsExcluding(new PcrEventLog(pcrIndex, measurements.get(pcrIndex)));
if (verifyMLE)
eventLogEqualsExcludingRule.setExcludeHostSpecificModules(verifyMLE);
eventLogEqualsExcludingRule.setMarkers(markers);
list.add(eventLogEqualsExcludingRule);
// We need to add the integrity only only for attestation and not for verification of MLE
if (!verifyMLE) {
log.debug("Adding PcrEventLogIntegrity rule for PCR {}", pcrIndex.toString());
PcrEventLogIntegrity integrityRule = new PcrEventLogIntegrity(pcrIndex);
integrityRule.setMarkers(markers);
list.add(integrityRule); // if we're going to look for things in the host's event log, it needs to have integrity
}
}
}
return list;
}
}