From 4b67747e3e6344ee23c8939719cc75d4e4bae3c0 Mon Sep 17 00:00:00 2001
From: Cyrus <24922493+cyrus-dev@users.noreply.github.com>
Date: Thu, 21 Sep 2023 15:02:24 -0400
Subject: [PATCH] Updated the bulk of the code that does all provisioning from
 a client. There is some parsed functionality to ease sorting through the
 changes and updates needed in the future.

---
 HIRS_AttestationCA/build.gradle               |    1 +
 .../persist/PCRQuoteValidator.java            |  223 ---
 .../ReferenceDigestValueRepository.java       |    5 +-
 .../manager/ReferenceManifestRepository.java  |    2 +
 .../certificate/PlatformCredential.java       |    2 +
 .../provision/CertificateRequestHandler.java  |    1 +
 .../provision/IdentityClaimHandler.java       |    9 +-
 .../service/SupplyChainValidationService.java |  366 +++-
 .../SupplyChainValidationServiceImpl.java     |  377 ----
 .../attestationca/persist/util}/PciIds.java   |    2 +-
 .../validation/CredentialValidator.java       |  223 ++-
 .../persist/validation/PcrValidator.java      |   26 +
 .../SupplyChainCredentialValidator.java       |  496 ++++-
 ...eferenceManifestDetailsPageController.java |   28 +-
 .../utils/CertificateStringMapBuilder.java    |    1 +
 .../utils/SupplyChainCredentialValidator.java | 1766 -----------------
 .../utils/tpm/eventlog/uefi/UefiGuid.java     |    2 +-
 17 files changed, 1055 insertions(+), 2475 deletions(-)
 delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/PCRQuoteValidator.java
 delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationServiceImpl.java
 rename {HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils => HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util}/PciIds.java (99%)
 delete mode 100644 HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/SupplyChainCredentialValidator.java

diff --git a/HIRS_AttestationCA/build.gradle b/HIRS_AttestationCA/build.gradle
index 31806ddd..e9427645 100644
--- a/HIRS_AttestationCA/build.gradle
+++ b/HIRS_AttestationCA/build.gradle
@@ -36,6 +36,7 @@ dependencies {
     implementation libs.jakarta.api
     implementation libs.jakarta.xml
     implementation libs.hibernate.core
+    implementation libs.pci
     implementation libs.guava
     implementation libs.jackson.core
     implementation libs.jackson.databind
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/PCRQuoteValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/PCRQuoteValidator.java
deleted file mode 100644
index 431dacf6..00000000
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/PCRQuoteValidator.java
+++ /dev/null
@@ -1,223 +0,0 @@
-package hirs.attestationca.persist;
-
-import hirs.attestationca.persist.entity.userdefined.PolicySettings;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import lombok.extern.log4j.Log4j2;
-
-/**
- * The class handles the flags that ignore certain PCRs for validation.
- */
-@Log4j2
-@NoArgsConstructor
-public class PCRQuoteValidator {
-
-    /**
-     * Minimum possible value for a PCR ID. This is 0.
-     */
-    public static final int MIN_PCR_ID = 0;
-
-    /**
-     * Maximum possible value for a PCR ID. This is 23.
-     */
-    public static final int MAX_PCR_ID = 23;
-
-    private static final int NUM_TO_SKIP = 1;
-    private static final int NUM_OF_TBOOT_PCR = 3;
-    // PCR 5-16
-    private static final int PXE_PCR_START = 5;
-    private static final int PXE_PCR_END = 16;
-    // PCR 10
-    private static final int IMA_PCR = 10;
-    // PCR 17-19
-    private static final int TBOOT_PCR_START = 17;
-    private static final int TBOOT_PCR_END = 19;
-    // PCR 5
-    private static final int GPT_PCR = 5;
-    private static final int IMA_MASK = 0xfffbff;
-
-    // Event Log Event Types
-    private static final String EVT_EFI_BOOT = "EV_EFI_BOOT_SERVICES_APPLICATION";
-    private static final String EVT_EFI_VAR = "EV_EFI_VARIABLE_BOOT";
-    private static final String EVT_EFI_GPT = "EV_EFI_GPT_EVENT";
-    private static final String EVT_EFI_CFG = "EV_EFI_VARIABLE_DRIVER_CONFIG";
-
-    private String[] baselinePCRS = new String[MAX_PCR_ID + 1];
-    @Getter
-    @Setter
-    private PolicySettings settings;
-
-    /**
-     * Constructor to parse PCR values.
-     * @param pcrValues pcrValues RIM provided baseline PCRs
-     * @param settings settings for the supply chain portal settings for provisioning
-     */
-    public PCRQuoteValidator(final String[] pcrValues,
-                             final PolicySettings settings) {
-        if (pcrValues != null) {
-            baselinePCRS = new String[MAX_PCR_ID + 1];
-            for (int i = 0; i <= MAX_PCR_ID; i++) {
-                baselinePCRS[i] = pcrValues[i];
-            }
-        }
-
-        this.settings = settings;
-    }
-
-    /**
-     * Getter for the array of baseline PCRs.
-     * @return instance of the PCRs.
-     */
-    public String[] getBaselinePCRS() {
-        return baselinePCRS.clone();
-    }
-
-    /**
-     * Setter for the array of baseline PCRs.
-     * @param baselinePCRS instance of the PCRs.
-     */
-    public void setBaselinePCRS(final String[] baselinePCRS) {
-        this.baselinePCRS = baselinePCRS.clone();
-    }
-
-    /**
-     * Compares the baseline pcr list and the quote pcr list.  If the
-     * ignore flags are set, 10 and 17-19 will be skipped for comparison.
-     *
-     * @param storedPCRS non-baseline pcr list
-     * @return a StringBuilder that is empty if everything passes.
-     */
-    public StringBuilder validatePCRS(final String[] storedPCRS) {
-        StringBuilder sb = new StringBuilder();
-        String failureMsg = "PCR %d does not match%n";
-        if (storedPCRS[0] == null || storedPCRS[0].isEmpty()) {
-            sb.append("failureMsg");
-        } else {
-            for (int i = 0; i <= MAX_PCR_ID; i++) {
-                if (settings.isIgnoreImaEnabled() && i == IMA_PCR) {
-                    log.info("PCR Policy IMA Ignore enabled.");
-                    i += NUM_TO_SKIP;
-                }
-
-                if (settings.isIgnoretBootEnabled() && i == TBOOT_PCR_START) {
-                    log.info("PCR Policy TBoot Ignore enabled.");
-                    i += NUM_OF_TBOOT_PCR;
-                }
-
-                if (settings.isIgnoreGptEnabled() && i == GPT_PCR) {
-                    log.info("PCR Policy GPT Ignore enabled.");
-                    i += NUM_TO_SKIP;
-                }
-
-                if (!baselinePCRS[i].equals(storedPCRS[i])) {
-                    //error
-                    log.error(String.format("%s =/= %s", baselinePCRS[i], storedPCRS[i]));
-                    sb.append(String.format(failureMsg, i));
-                }
-            }
-        }
-
-        return sb;
-    }
-
-    /**
-     * Checks that the expected FM events occurring. There are policy options that
-     * will ignore certain PCRs, Event Types and Event Variables present.
-     * @param tcgMeasurementLog Measurement log from the client
-     * @param eventValueMap The events stored as baseline to compare
-     * @return the events that didn't pass
-     */
-//    public List<TpmPcrEvent> validateTpmEvents(final TCGEventLog tcgMeasurementLog,
-//                                               final Map<String, ReferenceDigestValue> eventValueMap) {
-//        List<TpmPcrEvent> tpmPcrEvents = new LinkedList<>();
-//        for (TpmPcrEvent tpe : tcgMeasurementLog.getEventList()) {
-//            if (enableIgnoreIma && tpe.getPcrIndex() == IMA_PCR) {
-//                log.info(String.format("IMA Ignored -> %s", tpe));
-//            } else if (enableIgnoretBoot && (tpe.getPcrIndex() >= TBOOT_PCR_START
-//                    && tpe.getPcrIndex() <= TBOOT_PCR_END)) {
-//                log.info(String.format("TBOOT Ignored -> %s", tpe));
-//            } else if (enableIgnoreOsEvt && (tpe.getPcrIndex() >= PXE_PCR_START
-//                    && tpe.getPcrIndex() <= PXE_PCR_END)) {
-//                log.info(String.format("OS Evt Ignored -> %s", tpe));
-//            } else {
-//                if (enableIgnoreGpt && tpe.getEventTypeStr().contains(EVT_EFI_GPT)) {
-//                    log.info(String.format("GPT Ignored -> %s", tpe));
-//                } else if (enableIgnoreOsEvt && (tpe.getEventTypeStr().contains(EVT_EFI_BOOT)
-//                        || tpe.getEventTypeStr().contains(EVT_EFI_VAR))) {
-//                    log.info(String.format("OS Evt Ignored -> %s", tpe));
-//                } else if (enableIgnoreOsEvt && (tpe.getEventTypeStr().contains(EVT_EFI_CFG)
-//                        && tpe.getEventContentStr().contains("SecureBoot"))) {
-//                    log.info(String.format("OS Evt Config Ignored -> %s", tpe));
-//                } else {
-//                    if (!eventValueMap.containsKey(tpe.getEventDigestStr())) {
-//                        tpmPcrEvents.add(tpe);
-//                    }
-//                }
-//            }
-//        }
-//
-//        return tpmPcrEvents;
-//    }
-
-    /**
-     * Compares hashes to validate the quote from the client.
-     *
-     * @param tpmQuote the provided quote
-     * @param storedPCRS values from the RIM file
-     * @return true if validated, false if not
-     */
-//    public boolean validateQuote(final byte[] tpmQuote, final String[] storedPCRS) {
-//        System.out.println("Validating quote from associated device.");
-//        boolean validated = false;
-//        short localityAtRelease = 0;
-//        String quoteString = new String(tpmQuote, StandardCharsets.UTF_8);
-//        int pcrMaskSelection = PcrSelection.ALL_PCRS_ON;
-//
-//        if (enableIgnoreIma) {
-//            pcrMaskSelection = IMA_MASK;
-//        }
-//
-//        ArrayList<TPMMeasurementRecord> measurements = new ArrayList<>();
-//
-//        try {
-//            for (int i = 0; i < storedPcrs.length; i++) {
-//                if (i == IMA_PCR && enableIgnoreIma) {
-//                    log.info("Ignore IMA PCR policy is enabled.");
-//                } else {
-//                    measurements.add(new TPMMeasurementRecord(i, storedPcrs[i]));
-//                }
-//            }
-//        } catch (DecoderException deEx) {
-//            //error
-//            System.out.println(deEx);
-//        }
-//
-//        PcrSelection pcrSelection = new PcrSelection(pcrMaskSelection);
-//        PcrComposite pcrComposite = new PcrComposite(pcrSelection);
-//        PcrInfoShort pcrInfoShort = new PcrInfoShort(pcrSelection,
-//                localityAtRelease,
-//                tpmQuote, pcrComposite);
-//
-//        try {
-//            /**
-//             * The calculated string is being used in the contains method
-//             * because the TPM Quote's hash isn't just for PCR values,
-//             * it contains the calculated digest of the PCRs, along with
-//             * other information.
-//             */
-//            String calculatedString = Hex.encodeHexString(
-//                    pcrInfoShort.getCalculatedDigest());
-//            validated = quoteString.contains(calculatedString);
-//            if (!validated) {
-//                // warn
-//                System.out.println(calculatedString + " not found in " + quoteString);
-//            }
-//        } catch (NoSuchAlgorithmException naEx) {
-//            // error
-//            System.out.println(naEx);
-//        }
-//
-//        return validated;
-//    }
-}
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/manager/ReferenceDigestValueRepository.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/manager/ReferenceDigestValueRepository.java
index 24be3dd5..c228a587 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/manager/ReferenceDigestValueRepository.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/manager/ReferenceDigestValueRepository.java
@@ -11,12 +11,9 @@ import java.util.UUID;
 @Repository
 public interface ReferenceDigestValueRepository extends JpaRepository<ReferenceDigestValue, UUID> {
 
-    @Query(value = "SELECT * FROM ReferenceDigestValue", nativeQuery = true)
-    List<ReferenceDigestValue> listAll();
     List<ReferenceDigestValue> findByModel(String model);
     List<ReferenceDigestValue> findByManufacturer(String manufacturer);
-    @Query(value = "SELECT * FROM ReferenceDigestValue WHERE baseRimId = '?1' OR supportRimId = '?1'", nativeQuery = true)
-    List<ReferenceDigestValue> getValuesByRimId(UUID associatedRimId);
+    List<ReferenceDigestValue> findValuesByBaseRimId(UUID associatedRimId);
     List<ReferenceDigestValue> findBySupportRimId(UUID supportRimId);
     List<ReferenceDigestValue> findBySupportRimHash(String supportRimHash);
     List<ReferenceDigestValue> findByManufacturerAndModel(String manufacturer, String model);
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/manager/ReferenceManifestRepository.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/manager/ReferenceManifestRepository.java
index b74516bf..eb0892b2 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/manager/ReferenceManifestRepository.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/manager/ReferenceManifestRepository.java
@@ -39,4 +39,6 @@ public interface ReferenceManifestRepository extends JpaRepository<ReferenceMani
     EventLogMeasurements byMeasurementDeviceName(String deviceName);
     @Query(value = "SELECT * FROM ReferenceManifest WHERE platformManufacturer = ?1 AND platformModel = ?2 AND rimType = 'Support'", nativeQuery = true)
     List<SupportReferenceManifest> getSupportByManufacturerModel(String manufacturer, String model);
+    @Query(value = "SELECT * FROM ReferenceManifest WHERE platformModel = ?1 AND DTYPE = 'EventLogMeasurements'", nativeQuery = true)
+    EventLogMeasurements getLogByModel(String model);
 }
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredential.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredential.java
index 52b6769e..4956723f 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredential.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredential.java
@@ -176,6 +176,8 @@ public class PlatformCredential extends DeviceAssociatedCertificate {
 
     @Column(length = MAX_MESSAGE_LENGTH)
     private String componentFailures = Strings.EMPTY;
+    @Column(length = MAX_MESSAGE_LENGTH)
+    private String componentFailureMessage = Strings.EMPTY;
 
     @Transient
     private EndorsementCredential endorsementCredential = null;
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/CertificateRequestHandler.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/CertificateRequestHandler.java
index 2ca0611c..5eb42b76 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/CertificateRequestHandler.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/CertificateRequestHandler.java
@@ -198,6 +198,7 @@ public class CertificateRequestHandler extends AbstractRequestHandler {
      * @return the {@link AppraisalStatus} of the supply chain validation
      */
     private AppraisalStatus.Status doQuoteValidation(final Device device) {
+        log.info("Beginning Quote Validation...");
         // perform supply chain validation
         SupplyChainValidationSummary scvs = supplyChainValidationService.validateQuote(
                 device);
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/IdentityClaimHandler.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/IdentityClaimHandler.java
index a2d6dfc8..4dc3458c 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/IdentityClaimHandler.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/IdentityClaimHandler.java
@@ -124,6 +124,7 @@ public class IdentityClaimHandler extends AbstractRequestHandler {
         try {
             validationResult = doSupplyChainValidation(claim, ekPub);
         } catch (Exception ex) {
+            log.error(ex.getMessage());
             for (StackTraceElement ste : ex.getStackTrace()) {
                 log.error(ste.toString());
             }
@@ -191,12 +192,15 @@ public class IdentityClaimHandler extends AbstractRequestHandler {
         // this is to check what is in the platform object and pull
         // additional information from the DB if information exists
         if (platformCredentials.size() == 1) {
+            List<PlatformCredential> tempList = new LinkedList<>();
             for (PlatformCredential pc : platformCredentials) {
                 if (pc != null && pc.getPlatformSerial() != null) {
-                    platformCredentials.addAll(certificateRepository
+                    tempList.addAll(certificateRepository
                             .byBoardSerialNumber(pc.getPlatformSerial()));
                 }
             }
+
+            platformCredentials.addAll(tempList);
         }
         // perform supply chain validation
         SupplyChainValidationSummary summary = supplyChainValidationService.validateSupplyChain(
@@ -227,6 +231,9 @@ public class IdentityClaimHandler extends AbstractRequestHandler {
         log.info("Processing Device Info Report");
         // store device and device info report.
         Device device = this.deviceRepository.findByName(deviceInfoReport.getNetworkInfo().getHostname());
+        if (device == null) {
+            device = new Device(deviceInfoReport);
+        }
         device.setDeviceInfo(deviceInfoReport);
         return this.deviceRepository.save(device);
     }
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationService.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationService.java
index 55e01b09..1c6e9ec1 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationService.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationService.java
@@ -1,30 +1,259 @@
 package hirs.attestationca.persist.service;
 
+import hirs.attestationca.persist.DBManagerException;
+import hirs.attestationca.persist.entity.ArchivableEntity;
+import hirs.attestationca.persist.entity.manager.CACredentialRepository;
+import hirs.attestationca.persist.entity.manager.CertificateRepository;
+import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
+import hirs.attestationca.persist.entity.manager.PolicyRepository;
+import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
+import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
+import hirs.attestationca.persist.entity.manager.SupplyChainValidationSummaryRepository;
 import hirs.attestationca.persist.entity.userdefined.Device;
+import hirs.attestationca.persist.entity.userdefined.PolicySettings;
+import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
 import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary;
 import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
 import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
+import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
+import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
+import hirs.attestationca.persist.enums.AppraisalStatus;
+import hirs.attestationca.persist.validation.PcrValidator;
+import hirs.attestationca.persist.validation.SupplyChainCredentialValidator;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
 
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.Level;
+
+import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL;
+import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
+
+@Log4j2
+@Service
+public class SupplyChainValidationService {
+
+    private CACredentialRepository caCredentialRepository;
+    private PolicyRepository policyRepository;
+    private ReferenceManifestRepository referenceManifestRepository;
+    private ReferenceDigestValueRepository referenceDigestValueRepository;
+    private ComponentResultRepository componentResultRepository;
+    private CertificateRepository certificateRepository;
+    private SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository;
 
-/**
- * Interface defining a component that will perform supply chain validations, which yields a
- * {@link SupplyChainValidationSummary}.
- */
-public interface SupplyChainValidationService {
     /**
-     * The "main" method of supply chain validation. Takes the credentials from an identity
-     * request and validates the supply chain in accordance to the current supply chain
-     * policy.
+     * Constructor.
      *
-     * @param ec The endorsement credential from the identity request.
-     * @param pc The set of platform credentials from the identity request.
-     * @param device The device to be validated.
-     * @return True if validation is successful, false otherwise.
+     * @param caCredentialRepository    ca credential repository
+     * @param policyRepository                      the policy manager
+     * @param certificateRepository                 the cert manager
+     * @param componentResultRepository             the comp result manager
+     * @param referenceManifestRepository           the RIM manager
+     * @param supplyChainValidationSummaryRepository the summary manager
+     * @param referenceDigestValueRepository              the even manager
      */
-    SupplyChainValidationSummary validateSupplyChain(EndorsementCredential ec,
-                                                     List<PlatformCredential> pc,
-                                                     Device device);
+    @Autowired
+    @SuppressWarnings("ParameterNumberCheck")
+    public SupplyChainValidationService(
+            final CACredentialRepository caCredentialRepository,
+            final PolicyRepository policyRepository,
+            final CertificateRepository certificateRepository,
+            final ComponentResultRepository componentResultRepository,
+            final ReferenceManifestRepository referenceManifestRepository,
+            final SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository,
+            final ReferenceDigestValueRepository referenceDigestValueRepository) {
+        this.caCredentialRepository = caCredentialRepository;
+        this.policyRepository = policyRepository;
+        this.certificateRepository = certificateRepository;
+        this.componentResultRepository = componentResultRepository;
+        this.referenceManifestRepository = referenceManifestRepository;
+        this.supplyChainValidationSummaryRepository = supplyChainValidationSummaryRepository;
+        this.referenceDigestValueRepository = referenceDigestValueRepository;
+    }
+
+    /**
+     * The "main" method of supply chain validation. Takes the credentials from
+     * an identity request and validates the supply chain in accordance to the
+     * current supply chain policy.
+     *
+     * @param ec     The endorsement credential from the identity request.
+     * @param pcs    The platform credentials from the identity request.
+     * @param device The device to be validated.
+     * @return A summary of the validation results.
+     */
+    @SuppressWarnings("methodlength")
+    public SupplyChainValidationSummary validateSupplyChain(final EndorsementCredential ec,
+                                                            final List<PlatformCredential> pcs,
+                                                            final Device device) {
+        boolean acceptExpiredCerts = getPolicySettings().isExpiredCertificateValidationEnabled();
+        PlatformCredential baseCredential = null;
+        SupplyChainValidation platformScv = null;
+        SupplyChainValidation basePlatformScv = null;
+        boolean chkDeltas = false;
+        String pcErrorMessage = "";
+        List<SupplyChainValidation> validations = new LinkedList<>();
+        Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>();
+        SupplyChainValidation.ValidationType platformType = SupplyChainValidation
+                .ValidationType.PLATFORM_CREDENTIAL;
+        log.info("Beginning Supply Chain Validation...");
+
+        log.info("Beginning Endorsement Credential Validation...");
+        // Validate the Endorsement Credential
+        if (getPolicySettings().isEcValidationEnabled()) {
+            validations.add(ValidationManager.evaluateEndorsementCredentialStatus(ec, this.caCredentialRepository, acceptExpiredCerts));
+            // store the device with the credential
+            if (ec != null) {
+                ec.setDeviceId(device.getId());
+                this.certificateRepository.save(ec);
+            }
+        }
+
+        log.info("Beginning Platform Credential Validation...");
+        // Validate Platform Credential signatures
+        if (getPolicySettings().isPcValidationEnabled()) {
+            // Ensure there are platform credentials to validate
+            if (pcs == null || pcs.isEmpty()) {
+                log.error("There were no Platform Credentials to validate.");
+                pcErrorMessage = "Platform credential(s) missing\n";
+            } else {
+                for (PlatformCredential pc : pcs) {
+                    KeyStore trustedCa = ValidationManager.getCaChain(pc, caCredentialRepository);
+                    platformScv = ValidationManager.evaluatePlatformCredentialStatus(
+                            pc, trustedCa, acceptExpiredCerts);
+
+                    if (platformScv.getValidationResult() == AppraisalStatus.Status.FAIL) {
+                        pcErrorMessage = String.format("%s%s%n", pcErrorMessage,
+                                platformScv.getMessage());
+                    }
+                    // set the base credential
+                    if (pc.isPlatformBase()) {
+                        baseCredential = pc;
+                        basePlatformScv = platformScv;
+                    } else {
+                        chkDeltas = true;
+                        deltaMapping.put(pc, null);
+                    }
+                    pc.setDeviceId(device.getId());
+                    this.certificateRepository.save(pc);
+
+                }
+
+                // check that the delta certificates validity date is after
+                // the base
+                if (baseCredential != null) {
+                    for (PlatformCredential pc : pcs) {
+                        int result = baseCredential.getBeginValidity()
+                                .compareTo(pc.getBeginValidity());
+                        if (!pc.isPlatformBase() && (result > 0)) {
+                            pcErrorMessage = String.format("%s%s%n", pcErrorMessage,
+                                    "Delta Certificate's validity "
+                                            + "date is not after Base");
+                            break;
+                        }
+                    }
+                } else {
+                    // we don't have a base cert, fail
+                    pcErrorMessage = String.format("%s%s%n", pcErrorMessage,
+                            "Base Platform credential missing");
+                }
+            }
+
+            if (pcErrorMessage.isEmpty()) {
+                validations.add(platformScv);
+            } else {
+                if (pcs == null) {
+                    validations.add(new SupplyChainValidation(platformType,
+                            AppraisalStatus.Status.FAIL, new ArrayList<>(), pcErrorMessage));
+                } else {
+                    validations.add(new SupplyChainValidation(platformType,
+                            AppraisalStatus.Status.FAIL, new ArrayList<>(pcs), pcErrorMessage));
+                }
+            }
+        }
+
+        log.info("Beginning Platform Attributes Validation...");
+        // Validate Platform Credential attributes
+        if (getPolicySettings().isPcAttributeValidationEnabled()
+                && pcErrorMessage.isEmpty()) {
+            // Ensure there are platform credentials to validate
+            SupplyChainValidation attributeScv = null;
+            String attrErrorMessage = "";
+            List<ArchivableEntity> aes = new ArrayList<>();
+            // need to check if there are deltas, if not then just verify
+            // components of the base
+            if (baseCredential == null) {
+                validations.add(ValidationManager.buildValidationRecord(
+                        SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
+                        AppraisalStatus.Status.FAIL,
+                        "Base Platform credential missing."
+                                + " Cannot validate attributes",
+                        null, Level.ERROR));
+            } else {
+                if (chkDeltas) {
+                    aes.addAll(basePlatformScv.getCertificatesUsed());
+                    Iterator<PlatformCredential> it = pcs.iterator();
+                    while (it.hasNext()) {
+                        PlatformCredential pc = it.next();
+                        if (pc != null && !pc.isPlatformBase()) {
+                            attributeScv = ValidationManager.evaluateDeltaAttributesStatus(
+                                    pc, device.getDeviceInfo(),
+                                    baseCredential, deltaMapping, certificateRepository);
+                            if (attributeScv.getValidationResult() == AppraisalStatus.Status.FAIL) {
+                                attrErrorMessage = String.format("%s%s%n", attrErrorMessage,
+                                        attributeScv.getMessage());
+                            }
+                        }
+                    }
+                } else {
+                    aes.add(baseCredential);
+                    validations.remove(platformScv);
+                    // if there are no deltas, just check base credential
+                    platformScv = ValidationManager.evaluatePCAttributesStatus(
+                            baseCredential, device.getDeviceInfo(), ec,
+                            certificateRepository, componentResultRepository);
+                    validations.add(new SupplyChainValidation(
+                            SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
+                            platformScv.getValidationResult(), aes, platformScv.getMessage()));
+                }
+            }
+            if (!attrErrorMessage.isEmpty()) {
+                //combine platform and platform attributes
+                validations.remove(platformScv);
+                validations.add(new SupplyChainValidation(
+                        SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
+                        attributeScv.getValidationResult(), aes, attributeScv.getMessage()));
+            }
+        }
+
+        log.info("Beginning Firmware Validation...");
+        if (getPolicySettings().isFirmwareValidationEnabled()) {
+            // may need to associated with device to pull the correct info
+            // compare tpm quote with what is pulled from RIM associated file
+            validations.add(ValidationManager.evaluateFirmwareStatus(device, getPolicySettings(),
+                    referenceManifestRepository, referenceDigestValueRepository,
+                    caCredentialRepository));
+        }
+
+        log.info("The validation finished, summarizing...");
+        // Generate validation summary, save it, and return it.
+        SupplyChainValidationSummary summary
+                = new SupplyChainValidationSummary(device, validations);
+        try {
+            supplyChainValidationSummaryRepository.save(summary);
+        } catch (DBManagerException dbMEx) {
+            log.error("Failed to save Supply Chain Summary");
+        }
+
+        return summary;
+    }
 
     /**
      * A supplemental method that handles validating just the quote post main validation.
@@ -32,11 +261,110 @@ public interface SupplyChainValidationService {
      * @param device the associated device.
      * @return True if validation is successful, false otherwise.
      */
-    SupplyChainValidationSummary validateQuote(Device device);
+    public SupplyChainValidationSummary validateQuote(final Device device) {
+        SupplyChainValidation quoteScv = null;
+        SupplyChainValidationSummary summary = null;
+        Level level = Level.ERROR;
+        AppraisalStatus fwStatus = new AppraisalStatus(FAIL,
+                "Unknown exception caught during quote validation.");
+        SupportReferenceManifest sRim = null;
+        EventLogMeasurements eventLog = null;
+
+        // check if the policy is enabled
+        if (getPolicySettings().isFirmwareValidationEnabled()) {
+            String[] baseline = new String[Integer.SIZE];
+            String deviceName = device.getDeviceInfo()
+                    .getNetworkInfo().getHostname();
+
+            try {
+                List<SupportReferenceManifest> supportRims = referenceManifestRepository
+                        .getSupportByManufacturerModel(
+                                device.getDeviceInfo().getHardwareInfo().getManufacturer(),
+                                device.getDeviceInfo().getHardwareInfo().getProductName());
+                for (SupportReferenceManifest support : supportRims) {
+                    if (support.isBaseSupport()) {
+                        sRim = support;
+                    }
+                }
+                eventLog = (EventLogMeasurements) referenceManifestRepository
+                        .findByHexDecHash(sRim.getEventLogHash());
+
+                if (sRim == null) {
+                    fwStatus = new AppraisalStatus(FAIL,
+                            String.format("Firmware Quote validation failed: "
+                                            + "No associated Support RIM file "
+                                            + "could be found for %s",
+                                    deviceName));
+                } else if (eventLog == null) {
+                    fwStatus = new AppraisalStatus(FAIL,
+                            String.format("Firmware Quote validation failed: "
+                                            + "No associated Client Log file "
+                                            + "could be found for %s",
+                                    deviceName));
+                } else {
+                    baseline = sRim.getExpectedPCRList();
+                    String[] storedPcrs = eventLog.getExpectedPCRList();
+                    PcrValidator pcrValidator = new PcrValidator(baseline);
+                    // grab the quote
+                    byte[] hash = device.getDeviceInfo().getTpmInfo().getTpmQuoteHash();
+                    if (pcrValidator.validateQuote(hash, storedPcrs, getPolicySettings())) {
+                        level = Level.INFO;
+                        fwStatus = new AppraisalStatus(PASS,
+                                SupplyChainCredentialValidator.FIRMWARE_VALID);
+                        fwStatus.setMessage("Firmware validation of TPM Quote successful.");
+                    } else {
+                        fwStatus.setMessage("Firmware validation of TPM Quote failed."
+                                + "\nPCR hash and Quote hash do not match.");
+                    }
+                    eventLog.setOverallValidationResult(fwStatus.getAppStatus());
+                    this.referenceManifestRepository.save(eventLog);
+                }
+            } catch (Exception ex) {
+                log.error(ex);
+            }
+
+            quoteScv = ValidationManager.buildValidationRecord(SupplyChainValidation
+                            .ValidationType.FIRMWARE,
+                    fwStatus.getAppStatus(), fwStatus.getMessage(), eventLog, level);
+
+            // Generate validation summary, save it, and return it.
+            List<SupplyChainValidation> validations = new ArrayList<>();
+            SupplyChainValidationSummary previous
+                    = this.supplyChainValidationSummaryRepository.findByDevice(deviceName);
+            for (SupplyChainValidation scv : previous.getValidations()) {
+                if (scv.getValidationType() != SupplyChainValidation.ValidationType.FIRMWARE) {
+                    validations.add(ValidationManager.buildValidationRecord(scv.getValidationType(),
+                            scv.getValidationResult(), scv.getMessage(),
+                            scv.getCertificatesUsed().get(0), Level.INFO));
+                }
+            }
+            validations.add(quoteScv);
+            previous.archive();
+            supplyChainValidationSummaryRepository.save(previous);
+            summary = new SupplyChainValidationSummary(device, validations);
+
+            // try removing the supply chain validation as well and resaving that
+            try {
+                supplyChainValidationSummaryRepository.save(summary);
+            } catch (DBManagerException dbEx) {
+                log.error("Failed to save Supply Chain Summary", dbEx);
+            }
+        }
+
+        return summary;
+    }
 
     /**
-     * Allows other service access to the policy information.
-     * @return supply chain policy
+     * Helper function to get a fresh load of the default policy from the DB.
+     *
+     * @return The default Supply Chain Policy
      */
-//    SupplyChainPolicy getPolicy();
+    private PolicySettings getPolicySettings() {
+        PolicySettings defaultSettings = this.policyRepository.findByName("Default");
+
+        if (defaultSettings == null) {
+            defaultSettings = new PolicySettings("Default", "Settings are configured for no validation flags set.");
+        }
+        return defaultSettings;
+    }
 }
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationServiceImpl.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationServiceImpl.java
deleted file mode 100644
index 02c7c7ab..00000000
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationServiceImpl.java
+++ /dev/null
@@ -1,377 +0,0 @@
-package hirs.attestationca.persist.service;
-
-import hirs.attestationca.persist.entity.ArchivableEntity;
-import hirs.attestationca.persist.DBManagerException;
-import hirs.attestationca.persist.entity.manager.CACredentialRepository;
-import hirs.attestationca.persist.entity.manager.CertificateRepository;
-import hirs.attestationca.persist.entity.manager.ComponentResultRepository;
-import hirs.attestationca.persist.entity.manager.PolicyRepository;
-import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
-import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
-import hirs.attestationca.persist.entity.manager.SupplyChainValidationSummaryRepository;
-import hirs.attestationca.persist.entity.userdefined.Certificate;
-import hirs.attestationca.persist.entity.userdefined.Device;
-import hirs.attestationca.persist.entity.userdefined.PolicySettings;
-import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
-import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary;
-import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential;
-import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
-import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
-import hirs.attestationca.persist.entity.userdefined.record.TPMMeasurementRecord;
-import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
-import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
-import hirs.attestationca.persist.enums.AppraisalStatus;
-import hirs.attestationca.persist.validation.CredentialValidator;
-import hirs.attestationca.persist.validation.PcrValidator;
-import hirs.attestationca.persist.validation.SupplyChainCredentialValidator;
-import hirs.utils.BouncyCastleUtils;
-import lombok.extern.log4j.Log4j2;
-import org.bouncycastle.util.encoders.Hex;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.io.IOException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import org.apache.logging.log4j.Level;
-
-import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL;
-import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
-
-@Log4j2
-@Service
-public class SupplyChainValidationServiceImpl implements SupplyChainValidationService {
-
-    private CACredentialRepository caCredentialRepository;
-    private PolicyRepository policyRepository;
-    private ReferenceManifestRepository referenceManifestRepository;
-    private ReferenceDigestValueRepository referenceDigestValueRepository;
-    private ComponentResultRepository componentResultRepository;
-    private CertificateRepository certificateRepository;
-    private CredentialValidator supplyChainCredentialValidator;
-    private SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository;
-
-    /**
-     * Constructor to set just the CertificateRepository, so that cert chain validating
-     * methods can be called from outside classes.
-     *
-     * @param certificateRepository the cert repository
-     */
-    public SupplyChainValidationServiceImpl(final CertificateRepository certificateRepository) {
-        this.certificateRepository = certificateRepository;
-    }
-
-    /**
-     * Constructor.
-     *
-     * @param caCredentialRepository    ca credential repository
-     * @param policyRepository                      the policy manager
-     * @param certificateRepository                 the cert manager
-     * @param componentResultRepository             the comp result manager
-     * @param referenceManifestRepository           the RIM manager
-     * @param supplyChainValidationSummaryRepository the summary manager
-     * @param supplyChainCredentialValidator     the credential validator
-     * @param referenceDigestValueRepository              the even manager
-     */
-    @Autowired
-    @SuppressWarnings("ParameterNumberCheck")
-    public SupplyChainValidationServiceImpl(
-            final CACredentialRepository caCredentialRepository,
-            final PolicyRepository policyRepository,
-            final CertificateRepository certificateRepository,
-            final ComponentResultRepository componentResultRepository,
-            final ReferenceManifestRepository referenceManifestRepository,
-            final SupplyChainValidationSummaryRepository supplyChainValidationSummaryRepository,
-            final CredentialValidator supplyChainCredentialValidator,
-            final ReferenceDigestValueRepository referenceDigestValueRepository) {
-        this.caCredentialRepository = caCredentialRepository;
-        this.policyRepository = policyRepository;
-        this.certificateRepository = certificateRepository;
-        this.componentResultRepository = componentResultRepository;
-        this.referenceManifestRepository = referenceManifestRepository;
-        this.supplyChainValidationSummaryRepository = supplyChainValidationSummaryRepository;
-        this.supplyChainCredentialValidator = supplyChainCredentialValidator;
-        this.referenceDigestValueRepository = referenceDigestValueRepository;
-    }
-
-    @Override
-    public SupplyChainValidationSummary validateSupplyChain(final EndorsementCredential ec,
-                                                            final List<PlatformCredential> pc,
-                                                            final Device device) {
-        return null;
-    }
-
-    /**
-     * A supplemental method that handles validating just the quote post main validation.
-     *
-     * @param device the associated device.
-     * @return True if validation is successful, false otherwise.
-     */
-    @Override
-    public SupplyChainValidationSummary validateQuote(final Device device) {
-        SupplyChainValidation quoteScv = null;
-        SupplyChainValidationSummary summary = null;
-        Level level = Level.ERROR;
-        AppraisalStatus fwStatus = new AppraisalStatus(FAIL,
-                "Unknown exception caught during quote validation.");
-        SupportReferenceManifest sRim = null;
-        EventLogMeasurements eventLog = null;
-
-        // check if the policy is enabled
-        if (getPolicySettings().isFirmwareValidationEnabled()) {
-            String[] baseline = new String[Integer.SIZE];
-            String deviceName = device.getDeviceInfo()
-                    .getNetworkInfo().getHostname();
-
-            try {
-                List<SupportReferenceManifest> supportRims = referenceManifestRepository.getSupportByManufacturerModel(
-                        device.getDeviceInfo().getHardwareInfo().getManufacturer(),
-                        device.getDeviceInfo().getHardwareInfo().getProductName());
-                for (SupportReferenceManifest support : supportRims) {
-                    if (support.isBaseSupport()) {
-                        sRim = support;
-                    }
-                }
-                eventLog = (EventLogMeasurements) referenceManifestRepository
-                        .findByHexDecHash(sRim.getEventLogHash());
-
-                if (sRim == null) {
-                    fwStatus = new AppraisalStatus(FAIL,
-                            String.format("Firmware Quote validation failed: "
-                                            + "No associated Support RIM file "
-                                            + "could be found for %s",
-                                    deviceName));
-                } else if (eventLog == null) {
-                    fwStatus = new AppraisalStatus(FAIL,
-                            String.format("Firmware Quote validation failed: "
-                                            + "No associated Client Log file "
-                                            + "could be found for %s",
-                                    deviceName));
-                } else {
-                    baseline = sRim.getExpectedPCRList();
-                    String[] storedPcrs = eventLog.getExpectedPCRList();
-                    PcrValidator pcrValidator = new PcrValidator(baseline);
-                    // grab the quote
-                    byte[] hash = device.getDeviceInfo().getTpmInfo().getTpmQuoteHash();
-                    if (pcrValidator.validateQuote(hash, storedPcrs, getPolicySettings())) {
-                        level = Level.INFO;
-                        fwStatus = new AppraisalStatus(PASS,
-                                SupplyChainCredentialValidator.FIRMWARE_VALID);
-                        fwStatus.setMessage("Firmware validation of TPM Quote successful.");
-                    } else {
-                        fwStatus.setMessage("Firmware validation of TPM Quote failed."
-                                + "\nPCR hash and Quote hash do not match.");
-                    }
-                    eventLog.setOverallValidationResult(fwStatus.getAppStatus());
-                    this.referenceManifestRepository.save(eventLog);
-                }
-            } catch (Exception ex) {
-                log.error(ex);
-            }
-
-            quoteScv = buildValidationRecord(SupplyChainValidation
-                            .ValidationType.FIRMWARE,
-                    fwStatus.getAppStatus(), fwStatus.getMessage(), eventLog, level);
-
-            // Generate validation summary, save it, and return it.
-            List<SupplyChainValidation> validations = new ArrayList<>();
-            SupplyChainValidationSummary previous
-                    = this.supplyChainValidationSummaryRepository.findByDevice(deviceName);
-            for (SupplyChainValidation scv : previous.getValidations()) {
-                if (scv.getValidationType() != SupplyChainValidation.ValidationType.FIRMWARE) {
-                    validations.add(buildValidationRecord(scv.getValidationType(),
-                            scv.getValidationResult(), scv.getMessage(),
-                            scv.getCertificatesUsed().get(0), Level.INFO));
-                }
-            }
-            validations.add(quoteScv);
-            previous.archive();
-            supplyChainValidationSummaryRepository.save(previous);
-            summary = new SupplyChainValidationSummary(device, validations);
-
-            // try removing the supply chain validation as well and resaving that
-            try {
-                supplyChainValidationSummaryRepository.save(summary);
-            } catch (DBManagerException dbEx) {
-                log.error("Failed to save Supply Chain Summary", dbEx);
-            }
-        }
-
-        return summary;
-    }
-
-    /**
-     * Creates a supply chain validation record and logs the validation message
-     * at the specified log level.
-     *
-     * @param validationType   the type of validation
-     * @param result           the appraisal status
-     * @param message          the validation message to include in the summary and log
-     * @param archivableEntity the archivableEntity associated with the
-     *                         validation
-     * @param logLevel         the log level
-     * @return a SupplyChainValidation
-     */
-    private SupplyChainValidation buildValidationRecord(
-            final SupplyChainValidation.ValidationType validationType,
-            final AppraisalStatus.Status result, final String message,
-            final ArchivableEntity archivableEntity, final Level logLevel) {
-        List<ArchivableEntity> aeList = new ArrayList<>();
-        if (archivableEntity != null) {
-            aeList.add(archivableEntity);
-        }
-
-        log.log(logLevel, message);
-        return new SupplyChainValidation(validationType, result, aeList, message);
-    }
-
-    /**
-     * This method is used to retrieve the entire CA chain (up to a trusted
-     * self-signed certificate) for the given certificate. This method will look
-     * up CA certificates that have a matching issuer organization as the given
-     * certificate, and will perform that operation recursively until all
-     * certificates for all relevant organizations have been retrieved. For that
-     * reason, the returned set of certificates may be larger than the the
-     * single trust chain for the queried certificate, but is guaranteed to
-     * include the trust chain if it exists in this class' CertificateManager.
-     * Returns the certificate authority credentials in a KeyStore.
-     *
-     * @param credential the credential whose CA chain should be retrieved
-     * @return A keystore containing all relevant CA credentials to the given
-     * certificate's organization or null if the keystore can't be assembled
-     */
-    public KeyStore getCaChain(final Certificate credential) {
-        KeyStore caKeyStore = null;
-        try {
-            caKeyStore = caCertSetToKeystore(getCaChainRec(credential, Collections.emptySet()));
-        } catch (KeyStoreException | IOException e) {
-            log.error("Unable to assemble CA keystore", e);
-        }
-        return caKeyStore;
-    }
-
-    /**
-     * This is a recursive method which is used to retrieve the entire CA chain
-     * (up to a trusted self-signed certificate) for the given certificate. This
-     * method will look up CA certificates that have a matching issuer
-     * organization as the given certificate, and will perform that operation
-     * recursively until all certificates for all relevant organizations have
-     * been retrieved. For that reason, the returned set of certificates may be
-     * larger than the the single trust chain for the queried certificate, but
-     * is guaranteed to include the trust chain if it exists in this class'
-     * CertificateManager.
-     * <p>
-     * Implementation notes: 1. Queries for CA certs with a subject org matching
-     * the given (argument's) issuer org 2. Add that org to
-     * queriedOrganizations, so we don't search for that organization again 3.
-     * For each returned CA cert, add that cert to the result set, and recurse
-     * with that as the argument (to go up the chain), if and only if we haven't
-     * already queried for that organization (which prevents infinite loops on
-     * certs with an identical subject and issuer org)
-     *
-     * @param credential                the credential whose CA chain should be retrieved
-     * @param previouslyQueriedSubjects a list of organizations to refrain
-     *                                  from querying
-     * @return a Set containing all relevant CA credentials to the given
-     * certificate's organization
-     */
-    private Set<CertificateAuthorityCredential> getCaChainRec(
-            final Certificate credential,
-            final Set<String> previouslyQueriedSubjects) {
-        CertificateAuthorityCredential skiCA = null;
-        List<CertificateAuthorityCredential> certAuthsWithMatchingIssuer = new LinkedList<>();
-        if (credential.getAuthorityKeyIdentifier() != null
-                && !credential.getAuthorityKeyIdentifier().isEmpty()) {
-            byte[] bytes = Hex.decode(credential.getAuthorityKeyIdentifier());
-            // CYRUS is SKI unique?
-            skiCA = caCredentialRepository.findBySubjectKeyIdentifier(bytes);
-        }
-
-        if (skiCA == null) {
-            if (credential.getIssuerSorted() == null
-                    || credential.getIssuerSorted().isEmpty()) {
-                certAuthsWithMatchingIssuer = caCredentialRepository.findBySubject(credential.getIssuer());
-            } else {
-                //Get certificates by subject organization
-                certAuthsWithMatchingIssuer = caCredentialRepository.findBySubjectSorted(credential.getIssuerSorted());
-            }
-        } else {
-            certAuthsWithMatchingIssuer.add(skiCA);
-        }
-        Set<String> queriedOrganizations = new HashSet<>(previouslyQueriedSubjects);
-        queriedOrganizations.add(credential.getIssuer());
-
-        HashSet<CertificateAuthorityCredential> caCreds = new HashSet<>();
-        for (CertificateAuthorityCredential cred : certAuthsWithMatchingIssuer) {
-            caCreds.add(cred);
-            if (!BouncyCastleUtils.x500NameCompare(cred.getIssuer(),
-                    cred.getSubject())) {
-                caCreds.addAll(getCaChainRec(cred, queriedOrganizations));
-            }
-        }
-        return caCreds;
-    }
-
-    private KeyStore caCertSetToKeystore(final Set<CertificateAuthorityCredential> certs)
-            throws KeyStoreException, IOException {
-        KeyStore keyStore = KeyStore.getInstance("JKS");
-        try {
-            keyStore.load(null, "".toCharArray());
-            for (Certificate cert : certs) {
-                keyStore.setCertificateEntry(cert.getId().toString(), cert.getX509Certificate());
-            }
-        } catch (IOException | CertificateException | NoSuchAlgorithmException e) {
-            throw new IOException("Could not create and populate keystore", e);
-        }
-
-        return keyStore;
-    }
-
-    private String[] buildStoredPcrs(final String pcrContent, final int algorithmLength) {
-        // we have a full set of PCR values
-        String[] pcrSet = pcrContent.split("\\n");
-        String[] storedPcrs = new String[TPMMeasurementRecord.MAX_PCR_ID + 1];
-
-        // we need to scroll through the entire list until we find
-        // a matching hash length
-        int offset = 1;
-
-        for (int i = 0; i < pcrSet.length; i++) {
-            if (pcrSet[i].contains("sha")) {
-                // entered a new set, check size
-                if (pcrSet[i + offset].split(":")[1].trim().length()
-                        == algorithmLength) {
-                    // found the matching set
-                    for (int j = 0; j <= TPMMeasurementRecord.MAX_PCR_ID; j++) {
-                        storedPcrs[j] = pcrSet[++i].split(":")[1].trim();
-                    }
-                    break;
-                }
-            }
-        }
-
-        return storedPcrs;
-    }
-
-    /**
-     * Helper function to get a fresh load of the default policy from the DB.
-     *
-     * @return The default Supply Chain Policy
-     */
-    private PolicySettings getPolicySettings() {
-        PolicySettings defaultSettings = this.policyRepository.findByName("Default");
-
-        if (defaultSettings == null) {
-            defaultSettings = new PolicySettings("Default", "Settings are configured for no validation flags set.");
-        }
-        return defaultSettings;
-    }
-}
diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/PciIds.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/PciIds.java
similarity index 99%
rename from HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/PciIds.java
rename to HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/PciIds.java
index 3623e922..e17fd1e8 100644
--- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/PciIds.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/PciIds.java
@@ -1,4 +1,4 @@
-package hirs.attestationca.portal.page.utils;
+package hirs.attestationca.persist.util;
 
 import com.github.marandus.pciid.model.Device;
 import com.github.marandus.pciid.model.Vendor;
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CredentialValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CredentialValidator.java
index 7e4638bf..2084cfe9 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CredentialValidator.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CredentialValidator.java
@@ -1,19 +1,86 @@
 package hirs.attestationca.persist.validation;
 
-import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
 import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
 import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
 import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
 import hirs.attestationca.persist.enums.AppraisalStatus;
+import lombok.extern.log4j.Log4j2;
+import org.bouncycastle.cert.X509AttributeCertificateHolder;
 
+import java.io.IOException;
 import java.security.KeyStore;
-import java.util.Map;
+import java.security.KeyStoreException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import static hirs.attestationca.persist.enums.AppraisalStatus.Status.ERROR;
+import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL;
+import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
+
+@Log4j2
+public class CredentialValidator extends SupplyChainCredentialValidator {
+
+    /**
+     * Checks if the endorsement credential is valid.
+     *
+     * @param ec the endorsement credential to verify.
+     * @param trustStore trust store holding trusted trusted certificates.
+     * @param acceptExpired whether or not to accept expired and not yet valid certificates
+     *                      as valid.
+     * @return the result of the validation.
+     */
+    public static AppraisalStatus validateEndorsementCredential(final EndorsementCredential ec,
+                                                                final KeyStore trustStore,
+                                                                final boolean acceptExpired) {
+        final String baseErrorMessage = "Can't validate endorsement credential attributes without ";
+        String message;
+        if (ec == null) {
+            message = baseErrorMessage + "an endorsement credential";
+            log.error(message);
+            return new AppraisalStatus(FAIL, message);
+        }
+        if (trustStore == null) {
+            message = baseErrorMessage + "a trust store";
+            log.error(message);
+            return new AppraisalStatus(FAIL, message);
+        }
+
+        try {
+            X509Certificate verifiableCert = ec.getX509Certificate();
+
+            // check validity period, currently acceptExpired will also accept not yet
+            // valid certificates
+            if (!acceptExpired) {
+                verifiableCert.checkValidity();
+            }
+
+            if (verifyCertificate(verifiableCert, trustStore)) {
+                return new AppraisalStatus(PASS, ENDORSEMENT_VALID);
+            } else {
+                return new AppraisalStatus(FAIL, "Endorsement credential does not have a valid "
+                        + "signature chain in the trust store");
+            }
+        } catch (IOException e) {
+            message = "Couldn't retrieve X509 certificate from endorsement credential";
+            log.error(message, e);
+            return new AppraisalStatus(ERROR, message + " " + e.getMessage());
+        } catch (SupplyChainValidatorException e) {
+            message = "An error occurred indicating the credential is not valid";
+            log.warn(message, e);
+            return new AppraisalStatus(ERROR, message + " " + e.getMessage());
+        } catch (CertificateExpiredException e) {
+            message = "The endorsement credential is expired";
+            log.warn(message, e);
+            return new AppraisalStatus(FAIL, message + " " + e.getMessage());
+        } catch (CertificateNotYetValidException e) {
+            message = "The endorsement credential is not yet valid";
+            log.warn(message, e);
+            return new AppraisalStatus(FAIL, message + " " + e.getMessage());
+        }
+    }
 
-/**
- * A class used to support supply chain validation by performing the actual
- * validation of credentials.
- */
-public interface CredentialValidator {
     /**
      * Checks if the platform credential is valid.
      *
@@ -22,47 +89,113 @@ public interface CredentialValidator {
      * @param acceptExpired whether or not to accept expired certificates as valid.
      * @return The result of the validation.
      */
-    AppraisalStatus validatePlatformCredential(PlatformCredential pc,
-                                               KeyStore trustStore,
-                                               boolean acceptExpired);
+    public static AppraisalStatus validatePlatformCredential(final PlatformCredential pc,
+                                                             final KeyStore trustStore,
+                                                             final boolean acceptExpired) {
+        final String baseErrorMessage = "Can't validate platform credential without ";
+        String message;
+        String certVerifyMsg;
+        if (pc == null) {
+            message = baseErrorMessage + "a platform credential\n";
+            log.error(message);
+            return new AppraisalStatus(FAIL, message);
+        }
+        try {
+            if (trustStore == null || trustStore.size() == 0) {
+                message = baseErrorMessage + "an Issuer Cert in the Trust Store\n";
+                log.error(message);
+                return new AppraisalStatus(FAIL, message);
+            }
+        } catch (KeyStoreException e) {
+            message = baseErrorMessage + "an initialized trust store";
+            log.error(message);
+            return new AppraisalStatus(FAIL, message);
+        }
+
+        X509AttributeCertificateHolder attributeCert = null;
+        try {
+            attributeCert = pc.getX509AttributeCertificateHolder();
+        } catch (IOException e) {
+            message = "Could not retrieve X509 Attribute certificate";
+            log.error(message, e);
+            return new AppraisalStatus(FAIL, message + " " + e.getMessage());
+        }
+
+        // check validity period, currently acceptExpired will also accept not yet
+        // valid certificates
+        if (!acceptExpired && !pc.isValidOn(new Date())) {
+            message = "Platform credential has expired";
+            // if not valid at the current time
+            log.warn(message);
+            return new AppraisalStatus(FAIL, message);
+        }
+
+        // verify cert against truststore
+        try {
+            certVerifyMsg = verifyCertificate(attributeCert, trustStore);
+            if (certVerifyMsg.isEmpty()) {
+                message = PLATFORM_VALID;
+                log.info(message);
+                return new AppraisalStatus(PASS, message);
+            } else {
+                message = String.format("Platform credential failed verification%n%s",
+                        certVerifyMsg);
+                log.error(message);
+                return new AppraisalStatus(FAIL, message);
+            }
+        } catch (SupplyChainValidatorException scvEx) {
+            message = "An error occurred indicating the credential is not valid";
+            log.warn(message, scvEx);
+            return new AppraisalStatus(FAIL, message + " " + scvEx.getMessage());
+        }
+    }
 
     /**
      * Checks if the platform credential's attributes are valid.
-     * @param pc The platform credential to verify.
-     * @param deviceInfoReport Report containing the serial numbers of the platform to be validated.
-     * @param ec The endorsement credential supplied from the same identity request as
-     *           the platform credential.
-     * @return The result of the validation.
-     */
-    AppraisalStatus validatePlatformCredentialAttributes(PlatformCredential pc,
-                                                         DeviceInfoReport deviceInfoReport,
-                                                         EndorsementCredential ec);
-
-    /**
-     * Checks if the delta credential's attributes are valid.
-     * @param delta the delta credential to verify
+     * @param platformCredential The platform credential to verify.
      * @param deviceInfoReport The device info report containing
      *                         serial number of the platform to be validated.
-     * @param base the base credential from the same identity request
-     *                              as the delta credential.
-     * @param deltaMapping delta certificates associated with the
-     *                          delta supply validation.
-     * @return the result of the validation.
+     * @param endorsementCredential The endorsement credential supplied from the same
+     *          identity request as the platform credential.
+     * @return The result of the validation.
      */
-    AppraisalStatus validateDeltaPlatformCredentialAttributes(PlatformCredential delta,
-                                                              DeviceInfoReport deviceInfoReport,
-                                                              PlatformCredential base,
-                                                              Map<PlatformCredential,
-                                                                      SupplyChainValidation> deltaMapping);
-    /**
-     * Checks if the endorsement credential is valid.
-     *
-     * @param ec the endorsement credential to verify.
-     * @param trustStore trust store holding trusted trusted certificates.
-     * @param acceptExpired whether or not to accept expired certificates as valid.
-     * @return the result of the validation.
-     */
-    AppraisalStatus validateEndorsementCredential(EndorsementCredential ec,
-                                                  KeyStore trustStore,
-                                                  boolean acceptExpired);
-}
+    public static AppraisalStatus validatePlatformCredentialAttributes(
+            final PlatformCredential platformCredential,
+            final DeviceInfoReport deviceInfoReport,
+            final EndorsementCredential endorsementCredential) {
+        final String baseErrorMessage = "Can't validate platform credential attributes without ";
+        String message;
+        if (platformCredential == null) {
+            message = baseErrorMessage + "a platform credential";
+            log.error(message);
+            return new AppraisalStatus(FAIL, message);
+        }
+        if (deviceInfoReport == null) {
+            message = baseErrorMessage + "a device info report";
+            log.error(message);
+            return new AppraisalStatus(FAIL, message);
+        }
+        if (endorsementCredential == null) {
+            message = baseErrorMessage + "an endorsement credential";
+            log.error(message);
+            return new AppraisalStatus(FAIL, message);
+        }
+
+        // Quick, early check if the platform credential references the endorsement credential
+        if (!endorsementCredential.getSerialNumber()
+                .equals(platformCredential.getHolderSerialNumber())) {
+            message = "Platform Credential holder serial number does not match "
+                    + "the Endorsement Credential's serial number";
+            log.error(message);
+            return new AppraisalStatus(FAIL, message);
+        }
+
+        String credentialType = platformCredential.getCredentialType();
+        if (PlatformCredential.CERTIFICATE_TYPE_2_0.equals(credentialType)) {
+            return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV2p0(
+                    platformCredential, deviceInfoReport);
+        }
+        return CertificateAttributeScvValidator.validatePlatformCredentialAttributesV1p2(
+                platformCredential, deviceInfoReport);
+    }
+}
\ No newline at end of file
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/PcrValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/PcrValidator.java
index 9e8b738c..568ebe72 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/PcrValidator.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/PcrValidator.java
@@ -226,4 +226,30 @@ public class PcrValidator {
 
         return validated;
     }
+
+    public static String[] buildStoredPcrs(final String pcrContent, final int algorithmLength) {
+        // we have a full set of PCR values
+        String[] pcrSet = pcrContent.split("\\n");
+        String[] storedPcrs = new String[TPMMeasurementRecord.MAX_PCR_ID + 1];
+
+        // we need to scroll through the entire list until we find
+        // a matching hash length
+        int offset = 1;
+
+        for (int i = 0; i < pcrSet.length; i++) {
+            if (pcrSet[i].contains("sha")) {
+                // entered a new set, check size
+                if (pcrSet[i + offset].split(":")[1].trim().length()
+                        == algorithmLength) {
+                    // found the matching set
+                    for (int j = 0; j <= TPMMeasurementRecord.MAX_PCR_ID; j++) {
+                        storedPcrs[j] = pcrSet[++i].split(":")[1].trim();
+                    }
+                    break;
+                }
+            }
+        }
+
+        return storedPcrs;
+    }
 }
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidator.java
index 70aaec2c..bcdc9d92 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidator.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidator.java
@@ -1,23 +1,50 @@
 package hirs.attestationca.persist.validation;
 
-import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult;
-import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
-import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
-import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
-import hirs.attestationca.persist.enums.AppraisalStatus;
+import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
+import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
+import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
 import lombok.NoArgsConstructor;
 import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.util.Strings;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.cert.CertException;
+import org.bouncycastle.cert.X509AttributeCertificateHolder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentVerifierProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
 
+import javax.security.auth.x500.X500Principal;
+import java.io.IOException;
+import java.security.InvalidKeyException;
 import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
+import java.util.Set;
 
 @Log4j2
 @NoArgsConstructor
-public class SupplyChainCredentialValidator implements CredentialValidator {
+public class SupplyChainCredentialValidator  {
 
+    public static final int NUC_VARIABLE_BIT = 159;
     /**
      * AppraisalStatus message for a valid endorsement credential appraisal.
      */
@@ -39,34 +66,447 @@ public class SupplyChainCredentialValidator implements CredentialValidator {
      */
     public static final String FIRMWARE_VALID = "Firmware validated";
 
-    private static List<ComponentResult> componentResultList = new LinkedList<>();
+    /**
+     * Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
+     * class expects it to be available.
+     */
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
 
-    @Override
-    public AppraisalStatus validatePlatformCredential(final PlatformCredential pc,
-                                                      final KeyStore trustStore,
-                                                      final boolean acceptExpired) {
+    /**
+     * Attempts to check if the certificate is validated by certificates in a cert chain. The cert
+     * chain is expected to be stored in a non-ordered KeyStore (trust store). If the signing
+     * certificate for the target cert is found, but it is an intermediate cert, the validation will
+     * continue to try to find the signing cert of the intermediate cert. It will continue searching
+     * until it follows the chain up to a root (self-signed) cert.
+     *
+     * @param cert
+     *            certificate to validate
+     * @param trustStore
+     *            trust store holding trusted root certificates and intermediate certificates
+     * @return the certificate chain if validation is successful
+     * @throws SupplyChainValidatorException
+     *             if the verification is not successful
+     */
+    public static String verifyCertificate(final X509AttributeCertificateHolder cert,
+                                           final KeyStore trustStore) throws SupplyChainValidatorException {
+        try {
+            if (cert == null || trustStore == null) {
+                throw new SupplyChainValidatorException("Certificate or trust store is null");
+            } else if (trustStore.size() == 0) {
+                throw new SupplyChainValidatorException("Truststore is empty");
+            }
+        } catch (KeyStoreException e) {
+            log.error("Error accessing trust store: " + e.getMessage());
+        }
+
+        try {
+            Set<X509Certificate> trustedCerts = new HashSet<>();
+
+            Enumeration<String> alias = trustStore.aliases();
+
+            while (alias.hasMoreElements()) {
+                trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement()));
+            }
+
+            String certChainValidated = validateCertChain(cert, trustedCerts);
+            if (!certChainValidated.isEmpty()) {
+                log.error("Cert chain could not be validated");
+            }
+            return certChainValidated;
+        } catch (KeyStoreException e) {
+            throw new SupplyChainValidatorException("Error with the trust store", e);
+        }
+    }
+
+    /**
+     * Attempts to check if the certificate is validated by certificates in a cert chain. The cert
+     * chain is expected to be stored in a non-ordered KeyStore (trust store). If the signing
+     * certificate for the target cert is found, but it is an intermediate cert, the validation will
+     * continue to try to find the signing cert of the intermediate cert. It will continue searching
+     * until it follows the chain up to a root (self-signed) cert.
+     *
+     * @param cert
+     *            certificate to validate
+     * @param trustStore
+     *            trust store holding trusted root certificates and intermediate certificates
+     * @return the certificate chain if validation is successful
+     * @throws SupplyChainValidatorException
+     *             if the verification is not successful
+     */
+    public static boolean verifyCertificate(final X509Certificate cert,
+                                            final KeyStore trustStore) throws SupplyChainValidatorException {
+        try {
+            if (cert == null || trustStore == null) {
+                throw new SupplyChainValidatorException("Certificate or trust store is null");
+            } else if (trustStore.size() == 0) {
+                throw new SupplyChainValidatorException("Truststore is empty");
+            }
+        } catch (KeyStoreException e) {
+            log.error("Error accessing trust store: " + e.getMessage());
+        }
+
+        try {
+            Set<X509Certificate> trustedCerts = new HashSet<>();
+            Enumeration<String> alias = trustStore.aliases();
+
+            while (alias.hasMoreElements()) {
+                trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement()));
+            }
+
+            return validateCertChain(cert, trustedCerts).isEmpty();
+        } catch (KeyStoreException e) {
+            log.error("Error accessing keystore", e);
+            throw new SupplyChainValidatorException("Error with the trust store", e);
+        }
+    }
+
+    /**
+     * Attempts to check if an attribute certificate is validated by certificates in a cert chain.
+     * The cert chain is represented as a Set of X509Certificates. If the signing certificate for
+     * the target cert is found, but it is an intermediate cert, the validation will continue to try
+     * to find the signing cert of the intermediate cert. It will continue searching until it
+     * follows the chain up to a root (self-signed) cert.
+     *
+     * @param cert
+     *            certificate to validate
+     * @param additionalCerts
+     *            Set of certs to validate against
+     * @return String status of the cert chain validation -
+     *  blank if successful, error message otherwise
+     * @throws SupplyChainValidatorException tried to validate using null certificates
+     */
+    public static String validateCertChain(final X509AttributeCertificateHolder cert,
+                                           final Set<X509Certificate> additionalCerts)
+            throws SupplyChainValidatorException {
+        if (cert == null || additionalCerts == null) {
+            throw new SupplyChainValidatorException(
+                    "Certificate or validation certificates are null");
+        }
+        final String intCAError = "Intermediate signing cert found, check for CA cert";
+        String foundRootOfCertChain = "";
+        X509Certificate nextInChain = null;
+
+        do {
+            for (X509Certificate trustedCert : additionalCerts) {
+                boolean issuerMatchesSubject = false;
+                boolean signatureMatchesPublicKey = false;
+                if (nextInChain != null) {
+                    issuerMatchesSubject = issuerMatchesSubjectDN(nextInChain, trustedCert);
+                    signatureMatchesPublicKey = signatureMatchesPublicKey(nextInChain,
+                            trustedCert);
+                } else {
+                    issuerMatchesSubject = issuerMatchesSubjectDN(cert, trustedCert);
+                    signatureMatchesPublicKey = signatureMatchesPublicKey(cert, trustedCert);
+                }
+
+                if (issuerMatchesSubject && signatureMatchesPublicKey) {
+                    if (isSelfSigned(trustedCert)) {
+                        log.info("CA Root found.");
+                        return "";
+                    } else {
+                        foundRootOfCertChain = intCAError;
+                        nextInChain = trustedCert;
+                        break;
+                    }
+                } else {
+                    if (!issuerMatchesSubject) {
+                        foundRootOfCertChain = "Issuer DN does not match Subject DN";
+                    }
+                    if (!signatureMatchesPublicKey) {
+                        foundRootOfCertChain = "Certificate signature failed to verify";
+                    }
+                }
+            }
+        } while (foundRootOfCertChain.equals(intCAError));
+
+        log.error(foundRootOfCertChain);
+        return foundRootOfCertChain;
+    }
+
+    /**
+     * Attempts to check if a public-key certificate is validated by certificates in a cert chain.
+     * The cert chain is represented as a Set of X509Certificates. If the signing certificate for
+     * the target cert is found, but it is an intermediate cert, the validation will continue to try
+     * to find the signing cert of the intermediate cert. It will continue searching until it
+     * follows the chain up to a root (self-signed) cert.
+     *
+     * @param cert
+     *            certificate to validate
+     * @param additionalCerts
+     *            Set of certs to validate against
+     * @return String status of the cert chain validation -
+     *  blank if successful, error message otherwise
+     * @throws SupplyChainValidatorException tried to validate using null certificates
+     */
+    public static String validateCertChain(final X509Certificate cert,
+                                           final Set<X509Certificate> additionalCerts) throws SupplyChainValidatorException {
+        if (cert == null || additionalCerts == null) {
+            throw new SupplyChainValidatorException(
+                    "Certificate or validation certificates are null");
+        }
+        final String intCAError = "Intermediate signing cert found, check for CA cert";
+        String foundRootOfCertChain = "";
+        X509Certificate startOfChain = cert;
+
+        do {
+            for (X509Certificate trustedCert : additionalCerts) {
+                boolean issuerMatchesSubject = issuerMatchesSubjectDN(startOfChain, trustedCert);
+                boolean signatureMatchesPublicKey = signatureMatchesPublicKey(startOfChain,
+                        trustedCert);
+                if (issuerMatchesSubject && signatureMatchesPublicKey) {
+                    if (isSelfSigned(trustedCert)) {
+                        log.info("CA Root found.");
+                        return "";
+                    } else {
+                        foundRootOfCertChain = intCAError;
+                        startOfChain = trustedCert;
+                        break;
+                    }
+                } else {
+                    if (!issuerMatchesSubject) {
+                        foundRootOfCertChain = "Issuer DN does not match Subject DN";
+                    }
+                    if (!signatureMatchesPublicKey) {
+                        foundRootOfCertChain = "Certificate signature failed to verify";
+                    }
+                }
+            }
+        } while (foundRootOfCertChain.equals(intCAError));
+
+        log.warn(foundRootOfCertChain);
+        return foundRootOfCertChain;
+    }
+
+    /**
+     * Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects.
+     * @param paccorOutput the output from PACCOR's allcomoponents.sh
+     * @return a list of ComponentInfo objects built from paccorOutput
+     * @throws java.io.IOException if something goes wrong parsing the JSON
+     */
+    public static List<ComponentInfo> getComponentInfoFromPaccorOutput(final String paccorOutput)
+            throws IOException {
+        List<ComponentInfo> componentInfoList = new ArrayList<>();
+
+        if (StringUtils.isNotEmpty(paccorOutput)) {
+            ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
+            JsonNode rootNode = objectMapper.readTree(paccorOutput);
+            Iterator<JsonNode> jsonComponentNodes
+                    = rootNode.findValue("COMPONENTS").elements();
+            while (jsonComponentNodes.hasNext()) {
+                JsonNode next = jsonComponentNodes.next();
+                componentInfoList.add(new ComponentInfo(
+                        getJSONNodeValueAsText(next, "MANUFACTURER"),
+                        getJSONNodeValueAsText(next, "MODEL"),
+                        getJSONNodeValueAsText(next, "SERIAL"),
+                        getJSONNodeValueAsText(next, "REVISION")));
+            }
+        }
+
+        return componentInfoList;
+    }
+
+    /**
+     * Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects.
+     * @param paccorOutput the output from PACCOR's allcomoponents.sh
+     * @return a list of ComponentInfo objects built from paccorOutput
+     * @throws IOException if something goes wrong parsing the JSON
+     */
+    public static List<ComponentInfo> getV2PaccorOutput(
+            final String paccorOutput) throws IOException {
+        List<ComponentInfo> ciList = new LinkedList<>();
+        String manufacturer, model, serial, revision;
+        String componentClass = Strings.EMPTY;
+
+        if (StringUtils.isNotEmpty(paccorOutput)) {
+            ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
+            JsonNode rootNode = objectMapper.readTree(paccorOutput);
+            Iterator<JsonNode> jsonComponentNodes
+                    = rootNode.findValue("COMPONENTS").elements();
+            while (jsonComponentNodes.hasNext()) {
+                JsonNode next = jsonComponentNodes.next();
+                manufacturer = getJSONNodeValueAsText(next, "MANUFACTURER");
+                model = getJSONNodeValueAsText(next, "MODEL");
+                serial = getJSONNodeValueAsText(next, "SERIAL");
+                revision = getJSONNodeValueAsText(next, "REVISION");
+                List<JsonNode> compClassNodes = next.findValues("COMPONENTCLASS");
+
+                for (JsonNode subNode : compClassNodes) {
+                    componentClass = getJSONNodeValueAsText(subNode,
+                            "COMPONENTCLASSVALUE");
+                }
+                ciList.add(new ComponentInfo(manufacturer, model,
+                        serial, revision, componentClass));
+            }
+        }
+
+        return ciList;
+    }
+
+    private static String getJSONNodeValueAsText(final JsonNode node, final String fieldName) {
+        if (node.hasNonNull(fieldName)) {
+            return node.findValue(fieldName).asText();
+        }
         return null;
     }
 
-    @Override
-    public AppraisalStatus validatePlatformCredentialAttributes(final PlatformCredential pc,
-                                                                final DeviceInfoReport deviceInfoReport,
-                                                                final EndorsementCredential ec) {
-        return null;
+    /**
+     * Checks if the issuer info of an attribute cert matches the supposed signing cert's
+     * distinguished name.
+     *
+     * @param cert
+     *            the attribute certificate with the signature to validate
+     * @param signingCert
+     *            the certificate with the public key to validate
+     * @return boolean indicating if the names
+     * @throws SupplyChainValidatorException tried to validate using null certificates
+     */
+    public static boolean issuerMatchesSubjectDN(final X509AttributeCertificateHolder cert,
+                                                 final X509Certificate signingCert) throws SupplyChainValidatorException {
+        if (cert == null || signingCert == null) {
+            throw new SupplyChainValidatorException("Certificate or signing certificate is null");
+        }
+        String signingCertSubjectDN = signingCert.getSubjectX500Principal().getName();
+        X500Name namedSubjectDN = new X500Name(signingCertSubjectDN);
+
+        X500Name issuerDN = cert.getIssuer().getNames()[0];
+
+        // equality check ignore DN component ordering
+        return issuerDN.equals(namedSubjectDN);
     }
 
-    @Override
-    public AppraisalStatus validateDeltaPlatformCredentialAttributes(final PlatformCredential delta,
-                                                                     final DeviceInfoReport deviceInfoReport,
-                                                                     final PlatformCredential base,
-                                                                     final Map<PlatformCredential, SupplyChainValidation> deltaMapping) {
-        return null;
+    /**
+     * Checks if the issuer info of a public-key cert matches the supposed signing cert's
+     * distinguished name.
+     *
+     * @param cert
+     *            the public-key certificate with the signature to validate
+     * @param signingCert
+     *            the certificate with the public key to validate
+     * @return boolean indicating if the names
+     * @throws SupplyChainValidatorException tried to validate using null certificates
+     */
+    public static boolean issuerMatchesSubjectDN(final X509Certificate cert,
+                                                 final X509Certificate signingCert) throws SupplyChainValidatorException {
+        if (cert == null || signingCert == null) {
+            throw new SupplyChainValidatorException("Certificate or signing certificate is null");
+        }
+        String signingCertSubjectDN = signingCert.getSubjectX500Principal().
+                getName(X500Principal.RFC1779);
+        X500Name namedSubjectDN = new X500Name(signingCertSubjectDN);
+
+        String certIssuerDN = cert.getIssuerX500Principal().getName();
+        X500Name namedIssuerDN = new X500Name(certIssuerDN);
+
+        // equality check ignore DN component ordering
+        return namedIssuerDN.equals(namedSubjectDN);
     }
 
-    @Override
-    public AppraisalStatus validateEndorsementCredential(final EndorsementCredential ec,
-                                                         final KeyStore trustStore,
-                                                         final boolean acceptExpired) {
-        return null;
+    /**
+     * Checks if the signature of an attribute cert is validated against the signing cert's public
+     * key.
+     *
+     * @param cert
+     *            the public-key certificate with the signature to validate
+     * @param signingCert
+     *            the certificate with the public key to validate
+     * @return boolean indicating if the validation passed
+     * @throws SupplyChainValidatorException tried to validate using null certificates
+     */
+    public static boolean signatureMatchesPublicKey(final X509Certificate cert,
+                                                    final X509Certificate signingCert) throws SupplyChainValidatorException {
+        if (cert == null || signingCert == null) {
+            throw new SupplyChainValidatorException("Certificate or signing certificate is null");
+        }
+        try {
+            cert.verify(signingCert.getPublicKey(), BouncyCastleProvider.PROVIDER_NAME);
+            return true;
+        } catch (InvalidKeyException e) {
+            log.info("Incorrect key given to validate this cert's signature");
+        } catch (CertificateException e) {
+            log.info("Encoding error while validating this cert's signature");
+        } catch (NoSuchAlgorithmException e) {
+            log.info("Unsupported signature algorithm found during validation");
+        } catch (NoSuchProviderException e) {
+            log.info("Incorrect provider for cert signature validation");
+        } catch (SignatureException e) {
+            log.info(String.format("%s.verify(%s)", cert.getSubjectX500Principal(),
+                    signingCert.getSubjectX500Principal()));
+        }
+        return false;
+
+    }
+
+    /**
+     * Checks if the signature of a public-key cert is validated against the signing cert's public
+     * key.
+     *
+     * @param cert
+     *            the attribute certificate with the signature to validate
+     * @param signingCert
+     *            the certificate with the public key to validate
+     * @return boolean indicating if the validation passed
+     * @throws SupplyChainValidatorException tried to validate using null certificates
+     */
+    public static boolean signatureMatchesPublicKey(final X509AttributeCertificateHolder cert,
+                                                    final X509Certificate signingCert) throws SupplyChainValidatorException {
+        if (signingCert == null) {
+            throw new SupplyChainValidatorException("Signing certificate is null");
+        }
+        return signatureMatchesPublicKey(cert, signingCert.getPublicKey());
+    }
+
+    /**
+     * Checks if an X509 Attribute Certificate is valid directly against a public key.
+     *
+     * @param cert
+     *            the attribute certificate with the signature to validate
+     * @param signingKey
+     *            the key to use to check the attribute cert
+     * @return boolean indicating if the validation passed
+     * @throws SupplyChainValidatorException tried to validate using null certificates
+     */
+    public static boolean signatureMatchesPublicKey(final X509AttributeCertificateHolder cert,
+                                                    final PublicKey signingKey) throws SupplyChainValidatorException {
+        if (cert == null || signingKey == null) {
+            throw new SupplyChainValidatorException("Certificate or signing certificate is null");
+        }
+        ContentVerifierProvider contentVerifierProvider;
+        try {
+            contentVerifierProvider =
+                    new JcaContentVerifierProviderBuilder().setProvider("BC").build(signingKey);
+            return cert.isSignatureValid(contentVerifierProvider);
+        } catch (OperatorCreationException | CertException e) {
+            log.info("Exception thrown while verifying certificate", e);
+            log.info(String.format("%s.isSignatureValid(%s)", cert.getSerialNumber(),
+                    signingKey.getFormat()));
+            return false;
+        }
+    }
+
+    /**
+     * Checks whether given X.509 public-key certificate is self-signed. If the cert can be
+     * verified using its own public key, that means it was self-signed.
+     *
+     * @param cert
+     *            X.509 Certificate
+     * @return boolean indicating if the cert was self-signed
+     */
+    private static boolean isSelfSigned(final X509Certificate cert)
+            throws SupplyChainValidatorException {
+        if (cert == null) {
+            throw new SupplyChainValidatorException("Certificate is null");
+        }
+        try {
+            PublicKey key = cert.getPublicKey();
+            cert.verify(key);
+            return true;
+        } catch (SignatureException | InvalidKeyException e) {
+            return false;
+        } catch (CertificateException | NoSuchAlgorithmException | NoSuchProviderException e) {
+            log.error("Exception occurred while checking if cert is self-signed", e);
+            return false;
+        }
     }
 }
diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java
index c2947c68..110bbd00 100644
--- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java
+++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java
@@ -1,6 +1,7 @@
 package hirs.attestationca.portal.page.controllers;
 
 import hirs.attestationca.persist.DBServiceException;
+import hirs.attestationca.persist.entity.manager.CACredentialRepository;
 import hirs.attestationca.persist.entity.manager.CertificateRepository;
 import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository;
 import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository;
@@ -10,14 +11,14 @@ import hirs.attestationca.persist.entity.userdefined.rim.BaseReferenceManifest;
 import hirs.attestationca.persist.entity.userdefined.rim.EventLogMeasurements;
 import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
 import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
-import hirs.attestationca.persist.service.SupplyChainValidationServiceImpl;
+import hirs.attestationca.persist.service.ValidationManager;
 import hirs.attestationca.persist.validation.ReferenceManifestValidator;
+import hirs.attestationca.persist.validation.SupplyChainCredentialValidator;
 import hirs.attestationca.persist.validation.SupplyChainValidatorException;
 import hirs.attestationca.portal.page.Page;
 import hirs.attestationca.portal.page.PageController;
 import hirs.attestationca.portal.page.PageMessages;
 import hirs.attestationca.portal.page.params.ReferenceManifestDetailsPageParams;
-import hirs.attestationca.portal.page.utils.SupplyChainCredentialValidator;
 import hirs.utils.SwidResource;
 import hirs.utils.tpm.eventlog.TCGEventLog;
 import hirs.utils.tpm.eventlog.TpmPcrEvent;
@@ -52,6 +53,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
     private final ReferenceManifestRepository referenceManifestRepository;
     private final ReferenceDigestValueRepository referenceDigestValueRepository;
     private final CertificateRepository certificateRepository;
+    private final CACredentialRepository caCertificateRepository;
     private static final ReferenceManifestValidator RIM_VALIDATOR
             = new ReferenceManifestValidator();
 
@@ -61,15 +63,18 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
      * @param referenceManifestRepository the repository for RIM.
      * @param referenceDigestValueRepository    the reference event manager.
      * @param certificateRepository       the certificate manager.
+     * @param caCertificateRepository       the CA certificate manager.
      */
     @Autowired
     public ReferenceManifestDetailsPageController(final ReferenceManifestRepository referenceManifestRepository,
                                                   final ReferenceDigestValueRepository referenceDigestValueRepository,
-                                                  final CertificateRepository certificateRepository) {
+                                                  final CertificateRepository certificateRepository,
+                                                  final CACredentialRepository caCertificateRepository) {
         super(Page.RIM_DETAILS);
         this.referenceManifestRepository = referenceManifestRepository;
         this.referenceDigestValueRepository = referenceDigestValueRepository;
         this.certificateRepository = certificateRepository;
+        this.caCertificateRepository = caCertificateRepository;
     }
 
     /**
@@ -100,7 +105,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
             try {
                 UUID uuid = UUID.fromString(params.getId());
                 data.putAll(getRimDetailInfo(uuid, referenceManifestRepository,
-                        referenceDigestValueRepository, certificateRepository));
+                        referenceDigestValueRepository, certificateRepository,
+                        caCertificateRepository));
             } catch (IllegalArgumentException iaEx) {
                 String uuidError = "Failed to parse ID from: " + params.getId();
                 messages.addError(uuidError);
@@ -130,6 +136,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
      * @param referenceManifestRepository the reference manifest manager.
      * @param referenceDigestValueRepository    the reference event manager.
      * @param certificateRepository       the certificate manager.
+     * @param caCertificateRepository       the certificate manager.
      * @return mapping of the RIM information from the database.
      * @throws java.io.IOException      error for reading file bytes.
      * @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
@@ -138,7 +145,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
     public static HashMap<String, Object> getRimDetailInfo(final UUID uuid,
                                                            final ReferenceManifestRepository referenceManifestRepository,
                                                            final ReferenceDigestValueRepository referenceDigestValueRepository,
-                                                           final CertificateRepository certificateRepository)
+                                                           final CertificateRepository certificateRepository,
+                                                           final CACredentialRepository caCertificateRepository)
             throws IOException,
             CertificateException, NoSuchAlgorithmException {
         HashMap<String, Object> data = new HashMap<>();
@@ -146,7 +154,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
         BaseReferenceManifest bRim = referenceManifestRepository.getBaseRimEntityById(uuid);
 
         if (bRim != null) {
-            data.putAll(getBaseRimInfo(bRim, referenceManifestRepository, certificateRepository));
+            data.putAll(getBaseRimInfo(bRim, referenceManifestRepository, certificateRepository, caCertificateRepository));
         }
 
         SupportReferenceManifest sRim = referenceManifestRepository.getSupportRimEntityById(uuid);
@@ -172,6 +180,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
      * @param baseRim                  established ReferenceManifest Type.
      * @param referenceManifestRepository the reference manifest manager.
      * @param certificateRepository       the certificate manager.
+     * @param caCertificateRepository       the certificate manager.
      * @return mapping of the RIM information from the database.
      * @throws java.io.IOException      error for reading file bytes.
      * @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
@@ -180,7 +189,8 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
     private static HashMap<String, Object> getBaseRimInfo(
             final BaseReferenceManifest baseRim,
             final ReferenceManifestRepository referenceManifestRepository,
-            final CertificateRepository certificateRepository)
+            final CertificateRepository certificateRepository,
+            final CACredentialRepository caCertificateRepository)
             throws IOException, CertificateException, NoSuchAlgorithmException {
         HashMap<String, Object> data = new HashMap<>();
 
@@ -288,9 +298,7 @@ public class ReferenceManifestDetailsPageController extends PageController<Refer
         //Report invalid signature unless RIM_VALIDATOR validates it and cert path is valid
         data.put("signatureValid", false);
         for (CertificateAuthorityCredential cert : certificates) {
-            SupplyChainValidationServiceImpl scvsImpl =
-                    new SupplyChainValidationServiceImpl(certificateRepository);
-            KeyStore keystore = scvsImpl.getCaChain(cert);
+            KeyStore keystore = ValidationManager.getCaChain(cert, caCertificateRepository);
             if (RIM_VALIDATOR.validateXmlSignature(cert)) {
                 try {
                     if (SupplyChainCredentialValidator.verifyCertificate(
diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/CertificateStringMapBuilder.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/CertificateStringMapBuilder.java
index 0506c1e9..f7921b6a 100644
--- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/CertificateStringMapBuilder.java
+++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/CertificateStringMapBuilder.java
@@ -12,6 +12,7 @@ import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredent
 import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
 import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration;
 import hirs.utils.BouncyCastleUtils;
+import hirs.attestationca.persist.util.PciIds;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import lombok.extern.log4j.Log4j2;
diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/SupplyChainCredentialValidator.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/SupplyChainCredentialValidator.java
deleted file mode 100644
index d28066d6..00000000
--- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/SupplyChainCredentialValidator.java
+++ /dev/null
@@ -1,1766 +0,0 @@
-package hirs.attestationca.portal.page.utils;
-
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import hirs.attestationca.persist.entity.ArchivableEntity;
-import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation;
-import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
-import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
-import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier;
-import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2;
-import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo;
-import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo;
-import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport;
-import hirs.attestationca.persist.enums.AppraisalStatus;
-import hirs.attestationca.persist.validation.CredentialValidator;
-import hirs.attestationca.persist.validation.SupplyChainValidatorException;
-import hirs.utils.enums.DeviceInfoEnums;
-import lombok.NoArgsConstructor;
-import lombok.extern.log4j.Log4j2;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.util.Strings;
-import org.bouncycastle.asn1.DERUTF8String;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.cert.CertException;
-import org.bouncycastle.cert.X509AttributeCertificateHolder;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.operator.ContentVerifierProvider;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
-import org.springframework.stereotype.Service;
-
-import javax.security.auth.x500.X500Principal;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.security.InvalidKeyException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.SignatureException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateExpiredException;
-import java.security.cert.CertificateNotYetValidException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import static hirs.attestationca.persist.enums.AppraisalStatus.Status.ERROR;
-import static hirs.attestationca.persist.enums.AppraisalStatus.Status.FAIL;
-import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS;
-
-/**
- * Validates elements of the supply chain.
- */
-@Log4j2
-@NoArgsConstructor
-@Service
-public final class SupplyChainCredentialValidator implements CredentialValidator {
-    private static final int NUC_VARIABLE_BIT = 159;
-
-    /**
-     * AppraisalStatus message for a valid endorsement credential appraisal.
-     */
-    public static final String ENDORSEMENT_VALID = "Endorsement credential validated";
-
-    /**
-     * AppraisalStatus message for a valid platform credential appraisal.
-     */
-    public static final String PLATFORM_VALID = "Platform credential validated";
-
-    /**
-     * AppraisalStatus message for a valid platform credential attributes appraisal.
-     */
-    public static final String PLATFORM_ATTRIBUTES_VALID =
-            "Platform credential attributes validated";
-
-    /**
-     * AppraisalStatus message for a valid firmware appraisal.
-     */
-    public static final String FIRMWARE_VALID = "Firmware validated";
-
-    /**
-     * Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
-     * class expects it to be available.
-     */
-    static {
-        Security.addProvider(new BouncyCastleProvider());
-    }
-
-    /**
-     * Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects.
-     * @param paccorOutput the output from PACCOR's allcomoponents.sh
-     * @return a list of ComponentInfo objects built from paccorOutput
-     * @throws IOException if something goes wrong parsing the JSON
-     */
-    public static List<ComponentInfo> getComponentInfoFromPaccorOutput(final String paccorOutput)
-            throws IOException {
-        List<ComponentInfo> componentInfoList = new ArrayList<>();
-
-        if (StringUtils.isNotEmpty(paccorOutput)) {
-            ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
-            JsonNode rootNode = objectMapper.readTree(paccorOutput);
-            Iterator<JsonNode> jsonComponentNodes
-                    = rootNode.findValue("COMPONENTS").elements();
-            while (jsonComponentNodes.hasNext()) {
-                JsonNode next = jsonComponentNodes.next();
-                componentInfoList.add(new ComponentInfo(
-                        getJSONNodeValueAsText(next, "MANUFACTURER"),
-                        getJSONNodeValueAsText(next, "MODEL"),
-                        getJSONNodeValueAsText(next, "SERIAL"),
-                        getJSONNodeValueAsText(next, "REVISION")));
-            }
-        }
-
-        return componentInfoList;
-    }
-
-    /**
-     * Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects.
-     * @param paccorOutput the output from PACCOR's allcomoponents.sh
-     * @return a list of ComponentInfo objects built from paccorOutput
-     * @throws IOException if something goes wrong parsing the JSON
-     */
-    public static List<ComponentInfo> getV2PaccorOutput(
-            final String paccorOutput) throws IOException {
-        List<ComponentInfo> ciList = new LinkedList<>();
-        String manufacturer, model, serial, revision;
-        String componentClass = Strings.EMPTY;
-
-        if (StringUtils.isNotEmpty(paccorOutput)) {
-            ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
-            JsonNode rootNode = objectMapper.readTree(paccorOutput);
-            Iterator<JsonNode> jsonComponentNodes
-                    = rootNode.findValue("COMPONENTS").elements();
-            while (jsonComponentNodes.hasNext()) {
-                JsonNode next = jsonComponentNodes.next();
-                manufacturer = getJSONNodeValueAsText(next, "MANUFACTURER");
-                model = getJSONNodeValueAsText(next, "MODEL");
-                serial = getJSONNodeValueAsText(next, "SERIAL");
-                revision = getJSONNodeValueAsText(next, "REVISION");
-                List<JsonNode> compClassNodes = next.findValues("COMPONENTCLASS");
-
-                for (JsonNode subNode : compClassNodes) {
-                    componentClass = getJSONNodeValueAsText(subNode,
-                            "COMPONENTCLASSVALUE");
-                }
-                ciList.add(new ComponentInfo(manufacturer, model,
-                        serial, revision, componentClass));
-            }
-        }
-
-        return ciList;
-    }
-
-    private static String getJSONNodeValueAsText(final JsonNode node, final String fieldName) {
-        if (node.hasNonNull(fieldName)) {
-            return node.findValue(fieldName).asText();
-        }
-        return null;
-    }
-
-    /**
-     * Checks if the platform credential is valid.
-     *
-     * @param pc The platform credential to verify.
-     * @param trustStore trust store holding trusted certificates.
-     * @param acceptExpired whether or not to accept expired certificates as valid.
-     * @return The result of the validation.
-     */
-    @Override
-    public AppraisalStatus validatePlatformCredential(final PlatformCredential pc,
-                                                      final KeyStore trustStore,
-                                                      final boolean acceptExpired) {
-        final String baseErrorMessage = "Can't validate platform credential without ";
-        String message;
-        String certVerifyMsg;
-        if (pc == null) {
-            message = baseErrorMessage + "a platform credential\n";
-            log.error(message);
-            return new AppraisalStatus(FAIL, message);
-        }
-        try {
-            if (trustStore == null || trustStore.size() == 0) {
-                message = baseErrorMessage + "an Issuer Cert in the Trust Store\n";
-                log.error(message);
-                return new AppraisalStatus(FAIL, message);
-            }
-        } catch (KeyStoreException e) {
-            message = baseErrorMessage + "an initialized trust store";
-            log.error(message);
-            return new AppraisalStatus(FAIL, message);
-        }
-
-        X509AttributeCertificateHolder attributeCert = null;
-        try {
-            attributeCert = pc.getX509AttributeCertificateHolder();
-        } catch (IOException e) {
-            message = "Could not retrieve X509 Attribute certificate";
-            log.error(message, e);
-            return new AppraisalStatus(FAIL, message + " " + e.getMessage());
-        }
-
-        // check validity period, currently acceptExpired will also accept not yet
-        // valid certificates
-        if (!acceptExpired && !pc.isValidOn(new Date())) {
-            message = "Platform credential has expired";
-            // if not valid at the current time
-            log.warn(message);
-            return new AppraisalStatus(FAIL, message);
-        }
-
-        // verify cert against truststore
-        try {
-            certVerifyMsg = verifyCertificate(attributeCert, trustStore);
-            if (certVerifyMsg.isEmpty()) {
-                message = PLATFORM_VALID;
-                log.info(message);
-                return new AppraisalStatus(PASS, message);
-            } else {
-                message = String.format("Platform credential failed verification%n%s",
-                        certVerifyMsg);
-                log.error(message);
-                return new AppraisalStatus(FAIL, message);
-            }
-        } catch (SupplyChainValidatorException scvEx) {
-            message = "An error occurred indicating the credential is not valid";
-            log.warn(message, scvEx);
-            return new AppraisalStatus(FAIL, message + " " + scvEx.getMessage());
-        }
-    }
-
-    /**
-     * Checks if the platform credential's attributes are valid.
-     * @param platformCredential The platform credential to verify.
-     * @param deviceInfoReport The device info report containing
-     *                         serial number of the platform to be validated.
-     * @param endorsementCredential The endorsement credential supplied from the same
-     *          identity request as the platform credential.
-     * @return The result of the validation.
-     */
-    @Override
-    public AppraisalStatus validatePlatformCredentialAttributes(
-            final PlatformCredential platformCredential,
-            final DeviceInfoReport deviceInfoReport,
-            final EndorsementCredential endorsementCredential) {
-        final String baseErrorMessage = "Can't validate platform credential attributes without ";
-        String message;
-        if (platformCredential == null) {
-            message = baseErrorMessage + "a platform credential";
-            log.error(message);
-            return new AppraisalStatus(FAIL, message);
-        }
-        if (deviceInfoReport == null) {
-            message = baseErrorMessage + "a device info report";
-            log.error(message);
-            return new AppraisalStatus(FAIL, message);
-        }
-        if (endorsementCredential == null) {
-            message = baseErrorMessage + "an endorsement credential";
-            log.error(message);
-            return new AppraisalStatus(FAIL, message);
-        }
-
-        // Quick, early check if the platform credential references the endorsement credential
-        if (!endorsementCredential.getSerialNumber()
-                .equals(platformCredential.getHolderSerialNumber())) {
-            message = "Platform Credential holder serial number does not match "
-                    + "the Endorsement Credential's serial number";
-            log.error(message);
-            return new AppraisalStatus(FAIL, message);
-        }
-
-        String credentialType = platformCredential.getCredentialType();
-        if (PlatformCredential.CERTIFICATE_TYPE_2_0.equals(credentialType)) {
-            return validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport);
-        }
-        return validatePlatformCredentialAttributesV1p2(platformCredential, deviceInfoReport);
-    }
-
-    /**
-     * Checks if the delta credential's attributes are valid.
-     * @param deltaPlatformCredential the delta credential to verify
-     * @param deviceInfoReport The device info report containing
-     *                         serial number of the platform to be validated.
-     * @param basePlatformCredential the base credential from the same identity request
-     *                              as the delta credential.
-     * @param deltaMapping delta certificates associated with the
-     *                          delta supply validation.
-     * @return the result of the validation.
-     */
-    @Override
-    public AppraisalStatus validateDeltaPlatformCredentialAttributes(
-            final PlatformCredential deltaPlatformCredential,
-            final DeviceInfoReport deviceInfoReport,
-            final PlatformCredential basePlatformCredential,
-            final Map<PlatformCredential, SupplyChainValidation> deltaMapping) {
-        String message;
-
-        // this needs to be a loop for all deltas, link to issue #110
-        // check that they don't have the same serial number
-        for (PlatformCredential pc : deltaMapping.keySet()) {
-            if (!basePlatformCredential.getPlatformSerial()
-                    .equals(pc.getPlatformSerial())) {
-                message = String.format("Base and Delta platform serial "
-                                + "numbers do not match (%s != %s)",
-                        pc.getPlatformSerial(),
-                        basePlatformCredential.getPlatformSerial());
-                log.error(message);
-                return new AppraisalStatus(FAIL, message);
-            }
-            // none of the deltas should have the serial number of the base
-            if (!pc.isPlatformBase() && basePlatformCredential.getSerialNumber()
-                    .equals(pc.getSerialNumber())) {
-                message = String.format("Delta Certificate with same serial number as base. (%s)",
-                        pc.getSerialNumber());
-                log.error(message);
-                return new AppraisalStatus(FAIL, message);
-            }
-        }
-
-        // parse out the provided delta and its specific chain.
-        List<ComponentIdentifier> origPcComponents
-                = new LinkedList<>(basePlatformCredential.getComponentIdentifiers());
-
-        return validateDeltaAttributesChainV2p0(deviceInfoReport,
-                deltaMapping, 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.
-        // Retrieve the various device serial numbers.
-        String credentialBoardSerialNumber = platformCredential.getPlatformSerial();
-        String credentialChassisSerialNumber = platformCredential.getChassisSerialNumber();
-
-        HardwareInfo hardwareInfo = deviceInfoReport.getHardwareInfo();
-        String deviceBaseboardSerialNumber = hardwareInfo.getBaseboardSerialNumber();
-        String deviceChassisSerialNumber = hardwareInfo.getChassisSerialNumber();
-        String deviceSystemSerialNumber = hardwareInfo.getSystemSerialNumber();
-
-        // log serial numbers that weren't collected. Force "not specified" serial numbers
-        // to be ignored in below case checks
-        Map<String, String> deviceInfoSerialNumbers = new HashMap<>();
-
-        if (StringUtils.isEmpty(deviceBaseboardSerialNumber)
-                || DeviceInfoEnums.NOT_SPECIFIED.equalsIgnoreCase(deviceBaseboardSerialNumber)) {
-            log.error("Failed to retrieve device baseboard serial number");
-            deviceBaseboardSerialNumber = null;
-        } else {
-            deviceInfoSerialNumbers.put("board serial number", deviceBaseboardSerialNumber);
-            log.info("Using device board serial number for validation: "
-                    + deviceBaseboardSerialNumber);
-        }
-
-        if (StringUtils.isEmpty(deviceChassisSerialNumber)
-                || DeviceInfoEnums.NOT_SPECIFIED.equalsIgnoreCase(deviceChassisSerialNumber)) {
-            log.error("Failed to retrieve device chassis serial number");
-        } else {
-            deviceInfoSerialNumbers.put("chassis serial number", deviceChassisSerialNumber);
-            log.info("Using device chassis serial number for validation: "
-                    + deviceChassisSerialNumber);
-        }
-        if (StringUtils.isEmpty(deviceSystemSerialNumber)
-                || DeviceInfoEnums.NOT_SPECIFIED.equalsIgnoreCase(deviceSystemSerialNumber)) {
-            log.error("Failed to retrieve device system serial number");
-        } else {
-            deviceInfoSerialNumbers.put("system serial number", deviceSystemSerialNumber);
-            log.info("Using device system serial number for validation: "
-                    + deviceSystemSerialNumber);
-        }
-
-        AppraisalStatus status;
-
-        // Test 1: If the board serial number or chassis is set on the PC,
-        // compare with each of the device serial numbers for any match
-        if (StringUtils.isNotEmpty(credentialBoardSerialNumber)
-                || StringUtils.isNotEmpty(credentialChassisSerialNumber)) {
-            status = validatePlatformSerialsWithDeviceSerials(credentialBoardSerialNumber,
-                    credentialChassisSerialNumber, deviceInfoSerialNumbers);
-            // Test 2: If the board and chassis serial numbers are not set on the PC,
-            // compare the SHA1 hash of the device baseboard serial number to
-            // the certificate serial number
-        } else {
-            String message;
-            log.debug("Credential Serial Number was null");
-            if (StringUtils.isEmpty(deviceBaseboardSerialNumber)) {
-                message = "Device Serial Number was null";
-                log.error(message);
-                status = new AppraisalStatus(FAIL, message);
-            } else {
-                // Calculate the SHA1 hash of the UTF8 encoded baseboard serial number
-                BigInteger baseboardSha1 = new BigInteger(1,
-                        DigestUtils.sha1(deviceBaseboardSerialNumber.getBytes(StandardCharsets.UTF_8)));
-                BigInteger certificateSerialNumber = platformCredential.getSerialNumber();
-
-                // compare the SHA1 hash of the baseboard serial number to the certificate SN
-                if (certificateSerialNumber != null
-                        && certificateSerialNumber.equals(baseboardSha1)) {
-                    log.info("Device Baseboard Serial Number matches "
-                            + "the Certificate Serial Number");
-                    status = new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID);
-                } else if (certificateSerialNumber != null
-                        && certificateSerialNumber.equals(
-                        baseboardSha1.clearBit(NUC_VARIABLE_BIT))) {
-                    log.info("Warning! The Certificate serial number had the most significant "
-                            + "bit truncated.  159 bits of it matched the device baseboard "
-                            + "serial number.");
-                    status = new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID);
-                } else {
-                    message = "The SHA1 hash of the Device Baseboard Serial Number "
-                            + deviceBaseboardSerialNumber
-                            + " did not match the Certificate's Serial Number";
-                    log.error(message);
-                    status = new AppraisalStatus(FAIL, message);
-
-                }
-            }
-        }
-
-        return status;
-    }
-
-    /**
-     * Validates device info report against the new platform credential.
-     * @param platformCredential the Platform Credential
-     * @param deviceInfoReport the Device Info Report
-     * @return either PASS or FAIL
-     */
-    static AppraisalStatus validatePlatformCredentialAttributesV2p0(
-            final PlatformCredential platformCredential,
-            final DeviceInfoReport deviceInfoReport) {
-        boolean passesValidation = true;
-        StringBuilder resultMessage = new StringBuilder();
-
-        HardwareInfo hardwareInfo = deviceInfoReport.getHardwareInfo();
-
-        boolean fieldValidation;
-        fieldValidation = requiredPlatformCredentialFieldIsNonEmptyAndMatches(
-                "PlatformManufacturerStr",
-                platformCredential.getManufacturer(),
-                hardwareInfo.getManufacturer());
-
-        if (!fieldValidation) {
-            resultMessage.append("Platform manufacturer did not match\n");
-        }
-
-        passesValidation &= fieldValidation;
-
-        fieldValidation = requiredPlatformCredentialFieldIsNonEmptyAndMatches(
-                "PlatformModel",
-                platformCredential.getModel(),
-                hardwareInfo.getProductName());
-
-        if (!fieldValidation) {
-            resultMessage.append("Platform model did not match\n");
-        }
-
-        passesValidation &= fieldValidation;
-
-        fieldValidation = requiredPlatformCredentialFieldIsNonEmptyAndMatches(
-                "PlatformVersion",
-                platformCredential.getVersion(),
-                hardwareInfo.getVersion());
-
-        if (!fieldValidation) {
-            resultMessage.append("Platform version did not match\n");
-        }
-
-        passesValidation &= fieldValidation;
-
-        // check PlatformSerial against both system-serial-number and baseboard-serial-number
-        fieldValidation = (
-                (optionalPlatformCredentialFieldNullOrMatches(
-                        "PlatformSerial",
-                        platformCredential.getPlatformSerial(),
-                        hardwareInfo.getSystemSerialNumber()))
-                        || (optionalPlatformCredentialFieldNullOrMatches(
-                        "PlatformSerial",
-                        platformCredential.getPlatformSerial(),
-                        hardwareInfo.getBaseboardSerialNumber())));
-
-        if (!fieldValidation) {
-            resultMessage.append("Platform serial did not match\n");
-        }
-
-        passesValidation &= fieldValidation;
-
-        // Retrieve the list of all components from the Platform Credential
-        List<ComponentIdentifier> allPcComponents
-                = new ArrayList<>(platformCredential.getComponentIdentifiers());
-
-        // All components listed in the Platform Credential must have a manufacturer and model
-        for (ComponentIdentifier pcComponent : allPcComponents) {
-            fieldValidation = !hasEmptyValueForRequiredField("componentManufacturer",
-                    pcComponent.getComponentManufacturer());
-
-            if (!fieldValidation) {
-                resultMessage.append("Component manufacturer is empty\n");
-            }
-
-            passesValidation &= fieldValidation;
-
-            fieldValidation = !hasEmptyValueForRequiredField("componentModel",
-                    pcComponent.getComponentModel());
-
-            if (!fieldValidation) {
-                resultMessage.append("Component model is empty\n");
-            }
-
-            passesValidation &= fieldValidation;
-        }
-
-        // There is no need to do comparisons with components that are invalid because
-        // they did not have a manufacturer or model.
-        List<ComponentIdentifier> validPcComponents = allPcComponents.stream()
-                .filter(identifier -> identifier.getComponentManufacturer() != null
-                        && identifier.getComponentModel() != null)
-                .collect(Collectors.toList());
-
-        String paccorOutputString = deviceInfoReport.getPaccorOutputString();
-        String unmatchedComponents;
-        try {
-            List<ComponentInfo> componentInfoList
-                    = getComponentInfoFromPaccorOutput(paccorOutputString);
-            unmatchedComponents = validateV2p0PlatformCredentialComponentsExpectingExactMatch(
-                    validPcComponents, componentInfoList);
-            fieldValidation &= unmatchedComponents.isEmpty();
-        } catch (IOException e) {
-            final String baseErrorMessage = "Error parsing JSON output from PACCOR: ";
-            log.error(baseErrorMessage + e.toString());
-            log.error("PACCOR output string:\n" + paccorOutputString);
-            return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage());
-        }
-
-        StringBuilder additionalInfo = new StringBuilder();
-        if (!fieldValidation) {
-            resultMessage.append("There are unmatched components:\n");
-            resultMessage.append(unmatchedComponents);
-
-            // pass information of which ones failed in additionInfo
-            int counter = 0;
-            for (ComponentIdentifier ci : validPcComponents) {
-                counter++;
-                additionalInfo.append(String.format("%d;", ci.hashCode()));
-            }
-            if (counter > 0) {
-                additionalInfo.insert(0, "COMPID=");
-                additionalInfo.append(counter);
-            }
-        }
-
-        passesValidation &= fieldValidation;
-
-        if (passesValidation) {
-            return new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID);
-        } else {
-            return new AppraisalStatus(FAIL, resultMessage.toString(), additionalInfo.toString());
-        }
-    }
-
-    /**
-     * 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 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.
-     */
-    @SuppressWarnings("methodlength")
-    static AppraisalStatus validateDeltaAttributesChainV2p0(
-            final DeviceInfoReport deviceInfoReport,
-            final Map<PlatformCredential, SupplyChainValidation> deltaMapping,
-            final List<ComponentIdentifier> origPcComponents) {
-        boolean fieldValidation = true;
-        StringBuilder resultMessage = new StringBuilder();
-        String tempStringMessage = "";
-        List<ComponentIdentifier> validOrigPcComponents = origPcComponents.stream()
-                .filter(identifier -> identifier.getComponentManufacturer() != null
-                        && identifier.getComponentModel() != null)
-                .collect(Collectors.toList());
-        List<PlatformCredential> chainCertificates = new LinkedList<>(deltaMapping.keySet());
-
-        // map the components throughout the chain
-        List<ComponentIdentifier> baseCompList = new LinkedList<>(validOrigPcComponents);
-
-        Collections.sort(chainCertificates, new Comparator<PlatformCredential>() {
-            @Override
-            public int compare(final PlatformCredential obj1,
-                               final PlatformCredential obj2) {
-                if (obj1 == null) {
-                    return 0;
-                }
-                if (obj2 == null) {
-                    return 0;
-                }
-                if (obj1.getBeginValidity() == null || obj2.getBeginValidity() == null) {
-                    return 0;
-                }
-                return obj1.getBeginValidity().compareTo(obj2.getBeginValidity());
-            }
-        });
-        // start of some changes
-        resultMessage.append("There are errors with Delta "
-                + "Component Statuses:\n");
-        List<ComponentIdentifier> leftOverDeltas = new ArrayList<>();
-        List<ComponentIdentifier> absentSerialNum = new ArrayList<>();
-        tempStringMessage = validateDeltaChain(deltaMapping, baseCompList,
-                leftOverDeltas, absentSerialNum, chainCertificates);
-
-        // check if there were any issues
-        if (!tempStringMessage.isEmpty()) {
-            resultMessage.append(tempStringMessage);
-            fieldValidation = false;
-        }
-
-        // finished up
-        List<ArchivableEntity> certificateList = null;
-        SupplyChainValidation scv = null;
-        StringBuilder deltaSb = new StringBuilder();
-
-        // non-empty serial values
-        for (ComponentIdentifier deltaCi : leftOverDeltas) {
-            String classValue;
-            ComponentIdentifierV2 ciV2 = (ComponentIdentifierV2) deltaCi;
-            ComponentIdentifierV2 baseCiV2;
-            boolean classFound;
-
-            for (ComponentIdentifier ci : absentSerialNum) {
-                classValue = ciV2.getComponentClass().getComponentIdentifier();
-                baseCiV2 = (ComponentIdentifierV2) ci;
-                classFound = classValue.equals(baseCiV2.getComponentClass()
-                        .getComponentIdentifier());
-                if (classFound) {
-                    if (isMatch(ciV2, baseCiV2)) {
-                        if (ciV2.isAdded() || ciV2.isModified()) {
-                            // since the base list doesn't have this ci
-                            // just add the delta
-                            baseCompList.add(deltaCi);
-                            break;
-                        }
-                        if (ciV2.isRemoved()) {
-                            baseCompList.remove(ciV2);
-                            break;
-                        }
-                        // if it is a remove
-                        // we do nothing because baseCompList doesn't have it
-                    } else {
-                        // it is an add
-                        if (ciV2.isAdded()) {
-                            baseCompList.add(deltaCi);
-                        }
-                    }
-                } else {
-                    // delta change to a class not there
-                    if (ciV2.isAdded()) {
-                        baseCompList.add(deltaCi);
-                    }
-
-                    if (ciV2.isModified()) {
-                        // error because you can't modify something
-                        // that isn't here
-                        resultMessage.append("MODIFIED attempted without prior instance\n");
-                        deltaSb.append(String.format("%s;", ci.hashCode()));
-                    }
-
-                    if (ciV2.isRemoved()) {
-                        // error because you can't remove something
-                        // that isn't here
-                        resultMessage.append("REMOVED attempted without prior instance\n");
-                        deltaSb.append(String.format("%s;", ci.hashCode()));
-                    }
-                }
-            }
-        }
-
-        if (!fieldValidation || !deltaSb.toString().isEmpty()) {
-            deltaSb.insert(0, "COMPID=");
-            return new AppraisalStatus(FAIL, resultMessage.toString(), deltaSb.toString());
-        }
-
-        String paccorOutputString = deviceInfoReport.getPaccorOutputString();
-        String unmatchedComponents;
-        try {
-            // compare based on component class
-            List<ComponentInfo> componentInfoList = getV2PaccorOutput(paccorOutputString);
-            // this is what I want to rewrite
-            unmatchedComponents = validateV2PlatformCredentialAttributes(
-                    baseCompList,
-                    componentInfoList);
-            fieldValidation &= unmatchedComponents.isEmpty();
-        } catch (IOException ioEx) {
-            final String baseErrorMessage = "Error parsing JSON output from PACCOR: ";
-            log.error(baseErrorMessage + ioEx.toString());
-            log.error("PACCOR output string:\n" + paccorOutputString);
-            return new AppraisalStatus(ERROR, baseErrorMessage + ioEx.getMessage());
-        }
-        StringBuilder additionalInfo = new StringBuilder();
-        if (!fieldValidation) {
-            resultMessage = new StringBuilder();
-            resultMessage.append("There are unmatched components:\n");
-            resultMessage.append(unmatchedComponents);
-
-            // pass information of which ones failed in additionInfo
-            int counter = 0;
-            for (ComponentIdentifier ci : baseCompList) {
-                counter++;
-                additionalInfo.append(String.format("%d;", ci.hashCode()));
-            }
-            if (counter > 0) {
-                additionalInfo.insert(0, "COMPID=");
-                additionalInfo.append(counter);
-            }
-        }
-
-        if (fieldValidation) {
-            return new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID);
-        } else {
-            return new AppraisalStatus(FAIL, resultMessage.toString(), additionalInfo.toString());
-        }
-    }
-
-    private static String validateV2PlatformCredentialAttributes(
-            final List<ComponentIdentifier> fullDeltaChainComponents,
-            final List<ComponentInfo> allDeviceInfoComponents) {
-        ComponentIdentifierV2 ciV2;
-        StringBuilder invalidPcIds = new StringBuilder();
-        List<ComponentIdentifier> subCompIdList = fullDeltaChainComponents
-                .stream().collect(Collectors.toList());
-        List<ComponentInfo> subCompInfoList = allDeviceInfoComponents
-                .stream().collect(Collectors.toList());
-
-        // Delta is the baseline
-        for (ComponentInfo cInfo : allDeviceInfoComponents) {
-            for (ComponentIdentifier cId : fullDeltaChainComponents) {
-                ciV2 = (ComponentIdentifierV2) cId;
-                if (cInfo.getComponentClass().contains(
-                        ciV2.getComponentClass().getComponentIdentifier())
-                        && isMatch(cId, cInfo)) {
-                    subCompIdList.remove(cId);
-                    subCompInfoList.remove(cInfo);
-                }
-            }
-        }
-
-        if (subCompIdList.isEmpty()) {
-            return Strings.EMPTY;
-        } else {
-            // now we return everything that was unmatched
-            // what is in the component info/device reported components
-            // is to be displayed as the failure
-            fullDeltaChainComponents.clear();
-            for (ComponentIdentifier ci : subCompIdList) {
-                if (ci.isVersion2() && PciIds.DB.isReady()) {
-                    ci = PciIds.translate((ComponentIdentifierV2) ci);
-                }
-                log.error("Unmatched component: " + ci);
-                fullDeltaChainComponents.add(ci);
-                invalidPcIds.append(String.format(
-                        "Manufacturer=%s, Model=%s, Serial=%s, Revision=%s;%n",
-                        ci.getComponentManufacturer(),
-                        ci.getComponentModel(),
-                        ci.getComponentSerial(),
-                        ci.getComponentRevision()));
-            }
-        }
-
-        return invalidPcIds.toString();
-    }
-
-    /**
-     * 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
-     * component in the device info report.  The device info report is allowed to have extra
-     * components not represented in the platform credential.
-     *
-     * @param untrimmedPcComponents the platform credential components (may contain end whitespace)
-     *                              **NEW** this is updated with just the unmatched components
-     *                              if there are any failures, otherwise it remains unchanged.
-     * @param allDeviceInfoComponents the device info report components
-     * @return true if validation passes
-     */
-    private static String validateV2p0PlatformCredentialComponentsExpectingExactMatch(
-            final List<ComponentIdentifier> untrimmedPcComponents,
-            final List<ComponentInfo> allDeviceInfoComponents) {
-        // For each manufacturer listed in the platform credential, create two lists:
-        // 1. a list of components listed in the platform credential for the manufacturer, and
-        // 2. a list of components listed in the device info for the same manufacturer
-        // Then eliminate matches from both lists. Finally, decide if the validation passes based
-        // on the leftovers in the lists and the policy in place.
-        final List<ComponentIdentifier> pcComponents = new ArrayList<>();
-        for (ComponentIdentifier component : untrimmedPcComponents) {
-            if (component.getComponentManufacturer() != null) {
-                component.setComponentManufacturer(new DERUTF8String(
-                        component.getComponentManufacturer().getString().trim()));
-            }
-            if (component.getComponentModel() != null) {
-                component.setComponentModel(new DERUTF8String(
-                        component.getComponentModel().getString().trim()));
-            }
-            if (component.getComponentSerial() != null) {
-                component.setComponentSerial(new DERUTF8String(
-                        component.getComponentSerial().getString().trim()));
-            }
-            if (component.getComponentRevision() != null) {
-                component.setComponentRevision(new DERUTF8String(
-                        component.getComponentRevision().getString().trim()));
-            }
-            pcComponents.add(component);
-        }
-
-        log.info("Validating the following Platform Cert components...");
-        pcComponents.forEach(component -> log.info(component.toString()));
-        log.info("...against the the following DeviceInfoReport components:");
-        allDeviceInfoComponents.forEach(component -> log.info(component.toString()));
-        Set<DERUTF8String> manufacturerSet = new HashSet<>();
-        pcComponents.forEach(pcComp -> manufacturerSet.add(pcComp.getComponentManufacturer()));
-
-        // Create a list for unmatched components across all manufacturers to display at the end.
-        List<ComponentIdentifier> pcUnmatchedComponents = new ArrayList<>();
-
-        for (DERUTF8String derUtf8Manufacturer : manufacturerSet) {
-            List<ComponentIdentifier> pcComponentsFromManufacturer
-                    = pcComponents.stream().filter(compIdentifier
-                    -> compIdentifier.getComponentManufacturer().equals(derUtf8Manufacturer))
-                    .collect(Collectors.toList());
-
-            String pcManufacturer = derUtf8Manufacturer.getString();
-            List<ComponentInfo> deviceInfoComponentsFromManufacturer
-                    = allDeviceInfoComponents.stream().filter(componentInfo
-                    -> componentInfo.getComponentManufacturer().equals(pcManufacturer))
-                    .collect(Collectors.toList());
-            // For each component listed in the platform credential from this manufacturer
-            // find the ones that specify a serial number so we can match the most specific ones
-            // first.
-            List<ComponentIdentifier> pcComponentsFromManufacturerWithSerialNumber
-                    = pcComponentsFromManufacturer.stream().filter(compIdentifier
-                    -> compIdentifier.getComponentSerial() != null
-                    && StringUtils.isNotEmpty(compIdentifier.getComponentSerial().getString()))
-                    .collect(Collectors.toList());
-            // 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) {
-                Optional<ComponentInfo> first
-                        = deviceInfoComponentsFromManufacturer.stream()
-                        .filter(componentInfo
-                                -> StringUtils.isNotEmpty(componentInfo.getComponentSerial()))
-                        .filter(componentInfo -> componentInfo.getComponentSerial()
-                                .equals(pcComponent.getComponentSerial().getString())).findFirst();
-
-                if (first.isPresent()) {
-                    ComponentInfo potentialMatch = first.get();
-                    if (isMatch(pcComponent, potentialMatch)) {
-                        pcComponentsFromManufacturer.remove(pcComponent);
-                        deviceInfoComponentsFromManufacturer.remove(potentialMatch);
-                    }
-                }
-            }
-            // For each component listed in the platform credential from this manufacturer
-            // find the ones that specify value for the revision field so we can match the most
-            // specific ones first.
-            List<ComponentIdentifier> pcComponentsFromManufacturerWithRevision
-                    = pcComponentsFromManufacturer.stream().filter(compIdentifier
-                    -> compIdentifier.getComponentRevision() != null
-                    && StringUtils.isNotEmpty(compIdentifier.getComponentRevision().getString()))
-                    .collect(Collectors.toList());
-            // 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) {
-                Optional<ComponentInfo> first
-                        = deviceInfoComponentsFromManufacturer.stream()
-                        .filter(info -> StringUtils.isNotEmpty(info.getComponentRevision()))
-                        .filter(info -> info.getComponentRevision()
-                                .equals(pcComponent.getComponentRevision().getString()))
-                        .findFirst();
-
-                if (first.isPresent()) {
-                    ComponentInfo potentialMatch = first.get();
-                    if (isMatch(pcComponent, potentialMatch)) {
-                        pcComponentsFromManufacturer.remove(pcComponent);
-                        deviceInfoComponentsFromManufacturer.remove(potentialMatch);
-                    }
-                }
-            }
-            // The remaining components from the manufacturer have only the 2 required fields so
-            // just match them.
-            List<ComponentIdentifier> templist = new ArrayList<>(pcComponentsFromManufacturer);
-            for (ComponentIdentifier ci : templist) {
-                Iterator<ComponentInfo> diComponentIter
-                        = deviceInfoComponentsFromManufacturer.iterator();
-                while (diComponentIter.hasNext()) {
-                    ComponentInfo potentialMatch = diComponentIter.next();
-                    if (isMatch(ci, potentialMatch)) {
-                        pcComponentsFromManufacturer.remove(ci);
-                        diComponentIter.remove();
-                    }
-                }
-            }
-            pcUnmatchedComponents.addAll(pcComponentsFromManufacturer);
-        }
-
-        if (!pcUnmatchedComponents.isEmpty()) {
-            untrimmedPcComponents.clear();
-            StringBuilder sb = new StringBuilder();
-            log.error(String.format("Platform Credential contained %d unmatched components:",
-                    pcUnmatchedComponents.size()));
-
-            int unmatchedComponentCounter = 1;
-            for (ComponentIdentifier unmatchedComponent : pcUnmatchedComponents) {
-                if (unmatchedComponent.isVersion2() && PciIds.DB.isReady()) {
-                    unmatchedComponent =
-                            PciIds.translate((ComponentIdentifierV2) unmatchedComponent);
-                }
-                log.error("Unmatched component " + unmatchedComponentCounter++ + ": "
-                        + unmatchedComponent);
-                sb.append(String.format("Manufacturer=%s, Model=%s, Serial=%s, Revision=%s;%n",
-                        unmatchedComponent.getComponentManufacturer(),
-                        unmatchedComponent.getComponentModel(),
-                        unmatchedComponent.getComponentSerial(),
-                        unmatchedComponent.getComponentRevision()));
-                unmatchedComponent.setValidationResult(false);
-                untrimmedPcComponents.add(unmatchedComponent);
-            }
-            return sb.toString();
-        }
-        return Strings.EMPTY;
-    }
-
-    /**
-     * Returns true if fieldValue is null or empty.
-     * @param description description of the value
-     * @param fieldValue value of the field
-     * @return true if fieldValue is null or empty; false otherwise
-     */
-    private static boolean hasEmptyValueForRequiredField(final String description,
-                                                         final String fieldValue) {
-        if (StringUtils.isEmpty(fieldValue)) {
-            log.error("Required field was empty or null in Platform Credential: "
-                    + description);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns true if fieldValue is null or empty.
-     * @param description description of the value
-     * @param fieldValue value of the field
-     * @return true if fieldValue is null or empty; false otherwise
-     */
-    private static boolean hasEmptyValueForRequiredField(final String description,
-                                                         final DERUTF8String fieldValue) {
-        if (fieldValue == null || StringUtils.isEmpty(fieldValue.getString().trim())) {
-            log.error("Required field was empty or null in Platform Credential: "
-                    + description);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Validates the information supplied for the Platform Credential.  This
-     * method checks if the field is required and therefore if the value is
-     * present then verifies that the values match.
-     * @param platformCredentialFieldName name of field to be compared
-     * @param platformCredentialFieldValue first value to compare
-     * @param otherValue second value to compare
-     * @return true if values match
-     */
-    private static boolean requiredPlatformCredentialFieldIsNonEmptyAndMatches(
-            final String platformCredentialFieldName,
-            final String platformCredentialFieldValue,
-            final String otherValue) {
-        if (hasEmptyValueForRequiredField(platformCredentialFieldName,
-                platformCredentialFieldValue)) {
-            return false;
-        }
-
-        return platformCredentialFieldMatches(platformCredentialFieldName,
-                platformCredentialFieldValue, otherValue);
-    }
-
-    /**
-     * Validates the information supplied for the Platform Credential.  This
-     * method checks if the value is present then verifies that the values match.
-     * If not present, then returns true.
-     * @param platformCredentialFieldName name of field to be compared
-     * @param platformCredentialFieldValue first value to compare
-     * @param otherValue second value to compare
-     * @return true if values match or null
-     */
-    private static boolean optionalPlatformCredentialFieldNullOrMatches(
-            final String platformCredentialFieldName,
-            final String platformCredentialFieldValue,
-            final String otherValue) {
-        if (platformCredentialFieldValue == null) {
-            return true;
-        }
-
-        return platformCredentialFieldMatches(platformCredentialFieldName,
-                platformCredentialFieldValue, otherValue);
-    }
-
-    private static boolean platformCredentialFieldMatches(
-            final String platformCredentialFieldName,
-            final String platformCredentialFieldValue,
-            final String otherValue) {
-        String trimmedFieldValue = platformCredentialFieldValue.trim();
-        String trimmedOtherValue = otherValue.trim();
-
-        if (!trimmedFieldValue.equals(trimmedOtherValue)) {
-            log.debug(String.format("%s field in Platform Credential (%s) does not match "
-                            + "a related field in the DeviceInfoReport (%s)",
-                    platformCredentialFieldName, trimmedFieldValue, trimmedOtherValue));
-            return false;
-        }
-
-        log.debug(String.format("%s field in Platform Credential matches "
-                        + "a related field in the DeviceInfoReport (%s)",
-                platformCredentialFieldName, trimmedFieldValue)
-        );
-
-        return true;
-    }
-
-    /**
-     * Checks if the fields in the potentialMatch match the fields in the pcComponent,
-     * or if the relevant field in the pcComponent is empty.
-     * @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)
-     */
-    static boolean isMatch(final ComponentIdentifier pcComponent,
-                           final ComponentInfo potentialMatch) {
-        boolean matchesSoFar = true;
-
-        matchesSoFar &= isMatchOrEmptyInPlatformCert(
-                potentialMatch.getComponentManufacturer(),
-                pcComponent.getComponentManufacturer()
-        );
-
-        matchesSoFar &= isMatchOrEmptyInPlatformCert(
-                potentialMatch.getComponentModel(),
-                pcComponent.getComponentModel()
-        );
-
-        matchesSoFar &= isMatchOrEmptyInPlatformCert(
-                potentialMatch.getComponentSerial(),
-                pcComponent.getComponentSerial()
-        );
-
-        matchesSoFar &= isMatchOrEmptyInPlatformCert(
-                potentialMatch.getComponentRevision(),
-                pcComponent.getComponentRevision()
-        );
-
-        return matchesSoFar;
-    }
-
-    /**
-     * Checks if the fields in the potentialMatch match the fields in the pcComponent,
-     * or if the relevant field in the pcComponent is empty.
-     * @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)
-     */
-    static boolean isMatch(final ComponentIdentifierV2 pcComponent,
-                           final ComponentIdentifierV2 potentialMatch) {
-        boolean matchesSoFar = true;
-
-        matchesSoFar &= isMatchOrEmptyInPlatformCert(
-                potentialMatch.getComponentManufacturer(),
-                pcComponent.getComponentManufacturer());
-
-        matchesSoFar &= isMatchOrEmptyInPlatformCert(
-                potentialMatch.getComponentModel(),
-                pcComponent.getComponentModel());
-
-        return matchesSoFar;
-    }
-
-    private static boolean isMatchOrEmptyInPlatformCert(
-            final String evidenceFromDevice,
-            final DERUTF8String valueInPlatformCert) {
-        if (valueInPlatformCert == null || StringUtils.isEmpty(valueInPlatformCert.getString())) {
-            return true;
-        }
-        return valueInPlatformCert.getString().equals(evidenceFromDevice);
-    }
-
-    private static boolean isMatchOrEmptyInPlatformCert(
-            final DERUTF8String evidenceFromDevice,
-            final DERUTF8String valueInPlatformCert) {
-        return evidenceFromDevice.equals(valueInPlatformCert);
-    }
-
-    /**
-     * Validates the platform credential's serial numbers with the device info's set of
-     * serial numbers.
-     * @param credentialBoardSerialNumber the PC board S/N
-     * @param credentialChassisSerialNumber the PC chassis S/N
-     * @param deviceInfoSerialNumbers the map of device info serial numbers with descriptions.
-     * @return the changed validation status
-     */
-    private static AppraisalStatus validatePlatformSerialsWithDeviceSerials(
-            final String credentialBoardSerialNumber, final String credentialChassisSerialNumber,
-            final Map<String, String> deviceInfoSerialNumbers) {
-        boolean boardSerialNumberFound = false;
-        boolean chassisSerialNumberFound = false;
-
-        if (StringUtils.isNotEmpty(credentialBoardSerialNumber)) {
-            boardSerialNumberFound = deviceInfoContainsPlatformSerialNumber(
-                    credentialBoardSerialNumber, "board serial number", deviceInfoSerialNumbers);
-        }
-        if (StringUtils.isNotEmpty(credentialChassisSerialNumber)) {
-            chassisSerialNumberFound = deviceInfoContainsPlatformSerialNumber(
-                    credentialChassisSerialNumber,
-                    "chassis serial number", deviceInfoSerialNumbers);
-        }
-
-        if (boardSerialNumberFound || chassisSerialNumberFound) {
-            log.info("The platform credential's board or chassis serial number matched"
-                    + " with a serial number from the client's device information");
-            return new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID);
-        }
-        log.error("The platform credential's board and chassis serial numbers did"
-                + " not match with any device info's serial numbers");
-
-        return new AppraisalStatus(FAIL, "Platform serial did not match device info");
-    }
-
-
-    /**
-     * Checks if a platform credential's serial number matches ANY of the device information's
-     * set of serial numbers.
-     * @param platformSerialNumber the platform serial number to compare
-     * @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),
-     *          false otherwise
-     */
-    private static boolean deviceInfoContainsPlatformSerialNumber(
-            final String platformSerialNumber, final String platformSerialNumberDescription,
-            final Map<String, String> deviceInfoSerialNumbers) {
-        // check to see if the platform serial number is contained in the map of device info's
-        // serial numbers
-        for (Map.Entry<String, String> entry : deviceInfoSerialNumbers.entrySet()) {
-            if (entry.getValue().equalsIgnoreCase(platformSerialNumber)) {
-                log.info("Device info contained platform {} {}"
-                                + " in the device info's {}", platformSerialNumberDescription,
-                        platformSerialNumber, entry.getKey());
-                return true;
-            }
-        }
-
-        log.warn("Platform {}, {}, did not match any device info serial numbers",
-                platformSerialNumberDescription, platformSerialNumber);
-        return false;
-    }
-
-    /**
-     * Checks if the endorsement credential is valid.
-     *
-     * @param ec the endorsement credential to verify.
-     * @param trustStore trust store holding trusted trusted certificates.
-     * @param acceptExpired whether or not to accept expired and not yet valid certificates
-     *                      as valid.
-     * @return the result of the validation.
-     */
-    @Override
-    public AppraisalStatus validateEndorsementCredential(final EndorsementCredential ec,
-                                                         final KeyStore trustStore,
-                                                         final boolean acceptExpired) {
-        final String baseErrorMessage = "Can't validate endorsement credential attributes without ";
-        String message;
-        if (ec == null) {
-            message = baseErrorMessage + "an endorsement credential";
-            log.error(message);
-            return new AppraisalStatus(FAIL, message);
-        }
-        if (trustStore == null) {
-            message = baseErrorMessage + "a trust store";
-            log.error(message);
-            return new AppraisalStatus(FAIL, message);
-        }
-
-        try {
-            X509Certificate verifiableCert = ec.getX509Certificate();
-
-            // check validity period, currently acceptExpired will also accept not yet
-            // valid certificates
-            if (!acceptExpired) {
-                verifiableCert.checkValidity();
-            }
-
-            if (verifyCertificate(verifiableCert, trustStore)) {
-                return new AppraisalStatus(PASS, ENDORSEMENT_VALID);
-            } else {
-                return new AppraisalStatus(FAIL, "Endorsement credential does not have a valid "
-                        + "signature chain in the trust store");
-            }
-        } catch (IOException e) {
-            message = "Couldn't retrieve X509 certificate from endorsement credential";
-            log.error(message, e);
-            return new AppraisalStatus(ERROR, message + " " + e.getMessage());
-        } catch (SupplyChainValidatorException e) {
-            message = "An error occurred indicating the credential is not valid";
-            log.warn(message, e);
-            return new AppraisalStatus(ERROR, message + " " + e.getMessage());
-        } catch (CertificateExpiredException e) {
-            message = "The endorsement credential is expired";
-            log.warn(message, e);
-            return new AppraisalStatus(FAIL, message + " " + e.getMessage());
-        } catch (CertificateNotYetValidException e) {
-            message = "The endorsement credential is not yet valid";
-            log.warn(message, e);
-            return new AppraisalStatus(FAIL, message + " " + e.getMessage());
-        }
-    }
-
-    /**
-     * Attempts to check if the certificate is validated by certificates in a cert chain. The cert
-     * chain is expected to be stored in a non-ordered KeyStore (trust store). If the signing
-     * certificate for the target cert is found, but it is an intermediate cert, the validation will
-     * continue to try to find the signing cert of the intermediate cert. It will continue searching
-     * until it follows the chain up to a root (self-signed) cert.
-     *
-     * @param cert
-     *            certificate to validate
-     * @param trustStore
-     *            trust store holding trusted root certificates and intermediate certificates
-     * @return the certificate chain if validation is successful
-     * @throws SupplyChainValidatorException
-     *             if the verification is not successful
-     */
-    public static String verifyCertificate(final X509AttributeCertificateHolder cert,
-                                           final KeyStore trustStore) throws SupplyChainValidatorException {
-        try {
-            if (cert == null || trustStore == null) {
-                throw new SupplyChainValidatorException("Certificate or trust store is null");
-            } else if (trustStore.size() == 0) {
-                throw new SupplyChainValidatorException("Truststore is empty");
-            }
-        } catch (KeyStoreException e) {
-            log.error("Error accessing trust store: " + e.getMessage());
-        }
-
-        try {
-            Set<X509Certificate> trustedCerts = new HashSet<>();
-
-            Enumeration<String> alias = trustStore.aliases();
-
-            while (alias.hasMoreElements()) {
-                trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement()));
-            }
-
-            String certChainValidated = validateCertChain(cert, trustedCerts);
-            if (!certChainValidated.isEmpty()) {
-                log.error("Cert chain could not be validated");
-            }
-            return certChainValidated;
-        } catch (KeyStoreException e) {
-            throw new SupplyChainValidatorException("Error with the trust store", e);
-        }
-    }
-
-    /**
-     * Attempts to check if the certificate is validated by certificates in a cert chain. The cert
-     * chain is expected to be stored in a non-ordered KeyStore (trust store). If the signing
-     * certificate for the target cert is found, but it is an intermediate cert, the validation will
-     * continue to try to find the signing cert of the intermediate cert. It will continue searching
-     * until it follows the chain up to a root (self-signed) cert.
-     *
-     * @param cert
-     *            certificate to validate
-     * @param trustStore
-     *            trust store holding trusted root certificates and intermediate certificates
-     * @return the certificate chain if validation is successful
-     * @throws SupplyChainValidatorException
-     *             if the verification is not successful
-     */
-    public static boolean verifyCertificate(final X509Certificate cert,
-                                            final KeyStore trustStore) throws SupplyChainValidatorException {
-        try {
-            if (cert == null || trustStore == null) {
-                throw new SupplyChainValidatorException("Certificate or trust store is null");
-            } else if (trustStore.size() == 0) {
-                throw new SupplyChainValidatorException("Truststore is empty");
-            }
-        } catch (KeyStoreException e) {
-            log.error("Error accessing trust store: " + e.getMessage());
-        }
-
-        try {
-            Set<X509Certificate> trustedCerts = new HashSet<>();
-
-            Enumeration<String> alias = trustStore.aliases();
-
-            while (alias.hasMoreElements()) {
-                trustedCerts.add((X509Certificate) trustStore.getCertificate(alias.nextElement()));
-            }
-
-            return validateCertChain(cert, trustedCerts).isEmpty();
-        } catch (KeyStoreException e) {
-            log.error("Error accessing keystore", e);
-            throw new SupplyChainValidatorException("Error with the trust store", e);
-        }
-
-    }
-
-    /**
-     * Attempts to check if an attribute certificate is validated by certificates in a cert chain.
-     * The cert chain is represented as a Set of X509Certificates. If the signing certificate for
-     * the target cert is found, but it is an intermediate cert, the validation will continue to try
-     * to find the signing cert of the intermediate cert. It will continue searching until it
-     * follows the chain up to a root (self-signed) cert.
-     *
-     * @param cert
-     *            certificate to validate
-     * @param additionalCerts
-     *            Set of certs to validate against
-     * @return String status of the cert chain validation -
-     *  blank if successful, error message otherwise
-     * @throws SupplyChainValidatorException tried to validate using null certificates
-     */
-    public static String validateCertChain(final X509AttributeCertificateHolder cert,
-                                           final Set<X509Certificate> additionalCerts)
-            throws SupplyChainValidatorException {
-        if (cert == null || additionalCerts == null) {
-            throw new SupplyChainValidatorException(
-                    "Certificate or validation certificates are null");
-        }
-        final String intCAError = "Intermediate signing cert found, check for CA cert";
-        String foundRootOfCertChain = "";
-        X509Certificate nextInChain = null;
-
-        do {
-            for (X509Certificate trustedCert : additionalCerts) {
-                boolean issuerMatchesSubject = false;
-                boolean signatureMatchesPublicKey = false;
-                if (nextInChain != null) {
-                    issuerMatchesSubject = issuerMatchesSubjectDN(nextInChain, trustedCert);
-                    signatureMatchesPublicKey = signatureMatchesPublicKey(nextInChain,
-                            trustedCert);
-                } else {
-                    issuerMatchesSubject = issuerMatchesSubjectDN(cert, trustedCert);
-                    signatureMatchesPublicKey = signatureMatchesPublicKey(cert, trustedCert);
-                }
-
-                if (issuerMatchesSubject && signatureMatchesPublicKey) {
-                    if (isSelfSigned(trustedCert)) {
-                        log.info("CA Root found.");
-                        return "";
-                    } else {
-                        foundRootOfCertChain = intCAError;
-                        nextInChain = trustedCert;
-                        break;
-                    }
-                } else {
-                    if (!issuerMatchesSubject) {
-                        foundRootOfCertChain = "Issuer DN does not match Subject DN";
-                    }
-                    if (!signatureMatchesPublicKey) {
-                        foundRootOfCertChain = "Certificate signature failed to verify";
-                    }
-                }
-            }
-        } while (foundRootOfCertChain.equals(intCAError));
-
-        log.error(foundRootOfCertChain);
-        return foundRootOfCertChain;
-    }
-
-    /**
-     * Attempts to check if a public-key certificate is validated by certificates in a cert chain.
-     * The cert chain is represented as a Set of X509Certificates. If the signing certificate for
-     * the target cert is found, but it is an intermediate cert, the validation will continue to try
-     * to find the signing cert of the intermediate cert. It will continue searching until it
-     * follows the chain up to a root (self-signed) cert.
-     *
-     * @param cert
-     *            certificate to validate
-     * @param additionalCerts
-     *            Set of certs to validate against
-     * @return String status of the cert chain validation -
-     *  blank if successful, error message otherwise
-     * @throws SupplyChainValidatorException tried to validate using null certificates
-     */
-    public static String validateCertChain(final X509Certificate cert,
-                                           final Set<X509Certificate> additionalCerts) throws SupplyChainValidatorException {
-        if (cert == null || additionalCerts == null) {
-            throw new SupplyChainValidatorException(
-                    "Certificate or validation certificates are null");
-        }
-        final String intCAError = "Intermediate signing cert found, check for CA cert";
-        String foundRootOfCertChain = "";
-        X509Certificate startOfChain = cert;
-
-        do {
-            for (X509Certificate trustedCert : additionalCerts) {
-                boolean issuerMatchesSubject = issuerMatchesSubjectDN(startOfChain, trustedCert);
-                boolean signatureMatchesPublicKey = signatureMatchesPublicKey(startOfChain,
-                        trustedCert);
-                if (issuerMatchesSubject && signatureMatchesPublicKey) {
-                    if (isSelfSigned(trustedCert)) {
-                        log.info("CA Root found.");
-                        return "";
-                    } else {
-                        foundRootOfCertChain = intCAError;
-                        startOfChain = trustedCert;
-                        break;
-                    }
-                } else {
-                    if (!issuerMatchesSubject) {
-                        foundRootOfCertChain = "Issuer DN does not match Subject DN";
-                    }
-                    if (!signatureMatchesPublicKey) {
-                        foundRootOfCertChain = "Certificate signature failed to verify";
-                    }
-                }
-            }
-        } while (foundRootOfCertChain.equals(intCAError));
-
-        log.warn(foundRootOfCertChain);
-        return foundRootOfCertChain;
-    }
-
-    private static String validateDeltaChain(
-            final Map<PlatformCredential, SupplyChainValidation> deltaMapping,
-            final List<ComponentIdentifier> baseCompList,
-            final List<ComponentIdentifier> leftOvers,
-            final List<ComponentIdentifier> absentSerials,
-            final List<PlatformCredential> chainCertificates) {
-        StringBuilder resultMessage = new StringBuilder();
-        List<String> noneSerialValues = new ArrayList<>();
-        noneSerialValues.add("");
-        noneSerialValues.add(null);
-        noneSerialValues.add("Not Specified");
-        noneSerialValues.add("To Be Filled By O.E.M.");
-
-        // map the components throughout the chain
-        Map<String, ComponentIdentifier> chainCiMapping = new HashMap<>();
-        baseCompList.stream().forEach((ci) -> {
-            if (!noneSerialValues.contains(ci.getComponentSerial().toString())) {
-                chainCiMapping.put(ci.getComponentSerial().toString(), ci);
-            } else {
-                absentSerials.add(ci);
-            }
-        });
-
-        String ciSerial;
-        List<ArchivableEntity> certificateList = null;
-        SupplyChainValidation scv = null;
-        // go through the leaf and check the changes against the valid components
-        // forget modifying validOrigPcComponents
-        for (PlatformCredential delta : chainCertificates) {
-            StringBuilder failureMsg = new StringBuilder();
-            certificateList = new ArrayList<>();
-            certificateList.add(delta);
-
-            for (ComponentIdentifier ci : delta.getComponentIdentifiers()) {
-                if (!noneSerialValues.contains(ci.getComponentSerial().toString())) {
-                    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)) {
-                                chainCiMapping.put(ciSerial, ci);
-                            } else {
-                                failureMsg.append(String.format(
-                                        "%s attempted MODIFIED with no prior instance.%n",
-                                        ciSerial));
-                                delta.setComponentFailures(String.format("%s,%d",
-                                        delta.getComponentFailures(), ciV2.hashCode()));
-                                scv = deltaMapping.get(delta);
-                                if (scv != null
-                                        && scv.getValidationResult() != PASS) {
-                                    failureMsg.append(scv.getMessage());
-                                }
-                                deltaMapping.put(delta, new SupplyChainValidation(
-                                        SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
-                                        FAIL,
-                                        certificateList,
-                                        failureMsg.toString()));
-                            }
-                        } else if (ciV2.isRemoved()) {
-                            if (!chainCiMapping.containsKey(ciSerial)) {
-                                // error thrown, can't remove if it doesn't exist
-                                failureMsg.append(String.format(
-                                        "%s attempted REMOVED with no prior instance.%n",
-                                        ciSerial));
-                                delta.setComponentFailures(String.format("%s,%d",
-                                        delta.getComponentFailures(), ciV2.hashCode()));
-                                scv = deltaMapping.get(delta);
-                                if (scv != null
-                                        && scv.getValidationResult() != PASS) {
-                                    failureMsg.append(scv.getMessage());
-                                }
-                                deltaMapping.put(delta, new SupplyChainValidation(
-                                        SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
-                                        FAIL,
-                                        certificateList,
-                                        failureMsg.toString()));
-                            } else {
-                                chainCiMapping.remove(ciSerial);
-                            }
-                        } else if (ciV2.isAdded()) {
-                            // ADDED
-                            if (chainCiMapping.containsKey(ciSerial)) {
-                                // error, shouldn't exist
-                                failureMsg.append(String.format(
-                                        "%s was ADDED, the serial already exists.%n",
-                                        ciSerial));
-                                delta.setComponentFailures(String.format("%s,%d",
-                                        delta.getComponentFailures(), ciV2.hashCode()));
-                                scv = deltaMapping.get(delta);
-                                if (scv != null
-                                        && scv.getValidationResult() != PASS) {
-                                    failureMsg.append(scv.getMessage());
-                                }
-                                deltaMapping.put(delta, new SupplyChainValidation(
-                                        SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL,
-                                        FAIL,
-                                        certificateList,
-                                        failureMsg.toString()));
-                            } else {
-                                // have to add in case later it is removed
-                                chainCiMapping.put(ciSerial, ci);
-                            }
-                        }
-                    }
-                } else {
-                    if (ci.isVersion2() && ((ComponentIdentifierV2) ci).isModified()) {
-                        ComponentIdentifierV2 ciV2 = (ComponentIdentifierV2) ci;
-                        // Look for singular component of same make/model/class
-                        ComponentIdentifier candidate = null;
-                        for (ComponentIdentifier search : absentSerials) {
-                            if (!search.isVersion2()) {
-                                continue;
-                            }
-                            ComponentIdentifierV2 noSerialV2 = (ComponentIdentifierV2) search;
-
-                            if (noSerialV2.getComponentClass().getComponentIdentifier().equals(
-                                    ciV2.getComponentClass().getComponentIdentifier())
-                                    && isMatch(noSerialV2, ciV2)) {
-                                if (candidate == null) {
-                                    candidate = noSerialV2;
-                                } else {
-                                    // This only works if there is one matching component
-                                    candidate = null;
-                                    break;
-                                }
-                            }
-                        }
-
-                        if (candidate != null) {
-                            absentSerials.remove(candidate);
-                            absentSerials.add(ciV2);
-                        } else {
-                            leftOvers.add(ci);
-                        }
-                    } else {
-                        // found a delta ci with no serial
-                        // add to list
-                        leftOvers.add(ci);
-                    }
-                }
-            }
-
-            resultMessage.append(failureMsg.toString());
-        }
-        baseCompList.clear();
-        baseCompList.addAll(chainCiMapping.values());
-        baseCompList.addAll(absentSerials);
-
-        return resultMessage.toString();
-    }
-
-    /**
-     * Checks if the issuer info of an attribute cert matches the supposed signing cert's
-     * distinguished name.
-     *
-     * @param cert
-     *            the attribute certificate with the signature to validate
-     * @param signingCert
-     *            the certificate with the public key to validate
-     * @return boolean indicating if the names
-     * @throws SupplyChainValidatorException tried to validate using null certificates
-     */
-    public static boolean issuerMatchesSubjectDN(final X509AttributeCertificateHolder cert,
-                                                 final X509Certificate signingCert) throws SupplyChainValidatorException {
-        if (cert == null || signingCert == null) {
-            throw new SupplyChainValidatorException("Certificate or signing certificate is null");
-        }
-        String signingCertSubjectDN = signingCert.getSubjectX500Principal().getName();
-        X500Name namedSubjectDN = new X500Name(signingCertSubjectDN);
-
-        X500Name issuerDN = cert.getIssuer().getNames()[0];
-
-        // equality check ignore DN component ordering
-        return issuerDN.equals(namedSubjectDN);
-    }
-
-    /**
-     * Checks if the issuer info of a public-key cert matches the supposed signing cert's
-     * distinguished name.
-     *
-     * @param cert
-     *            the public-key certificate with the signature to validate
-     * @param signingCert
-     *            the certificate with the public key to validate
-     * @return boolean indicating if the names
-     * @throws SupplyChainValidatorException tried to validate using null certificates
-     */
-    public static boolean issuerMatchesSubjectDN(final X509Certificate cert,
-                                                 final X509Certificate signingCert) throws SupplyChainValidatorException {
-        if (cert == null || signingCert == null) {
-            throw new SupplyChainValidatorException("Certificate or signing certificate is null");
-        }
-        String signingCertSubjectDN = signingCert.getSubjectX500Principal().
-                getName(X500Principal.RFC1779);
-        X500Name namedSubjectDN = new X500Name(signingCertSubjectDN);
-
-        String certIssuerDN = cert.getIssuerX500Principal().getName();
-        X500Name namedIssuerDN = new X500Name(certIssuerDN);
-
-        // equality check ignore DN component ordering
-        return namedIssuerDN.equals(namedSubjectDN);
-    }
-
-    /**
-     * Checks if the signature of an attribute cert is validated against the signing cert's public
-     * key.
-     *
-     * @param cert
-     *            the public-key certificate with the signature to validate
-     * @param signingCert
-     *            the certificate with the public key to validate
-     * @return boolean indicating if the validation passed
-     * @throws SupplyChainValidatorException tried to validate using null certificates
-     */
-    public static boolean signatureMatchesPublicKey(final X509Certificate cert,
-                                                    final X509Certificate signingCert) throws SupplyChainValidatorException {
-        if (cert == null || signingCert == null) {
-            throw new SupplyChainValidatorException("Certificate or signing certificate is null");
-        }
-        try {
-            cert.verify(signingCert.getPublicKey(), BouncyCastleProvider.PROVIDER_NAME);
-            return true;
-        } catch (InvalidKeyException e) {
-            log.info("Incorrect key given to validate this cert's signature");
-        } catch (CertificateException e) {
-            log.info("Encoding error while validating this cert's signature");
-        } catch (NoSuchAlgorithmException e) {
-            log.info("Unsupported signature algorithm found during validation");
-        } catch (NoSuchProviderException e) {
-            log.info("Incorrect provider for cert signature validation");
-        } catch (SignatureException e) {
-            log.info(String.format("%s.verify(%s)", cert.getSubjectX500Principal(),
-                    signingCert.getSubjectX500Principal()));
-        }
-        return false;
-
-    }
-
-    /**
-     * Checks if the signature of a public-key cert is validated against the signing cert's public
-     * key.
-     *
-     * @param cert
-     *            the attribute certificate with the signature to validate
-     * @param signingCert
-     *            the certificate with the public key to validate
-     * @return boolean indicating if the validation passed
-     * @throws SupplyChainValidatorException tried to validate using null certificates
-     */
-    public static boolean signatureMatchesPublicKey(final X509AttributeCertificateHolder cert,
-                                                    final X509Certificate signingCert) throws SupplyChainValidatorException {
-        if (signingCert == null) {
-            throw new SupplyChainValidatorException("Signing certificate is null");
-        }
-        return signatureMatchesPublicKey(cert, signingCert.getPublicKey());
-    }
-
-    /**
-     * Checks if an X509 Attribute Certificate is valid directly against a public key.
-     *
-     * @param cert
-     *            the attribute certificate with the signature to validate
-     * @param signingKey
-     *            the key to use to check the attribute cert
-     * @return boolean indicating if the validation passed
-     * @throws SupplyChainValidatorException tried to validate using null certificates
-     */
-    public static boolean signatureMatchesPublicKey(final X509AttributeCertificateHolder cert,
-                                                    final PublicKey signingKey) throws SupplyChainValidatorException {
-        if (cert == null || signingKey == null) {
-            throw new SupplyChainValidatorException("Certificate or signing certificate is null");
-        }
-        ContentVerifierProvider contentVerifierProvider;
-        try {
-            contentVerifierProvider =
-                    new JcaContentVerifierProviderBuilder().setProvider("BC").build(signingKey);
-            return cert.isSignatureValid(contentVerifierProvider);
-        } catch (OperatorCreationException | CertException e) {
-            log.info("Exception thrown while verifying certificate", e);
-            log.info(String.format("%s.isSignatureValid(%s)", cert.getSerialNumber(),
-                    signingKey.getFormat()));
-            return false;
-        }
-    }
-
-    /**
-     * Checks whether given X.509 public-key certificate is self-signed. If the cert can be
-     * verified using its own public key, that means it was self-signed.
-     *
-     * @param cert
-     *            X.509 Certificate
-     * @return boolean indicating if the cert was self-signed
-     */
-    private static boolean isSelfSigned(final X509Certificate cert)
-            throws SupplyChainValidatorException {
-        if (cert == null) {
-            throw new SupplyChainValidatorException("Certificate is null");
-        }
-        try {
-            PublicKey key = cert.getPublicKey();
-            cert.verify(key);
-            return true;
-        } catch (SignatureException | InvalidKeyException e) {
-            return false;
-        } catch (CertificateException | NoSuchAlgorithmException | NoSuchProviderException e) {
-            log.error("Exception occurred while checking if cert is self-signed", e);
-            return false;
-        }
-    }
-}
diff --git a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/uefi/UefiGuid.java b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/uefi/UefiGuid.java
index 7ceecdc0..aa83f937 100644
--- a/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/uefi/UefiGuid.java
+++ b/HIRS_Utils/src/main/java/hirs/utils/tpm/eventlog/uefi/UefiGuid.java
@@ -23,7 +23,7 @@ public class UefiGuid {
      */
     private static final int UUID_EPOCH_DIVISOR = 10000;
 
-    private static final Path JSON_PATH = FileSystems.getDefault().getPath("/opt",
+    private static final Path JSON_PATH = FileSystems.getDefault().getPath("/etc",
             "hirs/aca", "default-properties", "vendor-table.json");
     private JsonObject uefiVendorRef;
     /**