mirror of
https://github.com/nsacyber/HIRS.git
synced 2025-01-18 10:46:39 +00:00
* This pull request contains 2 main changes, the first is transferring the status text from the attributes failure to the icon specifically for platform trust chain validation. Then this removes the third column on the validation page that singles out the icons for the attribute status. In addition, this status is also rolled up to the summary status icon and displays the text there as well for all that have failed. This last change meant a change to the sizes of the columns in the database. The validation of a single base certificate with an error was not handled in the code base. Due to the changes with the introduction of delta certifications, the validation was modified and only handled changes presented by the deltas and ignored errors in the base certificate. This commit modifies the code that if there is just a single base certificate that is bad and error is thrown.
This commit is contained in:
parent
aa707b8665
commit
7cfabe756d
@ -12,14 +12,13 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
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.stream.Collectors;
|
||||
import java.util.HashMap;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import hirs.appraiser.Appraiser;
|
||||
import hirs.appraiser.SupplyChainAppraiser;
|
||||
@ -41,6 +40,8 @@ import hirs.persist.DBManagerException;
|
||||
import hirs.persist.PersistenceConfiguration;
|
||||
import hirs.persist.PolicyManager;
|
||||
import hirs.validation.CredentialValidator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The main executor of supply chain verification tasks. The AbstractAttestationCertificateAuthority
|
||||
@ -102,17 +103,16 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
SupplyChainPolicy policy = (SupplyChainPolicy) policyManager.getDefaultPolicy(
|
||||
supplyChainAppraiser);
|
||||
boolean acceptExpiredCerts = policy.isExpiredCertificateValidationEnabled();
|
||||
HashMap<PlatformCredential, SupplyChainValidation> credentialMap = new HashMap<>();
|
||||
PlatformCredential baseCredential = null;
|
||||
List<SupplyChainValidation> validations = new LinkedList<>();
|
||||
List<SupplyChainValidation> deltaValidations = new LinkedList<>();
|
||||
|
||||
// validate all supply chain pieces. Potentially, a policy setting could be made
|
||||
// to dictate stopping after the first validation failure.
|
||||
Map<SupplyChainValidation.ValidationType,
|
||||
SupplyChainValidation> validationTypeMap = new HashMap<>();
|
||||
Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>();
|
||||
|
||||
// Validate the Endorsement Credential
|
||||
if (policy.isEcValidationEnabled()) {
|
||||
validations.add(validateEndorsementCredential(ec, acceptExpiredCerts));
|
||||
validationTypeMap.put(SupplyChainValidation.ValidationType.ENDORSEMENT_CREDENTIAL,
|
||||
validateEndorsementCredential(ec, acceptExpiredCerts));
|
||||
// store the device with the credential
|
||||
if (null != ec) {
|
||||
ec.setDevice(device);
|
||||
@ -125,7 +125,9 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
// Ensure there are platform credentials to validate
|
||||
if (pcs == null || pcs.isEmpty()) {
|
||||
LOGGER.error("There were no Platform Credentials to validate.");
|
||||
validations.add(buildValidationRecord(
|
||||
validationTypeMap.put(SupplyChainValidation
|
||||
.ValidationType.PLATFORM_CREDENTIAL,
|
||||
buildValidationRecord(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.FAIL,
|
||||
"Platform credential(s) missing", null, Level.ERROR));
|
||||
@ -137,20 +139,17 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
SupplyChainValidation platformScv = validatePlatformCredential(
|
||||
pc, trustedCa, acceptExpiredCerts);
|
||||
|
||||
// check if this cert has been verified for multiple base associated
|
||||
// with the serial number
|
||||
// check if this cert has been verified for multiple base
|
||||
// associated with the serial number
|
||||
if (pc != null) {
|
||||
platformScv = validatePcPolicy(pc, platformScv,
|
||||
deltaValidations, acceptExpiredCerts);
|
||||
}
|
||||
validations.add(platformScv);
|
||||
if (!deltaValidations.isEmpty()) {
|
||||
validations.addAll(deltaValidations);
|
||||
}
|
||||
if (pc != null) {
|
||||
deltaMapping, acceptExpiredCerts);
|
||||
|
||||
validationTypeMap.put(SupplyChainValidation
|
||||
.ValidationType.PLATFORM_CREDENTIAL,
|
||||
platformScv);
|
||||
pc.setDevice(device);
|
||||
this.certificateManager.update(pc);
|
||||
credentialMap.put(pc, platformScv);
|
||||
if (pc.isBase()) {
|
||||
baseCredential = pc;
|
||||
}
|
||||
@ -164,53 +163,30 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
// Ensure there are platform credentials to validate
|
||||
if (pcs == null || pcs.isEmpty()) {
|
||||
LOGGER.error("There were no Platform Credentials to validate attributes.");
|
||||
validations.add(buildValidationRecord(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES,
|
||||
validationTypeMap.put(SupplyChainValidation
|
||||
.ValidationType.PLATFORM_CREDENTIAL,
|
||||
buildValidationRecord(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.FAIL,
|
||||
"Platform credential(s) missing. Cannot validate attributes",
|
||||
"Platform credential(s) missing.\nPlatform credential(s) missing."
|
||||
+ " Cannot validate attributes",
|
||||
null, Level.ERROR));
|
||||
} else {
|
||||
Iterator<PlatformCredential> it = pcs.iterator();
|
||||
while (it.hasNext()) {
|
||||
PlatformCredential pc = it.next();
|
||||
SupplyChainValidation attributeScv;
|
||||
if (baseCredential == null || pc == baseCredential && !pc.isDeltaChain()) {
|
||||
if (baseCredential == null || pc == baseCredential) {
|
||||
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, chainCertificates);
|
||||
validationTypeMap.put(SupplyChainValidation
|
||||
.ValidationType.PLATFORM_CREDENTIAL,
|
||||
attributeScv);
|
||||
}
|
||||
|
||||
SupplyChainValidation platformScv = credentialMap.get(pc);
|
||||
if (platformScv != null) {
|
||||
if (platformScv.getResult() == AppraisalStatus.Status.FAIL
|
||||
|| platformScv.getResult() == AppraisalStatus.Status.ERROR) {
|
||||
if (attributeScv != null
|
||||
&& attributeScv.getResult() == AppraisalStatus.Status.PASS) {
|
||||
validations.add(buildValidationRecord(
|
||||
SupplyChainValidation.ValidationType
|
||||
.PLATFORM_CREDENTIAL_ATTRIBUTES,
|
||||
AppraisalStatus.Status.FAIL,
|
||||
platformScv.getMessage(), pc, Level.WARN));
|
||||
}
|
||||
} else {
|
||||
validations.add(attributeScv);
|
||||
}
|
||||
if (pc != null && pc.isDeltaChain()) {
|
||||
validateDeltaPlatformCredentialAttributes(
|
||||
pc, device.getDeviceInfo(), baseCredential, deltaMapping);
|
||||
}
|
||||
|
||||
if (pc != null) {
|
||||
@ -221,6 +197,14 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
}
|
||||
}
|
||||
|
||||
if (!validationTypeMap.isEmpty()) {
|
||||
validations.addAll(validationTypeMap.values());
|
||||
}
|
||||
|
||||
if (!deltaMapping.isEmpty()) {
|
||||
validations.addAll(deltaMapping.values());
|
||||
}
|
||||
|
||||
// Generate validation summary, save it, and return it.
|
||||
SupplyChainValidationSummary summary =
|
||||
new SupplyChainValidationSummary(device, validations);
|
||||
@ -244,7 +228,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
private SupplyChainValidation validatePcPolicy(
|
||||
final PlatformCredential pc,
|
||||
final SupplyChainValidation platformScv,
|
||||
final List<SupplyChainValidation> deltaValidations,
|
||||
final Map<PlatformCredential, SupplyChainValidation> deltaMapping,
|
||||
final boolean acceptExpiredCerts) {
|
||||
SupplyChainValidation subPlatformScv = platformScv;
|
||||
|
||||
@ -263,13 +247,21 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
AppraisalStatus.Status.FAIL,
|
||||
message, pc, Level.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
// Grab all certs associated with this platform chain
|
||||
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());
|
||||
}
|
||||
});
|
||||
|
||||
SupplyChainValidation deltaScv;
|
||||
KeyStore trustedCa;
|
||||
@ -279,10 +271,10 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
trustedCa = getCaChain(delta);
|
||||
deltaScv = validatePlatformCredential(
|
||||
delta, trustedCa, acceptExpiredCerts);
|
||||
deltaValidations.add(deltaScv);
|
||||
deltaMapping.put(delta, deltaScv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return subPlatformScv;
|
||||
}
|
||||
|
||||
@ -352,7 +344,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
final DeviceInfoReport deviceInfoReport,
|
||||
final EndorsementCredential ec) {
|
||||
final SupplyChainValidation.ValidationType validationType
|
||||
= SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES;
|
||||
= SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL;
|
||||
|
||||
if (pc == null) {
|
||||
LOGGER.error("No platform credential to validate");
|
||||
@ -383,7 +375,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
final PlatformCredential delta,
|
||||
final DeviceInfoReport deviceInfoReport,
|
||||
final PlatformCredential base,
|
||||
final List<PlatformCredential> chainCertificates) {
|
||||
final Map<PlatformCredential, SupplyChainValidation> deltaMapping) {
|
||||
final SupplyChainValidation.ValidationType validationType =
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES;
|
||||
|
||||
@ -396,7 +388,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
|
||||
LOGGER.info("Validating delta platform certificate attributes");
|
||||
AppraisalStatus result = supplyChainCredentialValidator.
|
||||
validateDeltaPlatformCredentialAttributes(delta, deviceInfoReport,
|
||||
base, chainCertificates);
|
||||
base, deltaMapping);
|
||||
switch (result.getAppStatus()) {
|
||||
case PASS:
|
||||
return buildValidationRecord(validationType, AppraisalStatus.Status.PASS,
|
||||
|
@ -144,7 +144,6 @@ public class SupplyChainValidationServiceImplTest extends SpringPersistenceTest
|
||||
//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);
|
||||
@ -242,7 +241,7 @@ public class SupplyChainValidationServiceImplTest extends SpringPersistenceTest
|
||||
validateEndorsementCredential(eq(ec), any(KeyStore.class), eq(true));
|
||||
doReturn(new AppraisalStatus(FAIL, "")).when(supplyChainCredentialValidator).
|
||||
validatePlatformCredential(eq(pc), any(KeyStore.class), eq(true));
|
||||
doReturn(new AppraisalStatus(PASS, "")).when(supplyChainCredentialValidator)
|
||||
doReturn(new AppraisalStatus(FAIL, "")).when(supplyChainCredentialValidator)
|
||||
.validatePlatformCredentialAttributes(eq(pc), any(DeviceInfoReport.class),
|
||||
any(EndorsementCredential.class));
|
||||
Assert.assertEquals(service.validateSupplyChain(ec, pcs,
|
||||
|
@ -32,12 +32,12 @@
|
||||
<th rowspan="2">Result</th>
|
||||
<th rowspan="2">Timestamp</th>
|
||||
<th rowspan="2">Device</th>
|
||||
<th colspan="3">Credential Validations</th>
|
||||
<th colspan="2">Credential Validations</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Endorsement</th>
|
||||
<th>Platform</th>
|
||||
<th>Platform Attributes</th>
|
||||
<th style="text-align:center">Endorsement</th>
|
||||
<th style="text-align:center">Platform</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
@ -55,16 +55,17 @@
|
||||
|
||||
// create status icon
|
||||
var result = full.overallValidationResult;
|
||||
var ovallMessage = full.message;
|
||||
if (result) {
|
||||
switch (result) {
|
||||
case "PASS":
|
||||
html += '<img src="${passIcon}" title="${passText}"/>';
|
||||
break;
|
||||
case "FAIL":
|
||||
html += '<img src="${failIcon}" title="${failText}"/>';
|
||||
html += '<img src="${failIcon}" title="' + ovallMessage + '"/>';
|
||||
break;
|
||||
case "ERROR":
|
||||
html += '<img src="${errorIcon}" title="${errorText}"/>';
|
||||
html += '<img src="${errorIcon}" title="' + ovallMessage + '"/>';
|
||||
break;
|
||||
default:
|
||||
html += unknownStatus;
|
||||
@ -161,7 +162,7 @@
|
||||
|
||||
html += '<a href="${portal}/certificate-details?id='
|
||||
+ curValidation.certificatesUsed[0].id
|
||||
+ '&type=' + certType + '">'
|
||||
+ '&type=' + certType + '">';
|
||||
}
|
||||
|
||||
switch (curResult) {
|
||||
|
@ -15,6 +15,13 @@ import org.hibernate.annotations.Type;
|
||||
*/
|
||||
@MappedSuperclass
|
||||
public abstract class AbstractEntity {
|
||||
|
||||
/**
|
||||
* static value for the length of a status message for objects that
|
||||
* can have extremely long values, potentially.
|
||||
*/
|
||||
protected static final int RESULT_MESSAGE_LENGTH = 1000000;
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(generator = "uuid2")
|
||||
|
@ -29,8 +29,6 @@ import javax.xml.bind.annotation.XmlTransient;
|
||||
@JsonSerialize(using = AppraisalResultSerializer.class)
|
||||
public class AppraisalResult extends AbstractEntity {
|
||||
|
||||
private static final int RESULT_MESSAGE_LENGTH = 1000000;
|
||||
|
||||
/**
|
||||
* Corresponding <code>Appraiser</code>. Can be NULL.
|
||||
*/
|
||||
|
@ -22,22 +22,24 @@ public class NetworkInfo implements Serializable {
|
||||
private static final Logger LOGGER = LogManager
|
||||
.getLogger(NetworkInfo.class);
|
||||
|
||||
private static final int LONG_STRING_LENGTH = 255;
|
||||
private static final int SHORT_STRING_LENGTH = 32;
|
||||
private static final int NUM_MAC_ADDRESS_BYTES = 6;
|
||||
|
||||
@XmlElement
|
||||
@Column(length = 255, nullable = true)
|
||||
@Column(length = LONG_STRING_LENGTH, nullable = true)
|
||||
@SuppressWarnings("checkstyle:magicnumber")
|
||||
private String hostname;
|
||||
|
||||
@XmlElement
|
||||
@XmlJavaTypeAdapter(value = InetAddressXmlAdapter.class)
|
||||
@SuppressWarnings("checkstyle:magicnumber")
|
||||
@Column(length = 32, nullable = true)
|
||||
@Column(length = SHORT_STRING_LENGTH, nullable = true)
|
||||
@Type(type = "hirs.data.persist.type.InetAddressType")
|
||||
private InetAddress ipAddress;
|
||||
|
||||
@XmlElement
|
||||
@Column(length = 6, nullable = true)
|
||||
@Column(length = NUM_MAC_ADDRESS_BYTES, nullable = true)
|
||||
@SuppressWarnings("checkstyle:magicnumber")
|
||||
private byte[] macAddress;
|
||||
|
||||
|
@ -25,6 +25,7 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
/**
|
||||
* A container class to group multiple related {@link SupplyChainValidation} instances
|
||||
@ -42,6 +43,9 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
|
||||
@Enumerated(EnumType.STRING)
|
||||
private final AppraisalStatus.Status overallValidationResult;
|
||||
|
||||
@Column(length = RESULT_MESSAGE_LENGTH)
|
||||
private final String message;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,
|
||||
targetEntity = SupplyChainValidation.class, orphanRemoval = true)
|
||||
private final Set<SupplyChainValidation> validations;
|
||||
@ -53,6 +57,7 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
|
||||
this.device = null;
|
||||
overallValidationResult = AppraisalStatus.Status.FAIL;
|
||||
validations = Collections.emptySet();
|
||||
this.message = Strings.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,9 +188,10 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
|
||||
|
||||
|
||||
this.device = device;
|
||||
this.overallValidationResult = calculateValidationResult(validations);
|
||||
AppraisalStatus status = calculateValidationResult(validations);
|
||||
this.overallValidationResult = status.getAppStatus();
|
||||
this.validations = new HashSet<>(validations);
|
||||
|
||||
this.message = status.getMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,6 +210,13 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
|
||||
return overallValidationResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the fail message if there is a failure.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the validations that this summary contains
|
||||
*/
|
||||
@ -217,17 +230,20 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
|
||||
* @param validations the validations to evaluate
|
||||
* @return the overall appraisal result
|
||||
*/
|
||||
private AppraisalStatus.Status calculateValidationResult(
|
||||
private AppraisalStatus calculateValidationResult(
|
||||
final Collection<SupplyChainValidation> validations) {
|
||||
boolean hasAnyFailures = false;
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
for (SupplyChainValidation validation : validations) {
|
||||
switch (validation.getResult()) {
|
||||
// if any error, then process overall as error immediately.
|
||||
case ERROR:
|
||||
return AppraisalStatus.Status.ERROR;
|
||||
return new AppraisalStatus(AppraisalStatus.Status.ERROR,
|
||||
validation.getMessage());
|
||||
case FAIL:
|
||||
hasAnyFailures = true;
|
||||
failureMsg.append(validation.getMessage());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -236,8 +252,10 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
|
||||
}
|
||||
// if failures, but no error, indicate failure result.
|
||||
if (hasAnyFailures) {
|
||||
return AppraisalStatus.Status.FAIL;
|
||||
return new AppraisalStatus(AppraisalStatus.Status.FAIL,
|
||||
failureMsg.toString());
|
||||
}
|
||||
return AppraisalStatus.Status.PASS;
|
||||
return new AppraisalStatus(AppraisalStatus.Status.PASS,
|
||||
Strings.EMPTY);
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,12 @@ package hirs.validation;
|
||||
|
||||
import hirs.data.persist.AppraisalStatus;
|
||||
import hirs.data.persist.DeviceInfoReport;
|
||||
import hirs.data.persist.SupplyChainValidation;
|
||||
import hirs.data.persist.certificate.EndorsementCredential;
|
||||
import hirs.data.persist.certificate.PlatformCredential;
|
||||
|
||||
import java.security.KeyStore;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A class used to support supply chain validation by performing the actual
|
||||
@ -44,14 +45,15 @@ 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.
|
||||
* @param deltaMapping delta certificates associated with the
|
||||
* delta supply validation.
|
||||
* @return the result of the validation.
|
||||
*/
|
||||
AppraisalStatus validateDeltaPlatformCredentialAttributes(PlatformCredential delta,
|
||||
DeviceInfoReport deviceInfoReport,
|
||||
PlatformCredential base,
|
||||
List<PlatformCredential> chainCertificates);
|
||||
Map<PlatformCredential,
|
||||
SupplyChainValidation> deltaMapping);
|
||||
/**
|
||||
* Checks if the endorsement credential is valid.
|
||||
*
|
||||
|
@ -55,6 +55,8 @@ 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.SupplyChainValidation;
|
||||
import hirs.data.persist.certificate.Certificate;
|
||||
import hirs.data.persist.certificate.attributes.V2.ComponentIdentifierV2;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
@ -87,6 +89,8 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
public static final String PLATFORM_ATTRIBUTES_VALID =
|
||||
"Platform credential attributes validated";
|
||||
|
||||
private static final Map<PlatformCredential, StringBuilder> DELTA_FAILURES = new HashMap<>();
|
||||
|
||||
/*
|
||||
* Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
|
||||
* class expects it to be available.
|
||||
@ -135,7 +139,6 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
return node.findValue(fieldName).asText();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,16 +156,15 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
final String baseErrorMessage = "Can't validate platform credential without ";
|
||||
String message;
|
||||
if (pc == null) {
|
||||
message = baseErrorMessage + "a platform credential";
|
||||
message = baseErrorMessage + "a platform credential\n";
|
||||
LOGGER.error(message);
|
||||
return new AppraisalStatus(FAIL, message);
|
||||
}
|
||||
try {
|
||||
if (trustStore == null || trustStore.size() == 0) {
|
||||
message = baseErrorMessage + "a trust store";
|
||||
message = baseErrorMessage + "a trust store\n";
|
||||
LOGGER.error(message);
|
||||
return new AppraisalStatus(FAIL, message);
|
||||
|
||||
}
|
||||
} catch (KeyStoreException e) {
|
||||
message = baseErrorMessage + "an intitialized trust store";
|
||||
@ -261,8 +263,8 @@ 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.
|
||||
* @param deltaMapping delta certificates associated with the
|
||||
* delta supply validation.
|
||||
* @return the result of the validation.
|
||||
*/
|
||||
@Override
|
||||
@ -270,7 +272,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
final PlatformCredential deltaPlatformCredential,
|
||||
final DeviceInfoReport deviceInfoReport,
|
||||
final PlatformCredential basePlatformCredential,
|
||||
final List<PlatformCredential> chainCertificates) {
|
||||
final Map<PlatformCredential, SupplyChainValidation> deltaMapping) {
|
||||
final String baseErrorMessage = "Can't validate delta platform"
|
||||
+ "certificate attributes without ";
|
||||
String message;
|
||||
@ -302,30 +304,11 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
}
|
||||
|
||||
// parse out the provided delta and its specific chain.
|
||||
Collections.reverse(chainCertificates);
|
||||
List<PlatformCredential> leafChain = new LinkedList<>();
|
||||
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 {
|
||||
leafChain.add(pc);
|
||||
}
|
||||
}
|
||||
|
||||
// map the deltas to their holder serial numbers
|
||||
Map<String, PlatformCredential> leafMap = new HashMap<>();
|
||||
leafChain.stream().forEach((delta) -> {
|
||||
leafMap.put(delta.getHolderSerialNumber().toString(), delta);
|
||||
});
|
||||
List<ComponentIdentifier> origPcComponents
|
||||
= new LinkedList<>(basePlatformCredential.getComponentIdentifiers());
|
||||
|
||||
return validateDeltaAttributesChainV2p0(deviceInfoReport,
|
||||
leafChain, origPcComponents);
|
||||
deltaMapping, origPcComponents);
|
||||
}
|
||||
|
||||
private static AppraisalStatus validatePlatformCredentialAttributesV1p2(
|
||||
@ -561,19 +544,17 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
* are valid.
|
||||
*
|
||||
* @param deviceInfoReport The paccor profile of device being validated against.
|
||||
* @param leafChain The specific chain associated with delta cert being
|
||||
* validated.
|
||||
* @param deltaMapping map of delta certificates to their validated status
|
||||
* @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 Map<PlatformCredential, SupplyChainValidation> deltaMapping,
|
||||
final List<ComponentIdentifier> origPcComponents) {
|
||||
boolean fieldValidation = true;
|
||||
StringBuilder resultMessage = new StringBuilder();
|
||||
StringBuilder deltaMessage = new StringBuilder();
|
||||
List<ComponentIdentifier> validOrigPcComponents = origPcComponents.stream()
|
||||
.filter(identifier -> identifier.getComponentManufacturer() != null
|
||||
&& identifier.getComponentModel() != null)
|
||||
@ -587,9 +568,20 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
});
|
||||
|
||||
String ciSerial;
|
||||
List<Certificate> certificateList = null;
|
||||
PlatformCredential delta = null;
|
||||
SupplyChainValidation scv = null;
|
||||
resultMessage.append("There are errors with Delta "
|
||||
+ "Component Statuses components:\n");
|
||||
// go through the leaf and check the changes against the valid components
|
||||
// forget modifying validOrigPcComponents
|
||||
for (PlatformCredential delta : leafChain) {
|
||||
for (Map.Entry<PlatformCredential, SupplyChainValidation> deltaEntry
|
||||
: deltaMapping.entrySet()) {
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
delta = deltaEntry.getKey();
|
||||
certificateList = new ArrayList<>();
|
||||
certificateList.add(delta);
|
||||
|
||||
for (ComponentIdentifier ci : delta.getComponentIdentifiers()) {
|
||||
if (ci.isVersion2()) {
|
||||
ciSerial = ci.getComponentSerial().toString();
|
||||
@ -599,9 +591,18 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
// check it is there
|
||||
if (!chainCiMapping.containsKey(ciSerial)) {
|
||||
fieldValidation = false;
|
||||
deltaMessage.append(String.format(
|
||||
failureMsg.append(String.format(
|
||||
"%s attempted MODIFIED with no prior instance.%n",
|
||||
ciSerial));
|
||||
scv = deltaEntry.getValue();
|
||||
if (scv.getResult() != AppraisalStatus.Status.PASS) {
|
||||
failureMsg.append(scv.getMessage());
|
||||
}
|
||||
deltaMapping.put(delta, new SupplyChainValidation(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.FAIL,
|
||||
certificateList,
|
||||
failureMsg.toString()));
|
||||
} else {
|
||||
chainCiMapping.put(ci.getComponentSerial().toString(), ci);
|
||||
}
|
||||
@ -609,9 +610,18 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
if (!chainCiMapping.containsKey(ciSerial)) {
|
||||
// error thrown, can't remove if it doesn't exist
|
||||
fieldValidation = false;
|
||||
deltaMessage.append(String.format(
|
||||
failureMsg.append(String.format(
|
||||
"%s attempted REMOVED with no prior instance.%n",
|
||||
ciSerial));
|
||||
scv = deltaEntry.getValue();
|
||||
if (scv.getResult() != AppraisalStatus.Status.PASS) {
|
||||
failureMsg.append(scv.getMessage());
|
||||
}
|
||||
deltaMapping.put(delta, new SupplyChainValidation(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.FAIL,
|
||||
certificateList,
|
||||
failureMsg.toString()));
|
||||
} else {
|
||||
chainCiMapping.remove(ci.getComponentSerial().toString());
|
||||
}
|
||||
@ -620,9 +630,18 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
if (chainCiMapping.containsKey(ciSerial)) {
|
||||
// error, shouldn't exist
|
||||
fieldValidation = false;
|
||||
deltaMessage.append(String.format(
|
||||
failureMsg.append(String.format(
|
||||
"%s was ADDED, the serial already exists.%n",
|
||||
ciSerial));
|
||||
scv = deltaEntry.getValue();
|
||||
if (scv.getResult() != AppraisalStatus.Status.PASS) {
|
||||
failureMsg.append(scv.getMessage());
|
||||
}
|
||||
deltaMapping.put(delta, new SupplyChainValidation(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.FAIL,
|
||||
certificateList,
|
||||
failureMsg.toString()));
|
||||
} else {
|
||||
// have to add in case later it is removed
|
||||
chainCiMapping.put(ciSerial, ci);
|
||||
@ -630,11 +649,11 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resultMessage.append(failureMsg.toString());
|
||||
}
|
||||
|
||||
if (!fieldValidation) {
|
||||
resultMessage.append("There are errors with Delta Component Statuses components:\n");
|
||||
resultMessage.append(deltaMessage.toString());
|
||||
return new AppraisalStatus(FAIL, resultMessage.toString());
|
||||
}
|
||||
|
||||
@ -654,6 +673,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
}
|
||||
|
||||
if (!fieldValidation) {
|
||||
resultMessage = new StringBuilder();
|
||||
resultMessage.append("There are unmatched components:\n");
|
||||
resultMessage.append(unmatchedComponents);
|
||||
|
||||
@ -1407,4 +1427,13 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import hirs.data.persist.HardwareInfo;
|
||||
import hirs.data.persist.NICComponentInfo;
|
||||
import hirs.data.persist.NetworkInfo;
|
||||
import hirs.data.persist.OSInfo;
|
||||
import hirs.data.persist.SupplyChainValidation;
|
||||
import hirs.data.persist.TPMInfo;
|
||||
import hirs.data.persist.certificate.Certificate;
|
||||
import hirs.data.persist.certificate.CertificateAuthorityCredential;
|
||||
@ -79,8 +80,10 @@ import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.powermock.api.mockito.PowerMockito.mock;
|
||||
@ -1158,7 +1161,8 @@ public class SupplyChainCredentialValidatorTest {
|
||||
*/
|
||||
@Test
|
||||
public final void verifyPlatformCredentialNullCredentialPath() {
|
||||
String expectedMessage = "Can't validate platform credential without a platform credential";
|
||||
String expectedMessage = "Can't validate platform credential without "
|
||||
+ "a platform credential\n";
|
||||
|
||||
AppraisalStatus result = supplyChainCredentialValidator.validatePlatformCredential(
|
||||
null, keyStore, true);
|
||||
@ -1182,7 +1186,7 @@ public class SupplyChainCredentialValidatorTest {
|
||||
PlatformCredential pc = new PlatformCredential(certBytes);
|
||||
|
||||
String expectedMessage = "Can't validate platform credential without a "
|
||||
+ "trust store";
|
||||
+ "trust store\n";
|
||||
|
||||
AppraisalStatus result = supplyChainCredentialValidator.validatePlatformCredential(pc, null,
|
||||
true);
|
||||
@ -2092,10 +2096,22 @@ public class SupplyChainCredentialValidatorTest {
|
||||
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);
|
||||
Map<PlatformCredential, SupplyChainValidation> chainCredentials = new HashMap<>(0);
|
||||
List<Certificate> certsUsed = new ArrayList<>();
|
||||
certsUsed.add(base);
|
||||
chainCredentials.put(base, new SupplyChainValidation(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.PASS, certsUsed, ""));
|
||||
certsUsed.clear();
|
||||
certsUsed.add(delta1);
|
||||
chainCredentials.put(delta1, new SupplyChainValidation(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.PASS, certsUsed, ""));
|
||||
certsUsed.clear();
|
||||
certsUsed.add(delta2);
|
||||
chainCredentials.put(delta2, new SupplyChainValidation(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.PASS, certsUsed, ""));
|
||||
|
||||
AppraisalStatus result = supplyChainCredentialValidator
|
||||
.validateDeltaPlatformCredentialAttributes(delta2,
|
||||
@ -2185,9 +2201,17 @@ public class SupplyChainCredentialValidatorTest {
|
||||
when(base.getComponentIdentifiers()).thenReturn(compList);
|
||||
when(delta1.getComponentIdentifiers()).thenReturn(delta1List);
|
||||
|
||||
List<PlatformCredential> chainCredentials = new ArrayList<>(0);
|
||||
chainCredentials.add(base);
|
||||
chainCredentials.add(delta1);
|
||||
Map<PlatformCredential, SupplyChainValidation> chainCredentials = new HashMap<>(0);
|
||||
List<Certificate> certsUsed = new ArrayList<>();
|
||||
certsUsed.add(base);
|
||||
chainCredentials.put(base, new SupplyChainValidation(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.PASS, certsUsed, ""));
|
||||
certsUsed.clear();
|
||||
certsUsed.add(delta1);
|
||||
chainCredentials.put(delta1, new SupplyChainValidation(
|
||||
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
|
||||
AppraisalStatus.Status.PASS, certsUsed, ""));
|
||||
|
||||
AppraisalStatus result = supplyChainCredentialValidator
|
||||
.validateDeltaPlatformCredentialAttributes(delta1,
|
||||
|
Loading…
Reference in New Issue
Block a user