On a previous commit, I removed a piece of code that checked the base credential first. Because the delta fixed a problem in the base, the base failed before the delta was checked. This was completely removed. On a test that we had previously done, the test passes when it should fail because there is only a base, so that check isn't being done. This change reintroduces the check but in a different location with flags for when there is a delta present.

This commit is contained in:
Cyrus 2021-02-09 13:30:37 -05:00
parent 69cd06df3b
commit 9917fadef7
3 changed files with 85 additions and 43 deletions

View File

@ -133,6 +133,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
boolean acceptExpiredCerts = policy.isExpiredCertificateValidationEnabled(); boolean acceptExpiredCerts = policy.isExpiredCertificateValidationEnabled();
PlatformCredential baseCredential = null; PlatformCredential baseCredential = null;
SupplyChainValidation platformScv = null; SupplyChainValidation platformScv = null;
boolean chkDeltas = false;
String pcErrorMessage = ""; String pcErrorMessage = "";
List<SupplyChainValidation> validations = new LinkedList<>(); List<SupplyChainValidation> validations = new LinkedList<>();
Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>(); Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>();
@ -174,6 +175,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
if (pc.isBase()) { if (pc.isBase()) {
baseCredential = pc; baseCredential = pc;
} else { } else {
chkDeltas = true;
deltaMapping.put(pc, null); deltaMapping.put(pc, null);
} }
pc.setDevice(device); pc.setDevice(device);
@ -214,13 +216,23 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
&& pcErrorMessage.isEmpty()) { && pcErrorMessage.isEmpty()) {
// Ensure there are platform credentials to validate // Ensure there are platform credentials to validate
SupplyChainValidation attributeScv = null; SupplyChainValidation attributeScv = null;
String attrErrorMessage = "";
List<ArchivableEntity> aes = new ArrayList<>(); 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(buildValidationRecord(
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
AppraisalStatus.Status.FAIL,
"Base Platform credential missing."
+ " Cannot validate attributes",
null, Level.ERROR));
} else {
if (chkDeltas) {
if (platformScv != null) { if (platformScv != null) {
aes.addAll(platformScv.getCertificatesUsed()); aes.addAll(platformScv.getCertificatesUsed());
} }
Iterator<PlatformCredential> it = pcs.iterator(); Iterator<PlatformCredential> it = pcs.iterator();
String attrErrorMessage = "";
while (it.hasNext()) { while (it.hasNext()) {
PlatformCredential pc = it.next(); PlatformCredential pc = it.next();
if (pc != null) { if (pc != null) {
@ -235,12 +247,23 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
} }
} }
} }
} else {
aes.add(baseCredential);
validations.remove(platformScv);
// if there are no deltas, just check base credential
platformScv = validatePlatformCredentialAttributes(
baseCredential, device.getDeviceInfo(), ec);
validations.add(new SupplyChainValidation(
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
platformScv.getResult(), aes, platformScv.getMessage()));
}
}
if (!attrErrorMessage.isEmpty()) { if (!attrErrorMessage.isEmpty()) {
//combine platform and platform attributes //combine platform and platform attributes
validations.remove(platformScv); validations.remove(platformScv);
if (platformScv != null) { if (platformScv != null) {
validations.add(new SupplyChainValidation( validations.add(new SupplyChainValidation(
platformScv.getValidationType(), SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
attributeScv.getResult(), aes, attributeScv.getMessage())); attributeScv.getResult(), aes, attributeScv.getMessage()));
} }
} }
@ -252,7 +275,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
validations.add(validateFirmware(device, policy.getPcrPolicy())); validations.add(validateFirmware(device, policy.getPcrPolicy()));
} }
LOGGER.error("The service finished and now summarizing"); LOGGER.info("The service finished and now summarizing");
// Generate validation summary, save it, and return it. // Generate validation summary, save it, and return it.
SupplyChainValidationSummary summary SupplyChainValidationSummary summary
= new SupplyChainValidationSummary(device, validations); = new SupplyChainValidationSummary(device, validations);
@ -662,6 +685,10 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
return buildValidationRecord(validationType, PASS, return buildValidationRecord(validationType, PASS,
result.getMessage(), pc, Level.INFO); result.getMessage(), pc, Level.INFO);
case FAIL: case FAIL:
if (!result.getAdditionalInfo().isEmpty()) {
pc.setComponentFailures(result.getAdditionalInfo());
this.certificateManager.update(pc);
}
return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL, return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL,
result.getMessage(), pc, Level.WARN); result.getMessage(), pc, Level.WARN);
case ERROR: case ERROR:

View File

@ -74,6 +74,7 @@ public class ComponentIdentifier {
private ASN1ObjectIdentifier componentManufacturerId; private ASN1ObjectIdentifier componentManufacturerId;
private ASN1Boolean fieldReplaceable; private ASN1Boolean fieldReplaceable;
private List<ComponentAddress> componentAddress; private List<ComponentAddress> componentAddress;
private boolean validationResult = true;
/** /**
* Default constructor. * Default constructor.
@ -264,6 +265,24 @@ public class ComponentIdentifier {
return false; return false;
} }
/**
* Holds the status of the validation process for attributes
* specific to this instance.
* @return true is passed, false if failed.
*/
public boolean isValidationResult() {
return validationResult;
}
/**
* Sets the flag for the validation status for this instance
* of the attribute.
* @param validationResult validation flag.
*/
public void setValidationResult(final boolean validationResult) {
this.validationResult = validationResult;
}
/** /**
* Get all the component addresses inside the sequence. * Get all the component addresses inside the sequence.
* *

View File

@ -95,8 +95,6 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
*/ */
public static final String FIRMWARE_VALID = "Firmware validated"; public static final String FIRMWARE_VALID = "Firmware validated";
private static final Map<PlatformCredential, StringBuilder> DELTA_FAILURES = new HashMap<>();
/* /*
* Ensure that BouncyCastle is configured as a javax.security.Security provider, as this * Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
* class expects it to be available. * class expects it to be available.
@ -318,8 +316,6 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
final Map<PlatformCredential, SupplyChainValidation> deltaMapping) { final Map<PlatformCredential, SupplyChainValidation> deltaMapping) {
String message; String message;
LOGGER.error("Starting the method validateDeltaPlatformCredentialAttributes");
// this needs to be a loop for all deltas, link to issue #110 // this needs to be a loop for all deltas, link to issue #110
// check that they don't have the same serial number // check that they don't have the same serial number
for (PlatformCredential delta : deltaMapping.keySet()) { for (PlatformCredential delta : deltaMapping.keySet()) {
@ -342,7 +338,6 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
} }
} }
LOGGER.error("This is before validateDeltaAttributesChainV2p0");
// parse out the provided delta and its specific chain. // parse out the provided delta and its specific chain.
List<ComponentIdentifier> origPcComponents List<ComponentIdentifier> origPcComponents
= new LinkedList<>(basePlatformCredential.getComponentIdentifiers()); = new LinkedList<>(basePlatformCredential.getComponentIdentifiers());
@ -560,9 +555,15 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage()); return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage());
} }
StringBuilder additionalInfo = new StringBuilder();
if (!fieldValidation) { if (!fieldValidation) {
resultMessage.append("There are unmatched components:\n"); resultMessage.append("There are unmatched components:\n");
resultMessage.append(unmatchedComponents); resultMessage.append(unmatchedComponents);
// pass information of which ones failed in additionInfo
for (ComponentIdentifier ci : validPcComponents) {
additionalInfo.append(String.format("%d;", ci.hashCode()));
}
} }
passesValidation &= fieldValidation; passesValidation &= fieldValidation;
@ -570,7 +571,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
if (passesValidation) { if (passesValidation) {
return new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID); return new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID);
} else { } else {
return new AppraisalStatus(FAIL, resultMessage.toString()); return new AppraisalStatus(FAIL, resultMessage.toString(), additionalInfo.toString());
} }
} }
@ -635,6 +636,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
// finished up // finished up
List<ArchivableEntity> certificateList = null; List<ArchivableEntity> certificateList = null;
SupplyChainValidation scv = null; SupplyChainValidation scv = null;
StringBuilder deltaSb = new StringBuilder();
// non-empty serial values // non-empty serial values
for (ComponentIdentifier deltaCi : leftOverDeltas) { for (ComponentIdentifier deltaCi : leftOverDeltas) {
@ -653,6 +655,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
if (ciV2.isAdded()) { if (ciV2.isAdded()) {
// error // error
resultMessage.append("ADDED attempted with prior instance\n"); resultMessage.append("ADDED attempted with prior instance\n");
deltaSb.append(String.format("%s;", ci.hashCode()));
} }
if (ciV2.isModified()) { if (ciV2.isModified()) {
// since the base list doesn't have this ci // since the base list doesn't have this ci
@ -680,19 +683,21 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
// error because you can't modify something // error because you can't modify something
// that isn't here // that isn't here
resultMessage.append("MODIFIED attempted without prior instance\n"); resultMessage.append("MODIFIED attempted without prior instance\n");
deltaSb.append(String.format("%s;", ci.hashCode()));
} }
if (ciV2.isRemoved()) { if (ciV2.isRemoved()) {
// error because you can't remove something // error because you can't remove something
// that isn't here // that isn't here
resultMessage.append("REMOVED attempted without prior instance\n"); resultMessage.append("REMOVED attempted without prior instance\n");
deltaSb.append(String.format("%s;", ci.hashCode()));
} }
} }
} }
} }
if (!fieldValidation) { if (!fieldValidation) {
return new AppraisalStatus(FAIL, resultMessage.toString()); return new AppraisalStatus(FAIL, resultMessage.toString(), deltaSb.toString());
} }
String paccorOutputString = deviceInfoReport.getPaccorOutputString(); String paccorOutputString = deviceInfoReport.getPaccorOutputString();
@ -766,7 +771,6 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
if (!subCompInfoList.isEmpty()) { if (!subCompInfoList.isEmpty()) {
for (ComponentInfo ci : subCompInfoList) { for (ComponentInfo ci : subCompInfoList) {
LOGGER.error("For subComInfoList -> {}", ci.getComponentSerial());
invalidDeviceInfo.append(String.format("%d;", invalidDeviceInfo.append(String.format("%d;",
ci.hashCode())); ci.hashCode()));
} }
@ -783,6 +787,8 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
* components not represented in the platform credential. * components not represented in the platform credential.
* *
* @param untrimmedPcComponents the platform credential components (may contain end whitespace) * @param untrimmedPcComponents the platform credential components (may contain end whitespace)
* **NEW** this is updated with just the unmatched components
* if there are any failures, otherwise it remains unchanged.
* @param allDeviceInfoComponents the device info report components * @param allDeviceInfoComponents the device info report components
* @return true if validation passes * @return true if validation passes
*/ */
@ -813,8 +819,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
componentSerial, componentRevision, componentSerial, componentRevision,
component.getComponentManufacturerId(), component.getComponentManufacturerId(),
component.getFieldReplaceable(), component.getFieldReplaceable(),
component.getComponentAddress() component.getComponentAddress()));
));
} }
LOGGER.info("Validating the following Platform Cert components..."); LOGGER.info("Validating the following Platform Cert components...");
@ -822,8 +827,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
LOGGER.info("...against the the following DeviceInfoReport components:"); LOGGER.info("...against the the following DeviceInfoReport components:");
allDeviceInfoComponents.forEach(component -> LOGGER.info(component.toString())); allDeviceInfoComponents.forEach(component -> LOGGER.info(component.toString()));
Set<DERUTF8String> manufacturerSet = new HashSet<>(); Set<DERUTF8String> manufacturerSet = new HashSet<>();
pcComponents.forEach(component -> manufacturerSet.add( pcComponents.forEach(pcComp -> manufacturerSet.add(pcComp.getComponentManufacturer()));
component.getComponentManufacturer()));
// Create a list for unmatched components across all manufacturers to display at the end. // Create a list for unmatched components across all manufacturers to display at the end.
List<ComponentIdentifier> pcUnmatchedComponents = new ArrayList<>(); List<ComponentIdentifier> pcUnmatchedComponents = new ArrayList<>();
@ -859,8 +863,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
.filter(componentInfo .filter(componentInfo
-> StringUtils.isNotEmpty(componentInfo.getComponentSerial())) -> StringUtils.isNotEmpty(componentInfo.getComponentSerial()))
.filter(componentInfo -> componentInfo.getComponentSerial() .filter(componentInfo -> componentInfo.getComponentSerial()
.equals(pcComponent.getComponentSerial().getString())) .equals(pcComponent.getComponentSerial().getString())).findFirst();
.findFirst();
if (first.isPresent()) { if (first.isPresent()) {
ComponentInfo potentialMatch = first.get(); ComponentInfo potentialMatch = first.get();
@ -905,12 +908,11 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
// just match them. // just match them.
List<ComponentIdentifier> templist = new ArrayList<>(pcComponentsFromManufacturer); List<ComponentIdentifier> templist = new ArrayList<>(pcComponentsFromManufacturer);
for (ComponentIdentifier ci : templist) { for (ComponentIdentifier ci : templist) {
ComponentIdentifier pcComponent = ci;
Iterator<ComponentInfo> diComponentIter Iterator<ComponentInfo> diComponentIter
= deviceInfoComponentsFromManufacturer.iterator(); = deviceInfoComponentsFromManufacturer.iterator();
while (diComponentIter.hasNext()) { while (diComponentIter.hasNext()) {
ComponentInfo potentialMatch = diComponentIter.next(); ComponentInfo potentialMatch = diComponentIter.next();
if (isMatch(pcComponent, potentialMatch)) { if (isMatch(ci, potentialMatch)) {
pcComponentsFromManufacturer.remove(ci); pcComponentsFromManufacturer.remove(ci);
diComponentIter.remove(); diComponentIter.remove();
} }
@ -920,6 +922,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
} }
if (!pcUnmatchedComponents.isEmpty()) { if (!pcUnmatchedComponents.isEmpty()) {
untrimmedPcComponents.clear();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
LOGGER.error(String.format("Platform Credential contained %d unmatched components:", LOGGER.error(String.format("Platform Credential contained %d unmatched components:",
pcUnmatchedComponents.size())); pcUnmatchedComponents.size()));
@ -933,6 +936,8 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
unmatchedComponent.getComponentModel(), unmatchedComponent.getComponentModel(),
unmatchedComponent.getComponentSerial(), unmatchedComponent.getComponentSerial(),
unmatchedComponent.getComponentRevision())); unmatchedComponent.getComponentRevision()));
unmatchedComponent.setValidationResult(false);
untrimmedPcComponents.add(unmatchedComponent);
} }
return sb.toString(); return sb.toString();
} }
@ -1664,13 +1669,4 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
return false; return false;
} }
} }
/**
* Getter for the collection of delta certificates that have failed and the
* associated message.
* @return unmodifiable list of failed certificates
*/
public Map<PlatformCredential, StringBuilder> getDeltaFailures() {
return Collections.unmodifiableMap(DELTA_FAILURES);
}
} }