Updated the bulk of the code that does all provisioning from a client.

There is some parsed functionality to ease sorting through the changes
and updates needed in the future.
This commit is contained in:
Cyrus 2023-09-21 15:02:24 -04:00
parent 9fea7788ed
commit 4b67747e3e
17 changed files with 1055 additions and 2475 deletions

View File

@ -36,6 +36,7 @@ dependencies {
implementation libs.jakarta.api
implementation libs.jakarta.xml
implementation libs.hibernate.core
implementation libs.pci
implementation libs.guava
implementation libs.jackson.core
implementation libs.jackson.databind

View File

@ -1,223 +0,0 @@
package hirs.attestationca.persist;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
/**
* The class handles the flags that ignore certain PCRs for validation.
*/
@Log4j2
@NoArgsConstructor
public class PCRQuoteValidator {
/**
* Minimum possible value for a PCR ID. This is 0.
*/
public static final int MIN_PCR_ID = 0;
/**
* Maximum possible value for a PCR ID. This is 23.
*/
public static final int MAX_PCR_ID = 23;
private static final int NUM_TO_SKIP = 1;
private static final int NUM_OF_TBOOT_PCR = 3;
// PCR 5-16
private static final int PXE_PCR_START = 5;
private static final int PXE_PCR_END = 16;
// PCR 10
private static final int IMA_PCR = 10;
// PCR 17-19
private static final int TBOOT_PCR_START = 17;
private static final int TBOOT_PCR_END = 19;
// PCR 5
private static final int GPT_PCR = 5;
private static final int IMA_MASK = 0xfffbff;
// Event Log Event Types
private static final String EVT_EFI_BOOT = "EV_EFI_BOOT_SERVICES_APPLICATION";
private static final String EVT_EFI_VAR = "EV_EFI_VARIABLE_BOOT";
private static final String EVT_EFI_GPT = "EV_EFI_GPT_EVENT";
private static final String EVT_EFI_CFG = "EV_EFI_VARIABLE_DRIVER_CONFIG";
private String[] baselinePCRS = new String[MAX_PCR_ID + 1];
@Getter
@Setter
private PolicySettings settings;
/**
* Constructor to parse PCR values.
* @param pcrValues pcrValues RIM provided baseline PCRs
* @param settings settings for the supply chain portal settings for provisioning
*/
public PCRQuoteValidator(final String[] pcrValues,
final PolicySettings settings) {
if (pcrValues != null) {
baselinePCRS = new String[MAX_PCR_ID + 1];
for (int i = 0; i <= MAX_PCR_ID; i++) {
baselinePCRS[i] = pcrValues[i];
}
}
this.settings = settings;
}
/**
* Getter for the array of baseline PCRs.
* @return instance of the PCRs.
*/
public String[] getBaselinePCRS() {
return baselinePCRS.clone();
}
/**
* Setter for the array of baseline PCRs.
* @param baselinePCRS instance of the PCRs.
*/
public void setBaselinePCRS(final String[] baselinePCRS) {
this.baselinePCRS = baselinePCRS.clone();
}
/**
* Compares the baseline pcr list and the quote pcr list. If the
* ignore flags are set, 10 and 17-19 will be skipped for comparison.
*
* @param storedPCRS non-baseline pcr list
* @return a StringBuilder that is empty if everything passes.
*/
public StringBuilder validatePCRS(final String[] storedPCRS) {
StringBuilder sb = new StringBuilder();
String failureMsg = "PCR %d does not match%n";
if (storedPCRS[0] == null || storedPCRS[0].isEmpty()) {
sb.append("failureMsg");
} else {
for (int i = 0; i <= MAX_PCR_ID; i++) {
if (settings.isIgnoreImaEnabled() && i == IMA_PCR) {
log.info("PCR Policy IMA Ignore enabled.");
i += NUM_TO_SKIP;
}
if (settings.isIgnoretBootEnabled() && i == TBOOT_PCR_START) {
log.info("PCR Policy TBoot Ignore enabled.");
i += NUM_OF_TBOOT_PCR;
}
if (settings.isIgnoreGptEnabled() && i == GPT_PCR) {
log.info("PCR Policy GPT Ignore enabled.");
i += NUM_TO_SKIP;
}
if (!baselinePCRS[i].equals(storedPCRS[i])) {
//error
log.error(String.format("%s =/= %s", baselinePCRS[i], storedPCRS[i]));
sb.append(String.format(failureMsg, i));
}
}
}
return sb;
}
/**
* Checks that the expected FM events occurring. There are policy options that
* will ignore certain PCRs, Event Types and Event Variables present.
* @param tcgMeasurementLog Measurement log from the client
* @param eventValueMap The events stored as baseline to compare
* @return the events that didn't pass
*/
// public List<TpmPcrEvent> validateTpmEvents(final TCGEventLog tcgMeasurementLog,
// final Map<String, ReferenceDigestValue> eventValueMap) {
// List<TpmPcrEvent> tpmPcrEvents = new LinkedList<>();
// for (TpmPcrEvent tpe : tcgMeasurementLog.getEventList()) {
// if (enableIgnoreIma && tpe.getPcrIndex() == IMA_PCR) {
// log.info(String.format("IMA Ignored -> %s", tpe));
// } else if (enableIgnoretBoot && (tpe.getPcrIndex() >= TBOOT_PCR_START
// && tpe.getPcrIndex() <= TBOOT_PCR_END)) {
// log.info(String.format("TBOOT Ignored -> %s", tpe));
// } else if (enableIgnoreOsEvt && (tpe.getPcrIndex() >= PXE_PCR_START
// && tpe.getPcrIndex() <= PXE_PCR_END)) {
// log.info(String.format("OS Evt Ignored -> %s", tpe));
// } else {
// if (enableIgnoreGpt && tpe.getEventTypeStr().contains(EVT_EFI_GPT)) {
// log.info(String.format("GPT Ignored -> %s", tpe));
// } else if (enableIgnoreOsEvt && (tpe.getEventTypeStr().contains(EVT_EFI_BOOT)
// || tpe.getEventTypeStr().contains(EVT_EFI_VAR))) {
// log.info(String.format("OS Evt Ignored -> %s", tpe));
// } else if (enableIgnoreOsEvt && (tpe.getEventTypeStr().contains(EVT_EFI_CFG)
// && tpe.getEventContentStr().contains("SecureBoot"))) {
// log.info(String.format("OS Evt Config Ignored -> %s", tpe));
// } else {
// if (!eventValueMap.containsKey(tpe.getEventDigestStr())) {
// tpmPcrEvents.add(tpe);
// }
// }
// }
// }
//
// return tpmPcrEvents;
// }
/**
* Compares hashes to validate the quote from the client.
*
* @param tpmQuote the provided quote
* @param storedPCRS values from the RIM file
* @return true if validated, false if not
*/
// public boolean validateQuote(final byte[] tpmQuote, final String[] storedPCRS) {
// System.out.println("Validating quote from associated device.");
// boolean validated = false;
// short localityAtRelease = 0;
// String quoteString = new String(tpmQuote, StandardCharsets.UTF_8);
// int pcrMaskSelection = PcrSelection.ALL_PCRS_ON;
//
// if (enableIgnoreIma) {
// pcrMaskSelection = IMA_MASK;
// }
//
// ArrayList<TPMMeasurementRecord> measurements = new ArrayList<>();
//
// try {
// for (int i = 0; i < storedPcrs.length; i++) {
// if (i == IMA_PCR && enableIgnoreIma) {
// log.info("Ignore IMA PCR policy is enabled.");
// } else {
// measurements.add(new TPMMeasurementRecord(i, storedPcrs[i]));
// }
// }
// } catch (DecoderException deEx) {
// //error
// System.out.println(deEx);
// }
//
// PcrSelection pcrSelection = new PcrSelection(pcrMaskSelection);
// PcrComposite pcrComposite = new PcrComposite(pcrSelection);
// PcrInfoShort pcrInfoShort = new PcrInfoShort(pcrSelection,
// localityAtRelease,
// tpmQuote, pcrComposite);
//
// try {
// /**
// * The calculated string is being used in the contains method
// * because the TPM Quote's hash isn't just for PCR values,
// * it contains the calculated digest of the PCRs, along with
// * other information.
// */
// String calculatedString = Hex.encodeHexString(
// pcrInfoShort.getCalculatedDigest());
// validated = quoteString.contains(calculatedString);
// if (!validated) {
// // warn
// System.out.println(calculatedString + " not found in " + quoteString);
// }
// } catch (NoSuchAlgorithmException naEx) {
// // error
// System.out.println(naEx);
// }
//
// return validated;
// }
}

View File

@ -11,12 +11,9 @@ import java.util.UUID;
@Repository
public interface ReferenceDigestValueRepository extends JpaRepository<ReferenceDigestValue, UUID> {
@Query(value = "SELECT * FROM ReferenceDigestValue", nativeQuery = true)
List<ReferenceDigestValue> listAll();
List<ReferenceDigestValue> findByModel(String model);
List<ReferenceDigestValue> findByManufacturer(String manufacturer);
@Query(value = "SELECT * FROM ReferenceDigestValue WHERE baseRimId = '?1' OR supportRimId = '?1'", nativeQuery = true)
List<ReferenceDigestValue> getValuesByRimId(UUID associatedRimId);
List<ReferenceDigestValue> findValuesByBaseRimId(UUID associatedRimId);
List<ReferenceDigestValue> findBySupportRimId(UUID supportRimId);
List<ReferenceDigestValue> findBySupportRimHash(String supportRimHash);
List<ReferenceDigestValue> findByManufacturerAndModel(String manufacturer, String model);

View File

@ -39,4 +39,6 @@ public interface ReferenceManifestRepository extends JpaRepository<ReferenceMani
EventLogMeasurements byMeasurementDeviceName(String deviceName);
@Query(value = "SELECT * FROM ReferenceManifest WHERE platformManufacturer = ?1 AND platformModel = ?2 AND rimType = 'Support'", nativeQuery = true)
List<SupportReferenceManifest> getSupportByManufacturerModel(String manufacturer, String model);
@Query(value = "SELECT * FROM ReferenceManifest WHERE platformModel = ?1 AND DTYPE = 'EventLogMeasurements'", nativeQuery = true)
EventLogMeasurements getLogByModel(String model);
}

View File

@ -176,6 +176,8 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
@Column(length = MAX_MESSAGE_LENGTH)
private String componentFailures = Strings.EMPTY;
@Column(length = MAX_MESSAGE_LENGTH)
private String componentFailureMessage = Strings.EMPTY;
@Transient
private EndorsementCredential endorsementCredential = null;

View File

@ -198,6 +198,7 @@ public class CertificateRequestHandler extends AbstractRequestHandler {
* @return the {@link AppraisalStatus} of the supply chain validation
*/
private AppraisalStatus.Status doQuoteValidation(final Device device) {
log.info("Beginning Quote Validation...");
// perform supply chain validation
SupplyChainValidationSummary scvs = supplyChainValidationService.validateQuote(
device);

View File

@ -124,6 +124,7 @@ public class IdentityClaimHandler extends AbstractRequestHandler {
try {
validationResult = doSupplyChainValidation(claim, ekPub);
} catch (Exception ex) {
log.error(ex.getMessage());
for (StackTraceElement ste : ex.getStackTrace()) {
log.error(ste.toString());
}
@ -191,12 +192,15 @@ public class IdentityClaimHandler extends AbstractRequestHandler {
// this is to check what is in the platform object and pull
// additional information from the DB if information exists
if (platformCredentials.size() == 1) {
List<PlatformCredential> tempList = new LinkedList<>();
for (PlatformCredential pc : platformCredentials) {
if (pc != null && pc.getPlatformSerial() != null) {
platformCredentials.addAll(certificateRepository
tempList.addAll(certificateRepository
.byBoardSerialNumber(pc.getPlatformSerial()));
}
}
platformCredentials.addAll(tempList);
}
// perform supply chain validation
SupplyChainValidationSummary summary = supplyChainValidationService.validateSupplyChain(
@ -227,6 +231,9 @@ public class IdentityClaimHandler extends AbstractRequestHandler {
log.info("Processing Device Info Report");
// store device and device info report.
Device device = this.deviceRepository.findByName(deviceInfoReport.getNetworkInfo().getHostname());
if (device == null) {
device = new Device(deviceInfoReport);
}
device.setDeviceInfo(deviceInfoReport);
return this.deviceRepository.save(device);
}

View File

@ -1,30 +1,259 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.DBManagerException;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.manager.CACredentialRepository;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.PolicyRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.manager.SupplyChainValidationSummaryRepository;
import hirs.attestationca.persist.entity.userdefined.Device;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.validation.PcrValidator;
import hirs.attestationca.persist.validation.SupplyChainCredentialValidator;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.Level;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
@Log4j2
@Service
public class SupplyChainValidationService {
private CACredentialRepository caCredentialRepository;
private PolicyRepository policyRepository;
private ReferenceManifestRepository referenceManifestRepository;
private ReferenceDigestValueRepository referenceDigestValueRepository;
private ComponentResultRepository componentResultRepository;
private CertificateRepository certificateRepository;
private SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository;
/**
* Interface defining a component that will perform supply chain validations, which yields a
* {@link SupplyChainValidationSummary}.
*/
public interface SupplyChainValidationService {
/**
* The "main" method of supply chain validation. Takes the credentials from an identity
* request and validates the supply chain in accordance to the current supply chain
* policy.
* Constructor.
*
* @param ec The endorsement credential from the identity request.
* @param pc The set of platform credentials from the identity request.
* @param device The device to be validated.
* @return True if validation is successful, false otherwise.
* @param caCredentialRepository ca credential repository
* @param policyRepository the policy manager
* @param certificateRepository the cert manager
* @param componentResultRepository the comp result manager
* @param referenceManifestRepository the RIM manager
* @param supplyChainValidationSummaryRepository the summary manager
* @param referenceDigestValueRepository the even manager
*/
SupplyChainValidationSummary validateSupplyChain(EndorsementCredential ec,
List<PlatformCredential> pc,
Device device);
@Autowired
@SuppressWarnings("ParameterNumberCheck")
public SupplyChainValidationService(
final CACredentialRepository caCredentialRepository,
final PolicyRepository policyRepository,
final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository,
final ReferenceManifestRepository referenceManifestRepository,
final SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository) {
this.caCredentialRepository = caCredentialRepository;
this.policyRepository = policyRepository;
this.certificateRepository = certificateRepository;
this.componentResultRepository = componentResultRepository;
this.referenceManifestRepository = referenceManifestRepository;
this.supplyChainValidationSummaryRepository = supplyChainValidationSummaryRepository;
this.referenceDigestValueRepository = referenceDigestValueRepository;
}
/**
* The "main" method of supply chain validation. Takes the credentials from
* an identity request and validates the supply chain in accordance to the
* current supply chain policy.
*
* @param ec The endorsement credential from the identity request.
* @param pcs The platform credentials from the identity request.
* @param device The device to be validated.
* @return A summary of the validation results.
*/
@SuppressWarnings("methodlength")
public SupplyChainValidationSummary validateSupplyChain(final EndorsementCredential ec,
final List<PlatformCredential> pcs,
final Device device) {
boolean acceptExpiredCerts = getPolicySettings().isExpiredCertificateValidationEnabled();
PlatformCredential baseCredential = null;
SupplyChainValidation platformScv = null;
SupplyChainValidation basePlatformScv = null;
boolean chkDeltas = false;
String pcErrorMessage = "";
List<SupplyChainValidation> validations = new LinkedList<>();
Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>();
SupplyChainValidation.ValidationType platformType = SupplyChainValidation
.ValidationType.PLATFORM_CREDENTIAL;
log.info("Beginning Supply Chain Validation...");
log.info("Beginning Endorsement Credential Validation...");
// Validate the Endorsement Credential
if (getPolicySettings().isEcValidationEnabled()) {
validations.add(ValidationManager.evaluateEndorsementCredentialStatus(ec, this.caCredentialRepository, acceptExpiredCerts));
// store the device with the credential
if (ec != null) {
ec.setDeviceId(device.getId());
this.certificateRepository.save(ec);
}
}
log.info("Beginning Platform Credential Validation...");
// Validate Platform Credential signatures
if (getPolicySettings().isPcValidationEnabled()) {
// Ensure there are platform credentials to validate
if (pcs == null || pcs.isEmpty()) {
log.error("There were no Platform Credentials to validate.");
pcErrorMessage = "Platform credential(s) missing\n";
} else {
for (PlatformCredential pc : pcs) {
KeyStore trustedCa = ValidationManager.getCaChain(pc, caCredentialRepository);
platformScv = ValidationManager.evaluatePlatformCredentialStatus(
pc, trustedCa, acceptExpiredCerts);
if (platformScv.getValidationResult() == AppraisalStatus.Status.FAIL) {
pcErrorMessage = String.format("%s%s%n", pcErrorMessage,
platformScv.getMessage());
}
// set the base credential
if (pc.isPlatformBase()) {
baseCredential = pc;
basePlatformScv = platformScv;
} else {
chkDeltas = true;
deltaMapping.put(pc, null);
}
pc.setDeviceId(device.getId());
this.certificateRepository.save(pc);
}
// check that the delta certificates validity date is after
// the base
if (baseCredential != null) {
for (PlatformCredential pc : pcs) {
int result = baseCredential.getBeginValidity()
.compareTo(pc.getBeginValidity());
if (!pc.isPlatformBase() && (result > 0)) {
pcErrorMessage = String.format("%s%s%n", pcErrorMessage,
"Delta Certificate's validity "
+ "date is not after Base");
break;
}
}
} else {
// we don't have a base cert, fail
pcErrorMessage = String.format("%s%s%n", pcErrorMessage,
"Base Platform credential missing");
}
}
if (pcErrorMessage.isEmpty()) {
validations.add(platformScv);
} else {
if (pcs == null) {
validations.add(new SupplyChainValidation(platformType,
AppraisalStatus.Status.FAIL, new ArrayList<>(), pcErrorMessage));
} else {
validations.add(new SupplyChainValidation(platformType,
AppraisalStatus.Status.FAIL, new ArrayList<>(pcs), pcErrorMessage));
}
}
}
log.info("Beginning Platform Attributes Validation...");
// Validate Platform Credential attributes
if (getPolicySettings().isPcAttributeValidationEnabled()
&& pcErrorMessage.isEmpty()) {
// Ensure there are platform credentials to validate
SupplyChainValidation attributeScv = null;
String attrErrorMessage = "";
List<ArchivableEntity> aes = new ArrayList<>();
// need to check if there are deltas, if not then just verify
// components of the base
if (baseCredential == null) {
validations.add(ValidationManager.buildValidationRecord(
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
AppraisalStatus.Status.FAIL,
"Base Platform credential missing."
+ " Cannot validate attributes",
null, Level.ERROR));
} else {
if (chkDeltas) {
aes.addAll(basePlatformScv.getCertificatesUsed());
Iterator<PlatformCredential> it = pcs.iterator();
while (it.hasNext()) {
PlatformCredential pc = it.next();
if (pc != null && !pc.isPlatformBase()) {
attributeScv = ValidationManager.evaluateDeltaAttributesStatus(
pc, device.getDeviceInfo(),
baseCredential, deltaMapping, certificateRepository);
if (attributeScv.getValidationResult() == AppraisalStatus.Status.FAIL) {
attrErrorMessage = String.format("%s%s%n", attrErrorMessage,
attributeScv.getMessage());
}
}
}
} else {
aes.add(baseCredential);
validations.remove(platformScv);
// if there are no deltas, just check base credential
platformScv = ValidationManager.evaluatePCAttributesStatus(
baseCredential, device.getDeviceInfo(), ec,
certificateRepository, componentResultRepository);
validations.add(new SupplyChainValidation(
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
platformScv.getValidationResult(), aes, platformScv.getMessage()));
}
}
if (!attrErrorMessage.isEmpty()) {
//combine platform and platform attributes
validations.remove(platformScv);
validations.add(new SupplyChainValidation(
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
attributeScv.getValidationResult(), aes, attributeScv.getMessage()));
}
}
log.info("Beginning Firmware Validation...");
if (getPolicySettings().isFirmwareValidationEnabled()) {
// may need to associated with device to pull the correct info
// compare tpm quote with what is pulled from RIM associated file
validations.add(ValidationManager.evaluateFirmwareStatus(device, getPolicySettings(),
referenceManifestRepository, referenceDigestValueRepository,
caCredentialRepository));
}
log.info("The validation finished, summarizing...");
// Generate validation summary, save it, and return it.
SupplyChainValidationSummary summary
= new SupplyChainValidationSummary(device, validations);
try {
supplyChainValidationSummaryRepository.save(summary);
} catch (DBManagerException dbMEx) {
log.error("Failed to save Supply Chain Summary");
}
return summary;
}
/**
* A supplemental method that handles validating just the quote post main validation.
@ -32,11 +261,110 @@ public interface SupplyChainValidationService {
* @param device the associated device.
* @return True if validation is successful, false otherwise.
*/
SupplyChainValidationSummary validateQuote(Device device);
public SupplyChainValidationSummary validateQuote(final Device device) {
SupplyChainValidation quoteScv = null;
SupplyChainValidationSummary summary = null;
Level level = Level.ERROR;
AppraisalStatus fwStatus = new AppraisalStatus(FAIL,
"Unknown exception caught during quote validation.");
SupportReferenceManifest sRim = null;
EventLogMeasurements eventLog = null;
// check if the policy is enabled
if (getPolicySettings().isFirmwareValidationEnabled()) {
String[] baseline = new String[Integer.SIZE];
String deviceName = device.getDeviceInfo()
.getNetworkInfo().getHostname();
try {
List<SupportReferenceManifest> supportRims = referenceManifestRepository
.getSupportByManufacturerModel(
device.getDeviceInfo().getHardwareInfo().getManufacturer(),
device.getDeviceInfo().getHardwareInfo().getProductName());
for (SupportReferenceManifest support : supportRims) {
if (support.isBaseSupport()) {
sRim = support;
}
}
eventLog = (EventLogMeasurements) referenceManifestRepository
.findByHexDecHash(sRim.getEventLogHash());
if (sRim == null) {
fwStatus = new AppraisalStatus(FAIL,
String.format("Firmware Quote validation failed: "
+ "No associated Support RIM file "
+ "could be found for %s",
deviceName));
} else if (eventLog == null) {
fwStatus = new AppraisalStatus(FAIL,
String.format("Firmware Quote validation failed: "
+ "No associated Client Log file "
+ "could be found for %s",
deviceName));
} else {
baseline = sRim.getExpectedPCRList();
String[] storedPcrs = eventLog.getExpectedPCRList();
PcrValidator pcrValidator = new PcrValidator(baseline);
// grab the quote
byte[] hash = device.getDeviceInfo().getTpmInfo().getTpmQuoteHash();
if (pcrValidator.validateQuote(hash, storedPcrs, getPolicySettings())) {
level = Level.INFO;
fwStatus = new AppraisalStatus(PASS,
SupplyChainCredentialValidator.FIRMWARE_VALID);
fwStatus.setMessage("Firmware validation of TPM Quote successful.");
} else {
fwStatus.setMessage("Firmware validation of TPM Quote failed."
+ "\nPCR hash and Quote hash do not match.");
}
eventLog.setOverallValidationResult(fwStatus.getAppStatus());
this.referenceManifestRepository.save(eventLog);
}
} catch (Exception ex) {
log.error(ex);
}
quoteScv = ValidationManager.buildValidationRecord(SupplyChainValidation
.ValidationType.FIRMWARE,
fwStatus.getAppStatus(), fwStatus.getMessage(), eventLog, level);
// Generate validation summary, save it, and return it.
List<SupplyChainValidation> validations = new ArrayList<>();
SupplyChainValidationSummary previous
= this.supplyChainValidationSummaryRepository.findByDevice(deviceName);
for (SupplyChainValidation scv : previous.getValidations()) {
if (scv.getValidationType() != SupplyChainValidation.ValidationType.FIRMWARE) {
validations.add(ValidationManager.buildValidationRecord(scv.getValidationType(),
scv.getValidationResult(), scv.getMessage(),
scv.getCertificatesUsed().get(0), Level.INFO));
}
}
validations.add(quoteScv);
previous.archive();
supplyChainValidationSummaryRepository.save(previous);
summary = new SupplyChainValidationSummary(device, validations);
// try removing the supply chain validation as well and resaving that
try {
supplyChainValidationSummaryRepository.save(summary);
} catch (DBManagerException dbEx) {
log.error("Failed to save Supply Chain Summary", dbEx);
}
}
return summary;
}
/**
* Allows other service access to the policy information.
* @return supply chain policy
* Helper function to get a fresh load of the default policy from the DB.
*
* @return The default Supply Chain Policy
*/
// SupplyChainPolicy getPolicy();
private PolicySettings getPolicySettings() {
PolicySettings defaultSettings = this.policyRepository.findByName("Default");
if (defaultSettings == null) {
defaultSettings = new PolicySettings("Default", "Settings are configured for no validation flags set.");
}
return defaultSettings;
}
}

View File

@ -1,377 +0,0 @@
package hirs.attestationca.persist.service;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.DBManagerException;
import hirs.attestationca.persist.entity.manager.CACredentialRepository;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.PolicyRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
import hirs.attestationca.persist.entity.manager.SupplyChainValidationSummaryRepository;
import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.Device;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary;
import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.record.TPMMeasurementRecord;
import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.validation.CredentialValidator;
import hirs.attestationca.persist.validation.PcrValidator;
import hirs.attestationca.persist.validation.SupplyChainCredentialValidator;
import hirs.utils.BouncyCastleUtils;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.apache.logging.log4j.Level;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
@Log4j2
@Service
public class SupplyChainValidationServiceImpl implements SupplyChainValidationService {
private CACredentialRepository caCredentialRepository;
private PolicyRepository policyRepository;
private ReferenceManifestRepository referenceManifestRepository;
private ReferenceDigestValueRepository referenceDigestValueRepository;
private ComponentResultRepository componentResultRepository;
private CertificateRepository certificateRepository;
private CredentialValidator supplyChainCredentialValidator;
private SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository;
/**
* Constructor to set just the CertificateRepository, so that cert chain validating
* methods can be called from outside classes.
*
* @param certificateRepository the cert repository
*/
public SupplyChainValidationServiceImpl(final CertificateRepository certificateRepository) {
this.certificateRepository = certificateRepository;
}
/**
* Constructor.
*
* @param caCredentialRepository ca credential repository
* @param policyRepository the policy manager
* @param certificateRepository the cert manager
* @param componentResultRepository the comp result manager
* @param referenceManifestRepository the RIM manager
* @param supplyChainValidationSummaryRepository the summary manager
* @param supplyChainCredentialValidator the credential validator
* @param referenceDigestValueRepository the even manager
*/
@Autowired
@SuppressWarnings("ParameterNumberCheck")
public SupplyChainValidationServiceImpl(
final CACredentialRepository caCredentialRepository,
final PolicyRepository policyRepository,
final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository,
final ReferenceManifestRepository referenceManifestRepository,
final SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository,
final CredentialValidator supplyChainCredentialValidator,
final ReferenceDigestValueRepository referenceDigestValueRepository) {
this.caCredentialRepository = caCredentialRepository;
this.policyRepository = policyRepository;
this.certificateRepository = certificateRepository;
this.componentResultRepository = componentResultRepository;
this.referenceManifestRepository = referenceManifestRepository;
this.supplyChainValidationSummaryRepository = supplyChainValidationSummaryRepository;
this.supplyChainCredentialValidator = supplyChainCredentialValidator;
this.referenceDigestValueRepository = referenceDigestValueRepository;
}
@Override
public SupplyChainValidationSummary validateSupplyChain(final EndorsementCredential ec,
final List<PlatformCredential> pc,
final Device device) {
return null;
}
/**
* A supplemental method that handles validating just the quote post main validation.
*
* @param device the associated device.
* @return True if validation is successful, false otherwise.
*/
@Override
public SupplyChainValidationSummary validateQuote(final Device device) {
SupplyChainValidation quoteScv = null;
SupplyChainValidationSummary summary = null;
Level level = Level.ERROR;
AppraisalStatus fwStatus = new AppraisalStatus(FAIL,
"Unknown exception caught during quote validation.");
SupportReferenceManifest sRim = null;
EventLogMeasurements eventLog = null;
// check if the policy is enabled
if (getPolicySettings().isFirmwareValidationEnabled()) {
String[] baseline = new String[Integer.SIZE];
String deviceName = device.getDeviceInfo()
.getNetworkInfo().getHostname();
try {
List<SupportReferenceManifest> supportRims = referenceManifestRepository.getSupportByManufacturerModel(
device.getDeviceInfo().getHardwareInfo().getManufacturer(),
device.getDeviceInfo().getHardwareInfo().getProductName());
for (SupportReferenceManifest support : supportRims) {
if (support.isBaseSupport()) {
sRim = support;
}
}
eventLog = (EventLogMeasurements) referenceManifestRepository
.findByHexDecHash(sRim.getEventLogHash());
if (sRim == null) {
fwStatus = new AppraisalStatus(FAIL,
String.format("Firmware Quote validation failed: "
+ "No associated Support RIM file "
+ "could be found for %s",
deviceName));
} else if (eventLog == null) {
fwStatus = new AppraisalStatus(FAIL,
String.format("Firmware Quote validation failed: "
+ "No associated Client Log file "
+ "could be found for %s",
deviceName));
} else {
baseline = sRim.getExpectedPCRList();
String[] storedPcrs = eventLog.getExpectedPCRList();
PcrValidator pcrValidator = new PcrValidator(baseline);
// grab the quote
byte[] hash = device.getDeviceInfo().getTpmInfo().getTpmQuoteHash();
if (pcrValidator.validateQuote(hash, storedPcrs, getPolicySettings())) {
level = Level.INFO;
fwStatus = new AppraisalStatus(PASS,
SupplyChainCredentialValidator.FIRMWARE_VALID);
fwStatus.setMessage("Firmware validation of TPM Quote successful.");
} else {
fwStatus.setMessage("Firmware validation of TPM Quote failed."
+ "\nPCR hash and Quote hash do not match.");
}
eventLog.setOverallValidationResult(fwStatus.getAppStatus());
this.referenceManifestRepository.save(eventLog);
}
} catch (Exception ex) {
log.error(ex);
}
quoteScv = buildValidationRecord(SupplyChainValidation
.ValidationType.FIRMWARE,
fwStatus.getAppStatus(), fwStatus.getMessage(), eventLog, level);
// Generate validation summary, save it, and return it.
List<SupplyChainValidation> validations = new ArrayList<>();
SupplyChainValidationSummary previous
= this.supplyChainValidationSummaryRepository.findByDevice(deviceName);
for (SupplyChainValidation scv : previous.getValidations()) {
if (scv.getValidationType() != SupplyChainValidation.ValidationType.FIRMWARE) {
validations.add(buildValidationRecord(scv.getValidationType(),
scv.getValidationResult(), scv.getMessage(),
scv.getCertificatesUsed().get(0), Level.INFO));
}
}
validations.add(quoteScv);
previous.archive();
supplyChainValidationSummaryRepository.save(previous);
summary = new SupplyChainValidationSummary(device, validations);
// try removing the supply chain validation as well and resaving that
try {
supplyChainValidationSummaryRepository.save(summary);
} catch (DBManagerException dbEx) {
log.error("Failed to save Supply Chain Summary", dbEx);
}
}
return summary;
}
/**
* Creates a supply chain validation record and logs the validation message
* at the specified log level.
*
* @param validationType the type of validation
* @param result the appraisal status
* @param message the validation message to include in the summary and log
* @param archivableEntity the archivableEntity associated with the
* validation
* @param logLevel the log level
* @return a SupplyChainValidation
*/
private SupplyChainValidation buildValidationRecord(
final SupplyChainValidation.ValidationType validationType,
final AppraisalStatus.Status result, final String message,
final ArchivableEntity archivableEntity, final Level logLevel) {
List<ArchivableEntity> aeList = new ArrayList<>();
if (archivableEntity != null) {
aeList.add(archivableEntity);
}
log.log(logLevel, message);
return new SupplyChainValidation(validationType, result, aeList, message);
}
/**
* This method is used to retrieve the entire CA chain (up to a trusted
* self-signed certificate) for the given certificate. This method will look
* up CA certificates that have a matching issuer organization as the given
* certificate, and will perform that operation recursively until all
* certificates for all relevant organizations have been retrieved. For that
* reason, the returned set of certificates may be larger than the the
* single trust chain for the queried certificate, but is guaranteed to
* include the trust chain if it exists in this class' CertificateManager.
* Returns the certificate authority credentials in a KeyStore.
*
* @param credential the credential whose CA chain should be retrieved
* @return A keystore containing all relevant CA credentials to the given
* certificate's organization or null if the keystore can't be assembled
*/
public KeyStore getCaChain(final Certificate credential) {
KeyStore caKeyStore = null;
try {
caKeyStore = caCertSetToKeystore(getCaChainRec(credential, Collections.emptySet()));
} catch (KeyStoreException | IOException e) {
log.error("Unable to assemble CA keystore", e);
}
return caKeyStore;
}
/**
* This is a recursive method which is used to retrieve the entire CA chain
* (up to a trusted self-signed certificate) for the given certificate. This
* method will look up CA certificates that have a matching issuer
* organization as the given certificate, and will perform that operation
* recursively until all certificates for all relevant organizations have
* been retrieved. For that reason, the returned set of certificates may be
* larger than the the single trust chain for the queried certificate, but
* is guaranteed to include the trust chain if it exists in this class'
* CertificateManager.
* <p>
* Implementation notes: 1. Queries for CA certs with a subject org matching
* the given (argument's) issuer org 2. Add that org to
* queriedOrganizations, so we don't search for that organization again 3.
* For each returned CA cert, add that cert to the result set, and recurse
* with that as the argument (to go up the chain), if and only if we haven't
* already queried for that organization (which prevents infinite loops on
* certs with an identical subject and issuer org)
*
* @param credential the credential whose CA chain should be retrieved
* @param previouslyQueriedSubjects a list of organizations to refrain
* from querying
* @return a Set containing all relevant CA credentials to the given
* certificate's organization
*/
private Set<CertificateAuthorityCredential> getCaChainRec(
final Certificate credential,
final Set<String> previouslyQueriedSubjects) {
CertificateAuthorityCredential skiCA = null;
List<CertificateAuthorityCredential> certAuthsWithMatchingIssuer = new LinkedList<>();
if (credential.getAuthorityKeyIdentifier() != null
&& !credential.getAuthorityKeyIdentifier().isEmpty()) {
byte[] bytes = Hex.decode(credential.getAuthorityKeyIdentifier());
// CYRUS is SKI unique?
skiCA = caCredentialRepository.findBySubjectKeyIdentifier(bytes);
}
if (skiCA == null) {
if (credential.getIssuerSorted() == null
|| credential.getIssuerSorted().isEmpty()) {
certAuthsWithMatchingIssuer = caCredentialRepository.findBySubject(credential.getIssuer());
} else {
//Get certificates by subject organization
certAuthsWithMatchingIssuer = caCredentialRepository.findBySubjectSorted(credential.getIssuerSorted());
}
} else {
certAuthsWithMatchingIssuer.add(skiCA);
}
Set<String> queriedOrganizations = new HashSet<>(previouslyQueriedSubjects);
queriedOrganizations.add(credential.getIssuer());
HashSet<CertificateAuthorityCredential> caCreds = new HashSet<>();
for (CertificateAuthorityCredential cred : certAuthsWithMatchingIssuer) {
caCreds.add(cred);
if (!BouncyCastleUtils.x500NameCompare(cred.getIssuer(),
cred.getSubject())) {
caCreds.addAll(getCaChainRec(cred, queriedOrganizations));
}
}
return caCreds;
}
private KeyStore caCertSetToKeystore(final Set<CertificateAuthorityCredential> certs)
throws KeyStoreException, IOException {
KeyStore keyStore = KeyStore.getInstance("JKS");
try {
keyStore.load(null, "".toCharArray());
for (Certificate cert : certs) {
keyStore.setCertificateEntry(cert.getId().toString(), cert.getX509Certificate());
}
} catch (IOException | CertificateException | NoSuchAlgorithmException e) {
throw new IOException("Could not create and populate keystore", e);
}
return keyStore;
}
private String[] buildStoredPcrs(final String pcrContent, final int algorithmLength) {
// we have a full set of PCR values
String[] pcrSet = pcrContent.split("\\n");
String[] storedPcrs = new String[TPMMeasurementRecord.MAX_PCR_ID + 1];
// we need to scroll through the entire list until we find
// a matching hash length
int offset = 1;
for (int i = 0; i < pcrSet.length; i++) {
if (pcrSet[i].contains("sha")) {
// entered a new set, check size
if (pcrSet[i + offset].split(":")[1].trim().length()
== algorithmLength) {
// found the matching set
for (int j = 0; j <= TPMMeasurementRecord.MAX_PCR_ID; j++) {
storedPcrs[j] = pcrSet[++i].split(":")[1].trim();
}
break;
}
}
}
return storedPcrs;
}
/**
* Helper function to get a fresh load of the default policy from the DB.
*
* @return The default Supply Chain Policy
*/
private PolicySettings getPolicySettings() {
PolicySettings defaultSettings = this.policyRepository.findByName("Default");
if (defaultSettings == null) {
defaultSettings = new PolicySettings("Default", "Settings are configured for no validation flags set.");
}
return defaultSettings;
}
}

View File

@ -1,4 +1,4 @@
package hirs.attestationca.portal.page.utils;
package hirs.attestationca.persist.util;
import com.github.marandus.pciid.model.Device;
import com.github.marandus.pciid.model.Vendor;

View File

@ -1,19 +1,86 @@
package hirs.attestationca.persist.validation;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.attestationca.persist.enums.AppraisalStatus;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.cert.X509AttributeCertificateHolder;
import java.io.IOException;
import java.security.KeyStore;
import java.util.Map;
import java.security.KeyStoreException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.X509Certificate;
import java.util.Date;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.ERROR;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL;
import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
@Log4j2
public class CredentialValidator extends SupplyChainCredentialValidator {
/**
* Checks if the endorsement credential is valid.
*
* @param ec the endorsement credential to verify.
* @param trustStore trust store holding trusted trusted certificates.
* @param acceptExpired whether or not to accept expired and not yet valid certificates
* as valid.
* @return the result of the validation.
*/
public static AppraisalStatus validateEndorsementCredential(final EndorsementCredential ec,
final KeyStore trustStore,
final boolean acceptExpired) {
final String baseErrorMessage = "Can't validate endorsement credential attributes without ";
String message;
if (ec == null) {
message = baseErrorMessage + "an endorsement credential";
log.error(message);
return new AppraisalStatus(FAIL, message);
}
if (trustStore == null) {
message = baseErrorMessage + "a trust store";
log.error(message);
return new AppraisalStatus(FAIL, message);
}
try {
X509Certificate verifiableCert = ec.getX509Certificate();
// check validity period, currently acceptExpired will also accept not yet
// valid certificates
if (!acceptExpired) {
verifiableCert.checkValidity();
}
if (verifyCertificate(verifiableCert, trustStore)) {
return new AppraisalStatus(PASS, ENDORSEMENT_VALID);
} else {
return new AppraisalStatus(FAIL, "Endorsement credential does not have a valid "
+ "signature chain in the trust store");
}
} catch (IOException e) {
message = "Couldn't retrieve X509 certificate from endorsement credential";
log.error(message, e);
return new AppraisalStatus(ERROR, message + " " + e.getMessage());
} catch (SupplyChainValidatorException e) {
message = "An error occurred indicating the credential is not valid";
log.warn(message, e);
return new AppraisalStatus(ERROR, message + " " + e.getMessage());
} catch (CertificateExpiredException e) {
message = "The endorsement credential is expired";
log.warn(message, e);
return new AppraisalStatus(FAIL, message + " " + e.getMessage());
} catch (CertificateNotYetValidException e) {
message = "The endorsement credential is not yet valid";
log.warn(message, e);
return new AppraisalStatus(FAIL, message + " " + e.getMessage());
}
}
/**
* A class used to support supply chain validation by performing the actual
* validation of credentials.
*/
public interface CredentialValidator {
/**
* Checks if the platform credential is valid.
*
@ -22,47 +89,113 @@ public interface CredentialValidator {
* @param acceptExpired whether or not to accept expired certificates as valid.
* @return The result of the validation.
*/
AppraisalStatus validatePlatformCredential(PlatformCredential pc,
KeyStore trustStore,
boolean acceptExpired);
public static AppraisalStatus validatePlatformCredential(final PlatformCredential pc,
final KeyStore trustStore,
final boolean acceptExpired) {
final String baseErrorMessage = "Can't validate platform credential without ";
String message;
String certVerifyMsg;
if (pc == null) {
message = baseErrorMessage + "a platform credential\n";
log.error(message);
return new AppraisalStatus(FAIL, message);
}
try {
if (trustStore == null || trustStore.size() == 0) {
message = baseErrorMessage + "an Issuer Cert in the Trust Store\n";
log.error(message);
return new AppraisalStatus(FAIL, message);
}
} catch (KeyStoreException e) {
message = baseErrorMessage + "an initialized trust store";
log.error(message);
return new AppraisalStatus(FAIL, message);
}
X509AttributeCertificateHolder attributeCert = null;
try {
attributeCert = pc.getX509AttributeCertificateHolder();
} catch (IOException e) {
message = "Could not retrieve X509 Attribute certificate";
log.error(message, e);
return new AppraisalStatus(FAIL, message + " " + e.getMessage());
}
// check validity period, currently acceptExpired will also accept not yet
// valid certificates
if (!acceptExpired && !pc.isValidOn(new Date())) {
message = "Platform credential has expired";
// if not valid at the current time
log.warn(message);
return new AppraisalStatus(FAIL, message);
}
// verify cert against truststore
try {
certVerifyMsg = verifyCertificate(attributeCert, trustStore);
if (certVerifyMsg.isEmpty()) {
message = PLATFORM_VALID;
log.info(message);
return new AppraisalStatus(PASS, message);
} else {
message = String.format("Platform credential failed verification%n%s",
certVerifyMsg);
log.error(message);
return new AppraisalStatus(FAIL, message);
}
} catch (SupplyChainValidatorException scvEx) {
message = "An error occurred indicating the credential is not valid";
log.warn(message, scvEx);
return new AppraisalStatus(FAIL, message + " " + scvEx.getMessage());
}
}
/**
* Checks if the platform credential's attributes are valid.
* @param pc The platform credential to verify.
* @param deviceInfoReport Report containing the serial numbers of the platform to be validated.
* @param ec The endorsement credential supplied from the same identity request as
* the platform credential.
* @return The result of the validation.
*/
AppraisalStatus validatePlatformCredentialAttributes(PlatformCredential pc,
DeviceInfoReport deviceInfoReport,
EndorsementCredential ec);
/**
* Checks if the delta credential's attributes are valid.
* @param delta the delta credential to verify
* @param platformCredential The platform credential to verify.
* @param deviceInfoReport The device info report containing
* serial number of the platform to be validated.
* @param base the base credential from the same identity request
* as the delta credential.
* @param deltaMapping delta certificates associated with the
* delta supply validation.
* @return the result of the validation.
* @param endorsementCredential The endorsement credential supplied from the same
* identity request as the platform credential.
* @return The result of the validation.
*/
AppraisalStatus validateDeltaPlatformCredentialAttributes(PlatformCredential delta,
DeviceInfoReport deviceInfoReport,
PlatformCredential base,
Map<PlatformCredential,
SupplyChainValidation> deltaMapping);
/**
* Checks if the endorsement credential is valid.
*
* @param ec the endorsement credential to verify.
* @param trustStore trust store holding trusted trusted certificates.
* @param acceptExpired whether or not to accept expired certificates as valid.
* @return the result of the validation.
*/
AppraisalStatus validateEndorsementCredential(EndorsementCredential ec,
KeyStore trustStore,
boolean acceptExpired);
}
public static AppraisalStatus validatePlatformCredentialAttributes(
final PlatformCredential platformCredential,
final DeviceInfoReport deviceInfoReport,
final EndorsementCredential endorsementCredential) {
final String baseErrorMessage = "Can't validate platform credential attributes without ";
String message;
if (platformCredential == null) {
message = baseErrorMessage + "a platform credential";
log.error(message);
return new AppraisalStatus(FAIL, message);
}
if (deviceInfoReport == null) {
message = baseErrorMessage + "a device info report";
log.error(message);
return new AppraisalStatus(FAIL, message);
}
if (endorsementCredential == null) {
message = baseErrorMessage + "an endorsement credential";
log.error(message);
return new AppraisalStatus(FAIL, message);
}
// Quick, early check if the platform credential references the endorsement credential
if (!endorsementCredential.getSerialNumber()
.equals(platformCredential.getHolderSerialNumber())) {
message = "Platform Credential holder serial number does not match "
+ "the Endorsement Credential's serial number";
log.error(message);
return new AppraisalStatus(FAIL, message);
}
String credentialType = platformCredential.getCredentialType();
if (PlatformCredential.CERTIFICATE_TYPE_2_0.equals(credentialType)) {
return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV2p0(
platformCredential, deviceInfoReport);
}
return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV1p2(
platformCredential, deviceInfoReport);
}
}

View File

@ -226,4 +226,30 @@ public class PcrValidator {
return validated;
}
public static String[] buildStoredPcrs(final String pcrContent, final int algorithmLength) {
// we have a full set of PCR values
String[] pcrSet = pcrContent.split("\\n");
String[] storedPcrs = new String[TPMMeasurementRecord.MAX_PCR_ID + 1];
// we need to scroll through the entire list until we find
// a matching hash length
int offset = 1;
for (int i = 0; i < pcrSet.length; i++) {
if (pcrSet[i].contains("sha")) {
// entered a new set, check size
if (pcrSet[i + offset].split(":")[1].trim().length()
== algorithmLength) {
// found the matching set
for (int j = 0; j <= TPMMeasurementRecord.MAX_PCR_ID; j++) {
storedPcrs[j] = pcrSet[++i].split(":")[1].trim();
}
break;
}
}
}
return storedPcrs;
}
}

View File

@ -1,23 +1,50 @@
package hirs.attestationca.persist.validation;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
import hirs.attestationca.persist.enums.AppraisalStatus;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.CertException;
import org.bouncycastle.cert.X509AttributeCertificateHolder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Security;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Log4j2
@NoArgsConstructor
public class SupplyChainCredentialValidator implements CredentialValidator {
public class SupplyChainCredentialValidator {
public static final int NUC_VARIABLE_BIT = 159;
/**
* AppraisalStatus message for a valid endorsement credential appraisal.
*/
@ -39,34 +66,447 @@ public class SupplyChainCredentialValidator implements CredentialValidator {
*/
public static final String FIRMWARE_VALID = "Firmware validated";
private static List<ComponentResult> componentResultList = new LinkedList<>();
/**
* Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
* class expects it to be available.
*/
static {
Security.addProvider(new BouncyCastleProvider());
}
@Override
public AppraisalStatus validatePlatformCredential(final PlatformCredential pc,
final KeyStore trustStore,
final boolean acceptExpired) {
/**
* Attempts to check if the certificate is validated by certificates in a cert chain. The cert
* chain is expected to be stored in a non-ordered KeyStore (trust store). If the signing
* certificate for the target cert is found, but it is an intermediate cert, the validation will
* continue to try to find the signing cert of the intermediate cert. It will continue searching
* until it follows the chain up to a root (self-signed) cert.
*
* @param cert
* certificate to validate
* @param trustStore
* trust store holding trusted root certificates and intermediate certificates
* @return the certificate chain if validation is successful
* @throws SupplyChainValidatorException
* if the verification is not successful
*/
public static String verifyCertificate(final X509AttributeCertificateHolder cert,
final KeyStore trustStore) throws SupplyChainValidatorException {
try {
if (cert == null || trustStore == null) {
throw new SupplyChainValidatorException("Certificate or trust store is null");
} else if (trustStore.size() == 0) {
throw new SupplyChainValidatorException("Truststore is empty");
}
} catch (KeyStoreException e) {
log.error("Error accessing trust store: " + e.getMessage());
}
try {
Set<X509Certificate> trustedCerts = new HashSet<>();
Enumeration<String> alias = trustStore.aliases();
while (alias.hasMoreElements()) {
trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement()));
}
String certChainValidated = validateCertChain(cert, trustedCerts);
if (!certChainValidated.isEmpty()) {
log.error("Cert chain could not be validated");
}
return certChainValidated;
} catch (KeyStoreException e) {
throw new SupplyChainValidatorException("Error with the trust store", e);
}
}
/**
* Attempts to check if the certificate is validated by certificates in a cert chain. The cert
* chain is expected to be stored in a non-ordered KeyStore (trust store). If the signing
* certificate for the target cert is found, but it is an intermediate cert, the validation will
* continue to try to find the signing cert of the intermediate cert. It will continue searching
* until it follows the chain up to a root (self-signed) cert.
*
* @param cert
* certificate to validate
* @param trustStore
* trust store holding trusted root certificates and intermediate certificates
* @return the certificate chain if validation is successful
* @throws SupplyChainValidatorException
* if the verification is not successful
*/
public static boolean verifyCertificate(final X509Certificate cert,
final KeyStore trustStore) throws SupplyChainValidatorException {
try {
if (cert == null || trustStore == null) {
throw new SupplyChainValidatorException("Certificate or trust store is null");
} else if (trustStore.size() == 0) {
throw new SupplyChainValidatorException("Truststore is empty");
}
} catch (KeyStoreException e) {
log.error("Error accessing trust store: " + e.getMessage());
}
try {
Set<X509Certificate> trustedCerts = new HashSet<>();
Enumeration<String> alias = trustStore.aliases();
while (alias.hasMoreElements()) {
trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement()));
}
return validateCertChain(cert, trustedCerts).isEmpty();
} catch (KeyStoreException e) {
log.error("Error accessing keystore", e);
throw new SupplyChainValidatorException("Error with the trust store", e);
}
}
/**
* Attempts to check if an attribute certificate is validated by certificates in a cert chain.
* The cert chain is represented as a Set of X509Certificates. If the signing certificate for
* the target cert is found, but it is an intermediate cert, the validation will continue to try
* to find the signing cert of the intermediate cert. It will continue searching until it
* follows the chain up to a root (self-signed) cert.
*
* @param cert
* certificate to validate
* @param additionalCerts
* Set of certs to validate against
* @return String status of the cert chain validation -
* blank if successful, error message otherwise
* @throws SupplyChainValidatorException tried to validate using null certificates
*/
public static String validateCertChain(final X509AttributeCertificateHolder cert,
final Set<X509Certificate> additionalCerts)
throws SupplyChainValidatorException {
if (cert == null || additionalCerts == null) {
throw new SupplyChainValidatorException(
"Certificate or validation certificates are null");
}
final String intCAError = "Intermediate signing cert found, check for CA cert";
String foundRootOfCertChain = "";
X509Certificate nextInChain = null;
do {
for (X509Certificate trustedCert : additionalCerts) {
boolean issuerMatchesSubject = false;
boolean signatureMatchesPublicKey = false;
if (nextInChain != null) {
issuerMatchesSubject = issuerMatchesSubjectDN(nextInChain, trustedCert);
signatureMatchesPublicKey = signatureMatchesPublicKey(nextInChain,
trustedCert);
} else {
issuerMatchesSubject = issuerMatchesSubjectDN(cert, trustedCert);
signatureMatchesPublicKey = signatureMatchesPublicKey(cert, trustedCert);
}
if (issuerMatchesSubject && signatureMatchesPublicKey) {
if (isSelfSigned(trustedCert)) {
log.info("CA Root found.");
return "";
} else {
foundRootOfCertChain = intCAError;
nextInChain = trustedCert;
break;
}
} else {
if (!issuerMatchesSubject) {
foundRootOfCertChain = "Issuer DN does not match Subject DN";
}
if (!signatureMatchesPublicKey) {
foundRootOfCertChain = "Certificate signature failed to verify";
}
}
}
} while (foundRootOfCertChain.equals(intCAError));
log.error(foundRootOfCertChain);
return foundRootOfCertChain;
}
/**
* Attempts to check if a public-key certificate is validated by certificates in a cert chain.
* The cert chain is represented as a Set of X509Certificates. If the signing certificate for
* the target cert is found, but it is an intermediate cert, the validation will continue to try
* to find the signing cert of the intermediate cert. It will continue searching until it
* follows the chain up to a root (self-signed) cert.
*
* @param cert
* certificate to validate
* @param additionalCerts
* Set of certs to validate against
* @return String status of the cert chain validation -
* blank if successful, error message otherwise
* @throws SupplyChainValidatorException tried to validate using null certificates
*/
public static String validateCertChain(final X509Certificate cert,
final Set<X509Certificate> additionalCerts) throws SupplyChainValidatorException {
if (cert == null || additionalCerts == null) {
throw new SupplyChainValidatorException(
"Certificate or validation certificates are null");
}
final String intCAError = "Intermediate signing cert found, check for CA cert";
String foundRootOfCertChain = "";
X509Certificate startOfChain = cert;
do {
for (X509Certificate trustedCert : additionalCerts) {
boolean issuerMatchesSubject = issuerMatchesSubjectDN(startOfChain, trustedCert);
boolean signatureMatchesPublicKey = signatureMatchesPublicKey(startOfChain,
trustedCert);
if (issuerMatchesSubject && signatureMatchesPublicKey) {
if (isSelfSigned(trustedCert)) {
log.info("CA Root found.");
return "";
} else {
foundRootOfCertChain = intCAError;
startOfChain = trustedCert;
break;
}
} else {
if (!issuerMatchesSubject) {
foundRootOfCertChain = "Issuer DN does not match Subject DN";
}
if (!signatureMatchesPublicKey) {
foundRootOfCertChain = "Certificate signature failed to verify";
}
}
}
} while (foundRootOfCertChain.equals(intCAError));
log.warn(foundRootOfCertChain);
return foundRootOfCertChain;
}
/**
* Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects.
* @param paccorOutput the output from PACCOR's allcomoponents.sh
* @return a list of ComponentInfo objects built from paccorOutput
* @throws java.io.IOException if something goes wrong parsing the JSON
*/
public static List<ComponentInfo> getComponentInfoFromPaccorOutput(final String paccorOutput)
throws IOException {
List<ComponentInfo> componentInfoList = new ArrayList<>();
if (StringUtils.isNotEmpty(paccorOutput)) {
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
JsonNode rootNode = objectMapper.readTree(paccorOutput);
Iterator<JsonNode> jsonComponentNodes
= rootNode.findValue("COMPONENTS").elements();
while (jsonComponentNodes.hasNext()) {
JsonNode next = jsonComponentNodes.next();
componentInfoList.add(new ComponentInfo(
getJSONNodeValueAsText(next, "MANUFACTURER"),
getJSONNodeValueAsText(next, "MODEL"),
getJSONNodeValueAsText(next, "SERIAL"),
getJSONNodeValueAsText(next, "REVISION")));
}
}
return componentInfoList;
}
/**
* Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects.
* @param paccorOutput the output from PACCOR's allcomoponents.sh
* @return a list of ComponentInfo objects built from paccorOutput
* @throws IOException if something goes wrong parsing the JSON
*/
public static List<ComponentInfo> getV2PaccorOutput(
final String paccorOutput) throws IOException {
List<ComponentInfo> ciList = new LinkedList<>();
String manufacturer, model, serial, revision;
String componentClass = Strings.EMPTY;
if (StringUtils.isNotEmpty(paccorOutput)) {
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
JsonNode rootNode = objectMapper.readTree(paccorOutput);
Iterator<JsonNode> jsonComponentNodes
= rootNode.findValue("COMPONENTS").elements();
while (jsonComponentNodes.hasNext()) {
JsonNode next = jsonComponentNodes.next();
manufacturer = getJSONNodeValueAsText(next, "MANUFACTURER");
model = getJSONNodeValueAsText(next, "MODEL");
serial = getJSONNodeValueAsText(next, "SERIAL");
revision = getJSONNodeValueAsText(next, "REVISION");
List<JsonNode> compClassNodes = next.findValues("COMPONENTCLASS");
for (JsonNode subNode : compClassNodes) {
componentClass = getJSONNodeValueAsText(subNode,
"COMPONENTCLASSVALUE");
}
ciList.add(new ComponentInfo(manufacturer, model,
serial, revision, componentClass));
}
}
return ciList;
}
private static String getJSONNodeValueAsText(final JsonNode node, final String fieldName) {
if (node.hasNonNull(fieldName)) {
return node.findValue(fieldName).asText();
}
return null;
}
@Override
public AppraisalStatus validatePlatformCredentialAttributes(final PlatformCredential pc,
final DeviceInfoReport deviceInfoReport,
final EndorsementCredential ec) {
return null;
/**
* Checks if the issuer info of an attribute cert matches the supposed signing cert's
* distinguished name.
*
* @param cert
* the attribute certificate with the signature to validate
* @param signingCert
* the certificate with the public key to validate
* @return boolean indicating if the names
* @throws SupplyChainValidatorException tried to validate using null certificates
*/
public static boolean issuerMatchesSubjectDN(final X509AttributeCertificateHolder cert,
final X509Certificate signingCert) throws SupplyChainValidatorException {
if (cert == null || signingCert == null) {
throw new SupplyChainValidatorException("Certificate or signing certificate is null");
}
String signingCertSubjectDN = signingCert.getSubjectX500Principal().getName();
X500Name namedSubjectDN = new X500Name(signingCertSubjectDN);
X500Name issuerDN = cert.getIssuer().getNames()[0];
// equality check ignore DN component ordering
return issuerDN.equals(namedSubjectDN);
}
@Override
public AppraisalStatus validateDeltaPlatformCredentialAttributes(final PlatformCredential delta,
final DeviceInfoReport deviceInfoReport,
final PlatformCredential base,
final Map<PlatformCredential, SupplyChainValidation> deltaMapping) {
return null;
/**
* Checks if the issuer info of a public-key cert matches the supposed signing cert's
* distinguished name.
*
* @param cert
* the public-key certificate with the signature to validate
* @param signingCert
* the certificate with the public key to validate
* @return boolean indicating if the names
* @throws SupplyChainValidatorException tried to validate using null certificates
*/
public static boolean issuerMatchesSubjectDN(final X509Certificate cert,
final X509Certificate signingCert) throws SupplyChainValidatorException {
if (cert == null || signingCert == null) {
throw new SupplyChainValidatorException("Certificate or signing certificate is null");
}
String signingCertSubjectDN = signingCert.getSubjectX500Principal().
getName(X500Principal.RFC1779);
X500Name namedSubjectDN = new X500Name(signingCertSubjectDN);
String certIssuerDN = cert.getIssuerX500Principal().getName();
X500Name namedIssuerDN = new X500Name(certIssuerDN);
// equality check ignore DN component ordering
return namedIssuerDN.equals(namedSubjectDN);
}
@Override
public AppraisalStatus validateEndorsementCredential(final EndorsementCredential ec,
final KeyStore trustStore,
final boolean acceptExpired) {
return null;
/**
* Checks if the signature of an attribute cert is validated against the signing cert's public
* key.
*
* @param cert
* the public-key certificate with the signature to validate
* @param signingCert
* the certificate with the public key to validate
* @return boolean indicating if the validation passed
* @throws SupplyChainValidatorException tried to validate using null certificates
*/
public static boolean signatureMatchesPublicKey(final X509Certificate cert,
final X509Certificate signingCert) throws SupplyChainValidatorException {
if (cert == null || signingCert == null) {
throw new SupplyChainValidatorException("Certificate or signing certificate is null");
}
try {
cert.verify(signingCert.getPublicKey(), BouncyCastleProvider.PROVIDER_NAME);
return true;
} catch (InvalidKeyException e) {
log.info("Incorrect key given to validate this cert's signature");
} catch (CertificateException e) {
log.info("Encoding error while validating this cert's signature");
} catch (NoSuchAlgorithmException e) {
log.info("Unsupported signature algorithm found during validation");
} catch (NoSuchProviderException e) {
log.info("Incorrect provider for cert signature validation");
} catch (SignatureException e) {
log.info(String.format("%s.verify(%s)", cert.getSubjectX500Principal(),
signingCert.getSubjectX500Principal()));
}
return false;
}
/**
* Checks if the signature of a public-key cert is validated against the signing cert's public
* key.
*
* @param cert
* the attribute certificate with the signature to validate
* @param signingCert
* the certificate with the public key to validate
* @return boolean indicating if the validation passed
* @throws SupplyChainValidatorException tried to validate using null certificates
*/
public static boolean signatureMatchesPublicKey(final X509AttributeCertificateHolder cert,
final X509Certificate signingCert) throws SupplyChainValidatorException {
if (signingCert == null) {
throw new SupplyChainValidatorException("Signing certificate is null");
}
return signatureMatchesPublicKey(cert, signingCert.getPublicKey());
}
/**
* Checks if an X509 Attribute Certificate is valid directly against a public key.
*
* @param cert
* the attribute certificate with the signature to validate
* @param signingKey
* the key to use to check the attribute cert
* @return boolean indicating if the validation passed
* @throws SupplyChainValidatorException tried to validate using null certificates
*/
public static boolean signatureMatchesPublicKey(final X509AttributeCertificateHolder cert,
final PublicKey signingKey) throws SupplyChainValidatorException {
if (cert == null || signingKey == null) {
throw new SupplyChainValidatorException("Certificate or signing certificate is null");
}
ContentVerifierProvider contentVerifierProvider;
try {
contentVerifierProvider =
new JcaContentVerifierProviderBuilder().setProvider("BC").build(signingKey);
return cert.isSignatureValid(contentVerifierProvider);
} catch (OperatorCreationException | CertException e) {
log.info("Exception thrown while verifying certificate", e);
log.info(String.format("%s.isSignatureValid(%s)", cert.getSerialNumber(),
signingKey.getFormat()));
return false;
}
}
/**
* Checks whether given X.509 public-key certificate is self-signed. If the cert can be
* verified using its own public key, that means it was self-signed.
*
* @param cert
* X.509 Certificate
* @return boolean indicating if the cert was self-signed
*/
private static boolean isSelfSigned(final X509Certificate cert)
throws SupplyChainValidatorException {
if (cert == null) {
throw new SupplyChainValidatorException("Certificate is null");
}
try {
PublicKey key = cert.getPublicKey();
cert.verify(key);
return true;
} catch (SignatureException | InvalidKeyException e) {
return false;
} catch (CertificateException | NoSuchAlgorithmException | NoSuchProviderException e) {
log.error("Exception occurred while checking if cert is self-signed", e);
return false;
}
}
}

View File

@ -1,6 +1,7 @@
package hirs.attestationca.portal.page.controllers;
import hirs.attestationca.persist.DBServiceException;
import hirs.attestationca.persist.entity.manager.CACredentialRepository;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
@ -10,14 +11,14 @@ import hirs.attestationca.persist.entity.userdefined.rim.BaseReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import hirs.attestationca.persist.service.SupplyChainValidationServiceImpl;
import hirs.attestationca.persist.service.ValidationManager;
import hirs.attestationca.persist.validation.ReferenceManifestValidator;
import hirs.attestationca.persist.validation.SupplyChainCredentialValidator;
import hirs.attestationca.persist.validation.SupplyChainValidatorException;
import hirs.attestationca.portal.page.Page;
import hirs.attestationca.portal.page.PageController;
import hirs.attestationca.portal.page.PageMessages;
import hirs.attestationca.portal.page.params.ReferenceManifestDetailsPageParams;
import hirs.attestationca.portal.page.utils.SupplyChainCredentialValidator;
import hirs.utils.SwidResource;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
@ -52,6 +53,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
private final ReferenceManifestRepository referenceManifestRepository;
private final ReferenceDigestValueRepository referenceDigestValueRepository;
private final CertificateRepository certificateRepository;
private final CACredentialRepository caCertificateRepository;
private static final ReferenceManifestValidator RIM_VALIDATOR
= new ReferenceManifestValidator();
@ -61,15 +63,18 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
* @param referenceManifestRepository the repository for RIM.
* @param referenceDigestValueRepository the reference event manager.
* @param certificateRepository the certificate manager.
* @param caCertificateRepository the CA certificate manager.
*/
@Autowired
public ReferenceManifestDetailsPageController(final ReferenceManifestRepository referenceManifestRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository,
final CertificateRepository certificateRepository) {
final CertificateRepository certificateRepository,
final CACredentialRepository caCertificateRepository) {
super(Page.RIM_DETAILS);
this.referenceManifestRepository = referenceManifestRepository;
this.referenceDigestValueRepository = referenceDigestValueRepository;
this.certificateRepository = certificateRepository;
this.caCertificateRepository = caCertificateRepository;
}
/**
@ -100,7 +105,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
try {
UUID uuid = UUID.fromString(params.getId());
data.putAll(getRimDetailInfo(uuid, referenceManifestRepository,
referenceDigestValueRepository, certificateRepository));
referenceDigestValueRepository, certificateRepository,
caCertificateRepository));
} catch (IllegalArgumentException iaEx) {
String uuidError = "Failed to parse ID from: " + params.getId();
messages.addError(uuidError);
@ -130,6 +136,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
* @param referenceManifestRepository the reference manifest manager.
* @param referenceDigestValueRepository the reference event manager.
* @param certificateRepository the certificate manager.
* @param caCertificateRepository the certificate manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
@ -138,7 +145,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
public static HashMap<String, Object> getRimDetailInfo(final UUID uuid,
final ReferenceManifestRepository referenceManifestRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository,
final CertificateRepository certificateRepository)
final CertificateRepository certificateRepository,
final CACredentialRepository caCertificateRepository)
throws IOException,
CertificateException, NoSuchAlgorithmException {
HashMap<String, Object> data = new HashMap<>();
@ -146,7 +154,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
BaseReferenceManifest bRim = referenceManifestRepository.getBaseRimEntityById(uuid);
if (bRim != null) {
data.putAll(getBaseRimInfo(bRim, referenceManifestRepository, certificateRepository));
data.putAll(getBaseRimInfo(bRim, referenceManifestRepository, certificateRepository, caCertificateRepository));
}
SupportReferenceManifest sRim = referenceManifestRepository.getSupportRimEntityById(uuid);
@ -172,6 +180,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
* @param baseRim established ReferenceManifest Type.
* @param referenceManifestRepository the reference manifest manager.
* @param certificateRepository the certificate manager.
* @param caCertificateRepository the certificate manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
@ -180,7 +189,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
private static HashMap<String, Object> getBaseRimInfo(
final BaseReferenceManifest baseRim,
final ReferenceManifestRepository referenceManifestRepository,
final CertificateRepository certificateRepository)
final CertificateRepository certificateRepository,
final CACredentialRepository caCertificateRepository)
throws IOException, CertificateException, NoSuchAlgorithmException {
HashMap<String, Object> data = new HashMap<>();
@ -288,9 +298,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
//Report invalid signature unless RIM_VALIDATOR validates it and cert path is valid
data.put("signatureValid", false);
for (CertificateAuthorityCredential cert : certificates) {
SupplyChainValidationServiceImpl scvsImpl =
new SupplyChainValidationServiceImpl(certificateRepository);
KeyStore keystore = scvsImpl.getCaChain(cert);
KeyStore keystore = ValidationManager.getCaChain(cert, caCertificateRepository);
if (RIM_VALIDATOR.validateXmlSignature(cert)) {
try {
if (SupplyChainCredentialValidator.verifyCertificate(

View File

@ -12,6 +12,7 @@ import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredent
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration;
import hirs.utils.BouncyCastleUtils;
import hirs.attestationca.persist.util.PciIds;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;

View File

@ -23,7 +23,7 @@ public class UefiGuid {
*/
private static final int UUID_EPOCH_DIVISOR = 10000;
private static final Path JSON_PATH = FileSystems.getDefault().getPath("/opt",
private static final Path JSON_PATH = FileSystems.getDefault().getPath("/etc",
"hirs/aca", "default-properties", "vendor-table.json");
private JsonObject uefiVendorRef;
/**