mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-18 20:47:58 +00:00
* This code adds functionality to check the delta certificates in a chain. The main operation validates that the delta belongs in that chain and then that the chain establishes correct component modification. No removes before an add, no add to a component that exists, no remove to a component that doesn't exist. The unit test was updated to not use any flat file certificate. Closes #109 * Changes were made to the validation of a delta certificate based on newer information. There can be multiple bases and multiple leaves in a tree of associated certificates. However currently we don't have certificates to validate the entirety of the code to test. * Updated the code to treat the platform attributes policy, if v2, against all in the chain rather than one at a time.
This commit is contained in:
parent
75b84c8801
commit
157dcb649d
@ -16,6 +16,10 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.HashMap;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import hirs.appraiser.Appraiser;
|
||||
@ -101,8 +105,8 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
boolean acceptExpiredCerts = policy.isExpiredCertificateValidationEnabled();
|
||||
HashMap<PlatformCredential, SupplyChainValidation> credentialMap = new HashMap<>();
|
||||
PlatformCredential baseCredential = null;
|
||||
|
||||
List<SupplyChainValidation> validations = new ArrayList<>();
|
||||
List<SupplyChainValidation> validations = new LinkedList<>();
|
||||
Map<String, Boolean> multiBaseCheckMap = new HashMap<>();
|
||||
|
||||
// validate all supply chain pieces. Potentially, a policy setting could be made
|
||||
// to dictate stopping after the first validation failure.
|
||||
@ -133,19 +137,39 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
KeyStore trustedCa = getCaChain(pc);
|
||||
SupplyChainValidation platformScv = validatePlatformCredential(
|
||||
pc, trustedCa, acceptExpiredCerts);
|
||||
|
||||
// check if this cert has been verified for multiple base associated
|
||||
// with the serial number
|
||||
if (pc != null) {
|
||||
boolean checked = multiBaseCheckMap.containsKey(pc.getPlatformSerial());
|
||||
if (!checked) {
|
||||
// if not checked, update the map
|
||||
boolean result = checkForMultipleBaseCredentials(
|
||||
pc.getPlatformSerial());
|
||||
multiBaseCheckMap.put(pc.getPlatformSerial(), result);
|
||||
// if it is, then update the SupplyChainValidation message and result
|
||||
if (result) {
|
||||
String message = "Multiple Base certificates found in chain.";
|
||||
if (!platformScv.getResult()
|
||||
.equals(AppraisalStatus.Status.PASS)) {
|
||||
message = String.format("%s,%n%s",
|
||||
platformScv.getMessage(), message);
|
||||
}
|
||||
platformScv = buildValidationRecord(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.FAIL,
|
||||
message, pc, Level.ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
validations.add(platformScv);
|
||||
if (null != pc) {
|
||||
if (pc != null) {
|
||||
pc.setDevice(device);
|
||||
this.certificateManager.update(pc);
|
||||
credentialMap.put(pc, platformScv);
|
||||
/*
|
||||
* This method will be added to PlatformCredential to return whether a given
|
||||
* object is a base or a delta credential.
|
||||
*/
|
||||
/* if (pc.isBase()) {
|
||||
if (pc.isBase()) {
|
||||
baseCredential = pc;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -165,13 +189,27 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
Iterator<PlatformCredential> it = pcs.iterator();
|
||||
while (it.hasNext()) {
|
||||
PlatformCredential pc = it.next();
|
||||
SupplyChainValidation attributeScv = null;
|
||||
if (pc == baseCredential || baseCredential == null) {
|
||||
SupplyChainValidation attributeScv;
|
||||
if (baseCredential == null || pc == baseCredential && !pc.isDeltaChain()) {
|
||||
attributeScv = validatePlatformCredentialAttributes(
|
||||
pc, device.getDeviceInfo(), ec);
|
||||
} else {
|
||||
List<PlatformCredential> chainCertificates = PlatformCredential
|
||||
.select(certificateManager)
|
||||
.byBoardSerialNumber(pc.getPlatformSerial())
|
||||
.getCertificates().stream().collect(Collectors.toList());
|
||||
Collections.sort(chainCertificates,
|
||||
new Comparator<PlatformCredential>() {
|
||||
@Override
|
||||
public int compare(final PlatformCredential obj1,
|
||||
final PlatformCredential obj2) {
|
||||
return obj1.getBeginValidity()
|
||||
.compareTo(obj2.getBeginValidity());
|
||||
}
|
||||
});
|
||||
|
||||
attributeScv = validateDeltaPlatformCredentialAttributes(
|
||||
pc, device.getDeviceInfo(), baseCredential);
|
||||
pc, device.getDeviceInfo(), baseCredential, chainCertificates);
|
||||
}
|
||||
|
||||
SupplyChainValidation platformScv = credentialMap.get(pc);
|
||||
@ -191,7 +229,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
}
|
||||
}
|
||||
|
||||
if (null != pc) {
|
||||
if (pc != null) {
|
||||
pc.setDevice(device);
|
||||
this.certificateManager.update(pc);
|
||||
}
|
||||
@ -306,22 +344,21 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
private SupplyChainValidation validateDeltaPlatformCredentialAttributes(
|
||||
final PlatformCredential delta,
|
||||
final DeviceInfoReport deviceInfoReport,
|
||||
final PlatformCredential base) {
|
||||
/*
|
||||
* Do we need a new ValidationType for deltas?
|
||||
*/
|
||||
final PlatformCredential base,
|
||||
final List<PlatformCredential> chainCertificates) {
|
||||
final SupplyChainValidation.ValidationType validationType =
|
||||
SupplyChainValidation.ValidationType.DELTA_PLATFORM_CREDENTIAL_ATTRIBUTES;
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES;
|
||||
|
||||
if (delta == null) {
|
||||
LOGGER.error("No delta credential to validate");
|
||||
LOGGER.error("No delta certificate to validate");
|
||||
return buildValidationRecord(validationType,
|
||||
AppraisalStatus.Status.FAIL, "Platform credential is missing",
|
||||
AppraisalStatus.Status.FAIL, "Delta platform certificate is missing",
|
||||
null, Level.ERROR);
|
||||
}
|
||||
LOGGER.info("Validating platform credential attributes");
|
||||
LOGGER.info("Validating delta platform certificate attributes");
|
||||
AppraisalStatus result = supplyChainCredentialValidator.
|
||||
validateDeltaPlatformCredentialAttributes(delta, deviceInfoReport, base);
|
||||
validateDeltaPlatformCredentialAttributes(delta, deviceInfoReport,
|
||||
base, chainCertificates);
|
||||
switch (result.getAppStatus()) {
|
||||
case PASS:
|
||||
return buildValidationRecord(validationType, AppraisalStatus.Status.PASS,
|
||||
@ -354,7 +391,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
final Certificate certificate, final Level logLevel) {
|
||||
|
||||
List<Certificate> certificateList = new ArrayList<>();
|
||||
if (null != certificate) {
|
||||
if (certificate != null) {
|
||||
certificateList.add(certificate);
|
||||
}
|
||||
|
||||
@ -373,7 +410,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
* Returns the certificate authority credentials in a KeyStore.
|
||||
*
|
||||
* @param credential the credential whose CA chain should be retrieved
|
||||
* @return A keystore ontaining all relevant CA credentials to the given certificate's
|
||||
* @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) {
|
||||
@ -443,4 +480,26 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
private boolean checkForMultipleBaseCredentials(final String platformSerialNumber) {
|
||||
boolean multiple = false;
|
||||
PlatformCredential baseCredential = null;
|
||||
|
||||
if (platformSerialNumber != null) {
|
||||
List<PlatformCredential> chainCertificates = PlatformCredential
|
||||
.select(certificateManager)
|
||||
.byBoardSerialNumber(platformSerialNumber)
|
||||
.getCertificates().stream().collect(Collectors.toList());
|
||||
|
||||
for (PlatformCredential pc : chainCertificates) {
|
||||
if (baseCredential != null && pc.isBase()) {
|
||||
multiple = true;
|
||||
} else if (pc.isBase()) {
|
||||
baseCredential = pc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return multiple;
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ public class SupplyChainValidationServiceImplTest extends SpringPersistenceTest
|
||||
// mocked
|
||||
private SupplyChainPolicy policy;
|
||||
private PlatformCredential pc;
|
||||
// private PlatformCredential delta;
|
||||
private PlatformCredential delta;
|
||||
private EndorsementCredential ec;
|
||||
private HashSet<PlatformCredential> pcs;
|
||||
private Device device;
|
||||
@ -135,9 +135,15 @@ public class SupplyChainValidationServiceImplTest extends SpringPersistenceTest
|
||||
pcs = new HashSet<PlatformCredential>();
|
||||
pcs.add(pc);
|
||||
|
||||
/*
|
||||
* Mock delta platform credential here
|
||||
*/
|
||||
//Mock delta platform credential
|
||||
X509Certificate deltaCert = mock(X509Certificate.class);
|
||||
delta = mock(PlatformCredential.class);
|
||||
when(delta.getId()).thenReturn(UUID.randomUUID());
|
||||
when(delta.getX509Certificate()).thenReturn(deltaCert);
|
||||
//when(delta.getSerialNumber()).thenReturn(BigInteger.ONE);
|
||||
when(delta.getIssuerOrganization()).thenReturn("STMicroelectronics NV");
|
||||
when(delta.getSubjectOrganization()).thenReturn("STMicroelectronics NV");
|
||||
//pcs.add(delta);
|
||||
|
||||
Set<Certificate> resultPcs = new HashSet<>();
|
||||
resultPcs.add(pc);
|
||||
@ -182,11 +188,6 @@ public class SupplyChainValidationServiceImplTest extends SpringPersistenceTest
|
||||
doReturn(new AppraisalStatus(PASS, "")).when(supplyChainCredentialValidator)
|
||||
.validatePlatformCredentialAttributes(eq(pc), any(DeviceInfoReport.class),
|
||||
any(EndorsementCredential.class));
|
||||
/*
|
||||
doReturn(new AppraisalStatus(PASS, "")).when(supplyChainCredentialValidator)
|
||||
.validateDeltaPlatformCredentialAttributes(eq(delta), any(DeviceInfoReport.class),
|
||||
any(PlatformCredential.class));
|
||||
*/
|
||||
|
||||
Assert.assertEquals(service.validateSupplyChain(ec, pcs,
|
||||
device).getOverallValidationResult(), PASS);
|
||||
|
@ -877,4 +877,4 @@
|
||||
</script>
|
||||
</jsp:body>
|
||||
|
||||
</my:page>
|
||||
</my:page>
|
||||
|
@ -34,12 +34,7 @@ public class SupplyChainValidation extends ArchivableEntity {
|
||||
/**
|
||||
* Validation of a platform credential's attributes.
|
||||
*/
|
||||
PLATFORM_CREDENTIAL_ATTRIBUTES,
|
||||
|
||||
/**
|
||||
* Validation of a delta platform credential's attributes.
|
||||
*/
|
||||
DELTA_PLATFORM_CREDENTIAL_ATTRIBUTES
|
||||
PLATFORM_CREDENTIAL_ATTRIBUTES
|
||||
}
|
||||
|
||||
@Column
|
||||
|
@ -234,6 +234,7 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
|
||||
private EndorsementCredential endorsementCredential = null;
|
||||
|
||||
private String platformChainType = Strings.EMPTY;
|
||||
private boolean isDeltaChain = false;
|
||||
|
||||
/**
|
||||
* Get a Selector for use in retrieving PlatformCredentials.
|
||||
@ -371,6 +372,15 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
|
||||
return platformBase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag that indicates this PC has or can have a chain of delta
|
||||
* certificates.
|
||||
* @return status of the chain
|
||||
*/
|
||||
public boolean isDeltaChain() {
|
||||
return isDeltaChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the string representation of the platform type.
|
||||
*
|
||||
@ -522,9 +532,11 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
|
||||
if (platformOid.getId().equals(PLATFORM_BASE_CERT)) {
|
||||
this.platformBase = true;
|
||||
this.platformChainType = "Base";
|
||||
this.isDeltaChain = true;
|
||||
} else if (platformOid.getId().equals(PLATFORM_DELTA_CERT)) {
|
||||
this.platformBase = false;
|
||||
this.platformChainType = "Delta";
|
||||
this.isDeltaChain = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,6 +214,13 @@ public class ComponentIdentifierV2 extends ComponentIdentifier {
|
||||
this.attributeStatus = attributeStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the component has been modified.
|
||||
*/
|
||||
public final boolean isAdded() {
|
||||
return getAttributeStatus() == AttributeStatus.ADDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the component has been modified.
|
||||
*/
|
||||
|
@ -6,6 +6,7 @@ import hirs.data.persist.certificate.EndorsementCredential;
|
||||
import hirs.data.persist.certificate.PlatformCredential;
|
||||
|
||||
import java.security.KeyStore;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class used to support supply chain validation by performing the actual
|
||||
@ -43,11 +44,14 @@ public interface CredentialValidator {
|
||||
* serial number of the platform to be validated.
|
||||
* @param base the base credential from the same identity request
|
||||
* as the delta credential.
|
||||
* @param chainCertificates base and delta certificates associated with the
|
||||
* delta being validated.
|
||||
* @return the result of the validation.
|
||||
*/
|
||||
AppraisalStatus validateDeltaPlatformCredentialAttributes(PlatformCredential delta,
|
||||
DeviceInfoReport deviceInfoReport,
|
||||
PlatformCredential base);
|
||||
DeviceInfoReport deviceInfoReport,
|
||||
PlatformCredential base,
|
||||
List<PlatformCredential> chainCertificates);
|
||||
/**
|
||||
* Checks if the endorsement credential is valid.
|
||||
*
|
||||
|
@ -55,6 +55,9 @@ import java.util.stream.Collectors;
|
||||
import static hirs.data.persist.AppraisalStatus.Status.ERROR;
|
||||
import static hirs.data.persist.AppraisalStatus.Status.FAIL;
|
||||
import static hirs.data.persist.AppraisalStatus.Status.PASS;
|
||||
import hirs.data.persist.certificate.attributes.V2.ComponentIdentifierV2;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
|
||||
@ -258,26 +261,99 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
* serial number of the platform to be validated.
|
||||
* @param basePlatformCredential the base credential from the same identity request
|
||||
* as the delta credential.
|
||||
* @param chainCertificates base and delta certificates associated with the
|
||||
* delta being validated.
|
||||
* @return the result of the validation.
|
||||
*/
|
||||
@Override
|
||||
public AppraisalStatus validateDeltaPlatformCredentialAttributes(
|
||||
final PlatformCredential deltaPlatformCredential,
|
||||
final DeviceInfoReport deviceInfoReport,
|
||||
final PlatformCredential basePlatformCredential) {
|
||||
final PlatformCredential basePlatformCredential,
|
||||
final List<PlatformCredential> chainCertificates) {
|
||||
final String baseErrorMessage = "Can't validate delta platform"
|
||||
+ "certificate attributes without ";
|
||||
String message;
|
||||
if (deltaPlatformCredential == null) {
|
||||
message = baseErrorMessage + "a delta platform certificate";
|
||||
LOGGER.error(message);
|
||||
return new AppraisalStatus(FAIL, message);
|
||||
}
|
||||
if (deviceInfoReport == null) {
|
||||
message = baseErrorMessage + "a device info report";
|
||||
LOGGER.error(message);
|
||||
return new AppraisalStatus(FAIL, message);
|
||||
}
|
||||
if (basePlatformCredential == null) {
|
||||
message = baseErrorMessage + "a base platform credential";
|
||||
LOGGER.error(message);
|
||||
return new AppraisalStatus(FAIL, message);
|
||||
}
|
||||
|
||||
/*
|
||||
* Code here to check the holder and attribute status fields
|
||||
*/
|
||||
return validatePlatformCredentialAttributesV2p0(deltaPlatformCredential, deviceInfoReport);
|
||||
if (!basePlatformCredential.getPlatformSerial()
|
||||
.equals(deltaPlatformCredential.getPlatformSerial())) {
|
||||
message = String.format("Delta platform certificate "
|
||||
+ "platform serial number (%s) does not match "
|
||||
+ "the base certificate's platform serial number (%s)",
|
||||
deltaPlatformCredential.getPlatformSerial(),
|
||||
basePlatformCredential.getPlatformSerial());
|
||||
LOGGER.error(message);
|
||||
return new AppraisalStatus(FAIL, message);
|
||||
}
|
||||
|
||||
// parse out the provided delta and its specific chain.
|
||||
Collections.reverse(chainCertificates);
|
||||
List<PlatformCredential> leafChain = new LinkedList<>();
|
||||
PlatformCredential dc;
|
||||
List<ComponentIdentifier> origPcComponents = new LinkedList<>();
|
||||
|
||||
for (PlatformCredential pc : chainCertificates) {
|
||||
if (pc.isBase()) {
|
||||
if (basePlatformCredential.getSerialNumber()
|
||||
.equals(pc.getSerialNumber())) {
|
||||
// get original component list
|
||||
origPcComponents.addAll(pc.getComponentIdentifiers());
|
||||
}
|
||||
} else {
|
||||
dc = pc;
|
||||
leafChain.add(dc);
|
||||
}
|
||||
}
|
||||
|
||||
// map the deltas to their holder serial numbers
|
||||
Map<String, PlatformCredential> leafMap = new HashMap<>();
|
||||
leafChain.stream().forEach((delta) -> {
|
||||
leafMap.put(delta.getHolderSerialNumber().toString(), delta);
|
||||
});
|
||||
|
||||
leafChain.clear();
|
||||
String serialNumber = basePlatformCredential.getSerialNumber().toString();
|
||||
PlatformCredential tempCred;
|
||||
|
||||
// Start with the base serial number, find the delta pointing to it
|
||||
// and put that first in the list
|
||||
for (int i = 0; i < leafMap.size(); i++) {
|
||||
tempCred = leafMap.get(serialNumber);
|
||||
// this should never be null
|
||||
if (tempCred != null) {
|
||||
leafChain.add(i, tempCred);
|
||||
serialNumber = tempCred.getSerialNumber().toString();
|
||||
} else {
|
||||
return new AppraisalStatus(ERROR, String.format("Delta platform search "
|
||||
+ "for mapping returned null for %s", serialNumber));
|
||||
}
|
||||
}
|
||||
|
||||
return validateDeltaAttributesChainV2p0(deviceInfoReport,
|
||||
leafChain, origPcComponents);
|
||||
}
|
||||
|
||||
private static AppraisalStatus validatePlatformCredentialAttributesV1p2(
|
||||
final PlatformCredential platformCredential,
|
||||
final DeviceInfoReport deviceInfoReport) {
|
||||
|
||||
// check the device's board serial number, and compare against this platform credential's
|
||||
// board serial number.
|
||||
// check the device's board serial number, and compare against this
|
||||
// platform credential's board serial number.
|
||||
// Retrieve the various device serial numbers.
|
||||
String credentialBoardSerialNumber = platformCredential.getPlatformSerial();
|
||||
String credentialChassisSerialNumber = platformCredential.getChassisSerialNumber();
|
||||
@ -379,8 +455,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
final PlatformCredential platformCredential,
|
||||
final DeviceInfoReport deviceInfoReport) {
|
||||
boolean passesValidation = true;
|
||||
|
||||
StringBuffer resultMessage = new StringBuffer();
|
||||
StringBuilder resultMessage = new StringBuilder();
|
||||
|
||||
HardwareInfo hardwareInfo = deviceInfoReport.getHardwareInfo();
|
||||
|
||||
@ -500,6 +575,115 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main purpose of this method, the in process of validation, is to
|
||||
* pick out the changes that lead to the delta cert and make sure the changes
|
||||
* are valid.
|
||||
*
|
||||
* @param deviceInfoReport The paccor profile of device being validated against.
|
||||
* @param leafChain The specific chain associated with delta cert being
|
||||
* validated.
|
||||
* @param origPcComponents The component identifier list associated with the
|
||||
* base cert for this specific chain
|
||||
* @return Appraisal Status of delta being validated.
|
||||
*/
|
||||
static AppraisalStatus validateDeltaAttributesChainV2p0(
|
||||
final DeviceInfoReport deviceInfoReport,
|
||||
final List<PlatformCredential> leafChain,
|
||||
final List<ComponentIdentifier> origPcComponents) {
|
||||
boolean fieldValidation = true;
|
||||
StringBuilder resultMessage = new StringBuilder();
|
||||
List<ComponentIdentifier> validOrigPcComponents = origPcComponents.stream()
|
||||
.filter(identifier -> identifier.getComponentManufacturer() != null
|
||||
&& identifier.getComponentModel() != null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// map the components throughout the chain
|
||||
Map<String, ComponentIdentifier> chainCiMapping = new HashMap<>();
|
||||
List<ComponentIdentifier> deltaBuildList = new LinkedList<>(validOrigPcComponents);
|
||||
deltaBuildList.stream().forEach((ci) -> {
|
||||
chainCiMapping.put(ci.getComponentSerial().toString(), ci);
|
||||
});
|
||||
|
||||
String ciSerial;
|
||||
// go through the leaf and check the changes against the valid components
|
||||
// forget modifying validOrigPcComponents
|
||||
for (PlatformCredential delta : leafChain) {
|
||||
for (ComponentIdentifier ci : delta.getComponentIdentifiers()) {
|
||||
if (ci.isVersion2()) {
|
||||
ciSerial = ci.getComponentSerial().toString();
|
||||
ComponentIdentifierV2 ciV2 = (ComponentIdentifierV2) ci;
|
||||
|
||||
if (ciV2.isModified()) {
|
||||
// this won't match
|
||||
// check it is there
|
||||
if (!chainCiMapping.containsKey(ciSerial)) {
|
||||
fieldValidation = false;
|
||||
resultMessage.append(String.format(
|
||||
"%s attempted MODIFIED with no prior instance.%n",
|
||||
ciSerial));
|
||||
} else {
|
||||
chainCiMapping.put(ci.getComponentSerial().toString(), ci);
|
||||
}
|
||||
} else if (ciV2.isRemoved()) {
|
||||
if (!chainCiMapping.containsKey(ciSerial)) {
|
||||
// error thrown, can't remove if it doesn't exist
|
||||
fieldValidation = false;
|
||||
resultMessage.append(String.format(
|
||||
"%s attempted REMOVED with no prior instance.%n",
|
||||
ciSerial));
|
||||
} else {
|
||||
chainCiMapping.remove(ci.getComponentSerial().toString());
|
||||
}
|
||||
} else if (ciV2.isAdded()) {
|
||||
// ADDED
|
||||
if (chainCiMapping.containsKey(ciSerial)) {
|
||||
// error, shouldn't exist
|
||||
fieldValidation = false;
|
||||
resultMessage.append(String.format(
|
||||
"%s was ADDED, the serial already exists.%n",
|
||||
ciSerial));
|
||||
} else {
|
||||
// have to add incase later it is removed
|
||||
chainCiMapping.put(ciSerial, ci);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fieldValidation) {
|
||||
resultMessage.append("There are errors with Delta "
|
||||
+ "Component Statuses components:\n");
|
||||
|
||||
return new AppraisalStatus(FAIL, resultMessage.toString());
|
||||
}
|
||||
|
||||
String paccorOutputString = deviceInfoReport.getPaccorOutputString();
|
||||
String unmatchedComponents;
|
||||
try {
|
||||
List<ComponentInfo> componentInfoList
|
||||
= getComponentInfoFromPaccorOutput(paccorOutputString);
|
||||
unmatchedComponents = validateV2p0PlatformCredentialComponentsExpectingExactMatch(
|
||||
new LinkedList<>(chainCiMapping.values()), componentInfoList);
|
||||
fieldValidation &= unmatchedComponents.isEmpty();
|
||||
} catch (IOException e) {
|
||||
final String baseErrorMessage = "Error parsing JSON output from PACCOR: ";
|
||||
LOGGER.error(baseErrorMessage + e.toString());
|
||||
LOGGER.error("PACCOR output string:\n" + paccorOutputString);
|
||||
return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage());
|
||||
}
|
||||
|
||||
if (!fieldValidation) {
|
||||
resultMessage.append("There are unmatched components:\n");
|
||||
resultMessage.append(unmatchedComponents);
|
||||
|
||||
return new AppraisalStatus(FAIL, resultMessage.toString());
|
||||
}
|
||||
|
||||
return new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the component information from the device info report against those of the
|
||||
* platform credential. All components in the platform credential should exactly match one
|
||||
@ -545,7 +729,6 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
pcComponents.forEach(component -> LOGGER.info(component.toString()));
|
||||
LOGGER.info("...against the the following DeviceInfoReport components:");
|
||||
allDeviceInfoComponents.forEach(component -> LOGGER.info(component.toString()));
|
||||
|
||||
Set<DERUTF8String> manufacturerSet = new HashSet<>();
|
||||
pcComponents.forEach(component -> manufacturerSet.add(
|
||||
component.getComponentManufacturer()));
|
||||
@ -577,7 +760,8 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
// Now match up the components from the device info that are from the same
|
||||
// manufacturer and have a serial number. As matches are found, remove them from
|
||||
// both lists.
|
||||
for (ComponentIdentifier pcComponent : pcComponentsFromManufacturerWithSerialNumber) {
|
||||
for (ComponentIdentifier pcComponent
|
||||
: pcComponentsFromManufacturerWithSerialNumber) {
|
||||
Optional<ComponentInfo> first
|
||||
= deviceInfoComponentsFromManufacturer.stream()
|
||||
.filter(componentInfo
|
||||
@ -607,7 +791,8 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
// Now match up the components from the device info that are from the same
|
||||
// manufacturer and specify a value for the revision field. As matches are found,
|
||||
// remove them from both lists.
|
||||
for (ComponentIdentifier pcComponent : pcComponentsFromManufacturerWithRevision) {
|
||||
for (ComponentIdentifier pcComponent
|
||||
: pcComponentsFromManufacturerWithRevision) {
|
||||
Optional<ComponentInfo> first
|
||||
= deviceInfoComponentsFromManufacturer.stream()
|
||||
.filter(info -> StringUtils.isNotEmpty(info.getComponentRevision()))
|
||||
|
@ -15,7 +15,10 @@ import hirs.data.persist.certificate.CertificateAuthorityCredential;
|
||||
import hirs.data.persist.certificate.CertificateTest;
|
||||
import hirs.data.persist.certificate.EndorsementCredential;
|
||||
import hirs.data.persist.certificate.PlatformCredential;
|
||||
import hirs.data.persist.certificate.attributes.ComponentClass;
|
||||
import hirs.data.persist.certificate.attributes.ComponentIdentifier;
|
||||
import hirs.data.persist.certificate.attributes.V2.AttributeStatus;
|
||||
import hirs.data.persist.certificate.attributes.V2.ComponentIdentifierV2;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.bouncycastle.asn1.ASN1Boolean;
|
||||
import org.bouncycastle.asn1.DERUTF8String;
|
||||
@ -1992,6 +1995,211 @@ public class SupplyChainCredentialValidatorTest {
|
||||
SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SupplyChainCredentialValidator passes with a base and delta certificate where
|
||||
* the base serial number and delta holder serial number match.
|
||||
* @throws java.io.IOException Reading file for the certificates
|
||||
* @throws java.net.URISyntaxException when loading certificates bytes
|
||||
*/
|
||||
@Test
|
||||
public final void testValidateDeltaPlatformCredentialAttributes()
|
||||
throws IOException, URISyntaxException {
|
||||
DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(
|
||||
SAMPLE_PACCOR_OUTPUT_TXT);
|
||||
|
||||
PlatformCredential base = mock(PlatformCredential.class);
|
||||
PlatformCredential delta1 = mock(PlatformCredential.class);
|
||||
PlatformCredential delta2 = mock(PlatformCredential.class);
|
||||
|
||||
ComponentIdentifier compId1 = new ComponentIdentifier(new DERUTF8String("Intel"),
|
||||
new DERUTF8String("Core i7"), new DERUTF8String("Not Specified"),
|
||||
new DERUTF8String("Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz"), null,
|
||||
ASN1Boolean.TRUE, new ArrayList<>(0));
|
||||
ComponentIdentifier compId2 = new ComponentIdentifier(
|
||||
new DERUTF8String("Intel Corporation"),
|
||||
new DERUTF8String("Ethernet Connection I217-V-faulty"),
|
||||
new DERUTF8String("23:94:17:ba:86:5e"), new DERUTF8String("00"), null,
|
||||
ASN1Boolean.FALSE, new ArrayList<>(0));
|
||||
ComponentIdentifier compId3 = new ComponentIdentifier(
|
||||
new DERUTF8String("Intel Corporation"),
|
||||
new DERUTF8String("82580 Gigabit Network Connection-faulty"),
|
||||
new DERUTF8String("90:e2:ba:31:83:10"), new DERUTF8String(""), null,
|
||||
ASN1Boolean.FALSE, new ArrayList<>(0));
|
||||
ComponentIdentifierV2 deltaCompId2 = new ComponentIdentifierV2(
|
||||
new ComponentClass(),
|
||||
new DERUTF8String("Intel Corporation"),
|
||||
new DERUTF8String("Ethernet Connection I217-V"),
|
||||
new DERUTF8String("23:94:17:ba:86:5e"), new DERUTF8String("00"), null,
|
||||
ASN1Boolean.FALSE, new ArrayList<>(0), null, null,
|
||||
AttributeStatus.ADDED);
|
||||
ComponentIdentifierV2 deltaCompId3 = new ComponentIdentifierV2(
|
||||
new ComponentClass(),
|
||||
new DERUTF8String("Intel Corporation"),
|
||||
new DERUTF8String("82580 Gigabit Network Connection"),
|
||||
new DERUTF8String("90:e2:ba:31:83:10"), new DERUTF8String(""), null,
|
||||
ASN1Boolean.FALSE, new ArrayList<>(0), null, null,
|
||||
AttributeStatus.ADDED);
|
||||
|
||||
ComponentIdentifierV2 ciV21Faulty = new ComponentIdentifierV2();
|
||||
ComponentIdentifierV2 ciV22Faulty = new ComponentIdentifierV2();
|
||||
ciV21Faulty.setComponentManufacturer(compId2.getComponentManufacturer());
|
||||
ciV21Faulty.setComponentModel(compId2.getComponentModel());
|
||||
ciV21Faulty.setComponentSerial(compId2.getComponentSerial());
|
||||
ciV21Faulty.setComponentRevision(compId2.getComponentRevision());
|
||||
ciV21Faulty.setComponentManufacturerId(compId2.getComponentManufacturerId());
|
||||
ciV21Faulty.setFieldReplaceable(compId2.getFieldReplaceable());
|
||||
ciV21Faulty.setComponentAddress(compId2.getComponentAddress());
|
||||
ciV21Faulty.setAttributeStatus(AttributeStatus.REMOVED);
|
||||
ciV22Faulty.setComponentManufacturer(compId3.getComponentManufacturer());
|
||||
ciV22Faulty.setComponentModel(compId3.getComponentModel());
|
||||
ciV22Faulty.setComponentSerial(compId3.getComponentSerial());
|
||||
ciV22Faulty.setComponentRevision(compId3.getComponentRevision());
|
||||
ciV22Faulty.setComponentManufacturerId(compId3.getComponentManufacturerId());
|
||||
ciV22Faulty.setFieldReplaceable(compId3.getFieldReplaceable());
|
||||
ciV22Faulty.setComponentAddress(compId3.getComponentAddress());
|
||||
ciV22Faulty.setAttributeStatus(AttributeStatus.REMOVED);
|
||||
|
||||
List<ComponentIdentifier> compList = new ArrayList<>(3);
|
||||
compList.add(compId1);
|
||||
compList.add(compId2);
|
||||
compList.add(compId3);
|
||||
|
||||
List<ComponentIdentifier> delta1List = new ArrayList<>(2);
|
||||
delta1List.add(ciV21Faulty);
|
||||
delta1List.add(deltaCompId2);
|
||||
List<ComponentIdentifier> delta2List = new ArrayList<>(2);
|
||||
delta1List.add(ciV22Faulty);
|
||||
delta1List.add(deltaCompId3);
|
||||
|
||||
when(base.isBase()).thenReturn(true);
|
||||
when(delta1.isBase()).thenReturn(false);
|
||||
when(delta2.isBase()).thenReturn(false);
|
||||
when(base.getManufacturer()).thenReturn("innotek GmbH");
|
||||
when(base.getModel()).thenReturn("VirtualBox");
|
||||
when(base.getVersion()).thenReturn("1.2");
|
||||
when(base.getPlatformSerial()).thenReturn("0");
|
||||
when(delta1.getPlatformSerial()).thenReturn("0");
|
||||
when(delta2.getPlatformSerial()).thenReturn("0");
|
||||
when(base.getPlatformType()).thenReturn("base");
|
||||
when(delta1.getPlatformType()).thenReturn("delta");
|
||||
when(delta2.getPlatformType()).thenReturn("delta");
|
||||
when(base.getSerialNumber()).thenReturn(BigInteger.ZERO);
|
||||
when(delta1.getSerialNumber()).thenReturn(BigInteger.ONE);
|
||||
when(delta2.getSerialNumber()).thenReturn(BigInteger.TEN);
|
||||
when(delta1.getHolderSerialNumber()).thenReturn(BigInteger.ZERO);
|
||||
when(delta2.getHolderSerialNumber()).thenReturn(BigInteger.ONE);
|
||||
when(base.getComponentIdentifiers()).thenReturn(compList);
|
||||
when(delta1.getComponentIdentifiers()).thenReturn(delta1List);
|
||||
when(delta2.getComponentIdentifiers()).thenReturn(delta2List);
|
||||
|
||||
List<PlatformCredential> chainCredentials = new ArrayList<>(0);
|
||||
chainCredentials.add(base);
|
||||
chainCredentials.add(delta1);
|
||||
chainCredentials.add(delta2);
|
||||
|
||||
AppraisalStatus result = supplyChainCredentialValidator
|
||||
.validateDeltaPlatformCredentialAttributes(delta2,
|
||||
deviceInfoReport, base, chainCredentials);
|
||||
Assert.assertEquals(result.getAppStatus(), AppraisalStatus.Status.PASS);
|
||||
Assert.assertEquals(result.getMessage(),
|
||||
SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SupplyChainCredentialValidator fails when a component needs to
|
||||
* be replaced but hasn't been by a delta certificate.
|
||||
* @throws java.io.IOException Reading file for the certificates
|
||||
* @throws java.net.URISyntaxException when loading certificates bytes
|
||||
*/
|
||||
@Test
|
||||
public final void testValidateChainFailure()
|
||||
throws IOException, URISyntaxException {
|
||||
DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(
|
||||
SAMPLE_PACCOR_OUTPUT_TXT);
|
||||
|
||||
PlatformCredential base = mock(PlatformCredential.class);
|
||||
PlatformCredential delta1 = mock(PlatformCredential.class);
|
||||
|
||||
ComponentIdentifier compId1 = new ComponentIdentifier(new DERUTF8String("Intel"),
|
||||
new DERUTF8String("Core i7"), new DERUTF8String("Not Specified"),
|
||||
new DERUTF8String("Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz"), null,
|
||||
ASN1Boolean.TRUE, new ArrayList<>(0));
|
||||
ComponentIdentifier compId2 = new ComponentIdentifier(
|
||||
new DERUTF8String("Intel Corporation"),
|
||||
new DERUTF8String("Ethernet Connection I217-V-faulty"),
|
||||
new DERUTF8String("23:94:17:ba:86:5e"), new DERUTF8String("00"), null,
|
||||
ASN1Boolean.FALSE, new ArrayList<>(0));
|
||||
ComponentIdentifier compId3 = new ComponentIdentifier(
|
||||
new DERUTF8String("Intel Corporation"),
|
||||
new DERUTF8String("82580 Gigabit Network Connection-faulty"),
|
||||
new DERUTF8String("90:e2:ba:31:83:10"), new DERUTF8String(""), null,
|
||||
ASN1Boolean.FALSE, new ArrayList<>(0));
|
||||
ComponentIdentifierV2 deltaCompId2 = new ComponentIdentifierV2(
|
||||
new ComponentClass(),
|
||||
new DERUTF8String("Intel Corporation"),
|
||||
new DERUTF8String("Ethernet Connection I217-V"),
|
||||
new DERUTF8String("23:94:17:ba:86:5e"), new DERUTF8String("00"), null,
|
||||
ASN1Boolean.FALSE, new ArrayList<>(0), null, null,
|
||||
AttributeStatus.ADDED);
|
||||
|
||||
ComponentIdentifierV2 ciV21Faulty = new ComponentIdentifierV2();
|
||||
ComponentIdentifierV2 ciV22Faulty = new ComponentIdentifierV2();
|
||||
ciV21Faulty.setComponentManufacturer(compId2.getComponentManufacturer());
|
||||
ciV21Faulty.setComponentModel(compId2.getComponentModel());
|
||||
ciV21Faulty.setComponentSerial(compId2.getComponentSerial());
|
||||
ciV21Faulty.setComponentRevision(compId2.getComponentRevision());
|
||||
ciV21Faulty.setComponentManufacturerId(compId2.getComponentManufacturerId());
|
||||
ciV21Faulty.setFieldReplaceable(compId2.getFieldReplaceable());
|
||||
ciV21Faulty.setComponentAddress(compId2.getComponentAddress());
|
||||
ciV21Faulty.setAttributeStatus(AttributeStatus.REMOVED);
|
||||
ciV22Faulty.setComponentManufacturer(compId3.getComponentManufacturer());
|
||||
ciV22Faulty.setComponentModel(compId3.getComponentModel());
|
||||
ciV22Faulty.setComponentSerial(compId3.getComponentSerial());
|
||||
ciV22Faulty.setComponentRevision(compId3.getComponentRevision());
|
||||
ciV22Faulty.setComponentManufacturerId(compId3.getComponentManufacturerId());
|
||||
ciV22Faulty.setFieldReplaceable(compId3.getFieldReplaceable());
|
||||
ciV22Faulty.setComponentAddress(compId3.getComponentAddress());
|
||||
ciV22Faulty.setAttributeStatus(AttributeStatus.REMOVED);
|
||||
|
||||
List<ComponentIdentifier> compList = new ArrayList<>(3);
|
||||
compList.add(compId1);
|
||||
compList.add(compId2);
|
||||
compList.add(compId3);
|
||||
|
||||
List<ComponentIdentifier> delta1List = new ArrayList<>(2);
|
||||
delta1List.add(ciV21Faulty);
|
||||
delta1List.add(deltaCompId2);
|
||||
|
||||
when(base.isBase()).thenReturn(true);
|
||||
when(delta1.isBase()).thenReturn(false);
|
||||
when(base.getManufacturer()).thenReturn("innotek GmbH");
|
||||
when(base.getModel()).thenReturn("VirtualBox");
|
||||
when(base.getVersion()).thenReturn("1.2");
|
||||
when(base.getPlatformSerial()).thenReturn("0");
|
||||
when(delta1.getPlatformSerial()).thenReturn("0");
|
||||
when(base.getPlatformType()).thenReturn("base");
|
||||
when(delta1.getPlatformType()).thenReturn("delta");
|
||||
when(base.getSerialNumber()).thenReturn(BigInteger.ZERO);
|
||||
when(delta1.getSerialNumber()).thenReturn(BigInteger.ONE);
|
||||
when(delta1.getHolderSerialNumber()).thenReturn(BigInteger.ZERO);
|
||||
when(base.getComponentIdentifiers()).thenReturn(compList);
|
||||
when(delta1.getComponentIdentifiers()).thenReturn(delta1List);
|
||||
|
||||
List<PlatformCredential> chainCredentials = new ArrayList<>(0);
|
||||
chainCredentials.add(base);
|
||||
chainCredentials.add(delta1);
|
||||
|
||||
AppraisalStatus result = supplyChainCredentialValidator
|
||||
.validateDeltaPlatformCredentialAttributes(delta1,
|
||||
deviceInfoReport, base, chainCredentials);
|
||||
Assert.assertEquals(result.getAppStatus(), AppraisalStatus.Status.FAIL);
|
||||
Assert.assertEquals(result.getMessage(),
|
||||
"There are unmatched components:\n"
|
||||
+ "Manufacturer=Intel Corporation, Model=82580 "
|
||||
+ "Gigabit Network Connection-faulty, "
|
||||
+ "Serial=90:e2:ba:31:83:10, Revision=\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new RSA 1024-bit KeyPair using a Bouncy Castle Provider.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user