This is a set of changes that are prepping for further testing to add in

the last piece which populates the result of the isMatch in the DB.
This commit is contained in:
Cyrus 2024-02-20 14:57:58 -05:00
parent c3d3146a73
commit 3520680e2a
12 changed files with 130 additions and 95 deletions

View File

@ -0,0 +1,11 @@
package hirs.attestationca.persist.entity.manager;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentAttributeResult;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.UUID;
public interface ComponentAttributeRepository extends JpaRepository<ComponentAttributeResult, UUID> {
List<ComponentAttributeResult> findByComponentId(UUID componentId);
}

View File

@ -11,4 +11,5 @@ import java.util.UUID;
public interface ComponentResultRepository extends JpaRepository<ComponentResult, UUID> {
List<ComponentResult> findByBoardSerialNumber(String boardSerialNumber);
List<ComponentResult> findByCertificateSerialNumberAndBoardSerialNumber(String certificateSerialNumber, String boardSerialNumber);
}

View File

@ -10,7 +10,6 @@ import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.LinkedList;
import java.util.List;
@ -25,12 +24,6 @@ import java.util.List;
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ComponentResult extends ArchivableEntity {
private String boardSerialNumber;
@Setter
private String expected = "";
@Setter
private String actual = "";
// embedded component info
private String manufacturer;
private String model;
@ -42,11 +35,12 @@ public class ComponentResult extends ArchivableEntity {
private AttributeStatus attributeStatus;
private String componentAddress;
private boolean version2 = false;
private boolean mismatched = false;
private boolean mismatched;
private String certificateType;
private String issuerDN;
private String certificateSerialNumber;
private String boardSerialNumber;
private String uniformResourceIdentifier;
@ -55,9 +49,11 @@ public class ComponentResult extends ArchivableEntity {
* @param boardSerialNumber associated platform certificate serial number.
* @param componentIdentifier object with information from the platform certificate components.
*/
public ComponentResult(final String boardSerialNumber, final String certificateType,
public ComponentResult(final String boardSerialNumber, final String certificateSerialNumber,
final String certificateType,
final ComponentIdentifier componentIdentifier) {
this.boardSerialNumber = boardSerialNumber;
this.certificateSerialNumber = certificateSerialNumber;
this.certificateType = certificateType;
this.manufacturer = componentIdentifier.getComponentManufacturer().toString();
this.model = componentIdentifier.getComponentModel().toString();
@ -74,33 +70,32 @@ public class ComponentResult extends ArchivableEntity {
componentAddress = sb.toString();
// V2 fields
if (componentIdentifier.isVersion2()) {
if (componentIdentifier.isVersion2()
&& componentIdentifier instanceof ComponentIdentifierV2) {
// this is a downside of findbugs, the code is set up to indicate if a CI is V2 or not
// but find bugs is throwing a flag because instanceof isn't being used.
ComponentIdentifierV2 ciV2 = (ComponentIdentifierV2) componentIdentifier;
this.componentClass = ciV2.getComponentClass().toString();
this.attributeStatus = ciV2.getAttributeStatus();
this.version2 = true;
if (ciV2.getCertificateIdentifier() != null) {
this.issuerDN = ciV2.getCertificateIdentifier().getIssuerDN().toString();
this.certificateSerialNumber = ciV2.getCertificateIdentifier()
.getCertificateSerialNumber().toString();
// this.certificateSerialNumber = ciV2.getCertificateIdentifier()
// .getCertificateSerialNumber().toString();
if (ciV2.getComponentPlatformUri() != null) {
this.uniformResourceIdentifier = ciV2.getComponentPlatformUri()
.getUniformResourceIdentifier().toString();
}
}
}
checkMatchedStatus();
}
/**
* This method is used to update the mismatched status flag for
* displaying red if there is a failure.
* This method is only used by the certificate-details.jsp page. This
* method splits the compiled string of addresses into the component address
* object for display on the jsp page.
* @return a collection of component addresses.
*/
public void checkMatchedStatus() {
this.mismatched = this.actual.equals(this.expected);
}
public List<ComponentAddress> getComponentAddresses() {
List<ComponentAddress> addresses = new LinkedList<>();
ComponentAddress address;
@ -120,13 +115,8 @@ public class ComponentResult extends ArchivableEntity {
* @return a string for the component result
*/
public String toString() {
if (isMismatched()) {
return String.format("ComponentResult: expected=[%s] actual=[%s]",
expected, actual);
} else {
return String.format("ComponentResult: certificateSerialNumber=[%s] "
+ "manufacturer=[%s] model=[%s] componentClass=[%s]",
boardSerialNumber, manufacturer, model, componentClass);
}
return String.format("ComponentResult: certificateSerialNumber=[%s] "
+ "manufacturer=[%s] model=[%s] componentClass=[%s]",
boardSerialNumber, manufacturer, model, componentClass);
}
}

View File

@ -0,0 +1,45 @@
package hirs.attestationca.persist.entity.userdefined.certificate.attributes;
import hirs.attestationca.persist.entity.ArchivableEntity;
import jakarta.persistence.Entity;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.UUID;
/**
* This is tied to the ComponentResult class. If a component has a mismatched
* value from what the device has listed, this class represents which attribute
* of that component mismatched.
*/
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ComponentAttributeResult extends ArchivableEntity {
@Getter
private UUID componentId;
private String expectedValue;
private String actualValue;
/**
* Default constructor that populates the expected and actual values.
* @param expectedValue platform certificate value
* @param actualValue paccor value from the device
*/
public ComponentAttributeResult(final UUID componentId,
final String expectedValue,
final String actualValue) {
this.componentId = componentId;
this.expectedValue = expectedValue;
this.actualValue = actualValue;
}
/**
* This method is used to check the mismatched status flag for
* displaying red if there is a failure.
*/
public boolean checkMatchedStatus() {
return this.actualValue.equals(this.expectedValue);
}
}

View File

@ -19,26 +19,22 @@ import java.net.UnknownHostException;
* Store information about the Portal into the database.
*/
@NoArgsConstructor
@Getter
@Entity
@Table(name = "PortalInfo")
@Access(AccessType.FIELD)
public class PortalInfo {
@Id
@Getter
@Column
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Getter
@Column(unique = true, nullable = false)
private String name;
@Getter
@Column
private InetAddress ipAddress;
@Getter
@Column
private int port = 0;
@Getter
@Column
private String context;
@ -57,14 +53,14 @@ public class PortalInfo {
/**
* Stores the address of the portal.
*
* @param newip address used by the portal.
* @param inetAddress address used by the portal.
*/
public void setIpAddress(final InetAddress newip) {
if (newip == null) {
public void setIpAddress(final InetAddress inetAddress) {
if (inetAddress == null) {
throw new IllegalArgumentException("setIpAddress input was null.");
}
ipAddress = newip;
this.ipAddress = inetAddress;
}
/**
@ -74,18 +70,18 @@ public class PortalInfo {
* @throws UnknownHostException For problems resolving or storing the host.
*/
public void setIpAddress(final String host) throws UnknownHostException {
ipAddress = InetAddress.getByName(host);
this.ipAddress = InetAddress.getByName(host);
}
/**
* Store the port of the portal.
*
* @param newport port of the portal
* @param port port of the portal
*/
public void setPort(final int newport) {
public void setPort(final int port) {
final int upperBound = 65535;
if (newport > 0 && newport <= upperBound) {
port = newport;
if (port > 0 && port <= upperBound) {
this.port = port;
} else {
throw new IllegalArgumentException("Failed to store portal port. Provided number was"
+ " outside of valid range (1 - " + upperBound + ")");

View File

@ -213,7 +213,9 @@ public class IdentityClaimProcessor extends AbstractProcessor {
// store component results objects
for (PlatformCredential platformCredential : platformCredentials) {
List<ComponentResult> componentResults = componentResultRepository
.findByBoardSerialNumber(platformCredential.getPlatformSerial());
.findByCertificateSerialNumberAndBoardSerialNumber(
platformCredential.getSerialNumber().toString(),
platformCredential.getPlatformSerial());
if (componentResults.isEmpty()) {
handlePlatformComponents(platformCredential);
}
@ -622,6 +624,7 @@ public class IdentityClaimProcessor extends AbstractProcessor {
.getComponentIdentifiers()) {
componentResult = new ComponentResult(platformCredential.getPlatformSerial(),
platformCredential.getSerialNumber().toString(),
platformCredential.getPlatformChainType(),
componentIdentifier);
componentResultRepository.save(componentResult);

View File

@ -4,6 +4,7 @@ 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.ComponentAttributeRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.PolicyRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
@ -22,6 +23,7 @@ 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.apache.logging.log4j.Level;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -33,8 +35,6 @@ 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;
@ -47,6 +47,7 @@ public class SupplyChainValidationService {
private ReferenceManifestRepository referenceManifestRepository;
private ReferenceDigestValueRepository referenceDigestValueRepository;
private ComponentResultRepository componentResultRepository;
private ComponentAttributeRepository componentAttributeRepository;
private CertificateRepository certificateRepository;
private SupplyChainValidationRepository supplyChainValidationRepository;
private SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository;
@ -70,6 +71,7 @@ public class SupplyChainValidationService {
final PolicyRepository policyRepository,
final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository,
final ComponentAttributeRepository componentAttributeRepository,
final ReferenceManifestRepository referenceManifestRepository,
final SupplyChainValidationRepository supplyChainValidationRepository,
final SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository,
@ -78,6 +80,7 @@ public class SupplyChainValidationService {
this.policyRepository = policyRepository;
this.certificateRepository = certificateRepository;
this.componentResultRepository = componentResultRepository;
this.componentAttributeRepository = componentAttributeRepository;
this.referenceManifestRepository = referenceManifestRepository;
this.supplyChainValidationRepository = supplyChainValidationRepository;
this.supplyChainValidationSummaryRepository = supplyChainValidationSummaryRepository;
@ -225,7 +228,8 @@ public class SupplyChainValidationService {
// if there are no deltas, just check base credential
platformScv = ValidationService.evaluatePCAttributesStatus(
baseCredential, device.getDeviceInfo(), ec,
certificateRepository, componentResultRepository);
certificateRepository, componentResultRepository,
componentAttributeRepository);
validations.add(new SupplyChainValidation(
SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
platformScv.getValidationResult(), aes, platformScv.getMessage()));

View File

@ -3,6 +3,7 @@ package hirs.attestationca.persist.service;
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.ComponentAttributeRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
@ -104,7 +105,8 @@ public class ValidationService {
final PlatformCredential pc, final DeviceInfoReport deviceInfoReport,
final EndorsementCredential ec,
final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository) {
final ComponentResultRepository componentResultRepository,
final ComponentAttributeRepository componentAttributeRepository) {
final SupplyChainValidation.ValidationType validationType
= SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES;
@ -115,8 +117,12 @@ public class ValidationService {
null, Level.ERROR);
}
log.info("Validating platform credential attributes");
List<ComponentResult> componentResults = componentResultRepository
.findByCertificateSerialNumberAndBoardSerialNumber(
pc.getSerialNumber().toString(), pc.getPlatformSerial());
AppraisalStatus result = CredentialValidator.
validatePlatformCredentialAttributes(pc, deviceInfoReport, ec);
validatePlatformCredentialAttributes(pc, deviceInfoReport, ec,
componentResultRepository, componentAttributeRepository);
switch (result.getAppStatus()) {
case PASS:
return buildValidationRecord(validationType, AppraisalStatus.Status.PASS,

View File

@ -1,6 +1,8 @@
package hirs.attestationca.persist.validation;
import hirs.attestationca.persist.entity.ArchivableEntity;
import hirs.attestationca.persist.entity.manager.ComponentAttributeRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
@ -179,7 +181,6 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
+ " did not match the Certificate's Serial Number";
log.error(message);
status = new AppraisalStatus(FAIL, message);
}
}
}
@ -187,7 +188,6 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
return status;
}
/**
* Validates device info report against the new platform credential.
* @param platformCredential the Platform Credential
@ -196,7 +196,9 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
*/
public static AppraisalStatus validatePlatformCredentialAttributesV2p0(
final PlatformCredential platformCredential,
final DeviceInfoReport deviceInfoReport) {
final DeviceInfoReport deviceInfoReport,
final ComponentResultRepository componentResultRepository,
final ComponentAttributeRepository componentAttributeRepository) {
boolean passesValidation = true;
StringBuilder resultMessage = new StringBuilder();
@ -291,16 +293,16 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
List<ComponentInfo> componentInfoList
= getComponentInfoFromPaccorOutput(paccorOutputString);
unmatchedComponents = validateV2p0PlatformCredentialComponentsExpectingExactMatch(
platformCredential.getId(),
validPcComponents, componentInfoList);
fieldValidation &= unmatchedComponents.isEmpty();
} catch (IOException e) {
} catch (IOException ioEx) {
final String baseErrorMessage = "Error parsing JSON output from PACCOR: ";
log.error(baseErrorMessage + e.toString());
log.error(baseErrorMessage + ioEx);
log.error("PACCOR output string:\n" + paccorOutputString);
return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage());
return new AppraisalStatus(ERROR, baseErrorMessage + ioEx.getMessage());
}
// WIP clean this up
StringBuilder additionalInfo = new StringBuilder();
if (!fieldValidation) {
resultMessage.append("There are unmatched components:\n");
@ -510,7 +512,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
ciV2 = (ComponentIdentifierV2) cId;
if (cInfo.getComponentClass().contains(
ciV2.getComponentClass().getComponentIdentifier())
&& isMatch(certificateId, cId, cInfo)) {
&& isMatch(cId, cInfo)) {
subCompIdList.remove(cId);
subCompInfoList.remove(cInfo);
}
@ -705,10 +707,10 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
* **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
* @return true if validation passes
* @return passes if the returned value is empty, otherwise the components that are unmatched
* populate the string
*/
private static String validateV2p0PlatformCredentialComponentsExpectingExactMatch(
final UUID certificateId,
final List<ComponentIdentifier> untrimmedPcComponents,
final List<ComponentInfo> allDeviceInfoComponents) {
// For each manufacturer listed in the platform credential, create two lists:
@ -780,7 +782,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
if (first.isPresent()) {
ComponentInfo potentialMatch = first.get();
if (isMatch(certificateId, pcComponent, potentialMatch)) {
if (isMatch(pcComponent, potentialMatch)) {
pcComponentsFromManufacturer.remove(pcComponent);
deviceInfoComponentsFromManufacturer.remove(potentialMatch);
}
@ -808,7 +810,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
if (first.isPresent()) {
ComponentInfo potentialMatch = first.get();
if (isMatch(certificateId, pcComponent, potentialMatch)) {
if (isMatch(pcComponent, potentialMatch)) {
pcComponentsFromManufacturer.remove(pcComponent);
deviceInfoComponentsFromManufacturer.remove(potentialMatch);
}
@ -822,7 +824,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
= deviceInfoComponentsFromManufacturer.iterator();
while (diComponentIter.hasNext()) {
ComponentInfo potentialMatch = diComponentIter.next();
if (isMatch(certificateId, ci, potentialMatch)) {
if (isMatch(ci, potentialMatch)) {
pcComponentsFromManufacturer.remove(ci);
diComponentIter.remove();
}
@ -861,63 +863,34 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
/**
* Checks if the fields in the potentialMatch match the fields in the pcComponent,
* or if the relevant field in the pcComponent is empty.
* @param certificateId the certificate id
* @param pcComponent the platform credential component
* @param potentialMatch the component info from a device info report
* @return true if the fields match exactly (null is considered the same as an empty string)
*/
private static boolean isMatch(final UUID certificateId,
final ComponentIdentifier pcComponent,
private static boolean isMatch(final ComponentIdentifier pcComponent,
final ComponentInfo potentialMatch) {
boolean matchesSoFar = true;
// List<ComponentResult> componentResultList = new LinkedList<>();
matchesSoFar &= isMatchOrEmptyInPlatformCert(
potentialMatch.getComponentManufacturer(),
pcComponent.getComponentManufacturer()
);
// if (matchesSoFar) {
// componentResultList.add(new ComponentResult(certificateId,
// potentialMatch.getComponentSerial(),
// pcComponent.getComponentSerial().getString()));
// }
matchesSoFar &= isMatchOrEmptyInPlatformCert(
potentialMatch.getComponentModel(),
pcComponent.getComponentModel()
);
// if (matchesSoFar) {
// componentResultList.add(new ComponentResult(certificateId,
// potentialMatch.getComponentSerial(),
// pcComponent.getComponentSerial().getString()));
// }
matchesSoFar &= isMatchOrEmptyInPlatformCert(
potentialMatch.getComponentSerial(),
pcComponent.getComponentSerial()
);
// if (matchesSoFar) {
// componentResultList.add(new ComponentResult(certificateId,
// potentialMatch.getComponentSerial(),
// pcComponent.getComponentSerial().getString()));
// }
matchesSoFar &= isMatchOrEmptyInPlatformCert(
potentialMatch.getComponentRevision(),
pcComponent.getComponentRevision()
);
// if (matchesSoFar) {
// componentResultList.add(new ComponentResult(certificateId,
// potentialMatch.getComponentSerial(),
// pcComponent.getComponentSerial().getString()));
// }
// componentResultMap.put(pcComponent, componentResultList);
return matchesSoFar;
}
@ -1000,7 +973,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid
* @param platformSerialNumberDescription description of the serial number for logging purposes.
* @param deviceInfoSerialNumbers the map of device info serial numbers
* (key = description, value = serial number)
* @return true if the platform serial number was found (case insensitive search),
* @return true if the platform serial number was found (case-insensitive search),
* false otherwise
*/
private static boolean deviceInfoContainsPlatformSerialNumber(

View File

@ -1,5 +1,7 @@
package hirs.attestationca.persist.validation;
import hirs.attestationca.persist.entity.manager.ComponentAttributeRepository;
import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
@ -165,7 +167,9 @@ public class CredentialValidator extends SupplyChainCredentialValidator {
public static AppraisalStatus validatePlatformCredentialAttributes(
final PlatformCredential platformCredential,
final DeviceInfoReport deviceInfoReport,
final EndorsementCredential endorsementCredential) {
final EndorsementCredential endorsementCredential,
final ComponentResultRepository componentResultRepository,
final ComponentAttributeRepository componentAttributeRepository) {
final String baseErrorMessage = "Can't validate platform credential attributes without ";
String message;
if (platformCredential == null) {
@ -192,7 +196,8 @@ public class CredentialValidator extends SupplyChainCredentialValidator {
String credentialType = platformCredential.getCredentialType();
if (PlatformCredential.CERTIFICATE_TYPE_2_0.equals(credentialType)) {
return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV2p0(
platformCredential, deviceInfoReport);
platformCredential, deviceInfoReport, componentResultRepository,
componentAttributeRepository);
}
return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV1p2(
platformCredential, deviceInfoReport);

View File

@ -982,6 +982,7 @@ public class CertificatePageController extends PageController<NoPageParams> {
.getComponentIdentifiers()) {
componentResult = new ComponentResult(platformCredential.getPlatformSerial(),
platformCredential.getSerialNumber().toString(),
platformCredential.getPlatformChainType(),
componentIdentifier);
componentResultRepository.save(componentResult);

View File

@ -619,7 +619,7 @@
<div class="component col col-md-4">
<div class="panel panel-default">
<c:choose>
<c:when test="${fn:${component.isMismatched()=='TRUE'}">
<c:when test="${component.isMismatched()=='TRUE'}">
<div class="panel-heading" style="background-color: red; color: white">
</c:when>
<c:otherwise>